]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-sabayon.in
Merge pull request #2057 from brauner/2017-12-22/bugfixes
[mirror_lxc.git] / templates / lxc-sabayon.in
1 #!/bin/bash
2 # vim: set ts=4 sw=4 expandtab
3
4 # Exit on error and treat unset variables as an error.
5 set -eu
6
7 #
8 # LXC template for Sabayon OS, based of Alpine script.
9 #
10
11 # Authors:
12 # Geaaru <geaaru@gmail.com>
13
14 # This library is free software; you can redistribute it and/or
15 # modify it under the terms of the GNU Lesser General Public
16 # License as published by the Free Software Foundation; either
17 # version 2.1 of the License, or (at your option) any later version.
18 #
19 # This library is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 # Lesser General Public License for more details.
23 #
24 # You should have received a copy of the GNU Lesser General Public
25 # License along with this library; if not, write to the Free Software
26 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27
28
29 #=========================== Constants ============================#
30
31 # Make sure the usual locations are in PATH
32 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
33
34 readonly LOCAL_STATE_DIR='@LOCALSTATEDIR@'
35 readonly LXC_TEMPLATE_CONFIG='@LXCTEMPLATECONFIG@'
36
37
38 # Temporary static MIRROR LIST. I will get list from online path on the near future.
39 readonly MIRRORS_LIST="
40 http://mirror.it.sabayon.org/
41 http://dl.sabayon.org/
42 ftp://ftp.klid.dk/sabayonlinux/
43 http://ftp.fsn.hu/pub/linux/distributions/sabayon/
44 http://ftp.cc.uoc.gr/mirrors/linux/SabayonLinux/
45 http://ftp.rnl.ist.utl.pt/pub/sabayon/
46 ftp://ftp.nluug.nl/pub/os/Linux/distr/sabayonlinux/
47 http://mirror.internode.on.net/pub/sabayon/
48 http://mirror.yandex.ru/sabayon/
49 http://sabayon.c3sl.ufpr.br/
50 http://mirror.clarkson.edu/sabayon/
51 http://na.mirror.garr.it/mirrors/sabayonlinux/"
52
53 #======================== Global variables ========================#
54
55 # Clean variables and set defaults.
56 arch="$(uname -m)"
57 debug='no'
58 flush_cache='no'
59 mirror_url=
60 name=
61 path=
62 release="DAILY"
63 rootfs=
64 unprivileged=false
65 mapped_uid=
66 mapped_gid=
67 flush_owner=false
68
69 #======================== Helper Functions ========================#
70
71 usage() {
72 cat <<-EOF
73 Template specific options can be passed to lxc-create after a '--' like this:
74
75 lxc-create --name=NAME [lxc-create-options] -- [template-options]
76
77 Template options:
78 -a ARCH, --arch=ARCH The container architecture (e.g. x86_64, armv7); defaults
79 to the host arch.
80 -d, --debug Run this script in a debug mode (set -x and wget w/o -q).
81 -m URL --mirror=URL The Sabayon mirror to use; defaults to random mirror.
82 -u, --unprivileged Tuning of rootfs for unprivileged containers.
83 -r, --release Identify release to use. Default is DAILY.
84 --mapped-gid Group Id to use on unprivileged container
85 (based of value present on file /etc/subgid).
86 --mapped-uid User Id to use on unprivileged container
87 (based of value present on file /etc/subuid)
88 --flush-owner Only for directly creation of unprivileged containers
89 through lxc-create command. Execute fuidshift command.
90 Require --mapped-gid,--mapped-uid and --unprivileged
91 options.
92
93 Environment variables:
94 RELEASE Release version of Sabayon. Default is ${RELEASE}.
95 EOF
96 }
97
98 random_mirror_url() {
99 local url=""
100
101 if [ $arch == 'amd64' ] ; then
102 url=$(echo $MIRRORS_LIST | sed -e 's/ /\n/g' | sort -R --random-source=/dev/urandom | head -n 1)
103 else
104 if [ $arch == 'armv7l' ] ; then
105 # Currently armv7l tarball is not on sabayon mirrored tree.
106 url="https://dockerbuilder.sabayon.org/"
107 fi
108 fi
109
110 [ -n "$url" ] && echo "$url"
111 }
112
113 die() {
114 local retval=$1; shift
115
116 echo -e "==> $@\n"
117 exit $retval
118 }
119
120 einfo() {
121 echo -e "==> $@\n"
122 }
123
124 fetch() {
125 if [ "$debug" = 'yes' ]; then
126 wget -T 10 -O - $@
127 else
128 wget -T 10 -O - -q $@
129 fi
130 }
131
132 parse_arch() {
133 case "$1" in
134 x86_64 | amd64) echo 'amd64';;
135 armv7 | armv7l) echo 'armv7l';;
136 #arm*) echo 'armhf';;
137 *) return 1;;
138 esac
139 }
140
141 run_exclusively() {
142
143 local lock_name="$1"
144 local timeout=$2
145 local method=$3
146 shift 3
147
148 mkdir -p "$LOCAL_STATE_DIR/lock/subsys"
149
150 local retval
151 {
152 echo -n "Obtaining an exclusive lock..."
153 if ! flock -x 9; then
154 echo ' failed.'
155 return 1
156 fi
157 echo ' done'
158
159 ${method} $@
160 retval=$?
161 } 9> "$LOCAL_STATE_DIR/lock/subsys/lxc-sabayon-$lock_name"
162
163 return $retval
164 }
165
166 create_url () {
167
168 local url=""
169 # Example of amd64 tarball url
170 # http://mirror.yandex.ru/sabayon/iso/daily/Sabayon_Linux_DAILY_amd64_tarball.tar.gz
171
172 if [ $arch == 'amd64' ] ; then
173
174 if [ $release = 'DAILY' ] ; then
175 url="${MIRROR_URL}iso/daily/Sabayon_Linux_DAILY_amd64_tarball.tar.gz"
176 else
177 url="${MIRROR_URL}iso/monthly/Sabayon_Linux_${release}_amd64_tarball.tar.gz"
178 fi
179 else
180 # https://dockerbuilder.sabayon.org/Sabayon_Linux_16_armv7l.tar.bz2
181 if [ $arch == 'armv7l' ] ; then
182
183 # Currently $arch tarball is not on sabayon mirrored tree.
184 url="${MIRROR_URL}Sabayon_Linux_16_armv7l.tar.bz2"
185
186 fi
187 fi
188
189 echo $url
190 }
191
192
193 #=========================== Configure ===========================#
194
195 unprivileged_rootfs() {
196
197 pushd ${rootfs}/etc/systemd/system
198
199 # Disable systemd-journald-audit.socket because it seems that doesn't
200 # start correctly on unprivileged container
201 ln -s /dev/null systemd-journald-audit.socket
202
203 # Disable systemd-remount-fs.service because on unprivileged container
204 # systemd can't remount filesystem
205 ln -s /dev/null systemd-remount-fs.service
206
207 # Remove mount of FUSE Control File system
208 ln -s /dev/null sys-fs-fuse-connections.mount
209
210 # Change execution of service systemd-sysctl to avoid errors.
211 mkdir systemd-sysctl.service.d
212 cat <<EOF > systemd-sysctl.service.d/00gentoo.conf
213 [Service]
214 ExecStart=
215 ExecStart=/usr/lib/systemd/systemd-sysctl --prefix=/etc/sysctl.d/
216 EOF
217
218 # Disable mount of hugepages
219 ln -s /dev/null dev-hugepages.mount
220
221 popd
222
223 pushd ${rootfs}
224
225 # Disable sabayon-anti-fork-bomb limits (already apply to lxc container manager)
226 sed -i -e 's/^*/#*/g' ./etc/security/limits.d/00-sabayon-anti-fork-bomb.conf || return 1
227 sed -i -e 's/^root/#root/g' ./etc/security/limits.d/00-sabayon-anti-fork-bomb.conf || return 1
228
229 popd
230
231 return 0
232 }
233
234 unprivileged_shift_owner () {
235
236 # I use /usr/bin/fuidshift from LXD project.
237
238 einfo "Executing: fuidshift ${rootfs} u:0:${mapped_uid}:65536 g:0:${mapped_gid}:65536 ..."
239
240 fuidshift ${rootfs} u:0:${mapped_uid}:65536 g:0:${mapped_gid}:65536 ||
241 die 1 "Error on change owners of ${rootfs} directory"
242
243 einfo "Done."
244
245 # Fix permission of container directory
246 chmod a+rx ${path}
247
248 return 0
249 }
250
251 systemd_container_tuning () {
252
253 # To avoid error on start systemd-tmpfiles-setup service
254 # it is needed clean journal directory
255 rm -rf ${rootfs}/var/log/journal/
256
257 # Remove LVM service. Normally not needed on container system.
258 rm -rf ${rootfs}/etc/systemd/system/sysinit.target.wants/lvm2-lvmetad.service
259
260 # Comment unneeded entry on /etc/fstab
261 sed -e 's/\/dev/#\/dev/g' -i ${rootfs}/etc/fstab
262
263 # Fix this stupid error until fix is available on sabayon image
264 # /usr/lib/systemd/system-generators/gentoo-local-generator: line 4: cd: /etc/local.d: No such file or directory
265 mkdir ${rootfs}/etc/local.d/
266
267 # Fix TERM variable for container console
268 mkdir container-getty\@0.service.d
269 cat <<EOF > container-getty\@0.service.d/00gentoo.conf
270 [Service]
271 Environment=TERM=
272 Environment=TERM=linux
273 EOF
274
275 return 0
276 }
277
278 configure_container() {
279 local config="$1"
280 local hostname="$2"
281 local arch="$3"
282 local privileged_options=""
283 local unprivileged_options=""
284
285 if [[ $unprivileged && $unprivileged == true ]] ; then
286 if [[ $flush_owner == true ]] ; then
287 unprivileged_options="
288 lxc.idmap = u 0 ${mapped_uid} 65536
289 lxc.idmap = g 0 ${mapped_gid} 65536
290 "
291 fi
292
293 unprivileged_options="
294 $unprivileged_options
295
296 # Force use of cgroup v1. Currently systemd doesn't support
297 # correctly cgroup v2. See: https://github.com/lxc/lxc/issues/1669
298 # about discussion of default-hierarchy option.
299 lxc.init.cmd = /sbin/init systemd.legacy_systemd_cgroup_controller=yes
300
301 # Include common configuration.
302 lxc.include = $LXC_TEMPLATE_CONFIG/sabayon.userns.conf
303 "
304
305 else
306 privileged_options="
307 ## Allow any mknod (but not reading/writing the node)
308 lxc.cgroup.devices.allow = b *:* m
309 lxc.cgroup.devices.allow = c *:* m
310
311 ### /dev/pts/*
312 lxc.cgroup.devices.allow = c 136:* rwm
313 ### /dev/tty
314 lxc.cgroup.devices.allow = c 5:0 rwm
315 ### /dev/console
316 lxc.cgroup.devices.allow = c 5:1 rwm
317 ### /dev/ptmx
318 lxc.cgroup.devices.allow = c 5:2 rwm
319 ### fuse
320 lxc.cgroup.devices.allow = c 10:229 rwm
321
322 "
323 fi
324
325 cat <<-EOF >> "$config"
326 # Specify container architecture.
327 lxc.arch = $arch
328
329 # Set hostname.
330 lxc.uts.name = $hostname
331
332 # Include common configuration.
333 lxc.include = $LXC_TEMPLATE_CONFIG/sabayon.common.conf
334
335 $unprivileged_options
336 $privileged_options
337 EOF
338 }
339
340
341 #============================= Main ==============================#
342
343 parse_cmdline() {
344
345 # Parse command options.
346 local short_options="a:dm:n:p:r:hu"
347 local long_options="arch:,debug,mirror:,name:,path:,release:,rootfs:,mapped-uid:,mapped-gid:,flush-owner,help"
348
349 options=$(getopt -u -q -a -o "$short_options" -l "$long_options" -- "$@")
350
351 eval set -- "$options"
352
353 # Process command options.
354 while [ $# -gt 0 ]; do
355 case $1 in
356 -a | --arch)
357 arch=$2
358 shift
359 ;;
360 -d | --debug)
361 debug='yes'
362 ;;
363 -m | --mirror)
364 mirror_url=$2
365 shift
366 ;;
367 -n | --name)
368 name=$2
369 shift
370 ;;
371 -p | --path)
372 path=$2
373 shift
374 ;;
375 -r | --release)
376 release=$2
377 shift
378 ;;
379 --rootfs)
380 rootfs=$2
381 shift
382 ;;
383 -u | --unprivileged)
384 unprivileged=true
385 ;;
386 -h | --help)
387 usage
388 exit 1
389 ;;
390 --mapped-uid)
391 mapped_uid=$2
392 shift
393 ;;
394 --mapped-gid)
395 mapped_gid=$2
396 shift
397 ;;
398 --flush-owner)
399 flush_owner=true
400 ;;
401 --)
402 break
403 ;;
404 *)
405 einfo "Unknown option: $1"
406 usage
407 exit 1
408 ;;
409 esac
410 shift
411 done
412
413 if [ "$(id -u)" != "0" ]; then
414 die 1 "This script must be run as 'root'"
415 fi
416
417 # Validate options.
418 [ -n "$name" ] || die 1 'Missing required option --name'
419 [ -n "$path" ] || die 1 'Missing required option --path'
420
421 if [ -z "$rootfs" ] && [ -f "$path/config" ]; then
422 rootfs="$(sed -nE 's/^lxc.rootfs\s*=\s*(.*)$/\1/p' "$path/config")"
423 fi
424 if [ -z "$rootfs" ]; then
425 rootfs="$path/rootfs"
426 fi
427
428 [ -z "$path" ] && die 1 "'path' parameter is required."
429
430 arch=$(parse_arch "$arch") \
431 || die 1 "Unsupported architecture: $arch"
432
433 [[ $unprivileged == true && $flush_owner == true &&-z "$mapped_uid" ]] && \
434 die 1 'Missing required option --mapped-uid with --unprivileged option'
435
436 [[ $unprivileged == true && $flush_owner == true && -z "$mapped_gid" ]] && \
437 die 1 'Missing required option --mapped-gid with --unprivileged option'
438
439 [[ $flush_owner == true && $unprivileged == false ]] && \
440 die 1 'flush-owner require --unprivileged option'
441
442 return 0
443 }
444
445 main () {
446
447 local tarball=""
448
449 # Set global variables.
450 RELEASE="${RELEASE:-"DAILY"}"
451 ARCH="${ARCH:-`uname -m`}"
452 OS="${OS:-"sabayon"}"
453
454 einfo "Processing command line arguments: $@"
455
456 # Parse command line options
457 parse_cmdline "$@"
458
459 DEBUG="$debug"
460 MIRROR_URL="${mirror_url:-$(random_mirror_url)}"
461
462 einfo "Use arch = $arch, mirror_url = $MIRROR_URL, path = $path, name = $name, release = $release, unprivileged = $unprivileged, rootfs = $rootfs, mapped_uid = $mapped_uid, mapped_gid = $mapped_gid, flush_owner = $flush_owner"
463
464 [ "$debug" = 'yes' ] && set -x
465
466 # Download sabayon tarball
467 tarball=$(create_url)
468 einfo "Fetching tarball $tarball..."
469
470 # TODO: use only a compression mode
471 if [ $arch == 'amd64' ] ; then
472 fetch "${tarball}" | tar -xpz -C "${rootfs}"
473 else
474 if [ $arch == 'armv7l' ] ; then
475 fetch "${tarball}" | tar -xpj -C "${rootfs}"
476 fi
477 fi
478
479 einfo "Tarball ${tarball} Extracted."
480
481 systemd_container_tuning
482
483 # Fix container for unprivileged mode.
484 if [[ $unprivileged == true ]] ; then
485 unprivileged_rootfs
486 if [[ $flush_owner == true ]] ; then
487 unprivileged_shift_owner
488 fi
489 fi
490
491 return 0
492 }
493
494
495 einfo "Prepare creation of sabayon container with params: $@ ($#)"
496
497 # Here we go!
498 run_exclusively 'main' 10 main "$@"
499 configure_container "$path/config" "$name" "$arch"
500
501 einfo "Container's rootfs and config have been created"
502 cat <<-EOF
503 Edit the config file $path/config to check/enable networking setup.
504 The installed system is preconfigured for a loopback and single network
505 interface configured via DHCP.
506
507 To start the container, run "lxc-start -n $name".
508 The root password is not set; to enter the container run "lxc-attach -n $name".
509
510 Note: From kenel >= 4.6 for use unprivileged containers it is needed this mount on host:
511
512 mkdir /sys/fs/cgroup/systemd
513 mount -t cgroup -o none,name=systemd systemd /sys/fs/cgroup/systemd
514 EOF