PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/templates/lxc-ubuntu-cloud.in

https://gitlab.com/Red54/lxc
Autoconf | 406 lines | 304 code | 56 blank | 46 comment | 59 complexity | 2ff083c4174cae56c3d8d1c38c288834 MD5 | raw file
  1. #!/bin/bash
  2. # template script for generating ubuntu container for LXC based on released
  3. # cloud images.
  4. #
  5. # Copyright © 2012 Serge Hallyn <serge.hallyn@canonical.com>
  6. #
  7. # This library is free software; you can redistribute it and/or
  8. # modify it under the terms of the GNU Lesser General Public
  9. # License as published by the Free Software Foundation; either
  10. # version 2.1 of the License, or (at your option) any later version.
  11. # This library is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. # Lesser General Public License for more details.
  15. # You should have received a copy of the GNU Lesser General Public
  16. # License along with this library; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. set -e
  19. STATE_DIR="@LOCALSTATEDIR@"
  20. HOOK_DIR="@LXCHOOKDIR@"
  21. CLONE_HOOK_FN="$HOOK_DIR/ubuntu-cloud-prep"
  22. LXC_TEMPLATE_CONFIG="@LXCTEMPLATECONFIG@"
  23. KNOWN_RELEASES="lucid precise quantal saucy trusty"
  24. skip_arch_check=${UCTEMPLATE_SKIP_ARCH_CHECK:-0}
  25. # Make sure the usual locations are in PATH
  26. export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin
  27. if [ -r /etc/default/lxc ]; then
  28. . /etc/default/lxc
  29. fi
  30. am_in_userns() {
  31. [ -e /proc/self/uid_map ] || { echo no; return; }
  32. [ "$(wc -l /proc/self/uid_map | awk '{ print $1 }')" -eq 1 ] || { echo yes; return; }
  33. line=$(awk '{ print $1 " " $2 " " $3 }' /proc/self/uid_map)
  34. [ "$line" = "0 0 4294967295" ] && { echo no; return; }
  35. echo yes
  36. }
  37. in_userns=0
  38. [ $(am_in_userns) = "yes" ] && in_userns=1
  39. copy_configuration()
  40. {
  41. path=$1
  42. rootfs=$2
  43. name=$3
  44. arch=$4
  45. release=$5
  46. if [ $arch = "i386" ]; then
  47. arch="i686"
  48. fi
  49. # if there is exactly one veth network entry, make sure it has an
  50. # associated hwaddr.
  51. nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
  52. if [ $nics -eq 1 ]; then
  53. grep -q "^lxc.network.hwaddr" $path/config || sed -i -e "/^lxc\.network\.type[ \t]*=[ \t]*veth/a lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')" $path/config
  54. fi
  55. # Generate the configuration file
  56. ## Create the fstab (empty by default)
  57. touch $path/fstab
  58. ## Relocate all the network config entries
  59. sed -i -e "/lxc.network/{w ${path}/config-network" -e "d}" $path/config
  60. ## Relocate any other config entries
  61. sed -i -e "/lxc./{w ${path}/config-auto" -e "d}" $path/config
  62. ## Add all the includes
  63. echo "" >> $path/config
  64. echo "# Common configuration" >> $path/config
  65. if [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.common.conf" ]; then
  66. echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.common.conf" >> $path/config
  67. fi
  68. if [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.${release}.conf" ]; then
  69. echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.${release}.conf" >> $path/config
  70. fi
  71. if [ $in_userns -eq 1 ] && [ -e "${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.userns.conf" ]; then
  72. echo "lxc.include = ${LXC_TEMPLATE_CONFIG}/ubuntu-cloud.userns.conf" >> $path/config
  73. fi
  74. ## Add the container-specific config
  75. echo "" >> $path/config
  76. echo "# Container specific configuration" >> $path/config
  77. [ -e "$path/config-auto" ] && cat $path/config-auto >> $path/config && rm $path/config-auto
  78. grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config
  79. cat <<EOF >> $path/config
  80. lxc.mount = $path/fstab
  81. lxc.utsname = $name
  82. lxc.arch = $arch
  83. EOF
  84. ## Re-add the previously removed network config
  85. echo "" >> $path/config
  86. echo "# Network configuration" >> $path/config
  87. cat $path/config-network >> $path/config
  88. rm $path/config-network
  89. # Set initial timezone as on host
  90. if [ -f /etc/timezone ]; then
  91. cat /etc/timezone > $rootfs/etc/timezone
  92. chroot $rootfs dpkg-reconfigure -f noninteractive tzdata
  93. elif [ -f /etc/sysconfig/clock ]; then
  94. . /etc/sysconfig/clock
  95. echo $ZONE > $rootfs/etc/timezone
  96. chroot $rootfs dpkg-reconfigure -f noninteractive tzdata
  97. else
  98. echo "Timezone in container is not configured. Adjust it manually."
  99. fi
  100. # rmdir /dev/shm for containers that have /run/shm
  101. # I'm afraid of doing rm -rf $rootfs/dev/shm, in case it did
  102. # get bind mounted to the host's /run/shm. So try to rmdir
  103. # it, and in case that fails move it out of the way.
  104. # NOTE: This can only be removed once 12.04 goes out of support
  105. if [ ! -L $rootfs/dev/shm ] && [ -e $rootfs/dev/shm ]; then
  106. rmdir $rootfs/dev/shm 2>/dev/null || mv $rootfs/dev/shm $rootfs/dev/shm.bak
  107. ln -s /run/shm $rootfs/dev/shm
  108. fi
  109. return 0
  110. }
  111. usage()
  112. {
  113. cat <<EOF
  114. LXC Container configuration for Ubuntu Cloud images.
  115. Generic Options
  116. [ -r | --release <release> ]: Release name of container, defaults to host
  117. [ --rootfs <path> ]: Path in which rootfs will be placed
  118. [ -a | --arch ]: Architecture of container, defaults to host architecture
  119. [ -T | --tarball ]: Location of tarball
  120. [ -d | --debug ]: Run with 'set -x' to debug errors
  121. [ -s | --stream]: Use specified stream rather than 'tryreleased'
  122. Additionally, clone hooks can be passed through (ie, --userdata). For those,
  123. see:
  124. $CLONE_HOOK_FN --help
  125. EOF
  126. return 0
  127. }
  128. options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds:u: -l arch:,help,rootfs:,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata:,mapped-uid:,mapped-gid: -- "$@")
  129. if [ $? -ne 0 ]; then
  130. usage $(basename $0)
  131. exit 1
  132. fi
  133. eval set -- "$options"
  134. mapped_uid=-1
  135. mapped_gid=-1
  136. # default release is precise, or the systems release if recognized
  137. release=precise
  138. if [ -f /etc/lsb-release ]; then
  139. . /etc/lsb-release
  140. rels=$(ubuntu-distro-info --supported 2>/dev/null) ||
  141. rels="$KNOWN_RELEASES"
  142. for r in $rels; do
  143. [ "$DISTRIB_CODENAME" = "$r" ] && release="$r"
  144. done
  145. fi
  146. # Code taken from debootstrap
  147. if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
  148. arch=`/usr/bin/dpkg --print-architecture`
  149. elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
  150. arch=`/usr/bin/udpkg --print-architecture`
  151. else
  152. arch=$(uname -m)
  153. if [ "$arch" = "i686" ]; then
  154. arch="i386"
  155. elif [ "$arch" = "x86_64" ]; then
  156. arch="amd64"
  157. elif [ "$arch" = "armv7l" ]; then
  158. # note: arm images don't exist before oneiric; are called armhf in
  159. # precise and later; and are not supported by the query, so we don't actually
  160. # support them yet (see check later on). When Query2 is available,
  161. # we'll use that to enable arm images.
  162. arch="armhf"
  163. elif [ "$arch" = "aarch64" ]; then
  164. arch="arm64"
  165. elif [ "$arch" = "ppc64le" ]; then
  166. arch="ppc64el"
  167. fi
  168. fi
  169. debug=0
  170. hostarch=$arch
  171. cloud=0
  172. locales=1
  173. flushcache=0
  174. stream="tryreleased"
  175. cloneargs=()
  176. while true
  177. do
  178. case "$1" in
  179. -h|--help) usage $0 && exit 0;;
  180. -p|--path) path=$2; shift 2;;
  181. -n|--name) name=$2; shift 2;;
  182. -F|--flush-cache) flushcache=1; shift 1;;
  183. -r|--release) release=$2; shift 2;;
  184. -a|--arch) arch=$2; shift 2;;
  185. -T|--tarball) tarball=$2; shift 2;;
  186. -d|--debug) debug=1; shift 1;;
  187. -s|--stream) stream=$2; shift 2;;
  188. --rootfs) rootfs=$2; shift 2;;
  189. -L|--no?locales) cloneargs[${#cloneargs[@]}]="--no-locales"; shift 1;;
  190. -i|--hostid) cloneargs[${#cloneargs[@]}]="--hostid=$2"; shift 2;;
  191. -u|--userdata) cloneargs[${#cloneargs[@]}]="--userdata=$2"; shift 2;;
  192. -C|--cloud) cloneargs[${#cloneargs[@]}]="--cloud"; shift 1;;
  193. -S|--auth-key) cloneargs[${#cloneargs[@]}]="--auth-key=$2"; shift 2;;
  194. --mapped-uid) mapped_uid=$2; shift 2;;
  195. --mapped-gid) mapped_gid=$2; shift 2;;
  196. --) shift 1; break ;;
  197. *) break ;;
  198. esac
  199. done
  200. cloneargs=( "--name=$name" "${cloneargs[@]}" )
  201. if [ $debug -eq 1 ]; then
  202. set -x
  203. fi
  204. if [ "$arch" = "i686" ]; then
  205. arch=i386
  206. fi
  207. if [ "$skip_arch_check" = "0" ]; then
  208. case "$hostarch:$arch" in
  209. $arch:$arch) : ;; # the host == container
  210. amd64:i386) :;; # supported "cross"
  211. arm64:arm*) :;; # supported "cross"
  212. armel:armhf) :;; # supported "cross"
  213. armhf:armel) :;; # supported "cross"
  214. *) echo "cannot create '$arch' container on hostarch '$hostarch'";
  215. exit 1;;
  216. esac
  217. fi
  218. if [ "$stream" != "daily" -a "$stream" != "released" -a "$stream" != "tryreleased" ]; then
  219. echo "Only 'daily' and 'released' and 'tryreleased' streams are supported"
  220. exit 1
  221. fi
  222. if [ -z "$path" ]; then
  223. echo "'path' parameter is required"
  224. exit 1
  225. fi
  226. if [ "$(id -u)" != "0" ]; then
  227. echo "This script should be run as 'root'"
  228. exit 1
  229. fi
  230. # detect rootfs
  231. config="$path/config"
  232. if [ -z "$rootfs" ]; then
  233. if grep -q '^lxc.rootfs' $config 2>/dev/null ; then
  234. rootfs=$(awk -F= '/^lxc.rootfs =/{ print $2 }' $config)
  235. else
  236. rootfs=$path/rootfs
  237. fi
  238. fi
  239. type ubuntu-cloudimg-query
  240. type wget
  241. # determine the url, tarball, and directory names
  242. # download if needed
  243. cache="$STATE_DIR/cache/lxc/cloud-$release"
  244. if [ $in_userns -eq 1 ]; then
  245. STATE_DIR="$HOME/.cache/lxc/"
  246. cache="$HOME/.cache/lxc/cloud-$release"
  247. fi
  248. mkdir -p $cache
  249. if [ "$stream" = "tryreleased" ]; then
  250. stream=released
  251. ubuntu-cloudimg-query $release $stream $arch 1>/dev/null 2>/dev/null || stream=daily
  252. fi
  253. if [ -n "$tarball" ]; then
  254. url2="$tarball"
  255. else
  256. if ! url1=`ubuntu-cloudimg-query $release $stream $arch --format "%{url}\n"`; then
  257. echo "There is no download available for release=$release, stream=$stream, arch=$arch"
  258. [ "$stream" = "daily" ] || echo "You may try with '--stream=daily'"
  259. exit
  260. fi
  261. url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/'`
  262. fi
  263. filename=`basename $url2`
  264. wgetcleanup()
  265. {
  266. rm -f $filename
  267. }
  268. buildcleanup()
  269. {
  270. cd $rootfs
  271. umount -l $cache/$xdir || true
  272. rm -rf $cache
  273. }
  274. # if the release doesn't have a *-rootfs.tar.gz, then create one from the
  275. # cloudimg.tar.gz by extracting the .img, mounting it loopback, and creating
  276. # a tarball from the mounted image.
  277. build_root_tgz()
  278. {
  279. url=$1
  280. filename=$2
  281. xdir=`mktemp -d -p .`
  282. tarname=`basename $url`
  283. imgname="$release-*-cloudimg-$arch.img"
  284. trap buildcleanup EXIT SIGHUP SIGINT SIGTERM
  285. if [ $flushcache -eq 1 -o ! -f $cache/$tarname ]; then
  286. rm -f $tarname
  287. echo "Downloading cloud image from $url"
  288. wget $url || { echo "Couldn't find cloud image $url."; exit 1; }
  289. fi
  290. echo "Creating new cached cloud image rootfs"
  291. tar --wildcards -zxf "$tarname" "$imgname"
  292. mount -o loop $imgname $xdir
  293. (cd $xdir; tar --numeric-owner -cpzf "../$filename" .)
  294. umount $xdir
  295. rm -f $tarname $imgname
  296. rmdir $xdir
  297. echo "New cloud image cache created"
  298. trap EXIT
  299. trap SIGHUP
  300. trap SIGINT
  301. trap SIGTERM
  302. }
  303. do_extract_rootfs() {
  304. cd $cache
  305. if [ $flushcache -eq 1 ]; then
  306. echo "Clearing the cached images"
  307. rm -f $filename
  308. fi
  309. trap wgetcleanup EXIT SIGHUP SIGINT SIGTERM
  310. if [ ! -f $filename ]; then
  311. wget $url2 || build_root_tgz $url1 $filename
  312. fi
  313. trap EXIT
  314. trap SIGHUP
  315. trap SIGINT
  316. trap SIGTERM
  317. echo "Extracting container rootfs"
  318. mkdir -p $rootfs
  319. cd $rootfs
  320. if [ $in_userns -eq 1 ]; then
  321. tar --anchored --exclude="dev/*" --numeric-owner -xpzf "$cache/$filename"
  322. mkdir -p $rootfs/dev/pts/
  323. else
  324. tar --numeric-owner -xpzf "$cache/$filename"
  325. fi
  326. }
  327. if [ -n "$tarball" ]; then
  328. do_extract_rootfs
  329. else
  330. mkdir -p "$STATE_DIR/lock/subsys/"
  331. (
  332. flock -x 9
  333. do_extract_rootfs
  334. ) 9>"$STATE_DIR/lock/subsys/lxc-ubuntu-cloud"
  335. fi
  336. copy_configuration $path $rootfs $name $arch $release
  337. "$CLONE_HOOK_FN" "${cloneargs[@]}" "$rootfs"
  338. if [ $mapped_uid -ne -1 ]; then
  339. chown $mapped_uid $path/config
  340. chown -R $mapped_uid $STATE_DIR
  341. chown -R $mapped_uid $cache
  342. fi
  343. if [ $mapped_gid -ne -1 ]; then
  344. chgrp $mapped_gid $path/config
  345. chgrp -R $mapped_gid $STATE_DIR
  346. chgrp -R $mapped_gid $cache
  347. fi
  348. echo "Container $name created."
  349. exit 0
  350. # vi: ts=4 expandtab