]>
Commit | Line | Data |
---|---|---|
54b1eb68 MH |
1 | #!/bin/bash |
2 | # set -ex | |
3 | ||
4 | DISTRO="fedora" | |
5 | CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}" | |
6 | ||
7 | # Default container name | |
8 | NAME="fedora" | |
9 | CONFFILE="lxc.conf" | |
54b1eb68 MH |
10 | UTSNAME= |
11 | IPV4="172.20.0.21" | |
12 | GATEWAY="172.20.0.1" | |
b44cb779 | 13 | MTU="1500" |
54b1eb68 MH |
14 | |
15 | # These paths are within the container so do not need to obey configure prefixes | |
16 | INITTAB="/etc/inittab" | |
17 | FSTAB="/etc/fstab" | |
18 | SSHD_CONFIG="/etc/ssh/sshd_config" | |
19 | ||
20 | ################################################################################ | |
21 | # DISTRO custom configuration files | |
22 | ################################################################################ | |
23 | ||
24 | # custom selinux | |
25 | ||
26 | write_distro_selinux() { | |
27 | mkdir -p ${ROOTFS}/selinux | |
28 | echo 0 > ${ROOTFS}/selinux/enforce | |
29 | } | |
30 | ||
31 | # custom fstab | |
32 | ||
33 | write_distro_fstab() { | |
34 | cat <<EOF > ${ROOTFS}/${FSTAB} | |
35 | tmpfs /dev/shm tmpfs defaults 0 0 | |
36 | EOF | |
37 | } | |
38 | ||
39 | # custom inittab | |
40 | ||
41 | write_distro_inittab() { | |
42 | cat <<EOF > ${ROOTFS}/${INITTAB} | |
43 | id:3:initdefault: | |
44 | si::sysinit:/etc/init.d/rcS | |
45 | l0:0:wait:/etc/init.d/rc 0 | |
46 | l1:1:wait:/etc/init.d/rc 1 | |
47 | l2:2:wait:/etc/init.d/rc 2 | |
48 | l3:3:wait:/etc/init.d/rc 3 | |
49 | l4:4:wait:/etc/init.d/rc 4 | |
50 | l5:5:wait:/etc/init.d/rc 5 | |
51 | l6:6:wait:/etc/init.d/rc 6 | |
52 | # Normally not reached, but fallthrough in case of emergency. | |
53 | z6:6:respawn:/sbin/sulogin | |
54 | 1:2345:respawn:/sbin/getty 38400 console | |
55 | c1:12345:respawn:/sbin/getty 38400 tty1 linux | |
56 | c2:12345:respawn:/sbin/getty 38400 tty2 linux | |
57 | c3:12345:respawn:/sbin/getty 38400 tty3 linux | |
58 | c4:12345:respawn:/sbin/getty 38400 tty4 linux | |
59 | EOF | |
60 | } | |
61 | ||
62 | # custom network configuration | |
63 | write_distro_network() { | |
64 | cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-lo | |
65 | DEVICE=lo | |
66 | IPADDR=127.0.0.1 | |
67 | NETMASK=255.0.0.0 | |
68 | NETWORK=127.0.0.0 | |
69 | # If you're having problems with gated making 127.0.0.0/8 a martian, | |
70 | # you can change this to something else (255.255.255.255, for example) | |
71 | BROADCAST=127.255.255.255 | |
72 | ONBOOT=yes | |
73 | NAME=loopback | |
74 | EOF | |
75 | cat <<EOF > ${ROOTFS}/etc/sysconfig/network-scripts/ifcfg-eth0 | |
76 | DEVICE=eth0 | |
77 | BOOTPROTO=static | |
78 | HWADDR=52:54:00:12:34:56 | |
79 | ONBOOT=yes | |
80 | HOSTNAME=${UTSNAME} | |
81 | NM_CONTROLLED=no | |
82 | TYPE=Ethernet | |
83 | IPADDR=${IPV4} | |
84 | NETWORK=$(ipcalc -sn ${IPV4} 255.255.255.0) | |
85 | GATEWAY=${GATEWAY} | |
86 | BROADCAST=$(ipcalc -sb ${IPV4} 255.255.255.0) | |
87 | NETMASK=255.255.255.0 | |
b44cb779 | 88 | MTU=${MTU} |
54b1eb68 MH |
89 | EOF |
90 | } | |
91 | ||
92 | # custom hostname | |
93 | ||
94 | write_distro_hostname() { | |
4f3f0d4b | 95 | cat <<EOF > ${ROOTFS}/etc/sysconfig/network |
54b1eb68 MH |
96 | NETWORKING=yes |
97 | HOSTNAME=${UTSNAME} | |
98 | EOF | |
99 | } | |
100 | ||
101 | # custom sshd configuration file | |
102 | ||
103 | write_distro_sshd_config() { | |
104 | cat <<EOF > ${ROOTFS}/${SSHD_CONFIG} | |
105 | Port 22 | |
106 | Protocol 2 | |
107 | HostKey /etc/ssh/ssh_host_rsa_key | |
108 | HostKey /etc/ssh/ssh_host_dsa_key | |
109 | UsePrivilegeSeparation yes | |
110 | KeyRegenerationInterval 3600 | |
111 | ServerKeyBits 768 | |
112 | SyslogFacility AUTH | |
113 | LogLevel INFO | |
114 | LoginGraceTime 120 | |
115 | PermitRootLogin yes | |
116 | StrictModes yes | |
117 | RSAAuthentication yes | |
118 | PubkeyAuthentication yes | |
119 | IgnoreRhosts yes | |
120 | RhostsRSAAuthentication no | |
121 | HostbasedAuthentication no | |
122 | PermitEmptyPasswords yes | |
123 | ChallengeResponseAuthentication no | |
124 | EOF | |
125 | } | |
126 | ||
127 | ################################################################################ | |
128 | # lxc configuration files | |
129 | ################################################################################ | |
130 | ||
131 | write_lxc_configuration() { | |
132 | cat <<EOF > ${CONFFILE} | |
133 | lxc.utsname = ${UTSNAME} | |
134 | lxc.tty = 4 | |
135 | lxc.network.type = veth | |
136 | lxc.network.flags = up | |
137 | lxc.network.link = br0 | |
138 | lxc.network.name = eth0 | |
b44cb779 | 139 | lxc.network.mtu = ${MTU} |
54b1eb68 MH |
140 | lxc.rootfs = ${ROOTFS} |
141 | lxc.cgroup.devices.deny = a | |
142 | # /dev/null and zero | |
143 | lxc.cgroup.devices.allow = c 1:3 rwm | |
144 | lxc.cgroup.devices.allow = c 1:5 rwm | |
145 | # consoles | |
146 | lxc.cgroup.devices.allow = c 5:1 rwm | |
147 | lxc.cgroup.devices.allow = c 5:0 rwm | |
148 | lxc.cgroup.devices.allow = c 4:0 rwm | |
149 | lxc.cgroup.devices.allow = c 4:1 rwm | |
150 | # /dev/{,u}random | |
151 | lxc.cgroup.devices.allow = c 1:9 rwm | |
152 | lxc.cgroup.devices.allow = c 1:8 rwm | |
153 | # /dev/pts/* - pts namespaces are "coming soon" | |
154 | lxc.cgroup.devices.allow = c 136:* rwm | |
155 | lxc.cgroup.devices.allow = c 5:2 rwm | |
156 | # rtc | |
157 | lxc.cgroup.devices.allow = c 254:0 rwm | |
158 | EOF | |
159 | } | |
160 | ||
54b1eb68 MH |
161 | create() { |
162 | ||
163 | # choose a container name, default is already in shell NAME variable | |
164 | echo -n "What is the name for the container ? [${NAME}] " | |
165 | read _NAME_ | |
166 | ||
167 | if [ ! -z "${_NAME_}" ]; then | |
168 | NAME=${_NAME_} | |
169 | fi | |
170 | ||
171 | # choose a hostname, default is the container name | |
172 | echo -n "What hostname do you wish for this container ? [${NAME}] " | |
173 | read _UTSNAME_ | |
174 | ||
175 | if [ ! -z "${_UTSNAME_}" ]; then | |
176 | UTSNAME=${_UTSNAME_} | |
177 | else | |
178 | UTSNAME=${NAME} | |
179 | fi | |
180 | ||
181 | # choose an ipv4 address, better to choose the same network than | |
182 | # your host | |
183 | echo -n "What IP address do you wish for this container ? [${IPV4}] " | |
184 | read _IPV4_ | |
185 | ||
186 | if [ ! -z "${_IPV4_}" ]; then | |
187 | IPV4=${_IPV4_} | |
188 | fi | |
189 | ||
190 | # choose the gateway ip address | |
191 | echo -n "What is the gateway IP address ? [${GATEWAY}] " | |
192 | read _GATEWAY_ | |
193 | ||
194 | if [ ! -z "${_GATEWAY_}" ]; then | |
195 | GATEWAY=${_GATEWAY_} | |
196 | fi | |
197 | ||
b44cb779 RT |
198 | # choose the MTU size |
199 | echo -n "What is the MTU size ? [$MTU] " | |
200 | read _MTU_ | |
201 | ||
202 | if [ ! -z "$_MTU_" ]; then | |
203 | MTU=$_MTU_ | |
204 | fi | |
205 | ||
54b1eb68 MH |
206 | # the rootfs name will be build with the container name |
207 | ROOTFS="./rootfs.${NAME}" | |
208 | ||
209 | # check if the rootfs does already exist | |
210 | if [ ! -e "${ROOTFS}" ]; then | |
211 | mkdir -p @LOCALSTATEDIR@/lock/subsys/ | |
212 | ( | |
213 | flock -n -x 200 | |
214 | ||
215 | ||
216 | RES=$? | |
217 | if [ "${RES}" != "0" ]; then | |
218 | echo "Cache repository is busy." | |
219 | break | |
220 | fi | |
221 | ||
222 | # check the mini distro was not already downloaded | |
223 | echo -n "Checking cache download ..." | |
224 | if [ ! -e "${CACHE}/rootfs" ]; then | |
225 | ||
226 | echo "not cached" | |
227 | ||
228 | # Rather than write a special yum config we just make the | |
229 | # default RPM and yum layout in ${CACHE}. The alternative is | |
230 | # to copy /etc/yum/yum.conf or /etc/yum.conf and fiddle with | |
231 | # some settings. | |
232 | mkdir -p "${CACHE}/partial/var/lib/rpm" | |
233 | mkdir -p "${CACHE}/partial/var/log" | |
234 | touch "${CACHE}/partial/var/log/yum.log" | |
235 | ||
236 | RELEASE="$(yum info ${DISTRO}-release | \ | |
237 | awk -F '[[:space:]]*:[[:space:]]*' \ | |
238 | '/^Release/ { release = $2 } | |
239 | /^Version/ { version = $2 } | |
240 | END { print version "-" release }')" | |
4f3f0d4b M |
241 | |
242 | PKG="${DISTRO}-release-${RELEASE}.noarch" | |
243 | RPM="rpm --root ${CACHE}/partial" | |
54b1eb68 MH |
244 | |
245 | echo "Initializing RPM cache ..." | |
246 | ${RPM} --initdb | |
4f3f0d4b M |
247 | echo "Downloading distribution release file ${PKG}" |
248 | yumdownloader --destdir="${CACHE}/partial" "${PKG}" | |
249 | RESULT=$? | |
250 | ||
251 | if [ "${RESULT}" != "0" ]; then | |
252 | echo "Enable to download the distribution release file" | |
253 | exit 1 | |
254 | fi | |
255 | ||
256 | ${RPM} --nodeps -ihv "${CACHE}/partial/${PKG}.rpm" | |
257 | ||
54b1eb68 MH |
258 | echo "Downloading ${DISTRO} minimal ..." |
259 | yum --installroot="${CACHE}/partial" -y groupinstall Base | |
260 | RESULT=$? | |
261 | if [ "${RESULT}" != "0" ]; then | |
262 | echo "Failed to download the rootfs, aborting." | |
263 | exit 1 | |
264 | fi | |
265 | mv "${CACHE}/partial" "${CACHE}/rootfs" | |
266 | echo "Download complete." | |
267 | else | |
268 | echo "Found." | |
269 | fi | |
270 | ||
271 | # make a local copy of the mini | |
272 | echo -n "Copying rootfs ..." | |
273 | cp -a ${CACHE}/rootfs ${ROOTFS} && echo "Done." || exit | |
274 | ) 200> "@LOCALSTATEDIR@/lock/subsys/lxc" | |
275 | fi | |
276 | ||
54b1eb68 MH |
277 | write_lxc_configuration |
278 | ||
279 | write_distro_inittab | |
280 | ||
281 | write_distro_hostname | |
282 | ||
283 | write_distro_fstab | |
284 | ||
285 | write_distro_network | |
286 | ||
287 | write_distro_sshd_config | |
288 | ||
289 | write_distro_selinux | |
290 | ||
291 | @BINDIR@/lxc-create -n ${NAME} -f ${CONFFILE} | |
292 | RES=$? | |
293 | ||
294 | # remove the configuration files | |
295 | rm -f ${CONFFILE} | |
54b1eb68 MH |
296 | |
297 | if [ "${RES}" != "0" ]; then | |
298 | echo "Failed to create '${NAME}'" | |
299 | exit 1 | |
300 | fi | |
301 | ||
302 | echo "Done." | |
303 | echo -e "\nYou can run your container with the 'lxc-start -n ${NAME}'\n" | |
304 | } | |
305 | ||
306 | destroy() { | |
307 | ||
308 | echo -n "What is the name for the container ? [${NAME}] " | |
309 | read _NAME_ | |
310 | ||
311 | if [ ! -z "${_NAME_}" ]; then | |
312 | NAME=${_NAME_} | |
313 | fi | |
314 | ||
315 | @BINDIR@/lxc-destroy -n ${NAME} | |
316 | RETVAL=$? | |
317 | if [ ! ${RETVAL} -eq 0 ]; then | |
318 | echo "Failed to destroyed '${NAME}'" | |
319 | return ${RETVAL} | |
320 | fi | |
321 | ||
322 | ROOTFS="./rootfs.${NAME}" | |
323 | ||
324 | echo -n "Shall I remove the rootfs [y/n] ? " | |
325 | read | |
326 | if [ "${REPLY}" = "y" ]; then | |
327 | rm -rf ${ROOTFS} | |
328 | fi | |
329 | ||
330 | return 0 | |
331 | } | |
332 | ||
333 | help() { | |
334 | cat <<EOF | |
335 | ||
336 | This script is a helper to create ${DISTRO} system containers. | |
337 | ||
338 | The script will create the container configuration file following | |
339 | the informations submitted interactively with 'lxc-${DISTRO} create' | |
340 | ||
341 | The first creation will download, with yum, a ${DISTRO} minimal | |
342 | install and store it into a cache. | |
343 | ||
344 | The script will copy from the cache the root filesystem to the | |
345 | current directory. | |
346 | ||
347 | If there is a problem with the container, (bad configuration for | |
348 | example), you can destroy the container with 'lxc-${DISTRO} destroy' | |
349 | but without removing the rootfs and recreate it again with | |
350 | 'lxc-${DISTRO} create'. | |
351 | ||
352 | If you want to create another ${DISTRO} container, call the 'lxc-${DISTRO} | |
353 | create' again, specifying another name and new parameters. | |
354 | ||
355 | At any time you can purge the ${DISTRO} cache download by calling | |
356 | 'lxc-${DISTRO} purge' | |
357 | ||
358 | Have fun :) | |
359 | ||
360 | EOF | |
361 | } | |
362 | ||
363 | purge() { | |
364 | ||
365 | if [ ! -e ${CACHE} ]; then | |
366 | exit 0 | |
367 | fi | |
368 | ||
369 | # lock, so we won't purge while someone is creating a repository | |
370 | ( | |
371 | flock -n -x 200 | |
372 | ||
373 | RES=$? | |
374 | if [ "${RES}" != "0" ]; then | |
375 | echo "Cache repository is busy." | |
376 | exit 1 | |
377 | fi | |
378 | ||
379 | echo -n "Purging the download cache..." | |
380 | rm --preserve-root --one-file-system -rf ${CACHE} && echo "Done." || exit 1 | |
381 | exit 0 | |
382 | ||
383 | ) 200> "@LOCALSTATEDIR@/lock/subsys/lxc" | |
384 | } | |
385 | ||
386 | # Note: assuming uid==0 is root -- might break with userns?? | |
387 | if [ "$(id -u)" != "0" ]; then | |
388 | echo "This script should be run as 'root'" | |
389 | exit 1 | |
390 | fi | |
391 | ||
392 | # Detect which executable we were run as, lxc-fedora or lxc-redhat | |
393 | case "$0" in | |
394 | *lxc-redhat) | |
395 | DISTRO="redhat";; | |
396 | *) # default is fedora | |
397 | DISTRO="fedora";; | |
398 | esac | |
399 | CACHE="@LOCALSTATEDIR@/cache/lxc/${DISTRO}" | |
400 | ||
401 | case "$1" in | |
402 | create) | |
403 | create;; | |
404 | destroy) | |
405 | destroy;; | |
406 | help) | |
407 | help;; | |
408 | purge) | |
409 | purge;; | |
410 | *) | |
411 | echo "Usage: $0 {create|destroy|purge|help}" | |
412 | exit 1;; | |
413 | esac |