1318 lines
43 KiB
Python
Executable File

#!/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
from util import CommandException
import hostvmstats
import socket
import stat
import base64
import tempfile
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 gethostvmstats(session, args):
collect_host_stats = args['collectHostStats']
consolidation_function = args['consolidationFunction']
interval = args['interval']
start_time = args['startTime']
result = hostvmstats.get_stats(session, collect_host_stats, consolidation_function, interval, start_time)
return result
@echo
def setup_iscsi(session, args):
uuid=args['uuid']
try:
cmd = ["bash", "/opt/xensource/bin/setup_iscsi.sh", uuid]
txt = util.pread2(cmd)
except:
txt = ''
return txt
@echo
def getvncport(session, args):
domid = args['domID']
hvm = args['hvm']
if hvm == 'true':
path = "/local/domain/" + domid + "/console/vnc-port"
else:
path = "/local/domain/" + domid + "/serial/0/vnc-port"
try:
cmd = ["xenstore-read", path]
txt = util.pread2(cmd)
except:
txt = ''
return txt
@echo
def getgateway(session, args):
mgmt_ip = args['mgmtIP']
try:
cmd = ["bash", "/opt/xensource/bin/network_info.sh", "-g", mgmt_ip]
txt = util.pread2(cmd)
except:
txt = ''
return txt
@echo
def preparemigration(session, args):
uuid = args['uuid']
try:
cmd = ["/opt/xensource/bin/make_migratable.sh", uuid]
util.pread2(cmd)
txt = 'success'
except:
util.SMlog("Catch prepare migration exception" )
txt = ''
return txt
@echo
def setIptables(session, args):
try:
cmd = ["/bin/bash", "/opt/xensource/bin/setupxenserver.sh"]
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" setIptables execution failed " )
txt = ''
return txt
@echo
def pingdomr(session, args):
host = args['host']
port = args['port']
socket.setdefaulttimeout(3)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host,int(port)))
txt = 'success'
except:
txt = ''
s.close()
return txt
@echo
def pingxenserver(session, args):
txt = 'success'
return txt
@echo
def ipassoc(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/ipassoc.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" ip associate failed " )
txt = ''
return txt
@echo
def vlanRemapUtils(session, args):
cmd = []
cmd.insert(0, "python")
cmd.insert(1, "/opt/xensource/bin/vlanRemapUtils.py")
op = args.pop("op")
cmd.insert(2, op)
if op == "createGRE":
cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("remoteIP"))
cmd.insert(5, args.pop("greKey"))
elif op == "createFlow":
cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("vifName"))
cmd.insert(5, args.pop("mac"))
cmd.insert(7, args.pop("remap"))
elif op == "deleteFlow":
cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("ofports"))
cmd.insert(5, args.pop("macs"))
cmd.insert(6, args.pop("remap"))
elif op == "setTag":
cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("vifName"))
cmd.insert(5, args.pop("tag"))
elif op == "askPorts":
cmd.insert(3, args.pop("bridge"))
cmd.insert(4, args.pop("vifNames"))
try:
txt = util.pread2(cmd)
except:
util.SMlog("vlanRemapUtils failed")
txt = 'failed'
return txt
@echo
def vm_data(session, args):
router_ip = args.pop('routerIP')
vm_ip = args.pop('vmIP')
util.SMlog(" adding vmdata for VM with IP: " + vm_ip + " to router with IP: " + router_ip)
for pair in args:
pairList = pair.split(',')
vmDataFolder = pairList[0]
vmDataFile = pairList[1]
vmDataValue = args[pair]
cmd = ["/bin/bash", "/opt/xensource/bin/vm_data.sh", "-r", router_ip, "-v", vm_ip, "-F", vmDataFolder, "-f", vmDataFile]
fd = None
tmp_path = None
if (vmDataValue != "none"):
try:
fd,tmp_path = tempfile.mkstemp()
tmpfile = open(tmp_path, 'w')
if (vmDataFolder == "userdata"):
vmDataValue = base64.urlsafe_b64decode(vmDataValue)
tmpfile.write(vmDataValue)
tmpfile.close()
cmd.append("-d")
cmd.append(tmp_path)
except:
util.SMlog(" vmdata failed to write tempfile " )
os.close(fd)
os.remove(tmp_path)
return ''
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" vmdata failed with folder: " + vmDataFolder + " and file: " + vmDataFile)
txt = ''
if (fd != None):
os.close(fd)
os.remove(tmp_path)
return txt
def pingtest(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/pingtest.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" pingtest failed " )
txt = ''
return txt
@echo
def savePassword(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/save_password_to_domr.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" save password to domr failed " )
txt = ''
return txt
@echo
def saveDhcpEntry(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/dhcp_entry.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" save dhcp entry failed " )
txt = ''
return txt
@echo
def lt2p_vpn(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/l2tp_vpn.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog("l2tp vpn failed " )
txt = ''
return txt
@echo
def setLinkLocalIP(session, args):
brName = args['brName']
try:
cmd = ["ip", "route", "del", "169.254.0.0/16"]
txt = util.pread2(cmd)
except:
txt = ''
try:
cmd = ["ifconfig", brName, "169.254.0.1", "netmask", "255.255.0.0"]
txt = util.pread2(cmd)
except:
txt = ''
try:
cmd = ["ip", "route", "add", "169.254.0.0/16", "dev", brName, "src", "169.254.0.1"]
txt = util.pread2(cmd)
except:
txt = ''
txt = 'success'
return txt
@echo
def setFirewallRule(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/call_firewall.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" set firewall rule failed " )
txt = ''
return txt
@echo
def setLoadBalancerRule(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/call_loadbalancer.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
txt = 'success'
except:
util.SMlog(" set loadbalancer rule failed " )
txt = ''
return txt
@echo
def createFile(session, args):
file_path = args['filepath']
file_contents = args['filecontents']
try:
f = open(file_path, "w")
f.write(file_contents)
f.close()
txt = 'success'
except:
util.SMlog(" failed to create HA proxy cfg file ")
txt = ''
return txt
@echo
def deleteFile(session, args):
file_path = args["filepath"]
try:
if os.path.isfile(file_path):
os.remove(file_path)
txt = 'success'
except:
util.SMlog(" failed to remove HA proxy cfg file ")
txt = ''
return txt
@echo
def networkUsage(session, args):
sargs = args['args']
cmd = sargs.split(' ')
cmd.insert(0, "/opt/xensource/bin/networkUsage.sh")
cmd.insert(0, "/bin/bash")
try:
txt = util.pread2(cmd)
except:
util.SMlog(" network usage error " )
txt = ''
return txt
def get_private_nic(session, args):
vms = session.xenapi.VM.get_all()
host_uuid = args.get('host_uuid')
host = session.xenapi.host.get_by_uuid(host_uuid)
piflist = session.xenapi.host.get_PIFs(host)
mgmtnic = 'eth0'
for pif in piflist:
pifrec = session.xenapi.PIF.get_record(pif)
network = pifrec.get('network')
nwrec = session.xenapi.network.get_record(network)
if nwrec.get('name_label') == 'cloud-guest':
return pifrec.get('device')
if pifrec.get('management'):
mgmtnic = pifrec.get('device')
return mgmtnic
@echo
def can_bridge_firewall(session, args):
host_uuid = args.get('host_uuid')
try:
util.pread2(['iptables', '-N', 'BRIDGE-FIREWALL'])
util.pread2(['iptables', '-I', 'BRIDGE-FIREWALL', '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT'])
util.pread2(['iptables', '-D', 'FORWARD', '-j', 'RH-Firewall-1-INPUT'])
except:
util.SMlog('Chain BRIDGE-FIREWALL already exists')
privnic = get_private_nic(session, args)
result = 'true'
try:
util.pread2(['/bin/bash', '-c', 'iptables -n -L FORWARD | grep BRIDGE-FIREWALL'])
except:
try:
util.pread2(['iptables', '-I', 'FORWARD', '-m', 'physdev', '--physdev-is-bridged', '-j', 'BRIDGE-FIREWALL'])
util.pread2(['iptables', '-A', 'FORWARD', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', privnic, '-j', 'ACCEPT'])
util.pread2(['iptables', '-A', 'FORWARD', '-j', 'DROP'])
except:
result = 'false'
if not os.path.exists('/var/run/cloud'):
os.makedirs('/var/run/cloud')
cleanup_rules_for_dead_vms(session)
cleanup_rules(session, args)
return result
def ipset(ipsetname, proto, start, end, ips):
try:
util.pread2(['ipset', '-N', ipsetname, 'iptreemap'])
except:
util.SMlog("ipset chain already exists" + ipsetname)
result = True
ipsettmp = ''.join(''.join(ipsetname.split('-')).split('_')) + str(int(time.time()) % 1000)
try:
util.pread2(['ipset', '-N', ipsettmp, 'iptreemap'])
for ip in ips:
try:
util.pread2(['ipset', '-A', ipsettmp, ip])
except CommandException, cex:
if cex.reason.rfind('already in set') == -1:
raise
util.pread2(['ipset', '-W', ipsettmp, ipsetname])
util.pread2(['ipset', '-X', ipsettmp])
except:
util.SMlog("Failed to program ipset " + ipsetname)
result = False
return result
@echo
def destroy_network_rules_for_vm(session, args):
vm_name = args.pop('vmName')
vmchain = vm_name
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
if vm_name.startswith('i-') or vm_name.startswith('r-'):
vmchain = '-'.join(vm_name.split('-')[:-1])
vmchain_default = '-'.join(vm_name.split('-')[:-2]) + "-def"
try:
util.pread2(['iptables', '-F', vmchain_default])
util.pread2(['iptables', '-X', vmchain_default])
except:
util.SMlog("Ignoring failure to delete chain " + vmchain_default)
destroy_ebtables_rules(vmchain)
try:
util.pread2(['iptables', '-F', vmchain])
util.pread2(['iptables', '-X', vmchain])
except:
util.SMlog("Ignoring failure to delete chain " + vmchain)
remove_rule_log_for_vm(vm_name)
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-'] ]:
return 'true'
try:
setscmd = "ipset --save | grep " + vmchain + " | grep '^-N' | awk '{print $2}'"
setsforvm = util.pread2(['/bin/bash', '-c', setscmd]).split('\n')
for set in setsforvm:
if set != '':
util.pread2(['ipset', '-F', set])
util.pread2(['ipset', '-X', set])
except:
util.SMlog("Failed to destroy ipsets for %" % vm_name)
return 'true'
@echo
def destroy_ebtables_rules(vm_name):
if not os.path.exists('/usr/local/sbin/ebtables'):
return
delcmd = "/usr/local/sbin/ebtables-save | grep ROUTING | grep " + vm_name + " | sed 's/-A/-D/'"
delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n')
delcmds.pop()
for cmd in delcmds:
try:
dc = cmd.split(' ')
dc.insert(0, '/usr/local/sbin/ebtables')
dc.insert(1, '-t')
dc.insert(2, 'nat')
util.pread2(dc)
except:
util.SMlog("Ignoring failure to delete ebtables rules for vm " + vm_name)
chains = [vm_name+"-in", vm_name+"-out"]
for chain in chains:
try:
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-F', chain])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-X', chain])
except:
util.SMlog("Ignoring failure to delete ebtables chain for vm " + vm_name)
@echo
def default_ebtables_rules(vm_name, vif, vm_ip, vm_mac):
if not os.path.exists('/usr/local/sbin/ebtables'):
return
vmchain_in = vm_name + "-in"
vmchain_out = vm_name + "-out"
for chain in [vmchain_in, vmchain_out]:
try:
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-N', chain])
except:
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-F', chain])
try:
# -s ! 52:54:0:56:44:32 -j DROP
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', 'PREROUTING', '-i', vif, '-j', vmchain_in])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', 'POSTROUTING', '-o', vif, '-j', vmchain_out])
except:
util.SMlog("Failed to program default rules")
return 'false'
try:
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-i', vif, '-s', '!', vm_mac, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-s', '!', vm_mac, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-mac-src', '!', vm_mac, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-ip-src', '!', vm_ip, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_in, '-p', 'ARP', '-j', 'DROP'])
except:
util.SMlog("Failed to program default ebtables IN rules")
return 'false'
try:
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '--arp-mac-dst', '!', vm_mac, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-ip-dst', '!', vm_ip, '-j', 'DROP'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Request', '-j', 'ACCEPT'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '--arp-op', 'Reply', '-j', 'ACCEPT'])
util.pread2(['/usr/local/sbin/ebtables', '-t', 'nat', '-A', vmchain_out, '-p', 'ARP', '-j', 'DROP'])
except:
util.SMlog("Failed to program default ebtables OUT rules")
return 'false'
def format_ovs_vm_log_name(vmName):
vm_name = "ovs-%s" % vmName;
logfilename = "/var/run/cloud/" + vm_name +".log"
return logfilename
def remove_ovs_log_for_vm(vmName):
logfilename = format_ovs_vm_log_name(vmName)
result = True
try:
os.remove(logfilename)
except:
util.SMlog("Failed to delete ovs log file " + logfilename)
result = False
return result
def ovs_get_info_from_log(vmName, num):
logfilename = format_ovs_vm_log_name(vmName)
try:
lines = [line.rstrip() for line in open(logfilename)]
return lines[num]
except:
util.SMlog("Failed to open ovs log %s" % logfilename);
remove_ovs_log_for_vm(vmName)
return None
def ovs_get_common_info_from_log(vmName):
return ovs_get_info_from_log(vmName, 0)
def ovs_get_nic_info_from_log(vmName):
return ovs_get_info_from_log(vmName, 1)
def ovs_get_mac_info_from_log(vmName):
return ovs_get_info_from_log(vmName, 2)
def ovs_get_vlans_info_from_log(vmName):
return ovs_get_info_from_log(vmName, 3)
def ovs_get_ofports_info_from_log(vmName):
return ovs_get_info_from_log(vmName, 4)
def ovs_parse_common_info_from_log(vmName, num):
info = ovs_get_common_info_from_log(vmName)
if info == None:
return None
return info.split(",")[num]
def ovs_get_bridge_from_log(vmName):
return ovs_parse_common_info_from_log(vmName, 1)
def ovs_get_vm_id_from_log(vmName):
return ovs_parse_common_info_from_log(vmName, 2)
def ovs_get_seqno_from_log(vmName):
return ovs_parse_common_info_from_log(vmName, 3)
def ovs_get_tag_from_log(vmName):
return ovs_parse_common_info_from_log(vmName, 4)
def ovs_handle_rebooted_vm(session, vmName):
curr_domid = '-1'
(curr_domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName)
old_id = ovs_get_vm_id_from_log(vmName)
if curr_domid == old_id:
util.SMlog("OvsInfo:%s is normal" % vmName)
return True
util.SMlog("%s rebooted, reset flow for it" % vmName)
try:
vlanstr = ovs_get_vlans_info_from_log(vmName)
bridge = ovs_get_bridge_from_log(vmName)
except Exception, e:
util.SMlog(e.__str__())
util.SMlog("ovs get info from %s failed" % \
format_ovs_vm_log_name(vmName))
return False
i = 0
if vlanstr == None:
util.SMlog("OVSErr: cannot get vlanstr for %s" % vmName)
return False
tag = ovs_get_tag_from_log(vmName)
nics = []
macs = []
for vifr in vifrs:
vifName = "vif" + curr_domid + "." + vifr[0]
vlanRemapUtils(session, {"op":"setTag", "vifName":vifName, "bridge":bridge, "tag":tag})
vlanRemapUtils(session, {"op":"createFlow", "vifName":vifName, "bridge":bridge, "mac":vifr[1], "remap":vlanstr})
nics.append(vifName)
macs.append(vifr[1])
i += 1
seqno = ovs_get_seqno_from_log(vmName)
ofports = ovs_get_ofports_info_from_log(vmName)
ovs_write_vm_log(bridge, vmName, curr_domid, seqno, nics, macs, tag, vlanstr, ofports)
return True
@echo
def ovs_get_vm_log(session, args):
host_uuid = args.pop('host_uuid')
try:
thishost = session.xenapi.host.get_by_uuid(host_uuid)
hostrec = session.xenapi.host.get_record(thishost)
vms = hostrec.get('resident_VMs')
except Exception, e:
util.SMlog("Failed to get host from uuid %s, exception: %s" % (host_uuid, e.__str__()))
return ' '
result = []
try:
for name in [session.xenapi.VM.get_name_label(x) for x in vms]:
if 1 not in [ name.startswith(c) for c in ['r-', 'i-'] ]:
continue
ovs_handle_rebooted_vm(session, name)
if name.startswith('i-'):
info = ovs_get_common_info_from_log(name)
if info == None:
util.SMlog("ovs_get_common_info_from_log return None for %s" % name)
continue
result.append(info)
except Exception, e:
util.SMlog(e.__str__())
util.SMlog("OVs failed to get logs, better luck next time!")
return ";".join(result)
def ovs_write_vm_log(bridge, vmName, vmId, seqno, vifNames, macs, tag, vlans, ofports):
logfilename = format_ovs_vm_log_name(vmName)
util.SMlog("Writing ovs log to " + logfilename)
logf = open(logfilename, 'w')
output = ','.join([vmName, bridge, vmId, seqno, tag])
result = True
try:
logf.write(output)
logf.write('\n')
output = ','.join(vifNames)
logf.write(output)
logf.write('\n')
output = ','.join(macs)
logf.write(output)
logf.write('\n')
logf.write(vlans)
logf.write('\n')
logf.write(ofports)
logf.write('\n')
except:
util.SMlog("Failed to write to ovs log file " + logfilename)
result = False
logf.close()
return result
def ovs_delete_flow(session, args):
bridge = args.pop('bridge')
vm_name = args.pop('vmName')
reCreate = args.pop('reCreate')
macs = ovs_get_mac_info_from_log(vm_name)
vlans = ovs_get_vlans_info_from_log(vm_name)
ofports = ovs_get_ofports_info_from_log(vm_name)
if macs == None or vlans == None or ofports == None:
return 'ERROR_LOG'
vlanRemapUtils(session, {"op":"deleteFlow", "bridge":bridge, \
"ofports":ofports, "macs":macs, "remap":vlans, "reCreate":reCreate})
remove_ovs_log_for_vm(vm_name)
return 'SUCCESS'
def ovs_get_domid_vifrs_hostuuid(session, vm_name):
def get_vif_field(name, field):
return session.xenapi.VIF.get_record(name).get(field)
try:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
return 'NO_VM'
vm_rec = session.xenapi.VM.get_record(vm[0])
vm_vifs = vm_rec.get('VIFs')
vifrs = []
for vif in vm_vifs:
rec = (get_vif_field(vif, 'device'), get_vif_field(vif, 'MAC'))
vifrs.append(rec)
domid = vm_rec.get('domid')
host = vm_rec.get('resident_on')
host_rec = session.xenapi.host.get_record(host)
uuid = host_rec.get('uuid')
util.SMlog("OVSINFO: (domid:%s, uuid:%s)" % (domid, uuid))
return (domid, vifrs, uuid)
except:
util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name)
return (-1, [], "-1")
def ovs_set_tag_and_flow(session, args):
bridge = args.pop('bridge')
vm_name = args.pop('vmName')
vlanStr = args.pop('vlans')
tag = args.pop('tag')
seqno = args.pop('seqno')
(domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vm_name)
if domid == '-1':
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
return 'NO_DOMID'
if len(vifrs) == 0:
return 'SUCCESS'
#delete old flows first
ovs_delete_flow(session, {"bridge":bridge, "vmName":vm_name, "reCreate":"false"})
if vlanStr.startswith("/"): vlanStr = vlanStr[1:]
if vlanStr.endswith("/"): vlanStr = vlanStr[:-1]
vlans = vlanStr.split("/")
vifNames = []
macs = []
for vifr in vifrs:
vifName = "vif" + domid + "." + vifr[0]
vifNames.append(vifName)
mac = vifr[1]
macs.append(mac)
vlanRemapUtils(session, {"op":"setTag", "vifName":vifName, "bridge":bridge, "tag":tag})
vlanRemapUtils(session, {"op":"createFlow", "vifName":vifName, "bridge":bridge, "mac":mac, "remap":vlanStr})
ofports = vlanRemapUtils(session, {"op":"askPorts", "bridge":bridge, "vifNames":",".join(vifNames)})
res = ovs_write_vm_log(bridge, vm_name, domid, seqno, vifNames, macs, tag, vlanStr, ofports)
if res == 'false':
return 'CREATE_LOG_FAILED'
#see if there is rebooted vm to handle
ovs_get_vm_log(session, {"host_uuid":hostuuid})
return 'SUCCESS'
@echo
def default_network_rules_systemvm(session, args):
vm_name = args.pop('vmName')
try:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
return 'false'
vm_rec = session.xenapi.VM.get_record(vm[0])
vm_vifs = vm_rec.get('VIFs')
vifnums = [session.xenapi.VIF.get_record(vif).get('device') for vif in vm_vifs]
domid = vm_rec.get('domid')
except:
util.SMlog("### Failed to get domid or vif list for vm ##" + vm_name)
return 'false'
if domid == '-1':
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
return 'false'
vifs = ["vif" + domid + "." + v for v in vifnums]
#vm_name = '-'.join(vm_name.split('-')[:-1])
vmchain = vm_name
if vm_name.startswith('r-'):
vmchain = '-'.join(vm_name.split('-')[:-1])
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
try:
util.pread2(['iptables', '-N', vmchain])
except:
util.pread2(['iptables', '-F', vmchain])
for vif in vifs:
try:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', vif, '-j', vmchain])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', vif, '-j', vmchain])
except:
util.SMlog("Failed to program default rules")
return 'false'
util.pread2(['iptables', '-A', vmchain, '-j', 'ACCEPT'])
if write_rule_log_for_vm(vm_name, '-1', '_ignore_', domid, '_initial_', '-1') == False:
util.SMlog("Failed to log default network rules for systemvm, ignoring")
return 'true'
@echo
def default_network_rules(session, args):
vmName = args.pop('vmName')
vm_name = vmName
vm_ip = args.pop('vmIP')
vm_id = args.pop('vmID')
vm_mac = args.pop('vmMAC')
try:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
util.SMlog("### Failed to get record for vm " + vm_name)
return 'false'
vm_rec = session.xenapi.VM.get_record(vm[0])
domid = vm_rec.get('domid')
except:
util.SMlog("### Failed to get domid for vm " + vm_name)
return 'false'
if domid == '-1':
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
return 'false'
vif = "vif" + domid + ".0"
tap = "tap" + domid + ".0"
vifs = [vif]
try:
util.pread2(['ifconfig', tap])
vifs.append(tap)
except:
pass
delete_rules_for_vm_in_bridge_firewall_chain(vm_name)
vmchain = '-'.join(vm_name.split('-')[:-1])
vmchain_default = '-'.join(vm_name.split('-')[:-2]) + "-def"
destroy_ebtables_rules(vmchain)
try:
util.pread2(['iptables', '-N', vmchain])
except:
util.pread2(['iptables', '-F', vmchain])
try:
util.pread2(['iptables', '-N', vmchain_default])
except:
util.pread2(['iptables', '-F', vmchain_default])
try:
for v in vifs:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', vmchain_default, '-m', 'state', '--state', 'RELATED,ESTABLISHED', '-j', 'ACCEPT'])
#allow dhcp
for v in vifs:
util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-p', 'udp', '--dport', '67', '--sport', '68', '-j', 'ACCEPT'])
util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-p', 'udp', '--dport', '68', '--sport', '67', '-j', 'ACCEPT'])
#don't let vm spoof its ip address
for v in vifs:
util.pread2(['iptables', '-A', vmchain_default, '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '--source', vm_ip, '-j', 'RETURN'])
util.pread2(['iptables', '-A', vmchain_default, '-j', vmchain])
except:
util.SMlog("Failed to program default rules for vm " + vm_name)
return 'false'
for v in vifs:
default_ebtables_rules(vm_name, v, vm_ip, vm_mac)
if write_rule_log_for_vm(vmName, vm_id, vm_ip, domid, '_initial_', '-1') == False:
util.SMlog("Failed to log default network rules, ignoring")
util.SMlog("Programmed default rules for vm " + vm_name)
return 'true'
def check_domid_changed(session, vmName):
curr_domid = '-1'
try:
vm = session.xenapi.VM.get_by_name_label(vmName)
if len(vm) != 1:
util.SMlog("### Could not get record for vm ## " + vmName)
else:
vm_rec = session.xenapi.VM.get_record(vm[0])
curr_domid = vm_rec.get('domid')
except:
util.SMlog("### Failed to get domid for vm ## " + vmName)
logfilename = "/var/run/cloud/" + vmName +".log"
if not os.path.exists(logfilename):
return ['-1', curr_domid]
lines = (line.rstrip() for line in open(logfilename))
[_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1']
for line in lines:
[_vmName,_vmID,_vmIP,old_domid,_signature,_seqno] = line.split(',')
break
return [curr_domid, old_domid]
def delete_rules_for_vm_in_bridge_firewall_chain(vmName):
vm_name = vmName
vmchain = vm_name
if vm_name.startswith('i-') or vm_name.startswith('r-'):
vmchain = '-'.join(vm_name.split('-')[:-1])
delcmd = "iptables -S BRIDGE-FIREWALL | grep " + vmchain + " | sed 's/-A/-D/'"
delcmds = util.pread2(['/bin/bash', '-c', delcmd]).split('\n')
delcmds.pop()
for cmd in delcmds:
try:
dc = cmd.split(' ')
dc.insert(0, 'iptables')
dc.pop()
util.pread2(dc)
except:
util.SMlog("Ignoring failure to delete rules for vm " + vmName)
def network_rules_for_rebooted_vm(session, vmName):
vm_name = vmName
[curr_domid, old_domid] = check_domid_changed(session, vmName)
if curr_domid == old_domid:
return True
if old_domid == '-1':
return True
if curr_domid == '-1':
return True
util.SMlog("Found a rebooted VM -- reprogramming rules for " + vmName)
delete_rules_for_vm_in_bridge_firewall_chain(vmName)
if 1 in [ vm_name.startswith(c) for c in ['r-', 's-', 'v-'] ]:
default_network_rules_systemvm(session, {"vmName":vmName})
return True
vif = "vif" + curr_domid + ".0"
tap = "tap" + curr_domid + ".0"
vifs = [vif]
try:
util.pread2(['ifconfig', tap])
vifs.append(tap)
except:
pass
vmchain = '-'.join(vm_name.split('-')[:-1])
vmchain_default = '-'.join(vm_name.split('-')[:-2]) + "-def"
for v in vifs:
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-out', v, '-j', vmchain_default])
util.pread2(['iptables', '-A', 'BRIDGE-FIREWALL', '-m', 'physdev', '--physdev-is-bridged', '--physdev-in', v, '-j', vmchain_default])
#change antispoof rule in vmchain
try:
delcmd = "iptables -S " + vmchain_default + " | grep physdev-in | sed 's/-A/-D/'"
inscmd = "iptables -S " + vmchain_default + " | grep physdev-in | grep vif | sed -r 's/vif[0-9]+.0/" + vif + "/' | sed 's/-A/-I/'"
inscmd2 = "iptables -S " + vmchain_default + " | grep physdev-in | grep tap | sed -r 's/tap[0-9]+.0/" + tap + "/' | sed 's/-A/-I/'"
ipts = []
for cmd in [delcmd, inscmd, inscmd2]:
cmds = util.pread2(['/bin/bash', '-c', cmd]).split('\n')
cmds.pop()
for c in cmds:
ipt = c.split(' ')
ipt.insert(0, 'iptables')
ipt.pop()
ipts.append(ipt)
for ipt in ipts:
try:
util.pread2(ipt)
except:
util.SMlog("Failed to rewrite antispoofing rules for vm " + vmName)
except:
util.SMlog("No rules found for vm " + vmchain)
rewrite_rule_log_for_vm(vmName, curr_domid)
return True
def rewrite_rule_log_for_vm(vm_name, new_domid):
logfilename = "/var/run/cloud/" + vm_name +".log"
if not os.path.exists(logfilename):
return
lines = (line.rstrip() for line in open(logfilename))
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1']
for line in lines:
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',')
break
write_rule_log_for_vm(_vmName, _vmID, '0.0.0.0', new_domid, _signature, '-1')
def get_rule_log_for_vm(session, vmName):
vm_name = vmName;
logfilename = "/var/run/cloud/" + vm_name +".log"
if not os.path.exists(logfilename):
return ''
lines = (line.rstrip() for line in open(logfilename))
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1']
for line in lines:
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',')
break
return ','.join([_vmName, _vmID, _vmIP, _domID, _signature, _seqno])
@echo
def get_rule_logs_for_vms(session, args):
host_uuid = args.pop('host_uuid')
try:
thishost = session.xenapi.host.get_by_uuid(host_uuid)
hostrec = session.xenapi.host.get_record(thishost)
vms = hostrec.get('resident_VMs')
except:
util.SMlog("Failed to get host from uuid " + host_uuid)
return ' '
result = []
try:
for name in [session.xenapi.VM.get_name_label(x) for x in vms]:
if 1 not in [ name.startswith(c) for c in ['r-', 's-', 'v-', 'i-'] ]:
continue
network_rules_for_rebooted_vm(session, name)
if name.startswith('i-'):
log = get_rule_log_for_vm(session, name)
result.append(log)
except:
util.SMlog("Failed to get rule logs, better luck next time!")
return ";".join(result)
@echo
def cleanup_rules_for_dead_vms(session):
try:
vms = session.xenapi.VM.get_all()
cleaned = 0
for vm_name in [session.xenapi.VM.get_name_label(x) for x in vms]:
if 1 in [ vm_name.startswith(c) for c in ['r-', 'i-', 's-', 'v-'] ]:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
continue
vm_rec = session.xenapi.VM.get_record(vm[0])
state = vm_rec.get('power_state')
if state != 'Running' and state != 'Paused':
util.SMlog("vm " + vm_name + " is not running, cleaning up")
destroy_network_rules_for_vm(session, {'vmName':vm_name})
cleaned = cleaned+1
util.SMlog("Cleaned up rules for " + str(cleaned) + " vms")
except:
util.SMlog("Failed to cleanup rules for dead vms!")
@echo
def cleanup_rules(session, args):
try:
chainscmd = "iptables-save | grep '^:' | grep -v '.*-def' | awk '{print $1}' | cut -d':' -f2"
chains = util.pread2(['/bin/bash', '-c', chainscmd]).split('\n')
cleaned = 0
cleanup = []
for chain in chains:
if 1 in [ chain.startswith(c) for c in ['r-', 'i-', 's-', 'v-'] ]:
if chain.startswith('i-') or chain.startswith('r-'):
vm_name = chain + '-untagged'
else:
vm_name = chain
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
util.SMlog("chain " + chain + " does not correspond to a vm, cleaning up")
cleanup.append(vm_name)
continue
vm_rec = session.xenapi.VM.get_record(vm[0])
state = vm_rec.get('power_state')
if state != 'Running' and state != 'Paused':
util.SMlog("vm " + vm_name + " is not running, cleaning up")
cleanup.append(vm_name)
for vmname in cleanup:
destroy_network_rules_for_vm(session, {'vmName':vmname})
util.SMlog("Cleaned up rules for " + str(len(cleanup)) + " chains")
return str(len(cleanup))
except:
util.SMlog("Failed to cleanup rules !")
return '-1';
@echo
def check_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno):
vm_name = vmName;
logfilename = "/var/run/cloud/" + vm_name +".log"
if not os.path.exists(logfilename):
return [True, True, True, True, True, True]
lines = (line.rstrip() for line in open(logfilename))
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = ['_', '-1', '_', '-1', '_', '-1']
try:
for line in lines:
[_vmName,_vmID,_vmIP,_domID,_signature,_seqno] = line.split(',')
break
except:
util.SMlog("Failed to parse log file for vm " + vm_name)
remove_rule_log_for_vm(vm_name)
return False
return [(vm_name != _vmName), \
(vmID != _vmID), \
(vmIP != _vmIP), \
(domID != _domID), \
(signature != _signature), \
(seqno != _seqno)]
@echo
def write_rule_log_for_vm(vmName, vmID, vmIP, domID, signature, seqno):
vm_name = vmName
logfilename = "/var/run/cloud/" + vm_name +".log"
util.SMlog("Writing log to " + logfilename)
logf = open(logfilename, 'w')
output = ','.join([vmName, vmID, vmIP, domID, signature, seqno])
result = True
try:
logf.write(output)
logf.write('\n')
except:
util.SMlog("Failed to write to rule log file " + logfilename)
result = False
logf.close()
return result
@echo
def remove_rule_log_for_vm(vmName):
vm_name = vmName
logfilename = "/var/run/cloud/" + vm_name +".log"
result = True
try:
os.remove(logfilename)
except:
util.SMlog("Failed to delete rule log file " + logfilename)
result = False
return result
@echo
def network_rules(session, args):
try:
vm_name = args.get('vmName')
vmName = vm_name
vm_ip = args.get('vmIP')
vm_id = args.get('vmID')
signature = args.pop('signature')
seqno = args.pop('seqno')
try:
vm = session.xenapi.VM.get_by_name_label(vm_name)
if len(vm) != 1:
util.SMlog("### Could not get record for vm ## " + vm_name)
return 'false'
vm_rec = session.xenapi.VM.get_record(vm[0])
domid = vm_rec.get('domid')
except:
util.SMlog("### Failed to get domid for vm ## " + vm_name)
return 'false'
if domid == '-1':
util.SMlog("### Failed to get domid for vm (-1): " + vm_name)
return 'false'
vif = "vif" + domid + ".0"
tap = "tap" + domid + ".0"
vifs = [vif]
try:
util.pread2(['ifconfig', tap])
vifs.append(tap)
except:
pass
vm_name = '-'.join(vm_name.split('-')[:-1])
vmchain = vm_name
changes = check_rule_log_for_vm (vmName, vm_id, vm_ip, domid, signature, seqno)
if not 1 in changes:
util.SMlog("Rules already programmed for vm " + vm_name)
return 'true'
if changes[1] or changes[2] or changes[3]:
util.SMlog("Change detected in vmId or vmIp or domId, resetting default rules")
default_network_rules(session, args)
rules = args.pop('rules')
lines = rules.split(' ')
util.SMlog(" programming network rules for IP: " + vm_ip + " vmname=" + vm_name)
util.pread2(['iptables', '-F', vmchain])
for line in lines:
tokens = line.split(':')
if len(tokens) != 4:
continue
protocol = tokens[0]
start = tokens[1]
end = tokens[2]
cidrs = tokens.pop();
ips = cidrs.split(",")
ips.pop()
allow_any = False
if '0.0.0.0/0' in ips:
i = ips.index('0.0.0.0/0')
del ips[i]
allow_any = True
range = start + ":" + end
if ips:
ipsetname = vm_name + "_" + protocol + "_" + start + "_" + end
if start == "-1":
ipsetname = vm_name + "_" + protocol + "_any"
if ipset(ipsetname, protocol, start, end, ips) == False:
util.SMlog(" failed to create ipset for rule " + str(tokens))
if protocol == 'all':
iptables = ['iptables', '-I', vmchain, '-m', 'state', '--state', 'NEW', '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT']
elif protocol != 'icmp':
iptables = ['iptables', '-I', vmchain, '-p', protocol, '-m', protocol, '--dport', range, '-m', 'state', '--state', 'NEW', '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT']
else:
range = start + "/" + end
if start == "-1":
range = "any"
iptables = ['iptables', '-I', vmchain, '-p', 'icmp', '--icmp-type', range, '-m', 'set', '--match-set', ipsetname, 'src', '-j', 'ACCEPT']
util.pread2(iptables)
util.SMlog(iptables)
if allow_any and protocol != 'all':
if protocol != 'icmp':
iptables = ['iptables', '-I', vmchain, '-p', protocol, '-m', protocol, '--dport', range, '-m', 'state', '--state', 'NEW', '-j', 'ACCEPT']
else:
range = start + "/" + end
if start == "-1":
range = "any"
iptables = ['iptables', '-I', vmchain, '-p', 'icmp', '--icmp-type', range, '-j', 'ACCEPT']
util.pread2(iptables)
util.SMlog(iptables)
util.pread2(['iptables', '-A', vmchain, '-j', 'DROP'])
if write_rule_log_for_vm(vmName, vm_id, vm_ip, domid, signature, seqno) == False:
return 'false'
return 'true'
except:
util.SMlog("Failed to network rule !")
if __name__ == "__main__":
XenAPIPlugin.dispatch({"pingtest": pingtest, "setup_iscsi":setup_iscsi, "gethostvmstats": gethostvmstats, "getvncport": getvncport, "getgateway": getgateway, "preparemigration": preparemigration, "setIptables": setIptables, "pingdomr": pingdomr, "pingxenserver": pingxenserver, "ipassoc": ipassoc, "vm_data": vm_data, "savePassword": savePassword, "saveDhcpEntry": saveDhcpEntry, "setFirewallRule": setFirewallRule, "setLoadBalancerRule": setLoadBalancerRule, "createFile": createFile, "deleteFile": deleteFile, "networkUsage": networkUsage, "network_rules":network_rules, "can_bridge_firewall":can_bridge_firewall, "default_network_rules":default_network_rules, "destroy_network_rules_for_vm":destroy_network_rules_for_vm, "default_network_rules_systemvm":default_network_rules_systemvm, "get_rule_logs_for_vms":get_rule_logs_for_vms, "setLinkLocalIP":setLinkLocalIP, "lt2p_vpn":lt2p_vpn, "vlanRemapUtils":vlanRemapUtils, "ovs_set_tag_and_flow":ovs_set_tag_and_flow, "ovs_get_vm_log":ovs_get_vm_log,"ovs_delete_flow":ovs_delete_flow,"cleanup_rules":cleanup_rules})