lxc-vinelinux 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. #!/bin/bash
  2. #
  3. # template script for generating Vine Linux container for LXC
  4. # (based on altlinux/centos template script)
  5. #
  6. #
  7. # lxc: linux Container library
  8. # Authors:
  9. # Daisuke SUZUKI <daisuke@vinelinux.org>
  10. # This library is free software; you can redistribute it and/or
  11. # modify it under the terms of the GNU Lesser General Public
  12. # License as published by the Free Software Foundation; either
  13. # version 2.1 of the License, or (at your option) any later version.
  14. # This library is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. # Lesser General Public License for more details.
  18. # You should have received a copy of the GNU Lesser General Public
  19. # License along with this library; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. # Detect use under userns (unsupported)
  22. for arg in "$@"; do
  23. [ "$arg" = "--" ] && break
  24. if [ "$arg" = "--mapped-uid" -o "$arg" = "--mapped-gid" ]; then
  25. echo "This template can't be used for unprivileged containers." 1>&2
  26. echo "You may want to try the \"download\" template instead." 1>&2
  27. exit 1
  28. fi
  29. done
  30. # Make sure the usual locations are in PATH
  31. export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
  32. # Configurations
  33. arch=$(uname -i)
  34. cache_base=/var/cache/lxc/vinelinux
  35. default_path=/var/lib/lxc
  36. default_profile=default
  37. profile_dir=/etc/lxc/profiles
  38. lxc_network_type=veth
  39. lxc_network_link=lxcbr0
  40. # is this vinelinux?
  41. [ -f /etc/vine-release ] && is_vinelinux=true
  42. configure_vinelinux()
  43. {
  44. # Set default localtime to the host localtime if not set...
  45. if [ -e /etc/localtime -a ! -e ${rootfs_path}/etc/localtime ]
  46. then
  47. # if /etc/localtime is a symlink, this should preserve it.
  48. cp -a /etc/localtime ${rootfs_path}/etc/localtime
  49. fi
  50. # create /lxcroot
  51. touch ${rootfs_path}/lxcroot
  52. # fix bxxxn damaged halt script.
  53. if [ -f ${rootfs_path}/etc/init.d/halt ]
  54. then
  55. sed -e '/hwclock/,$d' \
  56. < ${rootfs_path}/etc/init.d/halt \
  57. > ${rootfs_path}/etc/init.d/lxc-halt
  58. echo '$command -f' >> ${rootfs_path}/etc/init.d/lxc-halt
  59. chmod 755 ${rootfs_path}/etc/init.d/lxc-halt
  60. # Link them into the rc directories...
  61. (
  62. cd ${rootfs_path}/etc/rc.d/rc0.d
  63. ln -s ../init.d/lxc-halt S00lxc-halt
  64. cd ${rootfs_path}/etc/rc.d/rc6.d
  65. ln -s ../init.d/lxc-halt S00lxc-reboot
  66. )
  67. fi
  68. # configure the network using the dhcp
  69. cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
  70. DEVICE=eth0
  71. BOOTPROTO=dhcp
  72. ONBOOT=yes
  73. HOSTNAME=${UTSNAME}
  74. NM_CONTROLLED=no
  75. TYPE=Ethernet
  76. MTU=${MTU}
  77. DHCP_HOSTNAME=\`hostname\`
  78. EOF
  79. # set the hostname
  80. cat <<EOF > ${rootfs_path}/etc/sysconfig/network
  81. NETWORKING=yes
  82. HOSTNAME=${UTSNAME}
  83. EOF
  84. # set minimal hosts
  85. cat <<EOF > $rootfs_path/etc/hosts
  86. 127.0.0.1 localhost.localdomain localhost $name
  87. EOF
  88. # set minimal fstab
  89. cat <<EOF > $rootfs_path/etc/fstab
  90. /dev/root / rootfs defaults 0 0
  91. EOF
  92. # create lxc compatibility init script
  93. cat <<EOF > $rootfs_path/etc/init/lxc-sysinit.conf
  94. start on startup
  95. env container
  96. pre-start script
  97. if [ "x\$container" != "xlxc" -a "x\$container" != "xlibvirt" ]; then
  98. stop;
  99. fi
  100. rm -f /var/lock/subsys/*
  101. rm -f /var/run/*.pid
  102. [ -e /etc/mtab ] || ln -s /proc/mounts /etc/mtab
  103. mkdir -p /dev/shm
  104. mount -t tmpfs -o nosuid,nodev tmpfs /dev/shm
  105. initctl start tty TTY=console
  106. telinit 3
  107. exit 0
  108. end script
  109. EOF
  110. # Enable services
  111. for service in network random
  112. do
  113. chroot ${rootfs_path} chkconfig $service --list &>/dev/null && chroot ${rootfs_path} chkconfig $service on || true
  114. done
  115. dev_path="${rootfs_path}/dev"
  116. rm -rf ${dev_path}
  117. mkdir -p ${dev_path}
  118. mknod -m 666 ${dev_path}/null c 1 3
  119. mknod -m 666 ${dev_path}/zero c 1 5
  120. mknod -m 644 ${dev_path}/random c 1 8
  121. mknod -m 644 ${dev_path}/urandom c 1 9
  122. mkdir -m 755 ${dev_path}/pts
  123. mkdir -m 1777 ${dev_path}/shm
  124. mknod -m 666 ${dev_path}/tty c 5 0
  125. chown root:tty ${dev_path}/tty
  126. mknod -m 600 ${dev_path}/tty0 c 4 0
  127. mknod -m 600 ${dev_path}/tty1 c 4 1
  128. mknod -m 600 ${dev_path}/tty2 c 4 2
  129. mknod -m 600 ${dev_path}/tty3 c 4 3
  130. mknod -m 600 ${dev_path}/tty4 c 4 4
  131. mknod -m 600 ${dev_path}/console c 5 1
  132. mknod -m 666 ${dev_path}/full c 1 7
  133. mknod -m 600 ${dev_path}/initctl p
  134. mknod -m 666 ${dev_path}/ptmx c 5 2
  135. chown root:tty ${dev_path}/ptmx
  136. ln -s /proc/self/fd ${dev_path}/fd
  137. ln -s /proc/kcore ${dev_path}/core
  138. mkdir -m 755 ${dev_path}/mapper
  139. mknod -m 600 ${dev_path}/mapper/control c 10 236
  140. mkdir -m 755 ${dev_path}/net
  141. mknod -m 666 ${dev_path}/net/tun c 10 200
  142. # setup console and tty[1-4] for login. note that /dev/console and
  143. # /dev/tty[1-4] will be symlinks to the ptys /dev/lxc/console and
  144. # /dev/lxc/tty[1-4] so that package updates can overwrite the symlinks.
  145. # lxc will maintain these links and bind mount ptys over /dev/lxc/*
  146. # since lxc.devttydir is specified in the config.
  147. # allow root login on console, tty[1-4], and pts/0 for libvirt
  148. echo "# LXC (Linux Containers)" >>${rootfs_path}/etc/securetty
  149. echo "lxc/console" >>${rootfs_path}/etc/securetty
  150. echo "lxc/tty1" >>${rootfs_path}/etc/securetty
  151. echo "lxc/tty2" >>${rootfs_path}/etc/securetty
  152. echo "lxc/tty3" >>${rootfs_path}/etc/securetty
  153. echo "lxc/tty4" >>${rootfs_path}/etc/securetty
  154. echo "# For libvirt/Virtual Machine Monitor" >>${rootfs_path}/etc/securetty
  155. echo "pts/0" >>${rootfs_path}/etc/securetty
  156. # prevent mingetty from calling vhangup(2) since it fails with userns.
  157. # Same issue as oracle template: prevent mingetty from calling vhangup(2)
  158. # commit 2e83f7201c5d402478b9849f0a85c62d5b9f1589.
  159. sed -i 's|mingetty|mingetty --nohangup|' $rootfs_path/etc/init/tty.conf
  160. # set root password
  161. echo "Setting root password to $root_password"
  162. echo "root:$root_password" | chroot $rootfs_path chpasswd
  163. # store root password
  164. touch ${config_path}/tmp_root_pass
  165. chmod 600 ${config_path}/tmp_root_pass
  166. echo ${root_password} > ${config_path}/tmp_root_pass
  167. echo "Storing root password in '${config_path}/tmp_root_pass'"
  168. # create default user.
  169. echo "Create default user '${default_user}'"
  170. chroot ${rootfs_path} /usr/sbin/useradd -G wheel ${default_user}
  171. echo "Setting default user \'${default_user}\' password to $default_user_password"
  172. echo "${default_user}:${default_user_password}" | chroot $rootfs_path chpasswd
  173. # store default user password
  174. touch ${config_path}/tmp_user_pass
  175. chmod 600 ${config_path}/tmp_user_pass
  176. echo "username: ${default_user}" > ${config_path}/tmp_user_pass
  177. echo "password: ${default_user_password}" >> ${config_path}/tmp_user_pass
  178. echo "Storing default user infomation in '${config_path}/tmp_user_pass'"
  179. return 0
  180. }
  181. download_vinelinux()
  182. {
  183. # Default configuration
  184. FETCH_URL="http://updates.vinelinux.org/apt"
  185. # create cache dir
  186. mkdir -p $cache
  187. # check target availability
  188. if ! (vbootstrap | grep -q "${release}_${arch}"); then
  189. echo "Specified release and/or arch is not supported, aborting."
  190. return 1
  191. fi
  192. if [ "$(uname -i)" == "i386" ] && [ "${arch}" == "x86_64" ]; then
  193. echo "x86_64 containers does not run on $(uname -i) host, aborting."
  194. return 1
  195. fi
  196. # download a mini vinelinux into a cache
  197. echo "Downloading vinelinux minimal ..."
  198. VBOOTSTRAP="vbootstrap ${release}_${arch} ${FETCH_URL} $cache/partial"
  199. $VBOOTSTRAP
  200. if [ $? -ne 0 ]; then
  201. echo "Failed to download the rootfs, aborting."
  202. return 1
  203. fi
  204. # install additional packages
  205. PKG_LIST0="openssh-server openssh-clients etcskel sudo net-tools"
  206. PKG_LIST="$(grep -hs '^[^#]' "$profile_dir/$profile")"
  207. # if no configuration file $profile -- fall back to default list of packages
  208. PKG_LIST="$PKG_LIST0 $PKG_LIST"
  209. chroot $cache/partial apt-get -y install $PKG_LIST
  210. if [ $? -ne 0 ]; then
  211. echo "Failed to install additional packages to the rootfs, aborting."
  212. return 1
  213. fi
  214. mv "$cache/partial" "$cache/rootfs"
  215. echo "Download complete."
  216. return 0
  217. }
  218. copy_vinelinux()
  219. {
  220. # make a local copy of the minivinelinux
  221. echo -n "Copying rootfs to $rootfs_path ..."
  222. # prefer rsync
  223. mkdir -p $rootfs_path
  224. if [ -x /usr/bin/rsync ]; then
  225. rsync -Ha $cache/rootfs/ $rootfs_path/
  226. else
  227. echo "rsync is not found, using cp instead."
  228. cp -a $cache/rootfs-$arch $rootfs_path
  229. fi
  230. return 0
  231. }
  232. update_vinelinux()
  233. {
  234. chroot $cache/rootfs apt-get update
  235. chroot $cache/rootfs apt-get -y dist-upgrade
  236. }
  237. install_vinelinux()
  238. {
  239. mkdir -p /var/lock/subsys/
  240. (
  241. flock -x 9
  242. if [ $? -ne 0 ]; then
  243. echo "Cache repository is busy."
  244. return 1
  245. fi
  246. echo "Checking cache download in $cache/rootfs ... "
  247. if [ ! -e "$cache/rootfs" ]; then
  248. download_vinelinux
  249. if [ $? -ne 0 ]; then
  250. echo "Failed to download 'vinelinux base'"
  251. return 1
  252. fi
  253. else
  254. echo "Cache found. Updating..."
  255. update_vinelinux
  256. if [ $? -ne 0 ]; then
  257. echo "Failed to update 'vinelinux base', continuing with last known good cache"
  258. else
  259. echo "Update finished"
  260. fi
  261. fi
  262. echo "Copy $cache/rootfs to $rootfs_path ... "
  263. copy_vinelinux
  264. if [ $? -ne 0 ]; then
  265. echo "Failed to copy rootfs"
  266. return 1
  267. fi
  268. return 0
  269. ) 9>/var/lock/subsys/lxc-vinelinux
  270. return $?
  271. }
  272. create_hwaddr()
  273. {
  274. openssl rand -hex 5 | sed -e 's/\(..\)/:\1/g; s/^/fe/'
  275. }
  276. copy_configuration()
  277. {
  278. mkdir -p $config_path
  279. grep -q "^lxc.rootfs" $config_path/config 2>/dev/null || echo "
  280. lxc.rootfs = $rootfs_path
  281. " >> $config_path/config
  282. # The following code is to create static MAC addresses for each
  283. # interface in the container. This code will work for multiple
  284. # interfaces in the default config.
  285. mv $config_path/config $config_path/config.def
  286. while read LINE
  287. do
  288. # This should catch variable expansions from the default config...
  289. if expr "${LINE}" : '.*\$' > /dev/null 2>&1
  290. then
  291. LINE=$(eval "echo \"${LINE}\"")
  292. fi
  293. # There is a tab and a space in the regex bracket below!
  294. # Seems that \s doesn't work in brackets.
  295. KEY=$(expr "${LINE}" : '\s*\([^ ]*\)\s*=')
  296. if [[ "${KEY}" != "lxc.network.hwaddr" ]]
  297. then
  298. echo ${LINE} >> $config_path/config
  299. if [[ "${KEY}" == "lxc.network.link" ]]
  300. then
  301. echo "lxc.network.hwaddr = $(create_hwaddr)" >> $config_path/config
  302. fi
  303. fi
  304. done < $config_path/config.def
  305. rm -f $config_path/config.def
  306. # static network settings
  307. if [ ! -z ${ipv4} ]; then
  308. cat <<EOF >> $config_path/config
  309. lxc.network.ipv4 = $ipv4
  310. EOF
  311. fi
  312. if [ ! -z ${gw} ]; then
  313. cat <<EOF >> $config_path/config
  314. lxc.network.ipv4.gateway = $gw
  315. EOF
  316. fi
  317. #if [ ! -z ${ipv6} ]; then
  318. # cat <<EOF >> $config_path/config
  319. #lxc.network.ipv6 = $ipv6
  320. #EOF
  321. #fi
  322. #if [ ! -z ${gw6} ]; then
  323. # cat <<EOF >> $config_path/config
  324. #lxc.network.ipv6.gateway = $gw6
  325. #EOF
  326. #fi
  327. # include common configuration
  328. if [ -e "/usr/share/lxc/config/vinelinux.common.conf" ]; then
  329. echo "
  330. # Include common configuration
  331. lxc.include = /usr/share/lxc/config/vinelinux.common.conf
  332. " >> $config_path/config
  333. fi
  334. # append lxc.utsname
  335. echo "lxc.utsname = $utsname" >> $config_path/config
  336. if [ "$arch" == "i386" ] && [ "$(uname -i)" == "x86_64" ]; then
  337. cat <<EOF >> $config_path/config
  338. # lxc container architecture
  339. lxc.arch = x86
  340. EOF
  341. fi
  342. if [ $? -ne 0 ]; then
  343. echo "Failed to add configuration"
  344. return 1
  345. fi
  346. return 0
  347. }
  348. clean()
  349. {
  350. if [ ! -e $cache ]; then
  351. exit 0
  352. fi
  353. # lock, so we won't purge while someone is creating a repository
  354. (
  355. flock -x 9
  356. if [ $? != 0 ]; then
  357. echo "Cache repository is busy."
  358. exit 1
  359. fi
  360. echo -n "Purging the download cache for Vine Linux $release..."
  361. rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
  362. exit 0
  363. ) 9>/var/lock/subsys/lxc-vinelinux
  364. }
  365. usage()
  366. {
  367. cat <<EOF
  368. usage:
  369. $1 -n|--name=<container_name>
  370. [-p|--path=<path>] [-c|--clean]
  371. [-R|--release=<Vine Linux release>]
  372. [-A|--arch=<arch of the container>]
  373. [-4|--ipv4=<ipv4 address>]
  374. [-g|--gw=<gw address>] [-d|--dns=<dns address>]
  375. [-u|--user=<user>] [--password=<password>]
  376. [-P|--profile=<name of the profile>] [--rootfs=<path>]
  377. [-h|--help]
  378. Mandatory args:
  379. -n,--name container name, used to as an identifier for that container from now on
  380. Optional args:
  381. -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
  382. -c,--clean clean the cache
  383. -R,--release Vine Linux release [VineSeed, 6] for the new container, defaults to VineSeed
  384. -A,--arch Define what arch the container will be [i386,x86_64]
  385. -4,--ipv4 specify the ipv4 address to assign to the virtualized interface, eg. 192.168.1.123/24
  386. -g,--gw specify the default gw, eg. 192.168.1.1
  387. -d,--dns specify the DNS server, eg. 192.168.1.2
  388. -u,--user specify default user name, who can sudo.
  389. --password initial password for default user.
  390. --fqdn fully qualified domain name (FQDN) for DNS and system naming.
  391. --rootpassword initial password for root user.
  392. -P,--profile Profile name is the file name in /etc/lxc/profiles contained packages name for install to cache.
  393. ---rootfs rootfs path
  394. -h,--help print this help
  395. EOF
  396. return 0
  397. }
  398. options=$(getopt -o hp:n:P:cR:4:g:d:u:A: -l help,rootfs:,path:,name:,profile:,clean,release:,ipv4:,gw:,dns:,user:,password:,arch:,fqdn:,rootpassword: -- "$@")
  399. if [ $? -ne 0 ]; then
  400. usage $(basename $0)
  401. exit 1
  402. fi
  403. eval set -- "$options"
  404. while true
  405. do
  406. case "$1" in
  407. -h|--help) usage $0 && exit 0;;
  408. -p|--path) path=$2; shift 2;;
  409. --rootfs) rootfs_path=$2; shift 2;;
  410. -n|--name) name=$2; shift 2;;
  411. -P|--profile) profile=$2; shift 2;;
  412. -c|--clean) clean=1; shift 1;;
  413. -R|--release) release=$2; shift 2;;
  414. -A|--arch) arch=$2; shift 2;;
  415. -4|--ipv4) ipv4=$2; shift 2;;
  416. -g|--gw) gw=$2; shift 2;;
  417. -d|--dns) dns=$2; shift 2;;
  418. -u|--user) default_user=$2; shift 2;;
  419. --password) default_user_password=$2; shift 2;;
  420. --rootpassword) root_password=$2; shift 2;;
  421. --fqdn) utsname=$2; shift 2;;
  422. --) shift 1; break ;;
  423. *) break ;;
  424. esac
  425. done
  426. if [ ! -z "$clean" -a -z "$path" ]; then
  427. clean || exit 1
  428. exit 0
  429. fi
  430. type apt-get >/dev/null 2>&1
  431. if [ $? -ne 0 ]; then
  432. echo "'apt-get' command is missing"
  433. exit 1
  434. fi
  435. type vbootstrap >/dev/null 2>&1
  436. if [ $? -ne 0 ]; then
  437. echo "'vbootstrap' command is missing"
  438. exit 1
  439. fi
  440. if [ -z "$path" ]; then
  441. path=$default_path
  442. fi
  443. if [ -z "$profile" ]; then
  444. profile=$default_profile
  445. fi
  446. if [ -z "$release" ]; then
  447. release="VineSeed"
  448. fi
  449. if [ -z "$ipv4" ]; then
  450. BOOTPROTO="dhcp"
  451. else
  452. BOOTPROTO="static"
  453. fi
  454. if [ -z "$default_user" ]; then
  455. default_user="vine"
  456. fi
  457. if [ -z "$default_user_password" ]; then
  458. default_user_password="$(mktemp -u XXXXXXXX)"
  459. fi
  460. if [ -z "$arch" ]; then
  461. arch="$(uname -i)"
  462. fi
  463. if [ -z "${utsname}" ]; then
  464. utsname=${name}
  465. fi
  466. if [ $(expr "$utsname" : '.*\..*\.') = 0 ]; then
  467. if [[ "$(dnsdomainname)" != "" && "$(dnsdomainname)" != "localdomain" ]]; then
  468. utsname=${utsname}.$(dnsdomainname)
  469. fi
  470. fi
  471. if [ -z "${root_password}" ]; then
  472. root_password="$(mktemp -u XXXXXXXX)"
  473. fi
  474. if [ "$(id -u)" != "0" ]; then
  475. echo "This script should be run as 'root'"
  476. exit 1
  477. fi
  478. # check for 'lxc.rootfs' passed in through default config by lxc-create
  479. if [ -z "$rootfs_path" ]; then
  480. if grep -q '^lxc.rootfs' $path/config 2>/dev/null ; then
  481. rootfs_path=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $path/config)
  482. else
  483. rootfs_path=$path/rootfs
  484. fi
  485. fi
  486. config_path=$default_path/$name
  487. cache=$cache_base/$arch/$release/$profile
  488. install_vinelinux
  489. if [ $? -ne 0 ]; then
  490. echo "failed to install vinelinux"
  491. exit 1
  492. fi
  493. configure_vinelinux
  494. if [ $? -ne 0 ]; then
  495. echo "failed to configure vinelinux for a container"
  496. exit 1
  497. fi
  498. copy_configuration
  499. if [ $? -ne 0 ]; then
  500. echo "failed write configuration file"
  501. exit 1
  502. fi
  503. if [ ! -z "$clean" ]; then
  504. clean || exit 1
  505. exit 0
  506. fi
  507. echo "container rootfs and config created"
  508. echo "network configured as $lxc_network_type in the $lxc_network_link"