~ubuntu-branches/ubuntu/quantal/lxc/quantal-201206191543

« back to all changes in this revision

Viewing changes to templates/lxc-archlinux.in

  • Committer: Package Import Robot
  • Author(s): Daniel Baumann
  • Date: 2012-03-09 13:05:03 UTC
  • mto: (3.1.38 sid)
  • mto: This revision was merged to the branch mainline in revision 94.
  • Revision ID: package-import@ubuntu.com-20120309130503-j0prgw9tsp967bbv
Tags: upstream-0.8.0~rc1
ImportĀ upstreamĀ versionĀ 0.8.0~rc1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/bin/bash
 
2
 
 
3
#
 
4
# template script for generating Arch linux container for LXC
 
5
#
 
6
 
 
7
#
 
8
# lxc: linux Container library
 
9
 
 
10
# Authors:
 
11
# Alexander Vladimirov <idkfa@vlan1.ru>
 
12
 
 
13
# This library is free software; you can redistribute it and/or
 
14
# modify it under the terms of the GNU Lesser General Public
 
15
# License as published by the Free Software Foundation; either
 
16
# version 2.1 of the License, or (at your option) any later version.
 
17
 
 
18
# This library is distributed in the hope that it will be useful,
 
19
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
21
# Lesser General Public License for more details.
 
22
 
 
23
# You should have received a copy of the GNU Lesser General Public
 
24
# License along with this library; if not, write to the Free Software
 
25
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
26
 
 
27
# defaults
 
28
arch=$(arch)
 
29
cache=/var/cache/lxc/arch/${arch}
 
30
lxc_network_type="veth"
 
31
lxc_network_link="br0"
 
32
default_path=/var/lib/lxc
 
33
default_rc_locale="en-US.UTF-8"
 
34
default_rc_timezone="UTC"
 
35
host_mirror="http://mirrors.kernel.org/archlinux/\$repo/os/$arch"
 
36
 
 
37
# sort of minimal package set
 
38
base_packages=(
 
39
    "filesystem"
 
40
    "initscripts"
 
41
    "coreutils"
 
42
    "module-init-tools"
 
43
    "procps"
 
44
    "psmisc"
 
45
    "pacman"
 
46
    "bash"
 
47
    "syslog-ng"
 
48
    "cronie"
 
49
    "iproute2"
 
50
    "iputils"
 
51
    "inetutils"
 
52
    "dhcpcd"
 
53
    "dnsutils"
 
54
    "nano"
 
55
    "grep"
 
56
    "less"
 
57
    "gawk"
 
58
    "sed"
 
59
    "tar"
 
60
    "wget"
 
61
    "gzip"
 
62
    "which"
 
63
)
 
64
declare -a additional_packages
 
65
 
 
66
[ -f /etc/arch-release ] && is_arch=true
 
67
 
 
68
# find and extract parameter value from given config file
 
69
# ${1} - file to read parameter from
 
70
# ${2} - parameter name
 
71
# ${result} - result value on success
 
72
function read_parameter_value {
 
73
    [ -f ${1} ] && [ "${2}" ] || return 1
 
74
    local pattern="^[[:space:]]*${2}[[:space:]]*=[[:space:]]*"
 
75
    local str=$(grep "${pattern}" "${1}")
 
76
    local str=${str/#$(grep -o "${pattern}" "${1}")/}
 
77
    result=${str//\"/}
 
78
    return 0
 
79
}
 
80
 
 
81
# split comma-separated string into an array
 
82
# ${1} - string to split
 
83
# ${2} - separator (default is ",")
 
84
# ${result} - result value on success
 
85
function split_string {
 
86
    local ifs=${IFS}
 
87
    IFS="${2:-,}"
 
88
    read -a result < <(echo "${1}")
 
89
    IFS=${ifs}
 
90
    return 0
 
91
}
 
92
 
 
93
# Arch-specific preconfiguration for container
 
94
function configure_arch {
 
95
    # read locale and timezone defaults from system rc.conf if running on Arch
 
96
    if [ "${is_arch}" ]; then
 
97
        read_parameter_value "/etc/rc.conf" "LOCALE"
 
98
        rc_locale=${result:-${default_rc_locale}}
 
99
        read_parameter_value "/etc/rc.conf" "TIMEZONE"
 
100
        rc_timezone=${result:-${default_rc_timezone}}
 
101
    else
 
102
        rc_locale=${default_rc_locale}
 
103
        rc_timezone=${default_rc_timezone}
 
104
    fi
 
105
 
 
106
    echo "Setting up rc.conf"
 
107
    cat > "${rootfs_path}/etc/rc.conf" << EOF
 
108
# /etc/rc.conf - Main Configuration for Arch Linux
 
109
LOCALE="${rc_locale}"
 
110
DAEMON_LOCALE="no"
 
111
HARDWARECLOCK="local"
 
112
TIMEZONE="${rc_timezone}"
 
113
KEYMAP=us
 
114
CONSOLEFONT=
 
115
CONSOLEMAP=
 
116
USECOLOR="yes"
 
117
MODULES=()
 
118
HOSTNAME="${name}"
 
119
interface=eth0
 
120
address=
 
121
netmask=
 
122
broadcast=
 
123
gateway=
 
124
DAEMONS=(syslog-ng crond network)
 
125
EOF
 
126
 
 
127
    if [ -e "${rootfs_path}/etc/locale.gen" ]; then
 
128
        sed -i 's@^#\(en_US\.UTF-8\)@\1@' "${rootfs_path}/etc/locale.gen"
 
129
        if [ ! "${rc_locale}" = "en_US.UTF-8" ]; then
 
130
            echo "${rc_locale} ${rc_locale##*.}" >> "${rootfs_path}/etc/locale.gen"
 
131
        fi
 
132
        chroot "${rootfs_path}" locale-gen
 
133
    fi
 
134
    cp "${rootfs_path}/usr/share/zoneinfo/${rc_timezone}" \
 
135
       "${rootfs_path}/etc/localtime"
 
136
 
 
137
    echo "Setting up rc.sysinit"
 
138
    cat > "${rootfs_path}/etc/rc.sysinit.lxc" << EOF
 
139
#!/bin/bash
 
140
. /etc/rc.conf
 
141
. /etc/rc.d/functions
 
142
 
 
143
echo "starting Arch Linux"
 
144
rm -f \$(find /var/run -name '*pid')
 
145
rm -f /run/daemons/*
 
146
rm -f /var/lock/subsys/*
 
147
rm -f /etc/mtab
 
148
touch /etc/mtab
 
149
run_hook sysinit_end
 
150
EOF
 
151
 
 
152
    echo "Setting up rc.shutdown"
 
153
    cat > "${rootfs_path}/etc/rc.shutdown.lxc" << EOF
 
154
#!/bin/bash
 
155
. /etc/rc.conf
 
156
. /etc/rc.d/functions
 
157
stty onlcr
 
158
run_hook shutdown_start
 
159
[[ -x /etc/rc.local.shutdown ]] && /etc/rc.local.shutdown
 
160
stop_all_daemons
 
161
run_hook shutdown_prekillall
 
162
kill_all
 
163
run_hook shutdown_postkillall
 
164
[[ \${TIMEZONE} ]] && cp --remove-destination "/usr/share/zoneinfo/\${TIMEZONE}" /etc/localtime
 
165
halt -w
 
166
umount -a -r -t nodevtmpfs,notmpfs,nosysfs,noproc,nodevpts -O no_netdev
 
167
run_hook shutdown_postumount
 
168
run_hook shutdown_poweroff
 
169
if [[ \${RUNLEVEL} = 0 ]]; then
 
170
    poweroff -d -f -i
 
171
else
 
172
    reboot -d -f -i
 
173
fi
 
174
# vim: set ts=2 sw=2 noet:
 
175
EOF
 
176
    chmod 755 "${rootfs_path}/etc/rc.shutdown.lxc" "${rootfs_path}/etc/rc.sysinit.lxc"
 
177
 
 
178
    echo "Setting up inittab"
 
179
    cat > "${rootfs_path}/etc/inittab" << EOF
 
180
id:3:initdefault:
 
181
rc::sysinit:/etc/rc.sysinit.lxc
 
182
rs:S1:wait:/etc/rc.single
 
183
rm:2345:wait:/etc/rc.multi
 
184
rh:06:wait:/etc/rc.shutdown.lxc
 
185
su:S:wait:/sbin/sulogin -p
 
186
c1:2345:respawn:/sbin/agetty -8 38400 tty1 linux
 
187
EOF
 
188
 
 
189
    echo "Setting up hosts"
 
190
    cat > "${rootfs_path}/etc/hosts" << EOF
 
191
127.0.0.1   localhost.localdomain   localhost ${name}
 
192
::1     localhost.localdomain   localhost
 
193
EOF
 
194
 
 
195
    echo "Setting up nameserver"
 
196
    grep nameserver /etc/resolv.conf > "${rootfs_path}/etc/resolv.conf"
 
197
 
 
198
    echo "Setting up device nodes"
 
199
    mkdir -m 755 "${rootfs_path}/dev/pts"
 
200
    mkdir -m 1777 "${rootfs_path}/dev/shm"
 
201
    mknod -m 666 "${rootfs_path}/dev/null" c 1 3
 
202
    mknod -m 666 "${rootfs_path}/dev/full" c 1 7
 
203
    mknod -m 666 "${rootfs_path}/dev/random" c 1 8
 
204
    mknod -m 666 "${rootfs_path}/dev/urandom" c 1 9
 
205
    mknod -m 666 "${rootfs_path}/dev/tty0" c 4 0
 
206
    mknod -m 666 "${rootfs_path}/dev/tty1" c 4 1
 
207
    mknod -m 666 "${rootfs_path}/dev/tty2" c 4 2
 
208
    mknod -m 666 "${rootfs_path}/dev/tty3" c 4 3
 
209
    mknod -m 666 "${rootfs_path}/dev/tty4" c 4 4
 
210
    mknod -m 600 "${rootfs_path}/dev/initctl" p
 
211
    mknod -m 666 "${rootfs_path}/dev/tty" c 5 0
 
212
    mknod -m 666 "${rootfs_path}/dev/console" c 5 1
 
213
    mknod -m 666 "${rootfs_path}/dev/ptmx" c 5 2
 
214
 
 
215
    return 0
 
216
}
 
217
 
 
218
# write container configuration files
 
219
function copy_configuration {
 
220
    mkdir -p "${config_path}"
 
221
    cat > "${config_path}/config" << EOF
 
222
lxc.utsname=${name}
 
223
lxc.tty=4
 
224
lxc.pts=1024
 
225
lxc.rootfs=${rootfs_path}
 
226
lxc.mount=${config_path}/fstab
 
227
#networking
 
228
lxc.network.type=${lxc_network_type}
 
229
lxc.network.flags=up
 
230
lxc.network.link=${lxc_network_link}
 
231
lxc.network.name=eth0
 
232
lxc.network.mtu=1500
 
233
#cgroups
 
234
lxc.cgroup.devices.deny = a
 
235
# /dev/null and zero
 
236
lxc.cgroup.devices.allow = c 1:3 rwm
 
237
lxc.cgroup.devices.allow = c 1:5 rwm
 
238
# consoles
 
239
lxc.cgroup.devices.allow = c 5:1 rwm
 
240
lxc.cgroup.devices.allow = c 5:0 rwm
 
241
lxc.cgroup.devices.allow = c 4:0 rwm
 
242
lxc.cgroup.devices.allow = c 4:1 rwm
 
243
# /dev/{,u}random
 
244
lxc.cgroup.devices.allow = c 1:9 rwm
 
245
lxc.cgroup.devices.allow = c 1:8 rwm
 
246
# /dev/pts
 
247
lxc.cgroup.devices.allow = c 136:* rwm
 
248
lxc.cgroup.devices.allow = c 5:2 rwm
 
249
# rtc
 
250
lxc.cgroup.devices.allow = c 254:0 rwm
 
251
EOF
 
252
 
 
253
    cat > "${config_path}/fstab" << EOF
 
254
none ${rootfs_path}/dev/pts devpts defaults 0 0
 
255
none ${rootfs_path}/proc proc nodev,noexec,nosuid 0 0
 
256
none ${rootfs_path}/sys sysfs defaults 0 0
 
257
none ${rootfs_path}/dev/shm tmpfs defaults 0 0
 
258
EOF
 
259
 
 
260
    if [ ${?} -ne 0 ]; then
 
261
        echo "Failed to configure container"
 
262
        return 1
 
263
    fi
 
264
 
 
265
    return 0
 
266
}
 
267
 
 
268
# lock chroot and mount subdirectories before installing container
 
269
function mount_chroot {
 
270
    echo "mounting chroot"
 
271
    umask 0022
 
272
    [ -e "${rootfs_path}/sys" ] || mkdir "${rootfs_path}/sys"
 
273
    mount -t sysfs sysfs "${rootfs_path}/sys"
 
274
    [ -e "${rootfs_path}/proc" ] || mkdir "${rootfs_path}/proc"
 
275
    mount -t proc proc "${rootfs_path}/proc"
 
276
    [ -e "${rootfs_path}/dev" ] || mkdir "${rootfs_path}/dev"
 
277
    mount -t tmpfs dev "${rootfs_path}/dev" -o mode=0755,size=10M,nosuid
 
278
    mknod -m 666 "${rootfs_path}/dev/null" c 1 3
 
279
    mknod -m 666 "${rootfs_path}/dev/zero" c 1 5
 
280
    mknod -m 600 "${rootfs_path}/dev/console" c 5 1
 
281
    mknod -m 644 "${rootfs_path}/dev/random" c 1 8
 
282
    mknod -m 644 "${rootfs_path}/dev/urandom" c 1 9
 
283
    mknod -m 666 "${rootfs_path}/dev/tty" c 5 0
 
284
    mknod -m 666 "${rootfs_path}/dev/tty0" c 4 0
 
285
    mknod -m 666 "${rootfs_path}/dev/full" c 1 7
 
286
    ln -s /proc/kcore "${rootfs_path}/dev/core"
 
287
    ln -s /proc/self/fd "${rootfs_path}/dev/fd"
 
288
    ln -s /proc/self/fd/0 "${rootfs_path}/dev/stdin"
 
289
    ln -s /proc/self/fd/1 "${rootfs_path}/dev/stdout"
 
290
    ln -s /proc/self/fd/2 "${rootfs_path}/dev/stderr"
 
291
    [ -e "${rootfs_path}/dev/shm" ] || mkdir "${rootfs_path}/dev/shm"
 
292
    mount -t tmpfs shm "${rootfs_path}/dev/shm" -o nodev,nosuid,size=128M
 
293
    [ -e "${rootfs_path}/dev/pts" ] || mkdir "${rootfs_path}/dev/pts"
 
294
    mount -t devpts devpts "${rootfs_path}/dev/pts" -o newinstance,ptmxmode=666
 
295
    ln -s pts/ptmx "${rootfs_path}/dev/ptmx"
 
296
    [ -e "${cache_dir}" ] || mkdir -p "${cache_dir}"
 
297
    [ -e "${rootfs_path}/${cache_dir}" ] || mkdir -p "${rootfs_path}/${cache_dir}"
 
298
    mount -o bind "${cache_dir}" "${rootfs_path}/${cache_dir}"
 
299
    if [ -n "${host_mirror_path}" ]; then
 
300
        [ -e "${rootfs_path}/${host_mirror_path}" ] || mkdir -p "${rootfs_path}/${host_mirror_path}"
 
301
        mount -o bind "${host_mirror_path}" "${rootfs_path}/${host_mirror_path}"
 
302
        mount -o remount,ro,bind "${host_mirror_path}" "${rootfs_path}/${host_mirror_path}"
 
303
    fi
 
304
    trap 'umount_chroot' EXIT INT QUIT TERM HUP
 
305
}
 
306
 
 
307
function umount_chroot {
 
308
    if [ -z "${umount_done}" ]; then
 
309
        echo "unmounting chroot"
 
310
        umount "${rootfs_path}/proc"
 
311
        umount "${rootfs_path}/sys"
 
312
        umount "${rootfs_path}/dev/pts"
 
313
        umount "${rootfs_path}/dev/shm"
 
314
        umount "${rootfs_path}/dev"
 
315
        umount "${rootfs_path}/${cache_dir}"
 
316
        [ -n "${host_mirror_path}" ] && umount "${rootfs_path}/${host_mirror_path}"
 
317
        umount_done=1
 
318
    fi
 
319
}
 
320
 
 
321
# install packages within container chroot
 
322
function install_arch {
 
323
    pacman_config=$(mktemp)
 
324
 
 
325
    cat <<EOF > "${pacman_config}"
 
326
[options]
 
327
HoldPkg      = pacman glibc
 
328
SyncFirst    = pacman
 
329
Architecture = auto
 
330
#IgnorePkg    = udev
 
331
[core]
 
332
Include = /etc/pacman.d/mirrorlist
 
333
Server = ${host_mirror}
 
334
[extra]
 
335
Include = /etc/pacman.d/mirrorlist
 
336
Server = ${host_mirror}
 
337
[community]
 
338
Include = /etc/pacman.d/mirrorlist
 
339
Server = ${host_mirror}
 
340
EOF
 
341
 
 
342
    mkdir -p "${rootfs_path}/var/lib/pacman/sync"
 
343
    mkdir -p "${rootfs_path}/etc"
 
344
 
 
345
    if echo "${host_mirror}" | grep -q 'file://'; then
 
346
        host_mirror_path=$(echo "${host_mirror}" | sed -E 's#file://(/.*)/\$repo/os/\$arch#\1#g')
 
347
    fi
 
348
    cache_dir=$( (grep -m 1 '^CacheDir' "${pacman_config}" || echo 'CacheDir = /var/cache/pacman/pkg') | sed 's/CacheDir\s*=\s*//')
 
349
    mount_chroot
 
350
    params="--root ${rootfs_path} --config=${pacman_config} --noconfirm"
 
351
    if ! pacman -Sydd ${params} --dbonly udev; then
 
352
        echo "Failed to preinstall udev package record"
 
353
        return 1
 
354
    fi
 
355
    if ! pacman -S ${params} ${base_packages[@]}; then
 
356
        echo "Failed to install container packages"
 
357
        return 1
 
358
    fi
 
359
    [ -d "${rootfs_path}/lib/modules" ] && ldconfig -r "${rootfs_path}"
 
360
    mv "${pacman_config}" "${rootfs_path}/etc/pacman.conf"
 
361
    umount_chroot
 
362
    return 0
 
363
}
 
364
 
 
365
usage()
 
366
{
 
367
    cat <<EOF
 
368
usage:
 
369
    ${1} -n|--name=<container_name>
 
370
        [-P|--packages=<pkg1,pkg2,...>] [-p|--path=<path>] [-h|--help]
 
371
Mandatory args:
 
372
  -n,--name         container name, used to as an identifier for that container from now on
 
373
Optional args:
 
374
  -p,--path         path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case
 
375
  -P,--packages     preinstall additional packages, comma-separated list
 
376
  -h,--help         print this help
 
377
EOF
 
378
    return 0
 
379
}
 
380
 
 
381
options=$(getopt -o hp:P:n:cm: -l help,path:,packages:,name:,clean,mirror: -- "${@}")
 
382
if [ ${?} -ne 0 ]; then
 
383
    usage $(basename ${0})
 
384
    exit 1
 
385
fi
 
386
eval set -- "${options}"
 
387
 
 
388
while true
 
389
do
 
390
    case "${1}" in
 
391
    -h|--help)      usage ${0} && exit 0;;
 
392
    -p|--path)      path=${2}; shift 2;;
 
393
    -n|--name)      name=${2}; shift 2;;
 
394
    -P|--packages)  additional_packages=${2}; shift 2;;
 
395
    -m|--mirror)    host_mirror=${2}; shift 2;;
 
396
    --)             shift 1; break ;;
 
397
    *)              break ;;
 
398
    esac
 
399
done
 
400
 
 
401
if [ -z "${name}" ]; then
 
402
    echo "missing required 'name' parameter"
 
403
    exit 1
 
404
fi
 
405
 
 
406
type pacman >/dev/null 2>&1
 
407
if [ ${?} -ne 0 ]; then
 
408
    echo "'pacman' command is missing, refer to wiki.archlinux.org for information about installing pacman"
 
409
    exit 1
 
410
fi
 
411
 
 
412
if [ -z "${path}" ]; then
 
413
    path="${default_path}/${name}"
 
414
fi
 
415
 
 
416
if [ "${EUID}" != "0" ]; then
 
417
    echo "This script should be run as 'root'"
 
418
    exit 1
 
419
fi
 
420
 
 
421
rootfs_path="${path}/rootfs"
 
422
config_path="${default_path}/${name}"
 
423
 
 
424
revert()
 
425
{
 
426
    echo "Interrupted, so cleaning up"
 
427
    lxc-destroy -n "${name}"
 
428
    # maybe was interrupted before copy config
 
429
    rm -rf "${path}/${name}"
 
430
    rm -rf "${default_path}/${name}"
 
431
    exit 1
 
432
}
 
433
 
 
434
trap revert SIGHUP SIGINT SIGTERM
 
435
 
 
436
copy_configuration
 
437
if [ ${?} -ne 0 ]; then
 
438
    echo "failed write configuration file"
 
439
    rm -rf "${config_path}"
 
440
    exit 1
 
441
fi
 
442
 
 
443
if [ ${#additional_packages[@]} -gt 0 ]; then
 
444
    split_string ${additional_packages}
 
445
    base_packages+=(${result[@]})
 
446
fi
 
447
 
 
448
install_arch
 
449
if [ ${?} -ne 0 ]; then
 
450
    echo "failed to install Arch linux"
 
451
    rm -rf "${config_path}" "${path}"
 
452
    exit 1
 
453
fi
 
454
 
 
455
configure_arch
 
456
if [ ${?} -ne 0 ]; then
 
457
    echo "failed to configure Arch linux for a container"
 
458
    rm -rf "${config_path}" "${path}"
 
459
    exit 1
 
460
fi
 
461
 
 
462
echo "container rootfs and config created"