]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-fedora-legacy.in
9731b350523068fe5f381205b27d744f27f800b5
[mirror_lxc.git] / templates / lxc-fedora-legacy.in
1 #!/bin/bash
2
3 #
4 # template script for generating fedora container for LXC
5 #
6
7 #
8 # lxc: linux Container library
9
10 # Authors:
11 # Daniel Lezcano <daniel.lezcano@free.fr>
12 # Ramez Hanna <rhanna@informatiq.org>
13 # Michael H. Warfield <mhw@WittsEnd.com>
14
15 # This library is free software; you can redistribute it and/or
16 # modify it under the terms of the GNU Lesser General Public
17 # License as published by the Free Software Foundation; either
18 # version 2.1 of the License, or (at your option) any later version.
19
20 # This library is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 # Lesser General Public License for more details.
24
25 # You should have received a copy of the GNU Lesser General Public
26 # License along with this library; if not, write to the Free Software
27 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28
29 #Configurations
30 default_path=@LXCPATH@
31
32 # Some combinations of the tuning knobs below do not exactly make sense.
33 # but that's ok.
34 #
35 # If the "root_password" is non-blank, use it, else set a default.
36 # This can be passed to the script as an environment variable and is
37 # set by a shell conditional assignment. Looks weird but it is what it is.
38 #
39 # If the root password contains a ding ($) then try to expand it.
40 # That will pick up things like ${name} and ${RANDOM}.
41 # If the root password contains more than 3 consecutive X's, pass it as
42 # a template to mktemp and take the result.
43 #
44 # If root_display_password = yes, display the temporary root password at exit.
45 # If root_store_password = yes, store it in the configuration directory
46 # If root_prompt_password = yes, invoke "passwd" to force the user to change
47 # the root password after the container is created.
48 # If root_expire_password = yes, you will be prompted to change the root
49 # password at the first login.
50 #
51 # These are conditional assignments... The can be overridden from the
52 # preexisting environment variables...
53 #
54 # Make sure this is in single quotes to defer expansion to later!
55 # :{root_password='Root-${name}-${RANDOM}'}
56 : ${root_password='Root-${name}-XXXXXX'}
57
58 # Now, it doesn't make much sense to display, store, and force change
59 # together. But, we gotta test, right???
60 : ${root_display_password='no'}
61 : ${root_store_password='yes'}
62 # Prompting for something interactive has potential for mayhem
63 # with users running under the API... Don't default to "yes"
64 : ${root_prompt_password='no'}
65
66 # Expire root password? Default to yes, but can be overridden from
67 # the environment variable
68 : ${root_expire_password='yes'}
69
70 # These are only going into comments in the resulting config...
71 lxc_network_type=veth
72 lxc_network_link=lxcbr0
73
74 # is this fedora?
75 # Alow for weird remixes like the Raspberry Pi
76 #
77 # Use the Mitre standard CPE identifier for the release ID if possible...
78 # This may be in /etc/os-release or /etc/system-release-cpe. We
79 # should be able to use EITHER. Give preference to /etc/os-release for now.
80
81 # Detect use under userns (unsupported)
82 for arg in "$@"; do
83 [ "$arg" = "--" ] && break
84 if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
85 echo "This template can't be used for unprivileged containers." 1>&2
86 echo "You may want to try the \"download\" template instead." 1>&2
87 exit 1
88 fi
89 done
90
91 # Make sure the usual locations are in PATH
92 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
93
94 if [ -e /etc/os-release ]
95 then
96 # This is a shell friendly configuration file. We can just source it.
97 # What we're looking for in here is the ID, VERSION_ID and the CPE_NAME
98 . /etc/os-release
99 echo "Host CPE ID from /etc/os-release: ${CPE_NAME}"
100 fi
101
102 if [ "${CPE_NAME}" = "" -a -e /etc/system-release-cpe ]
103 then
104 CPE_NAME=$(head -n1 /etc/system-release-cpe)
105 CPE_URI=$(expr ${CPE_NAME} : '\([^:]*:[^:]*\)')
106 if [ "${CPE_URI}" != "cpe:/o" ]
107 then
108 CPE_NAME=
109 else
110 echo "Host CPE ID from /etc/system-release-cpe: ${CPE_NAME}"
111 # Probably a better way to do this but sill remain posix
112 # compatible but this works, shrug...
113 # Must be nice and not introduce convenient bashisms here.
114 ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:\([^:]*\)')
115 VERSION_ID=$(expr ${CPE_NAME} : '[^:]*:[^:]*:[^:]*:[^:]*:\([^:]*\)')
116 fi
117 fi
118
119 if [ "${CPE_NAME}" != "" -a "${ID}" = "fedora" -a "${VERSION_ID}" != "" ]
120 then
121 fedora_host_ver=${VERSION_ID}
122 is_fedora=true
123 elif [ -e /etc/redhat-release ]
124 then
125 # Only if all other methods fail, try to parse the redhat-release file.
126 fedora_host_ver=$( sed -e '/^Fedora /!d' -e 's/Fedora.*\srelease\s*\([0-9][0-9]*\)\s.*/\1/' < /etc/redhat-release )
127 if [ "$fedora_host_ver" != "" ]
128 then
129 is_fedora=true
130 fi
131 fi
132
133 configure_fedora()
134 {
135
136 # disable selinux in fedora
137 mkdir -p $rootfs_path/selinux
138 echo 0 > $rootfs_path/selinux/enforce
139
140 # Also kill it in the /etc/selinux/config file if it's there...
141 if [[ -f $rootfs_path/etc/selinux/config ]]
142 then
143 sed -i '/^SELINUX=/s/.*/SELINUX=disabled/' $rootfs_path/etc/selinux/config
144 fi
145
146 # Nice catch from Dwight Engen in the Oracle template.
147 # Wantonly plagerized here with much appreciation.
148 if [ -f $rootfs_path/usr/sbin/selinuxenabled ]; then
149 mv $rootfs_path/usr/sbin/selinuxenabled $rootfs_path/usr/sbin/selinuxenabled.lxcorig
150 ln -s /bin/false $rootfs_path/usr/sbin/selinuxenabled
151 fi
152
153 # This is a known problem and documented in RedHat bugzilla as relating
154 # to a problem with auditing enabled. This prevents an error in
155 # the container "Cannot make/remove an entry for the specified session"
156 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/login
157 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/sshd
158
159 if [ -f ${rootfs_path}/etc/pam.d/crond ]
160 then
161 sed -i '/^session.*pam_loginuid.so/s/^session/# session/' ${rootfs_path}/etc/pam.d/crond
162 fi
163
164 # In addition to disabling pam_loginuid in the above config files
165 # we'll also disable it by linking it to pam_permit to catch any
166 # we missed or any that get installed after the container is built.
167 #
168 # Catch either or both 32 and 64 bit archs.
169 if [ -f ${rootfs_path}/lib/security/pam_loginuid.so ]
170 then
171 ( cd ${rootfs_path}/lib/security/
172 mv pam_loginuid.so pam_loginuid.so.disabled
173 ln -s pam_permit.so pam_loginuid.so
174 )
175 fi
176
177 if [ -f ${rootfs_path}/lib64/security/pam_loginuid.so ]
178 then
179 ( cd ${rootfs_path}/lib64/security/
180 mv pam_loginuid.so pam_loginuid.so.disabled
181 ln -s pam_permit.so pam_loginuid.so
182 )
183 fi
184
185 # Set default localtime to the host localtime if not set...
186 if [ -e /etc/localtime -a ! -e ${rootfs_path}/etc/localtime ]
187 then
188 # if /etc/localtime is a symlink, this should preserve it.
189 cp -a /etc/localtime ${rootfs_path}/etc/localtime
190 fi
191
192 # Deal with some dain bramage in the /etc/init.d/halt script.
193 # Trim it and make it our own and link it in before the default
194 # halt script so we can intercept it. This also preventions package
195 # updates from interferring with our interferring with it.
196 #
197 # There's generally not much in the halt script that useful but what's
198 # in there from resetting the hardware clock down is generally very bad.
199 # So we just eliminate the whole bottom half of that script in making
200 # ourselves a copy. That way a major update to the init scripts won't
201 # trash what we've set up.
202 #
203 # This is mostly for legacy distros since any modern systemd Fedora
204 # release will not have this script so we won't try to intercept it.
205 if [ -f ${rootfs_path}/etc/init.d/halt ]
206 then
207 sed -e '/hwclock/,$d' \
208 < ${rootfs_path}/etc/init.d/halt \
209 > ${rootfs_path}/etc/init.d/lxc-halt
210
211 echo '$command -f' >> ${rootfs_path}/etc/init.d/lxc-halt
212 chmod 755 ${rootfs_path}/etc/init.d/lxc-halt
213
214 # Link them into the rc directories...
215 (
216 cd ${rootfs_path}/etc/rc.d/rc0.d
217 ln -s ../init.d/lxc-halt S00lxc-halt
218 cd ${rootfs_path}/etc/rc.d/rc6.d
219 ln -s ../init.d/lxc-halt S00lxc-reboot
220 )
221 fi
222
223 # configure the network using the dhcp
224 cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
225 DEVICE=eth0
226 BOOTPROTO=dhcp
227 ONBOOT=yes
228 HOSTNAME=${utsname}
229 DHCP_HOSTNAME=\`hostname\`
230 NM_CONTROLLED=no
231 TYPE=Ethernet
232 MTU=${MTU}
233 EOF
234
235 # set the hostname
236 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
237 NETWORKING=yes
238 HOSTNAME=${utsname}
239 EOF
240
241 # set hostname on systemd Fedora systems
242 if [ $release -gt 14 ]; then
243 echo "${utsname}" > ${rootfs_path}/etc/hostname
244 fi
245
246 # set minimal hosts
247 cat <<EOF > $rootfs_path/etc/hosts
248 127.0.0.1 localhost.localdomain localhost $utsname
249 ::1 localhost6.localdomain6 localhost6
250 EOF
251
252 # These mknod's really don't make any sense with modern releases of
253 # Fedora with systemd, devtmpfs, and autodev enabled. They are left
254 # here for legacy reasons and older releases with upstart and sysv init.
255 dev_path="${rootfs_path}/dev"
256 rm -rf $dev_path
257 mkdir -p $dev_path
258 mknod -m 666 ${dev_path}/null c 1 3
259 mknod -m 666 ${dev_path}/zero c 1 5
260 mknod -m 666 ${dev_path}/random c 1 8
261 mknod -m 666 ${dev_path}/urandom c 1 9
262 mkdir -m 755 ${dev_path}/pts
263 mkdir -m 1777 ${dev_path}/shm
264 mknod -m 666 ${dev_path}/tty c 5 0
265 mknod -m 666 ${dev_path}/tty0 c 4 0
266 mknod -m 666 ${dev_path}/tty1 c 4 1
267 mknod -m 666 ${dev_path}/tty2 c 4 2
268 mknod -m 666 ${dev_path}/tty3 c 4 3
269 mknod -m 666 ${dev_path}/tty4 c 4 4
270 mknod -m 600 ${dev_path}/console c 5 1
271 mknod -m 666 ${dev_path}/full c 1 7
272 mknod -m 600 ${dev_path}/initctl p
273 mknod -m 666 ${dev_path}/ptmx c 5 2
274
275 # setup console and tty[1-4] for login. note that /dev/console and
276 # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
277 # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
278 # lxc will maintain these links and bind mount ptys over /dev/lxc/*
279 # since lxc.devttydir is specified in the config.
280
281 # allow root login on console, tty[1-4], and pts/0 for libvirt
282 echo "# LXC (Linux Containers)" >>${rootfs_path}/etc/securetty
283 echo "lxc/console" >>${rootfs_path}/etc/securetty
284 echo "lxc/tty1" >>${rootfs_path}/etc/securetty
285 echo "lxc/tty2" >>${rootfs_path}/etc/securetty
286 echo "lxc/tty3" >>${rootfs_path}/etc/securetty
287 echo "lxc/tty4" >>${rootfs_path}/etc/securetty
288 echo "# For libvirt/Virtual Machine Monitor" >>${rootfs_path}/etc/securetty
289 echo "pts/0" >>${rootfs_path}/etc/securetty
290
291 if [ ${root_display_password} = "yes" ]
292 then
293 echo "Setting root password to '$root_password'"
294 fi
295 if [ ${root_store_password} = "yes" ]
296 then
297 touch ${config_path}/tmp_root_pass
298 chmod 600 ${config_path}/tmp_root_pass
299 echo ${root_password} > ${config_path}/tmp_root_pass
300 echo "Storing root password in '${config_path}/tmp_root_pass'"
301 fi
302
303 echo "root:$root_password" | chroot $rootfs_path chpasswd
304
305 if [ ${root_expire_password} = "yes" ]
306 then
307 # Also set this password as expired to force the user to change it!
308 chroot $rootfs_path passwd -e root
309 fi
310
311 # specifying this in the initial packages doesn't always work.
312 # Even though it should have...
313 echo "installing fedora-release package"
314 mount -o bind /dev ${rootfs_path}/dev
315 mount -t proc proc ${rootfs_path}/proc
316 # Always make sure /etc/resolv.conf is up to date in the target!
317 cp /etc/resolv.conf ${rootfs_path}/etc/
318 # Rebuild the rpm database based on the target rpm version...
319 rm -f ${rootfs_path}/var/lib/rpm/__db*
320 chroot ${rootfs_path} rpm --rebuilddb
321 chroot ${rootfs_path} yum -y install fedora-release
322
323 if [[ ! -e ${rootfs_path}/sbin/NetworkManager ]]
324 then
325 # NetworkManager has not been installed. Use the
326 # legacy chkconfig command to enable the network startup
327 # scripts in the container.
328 chroot ${rootfs_path} chkconfig network on
329 fi
330
331 umount ${rootfs_path}/proc
332 umount ${rootfs_path}/dev
333
334 # silence some needless startup errors
335 touch ${rootfs_path}/etc/fstab
336
337 # give us a console on /dev/console
338 sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \
339 ${rootfs_path}/etc/sysconfig/init
340
341 return 0
342 }
343
344 configure_fedora_init()
345 {
346 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
347 sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
348 # don't mount devpts, for pete's sake
349 sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit
350 sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
351 chroot ${rootfs_path} chkconfig udev-post off
352 chroot ${rootfs_path} chkconfig network on
353
354 if [ -d ${rootfs_path}/etc/init ]
355 then
356 # This is to make upstart honor SIGPWR. Should do no harm
357 # on systemd systems and some systems may have both.
358 cat <<EOF >${rootfs_path}/etc/init/power-status-changed.conf
359 # power-status-changed - shutdown on SIGPWR
360 #
361 start on power-status-changed
362
363 exec /sbin/shutdown -h now "SIGPWR received"
364 EOF
365 fi
366 }
367
368 configure_fedora_systemd()
369 {
370 rm -f ${rootfs_path}/etc/systemd/system/default.target
371 touch ${rootfs_path}/etc/fstab
372 chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/udev.service
373 chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
374 # Make systemd honor SIGPWR
375 chroot ${rootfs_path} ln -s /usr/lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
376
377 # if desired, prevent systemd from over-mounting /tmp with tmpfs
378 if [ $masktmp -eq 1 ]; then
379 chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/tmp.mount
380 fi
381
382 #dependency on a device unit fails it specially that we disabled udev
383 # sed -i 's/After=dev-%i.device/After=/' ${rootfs_path}/lib/systemd/system/getty\@.service
384 #
385 # Actually, the After=dev-%i.device line does not appear in the
386 # Fedora 17 or Fedora 18 systemd getty\@.service file. It may be left
387 # over from an earlier version and it's not doing any harm. We do need
388 # to disable the "ConditionalPathExists=/dev/tty0" line or no gettys are
389 # started on the ttys in the container. Lets do it in an override copy of
390 # the service so it can still pass rpm verifies and not be automatically
391 # updated by a new systemd version. -- mhw /\/\|=mhw=|\/\/
392
393 sed -e 's/^ConditionPathExists=/# ConditionPathExists=/' \
394 -e 's/After=dev-%i.device/After=/' \
395 < ${rootfs_path}/lib/systemd/system/getty\@.service \
396 > ${rootfs_path}/etc/systemd/system/getty\@.service
397 # Setup getty service on the 4 ttys we are going to allow in the
398 # default config. Number should match lxc.tty
399 ( cd ${rootfs_path}/etc/systemd/system/getty.target.wants
400 for i in 1 2 3 4 ; do ln -sf ../getty\@.service getty@tty${i}.service; done )
401 }
402
403 ### BEGIN Bootstrap Environment Code... Michael H. Warfield /\/\|=mhw=|\/\/
404
405 # Ok... Heads up. If you're reading these comments, you're either a
406 # template owner or someone wondering how the hell I did this (or, worse,
407 # someone in the future trying to maintain it). This code is slightly
408 # "evil coding bastard" code with one significant hack / dirty trick
409 # that you would probably miss just reading the code below. I'll mark
410 # it out with comments.
411 #
412 # Because of what this code does, it deserves a lot of comments so people
413 # can understand WHY I did it this way...
414 #
415 # Ultimate Objective - Build a Fedora container on a host system which does
416 # not have a (complete compatible) version of rpm and/or yum. That basically
417 # means damn near any distro other than Fedora and Ubuntu (which has rpm and
418 # yum available). Only requirements for this function are rsync and
419 # squashfs available to the kernel. If you don't have those, why are you
420 # even attempting to build containers?
421 #
422 # Challenge for this function - Bootstrap a Fedora install bootstrap
423 # run time environment which has all the pieces to run rpm and yum and
424 # from which we can build targets containers even where the host system
425 # has no support for rpm, yum, or fedora.
426 #
427 # Steps:
428 # Stage 0 - Download a Fedora LiveOS squashfs core (netinst core).
429 # Stage 1 - Extract filesystem from Stage 0 and update to full rpm & yum
430 # Stage 2 - Use Stage 1 to build a rootfs with python, rpm, and yum.
431 #
432 # Stage 2 becomes our bootstrap file system which can be cached
433 # and then used to build other arbitrary vesions of Fedora of a
434 # given architecture. Note that this only has to run once for
435 # Fedora on a given architecture since rpm and yum can build other
436 # versions. We'll arbitrarily pick Fedora 20 to build this. This
437 # will need to change as time goes on.
438
439 # Programmers Note... A future fall back may be to download the netinst
440 # iso image instead of the LiveOS squasfs image and work from that.
441 # That may be more general but will introduce another substep
442 # (mounting the iso) to the stage0 setup.
443
444 # This system is designed to be as autonomous as possible so all whitelists
445 # and controls are self-contained.
446
447 # Initial testing - Whitelist nobody. Build for everybody...
448 # Initial deployment - Whitelist Fedora.
449 # Long term - Whitelist Fedora, Debian, Ubuntu, CentOs, Scientific, and NST.
450
451 # List of distros which do not (should not) need a bootstrap (but we will test
452 # for rpm and yum none the less... OS SHOULD be taken from CPE values but
453 # Debian / Ubuntu doesn't support CPE yet.
454
455 # BOOTSTRAP_WHITE_LIST=""
456 BOOTSTRAP_WHITE_LIST="fedora"
457 # BOOTSTRAP_WHITE_LIST="fedora debian ubuntu centos scientific sl nst"
458
459 BOOTSTRAP=0
460 BOOTSTRAP_DIR=
461 BOOTSTRAP_CHROOT=
462
463 fedora_get_bootstrap()
464 {
465 echo "Bootstrap Environment testing..."
466
467 WHITE_LISTED=1
468
469 # We need rpm. No rpm - not possible to white list...
470 if ! which rpm > /dev/null 2>&1
471 then
472 WHITE_LISTED=0
473 fi
474
475 # We need yum No yum - not possible to white list...
476 if ! which yum > /dev/null 2>&1
477 then
478 WHITE_LISTED=0
479 fi
480
481 if [[ ${WHITE_LISTED} != 0 ]]
482 then
483 for OS in ${BOOTSTRAP_WHITE_LIST}
484 do
485 if [[ ${ID} = ${OS} ]]
486 then
487 echo "
488 OS ${ID} is whitelisted. Installation Bootstrap Environment not required.
489 "
490 return 0;
491 fi
492 done
493 fi
494
495 echo "
496 Fedora Installation Bootstrap Build..."
497
498 if ! which rsync > /dev/null 2>&1
499 then
500 echo "
501 Unable to locate rsync. Cravely bailing out before even attempting to build
502 an Installation Bootstrap Please install rsync and then rerun this process.
503 "
504
505 return 255
506 fi
507
508 [[ -d ${cache_base} ]] || mkdir -p ${cache_base}
509
510 cd ${cache_base}
511
512 # We know we don't have a cache directory of this version or we
513 # would have never reached this code to begin with. But we may
514 # have another Fedora cache directory from which we could run...
515 # We'll give a preference for close matches preferring higher over
516 # lower - which makes for really ugly code...
517
518 # Is this a "bashism" that will need cleaning up????
519 BOOTSTRAP_LIST="$(( $release + 1 ))/rootfs $(( $release - 1 ))/rootfs \
520 $(( $release + 2 ))/rootfs $(( $release - 2 ))/rootfs \
521 $(( $release + 3 ))/rootfs $(( $release - 3 ))/rootfs \
522 bootstrap"
523
524 for bootstrap in ${BOOTSTRAP_LIST}
525 do
526 if [[ -d ${bootstrap} ]]
527 then
528 echo "
529 Existing Bootstrap found. Testing..."
530
531 mount -o bind /dev ${bootstrap}/dev
532 mount -t proc proc ${bootstrap}/proc
533 # Always make sure /etc/resolv.conf is up to date in the target!
534 cp /etc/resolv.conf ${bootstrap}/etc/
535 rm -f ${bootstrap}/var/lib/rpm/__db*
536 chroot ${bootstrap} rpm --rebuilddb
537 chroot ${bootstrap} yum -y update
538 RC=$?
539 umount ${bootstrap}/proc
540 umount ${bootstrap}/dev
541
542 if [[ 0 == ${RC} ]]
543 then
544 BOOTSTRAP=1
545 BOOTSTRAP_DIR="${cache_base}/${bootstrap}"
546 BOOTSTRAP_CHROOT="chroot ${BOOTSTRAP_DIR} "
547 BOOTSTRAP_INSTALL_ROOT=/run/install
548
549 echo "
550 Functional Installation Bootstrap exists and appears to be completed.
551 Will use existing Bootstrap: ${BOOTSTRAP_DIR}
552 "
553 return 0
554 fi
555 echo "
556 Installation Bootstrap in ${BOOTSTRAP_DIR} exists
557 but appears to be non-functional. Skipping... It should be removed.
558 "
559 fi
560 done
561
562 TMP_BOOTSTRAP_DIR=$( mktemp -d --tmpdir=${cache_base} bootstrap_XXXXXX )
563
564 cd ${TMP_BOOTSTRAP_DIR}
565
566 mkdir squashfs stage0 stage1 bootstrap
567
568 ### Stage 0 setup.
569 # Download the LiveOS squashfs image
570 # mount image to "squashfs"
571 # mount contained LiveOS to stage0
572
573 # We're going to use the archives.fedoraproject.org mirror for the initial stages...
574 # 1 - It's generally up to date and complete
575 # 2 - It's has high bandwidth access
576 # 3 - It supports rsync and wildcarding (and we need both)
577 # 4 - Not all the mirrors carry the LiveOS images
578
579 if [[ ! -f ../LiveOS/squashfs.img ]]
580 then
581 echo "
582 Downloading stage 0 LiveOS squashfs file system from archives.fedoraproject.org...
583 Have a beer or a cup of coffee. This will take a bit (~300MB).
584 "
585 sleep 3 # let him read it...
586
587 # Right now, we are using Fedora 20 for the inial bootstrap.
588 # We could make this the "current" Fedora rev (F > 15).
589
590 rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/LiveOS .
591
592 if [[ 0 == $? ]]
593 then
594 echo "Download of squashfs image complete."
595 mv LiveOS ..
596 else
597 echo "
598 Download of squashfs image failed.
599 "
600 return 255
601 fi
602 else
603 echo "Using cached stage 0 LiveOS squashfs file system."
604 fi
605
606 mount -o loop ../LiveOS/squashfs.img squashfs
607
608 if [[ $? != 0 ]]
609 then
610 echo "
611 Mount of LiveOS squashfs image failed! You mush have squashfs support
612 available to mount image. Unable to continue. Correct and retry
613 process later! LiveOS image not removed. Process may be rerun
614 without penalty of downloading LiveOS again. If LiveOS is corrupt,
615 remove ${cache_base}/LiveOS before rerunning to redownload.
616 "
617 return 255
618 fi
619
620 mount -o loop squashfs/LiveOS/rootfs.img stage0
621
622 if [[ $? != 0 ]]
623 then
624 echo "
625 Mount of LiveOS stage0 rootfs image failed! LiveOS download may be corrupt.
626 Remove ${cache_base}/LiveOS to force a new download or
627 troubleshoot cached image and then rerun process.
628 "
629 return 255
630 fi
631
632
633 ### Stage 1 setup.
634 # Copy stage0 (which is ro) to stage1 area (rw) for modification.
635 # Unmount stage0 mounts - we're done with stage 0 at this point.
636 # Download our rpm and yum rpm packages.
637 # Force install of rpm and yum into stage1 image (dirty hack!)
638
639 echo "Stage 0 complete, building Stage 1 image...
640 This will take a couple of minutes. Patience..."
641
642 echo "Creating Stage 1 r/w copy of r/o Stage 0 squashfs image from LiveOS."
643
644 rsync -aAHS stage0/. stage1/
645
646 umount stage0
647 umount squashfs
648
649 cd stage1
650
651 # Setup stage1 image with pieces to run installs...
652
653
654 mount -o bind /dev dev
655 mount -t proc proc proc
656 # Always make sure /etc/resolv.conf is up to date in the target!
657 cp /etc/resolv.conf etc/
658
659 mkdir run/install
660
661 echo "Updating Stage 1 image with full rpm and yum packages"
662
663 # Retrieve our 2 rpm packages we need to force down the throat
664 # of this LiveOS image we're camped out on. This is the beginning
665 # of the butt ugly hack. Look close or you may missing it...
666
667 rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/r/rpm-[0-9]* \
668 ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/y/yum-[0-9]* .
669
670 # And here it is...
671 # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
672 chroot . rpm -ivh --nodeps rpm-* yum-*
673 # Did you catch it?
674
675 # The LiveOS image contains rpm (but not rpmdb) and yum (but not
676 # yummain.py - What the hell good does yum do with no
677 # yummain.py?!?! - Sigh...). It contains all the supporting
678 # pieces but the rpm database has not be initialized and it
679 # doesn't know all the dependences (seem to) have been met.
680 # So we do a "--nodeps" rpm install in the chrooted environment
681 # to force the installation of the full rpm and yum packages.
682 #
683 # For the purists - Yes, I know the rpm database is wildly out
684 # of whack now. That's why this is a butt ugly hack / dirty trick.
685 # But, this is just the stage1 image that we are going to discard as
686 # soon as the stage2 image is built, so we don't care. All we care
687 # is that the stage2 image ends up with all the pieces it need to
688 # run yum and rpm and that the stage2 rpm database is coherent.
689 #
690 # NOW we can really go to work!
691
692 ### Stage 2 setup.
693 # Download our Fedora Release rpm packages.
694 # Install fedora-release into bootstrap to initialize fs and databases.
695 # Install rpm, and yum into bootstrap image using yum
696
697 echo "Stage 1 creation complete. Building stage 2 Installation Bootstrap"
698
699 mount -o bind ../bootstrap run/install
700 rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* .
701
702 # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
703 chroot . rpm --root /run/install --nodeps -ivh fedora-release-*
704
705 # yum will take $basearch from host, so force the arch we want
706 sed -i "s|\$basearch|$basearch|" ./run/install/etc/yum.repos.d/*
707
708 chroot . yum -y --nogpgcheck --installroot /run/install install python rpm yum
709
710 umount run/install
711 umount proc
712 umount dev
713
714 # That's it! We should now have a viable installation BOOTSTRAP in
715 # bootstrap We'll do a yum update in that to verify and then
716 # move it to the cache location before cleaning up.
717
718 cd ../bootstrap
719 mount -o bind /dev dev
720 mount -t proc proc proc
721 # Always make sure /etc/resolv.conf is up to date in the target!
722 cp /etc/resolv.conf etc/
723
724 # yum will take $basearch from host, so force the arch we want
725 sed -i "s|\$basearch|$basearch|" ./etc/yum.repos.d/*
726
727 chroot . yum -y update
728
729 RC=$?
730
731 umount proc
732 umount dev
733
734 cd ..
735
736 if [[ ${RC} != 0 ]]
737 then
738 echo "
739 Build of Installation Bootstrap failed. Temp directory
740 not removed so it can be investigated.
741 "
742 return 255
743 fi
744
745 # We know have a working run time environment in rootfs...
746 mv bootstrap ..
747 cd ..
748 rm -rf ${TMP_BOOTSTRAP_DIR}
749
750 echo "
751 Build of Installation Bootstrap complete! We now return you to your
752 normally scheduled template creation.
753 "
754
755 BOOTSTRAP=1
756 BOOTSTRAP_DIR="${cache_base}/bootstrap"
757 BOOTSTRAP_CHROOT="chroot ${BOOTSTRAP_DIR} "
758 BOOTSTRAP_INSTALL_ROOT=/run/install
759
760 return 0
761 }
762
763
764 fedora_bootstrap_mounts()
765 {
766 if [[ ${BOOTSTRAP} -ne 1 ]]
767 then
768 return 0
769 fi
770
771 BOOTSTRAP_CHROOT="chroot ${BOOTSTRAP_DIR} "
772
773 echo "Mounting Bootstrap mount points"
774
775 [[ -d ${BOOTSTRAP_DIR}/run/install ]] || mkdir -p ${BOOTSTRAP_DIR}/run/install
776
777 mount -o bind ${INSTALL_ROOT} ${BOOTSTRAP_DIR}/run/install
778 mount -o bind /dev ${BOOTSTRAP_DIR}/dev
779 mount -t proc proc ${BOOTSTRAP_DIR}/proc
780 # Always make sure /etc/resolv.conf is up to date in the target!
781 cp /etc/resolv.conf ${BOOTSTRAP_DIR}/etc/
782 }
783
784 fedora_bootstrap_umounts()
785 {
786 if [[ ${BOOTSTRAP} -ne 1 ]]
787 then
788 return 0
789 fi
790
791 umount ${BOOTSTRAP_DIR}/proc
792 umount ${BOOTSTRAP_DIR}/dev
793 umount ${BOOTSTRAP_DIR}/run/install
794 }
795
796
797 # This is the code to create the initial roofs for Fedora. It may
798 # require a run time environment by calling the routines above...
799
800 download_fedora()
801 {
802
803 # check the mini fedora was not already downloaded
804 INSTALL_ROOT=$cache/partial
805 mkdir -p $INSTALL_ROOT
806 if [ $? -ne 0 ]; then
807 echo "Failed to create '$INSTALL_ROOT' directory"
808 return 1
809 fi
810
811 # download a mini fedora into a cache
812 echo "Downloading fedora minimal ..."
813
814 # These will get changed if it's decided that we need a
815 # boostrap environment (can not build natively). These
816 # are the defaults for the non-boostrap (native) mode.
817
818 BOOTSTRAP_INSTALL_ROOT=${INSTALL_ROOT}
819 BOOTSTRAP_CHROOT=
820 BOOTSTRAP_DIR=
821
822 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils fedora-release"
823 MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$basearch"
824
825 if [[ ${release} -lt 17 ]]
826 then
827 # The reflects the move of db_dump and db_load from db4_utils to
828 # libdb_utils in Fedora 17 and above and it's inclusion as a dep...
829 # Prior to Fedora 11, we need to explicitly include it!
830 PKG_LIST="${PKG_LIST} db4-utils"
831 fi
832
833 if [[ ${release} -ge 21 ]]
834 then
835 # Since Fedora 21, a separate fedora-repos package is needed.
836 # Before, the information was conained in fedora-release.
837 PKG_LIST="${PKG_LIST} fedora-repos"
838 fi
839
840 DOWNLOAD_OK=no
841
842 # We're splitting the old loop into two loops plus a directory retrival.
843 # First loop... Try and retrive a mirror list with retries and a slight
844 # delay between attempts...
845 for trynumber in 1 2 3 4; do
846 [ $trynumber != 1 ] && echo "Trying again..."
847 # This code is mildly "brittle" in that it assumes a certain
848 # page format and parsing HTML. I've done worse. :-P
849 MIRROR_URLS=$(curl -s -S -f "$MIRRORLIST_URL" | sed -e '/^http:/!d' -e '2,6!d')
850 if [ $? -eq 0 ] && [ -n "$MIRROR_URLS" ]
851 then
852 break
853 fi
854
855 echo "Failed to get a mirror on try $trynumber"
856 sleep 3
857 done
858
859 # This will fall through if we didn't get any URLS above
860 for MIRROR_URL in ${MIRROR_URLS}
861 do
862 if [ "$release" -gt "16" ]; then
863 RELEASE_URL="$MIRROR_URL/Packages/f"
864 else
865 RELEASE_URL="$MIRROR_URL/Packages/"
866 fi
867
868 echo "Fetching release rpm name from $RELEASE_URL..."
869 # This code is mildly "brittle" in that it assumes a certain directory
870 # page format and parsing HTML. I've done worse. :-P
871 RELEASE_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-release-${release}-/!d" -e 's/.*<a href=\"//' -e 's/\">.*//' )
872 if [ $? -ne 0 -o "${RELEASE_RPM}" = "" ]; then
873 echo "Failed to identify fedora release rpm."
874 continue
875 fi
876
877 echo "Fetching fedora release rpm from ${RELEASE_URL}/${RELEASE_RPM}......"
878 curl -L -f "${RELEASE_URL}/${RELEASE_RPM}" > ${INSTALL_ROOT}/${RELEASE_RPM}
879 if [ $? -ne 0 ]; then
880 echo "Failed to download fedora release rpm ${RELEASE_RPM}."
881 continue
882 fi
883
884 # F21 and newer need fedora-repos in addition to fedora-release.
885 if [ "$release" -ge "21" ]; then
886 echo "Fetching repos rpm name from $RELEASE_URL..."
887 REPOS_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-repos-${release}-/!d" -e 's/.*<a href=\"//' -e 's/\">.*//' )
888 if [ $? -ne 0 -o "${REPOS_RPM}" = "" ]; then
889 echo "Failed to identify fedora repos rpm."
890 continue
891 fi
892
893 echo "Fetching fedora repos rpm from ${RELEASE_URL}/${REPOS_RPM}..."
894 curl -L -f "${RELEASE_URL}/${REPOS_RPM}" > ${INSTALL_ROOT}/${REPOS_RPM}
895 if [ $? -ne 0 ]; then
896 echo "Failed to download fedora repos rpm ${RELEASE_RPM}."
897 continue
898 fi
899 fi
900
901
902 DOWNLOAD_OK=yes
903 break
904 done
905
906 if [ $DOWNLOAD_OK != yes ]; then
907 echo "Aborting"
908 return 1
909 fi
910
911 mkdir -p ${INSTALL_ROOT}/var/lib/rpm
912
913 if ! fedora_get_bootstrap
914 then
915 echo "Fedora Bootstrap setup failed"
916 return 1
917 fi
918
919 fedora_bootstrap_mounts
920
921 ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --initdb
922
923 # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
924 ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} --nodeps -ivh ${BOOTSTRAP_INSTALL_ROOT}/${RELEASE_RPM}
925
926 # F21 and newer need fedora-repos in addition to fedora-release...
927 # Note that fedora-release and fedora-system have a mutual dependency.
928 # So installing the reops package after the release package we can
929 # spare one --nodeps.
930 if [ "$release" -ge "21" ]; then
931 ${BOOTSTRAP_CHROOT}rpm --root ${BOOTSTRAP_INSTALL_ROOT} -ivh ${BOOTSTRAP_INSTALL_ROOT}/${REPOS_RPM}
932 fi
933
934 # yum will take $basearch from host, so force the arch we want
935 sed -i "s|\$basearch|$basearch|" ${BOOTSTRAP_DIR}/${BOOTSTRAP_INSTALL_ROOT}/etc/yum.repos.d/*
936
937 ${BOOTSTRAP_CHROOT}yum --installroot ${BOOTSTRAP_INSTALL_ROOT} -y --nogpgcheck install ${PKG_LIST}
938
939 RC=$?
940
941 if [[ ${BOOTSTRAP} -eq 1 ]]
942 then
943 # Here we have a bit of a sticky problem. We MIGHT have just installed
944 # this template cache using versions of yum and rpm in the bootstrap
945 # chroot that use a different database version than the target version.
946 # That can be a very big problem. Solution is to rebuild the rpmdatabase
947 # with the target database now that we are done building the cache. In the
948 # vast majority of cases, this is a do-not-care with no harm done if we
949 # didn't do it. But it catches several corner cases with older unsupported
950 # releases and it really doesn't cost us a lot of time for a one shot
951 # install that will never be done again for this rev.
952 #
953 # Thanks and appreciation to Dwight Engen and the Oracle template for the
954 # database rewrite hint!
955
956 echo "Fixing up rpm databases"
957
958 # Change to our target install directory (if we're not already
959 # there) just to simplify some of the logic to follow...
960 cd ${INSTALL_ROOT}
961
962 rm -f var/lib/rpm/__db*
963 # Programmers Note (warning):
964 #
965 # Pay careful attention to the following commands! It
966 # crosses TWO chroot boundaries linked by a bind mount!
967 # In the bootstrap case, that's the bind mount of ${INSTALL_ROOT}
968 # to the ${BOOTSTRAP_CHROOT}/run/install directory! This is
969 # a deliberate hack across that bind mount to do a database
970 # translation between two environments, neither of which may
971 # be the host environment! It's ugly and hard to follow but,
972 # if you don't understand it, don't mess with it! The pipe
973 # is in host space between the two chrooted environments!
974 # This is also why we cd'ed into the INSTALL_ROOT directory
975 # in advance of this loop, so everything is relative to the
976 # current working directory and congruent with the same working
977 # space in both chrooted environments. The output into the new
978 # db is also done in INSTALL_ROOT space but works in either host
979 # space or INSTALL_ROOT space for the mv, so we don't care. It's
980 # just not obvious what's happening in the db_dump and db_load
981 # commands...
982 #
983 for db in var/lib/rpm/* ; do
984 ${BOOTSTRAP_CHROOT} db_dump ${BOOTSTRAP_INSTALL_ROOT}/$db | chroot . db_load $db.new
985 mv $db.new $db
986 done
987 # finish up by rebuilding the database...
988 # This should be redundant but we do it for completeness and
989 # any corner cases I may have missed...
990 mount -t proc proc proc
991 mount -o bind /dev dev
992 chroot . rpm --rebuilddb
993 umount dev
994 umount proc
995 fi
996
997 fedora_bootstrap_umounts
998
999 if [ ${RC} -ne 0 ]; then
1000 echo "Failed to download the rootfs, aborting."
1001 return 1
1002 fi
1003
1004 mv "$INSTALL_ROOT" "$cache/rootfs"
1005 echo "Download complete."
1006
1007 return 0
1008 }
1009
1010 copy_fedora()
1011 {
1012
1013 # make a local copy of the minifedora
1014 echo -n "Copying rootfs to $rootfs_path ..."
1015 #cp -a $cache/rootfs-$basearch $rootfs_path || return 1
1016 # i prefer rsync (no reason really)
1017 mkdir -p $rootfs_path
1018 rsync -Ha $cache/rootfs/ $rootfs_path/
1019 echo
1020 return 0
1021 }
1022
1023 update_fedora()
1024 {
1025 mount -o bind /dev ${cache}/rootfs/dev
1026 mount -t proc proc ${cache}/rootfs/proc
1027 # Always make sure /etc/resolv.conf is up to date in the target!
1028 cp /etc/resolv.conf ${cache}/rootfs/etc/
1029 chroot ${cache}/rootfs yum -y update
1030 umount ${cache}/rootfs/proc
1031 umount ${cache}/rootfs/dev
1032 }
1033
1034 install_fedora()
1035 {
1036 mkdir -p @LOCALSTATEDIR@/lock/subsys/
1037 (
1038 flock -x 9
1039 if [ $? -ne 0 ]; then
1040 echo "Cache repository is busy."
1041 return 1
1042 fi
1043
1044 echo "Checking cache download in $cache/rootfs ... "
1045 if [ ! -e "$cache/rootfs" ]; then
1046 download_fedora
1047 if [ $? -ne 0 ]; then
1048 echo "Failed to download 'fedora base'"
1049 return 1
1050 fi
1051 else
1052 echo "Cache found. Updating..."
1053 update_fedora
1054 if [ $? -ne 0 ]; then
1055 echo "Failed to update 'fedora base', continuing with last known good cache"
1056 else
1057 echo "Update finished"
1058 fi
1059 fi
1060
1061 echo "Copy $cache/rootfs to $rootfs_path ... "
1062 copy_fedora
1063 if [ $? -ne 0 ]; then
1064 echo "Failed to copy rootfs"
1065 return 1
1066 fi
1067
1068 return 0
1069 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-fedora
1070
1071 return $?
1072 }
1073
1074 # Generate a random hardware (MAC) address composed of FE followed by
1075 # 5 random bytes...
1076 create_hwaddr()
1077 {
1078 openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
1079 }
1080
1081 copy_configuration()
1082 {
1083 mkdir -p $config_path
1084
1085 grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
1086 lxc.rootfs = $rootfs_path
1087 " >> $config_path/config
1088
1089 # The following code is to create static MAC addresses for each
1090 # interface in the container. This code will work for multiple
1091 # interfaces in the default config. It will also strip any
1092 # hwaddr stanzas out of the default config since we can not share
1093 # MAC addresses between containers.
1094 mv $config_path/config $config_path/config.def
1095 while read LINE
1096 do
1097 # This should catch variable expansions from the default config...
1098 if expr "${LINE}" : '.*\$' > /dev/null 2>&1
1099 then
1100 LINE=$(eval "echo \"${LINE}\"")
1101 fi
1102
1103 # There is a tab and a space in the regex bracket below!
1104 # Seems that \s doesn't work in brackets.
1105 KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
1106
1107 if [[ "${KEY}" != "lxc.net.0.hwaddr" ]]
1108 then
1109 echo "${LINE}" >> $config_path/config
1110
1111 if [[ "${KEY}" == "lxc.net.0.link" ]]
1112 then
1113 echo "lxc.net.0.hwaddr = $(create_hwaddr)" >> $config_path/config
1114 fi
1115 fi
1116 done < $config_path/config.def
1117
1118 rm -f $config_path/config.def
1119
1120 if [ -e "@LXCTEMPLATECONFIG@/fedora.common.conf" ]; then
1121 echo "
1122 # Include common configuration
1123 lxc.include = @LXCTEMPLATECONFIG@/fedora.common.conf
1124 " >> $config_path/config
1125 fi
1126
1127 # Append things which require expansion here...
1128 cat <<EOF >> $config_path/config
1129 lxc.arch = $arch
1130 lxc.utsname = $utsname
1131
1132 # When using LXC with apparmor, uncomment the next line to run unconfined:
1133 #lxc.aa_profile = unconfined
1134
1135 # example simple networking setup, uncomment to enable
1136 #lxc.net.0.type = $lxc_network_type
1137 #lxc.net.0.flags = up
1138 #lxc.net.0.link = $lxc_network_link
1139 #lxc.net.0.name = eth0
1140 # Additional example for veth network type
1141 # static MAC address,
1142 #lxc.net.0.hwaddr = 00:16:3e:77:52:20
1143 # persistent veth device name on host side
1144 # Note: This may potentially collide with other containers of same name!
1145 #lxc.net.0.veth.pair = v-$name-e0
1146
1147 EOF
1148
1149 if [ $? -ne 0 ]; then
1150 echo "Failed to add configuration"
1151 return 1
1152 fi
1153
1154 return 0
1155 }
1156
1157 clean()
1158 {
1159
1160 if [ ! -e $cache ]; then
1161 exit 0
1162 fi
1163
1164 # lock, so we won't purge while someone is creating a repository
1165 (
1166 flock -x 9
1167 if [ $? != 0 ]; then
1168 echo "Cache repository is busy."
1169 exit 1
1170 fi
1171
1172 echo -n "Purging the download cache for Fedora-$release..."
1173 rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
1174 exit 0
1175 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-fedora
1176 }
1177
1178 usage()
1179 {
1180 cat <<EOF
1181 usage:
1182 $1 -n|--name=<container_name>
1183 [-p|--path=<path>] [-c|--clean] [-R|--release=<Fedora_release>]
1184 [--fqdn=<network name of container>] [-a|--arch=<arch of the container>]
1185 [--mask-tmp]
1186 [-h|--help]
1187 Mandatory args:
1188 -n,--name container name, used to as an identifier for that container
1189 Optional args:
1190 -p,--path path to where the container will be created,
1191 defaults to @LXCPATH@.
1192 --rootfs path for actual rootfs.
1193 -c,--clean clean the cache
1194 -R,--release Fedora release for the new container.
1195 Defaults to host's release if the host is Fedora.
1196 --fqdn fully qualified domain name (FQDN) for DNS and system naming
1197 -a,--arch Define what arch the container will be [i686,x86_64]
1198 --mask-tmp Prevent systemd from over-mounting /tmp with tmpfs.
1199 -h,--help print this help
1200 EOF
1201 return 0
1202 }
1203
1204 options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,arch:,fqdn:,mask-tmp -- "$@")
1205 if [ $? -ne 0 ]; then
1206 usage $(basename $0)
1207 exit 1
1208 fi
1209
1210 arch=$(uname -m)
1211 masktmp=0
1212
1213 eval set -- "$options"
1214 while true
1215 do
1216 case "$1" in
1217 -h|--help) usage $0 && exit 0;;
1218 -p|--path) path=$2; shift 2;;
1219 --rootfs) rootfs_path=$2; shift 2;;
1220 -n|--name) name=$2; shift 2;;
1221 -c|--clean) clean=1; shift 1;;
1222 -R|--release) release=$2; shift 2;;
1223 -a|--arch) newarch=$2; shift 2;;
1224 --fqdn) utsname=$2; shift 2;;
1225 --mask-tmp) masktmp=1; shift 1;;
1226 --) shift 1; break ;;
1227 *) break ;;
1228 esac
1229 done
1230
1231 if [ ! -z "$clean" -a -z "$path" ]; then
1232 clean || exit 1
1233 exit 0
1234 fi
1235
1236 basearch=${arch}
1237 # Map a few architectures to their generic Fedora repository archs.
1238 # The two ARM archs are a bit of a guesstimate for the v5 and v6
1239 # archs. V6 should have hardware floating point (Rasberry Pi).
1240 # The "arm" arch is safer (no hardware floating point). So
1241 # there may be cases where we "get it wrong" for some v6 other
1242 # than RPi.
1243 case "$arch" in
1244 i686) basearch=i386 ;;
1245 armv3l|armv4l|armv5l) basearch=arm ;;
1246 armv6l|armv7l|armv8l) basearch=armhfp ;;
1247 *) ;;
1248 esac
1249
1250 mirrorurl="archives.fedoraproject.org::fedora-archive"
1251 case "$basearch" in
1252 ppc64|s390x) mirrorurl="archives.fedoraproject.org::fedora-secondary" ;;
1253 *) ;;
1254 esac
1255
1256 # Somebody wants to specify an arch. This is very limited case.
1257 # i386/i586/i686 on i386/x86_64
1258 # - or -
1259 # x86_64 on x86_64
1260 if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
1261 then
1262 case "${newarch}" in
1263 i386|i586|i686)
1264 if [ "${basearch}" = "i386" -o "${basearch}" = "x86_64" ]
1265 then
1266 # Make the arch a generic x86 32 bit...
1267 arch=${newarch}
1268 basearch=i386
1269 else
1270 basearch=bad
1271 fi
1272 ;;
1273 *)
1274 basearch=bad
1275 ;;
1276 esac
1277
1278 if [ "${basearch}" = "bad" ]
1279 then
1280 echo "You cannot build a ${newarch} Fedora container on a ${arch} host. Sorry!"
1281 exit 1
1282 fi
1283 fi
1284
1285 # Allow the cache base to be set by environment variable
1286 cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/fedora/$basearch
1287
1288 # Let's do something better for the initial root password.
1289 # It's not perfect but it will defeat common scanning brute force
1290 # attacks in the case where ssh is exposed. It will also be set to
1291 # expired, forcing the user to change it at first login.
1292 if [ "${root_password}" = "" ]
1293 then
1294 root_password=Root-${name}-${RANDOM}
1295 else
1296 # If it's got a ding in it, try and expand it!
1297 if [ $(expr "${root_password}" : '.*$.') != 0 ]
1298 then
1299 root_password=$(eval echo "${root_password}")
1300 fi
1301
1302 # If it has more than 3 consecutive X's in it, feed it
1303 # through mktemp as a template.
1304 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
1305 then
1306 root_password=$(mktemp -u ${root_password})
1307 fi
1308 fi
1309
1310 if [ -z "${utsname}" ]; then
1311 utsname=${name}
1312 fi
1313
1314 # This follows a standard "resolver" convention that an FQDN must have
1315 # at least two dots or it is considered a local relative host name.
1316 # If it doesn't, append the dns domain name of the host system.
1317 #
1318 # This changes one significant behavior when running
1319 # "lxc_create -n Container_Name" without using the
1320 # --fqdn option.
1321 #
1322 # Old behavior:
1323 # utsname and hostname = Container_Name
1324 # New behavior:
1325 # utsname and hostname = Container_Name.Domain_Name
1326
1327 if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
1328 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
1329 utsname=${utsname}.$(dnsdomainname)
1330 fi
1331 fi
1332
1333 needed_pkgs=""
1334
1335 type curl >/dev/null 2>&1
1336 if [ $? -ne 0 ]; then
1337 needed_pkgs="curl $needed_pkgs"
1338 fi
1339 type openssl >/dev/null 2>&1
1340 if [ $? -ne 0 ]; then
1341 needed_pkgs="openssl $needed_pkgs"
1342 fi
1343
1344 if [ -n "$needed_pkgs" ]; then
1345 echo "Missing commands: $needed_pkgs"
1346 echo "Please install these using \"sudo yum install $needed_pkgs\""
1347 exit 1
1348 fi
1349
1350 if [ -z "$path" ]; then
1351 path=$default_path/$name
1352 fi
1353
1354 if [ -z "$release" ]; then
1355 if [ "$is_fedora" -a "$fedora_host_ver" ]; then
1356 release=$fedora_host_ver
1357 else
1358 echo "This is not a fedora host and release missing, defaulting to 22 use -R|--release to specify release"
1359 release=22
1360 fi
1361 fi
1362
1363 if [ "$(id -u)" != "0" ]; then
1364 echo "This script should be run as 'root'"
1365 exit 1
1366 fi
1367
1368 if [ -z "$rootfs_path" ]; then
1369 rootfs_path=$path/rootfs
1370 # check for 'lxc.rootfs' passed in through default config by lxc-create
1371 if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
1372 rootfs_path=$(sed -e '/^lxc.rootfs\s*=/!d' -e 's/\s*#.*//' \
1373 -e 's/^lxc.rootfs\s*=\s*//' -e q $path/config)
1374 fi
1375 fi
1376 config_path=$path
1377 cache=$cache_base/$release
1378
1379 revert()
1380 {
1381 echo "Interrupted, so cleaning up"
1382 lxc-destroy -n $name
1383 # maybe was interrupted before copy config
1384 rm -rf $path
1385 echo "exiting..."
1386 exit 1
1387 }
1388
1389 trap revert SIGHUP SIGINT SIGTERM
1390
1391 copy_configuration
1392 if [ $? -ne 0 ]; then
1393 echo "failed write configuration file"
1394 exit 1
1395 fi
1396
1397 install_fedora
1398 if [ $? -ne 0 ]; then
1399 echo "failed to install fedora"
1400 exit 1
1401 fi
1402
1403 configure_fedora
1404 if [ $? -ne 0 ]; then
1405 echo "failed to configure fedora for a container"
1406 exit 1
1407 fi
1408
1409 # If the systemd configuration directory exists - set it up for what we need.
1410 if [ -d ${rootfs_path}/etc/systemd/system ]
1411 then
1412 configure_fedora_systemd
1413 fi
1414
1415 # This configuration (rc.sysinit) is not inconsistent with the systemd stuff
1416 # above and may actually coexist on some upgraded systems. Let's just make
1417 # sure that, if it exists, we update this file, even if it's not used...
1418 if [ -f ${rootfs_path}/etc/rc.sysinit ]
1419 then
1420 configure_fedora_init
1421 fi
1422
1423 if [ ! -z "$clean" ]; then
1424 clean || exit 1
1425 exit 0
1426 fi
1427 echo "
1428 Container rootfs and config have been created.
1429 Edit the config file to check/enable networking setup.
1430 "
1431
1432 if [[ -d ${cache_base}/bootstrap ]]
1433 then
1434 echo "You have successfully built a Fedora container and cache. This cache may
1435 be used to create future containers of various revisions. The directory
1436 ${cache_base}/bootstrap contains a bootstrap
1437 which may no longer needed and can be removed.
1438 "
1439 fi
1440
1441 if [[ -e ${cache_base}/LiveOS ]]
1442 then
1443 echo "A LiveOS directory exists at ${cache_base}/LiveOS.
1444 This is only used in the creation of the bootstrap run-time-environment
1445 and may be removed.
1446 "
1447 fi
1448
1449 if [ ${root_display_password} = "yes" ]
1450 then
1451 echo "The temporary password for root is: '$root_password'
1452
1453 You may want to note that password down before starting the container.
1454 "
1455 fi
1456
1457 if [ ${root_store_password} = "yes" ]
1458 then
1459 echo "The temporary root password is stored in:
1460
1461 '${config_path}/tmp_root_pass'
1462 "
1463 fi
1464
1465 if [ ${root_prompt_password} = "yes" ]
1466 then
1467 echo "Invoking the passwd command in the container to set the root password.
1468
1469 chroot ${rootfs_path} passwd
1470 "
1471 chroot ${rootfs_path} passwd
1472 else
1473 if [ ${root_expire_password} = "yes" ]
1474 then
1475 if ( mountpoint -q -- "${rootfs_path}" )
1476 then
1477 echo "To reset the root password, you can do:
1478
1479 lxc-start -n ${name}
1480 lxc-attach -n ${name} -- passwd
1481 lxc-stop -n ${name}
1482 "
1483 else
1484 echo "
1485 The root password is set up as "expired" and will require it to be changed
1486 at first login, which you should do as soon as possible. If you lose the
1487 root password or wish to change it without starting the container, you
1488 can change it from the host by running the following command (which will
1489 also reset the expired flag):
1490
1491 chroot ${rootfs_path} passwd
1492 "
1493 fi
1494 fi
1495 fi