]> git.proxmox.com Git - mirror_lxc.git/blob - templates/lxc-cirros.in
Merge pull request #2055 from marcosps/cgfsng_debug
[mirror_lxc.git] / templates / lxc-cirros.in
1 #!/bin/bash
2
3 # template script for generating ubuntu container for LXC
4 #
5 # This script consolidates and extends the existing lxc ubuntu scripts
6 #
7
8 # Copyright © 2013 Canonical Ltd.
9 # Author: Scott Moser <scott.moser@canonical.com>
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License version 2, as
13 # published by the Free Software Foundation.
14
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19
20 # You should have received a copy of the GNU General Public License along
21 # with this program; if not, write to the Free Software Foundation, Inc.,
22 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24 # Detect use under userns (unsupported)
25 # Make sure the usual locations are in PATH
26 export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
27
28 VERBOSITY=0
29 DOWNLOAD_URL="http://download.cirros-cloud.net/"
30
31 UNAME_M=$(uname -m)
32 ARCHES=( i386 x86_64 amd64 arm )
33 STREAMS=( released devel )
34 SOURCES=( nocloud none )
35 BUILD="standard"
36 LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
37
38 LXC_MAPPED_GID=
39 LXC_MAPPED_UID=
40
41 DEF_VERSION="released"
42 DEF_SOURCE="nocloud"
43 case "${UNAME_M}" in
44 i?86) DEF_ARCH="i386";;
45 x86_64) DEF_ARCH="x86_64";;
46 arm*) DEF_ARCH="arm";;
47 *) DEF_ARCH="i386";;
48 esac
49
50 am_in_userns() {
51 [ -e /proc/self/uid_map ] || { echo no; return; }
52 [ "$(wc -l /proc/self/uid_map | awk '{ print $1 }')" -eq 1 ] || { echo yes; return; }
53 line=$(awk '{ print $1 " " $2 " " $3 }' /proc/self/uid_map)
54 [ "$line" = "0 0 4294967295" ] && { echo no; return; }
55 echo yes
56 }
57
58 in_userns=0
59 [ $(am_in_userns) = "yes" ] && in_userns=1
60
61 # Allow the cache base to be set by environment variable
62 if [ $(id -u) -eq 0 ]; then
63 CACHE_D=${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc/cirros"}
64 else
65 CACHE_D=${LXC_CACHE_PATH:-"$HOME/.cache/lxc/cirros"}
66 fi
67
68 error() { echo "$@" 1>&2; }
69 inargs() {
70 local needle="$1" x=""
71 shift
72 for x in "$@"; do
73 [ "$needle" = "$x" ] && return 0
74 done
75 return 1
76 }
77
78 Usage() {
79 cat <<EOF
80 ${0##*/} [options]
81
82 -a | --arch A architecture to use [${ARCHES[*]}]
83 default: ${DEF_ARCH}
84 -h | --help this usage
85 -v | --verbose increase verbosity
86 -S | --auth-key K insert auth key 'K'
87 -v | --version V version [${STREAMS[*]}]
88 default: ${DEF_VERSION}
89 -u | --userdata U user-data file
90 --tarball T read from tarball 'T' rather than downloading
91 or using cache.
92 --source S insert userdata/metadata via source S
93 [${SOURCES[*]}]
94 EOF
95 }
96
97 bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
98
99 debug() {
100 local level=${1}; shift;
101 [ "${level}" -gt "${VERBOSITY}" ] && return
102 error "${@}"
103 }
104 jsondict() {
105 local k="" v="" ret="{"
106 for arg in "$@"; do
107 k="${arg%%=*}"
108 v="${arg#*=}"
109 ret="${ret} \"${k}\": \"$v\","
110 done
111 ret="${ret%,} }"
112 echo "$ret"
113 }
114
115 copy_configuration()
116 {
117 local path=$1 rootfs=$2 name=$3 arch=$4 release=$5
118 cat >> "$path/config" <<EOF
119 # Template used to create this container: cirros
120
121 lxc.rootfs.path = $rootfs
122
123 lxc.tty.max = 4
124 lxc.pty.max = 1024
125
126 lxc.uts.name = $name
127 lxc.arch = $arch
128 lxc.cap.drop = sys_module mac_admin mac_override sys_time
129
130 # When using LXC with apparmor, uncomment the next line to run unconfined:
131 #lxc.apparmor.profile = unconfined
132 lxc.mount.auto = cgroup:mixed proc:mixed sys:mixed
133
134 lxc.cgroup.devices.deny = a
135 # Allow any mknod (but not using the node)
136 lxc.cgroup.devices.allow = c *:* m
137 lxc.cgroup.devices.allow = b *:* m
138 # /dev/null and zero
139 lxc.cgroup.devices.allow = c 1:3 rwm
140 lxc.cgroup.devices.allow = c 1:5 rwm
141 # consoles
142 lxc.cgroup.devices.allow = c 5:1 rwm
143 lxc.cgroup.devices.allow = c 5:0 rwm
144 # /dev/{,u}random
145 lxc.cgroup.devices.allow = c 1:9 rwm
146 lxc.cgroup.devices.allow = c 1:8 rwm
147 lxc.cgroup.devices.allow = c 136:* rwm
148 lxc.cgroup.devices.allow = c 5:2 rwm
149 # rtc
150 lxc.cgroup.devices.allow = c 254:0 rwm
151 # fuse
152 lxc.cgroup.devices.allow = c 10:229 rwm
153 # tun
154 lxc.cgroup.devices.allow = c 10:200 rwm
155 # full
156 lxc.cgroup.devices.allow = c 1:7 rwm
157 # hpet
158 lxc.cgroup.devices.allow = c 10:228 rwm
159 # kvm
160 lxc.cgroup.devices.allow = c 10:232 rwm
161 EOF
162
163 if [ $in_userns -eq 1 ] && [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.userns.conf" ]; then
164 echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu.userns.conf" >> $path/config
165 fi
166
167 }
168
169 insert_ds_nocloud() {
170 local root_d="$1" authkey="$2" udfile="$3"
171 local sdir="$root_d/var/lib/cloud/seed/nocloud"
172
173 mkdir -p "$sdir" ||
174 { error "failed to make datasource dir $sdir"; return 1; }
175 rm -f "$sdir/meta-data" "$sdir/user-data" ||
176 { error "failed to clean old data from $sdir"; return 1; }
177
178 iid="iid-local01"
179 jsondict "instance-id=$iid" \
180 ${authkeys:+"public-keys=${authkeys}"} > "$sdir/meta-data" ||
181 { error "failed to write metadata to $sdir/meta-data"; return 1; }
182
183 if [ -n "$udfile" ]; then
184 cat "$udfile" > "$sdir/user-data" ||
185 { error "failed to write user-data to $sdir"; return 1; }
186 else
187 rm -f "$sdir/user-data"
188 fi
189 }
190
191 insert_ds() {
192 local dstype="$1" root_d="$2" authkey="$3" udfile="$4"
193 case "$dstype" in
194 nocloud) insert_ds_nocloud "$root_d" "$authkey" "$udfile"
195 esac
196 }
197
198 extract_rootfs() {
199 local tarball="$1" rootfs_d="$2"
200 mkdir -p "${rootfs_d}" ||
201 { error "failed to make rootfs dir ${rootfs_d}"; return 1; }
202
203 if [ $in_userns -eq 1 ]; then
204 tar -C "${rootfs_d}" --anchored --exclude="dev/*" -Sxzf "${tarball}" ||
205 { error "failed to populate ${rootfs_d}"; return 1; }
206 else
207 tar -C "${rootfs_d}" -Sxzf "${tarball}" ||
208 { error "failed to populate ${rootfs_d}"; return 1; }
209 fi
210 return 0
211 }
212
213 download_tarball() {
214 local arch="$1" ver="$2" cached="$3" baseurl="$4"
215 local out="" outd="" file="" dlpath=""
216 file="cirros-$ver-$arch-lxc.tar.gz"
217 dlpath="$ver/$file"
218 outd="${cached}/${dlpath%/*}"
219 if [ -f "$cached/$dlpath" ]; then
220 _RET="$cached/$dlpath"
221 return 0
222 fi
223
224 mkdir -p "${outd}" ||
225 { error "failed to create ${outd}"; return 1; }
226
227 debug 1 "downloading ${baseurl%/}/$dlpath" to "${cached}/$dlpath"
228 wget "${baseurl%/}/$dlpath" -O "$cached/${dlpath}.$$" &&
229 mv "$cached/$dlpath.$$" "$cached/$dlpath" || {
230 rm -f "$cached/$dlpath.$$";
231 error "failed to download $dlpath";
232 return 1;
233 }
234 _RET="$cached/$dlpath"
235 }
236
237 create_main() {
238 local short_opts="a:hn:p:S:uvV"
239 local long_opts="arch:,auth-key:,name:,path:,tarball:,userdata:,verbose,version:,rootfs:,mapped-uid:,mapped-gid:"
240 local getopt_out=""
241 getopt_out=$(getopt --name "${0##*/}" \
242 --options "${short_opts}" --long "${long_opts}" -- "$@") &&
243 eval set -- "${getopt_out}" ||
244 { bad_Usage; return; }
245
246 local arch="${DEF_ARCH}" dsource="${DEF_SOURCE}" version="${DEF_VERSION}"
247 local authkey_f="" authkeys="" userdata_f="" path="" tarball=""
248 local cur="" next=""
249 local rootfs_d=""
250
251 while [ $# -ne 0 ]; do
252 cur=$1; next=$2;
253 case "$cur" in
254 -a|--arch) arch="$next"; shift;;
255 -h|--help) Usage ; return 0;;
256 -n|--name) name="$next"; shift;;
257 -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
258 -S|--auth-key) authkey_f="$next"; shift;;
259 -p|--path) path=$next; shift;;
260 -v|--version) version=$next; shift;;
261 -u|--userdata) userdata_f="$next"; shift;;
262 --tarball) tarball="$next"; shift;;
263 --source) dsource="$next"; shift;;
264 --rootfs) rootfs_d="$next"; shift;;
265 --mapped-uid) LXC_MAPPED_UID=$next; shift;;
266 --mapped-gid) LXC_MAPPED_GID=$next; shift;;
267 --) shift; break;;
268 esac
269 shift;
270 done
271
272 [ -n "$rootfs_d" ] || rootfs_d="$path/rootfs"
273 [ $# -eq 0 ] || { bad_Usage "unexpected arguments: $*"; return; }
274 [ -n "$path" ] || { error "'path' parameter is required"; return 1; }
275
276 if [ "$(id -u)" != "0" ]; then
277 { error "must be run as root"; return 1; }
278 fi
279
280 case "$arch" in
281 i?86) arch="i386";;
282 amd64) arch="x86_64";;
283 esac
284
285 inargs "$arch" "${ARCHES[@]}" ||
286 { error "bad arch '$arch'. allowed: ${ARCHES[*]}"; return 1; }
287
288 inargs "$dsource" "${SOURCES[@]}" ||
289 { error "bad source '$dsource'. allowed: ${SOURCES[*]}"; return 1; }
290
291 if [ "$dsource" = "none" ] && [ -n "$userdata_f" -o -n "$authkey_f" ]; then
292 error "userdata and authkey are incompatible with --source=none";
293 return 1;
294 fi
295
296 if [ -n "$authkey_f" ]; then
297 if [ ! -f "$authkey_f" ]; then
298 error "--auth-key=${authkey_f} must reference a file"
299 return 1
300 fi
301 authkeys=$(cat "$authkey_f") ||
302 { error "failed to read ${authkey_f}"; return 1; }
303 fi
304
305 if [ -n "$userdata_f" -a ! -f "${userdata_f}" ]; then
306 error "${userdata_f}: --userdata arg not a file"
307 return 1
308 fi
309
310 if [ -z "$tarball" ]; then
311 if inargs "$version" "${STREAMS[@]}"; then
312 out=$(wget -O - -q "${DOWNLOAD_URL%/}/version/$version") ||
313 { error "failed to convert 'version=$version'"; return 1; }
314 version="$out"
315 fi
316 download_tarball "$arch" "$version" "${CACHE_D}" "${DOWNLOAD_URL}" ||
317 return
318 tarball="$_RET"
319 fi
320
321 extract_rootfs "${tarball}" "${rootfs_d}" || return
322
323 if [ "$version" = "0.3.2~pre1" ]; then
324 debug 1 "fixing console for lxc and '$version'"
325 sed -i 's,^\(#console.* 115200 \)# /dev/console,\1 console,g' \
326 "$rootfs_d/etc/inittab" ||
327 { error "failed to fix console entry for $version"; return 1; }
328 fi
329
330 if [ "$dsource" != "none" ]; then
331 insert_ds "$dsource" "$path/rootfs" "$authkeys" "$userdata_f" || {
332 error "failed to insert userdata to $path/rootfs"
333 return 1
334 }
335 fi
336
337 copy_configuration "$path" "$path/rootfs" "$name" "$arch" "$release"
338 return
339 }
340
341 create_main "$@"
342
343 # vi: ts=4 expandtab