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