]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-alpine.in
Fix get_config_item for sys:mixed
[mirror_lxc.git] / templates / lxc-alpine.in
1 #!/bin/sh
2
3 # Detect use under userns (unsupported)
4 for arg in "$@"; do
5 [ "$arg" = "--" ] && break
6 if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
7 echo "This template can't be used for unprivileged containers." 1>&2
8 echo "You may want to try the \"download\" template instead." 1>&2
9 exit 1
10 fi
11 done
12
13 # Make sure the usual locations are in PATH
14 PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
15 export PATH
16
17 key_sha256sums="9c102bcc376af1498d549b77bdbfa815ae86faa1d2d82f040e616b18ef2df2d4 alpine-devel@lists.alpinelinux.org-4a6a0840.rsa.pub
18 2adcf7ce224f476330b5360ca5edb92fd0bf91c92d83292ed028d7c4e26333ab alpine-devel@lists.alpinelinux.org-4d07755e.rsa.pub
19 ebf31683b56410ecc4c00acd9f6e2839e237a3b62b5ae7ef686705c7ba0396a9 alpine-devel@lists.alpinelinux.org-5243ef4b.rsa.pub
20 1bb2a846c0ea4ca9d0e7862f970863857fc33c32f5506098c636a62a726a847b alpine-devel@lists.alpinelinux.org-524d27bb.rsa.pub
21 12f899e55a7691225603d6fb3324940fc51cd7f133e7ead788663c2b7eecb00c alpine-devel@lists.alpinelinux.org-5261cecb.rsa.pub"
22
23
24 get_static_apk () {
25 wget="wget -q -O -"
26 pkglist=alpine-keys:apk-tools-static
27 auto_repo_dir=
28
29 if [ -z "$repository" ]; then
30 url=http://wiki.alpinelinux.org/cgi-bin/dl.cgi
31 yaml_path="latest-stable/releases/$apk_arch/latest-releases.yaml"
32 if [ -z "$release" ]; then
33 echo -n "Determining the latest release... "
34 release=$($wget $url/$yaml_path | \
35 awk '$1 == "branch:" {print $2; exit 0}')
36 if [ -z "$release" ]; then
37 release=$($wget $url/.latest.$apk_arch.txt | \
38 cut -d " " -f 3 | cut -d / -f 1 | uniq)
39 fi
40 if [ -z "$release" ]; then
41 echo failed
42 return 1
43 fi
44 echo $release
45 fi
46 auto_repo_dir=$release/main
47 repository=$url/$auto_repo_dir
48 pkglist=$pkglist:alpine-mirrors
49 fi
50
51 rootfs="$1"
52 echo "Using static apk from $repository/$apk_arch"
53 wget="$wget $repository/$apk_arch"
54
55 # parse APKINDEX to find the current versions
56 static_pkgs=$($wget/APKINDEX.tar.gz | \
57 tar -Oxz APKINDEX | \
58 awk -F: -v pkglist=$pkglist '
59 BEGIN { split(pkglist,pkg) }
60 $0 != "" { f[$1] = $2 }
61 $0 == "" { for (i in pkg)
62 if (pkg[i] == f["P"])
63 print(f["P"] "-" f["V"] ".apk") }')
64 [ "$static_pkgs" ] || return 1
65
66 mkdir -p "$rootfs" || return 1
67 for pkg in $static_pkgs; do
68 echo "Downloading $pkg"
69 $wget/$pkg | tar -xz -C "$rootfs"
70 done
71
72 # clean up .apk meta files
73 rm -f "$rootfs"/.[A-Z]*
74
75 # verify checksum of the key
76 keyname=$(echo $rootfs/sbin/apk.static.*.pub | sed 's/.*\.SIGN\.RSA\.//')
77 checksum=$(echo "$key_sha256sums" | grep -w "$keyname")
78 if [ -z "$checksum" ]; then
79 echo "ERROR: checksum is missing for $keyname"
80 return 1
81 fi
82 (cd $rootfs/etc/apk/keys && echo "$checksum" | sha256sum -c -) || return 1
83
84 # verify the static apk binary signature
85 APK=$rootfs/sbin/apk.static
86 openssl dgst -verify $rootfs/etc/apk/keys/$keyname \
87 -signature "$APK.SIGN.RSA.$keyname" "$APK" || return 1
88
89 if [ "$auto_repo_dir" ]; then
90 mirror_list=$rootfs/usr/share/alpine-mirrors/MIRRORS.txt
91 mirror_count=$(wc -l $mirror_list | cut -d " " -f 1)
92 random=$(hexdump -n 2 -e '/2 "%u"' /dev/urandom)
93 repository=$(sed $(expr $random % $mirror_count + 1)\!d \
94 $mirror_list)$auto_repo_dir
95 echo "Selecting mirror $repository"
96 fi
97 }
98
99 install_alpine() {
100 rootfs="$1"
101 shift
102 mkdir -p "$rootfs"/etc/apk || return 1
103 : ${keys_dir:=/etc/apk/keys}
104 if ! [ -d "$rootfs"/etc/apk/keys ] && [ -d "$keys_dir" ]; then
105 cp -r "$keys_dir" "$rootfs"/etc/apk/keys
106 fi
107 if [ -n "$repository" ]; then
108 echo "$repository" > "$rootfs"/etc/apk/repositories
109 else
110 cp /etc/apk/repositories "$rootfs"/etc/apk/repositories || return 1
111 if [ -n "$release" ]; then
112 sed -i -e "s:/[^/]\+/\([^/]\+\)$:/$release/\1:" \
113 "$rootfs"/etc/apk/repositories
114 fi
115 fi
116 opt_arch=
117 if [ -n "$apk_arch" ]; then
118 opt_arch="--arch $apk_arch"
119 fi
120 $APK add -U --initdb --root $rootfs $opt_arch "$@" alpine-base
121 }
122
123 configure_alpine() {
124 rootfs="$1"
125 echo "Setting up /etc/inittab"
126 cat >"$rootfs"/etc/inittab<<EOF
127 ::sysinit:/sbin/rc sysinit
128 ::wait:/sbin/rc default
129 console:12345:respawn:/sbin/getty 38400 console
130 tty1:12345:respawn:/sbin/getty 38400 tty1
131 tty2:12345:respawn:/sbin/getty 38400 tty2
132 tty3:12345:respawn:/sbin/getty 38400 tty3
133 tty4:12345:respawn:/sbin/getty 38400 tty4
134 ::ctrlaltdel:/sbin/reboot
135 ::shutdown:/sbin/rc shutdown
136 EOF
137 # set up timezone
138 if [ -f /etc/TZ ]; then
139 cp /etc/TZ "$rootfs/etc/TZ"
140 fi
141
142 # set up nameserver
143 grep nameserver /etc/resolv.conf > "$rootfs/etc/resolv.conf"
144
145 # configure the network using the dhcp
146 cat <<EOF > $rootfs/etc/network/interfaces
147 auto lo
148 iface lo inet loopback
149
150 auto eth0
151 iface eth0 inet dhcp
152 EOF
153
154 # set the hostname
155 echo $hostname > $rootfs/etc/hostname
156
157 # missing device nodes
158 echo "Setting up device nodes"
159 mkdir -p -m 755 "$rootfs/dev/pts"
160 mkdir -p -m 1777 "$rootfs/dev/shm"
161 mknod -m 666 "$rootfs/dev/zero" c 1 5
162 mknod -m 666 "$rootfs/dev/full" c 1 7
163 mknod -m 666 "$rootfs/dev/random" c 1 8
164 mknod -m 666 "$rootfs/dev/urandom" c 1 9
165 mknod -m 666 "$rootfs/dev/tty0" c 4 0
166 mknod -m 666 "$rootfs/dev/tty1" c 4 1
167 mknod -m 666 "$rootfs/dev/tty2" c 4 2
168 mknod -m 666 "$rootfs/dev/tty3" c 4 3
169 mknod -m 666 "$rootfs/dev/tty4" c 4 4
170 # mknod -m 600 "$rootfs/dev/initctl" p
171 mknod -m 666 "$rootfs/dev/tty" c 5 0
172 mknod -m 666 "$rootfs/dev/console" c 5 1
173 mknod -m 666 "$rootfs/dev/ptmx" c 5 2
174
175 # start services
176 ln -s /etc/init.d/bootmisc "$rootfs"/etc/runlevels/boot/bootmisc
177 ln -s /etc/init.d/syslog "$rootfs"/etc/runlevels/boot/syslog
178
179 return 0
180 }
181
182 copy_configuration() {
183 path=$1
184 rootfs=$2
185 hostname=$3
186
187 grep -q "^lxc.rootfs" $path/config 2>/dev/null \
188 || echo "lxc.rootfs = $rootfs" >> $path/config
189 if [ -n "$lxc_arch" ]; then
190 echo "lxc.arch = $lxc_arch" >> $path/config
191 fi
192
193 lxc_network_link_line="# lxc.network.link = br0"
194 for br in lxcbr0 virbr0 br0; do
195 if [ -d /sys/class/net/$br/bridge ]; then
196 lxc_network_link_line="lxc.network.link = $br"
197 break
198 fi
199 done
200
201 if ! grep -q "^lxc.network.type" $path/config 2>/dev/null; then
202 cat <<EOF >> $path/config
203 lxc.network.type = veth
204 $lxc_network_link_line
205 lxc.network.flags = up
206 EOF
207 fi
208
209 # if there is exactly one veth or macvlan network entry, make sure
210 # it has an associated mac address.
211 nics=$(awk -F '[ \t]*=[ \t]*' \
212 '$1=="lxc.network.type" && ($2=="veth" || $2=="macvlan") {print $2}' \
213 $path/config | wc -l)
214 if [ "$nics" -eq 1 ] && ! grep -q "^lxc.network.hwaddr" $path/config; then
215 # see http://sourceforge.net/tracker/?func=detail&aid=3411497&group_id=163076&atid=826303
216 hwaddr="fe:$(dd if=/dev/urandom bs=8 count=1 2>/dev/null |od -t x8 | \
217 head -n 1 |awk '{print $2}' | cut -c1-10 |\
218 sed 's/\(..\)/\1:/g; s/.$//')"
219 echo "lxc.network.hwaddr = $hwaddr" >> $path/config
220 fi
221
222 cat <<EOF >> $path/config
223
224 lxc.tty = 4
225 lxc.pts = 1024
226 lxc.utsname = $hostname
227 lxc.cap.drop = sys_module mac_admin mac_override sys_time sys_admin
228
229 # When using LXC with apparmor, uncomment the next line to run unconfined:
230 #lxc.aa_profile = unconfined
231
232 # devices
233 lxc.cgroup.devices.deny = a
234 # /dev/null, zero and full
235 lxc.cgroup.devices.allow = c 1:3 rwm
236 lxc.cgroup.devices.allow = c 1:5 rwm
237 lxc.cgroup.devices.allow = c 1:7 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 lxc.cgroup.devices.allow = c 136:* rwm
247 lxc.cgroup.devices.allow = c 5:2 rwm
248 # rtc
249 lxc.cgroup.devices.allow = c 254:0 rm
250
251 # mounts point
252 lxc.mount.auto=cgroup:mixed proc:mixed sys:mixed
253 lxc.mount.entry=run run tmpfs nodev,noexec,nosuid,relatime,size=1m,mode=0755 0 0
254 lxc.mount.entry=shm dev/shm tmpfs nodev,nosuid,noexec,mode=1777 0 0
255
256 EOF
257
258 return 0
259 }
260
261 die() {
262 echo "$@" >&2
263 exit 1
264 }
265
266 usage() {
267 cat >&2 <<EOF
268 Usage: $(basename $0) [-h|--help] [-r|--repository <url>]
269 [-R|--release <release>] [-a|--arch <arch>]
270 [--rootfs <rootfs>] -p|--path <path> -n|--name <name>
271 [PKG...]
272 EOF
273 }
274
275 usage_err() {
276 usage
277 exit 1
278 }
279
280 optarg_check() {
281 if [ -z "$2" ]; then
282 usage_err "option '$1' requires an argument"
283 fi
284 }
285
286 default_path=@LXCPATH@
287 release=
288 arch=$(uname -m)
289
290 # template mknods, requires root
291 if [ $(id -u) -ne 0 ]; then
292 echo "$(basename $0): must be run as root" >&2
293 exit 1
294 fi
295
296 while [ $# -gt 0 ]; do
297 opt="$1"
298 shift
299 case "$opt" in
300 -h|--help)
301 usage
302 exit 0
303 ;;
304 -n|--name)
305 optarg_check $opt "$1"
306 name=$1
307 shift
308 ;;
309 --rootfs)
310 optarg_check $opt "$1"
311 rootfs=$1
312 shift
313 ;;
314 -p|--path)
315 optarg_check $opt "$1"
316 path=$1
317 shift
318 ;;
319 -r|--repository)
320 optarg_check $opt "$1"
321 repository=$1
322 shift
323 ;;
324 -R|--release)
325 optarg_check $opt "$1"
326 release=$1
327 shift
328 ;;
329 -a|--arch)
330 optarg_check $opt "$1"
331 arch=$1
332 shift
333 ;;
334 --)
335 break;;
336 --*=*)
337 # split --myopt=foo=bar into --myopt foo=bar
338 set -- ${opt%=*} ${opt#*=} "$@"
339 ;;
340 -?)
341 usage_err "unknown option '$opt'"
342 ;;
343 -*)
344 # split opts -abc into -a -b -c
345 set -- $(echo "${opt#-}" | sed 's/\(.\)/ -\1/g') "$@"
346 ;;
347 esac
348 done
349
350
351 [ -z "$name" ] && usage_err
352
353 if [ -z "${path}" ]; then
354 path="${default_path}/${name}"
355 fi
356
357 if [ -z "$rootfs" ]; then
358 rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 2>/dev/null`
359 if [ -z "$rootfs" ]; then
360 rootfs="${path}/rootfs"
361 fi
362 fi
363
364 lxc_arch=$arch
365 apk_arch=$arch
366
367 case "$arch" in
368 i[3-6]86)
369 apk_arch=x86
370 lxc_arch=x86
371 ;;
372 x86)
373 lxc_arch=i686
374 ;;
375 x86_64|"")
376 ;;
377 arm*)
378 apk_arch=armhf
379 ;;
380 *)
381 die "unsupported architecture: $arch"
382 ;;
383 esac
384
385 : ${APK:=apk}
386 if ! which $APK >/dev/null; then
387 get_static_apk "$rootfs" || die "Failed to download a valid static apk"
388 fi
389
390 install_alpine "$rootfs" "$@" || die "Failed to install rootfs for $name"
391 configure_alpine "$rootfs" "$name" || die "Failed to configure $name"
392 copy_configuration "$path" "$rootfs" "$name"