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