]> git.proxmox.com Git - mirror_lxc.git/blame - templates/lxc-fedora-legacy.in
lxc-oci: rely on jq instead of sed to transform values
[mirror_lxc.git] / templates / lxc-fedora-legacy.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}
7e1a946f 229DHCP_HOSTNAME=\`hostname\`
579ebf12
I
230NM_CONTROLLED=no
231TYPE=Ethernet
232MTU=${MTU}
54b1eb68 233EOF
54b1eb68 234
b6e91b67 235 # set the hostname
579ebf12
I
236 cat <<EOF > ${rootfs_path}/etc/sysconfig/network
237NETWORKING=yes
b9b3a92f 238HOSTNAME=${utsname}
b6e91b67 239EOF
54b1eb68 240
627fe3b4
MW
241 # set hostname on systemd Fedora systems
242 if [ $release -gt 14 ]; then
b9b3a92f 243 echo "${utsname}" > ${rootfs_path}/etc/hostname
627fe3b4
MW
244 fi
245
579ebf12
I
246 # set minimal hosts
247 cat <<EOF > $rootfs_path/etc/hosts
b9b3a92f 248127.0.0.1 localhost.localdomain localhost $utsname
627fe3b4 249::1 localhost6.localdomain6 localhost6
b6e91b67 250EOF
54b1eb68 251
5266cf0a
MW
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.
579ebf12
I
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
1ecee40b
MW
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/*
42e53c29 279 # since lxc.tty.dir is specified in the config.
1ecee40b
MW
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
b4f7af7a
MW
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
579ebf12 303 echo "root:$root_password" | chroot $rootfs_path chpasswd
826cde7c
MW
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
54b1eb68 310
cb26f1a5 311 # specifying this in the initial packages doesn't always work.
449989ac 312 # Even though it should have...
cb26f1a5 313 echo "installing fedora-release package"
449989ac
MW
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
67660331
MW
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
449989ac
MW
331 umount ${rootfs_path}/proc
332 umount ${rootfs_path}/dev
cb26f1a5
SG
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
b6e91b67
DL
341 return 0
342}
5266cf0a 343
f9d0d2cb
I
344configure_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
cb26f1a5
SG
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
f9d0d2cb
I
351 chroot ${rootfs_path} chkconfig udev-post off
352 chroot ${rootfs_path} chkconfig network on
779b47fd
MW
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#
361start on power-status-changed
362
363exec /sbin/shutdown -h now "SIGPWR received"
364EOF
365 fi
f9d0d2cb
I
366}
367
368configure_fedora_systemd()
369{
b4f7af7a 370 rm -f ${rootfs_path}/etc/systemd/system/default.target
f9d0d2cb 371 touch ${rootfs_path}/etc/fstab
5bb4a226 372 chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/udev.service
f9d0d2cb 373 chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
779b47fd 374 # Make systemd honor SIGPWR
e5469dad 375 chroot ${rootfs_path} ln -s /usr/lib/systemd/system/halt.target /etc/systemd/system/sigpwr.target
c2af3084
MA
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
f9d0d2cb 382 #dependency on a device unit fails it specially that we disabled udev
d1240f03
MW
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=/' \
8983aa6e
SG
395 < ${rootfs_path}/lib/systemd/system/getty\@.service \
396 > ${rootfs_path}/etc/systemd/system/getty\@.service
d1240f03
MW
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 )
f9d0d2cb 401}
54b1eb68 402
449989ac
MW
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.
0655a606 411#
449989ac
MW
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
08754f30 434# given architecture. Note that this only has to run once for
449989ac 435# Fedora on a given architecture since rpm and yum can build other
f71e8f41 436# versions. We'll arbitrarily pick Fedora 20 to build this. This
449989ac
MW
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
ec64264d 445# and controls are self-contained.
449989ac
MW
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=""
456BOOTSTRAP_WHITE_LIST="fedora"
457# BOOTSTRAP_WHITE_LIST="fedora debian ubuntu centos scientific sl nst"
458
459BOOTSTRAP=0
460BOOTSTRAP_DIR=
461BOOTSTRAP_CHROOT=
462
463fedora_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 "
488OS ${ID} is whitelisted. Installation Bootstrap Environment not required.
489"
490 return 0;
491 fi
492 done
493 fi
494
495 echo "
496Fedora Installation Bootstrap Build..."
497
498 if ! which rsync > /dev/null 2>&1
499 then
500 echo "
501Unable to locate rsync. Cravely bailing out before even attempting to build
502an 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...
ec64264d 515 # We'll give a preference for close matches preferring higher over
449989ac
MW
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 \
522bootstrap"
523
524 for bootstrap in ${BOOTSTRAP_LIST}
525 do
526 if [[ -d ${bootstrap} ]]
527 then
528 echo "
529Existing 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 "
550Functional Installation Bootstrap exists and appears to be completed.
551Will use existing Bootstrap: ${BOOTSTRAP_DIR}
552"
553 return 0
554 fi
555 echo "
556Installation Bootstrap in ${BOOTSTRAP_DIR} exists
557but 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
3bca4f5b
NW
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
449989ac
MW
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 "
95658200 582Downloading stage 0 LiveOS squashfs file system from archives.fedoraproject.org...
449989ac
MW
583Have a beer or a cup of coffee. This will take a bit (~300MB).
584"
585 sleep 3 # let him read it...
586
f71e8f41 587 # Right now, we are using Fedora 20 for the inial bootstrap.
449989ac
MW
588 # We could make this the "current" Fedora rev (F > 15).
589
f71e8f41 590 rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/LiveOS .
449989ac
MW
591
592 if [[ 0 == $? ]]
593 then
594 echo "Download of squashfs image complete."
595 mv LiveOS ..
596 else
597 echo "
598Download 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 "
611Mount of LiveOS squashfs image failed! You mush have squashfs support
612available to mount image. Unable to continue. Correct and retry
613process later! LiveOS image not removed. Process may be rerun
614without penalty of downloading LiveOS again. If LiveOS is corrupt,
615remove ${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 "
625Mount of LiveOS stage0 rootfs image failed! LiveOS download may be corrupt.
626Remove ${cache_base}/LiveOS to force a new download or
627troubleshoot 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...
640This 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
f71e8f41
SG
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]* .
449989ac
MW
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
f71e8f41 700 rsync -av ${mirrorurl}/fedora/linux/releases/20/Fedora/$basearch/os/Packages/f/fedora-release-20* .
449989ac
MW
701
702 # The --nodeps is STUPID but F15 had a bogus dependency on RawHide?!?!
703 chroot . rpm --root /run/install --nodeps -ivh fedora-release-*
08754f30
MW
704
705 # yum will take $basearch from host, so force the arch we want
dfb2291e 706 sed -i "s|\$basearch|$basearch|" ./run/install/etc/yum.repos.d/*
08754f30 707
449989ac
MW
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
08754f30
MW
724 # yum will take $basearch from host, so force the arch we want
725 sed -i "s|\$basearch|$basearch|" ./etc/yum.repos.d/*
726
449989ac
MW
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 "
739Build of Installation Bootstrap failed. Temp directory
740not 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 "
751Build of Installation Bootstrap complete! We now return you to your
752normally 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
764fedora_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
784fedora_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
b6e91b67
DL
800download_fedora()
801{
b44cb779 802
b6e91b67 803 # check the mini fedora was not already downloaded
579ebf12
I
804 INSTALL_ROOT=$cache/partial
805 mkdir -p $INSTALL_ROOT
b6e91b67 806 if [ $? -ne 0 ]; then
14d9c0f0
SG
807 echo "Failed to create '$INSTALL_ROOT' directory"
808 return 1
b44cb779
RT
809 fi
810
b6e91b67
DL
811 # download a mini fedora into a cache
812 echo "Downloading fedora minimal ..."
449989ac 813
0655a606 814 # These will get changed if it's decided that we need a
dfb2291e
MW
815 # boostrap environment (can not build natively). These
816 # are the defaults for the non-boostrap (native) mode.
449989ac
MW
817
818 BOOTSTRAP_INSTALL_ROOT=${INSTALL_ROOT}
819 BOOTSTRAP_CHROOT=
dfb2291e 820 BOOTSTRAP_DIR=
449989ac 821
5266cf0a 822 PKG_LIST="yum initscripts passwd rsyslog vim-minimal openssh-server openssh-clients dhclient chkconfig rootfiles policycoreutils fedora-release"
08754f30 823 MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$basearch"
7bd44bf6 824
449989ac
MW
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
afc55ed2
MA
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
7bd44bf6 840 DOWNLOAD_OK=no
b9b3a92f
MW
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
7bd44bf6 846 [ $trynumber != 1 ] && echo "Trying again..."
8983aa6e 847 # This code is mildly "brittle" in that it assumes a certain
b9b3a92f
MW
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
8983aa6e
SG
852 break
853 fi
b9b3a92f
MW
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
449989ac 862 if [ "$release" -gt "16" ]; then
b9b3a92f 863 RELEASE_URL="$MIRROR_URL/Packages/f"
29e18143 864 else
b9b3a92f
MW
865 RELEASE_URL="$MIRROR_URL/Packages/"
866 fi
867
afc55ed2 868 echo "Fetching release rpm name from $RELEASE_URL..."
8983aa6e 869 # This code is mildly "brittle" in that it assumes a certain directory
b9b3a92f 870 # page format and parsing HTML. I've done worse. :-P
8983aa6e 871 RELEASE_RPM=$(curl -L -f "$RELEASE_URL" | sed -e "/fedora-release-${release}-/!d" -e 's/.*<a href=\"//' -e 's/\">.*//' )
b9b3a92f
MW
872 if [ $? -ne 0 -o "${RELEASE_RPM}" = "" ]; then
873 echo "Failed to identify fedora release rpm."
874 continue
29e18143 875 fi
b9b3a92f
MW
876
877 echo "Fetching fedora release rpm from ${RELEASE_URL}/${RELEASE_RPM}......"
878 curl -L -f "${RELEASE_URL}/${RELEASE_RPM}" > ${INSTALL_ROOT}/${RELEASE_RPM}
7bd44bf6 879 if [ $? -ne 0 ]; then
b9b3a92f 880 echo "Failed to download fedora release rpm ${RELEASE_RPM}."
7bd44bf6
TS
881 continue
882 fi
b9b3a92f 883
afc55ed2
MA
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
7bd44bf6
TS
902 DOWNLOAD_OK=yes
903 break
904 done
b9b3a92f 905
7bd44bf6
TS
906 if [ $DOWNLOAD_OK != yes ]; then
907 echo "Aborting"
908 return 1
909 fi
579ebf12 910
449989ac 911 mkdir -p ${INSTALL_ROOT}/var/lib/rpm
579ebf12 912
449989ac
MW
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
afc55ed2 922
449989ac
MW
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}
08754f30 925
afc55ed2
MA
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
08754f30 934 # yum will take $basearch from host, so force the arch we want
dfb2291e 935 sed -i "s|\$basearch|$basearch|" ${BOOTSTRAP_DIR}/${BOOTSTRAP_INSTALL_ROOT}/etc/yum.repos.d/*
08754f30 936
449989ac
MW
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
14d9c0f0
SG
1000 echo "Failed to download the rootfs, aborting."
1001 return 1
54b1eb68
MH
1002 fi
1003
579ebf12 1004 mv "$INSTALL_ROOT" "$cache/rootfs"
b6e91b67 1005 echo "Download complete."
54b1eb68 1006
b6e91b67
DL
1007 return 0
1008}
54b1eb68 1009
b6e91b67
DL
1010copy_fedora()
1011{
54b1eb68 1012
b6e91b67 1013 # make a local copy of the minifedora
579ebf12 1014 echo -n "Copying rootfs to $rootfs_path ..."
08754f30 1015 #cp -a $cache/rootfs-$basearch $rootfs_path || return 1
579ebf12
I
1016 # i prefer rsync (no reason really)
1017 mkdir -p $rootfs_path
6273aef1 1018 rsync -SHaAX $cache/rootfs/ $rootfs_path/
b4f7af7a 1019 echo
b6e91b67 1020 return 0
54b1eb68
MH
1021}
1022
579ebf12
I
1023update_fedora()
1024{
449989ac
MW
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
579ebf12
I
1032}
1033
b6e91b67
DL
1034install_fedora()
1035{
e29bf450 1036 mkdir -p @LOCALSTATEDIR@/lock/subsys/
b6e91b67 1037 (
1ecee40b 1038 flock -x 9
14d9c0f0
SG
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
579ebf12 1051 else
14d9c0f0 1052 echo "Cache found. Updating..."
579ebf12 1053 update_fedora
14d9c0f0
SG
1054 if [ $? -ne 0 ]; then
1055 echo "Failed to update 'fedora base', continuing with last known good cache"
579ebf12
I
1056 else
1057 echo "Update finished"
14d9c0f0
SG
1058 fi
1059 fi
54b1eb68 1060
14d9c0f0
SG
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
54b1eb68 1067
14d9c0f0 1068 return 0
1ecee40b 1069 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-fedora
54b1eb68 1070
b6e91b67 1071 return $?
54b1eb68
MH
1072}
1073
b4f7af7a
MW
1074# Generate a random hardware (MAC) address composed of FE followed by
1075# 5 random bytes...
1076create_hwaddr()
b6e91b67 1077{
08754f30 1078 openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
b4f7af7a 1079}
54b1eb68 1080
b4f7af7a
MW
1081copy_configuration()
1082{
579ebf12 1083 mkdir -p $config_path
b4f7af7a 1084
7a96a068
CB
1085 grep -q "^lxc.rootfs.path" $config_path/config 2>/dev/null || echo "
1086lxc.rootfs.path = $rootfs_path
b4f7af7a
MW
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
7fa3f2e9 1107 if [[ "${KEY}" != "lxc.net.0.hwaddr" ]]
b4f7af7a
MW
1108 then
1109 echo "${LINE}" >> $config_path/config
1110
7fa3f2e9 1111 if [[ "${KEY}" == "lxc.net.0.link" ]]
b4f7af7a 1112 then
7fa3f2e9 1113 echo "lxc.net.0.hwaddr = $(create_hwaddr)" >> $config_path/config
b4f7af7a
MW
1114 fi
1115 fi
1116 done < $config_path/config.def
1117
1118 rm -f $config_path/config.def
1119
1ecee40b
MW
1120 if [ -e "@LXCTEMPLATECONFIG@/fedora.common.conf" ]; then
1121 echo "
1122# Include common configuration
1123lxc.include = @LXCTEMPLATECONFIG@/fedora.common.conf
1124" >> $config_path/config
1125 fi
1126
1127 # Append things which require expansion here...
579ebf12 1128 cat <<EOF >> $config_path/config
e13923c7 1129lxc.arch = $arch
b67771bc 1130lxc.uts.name = $utsname
f02ce27d
SG
1131
1132# When using LXC with apparmor, uncomment the next line to run unconfined:
a1d5fdfd 1133#lxc.apparmor.profile = unconfined
f02ce27d 1134
b4f7af7a 1135# example simple networking setup, uncomment to enable
7fa3f2e9 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
b4f7af7a
MW
1140# Additional example for veth network type
1141# static MAC address,
7fa3f2e9 1142#lxc.net.0.hwaddr = 00:16:3e:77:52:20
b4f7af7a
MW
1143# persistent veth device name on host side
1144# Note: This may potentially collide with other containers of same name!
7fa3f2e9 1145#lxc.net.0.veth.pair = v-$name-e0
b4f7af7a 1146
a30ce0ac 1147EOF
b4f7af7a 1148
b6e91b67 1149 if [ $? -ne 0 ]; then
14d9c0f0
SG
1150 echo "Failed to add configuration"
1151 return 1
b6e91b67 1152 fi
54b1eb68 1153
b6e91b67 1154 return 0
54b1eb68
MH
1155}
1156
b6e91b67
DL
1157clean()
1158{
54b1eb68 1159
b6e91b67 1160 if [ ! -e $cache ]; then
14d9c0f0 1161 exit 0
54b1eb68
MH
1162 fi
1163
1164 # lock, so we won't purge while someone is creating a repository
1165 (
1ecee40b 1166 flock -x 9
14d9c0f0
SG
1167 if [ $? != 0 ]; then
1168 echo "Cache repository is busy."
1169 exit 1
1170 fi
54b1eb68 1171
14d9c0f0
SG
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
1ecee40b 1175 ) 9>@LOCALSTATEDIR@/lock/subsys/lxc-fedora
b6e91b67
DL
1176}
1177
1178usage()
1179{
1180 cat <<EOF
579ebf12
I
1181usage:
1182 $1 -n|--name=<container_name>
fccc348b
MA
1183 [-p|--path=<path>] [-c|--clean] [-R|--release=<Fedora_release>]
1184 [--fqdn=<network name of container>] [-a|--arch=<arch of the container>]
c2af3084 1185 [--mask-tmp]
579ebf12
I
1186 [-h|--help]
1187Mandatory args:
fccc348b 1188 -n,--name container name, used to as an identifier for that container
579ebf12 1189Optional args:
fccc348b
MA
1190 -p,--path path to where the container will be created,
1191 defaults to @LXCPATH@.
1897e3bc 1192 --rootfs path for actual rootfs.
579ebf12 1193 -c,--clean clean the cache
fccc348b
MA
1194 -R,--release Fedora release for the new container.
1195 Defaults to host's release if the host is Fedora.
b9b3a92f 1196 --fqdn fully qualified domain name (FQDN) for DNS and system naming
08754f30 1197 -a,--arch Define what arch the container will be [i686,x86_64]
c2af3084 1198 --mask-tmp Prevent systemd from over-mounting /tmp with tmpfs.
579ebf12 1199 -h,--help print this help
b6e91b67
DL
1200EOF
1201 return 0
54b1eb68
MH
1202}
1203
c2af3084 1204options=$(getopt -o a:hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,arch:,fqdn:,mask-tmp -- "$@")
b6e91b67
DL
1205if [ $? -ne 0 ]; then
1206 usage $(basename $0)
1207 exit 1
1208fi
b6e91b67 1209
4849ab99 1210arch=$(uname -m)
c2af3084
MA
1211masktmp=0
1212
08754f30 1213eval set -- "$options"
b6e91b67
DL
1214while true
1215do
1216 case "$1" in
14d9c0f0
SG
1217 -h|--help) usage $0 && exit 0;;
1218 -p|--path) path=$2; shift 2;;
9f177a00 1219 --rootfs) rootfs_path=$2; shift 2;;
14d9c0f0 1220 -n|--name) name=$2; shift 2;;
98d316e2 1221 -c|--clean) clean=1; shift 1;;
579ebf12 1222 -R|--release) release=$2; shift 2;;
08754f30 1223 -a|--arch) newarch=$2; shift 2;;
b9b3a92f 1224 --fqdn) utsname=$2; shift 2;;
c2af3084 1225 --mask-tmp) masktmp=1; shift 1;;
14d9c0f0 1226 --) shift 1; break ;;
b6e91b67
DL
1227 *) break ;;
1228 esac
1229done
1230
1231if [ ! -z "$clean" -a -z "$path" ]; then
1232 clean || exit 1
1233 exit 0
1234fi
1235
08754f30
MW
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
f71e8f41 1250mirrorurl="archives.fedoraproject.org::fedora-archive"
e97aa817 1251case "$basearch" in
f71e8f41 1252ppc64|s390x) mirrorurl="archives.fedoraproject.org::fedora-secondary" ;;
e97aa817
LV
1253*) ;;
1254esac
1255
08754f30
MW
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
1260if [ "${newarch}" != "" -a "${newarch}" != "${arch}" ]
1261then
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
1283fi
1284
6dc6f80b
KC
1285# Allow the cache base to be set by environment variable
1286cache_base=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/fedora/$basearch
08754f30 1287
b4f7af7a
MW
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.
1292if [ "${root_password}" = "" ]
1293then
1294 root_password=Root-${name}-${RANDOM}
1295else
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
ec64264d 1302 # If it has more than 3 consecutive X's in it, feed it
b4f7af7a
MW
1303 # through mktemp as a template.
1304 if [ $(expr "${root_password}" : '.*XXXX') != 0 ]
1305 then
1306 root_password=$(mktemp -u ${root_password})
1307 fi
1308fi
1309
b9b3a92f
MW
1310if [ -z "${utsname}" ]; then
1311 utsname=${name}
1312fi
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
1327if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
b4f7af7a 1328 if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
b9b3a92f
MW
1329 utsname=${utsname}.$(dnsdomainname)
1330 fi
1331fi
1332
cb26f1a5 1333needed_pkgs=""
cb26f1a5
SG
1334
1335type curl >/dev/null 2>&1
1336if [ $? -ne 0 ]; then
1337 needed_pkgs="curl $needed_pkgs"
1338fi
51f88c5c
ER
1339type openssl >/dev/null 2>&1
1340if [ $? -ne 0 ]; then
1341 needed_pkgs="openssl $needed_pkgs"
1342fi
cb26f1a5
SG
1343
1344if [ -n "$needed_pkgs" ]; then
1345 echo "Missing commands: $needed_pkgs"
627fe3b4 1346 echo "Please install these using \"sudo yum install $needed_pkgs\""
b6e91b67
DL
1347 exit 1
1348fi
1349
1350if [ -z "$path" ]; then
5bb4a226 1351 path=$default_path/$name
579ebf12
I
1352fi
1353
1354if [ -z "$release" ]; then
627fe3b4
MW
1355 if [ "$is_fedora" -a "$fedora_host_ver" ]; then
1356 release=$fedora_host_ver
579ebf12 1357 else
29be874c
SG
1358 echo "This is not a fedora host and release missing, defaulting to 22 use -R|--release to specify release"
1359 release=22
579ebf12 1360 fi
b6e91b67
DL
1361fi
1362
54b1eb68 1363if [ "$(id -u)" != "0" ]; then
b6e91b67
DL
1364 echo "This script should be run as 'root'"
1365 exit 1
1366fi
1367
1897e3bc
SH
1368if [ -z "$rootfs_path" ]; then
1369 rootfs_path=$path/rootfs
7a96a068
CB
1370 # check for 'lxc.rootfs.path' passed in through default config by lxc-create
1371 if grep -q '^lxc.rootfs.path' $path/config 2>/dev/null ; then
1372 rootfs_path=$(sed -e '/^lxc.rootfs.path\s*=/!d' -e 's/\s*#.*//' \
1373 -e 's/^lxc.rootfs.path\s*=\s*//' -e q $path/config)
1897e3bc 1374 fi
cb26f1a5 1375fi
08754f30 1376config_path=$path
579ebf12
I
1377cache=$cache_base/$release
1378
29ec8f84
RH
1379revert()
1380{
1381 echo "Interrupted, so cleaning up"
1382 lxc-destroy -n $name
1383 # maybe was interrupted before copy config
f9d0d2cb 1384 rm -rf $path
29ec8f84
RH
1385 echo "exiting..."
1386 exit 1
1387}
1388
1389trap revert SIGHUP SIGINT SIGTERM
1390
1391copy_configuration
1392if [ $? -ne 0 ]; then
1393 echo "failed write configuration file"
1394 exit 1
1395fi
1396
579ebf12 1397install_fedora
b6e91b67
DL
1398if [ $? -ne 0 ]; then
1399 echo "failed to install fedora"
1400 exit 1
54b1eb68
MH
1401fi
1402
579ebf12 1403configure_fedora
b6e91b67
DL
1404if [ $? -ne 0 ]; then
1405 echo "failed to configure fedora for a container"
1406 exit 1
1407fi
1408
bf7d3153
MW
1409# If the systemd configuration directory exists - set it up for what we need.
1410if [ -d ${rootfs_path}/etc/systemd/system ]
1411then
f9d0d2cb
I
1412 configure_fedora_systemd
1413fi
b6e91b67 1414
bf7d3153
MW
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...
1418if [ -f ${rootfs_path}/etc/rc.sysinit ]
1419then
1420 configure_fedora_init
1421fi
1422
9aed78fa 1423if [ ! -z "$clean" ]; then
b6e91b67
DL
1424 clean || exit 1
1425 exit 0
1426fi
b4f7af7a
MW
1427echo "
1428Container rootfs and config have been created.
1429Edit the config file to check/enable networking setup.
1430"
449989ac
MW
1431
1432if [[ -d ${cache_base}/bootstrap ]]
1433then
b4f7af7a 1434 echo "You have successfully built a Fedora container and cache. This cache may
449989ac
MW
1435be used to create future containers of various revisions. The directory
1436${cache_base}/bootstrap contains a bootstrap
1437which may no longer needed and can be removed.
1438"
1439fi
1440
1441if [[ -e ${cache_base}/LiveOS ]]
1442then
1443 echo "A LiveOS directory exists at ${cache_base}/LiveOS.
1444This is only used in the creation of the bootstrap run-time-environment
1445and may be removed.
1446"
1447fi
b4f7af7a
MW
1448
1449if [ ${root_display_password} = "yes" ]
1450then
1451 echo "The temporary password for root is: '$root_password'
1452
1453You may want to note that password down before starting the container.
1454"
1455fi
1456
1457if [ ${root_store_password} = "yes" ]
1458then
1459 echo "The temporary root password is stored in:
1460
1461 '${config_path}/tmp_root_pass'
1462"
1463fi
1464
1465if [ ${root_prompt_password} = "yes" ]
1466then
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
1472else
826cde7c
MW
1473 if [ ${root_expire_password} = "yes" ]
1474 then
d510d522
NW
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 "
b4f7af7a
MW
1485The root password is set up as "expired" and will require it to be changed
1486at first login, which you should do as soon as possible. If you lose the
1487root password or wish to change it without starting the container, you
1488can change it from the host by running the following command (which will
1489also reset the expired flag):
1490
1491 chroot ${rootfs_path} passwd
1492"
d510d522 1493 fi
826cde7c 1494 fi
b4f7af7a 1495fi