diff --git a/scripts/vm/hypervisor/xenserver/check_heartbeat.sh b/scripts/vm/hypervisor/xenserver/check_heartbeat.sh new file mode 100755 index 00000000000..2f5b40022c3 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/check_heartbeat.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [uuid of this host] [interval in seconds]\n" $(basename $0) >&2 + +} + +if [ -z $1 ]; then + usage + exit 2 +fi + +if [ -z $2 ]; then + usage + exit 3 +fi + + +date=`date +%s` +hbs=`lvscan | grep hb-$1 | awk '{print $2}'` +for hb in $hbs +do + hb=${hb:1:`expr ${#hb} - 2`} + active=`lvscan | grep $hb | awk '{print $1}'` + if [ "$active" == "inactive" ]; then + lvchange -ay $hb + if [ ! -L $hb ]; then + continue; + fi + fi + ping=`dd if=$hb bs=1 count=100` + if [ $? -ne 0 ]; then + continue; + fi + diff=`expr $date - $ping` + if [ $diff -lt $2 ]; then + echo "=====> ALIVE <=====" + exit 0; + fi +done + +hbs=`ls -l /var/run/sr-mount/*/hb-$1 | awk '{print $9}'` +for hb in $hbs +do + ping=`cat $hb` + if [ $? -ne 0 ]; then + continue; + fi + diff=`expr $date - $ping` + if [ $diff -lt $2 ]; then + echo "=====> ALIVE <=====" + exit 0; + fi +done + +echo "=====> DEAD <======" diff --git a/scripts/vm/hypervisor/xenserver/copy_vhd_from_secondarystorage.sh b/scripts/vm/hypervisor/xenserver/copy_vhd_from_secondarystorage.sh new file mode 100755 index 00000000000..5760d5dffe3 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/copy_vhd_from_secondarystorage.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [mountpoint in secondary storage] [uuid of the source sr]\n" $(basename $0) +} + +cleanup() +{ + if [ ! -z $localmp ]; then + umount $localmp + if [ $? -eq 0 ]; then + rm $localmp -rf + fi + fi +} + +if [ -z $1 ]; then + usage + echo "2#no mountpoint" + exit 0 +else + mountpoint=$1 +fi + +if [ -z $2 ]; then + usage + echo "3#no uuid of the source sr" + exit 0 +else + sruuid=$2 +fi + +type=$(xe sr-param-get uuid=$sruuid param-name=type) +if [ $? -ne 0 ]; then + echo "4#sr $sruuid doesn't exist" + exit 0 +fi + +localmp=/var/run/cloud_mount/$(uuidgen -r) + +mkdir -p $localmp +if [ $? -ne 0 ]; then + echo "5#cann't make dir $localmp" + exit 0 +fi + +mount $mountpoint $localmp +if [ $? -ne 0 ]; then + echo "6#cann't mounbt $mountpoint to $localmp" + exit 0 +fi + +vhdfile=$(ls $localmp/*.vhd) +if [ $? -ne 0 ]; then + echo "7#There is no vhd file under $mountpoint" + cleanup + exit 0 +fi + +if [ $type == "nfs" ]; then + uuid=$(uuidgen -r) + dd if=$vhdfile of=/var/run/sr-mount/$sruuid/$uuid bs=2M + if [ $? -ne 0 ]; then + echo "8#failed ot copy vhdfile to /var/run/sr-mount/sruuid/$uuid" + cleanup + exit 0 + fi + mv /var/run/sr-mount/$sruuid/$uuid /var/run/sr-mount/$sruuid/${uuid}.vhd + xe sr-scan uuid=$sruuid +elif [ $type == "lvmoiscsi" -o $type == "lvm" ]; then + size=$(vhd-util query -v -n $vhdfile) + uuid=$(xe vdi-create sr-uuid=$sruuid virtual-size=${size}MiB type=user name-label="cloud") + if [ $? -ne 0 ]; then + echo "9#can not create vdi in sr $sruuid" + cleanup + exit 0 + fi + lvchange -ay /dev/VG_XenStorage-$sruuid/VHD-$uuid + if [ $? -ne 0 ]; then + echo "10#lvm can not make VDI $uuid visiable" + cleanup + exit 0 + fi + dd if=$vhdfile of=/dev/VG_XenStorage-$sruuid/VHD-$uuid bs=2M + if [ $? -ne 0 ]; then + echo "11#failed to dd to sr $sruuid" + cleanup + exit 0 + fi + lvsize=$(xe vdi-param-get uuid=$uuid param-name=physical-utilisation) + if [ $? -ne 0 ]; then + echo "12#failed to get physical size of vdi $uuid" + cleanup + exit 0 + fi + vhd-util modify -s $lvsize -n /dev/VG_XenStorage-$sruuid/VHD-$uuid + if [ $? -ne 0 ]; then + echo "13#failed to set new vhd physical size for vdi vdi $uuid" + cleanup + exit 0 + fi + xe sr-scan uuid=$sruuid + if [ $? -ne 0 ]; then + echo "14#failed to scan sr $sruuid" + cleanup + exit 0 + fi +else + echo "15#doesn't support sr type $type" + cleanup + exit 0 +fi + +echo "0#$uuid" +cleanup +exit 0 diff --git a/scripts/vm/hypervisor/xenserver/copy_vhd_to_secondarystorage.sh b/scripts/vm/hypervisor/xenserver/copy_vhd_to_secondarystorage.sh new file mode 100755 index 00000000000..65800dbe994 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/copy_vhd_to_secondarystorage.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [mountpoint in secondary storage] [uuid of the source vdi] [uuid of the source sr]\n" $(basename $0) +} + +cleanup() +{ + if [ ! -z $localmp ]; then + umount $localmp + if [ $? -eq 0 ]; then + rm $localmp -rf + fi + fi +} + +if [ -z $1 ]; then + usage + echo "1#no mountpoint" + exit 0 +else + mountpoint=$1 +fi + +if [ -z $2 ]; then + usage + echo "2#no uuid of the source sr" + exit 0 +else + vdiuuid=$2 +fi + + +if [ -z $3 ]; then + usage + echo "3#no uuid of the source sr" + exit 0 +else + sruuid=$3 +fi + +type=$(xe sr-param-get uuid=$sruuid param-name=type) +if [ $? -ne 0 ]; then + echo "4#sr $sruuid doesn't exist" + exit 0 +fi + +localmp=/var/run/cloud_mount/$(uuidgen -r) + +mkdir -p $localmp +if [ $? -ne 0 ]; then + echo "5#cann't make dir $localmp" + exit 0 +fi + +mount $mountpoint $localmp +if [ $? -ne 0 ]; then + echo "6#cann't mounbt $mountpoint to $localmp" + exit 0 +fi + +vhdfile=$localmp/${vdiuuid}.vhd + +if [ $type == "nfs" ]; then + dd if=/var/run/sr-mount/$sruuid/${vdiuuid}.vhd of=$vhdfile bs=2M + if [ $? -ne 0 ]; then + echo "8#failed to copy /var/run/sr-mount/$sruuid/${vdiuuid}.vhd to secondarystorage" + cleanup + exit 0 + fi +elif [ $type == "lvmoiscsi" -o $type == "lvm" ]; then + lvchange -ay /dev/VG_XenStorage-$sruuid/VHD-$vdiuuid + if [ $? -ne 0 ]; then + echo "9#lvm can not make VDI $vdiuuid visiable" + cleanup + exit 0 + fi + size=$(vhd-util query -s -n /dev/VG_XenStorage-$sruuid/VHD-$vdiuuid) + if [ $? -ne 0 ]; then + echo "10#can not get physical size of /dev/VG_XenStorage-$sruuid/VHD-$vdiuuid" + cleanup + exit 0 + fi +#in 2M unit + size=$((size>>21)) + size=$((size+1)) + dd if=/dev/VG_XenStorage-$sruuid/VHD-$vdiuuid of=$vhdfile bs=2M count=$size +#in byte unit + size=$((size<<21)) + vhd-util modify -s $size -n $vhdfile + if [ $? -ne 0 ]; then + echo "11#failed to change $vhdfile physical size" + cleanup + exit 0 + fi +else + echo "15#doesn't support sr type $type" + cleanup + exit 0 +fi + +echo "0#$vdiuuid" +cleanup +exit 0 diff --git a/scripts/vm/hypervisor/xenserver/fsimage.so b/scripts/vm/hypervisor/xenserver/fsimage.so new file mode 100755 index 00000000000..05e0d041d91 Binary files /dev/null and b/scripts/vm/hypervisor/xenserver/fsimage.so differ diff --git a/scripts/vm/hypervisor/xenserver/launch_hb.sh b/scripts/vm/hypervisor/xenserver/launch_hb.sh new file mode 100755 index 00000000000..b2b4b994528 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/launch_hb.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [uuid of this host] [interval in seconds]\n" $(basename $0) + +} + +if [ -z $1 ]; then + usage + exit 2 +fi + +if [ -z $2 ]; then + usage + exit 3 +fi + +if [ ! -f /opt/xensource/bin/xenheartbeat.sh ]; then + printf "Error: Unable to find xenheartbeat.sh to launch\n" + exit 4 +fi + +for psid in `ps -ef | grep xenheartbeat | grep -v grep | awk '{print $2}'`; do + kill $psid +done + +nohup /opt/xensource/bin/xenheartbeat.sh $1 $2 >/dev/null 2>/dev/null & +echo "======> DONE <======" diff --git a/scripts/vm/hypervisor/xenserver/setupXenServer.sh b/scripts/vm/hypervisor/xenserver/setupXenServer.sh new file mode 100755 index 00000000000..78743d644ca --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/setupXenServer.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# avoid disk full +mv /etc/cron.daily/logrotate /etc/cron.hourly 2>&1 + +# more aio thread +echo 1048576 >/proc/sys/fs/aio-max-nr + +# empty heartbeat +cat /dev/null > /opt/xensource/bin/heartbeat + +echo "success" + diff --git a/scripts/vm/hypervisor/xenserver/setup_heartbeat_file.sh b/scripts/vm/hypervisor/xenserver/setup_heartbeat_file.sh new file mode 100755 index 00000000000..42ff965e5be --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/setup_heartbeat_file.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s [uuid of this host] [uuid of the sr to place the heartbeat]\n" $(basename $0) + +} + + +if [ -z $1 ]; then + usage + echo "1# no uuid of host" + exit 0 +fi + +if [ -z $2 ]; then + usage + echo "2# no uuid of sr" + exit 0 +fi + +if [ `xe host-list | grep $1 | wc -l` -ne 1 ]; then + echo "3# Unable to find the host uuid: $1" + exit 0 +fi + +if [ `xe sr-list uuid=$2 | wc -l` -eq 0 ]; then + echo "4# Unable to find SR with uuid: $2" + exit 0 +fi + +if [ `xe pbd-list sr-uuid=$2 | grep -B 1 $1 | wc -l` -eq 0 ]; then + echo "5# Unable to find a pbd for the SR: $2" + exit 0 +fi + +srtype=`xe sr-param-get param-name=type uuid=$2` + + +if [ "$srtype" = "nfs" ];then + dir=/var/run/sr-mount/$2 + filename=$dir/hb-$1 + if [ ! -f "$filename" ]; then + echo "6# heartbeat file $filename doesn't exist" + exit 0 + fi +else + dir=/dev/VG_XenStorage-$2 + link=$dir/hb-$1 + lvchange -ay $link + if [ $? -ne 0 ]; then + echo "7# Unable to make the heartbeat $link active" + exit 0 + fi +fi + +hbfile=/opt/xensource/bin/heartbeat + +if [ -f $hbfile ]; then + grep $dir $hbfile >/dev/null + if [ $? -gt 0 ] + then + echo $dir >> $hbfile + fi +else + echo $dir >> $hbfile +fi + +echo "0#DONE" + +exit 0 diff --git a/scripts/vm/hypervisor/xenserver/setup_heartbeat_sr.sh b/scripts/vm/hypervisor/xenserver/setup_heartbeat_sr.sh new file mode 100755 index 00000000000..0408c417e90 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/setup_heartbeat_sr.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +#set -x + +usage() { + echo "Usage: $(basename $0) [uuid of this host] [uuid of the sr to place the heartbeat]" + +} + +if [ -z $1 ]; then + usage + echo "1#no host uuid" + exit 0 +fi + +if [ -z $2 ]; then + usage + echo "2#no sr uuid" + exit 0 +fi + +if [ `xe host-list | grep $1 | wc -l` -ne 1 ]; then + echo "3# Unable to find the host uuid: $1" + exit 0 +fi + +if [ `xe sr-list uuid=$2 | wc -l` -eq 0 ]; then + echo "4# Unable to find SR with uuid: $2" + exit 0 +fi + +if [ `xe pbd-list sr-uuid=$2 | grep -B 1 $1 | wc -l` -eq 0 ]; then + echo "5# Unable to find a pbd for the SR: $2" + exit 0 +fi + +srtype=`xe sr-param-get param-name=type uuid=$2` + +if [ "$srtype" == "nfs" ];then + dir=/var/run/sr-mount/$2 + filename=$dir/hb-$1 + files=`ls $dir | grep "hb-$1"` + if [ -z "$files" ]; then + date=`date +%s` + echo "$date" > $filename + fi +else + dir=/dev/VG_XenStorage-$2 + link=$dir/hb-$1 + lv=`lvscan | grep $link` + if [ -z "$lv" ]; then + if [ -e $link ]; then + devmapper=$(ls $link -l | awk '{print $NF}') + if [ -e $devmapper ]; then + dmsetup remove -f $devmapper + fi + rm $link -f + fi + lvcreate VG_XenStorage-$2 -n hb-$1 --size 4M + if [ $? -ne 0 ]; then + echo "6# Unable to create heartbeat volume hb-$1" + exit 0 + fi + lv=`lvscan | grep $link` + if [ -z "$lv" ]; then + echo "7# volume hb-$1 is not created" + exit 0 + fi + fi + + if [ `echo $lv | awk '{print $1}'` == "inactive" ]; then + lvchange -ay $link + if [ $? -ne 0 ]; then + echo "8# Unable to make $link active" + exit 0 + fi + fi + + if [ ! -L $link ]; then + echo "9# Unable to find the soft link $link" + exit 0 + fi + dd if=/dev/zero of=$link bs=1 count=100 +fi + +echo "0#DONE" + +exit 0 diff --git a/scripts/vm/hypervisor/xenserver/vmopspremium b/scripts/vm/hypervisor/xenserver/vmopspremium new file mode 100755 index 00000000000..5fada9eb5f9 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/vmopspremium @@ -0,0 +1,101 @@ +#!/usr/bin/python +# +# A plugin for executing script needed by vmops cloud + +import os, sys, time +import XenAPIPlugin +sys.path.append("/opt/xensource/sm/") +import util +import socket + +def echo(fn): + def wrapped(*v, **k): + name = fn.__name__ + util.SMlog("#### VMOPS enter %s ####" % name ) + res = fn(*v, **k) + util.SMlog("#### VMOPS exit %s ####" % name ) + return res + return wrapped + +@echo +def copy_vhd_to_secondarystorage(session, args): + mountpoint = args['mountpoint'] + vdiuuid = args['vdiuuid'] + sruuid = args['sruuid'] + try: + cmd = ["bash", "/opt/xensource/bin/copy_vhd_to_secondarystorage.sh", mountpoint, vdiuuid, sruuid] + txt = util.pread2(cmd) + except: + txt = '10#failed' + return txt + +@echo +def copy_vhd_from_secondarystorage(session, args): + mountpoint = args['mountpoint'] + sruuid = args['sruuid'] + try: + cmd = ["bash", "/opt/xensource/bin/copy_vhd_from_secondarystorage.sh", mountpoint, sruuid] + txt = util.pread2(cmd) + except: + txt = '10#failed' + return txt + +@echo +def setup_heartbeat_sr(session, args): + host = args['host'] + sr = args['sr'] + try: + cmd = ["bash", "/opt/xensource/bin/setup_heartbeat_sr.sh", host, sr] + txt = util.pread2(cmd) + except: + txt = '' + return txt + +@echo +def setup_heartbeat_file(session, args): + host = args['host'] + sr = args['sr'] + try: + cmd = ["bash", "/opt/xensource/bin/setup_heartbeat_file.sh", host, sr] + txt = util.pread2(cmd) + except: + txt = '' + return txt + +@echo +def check_heartbeat(session, args): + host = args['host'] + interval = args['interval'] + try: + cmd = ["bash", "/opt/xensource/bin/check_heartbeat.sh", host, interval] + txt = util.pread2(cmd) + except: + txt='' + return txt + + +@echo +def heartbeat(session, args): + host = args['host'] + interval = args['interval'] + try: + cmd = ["/bin/bash", "/opt/xensource/bin/launch_hb.sh", host, interval] + txt = util.pread2(cmd) + except: + txt='fail' + return txt + + +@echo +def setupXenServer(session, args): + try: + cmd = ["/bin/bash", "/opt/xensource/bin/setupXenServer.sh"] + txt = util.pread2(cmd) + return txt + except: + raise xs_errors.XenError('setupXenServer.sh execution failed.') + + +if __name__ == "__main__": + XenAPIPlugin.dispatch({"copy_vhd_to_secondarystorage":copy_vhd_to_secondarystorage, "copy_vhd_from_secondarystorage":copy_vhd_from_secondarystorage, "setup_heartbeat_sr":setup_heartbeat_sr, "setup_heartbeat_file":setup_heartbeat_file, "check_heartbeat":check_heartbeat, "heartbeat": heartbeat, "setupXenServer":setupXenServer}) + diff --git a/scripts/vm/hypervisor/xenserver/xenheartbeat.sh b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh new file mode 100755 index 00000000000..2ba79a21b12 --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/xenheartbeat.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Version @VERSION@ + +#set -x + +usage() { + printf "Usage: %s [uuid of this host] [interval in seconds]\n" $(basename $0) >&2 + +} + +if [ -z $1 ]; then + usage + exit 2 +fi + +if [ -z $2 ]; then + usage + exit 3 +fi + +file=/opt/xensource/bin/heartbeat +while true +do + sleep $2 + + if [ ! -f $file ] + then + continue + fi + + # for iscsi + dirs=$(cat $file | grep VG_XenStorage) + for dir in $dirs + do + if [ -d $dir ]; then + hb=$dir/hb-$1 + date +%s | dd of=$hb count=100 bs=1 2>/dev/null + if [ $? -ne 0 ]; then + /usr/bin/logger -t heartbeat "Problem with $hb" + reboot -f + fi + else + sed -i /${dir##/*/}/d $file + fi + done + # for nfs + dirs=$(cat $file | grep sr-mount) + for dir in $dirs + do + mp=`mount | grep $dir` + if [ -n "$mp" ]; then + hb=$dir/hb-$1 + date +%s | dd of=$hb count=100 bs=1 2>/dev/null + if [ $? -ne 0 ]; then + /usr/bin/logger -t heartbeat "Problem with $hb" + reboot -f + fi + else + sed -i /${dir##/*/}/d $file + fi + done + +done + diff --git a/scripts/vm/hypervisor/xenserver/xenserver56/InterfaceReconfigure.py b/scripts/vm/hypervisor/xenserver/xenserver56/InterfaceReconfigure.py new file mode 100755 index 00000000000..9723c6617eb --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/xenserver56/InterfaceReconfigure.py @@ -0,0 +1,870 @@ +# Copyright (c) 2008,2009 Citrix Systems, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation; version 2.1 only. with the special +# exception on linking described in file LICENSE. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +import sys +import syslog +import os + +from xml.dom.minidom import getDOMImplementation +from xml.dom.minidom import parse as parseXML + +the_root_prefix = "" +def root_prefix(): + """Returns a string to prefix to all file name references, which + is useful for testing.""" + return the_root_prefix +def set_root_prefix(prefix): + global the_root_prefix + the_root_prefix = prefix + +log_destination = "syslog" +def get_log_destination(): + """Returns the current log destination. + 'syslog' means "log to syslog". + 'stderr' means "log to stderr".""" + return log_destination +def set_log_destination(dest): + global log_destination + log_destination = dest + +# +# Logging. +# + +def log(s): + if get_log_destination() == 'syslog': + syslog.syslog(s) + else: + print >>sys.stderr, s + +# +# Exceptions. +# + +class Error(Exception): + def __init__(self, msg): + Exception.__init__(self) + self.msg = msg + +# +# Run external utilities +# + +def run_command(command): + log("Running command: " + ' '.join(command)) + rc = os.spawnl(os.P_WAIT, root_prefix() + command[0], *command) + if rc != 0: + log("Command failed %d: " % rc + ' '.join(command)) + return False + return True + +# +# Configuration File Handling. +# + +class ConfigurationFile(object): + """Write a file, tracking old and new versions. + + Supports writing a new version of a file and applying and + reverting those changes. + """ + + __STATE = {"OPEN":"OPEN", + "NOT-APPLIED":"NOT-APPLIED", "APPLIED":"APPLIED", + "REVERTED":"REVERTED", "COMMITTED": "COMMITTED"} + + def __init__(self, path): + dirname,basename = os.path.split(path) + + self.__state = self.__STATE['OPEN'] + self.__children = [] + + self.__path = os.path.join(dirname, basename) + self.__oldpath = os.path.join(dirname, "." + basename + ".xapi-old") + self.__newpath = os.path.join(dirname, "." + basename + ".xapi-new") + + self.__f = open(self.__newpath, "w") + + def attach_child(self, child): + self.__children.append(child) + + def path(self): + return self.__path + + def readlines(self): + try: + return open(self.path()).readlines() + except: + return "" + + def write(self, args): + if self.__state != self.__STATE['OPEN']: + raise Error("Attempt to write to file in state %s" % self.__state) + self.__f.write(args) + + def close(self): + if self.__state != self.__STATE['OPEN']: + raise Error("Attempt to close file in state %s" % self.__state) + + self.__f.close() + self.__state = self.__STATE['NOT-APPLIED'] + + def changed(self): + if self.__state != self.__STATE['NOT-APPLIED']: + raise Error("Attempt to compare file in state %s" % self.__state) + + return True + + def apply(self): + if self.__state != self.__STATE['NOT-APPLIED']: + raise Error("Attempt to apply configuration from state %s" % self.__state) + + for child in self.__children: + child.apply() + + log("Applying changes to %s configuration" % self.__path) + + # Remove previous backup. + if os.access(self.__oldpath, os.F_OK): + os.unlink(self.__oldpath) + + # Save current configuration. + if os.access(self.__path, os.F_OK): + os.link(self.__path, self.__oldpath) + os.unlink(self.__path) + + # Apply new configuration. + assert(os.path.exists(self.__newpath)) + os.link(self.__newpath, self.__path) + + # Remove temporary file. + os.unlink(self.__newpath) + + self.__state = self.__STATE['APPLIED'] + + def revert(self): + if self.__state != self.__STATE['APPLIED']: + raise Error("Attempt to revert configuration from state %s" % self.__state) + + for child in self.__children: + child.revert() + + log("Reverting changes to %s configuration" % self.__path) + + # Remove existing new configuration + if os.access(self.__newpath, os.F_OK): + os.unlink(self.__newpath) + + # Revert new configuration. + if os.access(self.__path, os.F_OK): + os.link(self.__path, self.__newpath) + os.unlink(self.__path) + + # Revert to old configuration. + if os.access(self.__oldpath, os.F_OK): + os.link(self.__oldpath, self.__path) + os.unlink(self.__oldpath) + + # Leave .*.xapi-new as an aid to debugging. + + self.__state = self.__STATE['REVERTED'] + + def commit(self): + if self.__state != self.__STATE['APPLIED']: + raise Error("Attempt to commit configuration from state %s" % self.__state) + + for child in self.__children: + child.commit() + + log("Committing changes to %s configuration" % self.__path) + + if os.access(self.__oldpath, os.F_OK): + os.unlink(self.__oldpath) + if os.access(self.__newpath, os.F_OK): + os.unlink(self.__newpath) + + self.__state = self.__STATE['COMMITTED'] + +# +# Helper functions for encoding/decoding database attributes to/from XML. +# + +def _str_to_xml(xml, parent, tag, val): + e = xml.createElement(tag) + parent.appendChild(e) + v = xml.createTextNode(val) + e.appendChild(v) +def _str_from_xml(n): + def getText(nodelist): + rc = "" + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + return getText(n.childNodes).strip() + +def _bool_to_xml(xml, parent, tag, val): + if val: + _str_to_xml(xml, parent, tag, "True") + else: + _str_to_xml(xml, parent, tag, "False") +def _bool_from_xml(n): + s = _str_from_xml(n) + if s == "True": + return True + elif s == "False": + return False + else: + raise Error("Unknown boolean value %s" % s) + +def _strlist_to_xml(xml, parent, ltag, itag, val): + e = xml.createElement(ltag) + parent.appendChild(e) + for v in val: + c = xml.createElement(itag) + e.appendChild(c) + cv = xml.createTextNode(v) + c.appendChild(cv) +def _strlist_from_xml(n, ltag, itag): + ret = [] + for n in n.childNodes: + if n.nodeName == itag: + ret.append(_str_from_xml(n)) + return ret + +def _otherconfig_to_xml(xml, parent, val, attrs): + otherconfig = xml.createElement("other_config") + parent.appendChild(otherconfig) + for n,v in val.items(): + if not n in attrs: + raise Error("Unknown other-config attribute: %s" % n) + _str_to_xml(xml, otherconfig, n, v) +def _otherconfig_from_xml(n, attrs): + ret = {} + for n in n.childNodes: + if n.nodeName in attrs: + ret[n.nodeName] = _str_from_xml(n) + return ret + +# +# Definitions of the database objects (and their attributes) used by interface-reconfigure. +# +# Each object is defined by a dictionary mapping an attribute name in +# the xapi database to a tuple containing two items: +# - a function which takes this attribute and encodes it as XML. +# - a function which takes XML and decocdes it into a value. +# +# other-config attributes are specified as a simple array of strings + +_PIF_XML_TAG = "pif" +_VLAN_XML_TAG = "vlan" +_BOND_XML_TAG = "bond" +_NETWORK_XML_TAG = "network" + +_ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ] + +_PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \ + [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay', 'updelay', 'use_carrier' ] + \ + _ETHTOOL_OTHERCONFIG_ATTRS + +_PIF_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml), + 'management': (_bool_to_xml,_bool_from_xml), + 'network': (_str_to_xml,_str_from_xml), + 'device': (_str_to_xml,_str_from_xml), + 'bond_master_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'bond_master_of', 'slave', v), + lambda n: _strlist_from_xml(n, 'bond_master_of', 'slave')), + 'bond_slave_of': (_str_to_xml,_str_from_xml), + 'VLAN': (_str_to_xml,_str_from_xml), + 'VLAN_master_of': (_str_to_xml,_str_from_xml), + 'VLAN_slave_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v), + lambda n: _strlist_from_xml(n, 'VLAN_slave_Of', 'master')), + 'ip_configuration_mode': (_str_to_xml,_str_from_xml), + 'IP': (_str_to_xml,_str_from_xml), + 'netmask': (_str_to_xml,_str_from_xml), + 'gateway': (_str_to_xml,_str_from_xml), + 'DNS': (_str_to_xml,_str_from_xml), + 'MAC': (_str_to_xml,_str_from_xml), + 'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _PIF_OTHERCONFIG_ATTRS), + lambda n: _otherconfig_from_xml(n, _PIF_OTHERCONFIG_ATTRS)), + + # Special case: We write the current value + # PIF.currently-attached to the cache but since it will + # not be valid when we come to use the cache later + # (i.e. after a reboot) we always read it as False. + 'currently_attached': (_bool_to_xml, lambda n: False), + } + +_VLAN_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml), + 'tagged_PIF': (_str_to_xml,_str_from_xml), + 'untagged_PIF': (_str_to_xml,_str_from_xml), + } + +_BOND_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml), + 'master': (_str_to_xml,_str_from_xml), + 'slaves': (lambda x, p, t, v: _strlist_to_xml(x, p, 'slaves', 'slave', v), + lambda n: _strlist_from_xml(n, 'slaves', 'slave')), + } + +_NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + _ETHTOOL_OTHERCONFIG_ATTRS + +_NETWORK_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml), + 'bridge': (_str_to_xml,_str_from_xml), + 'MTU': (_str_to_xml,_str_from_xml), + 'PIFs': (lambda x, p, t, v: _strlist_to_xml(x, p, 'PIFs', 'PIF', v), + lambda n: _strlist_from_xml(n, 'PIFs', 'PIF')), + 'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, v, _NETWORK_OTHERCONFIG_ATTRS), + lambda n: _otherconfig_from_xml(n, _NETWORK_OTHERCONFIG_ATTRS)), + } + +# +# Database Cache object +# + +_db = None + +def db(): + assert(_db is not None) + return _db + +def db_init_from_cache(cache): + global _db + assert(_db is None) + _db = DatabaseCache(cache_file=cache) + +def db_init_from_xenapi(session): + global _db + assert(_db is None) + _db = DatabaseCache(session_ref=session) + +class DatabaseCache(object): + def __read_xensource_inventory(self): + filename = root_prefix() + "/etc/xensource-inventory" + f = open(filename, "r") + lines = [x.strip("\n") for x in f.readlines()] + f.close() + + defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ] + defs = [ (a, b.strip("'")) for (a,b) in defs ] + + return dict(defs) + + def __pif_on_host(self,pif): + return self.__pifs.has_key(pif) + + def __get_pif_records_from_xapi(self, session, host): + self.__pifs = {} + for (p,rec) in session.xenapi.PIF.get_all_records().items(): + if rec['host'] != host: + continue + self.__pifs[p] = {} + for f in _PIF_ATTRS: + self.__pifs[p][f] = rec[f] + self.__pifs[p]['other_config'] = {} + for f in _PIF_OTHERCONFIG_ATTRS: + if not rec['other_config'].has_key(f): continue + self.__pifs[p]['other_config'][f] = rec['other_config'][f] + + def __get_vlan_records_from_xapi(self, session): + self.__vlans = {} + for v in session.xenapi.VLAN.get_all(): + rec = session.xenapi.VLAN.get_record(v) + if not self.__pif_on_host(rec['untagged_PIF']): + continue + self.__vlans[v] = {} + for f in _VLAN_ATTRS: + self.__vlans[v][f] = rec[f] + + def __get_bond_records_from_xapi(self, session): + self.__bonds = {} + for b in session.xenapi.Bond.get_all(): + rec = session.xenapi.Bond.get_record(b) + if not self.__pif_on_host(rec['master']): + continue + self.__bonds[b] = {} + for f in _BOND_ATTRS: + self.__bonds[b][f] = rec[f] + + def __get_network_records_from_xapi(self, session): + self.__networks = {} + for n in session.xenapi.network.get_all(): + rec = session.xenapi.network.get_record(n) + self.__networks[n] = {} + for f in _NETWORK_ATTRS: + if f == "PIFs": + # drop PIFs on other hosts + self.__networks[n][f] = [p for p in rec[f] if self.__pif_on_host(p)] + elif f == "MTU" and f not in rec: + # XenServer 5.5 network records did not have an + # MTU field, so allow this to be missing. + pass + else: + self.__networks[n][f] = rec[f] + self.__networks[n]['other_config'] = {} + for f in _NETWORK_OTHERCONFIG_ATTRS: + if not rec['other_config'].has_key(f): continue + self.__networks[n]['other_config'][f] = rec['other_config'][f] + + def __to_xml(self, xml, parent, key, ref, rec, attrs): + """Encode a database object as XML""" + e = xml.createElement(key) + parent.appendChild(e) + if ref: + e.setAttribute('ref', ref) + + for n,v in rec.items(): + if attrs.has_key(n): + h,_ = attrs[n] + h(xml, e, n, v) + else: + raise Error("Unknown attribute %s" % n) + def __from_xml(self, e, attrs): + """Decode a database object from XML""" + ref = e.attributes['ref'].value + rec = {} + for n in e.childNodes: + if n.nodeName in attrs: + _,h = attrs[n.nodeName] + rec[n.nodeName] = h(n) + return (ref,rec) + + def __init__(self, session_ref=None, cache_file=None): + if session_ref and cache_file: + raise Error("can't specify session reference and cache file") + if cache_file == None: + import XenAPI + session = XenAPI.xapi_local() + + if not session_ref: + log("No session ref given on command line, logging in.") + session.xenapi.login_with_password("root", "") + else: + session._session = session_ref + + try: + + inventory = self.__read_xensource_inventory() + assert(inventory.has_key('INSTALLATION_UUID')) + log("host uuid is %s" % inventory['INSTALLATION_UUID']) + + host = session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID']) + + self.__get_pif_records_from_xapi(session, host) + + self.__get_vlan_records_from_xapi(session) + self.__get_bond_records_from_xapi(session) + self.__get_network_records_from_xapi(session) + finally: + if not session_ref: + session.xenapi.session.logout() + else: + log("Loading xapi database cache from %s" % cache_file) + + xml = parseXML(root_prefix() + cache_file) + + self.__pifs = {} + self.__bonds = {} + self.__vlans = {} + self.__networks = {} + + assert(len(xml.childNodes) == 1) + toplevel = xml.childNodes[0] + + assert(toplevel.nodeName == "xenserver-network-configuration") + + for n in toplevel.childNodes: + if n.nodeName == "#text": + pass + elif n.nodeName == _PIF_XML_TAG: + (ref,rec) = self.__from_xml(n, _PIF_ATTRS) + self.__pifs[ref] = rec + elif n.nodeName == _BOND_XML_TAG: + (ref,rec) = self.__from_xml(n, _BOND_ATTRS) + self.__bonds[ref] = rec + elif n.nodeName == _VLAN_XML_TAG: + (ref,rec) = self.__from_xml(n, _VLAN_ATTRS) + self.__vlans[ref] = rec + elif n.nodeName == _NETWORK_XML_TAG: + (ref,rec) = self.__from_xml(n, _NETWORK_ATTRS) + self.__networks[ref] = rec + else: + raise Error("Unknown XML element %s" % n.nodeName) + + def save(self, cache_file): + + xml = getDOMImplementation().createDocument( + None, "xenserver-network-configuration", None) + for (ref,rec) in self.__pifs.items(): + self.__to_xml(xml, xml.documentElement, _PIF_XML_TAG, ref, rec, _PIF_ATTRS) + for (ref,rec) in self.__bonds.items(): + self.__to_xml(xml, xml.documentElement, _BOND_XML_TAG, ref, rec, _BOND_ATTRS) + for (ref,rec) in self.__vlans.items(): + self.__to_xml(xml, xml.documentElement, _VLAN_XML_TAG, ref, rec, _VLAN_ATTRS) + for (ref,rec) in self.__networks.items(): + self.__to_xml(xml, xml.documentElement, _NETWORK_XML_TAG, ref, rec, + _NETWORK_ATTRS) + + f = open(cache_file, 'w') + f.write(xml.toprettyxml()) + f.close() + + def get_pif_by_uuid(self, uuid): + pifs = map(lambda (ref,rec): ref, + filter(lambda (ref,rec): uuid == rec['uuid'], + self.__pifs.items())) + if len(pifs) == 0: + raise Error("Unknown PIF \"%s\"" % uuid) + elif len(pifs) > 1: + raise Error("Non-unique PIF \"%s\"" % uuid) + + return pifs[0] + + def get_pifs_by_device(self, device): + return map(lambda (ref,rec): ref, + filter(lambda (ref,rec): rec['device'] == device, + self.__pifs.items())) + + def get_pif_by_bridge(self, bridge): + networks = map(lambda (ref,rec): ref, + filter(lambda (ref,rec): rec['bridge'] == bridge, + self.__networks.items())) + if len(networks) == 0: + raise Error("No matching network \"%s\"" % bridge) + + answer = None + for network in networks: + nwrec = self.get_network_record(network) + for pif in nwrec['PIFs']: + pifrec = self.get_pif_record(pif) + if answer: + raise Error("Multiple PIFs on host for network %s" % (bridge)) + answer = pif + if not answer: + raise Error("No PIF on host for network %s" % (bridge)) + return answer + + def get_pif_record(self, pif): + if self.__pifs.has_key(pif): + return self.__pifs[pif] + raise Error("Unknown PIF \"%s\"" % pif) + def get_all_pifs(self): + return self.__pifs + def pif_exists(self, pif): + return self.__pifs.has_key(pif) + + def get_management_pif(self): + """ Returns the management pif on host + """ + all = self.get_all_pifs() + for pif in all: + pifrec = self.get_pif_record(pif) + if pifrec['management']: return pif + return None + + def get_network_record(self, network): + if self.__networks.has_key(network): + return self.__networks[network] + raise Error("Unknown network \"%s\"" % network) + + def get_bond_record(self, bond): + if self.__bonds.has_key(bond): + return self.__bonds[bond] + else: + return None + + def get_vlan_record(self, vlan): + if self.__vlans.has_key(vlan): + return self.__vlans[vlan] + else: + return None + +# +# +# + +def ethtool_settings(oc): + settings = [] + if oc.has_key('ethtool-speed'): + val = oc['ethtool-speed'] + if val in ["10", "100", "1000"]: + settings += ['speed', val] + else: + log("Invalid value for ethtool-speed = %s. Must be 10|100|1000." % val) + if oc.has_key('ethtool-duplex'): + val = oc['ethtool-duplex'] + if val in ["10", "100", "1000"]: + settings += ['duplex', 'val'] + else: + log("Invalid value for ethtool-duplex = %s. Must be half|full." % val) + if oc.has_key('ethtool-autoneg'): + val = oc['ethtool-autoneg'] + if val in ["true", "on"]: + settings += ['autoneg', 'on'] + elif val in ["false", "off"]: + settings += ['autoneg', 'off'] + else: + log("Invalid value for ethtool-autoneg = %s. Must be on|true|off|false." % val) + offload = [] + for opt in ("rx", "tx", "sg", "tso", "ufo", "gso"): + if oc.has_key("ethtool-" + opt): + val = oc["ethtool-" + opt] + if val in ["true", "on"]: + offload += [opt, 'on'] + elif val in ["false", "off"]: + offload += [opt, 'off'] + else: + log("Invalid value for ethtool-%s = %s. Must be on|true|off|false." % (opt, val)) + return settings,offload + +# By default the MTU is taken from the Network.MTU setting for VIF, +# PIF and Bridge. However it is possible to override this by using +# {VIF,PIF,Network}.other-config:mtu. +# +# type parameter is a string describing the object that the oc parameter +# is from. e.g. "PIF", "Network" +def mtu_setting(nw, type, oc): + mtu = None + + nwrec = db().get_network_record(nw) + if nwrec.has_key('MTU'): + mtu = nwrec['MTU'] + else: + mtu = "1500" + + if oc.has_key('mtu'): + log("Override Network.MTU setting on bridge %s from %s.MTU is %s" % \ + (nwrec['bridge'], type, mtu)) + mtu = oc['mtu'] + + if mtu is not None: + try: + int(mtu) # Check that the value is an integer + return mtu + except ValueError, x: + log("Invalid value for mtu = %s" % mtu) + + return None + +# +# IP Network Devices -- network devices with IP configuration +# +def pif_ipdev_name(pif): + """Return the ipdev name associated with pif""" + pifrec = db().get_pif_record(pif) + nwrec = db().get_network_record(pifrec['network']) + + if nwrec['bridge']: + # TODO: sanity check that nwrec['bridgeless'] != 'true' + return nwrec['bridge'] + else: + # TODO: sanity check that nwrec['bridgeless'] == 'true' + return pif_netdev_name(pif) + +# +# Bare Network Devices -- network devices without IP configuration +# + +def netdev_exists(netdev): + return os.path.exists(root_prefix() + "/sys/class/net/" + netdev) + +def pif_netdev_name(pif): + """Get the netdev name for a PIF.""" + + pifrec = db().get_pif_record(pif) + + if pif_is_vlan(pif): + return "%(device)s.%(VLAN)s" % pifrec + else: + return pifrec['device'] + +# +# Bridges +# + +def pif_is_bridged(pif): + pifrec = db().get_pif_record(pif) + nwrec = db().get_network_record(pifrec['network']) + + if nwrec['bridge']: + # TODO: sanity check that nwrec['bridgeless'] != 'true' + return True + else: + # TODO: sanity check that nwrec['bridgeless'] == 'true' + return False + +def pif_bridge_name(pif): + """Return the bridge name of a pif. + + PIF must be a bridged PIF.""" + pifrec = db().get_pif_record(pif) + + nwrec = db().get_network_record(pifrec['network']) + + if nwrec['bridge']: + return nwrec['bridge'] + else: + raise Error("PIF %(uuid)s does not have a bridge name" % pifrec) + +# +# Bonded PIFs +# +def pif_is_bond(pif): + pifrec = db().get_pif_record(pif) + + return len(pifrec['bond_master_of']) > 0 + +def pif_get_bond_masters(pif): + """Returns a list of PIFs which are bond masters of this PIF""" + + pifrec = db().get_pif_record(pif) + + bso = pifrec['bond_slave_of'] + + # bond-slave-of is currently a single reference but in principle a + # PIF could be a member of several bonds which are not + # concurrently attached. Be robust to this possibility. + if not bso or bso == "OpaqueRef:NULL": + bso = [] + elif not type(bso) == list: + bso = [bso] + + bondrecs = [db().get_bond_record(bond) for bond in bso] + bondrecs = [rec for rec in bondrecs if rec] + + return [bond['master'] for bond in bondrecs] + +def pif_get_bond_slaves(pif): + """Returns a list of PIFs which make up the given bonded pif.""" + + pifrec = db().get_pif_record(pif) + + bmo = pifrec['bond_master_of'] + if len(bmo) > 1: + raise Error("Bond-master-of contains too many elements") + + if len(bmo) == 0: + return [] + + bondrec = db().get_bond_record(bmo[0]) + if not bondrec: + raise Error("No bond record for bond master PIF") + + return bondrec['slaves'] + +# +# VLAN PIFs +# + +def pif_is_vlan(pif): + return db().get_pif_record(pif)['VLAN'] != '-1' + +def pif_get_vlan_slave(pif): + """Find the PIF which is the VLAN slave of pif. + +Returns the 'physical' PIF underneath the a VLAN PIF @pif.""" + + pifrec = db().get_pif_record(pif) + + vlan = pifrec['VLAN_master_of'] + if not vlan or vlan == "OpaqueRef:NULL": + raise Error("PIF is not a VLAN master") + + vlanrec = db().get_vlan_record(vlan) + if not vlanrec: + raise Error("No VLAN record found for PIF") + + return vlanrec['tagged_PIF'] + +def pif_get_vlan_masters(pif): + """Returns a list of PIFs which are VLANs on top of the given pif.""" + + pifrec = db().get_pif_record(pif) + vlans = [db().get_vlan_record(v) for v in pifrec['VLAN_slave_of']] + return [v['untagged_PIF'] for v in vlans if v and db().pif_exists(v['untagged_PIF'])] + +# +# Datapath base class +# + +class Datapath(object): + """Object encapsulating the actions necessary to (de)configure the + datapath for a given PIF. Does not include configuration of the + IP address on the ipdev. + """ + + def __init__(self, pif): + self._pif = pif + + def configure_ipdev(self, cfg): + """Write ifcfg TYPE field for an IPdev, plus any type specific + fields to cfg + """ + raise NotImplementedError + + def preconfigure(self, parent): + """Prepare datapath configuration for PIF, but do not actually + apply any changes. + + Any configuration files should be attached to parent. + """ + raise NotImplementedError + + def bring_down_existing(self): + """Tear down any existing network device configuration which + needs to be undone in order to bring this PIF up. + """ + raise NotImplementedError + + def configure(self): + """Apply the configuration prepared in the preconfigure stage. + + Should assume any configuration files changed attached in + the preconfigure stage are applied and bring up the + necesary devices to provide the datapath for the + PIF. + + Should not bring up the IPdev. + """ + raise NotImplementedError + + def post(self): + """Called after the IPdev has been brought up. + + Should do any final setup, including reinstating any + devices which were taken down in the bring_down_existing + hook. + """ + raise NotImplementedError + + def bring_down(self): + """Tear down and deconfigure the datapath. Should assume the + IPdev has already been brought down. + """ + raise NotImplementedError + +def DatapathFactory(pif): + # XXX Need a datapath object for bridgeless PIFs + + try: + network_conf = open(root_prefix() + "/etc/xensource/network.conf", 'r') + network_backend = network_conf.readline().strip() + network_conf.close() + except Exception, e: + raise Error("failed to determine network backend:" + e) + + if network_backend == "bridge": + from InterfaceReconfigureBridge import DatapathBridge + return DatapathBridge(pif) + elif network_backend in ["openvswitch", "vswitch"]: + from InterfaceReconfigureVswitch import DatapathVswitch + return DatapathVswitch(pif) + else: + raise Error("unknown network backend %s" % network_backend) diff --git a/scripts/vm/hypervisor/xenserver/xenserver56/patch b/scripts/vm/hypervisor/xenserver/xenserver56/patch index 944962b6b37..dba8a9b8a36 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56/patch @@ -31,3 +31,14 @@ networkUsage.sh=../../../../network/domr/,0755,/opt/xensource/bin call_firewall.sh=../../../../network/domr/,0755,/opt/xensource/bin call_loadbalancer.sh=../../../../network/domr/,0755,/opt/xensource/bin l2tp_vpn.sh=../../../../network/domr/,0755,/opt/xensource/bin +copy_vhd_to_secondarystorage.sh=..,0755,/opt/xensource/bin +copy_vhd_from_secondarystorage.sh=..,0755,/opt/xensource/bin +setup_heartbeat_sr.sh=..,0755,/opt/xensource/bin +setup_heartbeat_file.sh=..,0755,/opt/xensource/bin +check_heartbeat.sh=..,0755,/opt/xensource/bin +xenheartbeat.sh=..,0755,/opt/xensource/bin +launch_hb.sh=..,0755,/opt/xensource/bin +setupXenServer.sh=..,0755,/opt/xensource/bin +vmopspremium=..,0755,/etc/xapi.d/plugins +InterfaceReconfigure.py=.,0755,/opt/xensource/bin +fsimage.so=..,0755,/usr/lib/fs/ext2fs-lib diff --git a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch index 9f7c0d0d193..bc1d2c8ed12 100644 --- a/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch +++ b/scripts/vm/hypervisor/xenserver/xenserver56fp1/patch @@ -33,3 +33,12 @@ call_firewall.sh=../../../../network/domr/,0755,/opt/xensource/bin call_loadbalancer.sh=../../../../network/domr/,0755,/opt/xensource/bin l2tp_vpn.sh=../../../../network/domr/,0755,/opt/xensource/bin cloud-setup-bonding.sh=..,0755,/opt/xensource/bin +copy_vhd_to_secondarystorage.sh=..,0755,/opt/xensource/bin +copy_vhd_from_secondarystorage.sh=..,0755,/opt/xensource/bin +setup_heartbeat_sr.sh=..,0755,/opt/xensource/bin +setup_heartbeat_file.sh=..,0755,/opt/xensource/bin +check_heartbeat.sh=..,0755,/opt/xensource/bin +xenheartbeat.sh=..,0755,/opt/xensource/bin +launch_hb.sh=..,0755,/opt/xensource/bin +setupXenServer.sh=..,0755,/opt/xensource/bin +vmopspremium=..,0755,/etc/xapi.d/plugins diff --git a/scripts/vm/hypervisor/xenserver/xs_cleanup.sh b/scripts/vm/hypervisor/xenserver/xs_cleanup.sh new file mode 100755 index 00000000000..cb81a3f16ef --- /dev/null +++ b/scripts/vm/hypervisor/xenserver/xs_cleanup.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +#set -x + +usage() { + printf "Usage: %s \n" $(basename $0) >&2 + +} + +# remove device which is in xenstore but not in xapi +remove_device() { + be=$1 + xenstore-write /local/domain/0/backend/tap/0/$be/online 0 &>/dev/null + xenstore-write /local/domain/0/backend/tap/0/$be/shutdown-request normal &>/dev/null + for i in $(seq 20) + do + sleep 1 + xenstore-exists /local/domain/0/backend/tap/0/$be/shutdown-done &>/dev/null + if [ $? -eq 0 ] ; then + xenstore-rm /local/domain/0/device/vbd/$be &>/dev/null + xenstore-rm /local/domain/0/backend/tap/0/$be &>/dev/null + xenstore-rm /local/domain/0/error/backend/tap/0/$be &>/dev/null + xenstore-rm /local/domain/0/error/device/vbd/$be &>/dev/null + return + fi + xenstore-exists /local/domain/0/backend/tap/0/$be &>/dev/null + if [ $? -ne 0 ] ; then + return + fi + done + + echo "unplug device $be failed" + exit 2 +} + +bes=`xenstore-list /local/domain/0/backend/tap/0` + +if [ -z "$bes" ]; then + exit 0 +fi + +for be in $bes +do + device=`xenstore-read /local/domain/0/backend/tap/0/$be/dev` + ls $device >/dev/null 2>&1 + if [ $? -ne 0 ]; then + remove_device $be + fi +done + + +echo "======> DONE <======" +exit 0 +