]>
Commit | Line | Data |
---|---|---|
f8d0243a | 1 | #!/bin/bash |
2 | ||
3 | # | |
4 | # LXC template for gentoo | |
5 | # | |
6 | # Author: Guillaume Zitta <lxc@zitta.fr> | |
7 | # | |
8 | # Widely inspired from lxc-gentoo script at https://github.com/globalcitizen/lxc-gentoo | |
9 | # | |
10 | # this version is reworked with : | |
11 | # - out of the lxc-create compat | |
12 | # - vanilla gentoo config | |
13 | # - ready to use cache | |
14 | # | |
15 | ||
8ec981fc | 16 | # Detect use under userns (unsupported) |
c63c04fc | 17 | for arg in "$@"; do |
96283b54 SG |
18 | [ "$arg" = "--" ] && break |
19 | if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then | |
8ec981fc SG |
20 | echo "This template can't be used for unprivileged containers." 1>&2 |
21 | echo "You may want to try the \"download\" template instead." 1>&2 | |
22 | exit 1 | |
23 | fi | |
24 | done | |
25 | ||
207bf0e4 SG |
26 | # Make sure the usual locations are in PATH |
27 | export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin | |
28 | ||
f8d0243a | 29 | # Ensure strict root's umask doesen't render the VM unusable |
30 | umask 022 | |
31 | ||
cae3584e | 32 | LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@" |
33 | ||
f8d0243a | 34 | ################################################################################ |
35 | # Various helper functions | |
36 | ################################################################################ | |
37 | ||
38 | # param: $1: the name of the lock | |
39 | # param: $2: the timeout for the lock | |
40 | # The rest contain the command to execute and its parameters | |
41 | execute_exclusively() | |
42 | { | |
43 | mkdir -p @LOCALSTATEDIR@/lock/subsys/ | |
44 | ||
45 | local lock_name="$1" | |
46 | local timeout="$2" | |
47 | shift 2 | |
48 | ||
49 | { | |
50 | printf "Attempting to obtain an exclusive lock (timeout: %s sec) named \"%s\"...\n" "${timeout}" "$lock_name" | |
51 | ||
52 | flock -x -w "${timeout}" 50 | |
53 | ||
54 | if [[ $? -ne 0 ]]; then | |
55 | printf " => unable to obtain lock, aborting.\n" | |
56 | return 2 | |
57 | else | |
58 | printf " => done.\n" | |
59 | fi | |
60 | ||
61 | printf " => Executing \"%s\"\n" "$*" | |
62 | "$@" | |
63 | retval=$? | |
64 | } 50> "@LOCALSTATEDIR@/lock/subsys/lxc-gentoo-${lock_name}" | |
65 | return $retval | |
66 | } | |
67 | ||
68 | # a die function is always a good idea | |
69 | die() | |
70 | { | |
71 | printf "\n[the last exit code leading to this death was: %s ]\n" "$?" | |
72 | local retval="$1" | |
73 | shift 1 | |
74 | printf "$@" | |
75 | exit "$retval" | |
76 | } | |
77 | ||
78 | # gentoo arch/variant detection | |
79 | set_default_arch() | |
80 | { | |
81 | printf "### set_default_arch: default arch/variant autodetect...\n" | |
4849ab99 | 82 | arch=$(uname -m) |
f8d0243a | 83 | if [[ $arch =~ i.86 ]]; then |
84 | arch="x86" | |
85 | variant="x86" | |
86 | elif [[ $arch == "x86_64" ]]; then | |
87 | arch="amd64" | |
88 | variant="amd64" | |
89 | elif [[ $arch =~ arm.* ]]; then | |
90 | arch="arm" | |
91 | variant="armv7a" | |
92 | else | |
93 | #who knows, it may work... | |
94 | printf " => warn: unexpected arch:${arch} let me knows if it works :)\n" | |
95 | variant="${arch}" | |
96 | fi | |
97 | printf " => Got: arch=%s variant=%s\n" "${arch}" "${variant}" | |
98 | } | |
99 | ||
100 | store_user_message() | |
101 | { | |
102 | user_message="${user_message}=> $@\n" | |
103 | } | |
104 | ||
105 | ################################################################################ | |
106 | # CACHE Preparation | |
107 | ################################################################################ | |
108 | # during setup cachedir is $cacheroot/partial-$arch-$variant | |
109 | # at the end, it will be $cacheroot/rootfs-$arch-$variant | |
110 | ||
111 | cache_setup(){ | |
112 | partialfs="${cacheroot}/partial-${arch}-${variant}" | |
113 | ||
114 | #if cache exists and flush not needed, return | |
115 | [[ -d "${cachefs}" && -z "${flush_cache}" ]] && return 0 | |
116 | ||
117 | printf "###### cache_setup(): doing cache preparation\n" | |
118 | local retval=1 | |
119 | ||
120 | #clean from failed previous run | |
121 | rm -rf "${partialfs}" | |
122 | mkdir -p "${partialfs}" | |
123 | ||
124 | #let's go | |
125 | cache_precheck && \ | |
126 | cache_stage3 && \ | |
127 | cache_portage && \ | |
128 | cache_inittab && \ | |
129 | cache_net && \ | |
130 | cache_dev && \ | |
131 | cache_openrc && \ | |
3a74e909 | 132 | cache_locale && \ |
f8d0243a | 133 | rm -rf "${cachefs}" && \ |
134 | mv "${partialfs}" "${cachefs}" && \ | |
135 | printf "###### cache_setup: Cache should be ready\n" | |
136 | ||
137 | return $? | |
138 | } | |
139 | ||
140 | cache_precheck() | |
141 | { | |
142 | printf "### cache_precheck(): doing some pre-start checks ...\n" | |
143 | # never hurts to have a fail-safe. | |
144 | [[ -n "${cacheroot//\/}" ]] \ | |
ec64264d | 145 | || die 8 "\$cacheroot (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${cacheroot}" |
f8d0243a | 146 | } |
147 | ||
148 | #get latest stage3 tarball | |
149 | cache_stage3() | |
150 | { | |
151 | printf "### cache_stage3(): stage3 cache deployment...\n" | |
152 | ||
153 | if [ -z "${tarball}" ]; then | |
154 | #variables init | |
155 | local stage3_baseurl="${mirror}/releases/${arch}/autobuilds" | |
156 | ||
157 | # get latest-stage3....txt file for subpath | |
158 | local stage3_pointer="${stage3_baseurl}/latest-stage3-${variant}.txt" | |
159 | ||
160 | printf "Determining path to latest Gentoo %s (%s) stage3 archive...\n" "${arch}" "${variant}" | |
161 | printf " => downloading and processing %s\n" "${stage3_pointer}" | |
162 | ||
35e68b04 | 163 | local stage3_latest_tarball=$(wget -q -O - "${stage3_pointer}" | tail -n1 | cut -d' ' -f1) \ |
f8d0243a | 164 | || die 6 "Error: unable to fetch\n" |
165 | ||
166 | printf " => Got: %s\n" "${stage3_latest_tarball}" | |
167 | ||
168 | printf "Downloading/untarring the actual stage3 tarball...\n" | |
dc5518b8 TS |
169 | wget -O - "${stage3_baseurl}/${stage3_latest_tarball}" \ |
170 | | tar -xjpf - --numeric-owner -C "${partialfs}" \ | |
f8d0243a | 171 | || die 6 "Error: unable to fetch or untar\n" |
172 | printf " => extracted to: %s\n" "${partialfs}" | |
173 | else | |
174 | printf "Extracting the stage3 tarball...\n" | |
dc5518b8 TS |
175 | tar -xpf "${tarball}" --numeric-owner -C "${partialfs}" \ |
176 | || die 6 "unable to untar ${tarball} to ${partialfs}" | |
f8d0243a | 177 | fi |
178 | ||
179 | #check if it chroots | |
180 | printf "chroot test..." | |
181 | chroot ${partialfs} /bin/true || die 1 "Error: chroot %s /bin/true, failed" "${partialfs}" | |
182 | printf " OK\n" | |
183 | printf " => stage3 cache extracted in : %s\n" "${partialfs}" | |
184 | return 0 | |
185 | } | |
186 | ||
187 | cache_portage() | |
188 | { | |
189 | printf "### cache_portage: caching portage tree tarball...\n" | |
190 | [[ -z "${flush_cache}" && -f "${portage_cache}" ]] && return 0 | |
191 | ||
192 | rm -f ${portage_cache} | |
193 | ||
194 | printf "Downloading Gentoo portage (software build database) snapshot...\n" | |
195 | execute_exclusively portage 60 wget -O "${portage_cache}" "${mirror}/snapshots/portage-latest.tar.bz2" \ | |
196 | || die 6 "Error: unable to fetch\n" | |
197 | printf " => done.\n" | |
198 | } | |
199 | ||
200 | # custom inittab | |
201 | cache_inittab() | |
202 | { | |
203 | printf "### cache_inittab: tuning inittab...\n" | |
204 | ||
205 | INITTAB="${partialfs}/etc/inittab" | |
206 | ||
207 | [[ -w "$INITTAB" ]] || die 1 "Error: $INITTAB is not writeable" | |
208 | ||
209 | # create console | |
210 | echo "# Lxc main console" >> "$INITTAB" | |
211 | echo "1:12345:respawn:/sbin/agetty -a root --noclear 115200 console linux" >> "$INITTAB" | |
212 | ||
213 | # finally we add a pf line to enable clean shutdown on SIGPWR (issue 60) | |
214 | echo "# clean container shutdown on SIGPWR" >> "$INITTAB" | |
215 | echo "pf:12345:powerwait:/sbin/halt" >> "$INITTAB" | |
216 | ||
217 | # we also blank out /etc/issue here in order to prevent delays spawning login | |
218 | # caused by attempts to determine domainname on disconnected containers | |
219 | sed -i 's/[\][Oo]//g' "${partialfs}/etc/issue" | |
220 | } | |
221 | ||
222 | cache_net() | |
223 | { | |
224 | printf "### cache_net: doing some useful net tuning...\n" | |
225 | # useful for chroot | |
226 | # /etc/resolv.conf | |
227 | grep -i 'search ' /etc/resolv.conf > "${partialfs}/etc/resolv.conf" | |
228 | grep -i 'nameserver ' /etc/resolv.conf >> "${partialfs}/etc/resolv.conf" | |
229 | ||
230 | # fix boot-time interface config wipe under aggressive cap drop | |
231 | # (openrc 0.9.8.4 ~sep 2012 - https://bugs.gentoo.org/show_bug.cgi?id=436266) | |
232 | # initial warkaround was: sed -i -e 's/^#rc_nostop=""/rc_nostop="net.eth0 net.lo"/' "${partialfs}/etc/rc.conf" | |
233 | # but this one does not depends on interfaces names | |
234 | echo 'rc_keyword="-stop"' >> "${partialfs}/etc/conf.d/net" | |
235 | } | |
236 | ||
237 | cache_dev() | |
238 | { | |
239 | printf "### cache_dev(): /dev tuning...\n" | |
240 | ||
241 | #Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054 | |
242 | mkdir "${partialfs}/dev/pts" | |
cae3584e | 243 | mkdir "${partialfs}/dev/shm" |
244 | mkdir "${partialfs}/dev/mqueue" | |
f8d0243a | 245 | |
9749441a SG |
246 | mkdir -m 755 "${partialfs}/dev/net" |
247 | mknod -m 666 "${partialfs}/dev/net/tun" c 10 200 | |
f8d0243a | 248 | |
249 | return 0 | |
250 | } | |
251 | ||
252 | # fix openrc system | |
253 | cache_openrc() | |
254 | { | |
255 | printf "### cache_openrc(): doing openrc tuning\n" | |
256 | ||
257 | #Wait for https://bugs.gentoo.org/show_bug.cgi?id=496054 | |
258 | chroot "${partialfs}" sed s/-lxc//g -i "/etc/init.d/devfs" | |
259 | ||
260 | return 0 | |
261 | } | |
262 | ||
3a74e909 GZ |
263 | cache_locale() |
264 | { | |
265 | printf "### cache_locale(): initiating minimale locale en_US.UTF-8 \n" | |
266 | ||
267 | echo "en_US.UTF-8 UTF-8" >> "${partialfs}/etc/locale.gen" | |
268 | chroot "${partialfs}" locale-gen | |
269 | ||
270 | return 0 | |
271 | } | |
272 | ||
f8d0243a | 273 | ################################################################################ |
274 | # CONTAINER Preparation | |
275 | ################################################################################ | |
276 | ||
277 | container_setup() { | |
278 | printf "##### container_setup(): starting container setup\n" | |
279 | ||
280 | #in most cases lxc-create should have provided a copy of default lxc.conf | |
281 | #let's tag where template starts, or just create the files | |
282 | echo '### lxc-gentoo template stuff starts here' >> "$path/config" | |
283 | ||
284 | #Determine rootfs | |
285 | #If backingstore was specified, lxc.rootfs should be present or --rootfs did the rootfs var creation | |
286 | if [ -z "${rootfs}" ]; then | |
287 | rootfs=`awk -F= '$1 ~ /^lxc.rootfs/ { print $2 }' "$path/config" 2>/dev/null` | |
288 | if [ -z "${rootfs}" ]; then | |
289 | #OK it's default | |
290 | rootfs="${path}/rootfs" | |
291 | fi | |
292 | fi | |
293 | store_user_message "rootfs of container is : ${rootfs}" | |
294 | store_user_message "config of container is : ${path}/config" | |
295 | ||
296 | container_precheck && \ | |
297 | container_rootfs && \ | |
298 | container_consoles && \ | |
299 | container_tz && \ | |
300 | container_portage && \ | |
301 | container_net && \ | |
302 | container_hostname && \ | |
303 | container_auth && \ | |
84ad17ed | 304 | container_sshd && \ |
f8d0243a | 305 | container_conf |
306 | if [ $? -ne 0 ]; then | |
307 | die 1 "container_setup(): one step didn't complete, sorry\n" | |
308 | fi | |
309 | ||
310 | printf "###### container_setup(): container should be ready to start!\n" | |
311 | printf "\n\n" | |
312 | printf "You could now use you container with: lxc-start -n %s\n" "${name}" | |
313 | printf "little things you should know about your container:\n" | |
314 | printf "${user_message}" | |
315 | return 0 | |
316 | } | |
317 | ||
318 | container_precheck() | |
319 | { | |
320 | printf "### container_precheck(): doing some pre-start checks ...\n" | |
321 | # never hurts to have a fail-safe. | |
322 | [[ -n "${name//\/}" ]] \ | |
ec64264d | 323 | || die 8 "\$name (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${name}" |
f8d0243a | 324 | |
325 | [[ -n "${rootfs//\/}" ]] \ | |
ec64264d | 326 | || die 8 "\$rootfs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${rootfs}" |
f8d0243a | 327 | |
328 | [[ -n "${cachefs//\/}" ]] \ | |
ec64264d | 329 | || die 8 "\$cachefs (%s) IS EMPTY OR MADE OF ONLY DIRECTORY SEPARATORS, THIS IS *VERY* BAD!\n" "${cachefs}" |
f8d0243a | 330 | |
331 | # check if the rootfs already exists | |
332 | [[ -d "${rootfs}/etc" ]] && die 18 "Error: \$rootfs (%s) already exists!" "${rootfs}" | |
333 | ||
334 | # check cache | |
335 | [[ ! -d "${cachefs}/etc" ]] && die 1 "Error: \$cachefs (%s) not found!" "${cachefs}" | |
336 | ||
337 | return 0 | |
338 | } | |
339 | ||
340 | container_rootfs() | |
341 | { | |
342 | printf "#### container_rootfs(): copying rootfs %s from cache %s ...\n" "${rootfs}" "${cachefs}" | |
dc5518b8 TS |
343 | tar -c -f - --numeric-owner -C "${cachefs}" . \ |
344 | | tar -x -p -f - --numeric-owner -C "${rootfs}" \ | |
345 | || die 1 "Error: cache copy to rootfs failed" | |
f8d0243a | 346 | |
347 | printf "chroot test..." | |
348 | chroot "${rootfs}" /bin/true || die 1 "Error: 'chroot %s /bin/true' failed" | |
349 | printf " OK\n" | |
350 | ||
351 | printf " => done\n" | |
352 | return 0 | |
353 | } | |
354 | ||
355 | container_consoles() { | |
356 | printf "#### container_consoles(): setting container consoles ...\n" | |
357 | ||
358 | # disable unwanted ttys | |
359 | if [[ ${tty} < 6 ]]; then | |
360 | local mindis=$(( ${tty} + 1 )) | |
361 | sed -i "s/^c[${mindis}-6]/#&/" "${rootfs}/etc/inittab" | |
362 | fi | |
363 | printf " => main console + ${tty} ttys\n" | |
364 | ||
365 | if [[ -z "${autologin}" ]]; then | |
366 | sed 's/agetty -a root/agetty/' -i "${rootfs}/etc/inittab" | |
367 | elif [[ "${user}" != "root" ]]; then | |
368 | sed "s/agetty -a root/agetty -a ${user}/" -i "${rootfs}/etc/inittab" | |
369 | printf " => Autologin on main console for %s enabled\n" "${user}" | |
370 | [[ -z "${forced_password}" ]] && unset password | |
371 | store_user_message "${user} has autologin on main console" | |
372 | else | |
373 | printf " => Autologin on main console for root enabled\n" | |
374 | [[ -z "${forced_password}" ]] && unset password | |
375 | store_user_message "${user} has autologin on main console" | |
376 | fi | |
377 | printf " => done\n" | |
378 | } | |
379 | ||
380 | container_tz() | |
381 | { | |
382 | printf "#### container_tz(): setting container timezone ...\n" | |
383 | ||
384 | #let's try to copy it from host | |
385 | if [ -L "/etc/localtime" ]; then | |
386 | #host has a symlink | |
387 | #let see if we can reproduct symlink | |
388 | target=$(readlink /etc/localtime) | |
389 | if [[ "$target" != "" ]]; then | |
390 | if [ -f "${rootfs}/${target}" ]; then | |
391 | #same target exists in container | |
392 | chroot "${rootfs}" ln -sf "${target}" "/etc/localtime" | |
393 | printf " => host symlink reproducted in container : %s\n" "${target}" | |
394 | store_user_message "timezone copyed from host" | |
395 | return 0 | |
396 | fi | |
397 | fi | |
398 | fi | |
399 | ||
400 | if [ -e /etc/localtime ]; then | |
401 | # duplicate host timezone | |
402 | cat /etc/localtime > "${rootfs}/etc/localtime" | |
403 | printf " => host localtime copyed to container\n" | |
404 | store_user_message "timezone was staticly copyed from host" | |
405 | else | |
406 | # otherwise set up UTC | |
407 | chroot "${rootfs}" ln -sf /usr/share/zoneinfo/UTC /etc/localtime | |
408 | printf " => fallback: fixed to UTC\n" | |
409 | store_user_message "timezone was fixed to UTC" | |
410 | fi | |
411 | } | |
412 | ||
413 | ||
414 | container_portage() | |
415 | { | |
416 | printf "#### container_portage(): setting container portage... \n" | |
417 | ||
418 | #default entry for conf | |
419 | portage_mount="#container set with private portage tree, no mount here" | |
420 | ||
421 | printf "Warnings are normal here, don't worry\n" | |
422 | #container repos detection | |
423 | if chroot ${rootfs} portageq get_repo_path / gentoo > /dev/null ; then | |
424 | portage_container="$(chroot ${rootfs} portageq get_repo_path / gentoo)" | |
425 | else | |
426 | die 1 "Failed to figure out container portage tree location with portageq get_repo_path / gentoo\n" | |
427 | fi | |
428 | ||
429 | if [[ -n "${private_portage}" ]]; then | |
430 | container_private_portage | |
431 | return 0 | |
432 | fi | |
433 | ||
434 | if [ -z "${portage_dir}" ]; then | |
435 | #gentoo host detection | |
436 | printf "trying to guess portage_dir from host...\n" | |
437 | portage_dir="$(portageq get_repo_path / gentoo 2>/dev/null)" | |
438 | if [ ! -d "${portage_dir}/profiles" ]; then | |
439 | printf " => host portage detection failed (not gentoo host), fallback to private portage tree\n" | |
440 | container_private_portage | |
441 | return 0 | |
442 | fi | |
443 | else | |
444 | if [ ! -d "${portage_dir}/profiles" ]; then | |
445 | die 1 "specified portage_dir (%s) does not contains profiles, is it a portage tree ?\n" "${portage_dir}" | |
446 | fi | |
447 | fi | |
448 | ||
b69e7bf1 | 449 | printf "trying to guess portage distfiles dir from host ...\n" |
450 | portage_distfiles_dir="$(portageq distdir 2>/dev/null)" | |
451 | if [ ! -d "${portage_distfiles_dir}" ]; then | |
452 | portage_distfiles_dir="${portage_dir}/distfiles" | |
453 | fi | |
454 | ||
f8d0243a | 455 | # if we are here, we have shared portage_dir |
456 | #ensure dir exists | |
457 | chroot "${rootfs}" mkdir ${portage_container} | |
458 | portage_mount="#container set with shared portage | |
cf261d58 | 459 | lxc.mount.entry=${portage_dir} ${portage_container/\//} none ro,bind 0 0 |
b69e7bf1 | 460 | lxc.mount.entry=${portage_distfiles_dir} ${portage_container/\//}/distfiles none rw,bind 0 0 |
cf261d58 | 461 | #If you use eix, you should uncomment this |
462 | #lxc.mount.entry=/var/cache/eix var/cache/eix none ro,bind 0 0" | |
f8d0243a | 463 | store_user_message "container has a shared portage from host's ${portage_dir} to ${portage_container/\//}" |
464 | #Let's propose binary packages | |
465 | cat <<- EOF >> "${rootfs}/etc/portage/make.conf" | |
cf261d58 | 466 | # enable this to store built binary packages |
467 | #FEATURES="\$FEATURES buildpkg" | |
f8d0243a | 468 | |
cf261d58 | 469 | # enable this to use built binary packages |
470 | #EMERGE_DEFAULT_OPTS="\${EMERGE_DEFAULT_OPTS} --usepkg" | |
f8d0243a | 471 | |
cf261d58 | 472 | # enable and *tune* this kind of entry to slot binaries, specialy if you use multiples archs and variants |
473 | #PKGDIR="\${PKGDIR}/amd64 | |
474 | #or PKGDIR="\${PKGDIR}/hardened" | |
f8d0243a | 475 | EOF |
ec64264d | 476 | printf " => portage stuff done, see /etc/portage/make.conf for additional tricks\n" |
f8d0243a | 477 | |
478 | } | |
479 | ||
480 | container_private_portage() | |
481 | { | |
482 | #called from container_portage() do not call directly from container_setup | |
483 | printf "# untaring private portage to %s from %s ... \n" "${rootfs}/${portage_container}" "${portage_cache}" | |
484 | mkdir -p "${rootfs}/${portage_container}" | |
dc5518b8 TS |
485 | execute_exclusively portage 60 \ |
486 | tar -xp --strip-components 1 -C "${rootfs}/${portage_container}" \ | |
487 | -f "${portage_cache}" --numeric-owner \ | |
f8d0243a | 488 | || die 2 "Error: unable to extract the portage tree.\n" |
489 | store_user_message "container has its own portage tree at ${portage_container}" | |
490 | printf "=> done\n" | |
491 | } | |
492 | ||
493 | #helper func for container_genconf_net() | |
494 | nic_write() | |
495 | { | |
496 | #display with gentoo's confd.net format | |
497 | echo "config_${nic_name}=\"${nic_conf}\"" | |
498 | #add to managed list | |
499 | [[ "${nic_conf}" == "dhcp" ]] && nic_managed="${nic_managed} ${nic_name}" | |
500 | [[ "${nic_conf}" == "null" ]] && nic_unmanaged="${nic_unmanaged} ${nic_name}" | |
501 | [[ -z "${nic_hwaddr}" && ${nic_type} == "veth" ]] && nic_wo_hwaddr="${nic_wo_hwaddr} ${nic_name}" | |
502 | nic_writed=1 | |
503 | } | |
504 | ||
505 | #Analyse lxc.conf and print conf.d/net content | |
506 | container_conf_net() | |
507 | { | |
508 | local file=${1} | |
509 | [[ -z "${nic_last}" ]] && nic_last=-1 | |
510 | [[ -z "${nic_named}" ]] && nic_named=0 | |
511 | OLDIFS=$IFS | |
512 | IFS=" | |
513 | " | |
cae3584e | 514 | #let's do some drity bash things to parse lxc network conf |
f8d0243a | 515 | for line in $( sed -r "s/[ ]*=[ ]*/_real_ugly_sep_42_/" "${file}" ); do |
516 | key=$(echo "${line}" | sed 's/_real_ugly_sep_42_.*$//') | |
517 | value=$(echo "${line}" | sed 's/^.*_real_ugly_sep_42_//') | |
518 | ||
519 | #new nic ! | |
7fa3f2e9 | 520 | if [[ "${key}" == "lxc.net.0.type" ]]; then |
f8d0243a | 521 | #we don't know what to do with it. |
522 | [[ "${value}" == "empty" ]] && continue | |
523 | ||
524 | #write conf from previous loops | |
525 | [[ "${nic_writed}" == "0" ]] && nic_write | |
526 | ||
527 | #init defaults | |
528 | let nic_last=nic_last+1 | |
529 | ||
530 | nic_writed=0 | |
531 | #if 1 named between 2 not named: last is eth1 | |
532 | #=> Number is ID munis number of named NIC before | |
533 | nic_name="eth$(( ${nic_last} - ${nic_named} ))" | |
534 | nic_conf="dhcp" | |
535 | nic_type="${value}" | |
536 | fi | |
537 | ||
7fa3f2e9 | 538 | if [[ "${key}" == "lxc.net.0.hwaddr" ]]; then |
f8d0243a | 539 | nic_hwaddr=1 |
540 | fi | |
541 | ||
7fa3f2e9 | 542 | if [[ "${key}" =~ ^lxc.net.0.ipv(4|6) ]]; then |
f8d0243a | 543 | #tell openrc to not manage this NIC as LXC set there address |
544 | nic_conf="null" | |
545 | fi | |
7fa3f2e9 | 546 | if [[ "${key}" =~ ^lxc.net.0.name ]]; then |
f8d0243a | 547 | nic_name="${value}" |
548 | let nic_named=nic_named+1 | |
549 | fi | |
550 | if [[ "${key}" == "lxc.include" ]]; then | |
551 | #recursive into include | |
552 | container_conf_net "${value}" | |
553 | fi | |
554 | done | |
555 | #write conf from previous loops | |
556 | [[ "${nic_writed}" == "0" ]] && nic_write | |
557 | IFS=$OLDIFS | |
558 | } | |
559 | ||
560 | container_net() | |
561 | { | |
562 | printf "container_net(): setting container network conf... \n" | |
563 | ||
564 | #Analyse network configuration in config | |
565 | container_conf_net "$path/config" >> "${rootfs}/etc/conf.d/net" | |
566 | ||
ec64264d | 567 | # found how much nic finally have |
f8d0243a | 568 | nic_count=$(( ${nic_last} + 1 )) |
569 | ||
570 | # unless openrc manage a nic, we now have to force openrc to automatic | |
571 | # provision of the 'net' dep. If we do not, network dependent services | |
572 | # will fail to load | |
573 | if [[ -z "${nic_managed}" ]]; then | |
574 | #tell openrc that lxc already did the work | |
2562784e | 575 | echo 'rc_provide="net"' >> "${rootfs}/etc/rc.conf" |
f8d0243a | 576 | fi |
577 | ||
578 | #No NIC ? | |
579 | if [[ ${nic_count} == 0 ]]; then | |
580 | #If no Nic, no need to continue | |
581 | bridge=$(brctl show | awk 'NR==2 {print $1}') | |
582 | if [[ "${bridge}" != "" ]]; then | |
583 | store_user_message "No network interface for this container | |
584 | It's a pitty, you have bridge, ${bridge}. | |
585 | If it is for Lxc, use it next time by adding this to your default.conf : | |
7fa3f2e9 | 586 | lxc.net.0.type = veth |
587 | lxc.net.0.link = ${bridge} | |
588 | lxc.net.0.flags = up | |
589 | lxc.net.0.hwaddr = fe:xx:xx:xx:xx:xx" | |
f8d0243a | 590 | return 0 |
591 | else | |
592 | store_user_message "No network interface for this container" | |
593 | return 0 | |
594 | fi | |
595 | fi | |
596 | ||
597 | #For each openrc managed nic, activate | |
cae3584e | 598 | sys_nic_index=1 |
f8d0243a | 599 | for nic in ${nic_managed} |
600 | do | |
601 | chroot "${rootfs}" ln -s net.lo "/etc/init.d/net.${nic}" | |
602 | chroot "${rootfs}" rc-update add net.${nic} default | |
cae3584e | 603 | #fake sysfs for openrc, in case settings does not provide it |
604 | mkdir -p "${rootfs}/sys/class/net/${nic}" | |
605 | echo ${sys_nic_index} > "${rootfs}/sys/class/net/${nic}/ifindex" | |
606 | echo up > "${rootfs}/sys/class/net/${nic}/operstate" | |
607 | let sys_nic_index=sys_nic_index+1 | |
f8d0243a | 608 | done |
609 | ||
610 | #Warn about dynamic hwaddr | |
611 | if [[ -n "${nic_wo_hwaddr}" ]]; then | |
612 | store_user_message "Warning, these veth NIC don't have fixed hwaddr : | |
613 | ${nic_wo_hwaddr} | |
614 | ||
615 | see http://lists.linuxcontainers.org/pipermail/lxc-devel/2013-December/006736.html | |
616 | and man lxc.conf" | |
617 | fi | |
618 | ||
619 | printf " => network conf done.\n" | |
620 | } | |
621 | ||
622 | # custom hostname | |
623 | container_hostname() | |
624 | { | |
625 | printf "#### container_hostname(): setting hostname... \n" | |
3d8b68b1 | 626 | printf "hostname=\"%s\"\n" "${name}" > "${rootfs}/etc/conf.d/hostname" |
f8d0243a | 627 | printf " => done.\n" |
628 | } | |
629 | ||
630 | container_auth() | |
631 | { | |
632 | printf "#### container_auth(): setting authentification... \n" | |
633 | if [[ "${user}" != "root" ]]; then | |
634 | printf " non root user requested, creating... \n" | |
635 | chroot "${rootfs}" useradd --create-home -s /bin/bash "${user}" || die 1 "failed to create user ${user}" | |
636 | printf " => user %s created\n" "${user}" | |
637 | fi | |
638 | store_user_message "Connection user is ${user}" | |
639 | #Home of user | |
640 | auth_home=$(chroot "${rootfs}" getent passwd "${user}" | cut -d : -f 6) | |
641 | if [[ -r "${auth_key}" ]]; then | |
642 | printf " deploying auth_key %s for user %s ...\n" "${auth_key}" "${user}" | |
643 | mkdir -p "${rootfs}/${auth_home}/.ssh" | |
7785e39c | 644 | cat "${auth_key}" >> "${rootfs}/${auth_home}/.ssh/authorized_keys" |
f8d0243a | 645 | chroot "${rootfs}" chown "${user}:" "${auth_home}/.ssh/authorized_keys" |
646 | printf " => inserted public key in %s/.ssh/authorized_keys\n" "${auth_home}" | |
647 | [[ -z "${forced_password}" ]] && unset password | |
7785e39c | 648 | store_user_message "${user} has the ssh key you gave us" |
f8d0243a | 649 | fi |
650 | ||
651 | if [[ -n "${password}" ]]; then | |
652 | printf " setting password for %s ...\n" "${user}" | |
653 | echo "${user}:${password}" | chroot "${rootfs}" chpasswd || die 1 "failed to change password" | |
654 | printf " => done. if you didn't specify , default is 'toor'\n" | |
655 | if [[ -n "${forced_password}" ]]; then | |
656 | store_user_message "${user} has the password you give for him" | |
f8d0243a | 657 | fi |
658 | fi | |
659 | ||
660 | printf " => done.\n" | |
661 | } | |
662 | ||
84ad17ed GZ |
663 | container_sshd() { |
664 | printf "#### container_sshd(): enabling sshd... \n" | |
665 | ||
666 | chroot "${rootfs}" rc-update add sshd || die 1 "failed to enable sshd\n" | |
667 | ||
668 | printf " => done.\n" | |
669 | } | |
670 | ||
f8d0243a | 671 | ################################################################################ |
672 | # lxc configuration files | |
673 | ################################################################################ | |
674 | ||
675 | container_conf() | |
676 | { | |
677 | printf "container_configuration(): making lxc configuration file... \n" | |
678 | ||
679 | #at this point if there | |
680 | conf_file="${path}/config" | |
681 | ||
b8ebaa9c VOR |
682 | # if there is exactly one veth network entry, make sure it has an |
683 | # associated hwaddr. | |
7fa3f2e9 | 684 | nics=`grep -e '^lxc\.net\.0\.type[ \t]*=[ \t]*veth' ${conf_file} | wc -l` |
b8ebaa9c | 685 | if [ $nics -eq 1 ]; then |
7fa3f2e9 | 686 | grep -q "^lxc.net.0.hwaddr" ${conf_file} || sed -i -e "/^lxc\.net\.0\.type[ \t]*=[ \t]*veth/a lxc.net.0.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" ${conf_file} |
b8ebaa9c VOR |
687 | fi |
688 | ||
f8d0243a | 689 | if grep -q "^lxc.rootfs" "${conf_file}" ; then |
690 | #lxc-create already provided one | |
691 | conf_rootfs_line="" | |
692 | else | |
693 | conf_rootfs_line="lxc.rootfs = $(readlink -f "${rootfs}")" | |
694 | fi | |
695 | if [[ "${arch}" == "x86" || "${arch}" == "amd64" ]]; then | |
696 | local conf_arch_line="lxc.arch = ${arch}" | |
697 | else | |
698 | local conf_arch_line="# lxc.arch = ${arch}" | |
699 | fi | |
700 | ||
cae3584e | 701 | cat <<- EOF >> "${conf_file}" |
f8d0243a | 702 | # sets container architecture |
703 | # If desired architecture != amd64 or x86, then we leave it unset as | |
704 | # LXC does not oficially support anything other than x86 or amd64. | |
705 | ${conf_arch_line} | |
706 | ||
f8d0243a | 707 | # set the hostname |
708 | lxc.utsname = ${name} | |
cae3584e | 709 | lxc.tty = ${tty} |
f8d0243a | 710 | |
711 | ${conf_rootfs_line} | |
712 | ${portage_mount} | |
713 | ${conf_sysfs} | |
f8d0243a | 714 | ${conf_mounts} |
715 | ||
cae3584e | 716 | lxc.include = ${LXC_TEMPLATE_CONFIG}/gentoo.${settings}.conf |
f8d0243a | 717 | EOF |
f8d0243a | 718 | printf " => done.\n" |
719 | } | |
720 | ||
721 | usage() | |
722 | { | |
723 | cat <<EOF | |
724 | $1 -h|--help [-a|--arch <arch>] [-v|--variant <variant>] [-P|--private-portage] [--portage-dir <protagedir>] [-t|--tarball <stage3file>] | |
cae3584e | 725 | [-F|--flush-cache] [-c|--cache-only] [-u|--user <username>] [-w|--password <password>] [--autologin] [-S|--auth-key <keyfile>] |
726 | [-s|--settings <name>] [-m|--mirror <gentoomirror>] [--tty <number>] | |
f8d0243a | 727 | |
728 | arch: the container architecture (e.g. amd64): defaults to host arch (currently: '${arch}') | |
729 | If you choose one that needs emulation | |
730 | tested: amd64, x86 | |
731 | You could try any other gentoo arch, why not... | |
732 | ||
733 | variant: gentoo's Architecture variant as of dec 2013 : (currently: '${variant}') | |
734 | for amd64 arch: amd64 (default), amd64-hardened+nomultilib, amd64-hardened, amd64-nomultilib, x32 | |
735 | for x86 arch: i686 (default), i486, i686-hardened | |
736 | for arm arch: armv7a (default), armv7a_hardfp, armv6j, armv6j_hardfp, armv5tel, armv4tl | |
737 | ||
738 | private-portage: by default, /usr/portage is mount-binded with host one if exists (currently: '${private_portage}') | |
739 | this force container to have his own copy | |
740 | ||
741 | portage-dir: portage dir used for shared portage | |
742 | by default the host on if any (currently: '${portage_dir}') | |
743 | ||
744 | tarball: force usage of local stage3 archive (currently: '${arch}') | |
745 | If empty, latest will be downloaded | |
746 | ||
747 | flush-cache: do like there is no previous cache | |
748 | ||
749 | cache-only: just ensure cache is present | |
750 | if cache exists and "flush-cache" not specified, does nothing | |
751 | ||
752 | user: user used in auth oriented options (currently: '${user}') | |
753 | ||
754 | password: password for user (currently: '${password}') | |
755 | if default, usage of auth-key will disable password setting | |
756 | ||
757 | autologin: enable autologin for user (currently: '${autologin}') | |
758 | This unset default password setting | |
759 | ||
760 | auth-key: SSH Public key file to inject into container for user (currently: '${auth_key}') | |
761 | This unset default password setting | |
762 | ||
cae3584e | 763 | settings: choose common configuration (currently: '${settings}') |
764 | see ${LXC_TEMPLATE_CONFIG}/gentoo.*.conf | |
765 | Available settings: | |
766 | $(ls -1 ${LXC_TEMPLATE_CONFIG}/gentoo.*.conf | xargs basename -a -s .conf | sed 's/^gentoo.//') | |
f8d0243a | 767 | |
768 | mirror: gentoo mirror for download (currently: '${mirror}') | |
769 | ||
770 | tty: number of tty (6 max) (currently: '${tty}') | |
f8d0243a | 771 | EOF |
772 | exit 0 | |
773 | } | |
774 | ||
775 | #some overridable defaults | |
776 | set_default_arch | |
777 | ||
778 | mirror="http://distfiles.gentoo.org" | |
779 | user="root" | |
982b5959 | 780 | tty=1 |
cae3584e | 781 | settings="common" |
7785e39c | 782 | options=$(getopt -o hp:n:a:FcPv:t:S:u:w:s:m: -l help,rootfs:,path:,name:,arch:,flush-cache,cache-only,private-portage,variant:,portage-dir:,tarball:,auth-key:,user:,autologin,password:,settings:,mirror:,tty: -- "$@") |
f8d0243a | 783 | |
784 | eval set -- "$options" | |
785 | ||
786 | while true | |
787 | do | |
788 | case "$1" in | |
789 | -h|--help) usage $0 && exit 0;; | |
790 | --rootfs) rootfs=$2; shift 2;; | |
791 | -p|--path) path=$2; shift 2;; | |
792 | -n|--name) name=$2; shift 2;; | |
793 | -a|--arch) arch=$2; shift 2;; | |
794 | -F|--flush-cache) flush_cache=1; shift 1;; | |
4167102e | 795 | -c|--cache-only) cache_only=1; shift 1;; |
f8d0243a | 796 | -P|--private-portage) private_portage=1; shift 1;; |
797 | -v|--variant) variant=$2; shift 2;; | |
798 | --portage-dir) portage_dir=$2; shift 2;; | |
799 | -t|--tarball) tarball=$2; shift 2;; | |
800 | -S|--auth-key) auth_key=$2; shift 2;; | |
801 | -u|--user) user=$2; shift 2;; | |
802 | -w|--password) forced_password=1; password=$2; shift 2;; | |
cae3584e | 803 | -s|--settings) settings=$2; shift 2;; |
f8d0243a | 804 | -m|--mirror) mirror=$2; shift 2;; |
6dc6f80b | 805 | --container-cache) containercache=$2; shift 2;; |
f8d0243a | 806 | --tty) [[ $2 -lt 6 ]] && tty=$2; shift 2;; |
807 | --autologin) autologin=1; shift 1;; | |
808 | --) shift 1; break ;; | |
809 | *) break ;; | |
810 | esac | |
811 | done | |
812 | ||
6dc6f80b KC |
813 | # Allow the cache path to be set by environment variable |
814 | cacheroot="${LXC_CACHE_PATH:-"@LOCALSTATEDIR@/cache/lxc"}/gentoo" | |
f8d0243a | 815 | portage_cache="${cacheroot}/portage.tbz" |
816 | cachefs="${cacheroot}/rootfs-${arch}-${variant}" | |
817 | ||
818 | alias wget="wget --timeout=8 --read-timeout=15 -c -t10 -nd" | |
819 | ||
820 | do_all() { | |
821 | cache_setup | |
822 | if [ -z "${cache_only}" ]; then | |
823 | container_setup | |
824 | fi | |
825 | } | |
826 | ||
827 | execute_exclusively "cache-${arch}-${variant}" 60 do_all |