5808881 [rkeene@sledge /home/rkeene/tmp]$ cat -n lxc-centos.sh
  1 #!/bin/bash
  2 
  3 #
  4 # template script for generating centos container for LXC
  5 #
  6 
  7 #
  8 # lxc: linux Container library
  9 
 10 # Authors:
 11 # Johannes Graumann <johannes_graumann@web.de>
 12 # Based on the lxc-fedora template by
 13 # Daniel Lezcano <daniel.lezcano@free.fr>
 14 # Ramez Hanna <rhanna@informatiq.org>
 15 
 16 # This library is free software; you can redistribute it and/or
 17 # modify it under the terms of the GNU Lesser General Public
 18 # License as published by the Free Software Foundation; either
 19 # version 2.1 of the License, or (at your option) any later version.
 20 
 21 # This library is distributed in the hope that it will be useful,
 22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 23  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 24 # Lesser General Public License for more details.
 25 
 26 # You should have received a copy of the GNU Lesser General Public
 27 # License along with this library; if not, write to the Free Software
 28 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 29 
 30 
 31 #Configurations
 32 arch=$(arch)
 33 cache_base=/var/cache/lxc/centos/$arch
 34 default_path=/var/lib/lxc
 35 root_password=root
 36 
 37 # is this centos?
 38 [ -f /etc/centos-release ] && is_centos=true
 39 
 40 if [ "$arch" = "i686" ]; then
 41     basearch='i386'
 42 else
 43     basearch="${arch}"
 44 fi
 45 
 46 configure_centos()
 47 {
 48 
 49     # disable selinux in centos
 50     mkdir -p $rootfs_path/selinux
 51     echo 0 > $rootfs_path/selinux/enforce
 52 
 53    # configure the network using the dhcp
 54     cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
 55 DEVICE=eth0
 56 BOOTPROTO=dhcp
 57 ONBOOT=yes
 58 HOSTNAME=${name}
 59 NM_CONTROLLED=no
 60 TYPE=Ethernet
 61 EOF
 62 
 63     # set the hostname
 64     cat <<EOF > ${rootfs_path}/etc/sysconfig/network
 65 NETWORKING=yes
 66 HOSTNAME=${name}
 67 EOF
 68 
 69     # set minimal hosts
 70     cat <<EOF > $rootfs_path/etc/hosts
 71 127.0.0.1 localhost $name
 72 EOF
 73 
 74     sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
 75     sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
 76     chroot ${rootfs_path} chkconfig udev-post off
 77     chroot ${rootfs_path} chkconfig network on
 78 
 79     dev_path="${rootfs_path}/dev"
 80     rm -rf $dev_path
 81     mkdir -p $dev_path
 82     mknod -m 666 ${dev_path}/null c 1 3
 83     mknod -m 666 ${dev_path}/zero c 1 5
 84     mknod -m 666 ${dev_path}/random c 1 8
 85     mknod -m 666 ${dev_path}/urandom c 1 9
 86     mkdir -m 755 ${dev_path}/pts
 87     mkdir -m 1777 ${dev_path}/shm
 88     mknod -m 666 ${dev_path}/tty c 5 0
 89     mknod -m 666 ${dev_path}/tty0 c 4 0
 90     mknod -m 666 ${dev_path}/tty1 c 4 1
 91     mknod -m 666 ${dev_path}/tty2 c 4 2
 92     mknod -m 666 ${dev_path}/tty3 c 4 3
 93     mknod -m 666 ${dev_path}/tty4 c 4 4
 94     mknod -m 600 ${dev_path}/console c 5 1
 95     mknod -m 666 ${dev_path}/full c 1 7
 96     mknod -m 600 ${dev_path}/initctl p
 97     mknod -m 666 ${dev_path}/ptmx c 5 2
 98 
 99     echo "setting root passwd to $root_password"
100     echo "root:$root_password" | chroot $rootfs_path chpasswd
101 
102     return 0
103 }
104 
105 function rdom () {
106     local IFS='>'
107     read -d '<' E C
108 }
109 
110 function yum_init() {
111     local url
112     local repomd xmldata
113 
114     echo 'Initializing yum database' >&2
115 
116     url="$1"
117 
118     repomd="$(wget -O - -o /dev/null "${url}/repodata/repomd.xml")"
119 
120     xmldata_path="`while rdom; do
121         case "${E}" in
122             *location\ href=*-primary.xml.gz*)
123                 echo "$E" | sed 's@^.* href="@@;s@".*$@@'
124                 ;;
125         esac
126     done <<<"${repomd}"`"
127 
128     xmldata="$(wget -O - "${url}/${xmldata_path}" | gzip -dc)"
129 
130     echo 'function yum_download() {'
131     echo '  local package download_dir'
132     echo ''
133     echo '  package="$1"'
134     echo '  download_dir="$2"'
135     echo ''
136     echo '  case "${package}" in'
137 
138     echo 'Reading package information:' >&2
139 
140     while rdom; do
141 
142         obj="${E%% *}"
143         attrs="${E#* }"
144 
145         is_closing='0'
146         is_opening='0'
147         case "${obj}" in
148             ''|'?'*)
149                 continue
150                 ;;
151             /*)
152                 obj="${obj#/}"
153 
154                 is_closing='1'
155                 ;;
156             *)
157                 is_opening='1'
158                 case "${E}" in
159                     */)
160                         obj="${obj%/}"
161                         attrs="${attrs%/}"
162                         # Self closing
163                         is_closing='1'
164                         ;;
165                 esac
166 
167                 state="${state}/${obj}"
168 
169                 ;;
170         esac
171 
172         case "${state}" in
173             /metadata)
174                 totalpackages="$(echo "${attrs}" | sed 's@^.* packages="@@;s@".*$@@')"
175                 ;;
176             /metadata/package)
177                 if [ "${is_closing}" = '1' ]; then
178                     packageidx=$[${packageidx} + 1]
179 
180                     echo -ne "  * ${packageidx} / ${totalpackages}      "'\r' >&2
181 
182                     # Emit package data
183                     provides_case="$(echo "${provides}" | sed 's@   *@ @g;s@^ *@'"'"'@;s@ *$@'"'"'@;s@ @'"'|'"'@g')"
184                     package_file="$(basename "${location}")"
185 
186                     echo "      ${provides_case})"
187                     echo "          if [ -f \"\${download_dir}\"'/${package_file}' ]; then"
188                     echo '              echo "Skipping ${package}"'
189                     echo ''
190                     echo "              return 0"
191                     echo "          fi"
192                     echo ''
193                     echo '          echo "Installing ${package}"'
194                     echo ""
195                     echo "          wget -o /dev/null -O \"\${download_dir}\"'/${package_file}' '${url}/${location}' ||
	rm -f \"\${download_dir}\"'/${package_file}'"
196                     echo ""
197                     echo "          if [ ! -f \"\${download_dir}\"'/${package_file}' ]; then"
198                     echo "              return 1"
199                     echo "          fi"
200                     echo ""
201                     for require in ${requires}; do
202                         case "${require}" in
203                             /*)
204                                 echo "          yum_download '${require}' \"\${download_dir}\" || return 1"
205                                 ;;
206                             *)
207                                 if [ -n "${arch}" ]; then
208                                     require_with_arch="${require}.${arch}"
209 
210                                     echo -n "           yum_download '${require_with_arch}' \"\${download_dir}\" || "
211                                     echo "yum_download '${require}' \"\${download_dir}\" || return 1"
212                                 else
213                                     echo -n "           "
214                                     for dotarch in '' '.x86_64' '.i686' '.i386'; do
215                                         echo -n "yum_download '${require}${dotarch}' \"\${download_dir}\" || "
216                                     done
217                                     echo "return 1"
218                                 fi
219                                 ;;
220                         esac
221 
222                     done | sort -u
223                     echo "          ;;"
224                 fi
225 
226                 if [ "${is_opening}" = '1' ]; then
227                     # Initialize package data
228                     location=''
229                     provides=''
230                     requires=''
231                     arch=''
232                 fi
233                 ;;
234             /metadata/package/location)
235                 location="$(eval "${attrs}"; echo "${href}")"
236                 ;;
237             /metadata/package/arch)
238                 if [ "${is_opening}" = '1' ]; then
239                     arch="$(echo ${C})"
240 
241                     if [ "${arch}" = 'noarch' ]; then
242                         arch=''
243                     fi
244                 fi
245                 ;;
246             /metadata/package/format/file)
247                 if [ "${is_opening}" = '1' ]; then
248                     provides="${provides} $(echo ${C})"
249                 fi
250                 ;;
251             /metadata/package/format/rpm:provides/rpm:entry)
252                 provided="$(eval "${attrs}"; echo "${name}")"
253                 if [ -n "${arch}" ]; then
254                     provided="${provided}.${arch}"
255                 fi
256 
257                 provides="${provides} ${provided}"
258                 ;;
259             /metadata/package/format/rpm:requires/rpm:entry)
260                 requires="${requires} $(eval "${attrs}"; echo "${name}")"
261                 ;;
262             *)
263                 if false && [ "${is_closing}" = '1' ]; then
264                     echo "${state}: ${attrs}"
265                 fi
266                 ;;
267         esac
268 
269         if [ "${is_closing}" = '1' ]; then
270             state="${state%/*}"
271         fi
272     done <<<"${xmldata}"
273 
274     echo '      *)'
275     echo '          echo "Unknown package: ${package}"'
276     echo '          return 1'
277     echo '          ;;'
278     echo '  esac'
279     echo '}'
280 
281     echo '' >&2
282 }
283 
284 function yum_download() {
285     local packages dir url
286 
287     packages="$1"
288     dir="$2"
289     url="$3"
290 
291     if [ -z "${yum_init}" ]; then
292         yum_init="$(yum_init "${url}")"
293     fi
294 
295     (
296         echo "${yum_init}"
297         for package in ${packages}; do
298             echo "yum_download '${package}' '${dir}'"
299         done
300     ) | bash
301 }
302 
303 function yum_uninit() {
304     unset yum_init
305 }
306 
307 download_centos()
308 {
309     local retval
310 
311     # check the mini centos was not already downloaded
312     INSTALL_ROOT=$cache/partial
313     mkdir -p $INSTALL_ROOT
314     if [ $? -ne 0 ]; then
315     echo "Failed to create '$INSTALL_ROOT' directory"
316     return 1
317     fi
318 
319     # download a mini centos into a cache
320     mkdir -p $INSTALL_ROOT/var/lib/rpm
321     rpm --root $INSTALL_ROOT  --initdb
322 
323     echo "Downloading centos minimal ..."
324     PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig rootfiles policycoreutils"
325     #MIRRORLIST_URL="http://mirrors.fedoraproject.org/mirrorlist?repo=fedora-$release&arch=$arch"
326     MIRRORLIST_URL="http://mirrorlist.centos.org/?release=$release&arch=$basearch&repo=os"
327 
328     for trynumber in 1 2 3; do
329         [ $trynumber != 1 ] && echo "Trying again..."
330         MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1)
331         if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then
332             echo "Failed to get a mirror"
333             continue
334         fi
335         #RELEASE_URL="$MIRROR_URL/Packages/fedora-release-$release-1.noarch.rpm"
336 
337     DOWNLOAD_OK='yes'
338     for package in centos-release-$release-3.el6.centos.9.$arch.rpm; do
339         if [ -s "${INSTALL_ROOT}/${package}" ]; then
340             continue
341         fi
342 
343         PACKAGE_URL="$MIRROR_URL/Packages/${package}"
344         echo "Fetching from $PACKAGE_URL"
345         curl -f "$PACKAGE_URL" > "$INSTALL_ROOT/${package}"
346 
347         if [ $? -ne 0 ]; then
348             rm -f "${INSTALL_ROOT}/${package}"
349 
350             echo "Failed to download centos release rpm"
351 
352             DOWNLOAD_OK='no'
353 
354             continue
355         fi
356 
357     done
358     done
359     if [ $DOWNLOAD_OK != yes ]; then
360         echo "Aborting"
361         return 1
362     fi
363 
364     if [ "${yum_lite}" = '1' ]; then
365     yum_download yum "${INSTALL_ROOT}" "${MIRROR_URL}"
366     yum_uninit
367     fi
368 
369     rpm --root $INSTALL_ROOT --nodeps -ivh "$INSTALL_ROOT"/*.rpm || return 1
370     rm -f "$INSTALL_ROOT"/*.rpm
371 
372     if [ "${yum_lite}" = '1' ]; then
373     mount --bind /dev "${INSTALL_ROOT}/dev"
374     mount --bind /proc "${INSTALL_ROOT}/proc"
375     mount --bind /sys "${INSTALL_ROOT}/sys"
376 
377     cp /etc/resolv.conf "${INSTALL_ROOT}/etc/"
378 
379     chroot "${INSTALL_ROOT}" rpm --rebuilddb
380     chroot "${INSTALL_ROOT}" yum -y --nogpgcheck install $PKG_LIST
381     retval="$?"
382 
383     umount "${INSTALL_ROOT}/dev"
384     umount "${INSTALL_ROOT}/proc"
385     umount "${INSTALL_ROOT}/sys"
386     else
387     yum --installroot "$INSTALL_ROOT" -y --nogpgcheck install $PKG_LIST
388     retval="$?"
389     fi
390 
391     if [ "${retval}" -ne 0 ]; then
392     echo "Failed to download the rootfs, aborting."
393     return 1
394     fi
395 
396     mv "$INSTALL_ROOT" "$cache/rootfs"
397     echo "Download complete."
398 
399     return 0
400 }
401 
402 copy_centos()
403 {
404 
405     # make a local copy of the minicentos
406     echo -n "Copying rootfs to $rootfs_path ..."
407     cp -a $cache/rootfs $rootfs_path || return 1
408     return 0
409 }
410 
411 update_centos()
412 {
413     cp /etc/resolv.conf $cache/rootfs/etc/resolv.conf
414     mount --bind /dev "${cache}/dev"
415     mount --bind /sys "${cache}/sys"
416     mount --bind /proc "${cache}/proc"
417     chroot $cache/rootfs yum -y update
418     umount "${cache}/dev"
419     umount "${cache}/sys"
420     umount "${cache}/proc"
421 }
422 
423 install_centos()
424 {
425     mkdir -p /var/lock/subsys/
426     (
427     flock -n -x 200
428     if [ $? -ne 0 ]; then
429         echo "Cache repository is busy."
430         return 1
431     fi
432 
433     echo "Checking cache download in $cache/rootfs ... "
434     if [ ! -e "$cache/rootfs" ]; then
435         download_centos
436         if [ $? -ne 0 ]; then
437         echo "Failed to download 'centos base'"
438         return 1
439         fi
440         else
441         echo "Cache found. Updating..."
442             update_centos
443         if [ $? -ne 0 ]; then
444         echo "Failed to update 'centos base', continuing with last known good cache"
445             else
446                 echo "Update finished"
447         fi
448     fi
449 
450     echo "Copy $cache/rootfs to $rootfs_path ... "
451     copy_centos
452     if [ $? -ne 0 ]; then
453         echo "Failed to copy rootfs"
454         return 1
455     fi
456 
457     return 0
458 
459     ) 200>/var/lock/subsys/lxc
460 
461     return $?
462 }
463 
464 copy_configuration()
465 {
466 
467     mkdir -p $config_path
468     cat <<EOF >> $config_path/config
469 lxc.utsname = $name
470 lxc.tty = 4
471 lxc.pts = 1024
472 lxc.rootfs = $rootfs_path
473 lxc.mount  = $config_path/fstab
474 #cgroups
475 lxc.cgroup.devices.deny = a
476 # /dev/null and zero
477 lxc.cgroup.devices.allow = c 1:3 rwm
478 lxc.cgroup.devices.allow = c 1:5 rwm
479 # consoles
480 lxc.cgroup.devices.allow = c 5:1 rwm
481 lxc.cgroup.devices.allow = c 5:0 rwm
482 lxc.cgroup.devices.allow = c 4:0 rwm
483 lxc.cgroup.devices.allow = c 4:1 rwm
484 # /dev/{,u}random
485 lxc.cgroup.devices.allow = c 1:9 rwm
486 lxc.cgroup.devices.allow = c 1:8 rwm
487 lxc.cgroup.devices.allow = c 136:* rwm
488 lxc.cgroup.devices.allow = c 5:2 rwm
489 # rtc
490 lxc.cgroup.devices.allow = c 254:0 rwm
491 EOF
492 
493     cat <<EOF > $config_path/fstab
494 proc            $rootfs_path/proc         proc    nodev,noexec,nosuid 0 0
495 devpts          $rootfs_path/dev/pts      devpts defaults 0 0
496 sysfs           $rootfs_path/sys          sysfs defaults  0 0
497 EOF
498     if [ $? -ne 0 ]; then
499     echo "Failed to add configuration"
500     return 1
501     fi
502 
503     return 0
504 }
505 
506 clean()
507 {
508 
509     if [ ! -e $cache ]; then
510     exit 0
511     fi
512 
513     # lock, so we won't purge while someone is creating a repository
514     (
515     flock -n -x 200
516     if [ $? != 0 ]; then
517         echo "Cache repository is busy."
518         exit 1
519     fi
520 
521     echo -n "Purging the download cache for centos-$release..."
522     rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
523     exit 0
524 
525     ) 200>/var/lock/subsys/lxc
526 }
527 
528 usage()
529 {
530     cat <<EOF
531 usage:
532     $1 -n|--name=<container_name>
533         [-p|--path=<path>] [-c|--clean] [-R|--release=<centos_release>] [-A|--arch=<arch of the container>]
534         [-h|--help]
535 Mandatory args:
536   -n,--name         container name, used to as an identifier for that container from now on
537 Optional args:
538   -p,--path         path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config
	will go under /var/lib/lxc in that case
539   -c,--clean        clean the cache
540   -R,--release      centos release for the new container. if the host is centos, then it will defaultto the host's
	release.
541   -A,--arch         NOT USED YET. Define what arch the container will be [i686,x86_64]
542   -h,--help         print this help
543 EOF
544     return 0
545 }
546 
547 options=$(getopt -o hp:n:cR: -l help,path:,name:,clean,release: -- "$@")
548 if [ $? -ne 0 ]; then
549     usage $(basename $0)
550     exit 1
551 fi
552 eval set -- "$options"
553 
554 while true
555 do
556     case "$1" in
557     -h|--help)      usage $0 && exit 0;;
558     -p|--path)      path=$2; shift 2;;
559     -n|--name)      name=$2; shift 2;;
560     -c|--clean)     clean=$2; shift 2;;
561         -R|--release)   release=$2; shift 2;;
562     --)             shift 1; break ;;
563         *)              break ;;
564     esac
565 done
566 
567 if [ ! -z "$clean" -a -z "$path" ]; then
568     clean || exit 1
569     exit 0
570 fi
571 
572 yum_lite='0'
573 type yum >/dev/null 2>&1
574 if [ $? -ne 0 ]; then
575     echo "'yum' command is missing -- installing first"
576     yum_lite='1'
577 fi
578 
579 if [ -z "$path" ]; then
580     path=$default_path
581 fi
582 
583 if [ -z "$release" ]; then
584     if [ "$is_centos" ]; then
585         release=$(cat /etc/centos-release |awk '/^centos/ {print $3}')
586     else
587         echo "This is not a centos host and release missing, defaulting to 6. use -R|--release to specify release"
588         release=6
589     fi
590 fi
591 
592 if [ "$(id -u)" != "0" ]; then
593     echo "This script should be run as 'root'"
594     exit 1
595 fi
596 
597 
598 rootfs_path=$path/rootfs
599 config_path=$path
600 cache=$cache_base/$release
601 
602 revert()
603 {
604     echo "Interrupted, so cleaning up"
605     lxc-destroy -n $name
606     # maybe was interrupted before copy config
607     rm -rf $path/$name
608     rm -rf $default_path/$name
609     echo "exiting..."
610     exit 1
611 }
612 
613 trap revert SIGHUP SIGINT SIGTERM
614 
615 copy_configuration
616 if [ $? -ne 0 ]; then
617     echo "failed write configuration file"
618     exit 1
619 fi
620 
621 install_centos
622 if [ $? -ne 0 ]; then
623     echo "failed to install centos"
624     exit 1
625 fi
626 
627 configure_centos
628 if [ $? -ne 0 ]; then
629     echo "failed to configure centos for a container"
630     exit 1
631 fi
632 
633 
634 if [ ! -z $clean ]; then
635     clean || exit 1
636     exit 0
637 fi
638 echo "container rootfs and config created"
5808882 [rkeene@sledge /home/rkeene/tmp]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2012-11-08 06:12:25