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