From b62b4ca2928fbcdf339be804da9d4aade41380e4 Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Wed, 26 Oct 2011 22:29:08 -0700 Subject: [PATCH] Initial commit of xen devstack support --- files/apts/nova | 1 + stack.sh | 45 ++- tools/xen/README.md | 51 +++ tools/xen/build_domU.sh | 288 +++++++++++++++ tools/xen/files/fstab | 5 + tools/xen/files/hvc0.conf | 10 + tools/xen/prepare_dom0.sh | 41 +++ tools/xen/prepare_guest.sh | 88 +++++ tools/xen/scripts/install-os-vpx.sh | 508 ++++++++++++++++++++++++++ tools/xen/scripts/mkxva | 366 +++++++++++++++++++ tools/xen/scripts/uninstall-os-vpx.sh | 102 ++++++ tools/xen/templates/hosts.in | 8 + tools/xen/templates/interfaces.in | 21 ++ tools/xen/templates/menu.lst.in | 6 + tools/xen/templates/ova.xml.in | 14 + 15 files changed, 1547 insertions(+), 7 deletions(-) create mode 100644 tools/xen/README.md create mode 100755 tools/xen/build_domU.sh create mode 100644 tools/xen/files/fstab create mode 100644 tools/xen/files/hvc0.conf create mode 100755 tools/xen/prepare_dom0.sh create mode 100644 tools/xen/prepare_guest.sh create mode 100755 tools/xen/scripts/install-os-vpx.sh create mode 100755 tools/xen/scripts/mkxva create mode 100755 tools/xen/scripts/uninstall-os-vpx.sh create mode 100644 tools/xen/templates/hosts.in create mode 100644 tools/xen/templates/interfaces.in create mode 100644 tools/xen/templates/menu.lst.in create mode 100644 tools/xen/templates/ova.xml.in diff --git a/files/apts/nova b/files/apts/nova index eb85e26047..31adee1a31 100644 --- a/files/apts/nova +++ b/files/apts/nova @@ -1,5 +1,6 @@ dnsmasq-base kpartx +parted mysql-server python-mysqldb kvm diff --git a/stack.sh b/stack.sh index 628ce54e3f..9e2a7942de 100755 --- a/stack.sh +++ b/stack.sh @@ -130,9 +130,10 @@ NOVNC_DIR=$DEST/noVNC # Specify which services to launch. These generally correspond to screen tabs ENABLED_SERVICES=${ENABLED_SERVICES:-g-api,g-reg,key,n-api,n-cpu,n-net,n-sch,n-vnc,dash,mysql,rabbit} -# Nova hypervisor configuration. We default to **kvm** but will drop back to -# **qemu** if we are unable to load the kvm module. Stack.sh can also install -# an **LXC** based system. +# Nova hypervisor configuration. We default to libvirt whth **kvm** but will +# drop back to **qemu** if we are unable to load the kvm module. Stack.sh can +# also install an **LXC** based system. +VIRT_DRIVER=${VIRT_DRIVER:-libvirt} LIBVIRT_TYPE=${LIBVIRT_TYPE:-kvm} # nova supports pluggable schedulers. ``SimpleScheduler`` should work in most @@ -572,14 +573,30 @@ add_nova_flag "--ec2_dmz_host=$EC2_DMZ_HOST" add_nova_flag "--rabbit_host=$RABBIT_HOST" add_nova_flag "--rabbit_password=$RABBIT_PASSWORD" add_nova_flag "--glance_api_servers=$GLANCE_HOSTPORT" -add_nova_flag "--flat_network_bridge=$FLAT_NETWORK_BRIDGE" -if [ -n "$FLAT_INTERFACE" ]; then - add_nova_flag "--flat_interface=$FLAT_INTERFACE" -fi if [ -n "$MULTI_HOST" ]; then add_nova_flag "--multi_host=$MULTI_HOST" fi +# XenServer +# --------- + +if [ "$VIRT_DRIVER" = 'xenserver' ]; then + read_password XENAPI_PASSWORD "ENTER A PASSWORD TO USE FOR XEN." + add_nova_flag "--connection_type=xenapi" + add_nova_flag "--xenapi_connection_url=http://169.254.0.1" + add_nova_flag "--xenapi_connection_username=root" + add_nova_flag "--xenapi_connection_password=$XENAPI_PASSWORD" + add_nova_flag "--flat_injected=False" + add_nova_flag "--flat_interface=eth1" + add_nova_flag "--flat_network_bridge=xapi1" + add_nova_flag "--public_interface=eth3" +else + add_nova_flag "--flat_network_bridge=$FLAT_NETWORK_BRIDGE" + if [ -n "$FLAT_INTERFACE" ]; then + add_nova_flag "--flat_interface=$FLAT_INTERFACE" + fi +fi + # Nova Database # ~~~~~~~~~~~~~ @@ -712,6 +729,20 @@ if [[ "$ENABLED_SERVICES" =~ "g-reg" ]]; then # Create a directory for the downloaded image tarballs. mkdir -p $FILES/images + # Option to upload legacy ami-tty, which works with xenserver + if [ $UPLOAD_LEGACY_TTY ]; then + if [ ! -f $FILES/tty.tgz ]; then + wget -c http://images.ansolabs.com/tty.tgz -O $FILES/tty.tgz + fi + + tar -zxf $FILES/tty.tgz -C $FILES/images + RVAL=`glance add -A $SERVICE_TOKEN name="tty-kernel" is_public=true container_format=aki disk_format=aki < $FILES/images/aki-tty/image` + KERNEL_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "` + RVAL=`glance add -A $SERVICE_TOKEN name="tty-ramdisk" is_public=true container_format=ari disk_format=ari < $FILES/images/ari-tty/image` + RAMDISK_ID=`echo $RVAL | cut -d":" -f2 | tr -d " "` + glance add -A $SERVICE_TOKEN name="tty" is_public=true container_format=ami disk_format=ami kernel_id=$KERNEL_ID ramdisk_id=$RAMDISK_ID < $FILES/images/ami-tty/image + fi + for image_url in ${IMAGE_URLS//,/ }; do # Downloads the image (uec ami+aki style), then extracts it. IMAGE_FNAME=`echo "$image_url" | python -c "import sys; print sys.stdin.read().split('/')[-1]"` diff --git a/tools/xen/README.md b/tools/xen/README.md new file mode 100644 index 0000000000..014032e5fe --- /dev/null +++ b/tools/xen/README.md @@ -0,0 +1,51 @@ +Getting Started With XenServer 5.6 and Devstack +=============================================== +The purpose of the code in this directory it to help developers bootstrap +a XenServer 5.6 + Openstack development environment. This file gives +some pointers on how to get started. + +Install Xenserver +----------------- +Install XenServer 5.6 on a clean box. +Here are some sample Xenserver network settings for when you are just +getting started (I used settings like this using a lappy + cheap wifi router): + +* XenServer Host IP: 192.168.1.10 +* XenServer Netmask: 255.255.255.0 +* XenServer Gateway: 192.168.1.1 +* XenServer DNS: 192.168.1.1 + +Prepare DOM0 +------------ +At this point, your server is missing some critical software that you will +need to run devstack (like git). Do this to install required software: + + ./prepare_dom0.sh + +This script will also clone devstack in /root/devstack + +Configure your localrc +---------------------- +Devstack uses a localrc for user-specific configuration. Note that while +the first 4 passwords are arbitrary, the XENAPI_PASSWORD must be your dom0 +root password. And of course, use a real password if this machine is exposed. + + cd /root/devstack + + cat > /root/devstack/localrc <> /etc/sysconfig/network +fi + +# Also, enable ip forwarding in rc.local, since the above trick isn't working +if ! grep -q "echo 1 >/proc/sys/net/ipv4/ip_forward" /etc/rc.local; then + echo "echo 1 >/proc/sys/net/ipv4/ip_forward" >> /etc/rc.local +fi + +# Enable ip forwarding at runtime as well +echo 1 > /proc/sys/net/ipv4/ip_forward + +# Directory where we stage the build +STAGING_DIR=$TOP_DIR/stage + +# Option to clean out old stuff +CLEAN=${CLEAN:-0} +if [ "$CLEAN" = "1" ]; then + rm -rf $STAGING_DIR +fi + +# Download our base image. This image is made using prepare_guest.sh +BASE_IMAGE_URL=${BASE_IMAGE_URL:-http://images.ansolabs.com/xen/stage.tgz} +if [ ! -e $STAGING_DIR ]; then + if [ ! -e /tmp/stage.tgz ]; then + wget $BASE_IMAGE_URL -O /tmp/stage.tgz + fi + tar xfz /tmp/stage.tgz + cd $TOP_DIR +fi + +# Free up precious disk space +rm -f /tmp/stage.tgz + +# Make sure we have a stage +if [ ! -d $STAGING_DIR/etc ]; then + echo "Stage is not properly set up!" + exit 1 +fi + +# Directory where our conf files are stored +FILES_DIR=$TOP_DIR/files + +# Directory for supporting script files +SCRIPT_DIR=$TOP_DIR/scripts + +# Version of ubuntu with which we are working +UBUNTU_VERSION=`cat $STAGING_DIR/etc/lsb-release | grep "DISTRIB_CODENAME=" | sed "s/DISTRIB_CODENAME=//"` +KERNEL_VERSION=`ls $STAGING_DIR/boot/vmlinuz* | head -1 | sed "s/.*vmlinuz-//"` + +# Setup fake grub +rm -rf $STAGING_DIR/boot/grub/ +mkdir -p $STAGING_DIR/boot/grub/ +cp $FILES_DIR/menu.lst.in $STAGING_DIR/boot/grub/menu.lst +sed -e "s,@KERNEL_VERSION@,$KERNEL_VERSION,g" -i $STAGING_DIR/boot/grub/menu.lst + +# Setup fstab, tty, and other system stuff +cp $FILES_DIR/fstab $STAGING_DIR/etc/fstab +cp $FILES_DIR/hvc0.conf $STAGING_DIR/etc/init/ + +# Put the VPX into UTC. +rm -f $STAGING_DIR/etc/localtime + +# Helper to set hostname +function set_hostname() { + echo $1 > $STAGING_DIR/etc/hostname +} + +# We need a resolvable host name for rabbit to launch +if ! grep -q $GUEST_NAME $STAGING_DIR/etc/hosts; then + echo "$MGT_IP $GUEST_NAME" >> $STAGING_DIR/etc/hosts +fi + +# Configre hosts file +cat <$STAGING_DIR/etc/hosts +$MGT_IP $GUEST_NAME +127.0.0.1 localhost localhost.localdomain +EOF + +# Configure dns (use same dns as dom0) +cp /etc/resolv.conf $STAGING_DIR/etc/resolv.conf + +# Copy over devstack +rm -f /tmp/devstack.tar +tar --exclude='stage' --exclude='xen/xvas' --exclude='xen/nova' -cvf /tmp/devstack.tar $TOP_DIR/../../../devstack +cd $STAGING_DIR/opt/stack/ +tar xf /tmp/devstack.tar +cd $TOP_DIR + +# Configure OVA +VDI_SIZE=$(($VDI_MB*1024*1024)) +PRODUCT_BRAND=${PRODUCT_BRAND:-openstack} +PRODUCT_VERSION=${PRODUCT_VERSION:-001} +BUILD_NUMBER=${BUILD_NUMBER:-001} +LABEL="$PRODUCT_BRAND $PRODUCT_VERSION-$BUILD_NUMBER" +OVA=$STAGING_DIR/tmp/ova.xml +cp templates/ova.xml.in $OVA +sed -e "s,@VDI_SIZE@,$VDI_SIZE,g" -i $OVA +sed -e "s,@PRODUCT_BRAND@,$PRODUCT_BRAND,g" -i $OVA +sed -e "s,@PRODUCT_VERSION@,$PRODUCT_VERSION,g" -i $OVA +sed -e "s,@BUILD_NUMBER@,$BUILD_NUMBER,g" -i $OVA + +# Directory for xvas +XVA_DIR=$TOP_DIR/xvas + +# Create xva dir +mkdir -p $XVA_DIR + +# Clean nova if desired +if [ "$CLEAN" = "1" ]; then + rm -rf $TOP_DIR/nova +fi + +# Checkout nova +if [ ! -d $TOP_DIR/nova ]; then + git clone git://github.com/cloudbuilders/nova.git + git checkout diablo +fi + +# Run devstack on launch +cat <$STAGING_DIR/etc/rc.local +STAGING_DIR=/ DO_TGZ=0 bash /opt/stack/devstack/tools/xen/prepare_guest.sh +STAGING_DIR=/ DO_TGZ=0 bash /opt/stack/devstack/tools/xen/prepare_guest.sh +su -c "/opt/stack/run.sh > /opt/stack/run.sh.log" stack +exit 0 +EOF + +# Install plugins +cp -pr $TOP_DIR/nova/plugins/xenserver/xenapi/etc/xapi.d /etc/ +chmod a+x /etc/xapi.d/plugins/* +yum --enablerepo=base install -y parted +mkdir -p /boot/guest + +# Set local storage il8n +SR_UUID=`xe sr-list --minimal name-label="Local storage"` +xe sr-param-set uuid=$SR_UUID other-config:i18n-key=local-storage + +# Uninstall previous runs +xe vm-list --minimal name-label="$LABEL" | xargs ./scripts/uninstall-os-vpx.sh + +# Destroy any instances that were launched +for uuid in `xe vm-list | grep -1 instance | grep uuid | sed "s/.*\: //g"`; do + echo "Shutting down nova instance $uuid" + xe vm-shutdown uuid=$uuid + xe vm-destroy uuid=$uuid +done + +# Path to head xva. By default keep overwriting the same one to save space +USE_SEPARATE_XVAS=${USE_SEPARATE_XVAS:-0} +if [ "$USE_SEPARATE_XVAS" = "0" ]; then + XVA=$XVA_DIR/$UBUNTU_VERSION.xva +else + XVA=$XVA_DIR/$UBUNTU_VERSION.$GUEST_NAME.xva +fi + +# Clean old xva. In the future may not do this every time. +rm -f $XVA + +# Configure the network +set_hostname $GUEST_NAME +INTERFACES=$STAGING_DIR/etc/network/interfaces +cp templates/interfaces.in $INTERFACES +sed -e "s,@ETH1_NETMASK@,$VM_NETMASK,g" -i $INTERFACES +sed -e "s,@ETH2_IP@,$MGT_IP,g" -i $INTERFACES +sed -e "s,@ETH2_NETMASK@,$MGT_NETMASK,g" -i $INTERFACES +sed -e "s,@ETH3_IP@,$PUB_IP,g" -i $INTERFACES +sed -e "s,@ETH3_NETMASK@,$PUB_NETMASK,g" -i $INTERFACES + +# Configure run.sh +cat <$STAGING_DIR/opt/stack/run.sh +#!/bin/bash +cd /opt/stack/devstack +killall screen +UPLOAD_LEGACY_TTY=yes HOST_IP=$PUB_IP VIRT_DRIVER=xenserver FORCE=yes MULTI_HOST=1 $STACKSH_PARAMS ./stack.sh +EOF +chmod 755 $STAGING_DIR/opt/stack/run.sh + +# Create xva +if [ ! -e $XVA ]; then + rm -rf /tmp/mkxva* + UID=0 $SCRIPT_DIR/mkxva -o $XVA -t xva -x $OVA $STAGING_DIR $VDI_MB /tmp/ +fi + +# Start guest +$TOP_DIR/scripts/install-os-vpx.sh -f $XVA -v $VM_BR -m $MGT_BR -p $PUB_BR diff --git a/tools/xen/files/fstab b/tools/xen/files/fstab new file mode 100644 index 0000000000..6c9b9818c3 --- /dev/null +++ b/tools/xen/files/fstab @@ -0,0 +1,5 @@ +LABEL=vpxroot / ext3 defaults 1 1 +tmpfs /dev/shm tmpfs defaults 0 0 +devpts /dev/pts devpts gid=5,mode=620 0 0 +sysfs /sys sysfs defaults 0 0 +proc /proc proc defaults 0 0 diff --git a/tools/xen/files/hvc0.conf b/tools/xen/files/hvc0.conf new file mode 100644 index 0000000000..4eedaf6ee1 --- /dev/null +++ b/tools/xen/files/hvc0.conf @@ -0,0 +1,10 @@ +# hvc0 - getty +# +# This service maintains a getty on hvc0 from the point the system is +# started until it is shut down again. + +start on stopped rc RUNLEVEL=[2345] +stop on runlevel [!2345] + +respawn +exec /sbin/getty -8 9600 hvc0 diff --git a/tools/xen/prepare_dom0.sh b/tools/xen/prepare_dom0.sh new file mode 100755 index 0000000000..ce16ada43e --- /dev/null +++ b/tools/xen/prepare_dom0.sh @@ -0,0 +1,41 @@ +#!/bin/sh +set -o xtrace +set -o errexit + +# Install basics for vi and git +yum -y --enablerepo=base install gcc make vim-enhanced zlib-devel openssl-devel + +# Simple but usable vimrc +if [ ! -e /root/.vimrc ]; then + cat > /root/.vimrc <$STAGING_DIR/etc/apt/sources.list +deb http://us.archive.ubuntu.com/ubuntu/ oneiric main restricted +deb-src http://us.archive.ubuntu.com/ubuntu/ oneiric main restricted +deb http://us.archive.ubuntu.com/ubuntu/ oneiric-updates main restricted +deb-src http://us.archive.ubuntu.com/ubuntu/ oneiric-updates main restricted +deb http://us.archive.ubuntu.com/ubuntu/ oneiric universe +deb http://us.archive.ubuntu.com/ubuntu/ oneiric-updates universe +deb http://us.archive.ubuntu.com/ubuntu/ oneiric multiverse +deb http://us.archive.ubuntu.com/ubuntu/ oneiric-updates multiverse +EOF + +# Install basics +chroot $STAGING_DIR apt-get update +chroot $STAGING_DIR apt-get install -y linux-image-$KERNEL_VERSION +chroot $STAGING_DIR apt-get install -y cracklib-runtime curl wget ssh openssh-server tcpdump ethtool +chroot $STAGING_DIR apt-get install -y curl wget ssh openssh-server python-pip git vim-nox sudo +chroot $STAGING_DIR pip install xenapi + +# Install guest utilities +XEGUEST=xe-guest-utilities_5.6.100-651_amd64.deb +wget http://images.ansolabs.com/xen/$XEGUEST -O $XEGUEST +cp $XEGUEST $STAGING_DIR/root +chroot $STAGING_DIR dpkg -i /root/$XEGUEST +chroot $STAGING_DIR update-rc.d -f xe-linux-distribution remove +chroot $STAGING_DIR update-rc.d xe-linux-distribution defaults + +# Make a small cracklib dictionary, so that passwd still works, but we don't +# have the big dictionary. +mkdir -p $STAGING_DIR/usr/share/cracklib +echo a | chroot $STAGING_DIR cracklib-packer + +# Make /etc/shadow, and set the root password +chroot $STAGING_DIR "pwconv" +echo "root:$PASSWORD" | chroot $STAGING_DIR chpasswd + +# Put the VPX into UTC. +rm -f $STAGING_DIR/etc/localtime + +# Add stack user +chroot $STAGING_DIR groupadd libvirtd +chroot $STAGING_DIR useradd stack -s /bin/bash -d /opt/stack -G libvirtd +echo stack:$PASSWORD | chroot $STAGING_DIR chpasswd +echo "stack ALL=(ALL) NOPASSWD: ALL" >> $STAGING_DIR/etc/sudoers + +# Give ownership of /opt/stack to stack user +chroot $STAGING_DIR chown -R stack /opt/stack + +# Make our ip address hostnames look nice at the command prompt +echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $STAGING_DIR/opt/stack/.bashrc +echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $STAGING_DIR/root/.bashrc +echo "export PS1='${debian_chroot:+($debian_chroot)}\\u@\\H:\\w\\$ '" >> $STAGING_DIR/etc/profile + +function setup_vimrc { + if [ ! -e $1 ]; then + # Simple but usable vimrc + cat > $1 <&2 + exit 1 + else + echo "$dest_sr" + fi +} + + +find_network() +{ + result=$(xe_min network-list bridge="$1") + if [ "$result" = "" ] + then + result=$(xe_min network-list name-label="$1") + fi + echo "$result" +} + + +find_template() +{ + xe_min template-list other-config:os-vpx=true +} + + +renumber_system_disk() +{ + local v="$1" + local vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk userdevice=xvda \ + params=vdi-uuid) + if [ "$vdi_uuid" ] + then + local vbd_uuid=$(xe_min vbd-list vm-uuid="$v" vdi-uuid="$vdi_uuid") + xe vbd-destroy uuid="$vbd_uuid" + local new_vbd_uuid=$(xe vbd-create vm-uuid="$v" vdi-uuid="$vdi_uuid" \ + device=0 bootable=true type=Disk) + xe vbd-param-set other-config:owner uuid="$new_vbd_uuid" + fi +} + + +create_vif() +{ + xe vif-create vm-uuid="$1" network-uuid="$2" device="$3" +} + +create_gi_vif() +{ + local v="$1" + # Note that we've made the outbound device eth1, so that it comes up after + # the guest installer VIF, which means that the outbound one wins in terms + # of gateway. + local gi_network_uuid=$(xe_min network-list \ + other-config:is_guest_installer_network=true) + create_vif "$v" "$gi_network_uuid" "0" >/dev/null +} + +create_vm_vif() +{ + local v="$1" + echo "Installing management interface on $BRIDGE_V." + local out_network_uuid=$(find_network "$BRIDGE_V") + create_vif "$v" "$out_network_uuid" "1" >/dev/null +} + +create_management_vif() +{ + local v="$1" + echo "Installing management interface on $BRIDGE_M." + local out_network_uuid=$(find_network "$BRIDGE_M") + create_vif "$v" "$out_network_uuid" "2" >/dev/null +} + + +# This installs the interface for public traffic, only if a bridge is specified +# The interface is not configured at this stage, but it will be, once the admin +# tasks are complete for the services of this VPX +create_public_vif() +{ + local v="$1" + if [[ -z $BRIDGE_P ]] + then + echo "Skipping installation of interface for public traffic." + else + echo "Installing public interface on $BRIDGE_P." + pub_network_uuid=$(find_network "$BRIDGE_P") + create_vif "$v" "$pub_network_uuid" "3" >/dev/null + fi +} + + +label_system_disk() +{ + local v="$1" + local vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk userdevice=0 \ + params=vdi-uuid) + xe vdi-param-set \ + name-label="$NAME system disk" \ + other-config:os-vpx=true \ + uuid=$vdi_uuid +} + + +create_data_disk() +{ + local v="$1" + + local sys_vdi_uuid=$(xe_min vbd-list vm-uuid="$v" type=Disk params=vdi-uuid) + local data_vdi_uuid=$(xe_min vdi-list other-config:os-vpx-data=true) + + if echo "$data_vdi_uuid" | grep -q , + then + echo "Multiple data disks found -- assuming that you want a new one." + data_vdi_uuid="" + else + data_in_use=$(xe_min vbd-list vdi-uuid="$data_vdi_uuid") + if [ "$data_in_use" != "" ] + then + echo "Data disk already in use -- will create another one." + data_vdi_uuid="" + fi + fi + + if [ "$data_vdi_uuid" = "" ] + then + echo -n "Creating new data disk ($DATA_VDI_SIZE)... " + sr_uuid=$(xe_min vdi-list params=sr-uuid uuid="$sys_vdi_uuid") + data_vdi_uuid=$(xe vdi-create name-label="$NAME data disk" \ + sr-uuid="$sr_uuid" \ + type=user \ + virtual-size="$DATA_VDI_SIZE") + xe vdi-param-set \ + other-config:os-vpx-data=true \ + uuid="$data_vdi_uuid" + dom0_uuid=$(xe_min vm-list is-control-domain=true) + vbd_uuid=$(xe vbd-create device=autodetect type=Disk \ + vdi-uuid="$data_vdi_uuid" vm-uuid="$dom0_uuid") + xe vbd-plug uuid=$vbd_uuid + dev=$(xe_min vbd-list params=device uuid=$vbd_uuid) + mke2fs -q -j -m0 /dev/$dev + e2label /dev/$dev vpxstate + xe vbd-unplug uuid=$vbd_uuid + xe vbd-destroy uuid=$vbd_uuid + else + echo -n "Attaching old data disk... " + fi + vbd_uuid=$(xe vbd-create device=2 type=Disk \ + vdi-uuid="$data_vdi_uuid" vm-uuid="$v") + xe vbd-param-set other-config:os-vpx-data=true uuid=$vbd_uuid + echo "done." +} + + +set_kernel_params() +{ + local v="$1" + local args=$KERNEL_PARAMS + local cmdline=$(cat /proc/cmdline) + for word in $cmdline + do + if echo "$word" | grep -q "geppetto" + then + args="$word $args" + fi + done + if [ "$args" != "" ] + then + echo "Passing Geppetto args to VPX: $args." + xe vm-param-set PV-args="$args" uuid="$v" + fi +} + + +set_memory() +{ + local v="$1" + if [ "$RAM" != "" ] + then + echo "Setting RAM to $RAM MiB." + [ "$BALLOONING" == 1 ] && RAM_MIN=$(($RAM / 2)) || RAM_MIN=$RAM + xe vm-memory-limits-set static-min=16MiB static-max=${RAM}MiB \ + dynamic-min=${RAM_MIN}MiB dynamic-max=${RAM}MiB \ + uuid="$v" + fi +} + + +# Make the VM auto-start on server boot. +set_auto_start() +{ + local v="$1" + xe vm-param-set uuid="$v" other-config:auto_poweron=true +} + + +set_all() +{ + local v="$1" + set_kernel_params "$v" + set_memory "$v" + set_auto_start "$v" + label_system_disk "$v" + create_gi_vif "$v" + create_vm_vif "$v" + create_management_vif "$v" + create_public_vif "$v" +} + + +log_vifs() +{ + local v="$1" + + (IFS=, + for vif in $(xe_min vif-list vm-uuid="$v") + do + dev=$(xe_min vif-list uuid="$vif" params=device) + mac=$(xe_min vif-list uuid="$vif" params=MAC | sed -e 's/:/-/g') + echo "eth$dev has MAC $mac." + done + unset IFS) | sort +} + + +destroy_vifs() +{ + local v="$1" + IFS=, + for vif in $(xe_min vif-list vm-uuid="$v") + do + xe vif-destroy uuid="$vif" + done + unset IFS +} + + +get_params "$@" + +thisdir=$(dirname "$0") + +if [ "$FROM_TEMPLATE" ] +then + template_uuid=$(find_template) + name=$(xe_min template-list params=name-label uuid="$template_uuid") + echo -n "Cloning $name... " + vm_uuid=$(xe vm-clone vm="$template_uuid" new-name-label="$name") + xe vm-param-set is-a-template=false uuid="$vm_uuid" + echo $vm_uuid. + + destroy_vifs "$vm_uuid" + set_all "$vm_uuid" +else + if [ ! -f "$VPX_FILE" ] + then + # Search $thisdir/$VPX_FILE too. In particular, this is used when + # installing the VPX from the supp-pack, because we want to be able to + # invoke this script from the RPM and the firstboot script. + if [ -f "$thisdir/$VPX_FILE" ] + then + VPX_FILE="$thisdir/$VPX_FILE" + else + echo "$VPX_FILE does not exist." >&2 + exit 1 + fi + fi + + echo "Found OS-VPX File: $VPX_FILE. " + + dest_sr=$(get_dest_sr) + + echo -n "Installing $NAME... " + vm_uuid=$(xe vm-import filename=$VPX_FILE sr-uuid="$dest_sr") + echo $vm_uuid. + + renumber_system_disk "$vm_uuid" + + nl=$(xe_min vm-list params=name-label uuid=$vm_uuid) + xe vm-param-set \ + "name-label=${nl/ import/}" \ + other-config:os-vpx=true \ + uuid=$vm_uuid + + set_all "$vm_uuid" + create_data_disk "$vm_uuid" + + if [ "$AS_TEMPLATE" ] + then + xe vm-param-set uuid="$vm_uuid" is-a-template=true \ + other-config:instant=true + echo -n "Installing VPX from template... " + vm_uuid=$(xe vm-clone vm="$vm_uuid" new-name-label="${nl/ import/}") + xe vm-param-set is-a-template=false uuid="$vm_uuid" + echo "$vm_uuid." + fi +fi + + +log_vifs "$vm_uuid" + +echo -n "Starting VM... " +xe vm-start uuid=$vm_uuid +echo "done." + + +show_ip() +{ + ip_addr=$(echo "$1" | sed -n "s,^.*"$2"/ip: \([^;]*\).*$,\1,p") + echo -n "IP address for $3: " + if [ "$ip_addr" = "" ] + then + echo "did not appear." + else + echo "$ip_addr." + fi +} + + +if [ "$WAIT_FOR_NETWORK" ] +then + echo "Waiting for network configuration... " + i=0 + while [ $i -lt 600 ] + do + ip=$(xe_min vm-list params=networks uuid=$vm_uuid) + if [ "$ip" != "" ] + then + show_ip "$ip" "1" "$BRIDGE_M" + if [[ $BRIDGE_P ]] + then + show_ip "$ip" "2" "$BRIDGE_P" + fi + echo "Installation complete." + exit 0 + fi + sleep 10 + let i=i+1 + done +fi diff --git a/tools/xen/scripts/mkxva b/tools/xen/scripts/mkxva new file mode 100755 index 0000000000..a59545302a --- /dev/null +++ b/tools/xen/scripts/mkxva @@ -0,0 +1,366 @@ +#!/bin/bash +# +# Copyright (c) 2011 Citrix Systems, Inc. +# Copyright 2011 OpenStack LLC. +# Copyright (C) 2011 Nicira, Inc +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +set -eu + +set -o xtrace + +VBOX_IMG=/output/packages/vbox-img + +usage() { + cat >&2 < -t -x + -o: Colon-separated list of output filenames (one for each type). + -p: Create a disk label and partition within the output image + -t: Colon-separated list of types of output file. xva and ovf supported. + -x: XML filenames (one for each type) + +EOF + exit 1 +} + +# parse cmdline + +OPT_USE_PARTITION= +OPT_TYPES= +OPT_OUTPUT_FILES= +OPT_XML_FILES= + +while getopts o:pt:x: o +do case "$o" in + o) OPT_OUTPUT_FILES=$(echo "$OPTARG" | sed -e 's/\s*:\s*/ /g') + ;; + p) OPT_USE_PARTITION=1 + ;; + t) OPT_TYPES=$(echo "$OPTARG" | sed -e 's/\s*:\s*/ /g') + ;; + x) OPT_XML_FILES=$(echo "$OPTARG" | sed -e 's/\s*:\s*/ /g') + ;; + [?]) usage + ;; + esac +done +shift $((OPTIND-1)) + +[ $# -ne 3 ] && usage +FS_STAGING="$1" +FS_SIZE_MIB="$2" +TMPDIR="$3" + +if [ "$UID" = "0" ] +then + SUDO= +else + SUDO=sudo +fi + +if [ "$FS_SIZE_MIB" = "0" ] +then + # Just create a dummy file. This allows developers to bypass bits of + # the build by setting the size to 0. + touch $OPT_OUTPUT_FILES + exit 0 +fi + +# create temporary files and dirs +FS_TMPFILE=$(mktemp "$TMPDIR/mkxva-fsimg-XXXXX") +XVA_TARBALL_STAGING=$(mktemp -d "$TMPDIR/mkxva-tarball-staging-XXXXX") +OVF_STAGING=$(mktemp -d "$TMPDIR/mkxva-ovf-staging-XXXXX") + +# Find udevsettle and udevtrigger on this installation +if [ -x "/sbin/udevsettle" ] ; then + UDEVSETTLE="/sbin/udevsettle --timeout=30" +elif [ -x "/sbin/udevadm" ] ; then + UDEVSETTLE='/sbin/udevadm settle' +else + UDEVSETTLE='/bin/true' +fi + +if [ -x "/sbin/udevtrigger" ] ; then + UDEVTRIGGER=/sbin/udevtrigger +elif [ -x "/sbin/udevadm" ] ; then + UDEVTRIGGER='/sbin/udevadm trigger' +else + UDEVTRIGGER= +fi + +# CLEAN_ variables track devices and mounts that must be taken down +# no matter how the script exits. Loop devices are vulnerable to +# exhaustion so we make every effort to remove them + +CLEAN_KPARTX= +CLEAN_LOSETUP= +CLEAN_MOUNTPOINT= + +cleanup_devices () { + if [ -n "$CLEAN_MOUNTPOINT" ] ; then + echo "Mountpoint $CLEAN_MOUNTPOINT removed on abnormal exit" + $SUDO umount "$CLEAN_MOUNTPOINT" || echo "umount failed" + rmdir "$CLEAN_MOUNTPOINT" || echo "rmdir failed" + fi + if [ -n "$CLEAN_KPARTX" ] ; then + echo "kpartx devices for $CLEAN_KPARTX removed on abnormal exit" + $SUDO kpartx -d "$CLEAN_KPARTX" || echo "kpartx -d failed" + fi + if [ -n "$CLEAN_LOSETUP" ] ; then + echo "Loop device $CLEAN_LOSETUP removed on abnormal exit" + $SUDO losetup -d "$CLEAN_LOSETUP" # Allow losetup errors to propagate + fi +} + +trap "cleanup_devices" EXIT + +make_fs_inner () { + local staging="$1" + local output="$2" + local options="$3" + CLEAN_MOUNTPOINT=$(mktemp -d "$TMPDIR/mkfs-XXXXXX") + + # copy staging dir contents to fs image + $SUDO mount $options "$output" "$CLEAN_MOUNTPOINT" + $SUDO tar -C "$staging" -c . | tar -C "$CLEAN_MOUNTPOINT" -x + $SUDO umount "$CLEAN_MOUNTPOINT" + rmdir "$CLEAN_MOUNTPOINT" + CLEAN_MOUNTPOINT= +} + +# Turn a staging dir into an ext3 filesystem within a partition +make_fs_in_partition () { + local staging="$1" + local output="$2" + + # create new empty disk + dd if=/dev/zero of="$output" bs=1M count=$FS_SIZE_MIB + # Set up a loop device on the empty disk image + local loopdevice=$($SUDO losetup -f) + $SUDO losetup "$loopdevice" "$output" + CLEAN_LOSETUP="$loopdevice" + # Create a partition table and single partition. + # Start partition at sector 63 to allow space for grub + cat < "$CLEAN_MOUNTPOINT/boot/grub/grub.conf" </dev/null + gzip "$file" + else + local file="$outputdir"/$(printf "%08d" $i) + dd if="$diskimg" of="$file" skip=$i bs=1M count=1 2>/dev/null + local chksum=$(sha1sum -b "$file") + echo -n "${chksum/ */}" > "$file.checksum" + fi + i=$(($i + 1)) + done +} + +if [ -n "$OPT_USE_PARTITION" ] ; then + make_fs_in_partition "$FS_STAGING" "$FS_TMPFILE" +else + make_fs "$FS_STAGING" "$FS_TMPFILE" +fi + +VDI_SIZE=$(stat --format=%s "$FS_TMPFILE") + +make_xva () { + local output_file="$1" + local xml_file="$2" + local subdir + local rio + + if [[ `cat $xml_file` =~ "\s*class\s*VDI\s*\s*\s*id\s*(Ref:[0-9]+)" ]] + then + # it's a rio style xva + subdir="${BASH_REMATCH[1]}"; + rio=1 + else + # it's a geneva style xva + subdir="xvda" + rio=0 + fi + + cp "$xml_file" "$XVA_TARBALL_STAGING"/ova.xml + sed -i -e "s/@VDI_SIZE@/$VDI_SIZE/" "$XVA_TARBALL_STAGING"/ova.xml + mkdir "$XVA_TARBALL_STAGING/$subdir" + splitvdi "$FS_TMPFILE" "$XVA_TARBALL_STAGING/$subdir" "$rio" + TARFILE_MEMBERS=$(cd "$XVA_TARBALL_STAGING" && echo ova.xml $subdir/*) + tar -C "$XVA_TARBALL_STAGING" --format=v7 -c $TARFILE_MEMBERS -f "$output_file.tmp" + mv "$output_file.tmp" "$output_file" +} + +make_ovf () { + local output_dir="$1" + local xml_file="$2" + local output_base=$(basename "$output_dir") + local disk="$output_dir/${output_base}.vmdk" + local manifest="$output_dir/${output_base}.mf" + local ovf="$output_dir/${output_base}.ovf" + + mkdir -p "$output_dir" + rm -f "$disk" + $VBOX_IMG convert --srcfilename="$FS_TMPFILE" --dstfilename="$disk" \ + --srcformat RAW --dstformat VMDK --variant Stream + chmod 0644 "$disk" + + local n_bytes=$(stat --printf=%s "$disk") + cp "$xml_file" "$ovf" + sed -i -e "s/@MKXVA_DISK_FULLSIZE@/$VDI_SIZE/" "$ovf" + sed -i -e "s/@MKXVA_DISK_SIZE@/$n_bytes/" "$ovf" + sed -i -e "s/@MKXVA_DISK_MIB_SIZE@/$FS_SIZE_MIB/" "$ovf" + sed -i -e "s/@MKXVA_DISK_FILENAME@/${output_base}.vmdk/" "$ovf" + + for to_sign in "$ovf" "$disk" + do + local sha1_sum=$(sha1sum "$to_sign" | cut -d' ' -f1) + echo "SHA1($(basename "$to_sign"))= $sha1_sum" >> $manifest + done +} + +output_files="$OPT_OUTPUT_FILES" +xml_files="$OPT_XML_FILES" +# Iterate through the type list creating the relevant VMs +for create_type in $OPT_TYPES +do + # Shift one parameter from the front of the lists + create_output_file="${output_files%% *}" + output_files="${output_files#* }" + create_xml_file="${xml_files%% *}" + xml_files="${xml_files#* }" + echo "Creating $create_type appliance $create_output_file using metadata file $create_xml_file" + + case "$create_type" in + xva) + make_xva "$create_output_file" "$create_xml_file" + ;; + ovf) + make_ovf "$create_output_file" "$create_xml_file" + ;; + *) + echo "Unknown VM type '$create_type'" + exit 1 + ;; + esac + +done + + +# cleanup +if [ -z "${DO_NOT_CLEANUP:-}" ] ; then + rm -rf "$XVA_TARBALL_STAGING" + rm -f "$FS_TMPFILE" +fi diff --git a/tools/xen/scripts/uninstall-os-vpx.sh b/tools/xen/scripts/uninstall-os-vpx.sh new file mode 100755 index 0000000000..7c1cd41e1d --- /dev/null +++ b/tools/xen/scripts/uninstall-os-vpx.sh @@ -0,0 +1,102 @@ +#!/bin/bash +# +# Copyright (c) 2011 Citrix Systems, Inc. +# Copyright 2011 OpenStack LLC. +# Copyright (C) 2011 Nicira, Inc +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +remove_data= +if [ "$1" = "--remove-data" ] +then + remove_data=1 +fi + +set -eu + +xe_min() +{ + local cmd="$1" + shift + /opt/xensource/bin/xe "$cmd" --minimal "$@" +} + +destroy_vdi() +{ + local vbd_uuid="$1" + local type=$(xe_min vbd-list uuid=$vbd_uuid params=type) + local dev=$(xe_min vbd-list uuid=$vbd_uuid params=userdevice) + local vdi_uuid=$(xe_min vbd-list uuid=$vbd_uuid params=vdi-uuid) + + if [ "$type" = 'Disk' ] && [ "$dev" != 'xvda' ] && [ "$dev" != '0' ] + then + echo -n "Destroying data disk... " + xe vdi-destroy uuid=$vdi_uuid + echo "done." + fi +} + +uninstall() +{ + local vm_uuid="$1" + local power_state=$(xe_min vm-list uuid=$vm_uuid params=power-state) + + if [ "$power_state" != "halted" ] + then + echo -n "Shutting down VM... " + xe vm-shutdown vm=$vm_uuid force=true + echo "done." + fi + + if [ "$remove_data" = "1" ] + then + for v in $(xe_min vbd-list vm-uuid=$vm_uuid | sed -e 's/,/ /g') + do + destroy_vdi "$v" + done + fi + + echo -n "Deleting VM... " + xe vm-uninstall vm=$vm_uuid force=true >/dev/null + echo "done." +} + +uninstall_template() +{ + local vm_uuid="$1" + + if [ "$remove_data" = "1" ] + then + for v in $(xe_min vbd-list vm-uuid=$vm_uuid | sed -e 's/,/ /g') + do + destroy_vdi "$v" + done + fi + + echo -n "Deleting template... " + xe template-uninstall template-uuid=$vm_uuid force=true >/dev/null + echo "done." +} + + +for u in $(xe_min vm-list other-config:os-vpx=true | sed -e 's/,/ /g') +do + uninstall "$u" +done + +for u in $(xe_min template-list other-config:os-vpx=true | sed -e 's/,/ /g') +do + uninstall_template "$u" +done diff --git a/tools/xen/templates/hosts.in b/tools/xen/templates/hosts.in new file mode 100644 index 0000000000..8ab4c3e919 --- /dev/null +++ b/tools/xen/templates/hosts.in @@ -0,0 +1,8 @@ +127.0.0.1 localhost +127.0.0.1 %HOSTNAME% +::1 localhost ip6-localhost ip6-loopback +fe00::0 ip6-localnet +ff00::0 ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters + diff --git a/tools/xen/templates/interfaces.in b/tools/xen/templates/interfaces.in new file mode 100644 index 0000000000..ef4796fb05 --- /dev/null +++ b/tools/xen/templates/interfaces.in @@ -0,0 +1,21 @@ +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp + +auto eth1 +iface eth1 inet static + netmask @ETH1_NETMASK@ +post-up ethtool -K eth1 tx off +post-up ifconfig eth1 up + +auto eth2 +iface eth2 inet static + address @ETH2_IP@ + netmask @ETH2_NETMASK@ + +auto eth3 +iface eth3 inet static + address @ETH3_IP@ + netmask @ETH3_NETMASK@ diff --git a/tools/xen/templates/menu.lst.in b/tools/xen/templates/menu.lst.in new file mode 100644 index 0000000000..8bc6426251 --- /dev/null +++ b/tools/xen/templates/menu.lst.in @@ -0,0 +1,6 @@ +default 0 + +title default + root (hd0,0) + kernel /boot/vmlinuz-@KERNEL_VERSION@ ro root=LABEL=vpxroot console=xvc0 + initrd /boot/initrd.img-@KERNEL_VERSION@ diff --git a/tools/xen/templates/ova.xml.in b/tools/xen/templates/ova.xml.in new file mode 100644 index 0000000000..8443dcb856 --- /dev/null +++ b/tools/xen/templates/ova.xml.in @@ -0,0 +1,14 @@ + + + + + + + + + + + +