mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
merge premium xenserver scripts to oss
This commit is contained in:
parent
ce73013768
commit
ec98a539b4
58
scripts/vm/hypervisor/xenserver/check_heartbeat.sh
Executable file
58
scripts/vm/hypervisor/xenserver/check_heartbeat.sh
Executable file
@ -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 <======"
|
||||
118
scripts/vm/hypervisor/xenserver/copy_vhd_from_secondarystorage.sh
Executable file
118
scripts/vm/hypervisor/xenserver/copy_vhd_from_secondarystorage.sh
Executable file
@ -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
|
||||
106
scripts/vm/hypervisor/xenserver/copy_vhd_to_secondarystorage.sh
Executable file
106
scripts/vm/hypervisor/xenserver/copy_vhd_to_secondarystorage.sh
Executable file
@ -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
|
||||
BIN
scripts/vm/hypervisor/xenserver/fsimage.so
Executable file
BIN
scripts/vm/hypervisor/xenserver/fsimage.so
Executable file
Binary file not shown.
30
scripts/vm/hypervisor/xenserver/launch_hb.sh
Executable file
30
scripts/vm/hypervisor/xenserver/launch_hb.sh
Executable file
@ -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 <======"
|
||||
13
scripts/vm/hypervisor/xenserver/setupXenServer.sh
Executable file
13
scripts/vm/hypervisor/xenserver/setupXenServer.sh
Executable file
@ -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"
|
||||
|
||||
72
scripts/vm/hypervisor/xenserver/setup_heartbeat_file.sh
Executable file
72
scripts/vm/hypervisor/xenserver/setup_heartbeat_file.sh
Executable file
@ -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
|
||||
88
scripts/vm/hypervisor/xenserver/setup_heartbeat_sr.sh
Executable file
88
scripts/vm/hypervisor/xenserver/setup_heartbeat_sr.sh
Executable file
@ -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
|
||||
101
scripts/vm/hypervisor/xenserver/vmopspremium
Executable file
101
scripts/vm/hypervisor/xenserver/vmopspremium
Executable file
@ -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})
|
||||
|
||||
64
scripts/vm/hypervisor/xenserver/xenheartbeat.sh
Executable file
64
scripts/vm/hypervisor/xenserver/xenheartbeat.sh
Executable file
@ -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
|
||||
|
||||
870
scripts/vm/hypervisor/xenserver/xenserver56/InterfaceReconfigure.py
Executable file
870
scripts/vm/hypervisor/xenserver/xenserver56/InterfaceReconfigure.py
Executable file
@ -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)
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
54
scripts/vm/hypervisor/xenserver/xs_cleanup.sh
Executable file
54
scripts/vm/hypervisor/xenserver/xs_cleanup.sh
Executable file
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user