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