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