]>
Commit | Line | Data |
---|---|---|
8a96554a ER |
1 | #!/bin/sh |
2 | ||
3 | # | |
4 | # template script for generating PLD Linux container for LXC | |
5 | # | |
6 | ||
7 | # | |
8 | # lxc: Linux Container library | |
9 | ||
10 | # Authors: | |
11 | # Elan Ruusamäe <glen@pld-linux.org> | |
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 | # Configuration | |
28 | arch=$(uname -m) | |
29 | cache_base=@LOCALSTATEDIR@/cache/lxc/pld/$arch | |
30 | default_path=@LXCPATH@ | |
31 | root_password=root | |
32 | ||
33 | # is this pld? | |
34 | # Alow for weird remixes like the Raspberry Pi | |
35 | # | |
36 | # Use the Mitre standard CPE identifier for the release ID if possible... | |
37 | # This may be in /etc/os-release or /etc/system-release-cpe. We | |
38 | # should be able to use EITHER. Give preference to /etc/os-release for now. | |
39 | ||
40 | if [ -e /etc/os-release ]; then | |
41 | # This is a shell friendly configuration file. We can just source it. | |
42 | # What we're looking for in here is the ID, VERSION_ID and the CPE_NAME | |
43 | . /etc/os-release | |
44 | echo "Host CPE ID from /etc/os-release: ${CPE_NAME}" | |
45 | fi | |
46 | ||
47 | if [ "${CPE_NAME}" != "" -a "${ID}" = "pld" -a "${VERSION_ID}" != "" ]; then | |
48 | pld_host_ver=${VERSION_ID} | |
49 | is_pld=true | |
50 | elif [ -e /etc/pld-release ]; then | |
51 | # Only if all other methods fail, try to parse the pld-release file. | |
52 | pld_host_ver=$(sed -e '/PLD /!d' -e 's/^\([0-9.]*\)\sPLD.*/\1/' < /etc/pld-release) | |
53 | if [ "$pld_host_ver" != "" ]; then | |
54 | is_pld=true | |
55 | fi | |
56 | fi | |
57 | ||
58 | # Map a few architectures to their generic PLD Linux repository archs. | |
59 | case "$pld_host_ver:$arch" in | |
60 | 3.0:i586) arch=i486 ;; | |
61 | esac | |
62 | ||
63 | configure_pld() | |
64 | { | |
65 | ||
66 | # disable selinux | |
67 | mkdir -p $rootfs_path/selinux | |
68 | echo 0 > $rootfs_path/selinux/enforce | |
69 | ||
70 | # configure the network using the dhcp | |
71 | sed -i -e "/^HOSTNAME=.*/HOSTNAME=${utsname}/" ${rootfs_path}/etc/sysconfig/network | |
72 | ||
73 | # set hostname on systemd | |
74 | if [ $release = "3.0" ]; then | |
75 | echo "${utsname}" > ${rootfs_path}/etc/hostname | |
76 | fi | |
77 | ||
78 | # set minimal hosts | |
79 | cat <<EOF > $rootfs_path/etc/hosts | |
80 | 127.0.0.1 localhost.localdomain localhost $utsname | |
81 | ::1 localhost6.localdomain6 localhost6 | |
82 | EOF | |
83 | ||
84 | dev_path="${rootfs_path}/dev" | |
85 | rm -rf $dev_path | |
86 | mkdir -p $dev_path | |
87 | mknod -m 666 ${dev_path}/null c 1 3 | |
88 | mknod -m 666 ${dev_path}/zero c 1 5 | |
89 | mknod -m 666 ${dev_path}/random c 1 8 | |
90 | mknod -m 666 ${dev_path}/urandom c 1 9 | |
91 | mkdir -m 755 ${dev_path}/pts | |
92 | mkdir -m 1777 ${dev_path}/shm | |
93 | mknod -m 666 ${dev_path}/tty c 5 0 | |
94 | mknod -m 666 ${dev_path}/tty0 c 4 0 | |
95 | mknod -m 666 ${dev_path}/tty1 c 4 1 | |
96 | mknod -m 666 ${dev_path}/tty2 c 4 2 | |
97 | mknod -m 666 ${dev_path}/tty3 c 4 3 | |
98 | mknod -m 666 ${dev_path}/tty4 c 4 4 | |
99 | mknod -m 600 ${dev_path}/console c 5 1 | |
100 | mknod -m 666 ${dev_path}/full c 1 7 | |
101 | mknod -m 600 ${dev_path}/initctl p | |
102 | mknod -m 666 ${dev_path}/ptmx c 5 2 | |
103 | ||
104 | echo "setting root passwd to $root_password" | |
105 | echo "root:$root_password" | chroot $rootfs_path chpasswd | |
106 | ||
107 | return 0 | |
108 | } | |
109 | ||
110 | configure_pld_init() | |
111 | { | |
112 | # Setup getty service on the 4 ttys we are going to allow in the | |
113 | # default config. Number should match lxc.tty | |
114 | # sed -i -e 's///' ${rootfs_path}/etc/inittab | |
115 | } | |
116 | ||
117 | configure_pld_systemd() | |
118 | { | |
119 | unlink ${rootfs_path}/etc/systemd/system/default.target | |
120 | chroot ${rootfs_path} ln -s /dev/null /etc/systemd/system/udev.service | |
121 | chroot ${rootfs_path} ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target | |
122 | ||
123 | # Actually, the After=dev-%i.device line does not appear in the | |
124 | # Fedora 17 or Fedora 18 systemd getty@.service file. It may be left | |
125 | # over from an earlier version and it's not doing any harm. We do need | |
126 | # to disable the "ConditionalPathExists=/dev/tty0" line or no gettys are | |
127 | # started on the ttys in the container. Lets do it in an override copy of | |
128 | # the service so it can still pass rpm verifies and not be automatically | |
129 | # updated by a new systemd version. -- mhw /\/\|=mhw=|\/\/ | |
130 | ||
131 | sed -e 's/^ConditionPathExists=/# ConditionPathExists=/' \ | |
132 | -e 's/After=dev-%i.device/After=/' \ | |
133 | < ${rootfs_path}/lib/systemd/system/getty\@.service \ | |
134 | > ${rootfs_path}/etc/systemd/system/getty\@.service | |
135 | ||
136 | # Setup getty service on the 4 ttys we are going to allow in the | |
137 | # default config. Number should match lxc.tty | |
138 | for i in 1 2 3 4; do | |
139 | ln -sf ../getty@.service ${rootfs_path}/etc/systemd/system/getty.target.wants/getty@tty${i}.service | |
140 | done | |
141 | } | |
142 | ||
143 | download_pld() | |
144 | { | |
145 | ||
146 | # check the mini pld was not already downloaded | |
147 | INSTALL_ROOT=$cache/partial | |
148 | mkdir -p $INSTALL_ROOT | |
149 | if [ $? -ne 0 ]; then | |
150 | echo "Failed to create '$INSTALL_ROOT' directory" | |
151 | return 1 | |
152 | fi | |
153 | ||
154 | # download a mini pld into a cache | |
155 | echo "Downloading PLD Linux minimal ..." | |
156 | POLDEK="poldek --root $INSTALL_ROOT --noask --nohold --noignore" | |
157 | PKG_LIST="basesystem filesystem pld-release rpm poldek vserver-packages rc-scripts pwdutils mingetty" | |
158 | ||
159 | mkdir -p $INSTALL_ROOT@LOCALSTATEDIR@/lib/rpm | |
160 | rpm --root $INSTALL_ROOT --initdb | |
161 | rpm --root $INSTALL_ROOT -ivh ${INSTALL_ROOT}/${RELEASE_RPM} | |
162 | $POLDEK -u $PKG_LIST | |
163 | ||
164 | if [ $? -ne 0 ]; then | |
165 | echo "Failed to download the rootfs, aborting." | |
166 | return 1 | |
167 | fi | |
168 | ||
169 | mv "$INSTALL_ROOT" "$cache/rootfs" | |
170 | echo "Download complete." | |
171 | ||
172 | return 0 | |
173 | } | |
174 | ||
175 | copy_pld() | |
176 | { | |
177 | ||
178 | # make a local copy of the minipld | |
179 | echo -n "Copying rootfs to $rootfs_path ..." | |
180 | cp -a $cache/rootfs/ $rootfs_path || return 1 | |
181 | return 0 | |
182 | } | |
183 | ||
184 | update_pld() | |
185 | { | |
186 | POLDEK="poldek --root $cache/rootfs --noask" | |
187 | $POLDEK --upgrade-dist | |
188 | } | |
189 | ||
190 | install_pld() | |
191 | { | |
192 | mkdir -p @LOCALSTATEDIR@/lock/subsys/ | |
193 | ( | |
194 | flock -x 200 | |
195 | if [ $? -ne 0 ]; then | |
196 | echo "Cache repository is busy." | |
197 | return 1 | |
198 | fi | |
199 | ||
200 | echo "Checking cache download in $cache/rootfs ... " | |
201 | if [ ! -e "$cache/rootfs" ]; then | |
202 | download_pld | |
203 | if [ $? -ne 0 ]; then | |
204 | echo "Failed to download 'pld base'" | |
205 | return 1 | |
206 | fi | |
207 | else | |
208 | echo "Cache found. Updating..." | |
209 | update_pld | |
210 | if [ $? -ne 0 ]; then | |
211 | echo "Failed to update 'pld base', continuing with last known good cache" | |
212 | else | |
213 | echo "Update finished" | |
214 | fi | |
215 | fi | |
216 | ||
217 | echo "Copy $cache/rootfs to $rootfs_path ... " | |
218 | copy_pld | |
219 | if [ $? -ne 0 ]; then | |
220 | echo "Failed to copy rootfs" | |
221 | return 1 | |
222 | fi | |
223 | ||
224 | return 0 | |
225 | ) 200>@LOCALSTATEDIR@/lock/subsys/lxc-pld | |
226 | ||
227 | return $? | |
228 | } | |
229 | ||
230 | copy_configuration() | |
231 | { | |
232 | ||
233 | mkdir -p $config_path | |
234 | grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "lxc.rootfs = $rootfs_path" >> $config_path/config | |
235 | cat <<EOF >> $config_path/config | |
236 | lxc.utsname = $utsname | |
237 | lxc.tty = 4 | |
238 | lxc.pts = 1024 | |
239 | lxc.mount = $config_path/fstab | |
240 | lxc.cap.drop = sys_module mac_admin mac_override sys_time | |
241 | ||
242 | lxc.autodev = $auto_dev | |
243 | ||
244 | # When using LXC with apparmor, uncomment the next line to run unconfined: | |
245 | #lxc.aa_profile = unconfined | |
246 | ||
247 | #cgroups | |
248 | lxc.cgroup.devices.deny = a | |
249 | # /dev/null and zero | |
250 | lxc.cgroup.devices.allow = c 1:3 rwm | |
251 | lxc.cgroup.devices.allow = c 1:5 rwm | |
252 | # consoles | |
253 | lxc.cgroup.devices.allow = c 5:1 rwm | |
254 | lxc.cgroup.devices.allow = c 5:0 rwm | |
255 | lxc.cgroup.devices.allow = c 4:0 rwm | |
256 | lxc.cgroup.devices.allow = c 4:1 rwm | |
257 | # /dev/{,u}random | |
258 | lxc.cgroup.devices.allow = c 1:9 rwm | |
259 | lxc.cgroup.devices.allow = c 1:8 rwm | |
260 | lxc.cgroup.devices.allow = c 136:* rwm | |
261 | lxc.cgroup.devices.allow = c 5:2 rwm | |
262 | # rtc | |
263 | lxc.cgroup.devices.allow = c 254:0 rm | |
264 | EOF | |
265 | ||
266 | cat <<EOF > $config_path/fstab | |
267 | proc proc proc nodev,noexec,nosuid 0 0 | |
268 | sysfs sys sysfs defaults 0 0 | |
269 | EOF | |
270 | if [ $? -ne 0 ]; then | |
271 | echo "Failed to add configuration" | |
272 | return 1 | |
273 | fi | |
274 | ||
275 | return 0 | |
276 | } | |
277 | ||
278 | clean() | |
279 | { | |
280 | ||
281 | if [ ! -e $cache ]; then | |
282 | exit 0 | |
283 | fi | |
284 | ||
285 | # lock, so we won't purge while someone is creating a repository | |
286 | ( | |
287 | flock -x 200 | |
288 | if [ $? != 0 ]; then | |
289 | echo "Cache repository is busy." | |
290 | exit 1 | |
291 | fi | |
292 | ||
293 | echo -n "Purging the download cache for PLD Linux $release..." | |
294 | rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1 | |
295 | exit 0 | |
296 | ) 200>@LOCALSTATEDIR@/lock/subsys/lxc-pld | |
297 | } | |
298 | ||
299 | usage() | |
300 | { | |
301 | cat <<EOF | |
302 | usage: | |
303 | $1 -n|--name=<container_name> | |
304 | [-p|--path=<path>] [-c|--clean] [-R|--release=<PLD Release>] [--fqdn=<network name of container>] [-A|--arch=<arch of the container>] | |
305 | [-h|--help] | |
306 | Mandatory args: | |
307 | -n,--name container name, used to as an identifier for that container from now on | |
308 | Optional args: | |
309 | -p,--path path to where the container will be created, defaults to @LXCPATH@. The container config will go under @LXCPATH@ in that case | |
310 | --rootfs path for actual rootfs. | |
311 | -c,--clean clean the cache | |
312 | -R,--release PLD Linux release for the new container. if the host is PLD Linux, then it will default to the host's release. | |
313 | --fqdn fully qualified domain name (FQDN) for DNS and system naming | |
314 | -A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64] | |
315 | -h,--help print this help | |
316 | EOF | |
317 | return 0 | |
318 | } | |
319 | ||
320 | options=$(getopt -o hp:n:cR: -l help,path:,rootfs:,name:,clean,release:,fqdn: -- "$@") | |
321 | if [ $? -ne 0 ]; then | |
322 | usage $(basename $0) | |
323 | exit 1 | |
324 | fi | |
325 | eval set -- "$options" | |
326 | ||
327 | while :; do | |
328 | case "$1" in | |
329 | -h|--help) usage $0 && exit 0;; | |
330 | -p|--path) path=$2; shift 2;; | |
331 | --rootfs) rootfs=$2; shift 2;; | |
332 | -n|--name) name=$2; shift 2;; | |
333 | -c|--clean) clean=$2; shift 2;; | |
334 | -R|--release) release=$2; shift 2;; | |
335 | --fqdn) utsname=$2; shift 2;; | |
336 | --) shift 1; break ;; | |
337 | *) break ;; | |
338 | esac | |
339 | done | |
340 | ||
341 | if [ ! -z "$clean" -a -z "$path" ]; then | |
342 | clean || exit 1 | |
343 | exit 0 | |
344 | fi | |
345 | ||
346 | if [ -z "${utsname}" ]; then | |
347 | utsname=${name} | |
348 | fi | |
349 | ||
350 | # This follows a standard "resolver" convention that an FQDN must have | |
351 | # at least two dots or it is considered a local relative host name. | |
352 | # If it doesn't, append the dns domain name of the host system. | |
353 | # | |
354 | # This changes one significant behavior when running | |
355 | # "lxc_create -n Container_Name" without using the | |
356 | # --fqdn option. | |
357 | # | |
358 | # Old behavior: | |
359 | # utsname and hostname = Container_Name | |
360 | # New behavior: | |
361 | # utsname and hostname = Container_Name.Domain_Name | |
362 | ||
363 | if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then | |
364 | if [ -n "$(dnsdomainname)" ]; then | |
365 | utsname=${utsname}.$(dnsdomainname) | |
366 | fi | |
367 | fi | |
368 | ||
369 | needed_pkgs="" | |
370 | type poldek >/dev/null 2>&1 | |
371 | if [ $? -ne 0 ]; then | |
372 | needed_pkgs="poldek $needed_pkgs" | |
373 | fi | |
374 | ||
375 | #type curl >/dev/null 2>&1 | |
376 | #if [ $? -ne 0 ]; then | |
377 | # needed_pkgs="curl $needed_pkgs" | |
378 | #fi | |
379 | ||
380 | if [ -n "$needed_pkgs" ]; then | |
381 | echo "Missing commands: $needed_pkgs" | |
382 | echo "Please install these using \"sudo poldek -u $needed_pkgs\"" | |
383 | exit 1 | |
384 | fi | |
385 | ||
386 | if [ -z "$path" ]; then | |
387 | path=$default_path/$name | |
388 | fi | |
389 | ||
390 | if [ -z "$release" ]; then | |
391 | if [ "$is_pld" -a "$pld_host_ver" ]; then | |
392 | release=$pld_host_ver | |
393 | else | |
394 | echo "This is not a PLD Linux host and release missing, defaulting to 3.0. use -R|--release to specify release" | |
395 | release=3.0 | |
396 | fi | |
397 | fi | |
398 | ||
399 | # pld th have systemd. We need autodev enabled to keep systemd from causing problems. | |
400 | if [ $release = 3.0 ]; then | |
401 | auto_dev="0" | |
402 | else | |
403 | auto_dev="0" | |
404 | fi | |
405 | ||
406 | if [ "$(id -u)" != "0" ]; then | |
407 | echo "This script should be run as 'root'" | |
408 | exit 1 | |
409 | fi | |
410 | ||
411 | if [ -z "$rootfs_path" ]; then | |
412 | rootfs_path=$path/rootfs | |
413 | # check for 'lxc.rootfs' passed in through default config by lxc-create | |
414 | if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then | |
415 | rootfs_path=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $path/config) | |
416 | fi | |
417 | fi | |
418 | config_path=$default_path/$name | |
419 | cache=$cache_base/$release | |
420 | ||
421 | revert() | |
422 | { | |
423 | echo "Interrupted, so cleaning up" | |
424 | lxc-destroy -n $name | |
425 | # maybe was interrupted before copy config | |
426 | rm -rf $path | |
427 | rm -rf $default_path/$name | |
428 | echo "exiting..." | |
429 | exit 1 | |
430 | } | |
431 | ||
432 | trap revert SIGHUP SIGINT SIGTERM | |
433 | ||
434 | copy_configuration | |
435 | if [ $? -ne 0 ]; then | |
436 | echo "Failed write configuration file" | |
437 | exit 1 | |
438 | fi | |
439 | ||
440 | install_pld | |
441 | if [ $? -ne 0 ]; then | |
442 | echo "Failed to install PLD Linux" | |
443 | exit 1 | |
444 | fi | |
445 | ||
446 | configure_pld | |
447 | if [ $? -ne 0 ]; then | |
448 | echo "Failed to configure PLD Linux for a container" | |
449 | exit 1 | |
450 | fi | |
451 | ||
452 | # If the systemd configuration directory exists - set it up for what we need. | |
453 | if [ -d ${rootfs_path}/etc/systemd/system ]; then | |
454 | configure_pld_systemd | |
455 | fi | |
456 | ||
457 | # This configuration (rc.sysinit) is not inconsistent with the systemd stuff | |
458 | # above and may actually coexist on some upgraded systems. Let's just make | |
459 | # sure that, if it exists, we update this file, even if it's not used... | |
460 | if [ -f ${rootfs_path}/etc/rc.sysinit ]; then | |
461 | configure_pld_init | |
462 | fi | |
463 | ||
464 | if [ ! -z $clean ]; then | |
465 | clean || exit 1 | |
466 | exit 0 | |
467 | fi | |
468 | echo "container rootfs and config created" |