launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15303
[Merge] lp:~andreserl/maas/trunk-fpi into lp:maas
Andres Rodriguez has proposed merging lp:~andreserl/maas/trunk-fpi into lp:maas.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~andreserl/maas/trunk-fpi/+merge/152039
--
https://code.launchpad.net/~andreserl/maas/trunk-fpi/+merge/152039
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~andreserl/maas/trunk-fpi into lp:maas.
=== added file 'contrib/maas-cluster-http.conf'
--- contrib/maas-cluster-http.conf 1970-01-01 00:00:00 +0000
+++ contrib/maas-cluster-http.conf 2013-03-06 19:22:22 +0000
@@ -0,0 +1,6 @@
+# Server static files for tftp images as FPI
+# installer needs them
+Alias /MAAS/static/images/ /var/lib/maas/tftp/
+<Directory /var/lib/maas/tftp/>
+ SetHandler None
+</Directory>
=== modified file 'contrib/preseeds_v2/generic'
--- contrib/preseeds_v2/generic 2012-11-14 10:32:25 +0000
+++ contrib/preseeds_v2/generic 2013-03-06 19:22:22 +0000
@@ -1,3 +1,6 @@
+{{if node.should_use_default_installer() is True }}
+{{inherit "preseed_xinstall"}}
+{{else}}
{{inherit "preseed_master"}}
{{def proxy}}
@@ -31,3 +34,4 @@
in-target wget --no-proxy "{{node_disable_pxe_url|escape.shell}}" --post-data "{{node_disable_pxe_data|escape.shell}}" -O /dev/null && \
true
{{enddef}}
+{{endif}}
=== added file 'contrib/preseeds_v2/preseed_xinstall'
--- contrib/preseeds_v2/preseed_xinstall 1970-01-01 00:00:00 +0000
+++ contrib/preseeds_v2/preseed_xinstall 2013-03-06 19:22:22 +0000
@@ -0,0 +1,552 @@
+#cloud-config
+{{py:
+arch = node.architecture.split("/")[0]
+series = node.distro_series
+if not series:
+ series = "precise"
+}}
+output: {all: '| tee -a /var/log/cloud-init-output.log'}
+apt_proxy: http://{{server_host}}:8000/
+buckets:
+ - &w_poweroff |
+ #!/bin/sh
+ cat > '/etc/init/poweroff.conf' <<"__ENDFILE"
+ #!/bin/sh
+ description "poweroff when maas task is done"
+ start on stopped cloud-final
+ console output
+ task
+ script
+ [ ! -e /tmp/block-poweroff ] || exit 0
+ #poweroff
+ reboot
+ end script
+ __ENDFILE
+ chmod 0644 '/etc/init/poweroff.conf'
+ chown 0:0 '/etc/init/poweroff.conf'
+ - &w_installer |
+ #!/bin/sh
+ cat > '/usr/local/bin/installer' <<"__ENDFILE"
+ #!/bin/bash
+
+ set -o pipefail
+ VERBOSITY=0
+ TEMP_D=""
+ FORMATS=( tar-uec-image tar-rootfs qcow-disk )
+
+ error() { echo "$@" 1>&2; }
+ errorp() { printf "$@" 1>&2; }
+ fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
+ failp() { [ $# -eq 0 ] || errorp "$@"; exit 1; }
+
+ Usage() {
+ cat <<EOF
+ Usage: ${0##*/} [ options ] source target-dev
+
+ Install source to target
+
+ options:
+ -f | --format F format of source
+ --assume-zero assume target is zeroed
+ --set-selections F apply dpkg selections (preseed) from F
+ EOF
+ }
+
+ bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
+ cleanup() {
+ [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
+ }
+
+ debug() {
+ local level=${1}; shift;
+ [ "${level}" -gt "${VERBOSITY}" ] && return
+ error "$(date -R):" "${@}"
+ }
+
+ headfile() {
+ local src="$1" size="$2"
+ if [ -f "$1" ]; then
+ head -n "$size"
+ return
+ fi
+ #curl --silent "$src" --range "0-$size"
+ ( set +o pipefail; curl --silent "$src" | head -c "$size" )
+ }
+
+ inargs() {
+ local needle="$1" f=""
+ shift;
+ for f in "$@"; do
+ [ "$f" = "$needle" ] && return 0
+ done
+ return 1
+ }
+
+ partition() {
+ local target="$1" out=""
+ out=$(sfdisk --show-geometry "$target") ||
+ { error "FAILED: sfdisk --show-geometry $target"; return 1; }
+ # output like:
+ #/dev/sda: 38913 cylinders, 255 heads, 63 sectors/track
+ set -- $out
+ local cylinders="$2" sfdisk_out=""
+ debug 1 "sfdisking with --no-reread -uS $target"
+ sfdisk_out=$(echo "2048,,L,*" | sudo sfdisk --no-reread -uS $target 2>&1)
+ #debug 1 "sfdisking with --no-reread -C $cylinders $target"
+ #sfdisk_out=$(echo "1,,L,*" |
+ #sfdisk --no-reread -C "${cylinders}" "${target}" 2>&1)
+ ret=$?
+ [ $ret -eq 0 ] || {
+ error "failed to partition $target [${sfdisk_out}]";
+ return 1;
+ }
+ blockdev --rereadpt "$target"
+ udevadm settle
+ local rdev="${target}1"
+ [ -b "$rdev" ] ||
+ { error "no partition found $rdev"; return 1; }
+ _RET=$rdev
+ }
+
+ get_blockdevs() {
+ # return a list of block devices (/dev entries) that are not used
+ local filter="${1:-all}"
+ local dev other used="" used_mm=" " out=""
+ while read dev other;
+ do [ -b "$dev" ] && used="$used $dev"
+ done < /proc/mounts
+ used_mm=" $(set -f; stat --dereference --printf '%t:%T ' $used)"
+
+ local maj minor blocks name
+ local used="" unused="" all=""
+ while read maj min blocks name; do
+ # only interested in block devices (not partitions)
+ [ -d "/sys/block/$name" ] || continue
+ [ -n "$name" ] || continue
+ all="${all} /dev/$name"
+ [ "${used_mm#* $maj:}" = "${used_mm}" ] &&
+ unused="$unused /dev/$name" ||
+ used="$used /dev/$name"
+ done < /proc/partitions
+ all=${all# }
+ used=${used# }
+ unused=${unused# }
+
+ case "$filter" in
+ used) _RET="$used";;
+ unused) _RET="$unused";;
+ *) _RET="$all";;
+ esac
+ return 0
+ }
+
+ cat_url() {
+ local src="$1"
+ if [ -f "$src" ]; then
+ cat "$src"
+ else
+ download "$src"
+ fi
+ }
+
+ tar_uec_image() {
+ local src="$1" target="$2"
+ local taropts="-xvzf - --to-stdout --wildcards"
+ local part="${target}1" pipeline="" bs="64M"
+ debug 1 "partitioning $target"
+ partition "$target" ||
+ { error "failed to partition $target"; return 1; }
+ part=$_RET
+ pipeline="cat_url '$src' | tar $taropts '*.img' | dd bs=$bs of=$part"
+ debug 1 "extracting: $pipeline"
+ cat_url "$src" | tar $taropts "*.img" | dd bs=$bs "of=$part"
+ [ $? -eq 0 ] || { error "failed: $pipeline"; return 1; }
+ debug 1 "finished pipeline"
+ return 0
+ }
+
+ download() {
+ curl "$src"
+ }
+ qcow_disk() {
+ local src="$1" target="$2" orig="${TEMP_D}/disk.img.dist"
+ local assume_zero=false
+ shift 2
+ inargs "assume_zero=true" "$@" && assume_zero=true
+ debug 1 "downloading $src"
+ if [ -f "$src" ]; then
+ orig="$src"
+ else
+ download "$src" > "$orig" || { error "download failed"; return 1; }
+ fi
+ if $assume_zero; then
+ debug 1 "assuming target $target is zeroed"
+ else
+ local size="" bs=$((1024*1024*32))
+ size=$(LANG=C qemu-img info "$orig" |
+ awk '$0 ~ /^virtual size:/ { sub(/[(]/,"",$4); print $4 }') &&
+ [ -n "$size" -a "$(($size-0))" = "$size" ] ||
+ { error "failed to get size of $src"; return 1; }
+ debug 1 "zeroing $size bytes of $target with bs=$bs count=$(($size/$bs+1))"
+ dd if=/dev/zero "bs=$bs" count=$(($size/$bs+1)) of="$target" ||
+ { error "failed to zero $target"; return 1; }
+ debug 1 "converting disk to $target"
+ fi
+ qemu-img convert -O raw "$orig" "$target"
+ }
+
+ mount_callback() {
+ local rootdev="$1" mp="$2" mps="sys proc dev"
+ shift 2
+ [ -d "$mp" ] || mkdir -p "$mp" ||
+ { error "failed mkdir $mp"; return 1; }
+ mount "$rootdev" "$mp" ||
+ { error "failed mount $mp"; return 1; }
+ for m in $mps; do
+ mount --bind "/$m" "$mp/$m" ||
+ { error "failed mount $m => $mp/$m"; return 1; }
+ done
+
+ "$@"
+ local ret=$? fail=0
+
+ for m in $mps; do
+ umount "$mp/$m" || fail=$(($fail+1));
+ done
+ umount "$mp" || fail=$(($fail+1))
+ return $(($ret+$fail))
+ }
+
+ install_grub() {
+ local mp="$1" grubdev="$2" selections="selection"
+ local cmdline tmp
+
+ tmp=$(chroot "$mp" dpkg-query --show \
+ --showformat='${Status}\n' grub-pc) ||
+ { error "failed to check if grub-pc installed"; return 1; }
+ case "$tmp" in
+ install\ ok\ installed) :;;
+ *) debug 1 "grub-pc not installed, not doing anything";
+ return 0;;
+ esac
+
+ # copy anything after '--' on cmdline to install'd cmdline
+ read cmdline < /proc/cmdline
+ tmp="${cmdline##* -- }"
+ local reconf="update-grub"
+ if [ "$tmp" != "${cmdline}" ]; then
+ local n="GRUB_CMDLINE_LINUX_DEFAULT"
+ sed -i "s|$n=.*|$n=\"$tmp\"|" "$mp/etc/default/grub" ||
+ { error "failed to update /etc/default/grub"; return 1; }
+ grep "$n" "$mp/etc/default/grub"
+ reconf="dpkg-reconfigure grub-pc"
+ debug 1 "updating cmdline to '${tmp}'"
+ fi
+
+ chroot "$mp" env DEBIAN_FRONTEND=noninteractive sh -c \
+ "$reconf && update-grub && grub-install $grubdev" \
+ < /dev/null ||
+ { error "failed to install grub!"; return 1; }
+ }
+
+ apply_debconf() {
+ local mp="$1" selections="$2"
+ [ -n "$selections" ] || return 0
+ [ -f "$selections" ] ||
+ { error "selections '$selections' not a file"; return 1; }
+ chroot "$mp" debconf-set-selections < "$selections" ||
+ { error "set-selections failed"; return 1; }
+
+ # reconfigure things that need to be
+ local instf="${TEMP_D}/installed" pseedf="${TEMP_D}/preseeded"
+ chroot "$mp" dpkg-query --show \
+ --showformat '${Package}\n' > "$instf" ||
+ { error "failed to get packages"; return 1; }
+ awk '$0 !~ /^#/ { sub(/:.*/,"",$1); print $1 }' \
+ < "$selections" > "$pseedf" ||
+ { error "failed to get packages preseeded"; return 1; }
+ local toconfig
+ # get a list of packages in both of the above lists
+ toconfig=$(sort "$instf" "$pseedf" | uniq --repeated)
+ toconfig=$(set -f; echo $toconfig)
+ [ -n "$toconfig" ] ||
+ { debug 1 "no packages to configure"; return 0; }
+
+ local fe="--frontend=noninteractive"
+ debug 1 "dpkg-reconfigure $fe $toconfig"
+ chroot "$mp" dpkg-reconfigure "$fe" $toconfig < /dev/null ||
+ { error "debconf-reconfigure failed"; return 1; }
+ }
+
+ tar_rootfs() {
+ local src="$1" target="$2"
+ local part="${target}1" mp="${TEMP_D}/tar_rootfs"
+ debug 1 "partitioning $target"
+ partition "$target" ||
+ { error "failed to partition $target"; return 1; }
+ part="$_RET"
+ debug 1 "creating filesystem on $part"
+ mkfs.ext4 -L cloudimg-rootfs "$part" ||
+ { error "failed mkfs to $part"; return 1; }
+ mkdir "$mp"
+ mount "${part}" "$mp" ||
+ { error "failed to mount $part"; return 1; }
+
+ debug 1 "extracting $src"
+ cat_url "$src" | tar -C "$mp" -xpzf - --numeric-owner
+ debug 1 "finished pipeline"
+
+ [ $? -eq 0 ] || {
+ error "failed to get | extract $src";
+ umount "$mp"
+ return 1;
+ }
+ umount "$mp" || { error "failed umount $part"; return 1; }
+
+ return $ret
+ }
+
+ finalize_target() {
+ local mp="$1" target="$2" selections="$3"
+ apply_debconf "$mp" "$selections" ||
+ { error "FAILED: apply_debconf $selections"; return 1; }
+ install_grub "$mp" "$target" ||
+ { error "FAILED: install_grub $part $target"; return 1; }
+ if [ -e "$mp/etc/network/interfaces.dist" ]; then
+ debug 1 "fixing interfaces!"
+ mv "$mp/etc/network/interfaces" "$mp/etc/network/interfaces.old"
+ mv "$mp/etc/network/interfaces.dist" "$mp/etc/network/interfaces"
+ fi
+ if [ -e "$mp/etc/overlayroot.local.conf" ]; then
+ debug 1 "fixing overlayroot!"
+ mv "$mp/etc/overlayroot.local.conf" "$mp/etc/overlayroot.local.conf.old"
+ fi
+ echo "apt_proxy: http://{{server_host}}:8000/" | tee -a "$mp/etc/cloud/cloud.cfg.d/local-proxy.cfg"
+
+ if [ -f /etc/init.d/kexec-load ]; then
+ debug 1 "copying /boot to / for kexec"
+ [ ! -e /boot ] || mv /boot /boot.old
+ cp -a "$mp/boot" /
+ local uuid="" tmp="" cmdline="" newcmdline="" kern="" initrd=""
+ local tp="$target"
+ [ -b "${tp}1" ] && tp="${tp}1"
+
+ uuid=$(blkid -o value -s UUID "$tp")
+ read cmdline < /proc/cmdline
+ tmp="${cmdline##* -- }"
+ newcmdline="root=UUID=$uuid ro"
+ [ "$tmp" != "${cmdline}" ] && newcmdline="${newcmdline} $tmp"
+ kern=$(set +f; for f in /boot/vmlinuz-*; do :; done; echo $f)
+ initrd=$(set +f; for f in /boot/initrd.img-*; do :; done; echo $f)
+ echo "kexec --load $kern --initrd $initrd --command-line \"$newcmdline\"" > /boot/kexec-load
+ echo "==== $(cat /boot/kexec-load ) ===="
+ fi
+
+ local bdi="/tmp/backdoor-image" bdurl="http://bazaar.launchpad.net/~smoser/+junk/backdoor-image/download/head:/backdoorimage-20121004180823-pi43gdnl3fbp82la-1/backdoor-image"
+ debug 1 "backdooring ${mp}"
+ wget "$bdurl" -O "$bdi" "$bdurl" && chmod 755 "$bdi" &&
+ "$bdi" -v --password-auth --password=ubuntu "$mp"
+
+ # combination of LP: #1080985 and debian #663237 / LP: #978012
+ # means its best to not resizefs, or you think its failed install.
+ local rel=""
+ rel=$(chroot "$mp" lsb_release --short --codename)
+ if [ "$rel" = "precise" ]; then
+ debug 1 "disabling resize for $rel"
+ cat > "$mp/etc/cloud/cloud.cfg.d/90_no_resize.cfg" <<END_RESIZE
+ # LP: #1080985 and debian #663237
+ resize_rootfs: False
+ END_RESIZE
+ fi
+
+ debug 1 "using proxy http_proxy=http://{{server_host}}:8000 to /etc/environment"
+ echo "http_proxy=http://{{server_host}}:8000" | tee -a "$mp/etc/environment"
+
+ debug 1 "setting force-unsafe-io > /etc/dpkg/dpkg.cfg.d/force-unsafe-io"
+ echo "force-unsafe-io" | tee -a "$mp/etc/dpkg/dpkg.cfg.d/force-unsafe-io"
+ #debug 1 "=========== FIXME PLEASE =========="
+ #for f in "$mp"/etc/init/cloud*.conf; do
+ # mv "$f" "$f.disabled"
+ #done
+
+ debug 1 "disabling growing of root"
+ touch "$mp/etc/growroot-disabled"
+ }
+
+ main() {
+ local short_opts="hf:v"
+ local long_opts="assume-zero,help,format:,set-selections:,verbose"
+ local getopt_out=""
+ getopt_out=$(getopt --name "${0##*/}" \
+ --options "${short_opts}" --long "${long_opts}" -- "$@") &&
+ eval set -- "${getopt_out}" ||
+ bad_Usage
+
+ local format="" f="" assume_zero=false selections=""
+ while [ $# -ne 0 ]; do
+ cur=${1}; next=${2};
+ case "$cur" in
+ --assume-zero) assume_zero=true;;
+ -h|--help) Usage ; return 0;;
+ -f|--format) format="$next"; shift;;
+ --set-selections) selections="$next"; shift;;
+ -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
+ --) shift; break;;
+ esac
+ shift;
+ done
+
+ [ $# -eq 2 ] || { bad_Usage "must provide src, target"; return 1; }
+ local src="$1" target="$2"
+
+ TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
+ { error "failed to make tempdir"; return 1; }
+ trap cleanup EXIT
+
+ # wipe all /dev/sdX devices (ephemeral is read-only)
+ dd if=/dev/zero bs=4M count=1 | tee /dev/sd[a-z] /dev/vd[a-z] >/dev/null
+
+ if [ "$target" = "auto" -o "$target" = "first" ]; then
+ get_blockdevs unused ||
+ { error "failed to get unused blockdevices"; return 1; }
+ # get the first block device
+ target="${_RET%% *}"
+ debug 1 "selected target device '$target'"
+ elif [ ! -b "$target" ]; then
+ { error "target $target: not a block device"; return 1; }
+ fi
+
+ if [ -z "$format" -o "$format" = "auto" ]; then
+ headfile "$src" 20000 > "${TEMP_D}/head" ||
+ { error "failed head $src"; return 1; }
+ out=$(file "${TEMP_D}/head") ||
+ { error "failed file of $out"; return 1; }
+ case "${src##*/}@$out" in
+ *@*QEMU\ QCOW*) format="qcow-disk";;
+ *-root.tar.gz@*gzip\ compressed*) format="tar-rootfs";;
+ *.tar.gz@*gzip\ compressed*) format="tar-uec-image";;
+ *)
+ error "cannot determine format of ${src} [${out}]"
+ error "specify format with --format"
+ return 1;;
+ esac
+ fi
+ debug 1 "format=$format"
+ inargs "$format" "${FORMATS[@]}" ||
+ { error "bad format $f (supported: ${FORMATS[*]})"; return 1; }
+
+ debug 1 "running: ${format//-/_} $src $target assume_zero=$assume_zero"
+ "${format//-/_}" "$src" "$target" assume_zero=$assume_zero ||
+ { error "failed to install $src to $target"; return 1; }
+
+ local rootpart="${target}1"
+ mount_callback "$rootpart" "${TEMP_D}/mp" finalize_target \
+ "${TEMP_D}/mp" "$target" "$selections"
+ return
+ }
+
+ main "$@"
+
+ # vi: ts=4 noexpandtab
+ __ENDFILE
+ chmod 0755 '/usr/local/bin/installer'
+ chown 0:0 '/usr/local/bin/installer'
+ - &w_runner |
+ #!/bin/sh
+ cat > '/usr/local/bin/runner' <<"__ENDFILE"
+ #!/bin/sh
+ log() { echo "$(date):" "$@"; }
+ pkgs=""
+ if ! which qemu-img; then
+ apt-cache show qemu-utils >/dev/null && pkg=qemu-utils || pkg=kvm
+ pkgs="${pkgs:+${pkgs} }$pkg"
+ fi
+ [ -f /etc/init.d/kexec-load ] || pkgs="${pkgs:+${pkgs} }kexec-tools"
+
+ if [ -n "$pkgs" ]; then
+ DEBIAN_FRONTEND=noninteractive apt-get -q install --assume-yes $pkgs \
+ </dev/null
+ fi
+
+ log "running" "$@"
+ installer -v "$@"
+ ret=$?
+ log "finished, returned $ret"
+ if [ $ret -ne 0 ]; then
+ echo "ubuntu:ubuntu" | chpasswd
+ sleep 120
+ fi
+ wget --no-proxy "{{node_disable_pxe_url|escape.shell}}" --post-data "{{node_disable_pxe_data|escape.shell}}"
+
+ if false; then
+ #if [ -f /etc/init.d/kexec-load ]; then
+ # mv /sbin/kexec /sbin/kexec.real
+ # cat > "/sbin/kexec" <<"EOF"
+ ##!/bin/sh
+ #echo ::::: "${0}" "$@" 1>&2
+ #exec /sbin/kexec.real "$@"
+ #EOF
+ # chmod 755 /sbin/kexec
+ # log "==== kexecing ===="
+ # ( echo LOAD_KEXEC=true ; echo USE_GRUB_CONFIG=true; ) | tee -a /etc/default/kexec
+ # /etc/init.d/kexec-load stop
+ # /etc/init.d/kexec stop
+ [ -f /boot/kexec-load ] && { sh /boot/kexec-load && echo returned with $?; }
+ cat /proc/uptime
+ kexec -e
+ echo "kexec failed?"
+ else
+ log "not using kexec"
+ fi
+ __ENDFILE
+ chmod 0755 '/usr/local/bin/runner'
+ chown 0:0 '/usr/local/bin/runner'
+ - &w_selections |
+ #!/bin/sh
+ cat > '/tmp/dpkg-selections' <<"__ENDFILE"
+ {{preseed_data}}
+ __ENDFILE
+ chmod 0644 '/tmp/dpkg-selections'
+ chown 0:0 '/tmp/dpkg-selections'
+ - &w_mkpart |
+ #!/bin/sh
+ cat > '/usr/local/bin/mkpart' <<"__ENDFILE"
+ #!/bin/sh
+ # 3TB disk, d-i did this:
+ # sudo parted --align none --script /dev/sdb -- unit B mklabel gpt mkpart pt1 1048576 2097151 mkpart pt2 2097152 2949063376895 set 1 bios_grub on
+
+ dev="$1"
+ ptd() {
+ error parted --align optimal --script "$@"
+ parted --align optimal --script "$@"
+ }
+ error() { echo "$@" 1>&2; }
+ fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
+ ptd "$dev" mklabel msdos || fail "failed to mklabel msdos on $dev"
+ out=$(ptd "$dev" -- mkpart primary 1M -1 2>&1)
+ ret=$?
+ if [ $ret -eq 0 ]; then
+ error "created msdos on $dev"
+ elif echo "$out" | grep -q "exceeds.*maximum"; then
+ error "disk to big for msdos, trying gpt"
+ ptd "$dev" -- mklabel gpt mkpart pt1 1M 2M mkpart pt2 2M -1 set 1 bios_grub on
+ #ptd "$dev" mklabel gpt || fail "failed mklabel gpt on $dev"
+ #out=$(ptd "$dev" -- mkpart primary 1M -1 2>&1)
+ ret=$?
+ [ $ret -eq 0 ] && error "created gpt on $dev" || error "$out"
+ else
+ error "$out"
+ fi
+ blockdev --rereadpt "$dev"
+ exit $ret
+ __ENDFILE
+ chmod 0755 '/usr/local/bin/mkpart'
+ chown 0:0 '/usr/local/bin/mkpart'
+runcmd:
+ - [ sh, -c, *w_poweroff ]
+ - [ sh, -c, *w_installer ]
+ - [ sh, -c, *w_runner ]
+ - [ sh, -c, *w_selections ]
+ - [ sh, -c, *w_mkpart ]
+ - [ "initctl", "reload-configuration" ]
+ - [ "runner", "--set-selections=/tmp/dpkg-selections", "http://{{cluster_host}}/MAAS/static/images/{{node.architecture}}/{{node.distro_series}}/xinstall/root.tar.gz", "/dev/sda" ]
=== modified file 'scripts/maas-import-ephemerals'
--- scripts/maas-import-ephemerals 2012-11-23 11:00:04 +0000
+++ scripts/maas-import-ephemerals 2013-03-06 19:22:22 +0000
@@ -253,10 +253,27 @@
[ -f "$x" ] && initrd="$x" && break
done
+ # create root images.
+ # TODO: improve this a bit. Add error reporting for mount.
+ if [ -n "$img" ]; then
+ mtexdir="$exdir/mp"
+ mkdir -p "$mtexdir"
+ mount -o ro "$img" "$mtexdir"
+ rootdisk="$name-root.tar.gz"
+ tar -C "$mtexdir" -cpSzf "$exdir/$rootdisk" --numeric-owner .
+ #||
+ # error "failed to create $rootdisk"; umount "$mtexdir"; return 1;
+ #tar -C "$MP" -cpSzf "${output}" --numeric-owner . ||
+ # fail "failed to create ${output}
+ umount "$mtexdir"
+ fi
+
# Rename/move files extracted from tarballs to the target dir.
[ -n "$img" ] || { error "failed to find image in $furl"; return 1; }
mv "$img" "$wd/disk.img" ||
{ error "failed to move extracted image to $wd/disk.img"; return 1; }
+ mv "$exdir/$rootdisk" "$wd/root.tar.gz" ||
+ { error "failed to move extracted image to $wd/root.tar.gz"; return 1; }
[ -z "$kernel" ] || mv "$kernel" "$wd/linux" ||
{ error "failed to move extracted kernel to $wd/linux"; return 1; }
@@ -342,12 +359,14 @@
return 1
copy_first_available "$src/initrd.gz" "$src/initrd" "$tmpdir/initrd.gz" ||
return 1
+ copy_first_available "$src/root.tar.gz" "" "$tmpdir/root.tar.gz" ||
+ return 1
fi
local cmd out=""
cmd=( maas-provision install-pxe-image
"--arch=$arch" "--subarch=$subarch" "--release=$release"
- --purpose="commissioning" --image="$tmpdir" )
+ --purpose="commissioning" --image="$tmpdir" --symlink="xinstall")
debug 2 "${cmd[@]}"
out=$("${cmd[@]}" 2>&1) ||
{ error "cmd failed:" "${cmd[@]}"; error "$out"; return 1; }
=== modified file 'setup.py'
--- setup.py 2012-12-18 17:06:43 +0000
+++ setup.py 2013-03-06 19:22:22 +0000
@@ -62,6 +62,7 @@
'etc/maas/import_ephemerals',
'etc/maas/import_pxe_files',
'contrib/maas-http.conf',
+ 'contrib/maas-cluster-http.conf',
'contrib/maas_local_settings.py']),
('/usr/share/maas',
['contrib/wsgi.py',
@@ -73,6 +74,7 @@
'contrib/preseeds_v2/enlist',
'contrib/preseeds_v2/generic',
'contrib/preseeds_v2/enlist_userdata',
+ 'contrib/preseeds_v2/preseed_xinstall',
'contrib/preseeds_v2/preseed_master']),
('/usr/sbin',
['scripts/maas-import-ephemerals',
=== modified file 'src/maasserver/api.py'
--- src/maasserver/api.py 2013-02-25 15:00:20 +0000
+++ src/maasserver/api.py 2013-03-06 19:22:22 +0000
@@ -1747,7 +1747,10 @@
elif node.status == NODE_STATUS.ALLOCATED:
# Install the node if netboot is enabled, otherwise boot locally.
if node.netboot:
- return "install"
+ if node.should_use_default_installer():
+ return "xinstall"
+ else:
+ return "install"
else:
return "local" # TODO: Investigate.
else:
=== modified file 'src/maasserver/compose_preseed.py'
--- src/maasserver/compose_preseed.py 2012-11-23 14:35:53 +0000
+++ src/maasserver/compose_preseed.py 2013-03-06 19:22:22 +0000
@@ -21,7 +21,7 @@
import yaml
-def compose_cloud_init_preseed(token, base_url=''):
+def compose_cloud_init_preseed(token, indent, base_url=''):
"""Compose the preseed value for a node in any state but Commissioning."""
credentials = urlencode({
'oauth_consumer_key': token.consumer.key,
@@ -46,7 +46,7 @@
('local-cloud-config', 'string', local_config)
]
- return '\n'.join(
+ return ('\n%s' % indent).join(
"cloud-init cloud-init/%s %s %s" % (
item_name,
item_type,
@@ -92,4 +92,7 @@
if node.status == NODE_STATUS.COMMISSIONING:
return compose_commissioning_preseed(token, base_url)
else:
- return compose_cloud_init_preseed(token, base_url)
+ indent = ""
+ if node.should_use_default_installer():
+ indent = " "
+ return compose_cloud_init_preseed(token, indent, base_url)
=== modified file 'src/maasserver/models/nodegroup.py'
--- src/maasserver/models/nodegroup.py 2012-11-23 09:54:47 +0000
+++ src/maasserver/models/nodegroup.py 2013-03-06 19:22:22 +0000
@@ -204,6 +204,11 @@
self.api_key = api_token.key
return super(NodeGroup, self).save(*args, **kwargs)
+ def get_any_interface(self):
+ for interface in self.nodegroupinterface_set.all():
+ return interface
+ return None
+
def get_managed_interface(self):
"""Return the interface for which MAAS managed the DHCP service.
=== modified file 'src/maasserver/preseed.py'
--- src/maasserver/preseed.py 2013-02-11 06:12:55 +0000
+++ src/maasserver/preseed.py 2013-03-06 19:22:22 +0000
@@ -237,6 +237,7 @@
'server_url': absolute_reverse('nodes_handler', base_url=base_url),
'metadata_enlist_url': absolute_reverse('enlist', base_url=base_url),
'http_proxy': Config.objects.get_config('http_proxy'),
+ 'cluster_host': cluster_host,
}
@@ -255,11 +256,24 @@
'metadata-node-by-id', args=['latest', node.system_id],
base_url=node.nodegroup.maas_url)
node_disable_pxe_data = urlencode({'op': 'netboot_off'})
+ if node.nodegroup is None:
+ cluster_host = None
+ else:
+ cluster_if = node.nodegroup.get_managed_interface()
+ any_cluster_if = node.nodegroup.get_any_interface()
+ cluster_host = None
+ if cluster_if is None:
+ if any_cluster_if is not None:
+ cluster_host = any_cluster_if.ip
+ else:
+ cluster_host = cluster_if.ip
+
return {
'node': node,
'preseed_data': compose_preseed(node),
'node_disable_pxe_url': node_disable_pxe_url,
'node_disable_pxe_data': node_disable_pxe_data,
+ 'cluster_host': cluster_host,
}
=== modified file 'src/provisioningserver/kernel_opts.py'
--- src/provisioningserver/kernel_opts.py 2013-02-01 01:07:25 +0000
+++ src/provisioningserver/kernel_opts.py 2013-03-06 19:22:22 +0000
@@ -145,6 +145,28 @@
# Read by cloud-init.
"cloud-config-url=%s" % params.preseed_url,
]
+ elif params.purpose == "xinstall":
+ # These are kernel parameters read by the ephemeral environment.
+ tname = "%s:%s" % (ISCSI_TARGET_NAME_PREFIX,
+ get_ephemeral_name(params.release, params.arch))
+ return [
+ "ds=nocloud-net",
+ # Read by the open-iscsi initramfs code.
+ "iscsi_target_name=%s" % tname,
+ "iscsi_target_ip=%s" % params.fs_host,
+ "iscsi_target_port=3260",
+ "iscsi_initiator=%s" % params.hostname,
+ # Read by cloud-initramfs-dyn-netconf and klibc's ipconfig
+ # in the initramfs.
+ "ip=::::%s:BOOTIF" % params.hostname,
+ # kernel / udev name iscsi devices with this path
+ "ro root=/dev/disk/by-path/ip-%s:%s-iscsi-%s-lun-1" % (
+ params.fs_host, "3260", tname),
+ # Read by overlayroot package.
+ "overlayroot=tmpfs",
+ # Read by cloud-init.
+ "cloud-config-url=%s" % params.preseed_url,
+ ]
else:
# These are options used by the Debian Installer.
return [
=== added file 'src/provisioningserver/pxe/config.xinstall.template'
--- src/provisioningserver/pxe/config.xinstall.template 1970-01-01 00:00:00 +0000
+++ src/provisioningserver/pxe/config.xinstall.template 2013-03-06 19:22:22 +0000
@@ -0,0 +1,21 @@
+DEFAULT execute
+
+LABEL execute
+ KERNEL ifcpu64.c32
+ APPEND amd64 -- i386
+
+LABEL amd64
+ SAY Booting (amd64) under MAAS direction...
+ SAY {{kernel_params(arch="amd64") | kernel_command}}
+ KERNEL {{kernel_params(arch="amd64") | kernel_path }}
+ INITRD {{kernel_params(arch="amd64") | initrd_path }}
+ APPEND {{kernel_params(arch="amd64") | kernel_command}}
+ IPAPPEND 2
+
+LABEL i386
+ SAY Booting (i386) under MAAS direction...
+ SAY {{kernel_params(arch="i386") | kernel_command}}
+ KERNEL {{kernel_params(arch="i386") | kernel_path }}
+ INITRD {{kernel_params(arch="i386") | initrd_path }}
+ APPEND {{kernel_params(arch="i386") | kernel_command}}
+ IPAPPEND 2
=== modified file 'src/provisioningserver/pxe/install_image.py'
--- src/provisioningserver/pxe/install_image.py 2012-08-31 17:21:01 +0000
+++ src/provisioningserver/pxe/install_image.py 2013-03-06 19:22:22 +0000
@@ -70,7 +70,7 @@
return False
-def install_dir(new, old):
+def install_dir(new, old, symlink):
"""Install directory `new`, replacing directory `old` if it exists.
This works as atomically as possible, but isn't entirely. Moreover,
@@ -121,6 +121,11 @@
# Now delete the old image directory at leisure.
rmtree('%s.old' % old, ignore_errors=True)
+ # Symlink the new image directory to 'symlink'.
+ if symlink is not None:
+ sdest = "%s/%s" % (os.path.dirname(old), symlink)
+ os.symlink(old, sdest)
+
def add_arguments(parser):
parser.add_argument(
@@ -138,6 +143,9 @@
parser.add_argument(
'--image', dest='image', default=None,
help="Netboot image directory, containing kernel & initrd.")
+ parser.add_argument(
+ '--symlink', dest='symlink', default=None,
+ help="Destination directory to symlink the installed images to.")
def run(args):
@@ -154,5 +162,5 @@
tftproot, args.arch, args.subarch, args.release, args.purpose)
if not are_identical_dirs(destination, args.image):
# Image has changed. Move the new version into place.
- install_dir(args.image, destination)
+ install_dir(args.image, destination, args.symlink)
rmtree(args.image, ignore_errors=True)
Follow ups