mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
795 lines
20 KiB
Python
Executable File
795 lines
20 KiB
Python
Executable File
#!/usr/bin/python
|
|
# Version @VERSION@
|
|
#
|
|
# 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
|
|
from os.path import exists as _exists
|
|
from time import localtime as _localtime, asctime as _asctime
|
|
|
|
vSwitchDBPidFile = "/var/run/openvswitch/ovsdb-server.pid"
|
|
vSwitchDBDaemonName = "ovsdb-server"
|
|
vSwitchPidFile = "/var/run/openvswitch/ovs-vswitchd.pid"
|
|
vsctlPath = "/usr/bin/ovs-vsctl"
|
|
vSwitchDaemonName = "ovs-vswitchd"
|
|
|
|
logFile = "/var/log/ovsgre.log"
|
|
fLog = None
|
|
|
|
global result
|
|
|
|
errors = \
|
|
{"NO_DB_PID_FILE" : "NO_DB_PID_FILE", \
|
|
"DB_NOT_RUN" : "DB_NOT_RUN", \
|
|
"NO_SWITCH_PID_FILE" : "NO_SWITCH_PID_FILE", \
|
|
"SWITCH_NOT_RUN" : "SWITCH_NOT_RUN", \
|
|
"NO_VSCTL" : "NO_VSCTL", \
|
|
"COMMAND_FAILED" : "COMMAND_FAILED", \
|
|
"TUNNEL_EXISTED" : "TUNNEL_EXISTED", \
|
|
"NO_INPORT" : "NO_INPORT", \
|
|
"NO_OFPORT" : "NO_OFPORT", \
|
|
|
|
"ERR_ARGS_NUM" : "ERR_ARGS_NUM", \
|
|
"ERROR_OP" : "ERROR_OP", \
|
|
"SUCCESS" : "SUCCESS", \
|
|
}
|
|
|
|
class ovs_log(object):
|
|
def __init__(self, name):
|
|
n = "ovs-%s" % name;
|
|
logfilename = "/var/run/cloud/" + n +".log"
|
|
|
|
self.name = logfilename
|
|
self.vmName = name
|
|
self.bridge = ""
|
|
self.domId = ""
|
|
self.seqno = ""
|
|
self.tag = ""
|
|
self.vifs = ""
|
|
self.macs = ""
|
|
self.vlans = ""
|
|
self.ofports = ""
|
|
|
|
def write(self):
|
|
log = open(self.name, "w")
|
|
log.write("vmName=%s" % self.vmName)
|
|
log.write("\n")
|
|
log.write("bridge=%s" % self.bridge)
|
|
log.write("\n")
|
|
log.write("domId=%s" % self.domId)
|
|
log.write("\n")
|
|
log.write("seqno=%s" % self.seqno)
|
|
log.write("\n")
|
|
log.write("tag=%s" % self.tag)
|
|
log.write("\n")
|
|
log.write("vifs=%s" % self.vifs)
|
|
log.write("\n")
|
|
log.write("macs=%s" % self.macs)
|
|
log.write("\n")
|
|
log.write("vlans=%s" % self.vlans)
|
|
log.write("\n")
|
|
log.write("ofports=%s" % self.ofports)
|
|
log.close()
|
|
|
|
def read(self):
|
|
try:
|
|
lines = [line.rstrip() for line in open(self.name)]
|
|
for i in lines:
|
|
if "=" not in i:
|
|
util.SMlog("invalid line(%s) in %s" % (i, self.name))
|
|
continue
|
|
|
|
(key,value) = i.split("=")
|
|
if key == "vmName":
|
|
self.vmName = value
|
|
elif key == "bridge":
|
|
self.bridge = value
|
|
elif key == "domId":
|
|
self.domId = value
|
|
elif key == "seqno":
|
|
self.seqno = value
|
|
elif key == "tag":
|
|
self.tag = value
|
|
elif key == "vifs":
|
|
self.vifs = value
|
|
elif key == "macs":
|
|
self.macs = value
|
|
elif key == "vlans":
|
|
self.vlans = value
|
|
elif key == "ofports":
|
|
self.ofports = value
|
|
except Exception, e:
|
|
util.SMlog(e.__str__())
|
|
util.SMlog("Failed to open ovs log %s" % self.name);
|
|
|
|
def get_common_info(self):
|
|
self.read()
|
|
return "%s,%s,%s,%s,%s" % (self.vmName, self.bridge, self.domId,
|
|
self.seqno, self.tag)
|
|
|
|
def remove(self):
|
|
try:
|
|
os.remove(self.name)
|
|
except:
|
|
util.SMlog("Failed to delete ovs log file " + self.name)
|
|
|
|
def open_log ():
|
|
global fLog
|
|
|
|
try:
|
|
if fLog == None:
|
|
fLog = open (logFile, "a")
|
|
except IOError, e:
|
|
#print e
|
|
pass
|
|
|
|
def pr (str):
|
|
global fLog
|
|
|
|
if fLog != None:
|
|
str = "[%s]:" % _asctime (_localtime()) + str + "\n"
|
|
fLog.write (str)
|
|
|
|
def close_log ():
|
|
global fLog
|
|
|
|
if fLog != None:
|
|
fLog.close ()
|
|
|
|
def is_process_run (pidFile, name):
|
|
try:
|
|
fpid = open (pidFile, "r")
|
|
pid = fpid.readline ()
|
|
fpid.close ()
|
|
except IOError, e:
|
|
return -1
|
|
|
|
pid = pid[:-1]
|
|
ps = os.popen ("ps -ae")
|
|
for l in ps:
|
|
if pid in l and name in l:
|
|
ps.close ()
|
|
return 0
|
|
|
|
ps.close ()
|
|
return -2
|
|
|
|
def is_tool_exist (name):
|
|
if _exists (name):
|
|
return 0
|
|
return -1
|
|
|
|
|
|
def check_switch ():
|
|
global result
|
|
|
|
ret = is_process_run (vSwitchDBPidFile, vSwitchDBDaemonName);
|
|
if ret < 0:
|
|
if ret == -1: result = errors["NO_DB_PID_FILE"]
|
|
if ret == -2: result = errors["DB_NOT_RUN"]
|
|
return -1
|
|
|
|
ret = is_process_run (vSwitchPidFile, vSwitchDaemonName)
|
|
if ret < 0:
|
|
if ret == -1: result = errors["NO_SWITCH_PID_FILE"]
|
|
if ret == -2: result = errors["SWITCH_NOT_RUN"]
|
|
return -1
|
|
|
|
if is_tool_exist (vsctlPath) < 0:
|
|
result = errors["NO_VSCTL"]
|
|
return -1
|
|
|
|
return 0
|
|
|
|
def do_cmd (cmds, lines=False):
|
|
cmd = ""
|
|
for i in cmds:
|
|
cmd += " "
|
|
cmd += i
|
|
|
|
pr("do command '%s'" % cmd)
|
|
f = os.popen (cmd)
|
|
if lines == True:
|
|
res = f.readlines ()
|
|
else:
|
|
res = f.readline ()
|
|
res = res[:-1]
|
|
f.close ()
|
|
|
|
if lines == False:
|
|
pr("command output '%s'" % res)
|
|
return res
|
|
|
|
######################## GRE creation utils ##########################
|
|
# UUID's format is 8-4-4-4-12
|
|
def is_uuid (uuid):
|
|
list = uuid.split ("-")
|
|
|
|
if len (list) != 5:
|
|
return -1
|
|
|
|
if len (list[0]) != 8 or len (list[1]) != 4 \
|
|
or len (list[2]) != 4 or len (list[3]) != 4 \
|
|
or len (list[4]) != 12:
|
|
return -1
|
|
|
|
return 0
|
|
|
|
def check_gre (bridge, remoteIP, greKey):
|
|
ports = get_ports_on_bridge(bridge)
|
|
if ports == None:
|
|
return "[]"
|
|
|
|
for i in ports:
|
|
ifaces = get_interface_on_port(i)
|
|
if ifaces == None:
|
|
continue
|
|
|
|
for j in ifaces:
|
|
if j == '[]':
|
|
continue
|
|
options = get_field_of_interface(j, "options")
|
|
if remoteIP in options and greKey in options:
|
|
pr("WARNING: GRE tunnel for remote_ip=%s key=%s already here, \
|
|
interface(%s)" % (remoteIP, greKey, j))
|
|
return get_field_of_interface(j, "ofport")
|
|
|
|
return "[]"
|
|
|
|
def ovs_create_gre (session, args):
|
|
global result
|
|
bridge = args.pop("bridge")
|
|
remoteIP = args.pop("remoteIP")
|
|
greKey = args.pop("greKey")
|
|
srcHost = args.pop("from")
|
|
dstHost = args.pop("to")
|
|
|
|
name = "%s-%s" % (srcHost, dstHost)
|
|
res = check_gre(bridge, remoteIP, greKey)
|
|
if res != "[]":
|
|
result = "SUCCESS:%s" % res
|
|
return result
|
|
|
|
wait = [vsctlPath, "--timeout=30 wait-until bridge %s -- get bridge %s name" % \
|
|
(bridge, bridge)]
|
|
res = do_cmd(wait)
|
|
if bridge not in res:
|
|
pr("WARNIING:Can't find bridge %s for creating tunnel!" % bridge)
|
|
result = "COMMAND_FAILED_NO_BRIDGE"
|
|
return result
|
|
|
|
createInterface = [vsctlPath, "create interface", "name=%s" % name, \
|
|
'type=gre options:"remote_ip=%s key=%s"' % (remoteIP, greKey)]
|
|
ifaceUUID = do_cmd (createInterface)
|
|
if is_uuid (ifaceUUID) < 0:
|
|
pr("create interface failed, %s is not UUID" % ifaceUUID)
|
|
result = "COMMAND_FAILED_CREATE_INTERFACE_FAILED"
|
|
return result
|
|
|
|
createPort = [vsctlPath, "create port", "name=%s" % name, \
|
|
"interfaces=[%s]" % ifaceUUID]
|
|
portUUID = do_cmd (createPort)
|
|
if is_uuid (portUUID) < 0:
|
|
pr("create port failed, %s is not UUID" % portUUID)
|
|
result = "COMMAND_FAILED_CREATE_PORT_FAILED"
|
|
return result
|
|
|
|
addBridge = [vsctlPath, "add bridge %s" % bridge, "ports %s" % portUUID]
|
|
do_cmd (addBridge)
|
|
|
|
wait = [vsctlPath, "--timeout=30 wait-until port %s -- get port %s name" % \
|
|
(name, name)]
|
|
res = do_cmd(wait)
|
|
if name in res:
|
|
port = get_field_of_interface(name, "ofport");
|
|
noFlood = [vsctlPath, "ovs-ofctl mod-port %s %s noflood" % (bridge, \
|
|
name)]
|
|
do_cmd(noFlood)
|
|
result = "SUCCESS:%s" % port
|
|
else:
|
|
pr("create gre tunnel failed")
|
|
result = "COMMAND_FAILED_CREATE_TUNNEL_FAILED"
|
|
|
|
return result
|
|
######################## End GRE creation utils ##########################
|
|
|
|
######################## Flow creation utils ##########################
|
|
def get_ports_on_bridge(bridge):
|
|
listBr = [vsctlPath, "list br", bridge]
|
|
res = do_cmd(listBr, True)
|
|
|
|
for i in res:
|
|
if "ports" in i:
|
|
(x, str) = i.split(":")
|
|
str = str.lstrip().rstrip()
|
|
str = str[1:]
|
|
str = str[:-1]
|
|
return str.split(",")
|
|
return None
|
|
|
|
def get_filed_of_port(nameOruuid, field):
|
|
listport = [vsctlPath, "list port", nameOruuid]
|
|
res = do_cmd(listport, True)
|
|
|
|
for i in res:
|
|
if field in i:
|
|
(x, r) = i.split(":")
|
|
return r.lstrip().rstrip()
|
|
return None
|
|
|
|
def get_field_of_interface(nameOruuid, field):
|
|
listIface = [vsctlPath, "list interface", nameOruuid]
|
|
res = do_cmd(listIface, True)
|
|
|
|
for i in res:
|
|
if field in i:
|
|
(x, r) = i.split(":")
|
|
return r.lstrip().rstrip()
|
|
return None
|
|
|
|
def strip(str, direction="default"):
|
|
str = str.lstrip().rstrip()
|
|
if direction == "left":
|
|
return str[1:]
|
|
if direction == "right":
|
|
return str[:-1]
|
|
if direction == "both":
|
|
str = str[1:]
|
|
str = str[:-1]
|
|
return str
|
|
return str
|
|
|
|
def get_vif_port(bridge, vifName):
|
|
portUuids = get_ports_on_bridge(bridge)
|
|
if portUuids == None:
|
|
pr("No ports on bridge %s" % bridge)
|
|
return None
|
|
|
|
for i in portUuids:
|
|
name = get_filed_of_port(i, "name")
|
|
if name == None:
|
|
pr("WARNING: no name found for %s" % name)
|
|
continue
|
|
|
|
name = strip(name, "both")
|
|
if name == vifName:
|
|
return get_field_of_interface(vifName, "ofport")
|
|
return None
|
|
|
|
def get_interface_on_port(nameOruuid):
|
|
listPort = [vsctlPath, "list port", nameOruuid]
|
|
res = do_cmd(listPort, True)
|
|
|
|
for i in res:
|
|
if "interfaces" in i:
|
|
(x, str) = i.split(":")
|
|
str = strip(str, "both")
|
|
return str.split(",")
|
|
return None
|
|
|
|
def get_gre_ports(bridge):
|
|
portUuids = get_ports_on_bridge(bridge)
|
|
if portUuids == None:
|
|
pr("WARNING:No ports on bridge %s" % bridge)
|
|
return []
|
|
|
|
OfPorts = []
|
|
for i in portUuids:
|
|
iface = get_filed_of_port(i, "interfaces")
|
|
iface = strip(iface, "both")
|
|
type = get_field_of_interface(iface, "type")
|
|
if type == 'gre':
|
|
port = get_field_of_interface(iface, "ofport")
|
|
if port != '[]':
|
|
OfPorts.append(port)
|
|
|
|
return OfPorts
|
|
|
|
def get_ofports_by_tag(bridge, tag):
|
|
portUuids = get_ports_on_bridge(bridge)
|
|
if portUuids == None:
|
|
pr("WARNING:No ports on bridge %s" % bridge)
|
|
return []
|
|
|
|
OfPorts = []
|
|
for i in portUuids:
|
|
t = get_filed_of_port(i, "tag")
|
|
if t != tag:
|
|
pr("Skip port %s with tag=%s" % (i, t))
|
|
continue
|
|
|
|
iface = get_filed_of_port(i, "interfaces")
|
|
iface = strip(iface, "both")
|
|
port = get_field_of_interface(iface, "ofport")
|
|
if port != '[]':
|
|
OfPorts.append(port)
|
|
|
|
return OfPorts
|
|
|
|
def format_flow(inPort, vlan, mac, outPut):
|
|
flow = "in_port=%s dl_vlan=%s dl_dst=%s idle_timeout=0 hard_timeout=0 \
|
|
priority=10000 actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut)
|
|
return flow
|
|
|
|
def format_drop_flow(inPort):
|
|
flow = "in_port=%s priority=1000 idle_timeout=0 hard_timeout=0 \
|
|
actions=drop" % inPort
|
|
return flow
|
|
|
|
def add_drop_flow(bridge, port):
|
|
flow = format_drop_flow(port)
|
|
add_flow(bridge, flow)
|
|
|
|
def del_flow(bridge, mac):
|
|
param = "dl_dst=%s" % mac
|
|
flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
|
do_cmd(flow)
|
|
|
|
def del_arp_and_dhcp_flow(bridge, vlan, inPort):
|
|
param = "dl_type=0x0806 dl_vlan=%s in_port=%s" % (vlan, inPort)
|
|
flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
|
do_cmd(flow)
|
|
|
|
param = "dl_type=0x0800 nw_proto=17 tp_dst=68 dl_vlan=%s, in_port=%s" % (vlan, inPort)
|
|
flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
|
do_cmd(flow)
|
|
|
|
param = "dl_type=0x0800 nw_proto=17 tp_dst=67 dl_vlan=%s, in_port=%s" % (vlan, inPort)
|
|
flow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
|
|
do_cmd(flow)
|
|
|
|
def format_normal_flow():
|
|
flow = "priority=0 idle_timeout=0 hard_timeout=0 actions=normal"
|
|
return flow
|
|
|
|
def format_dhcp_flow(bridge, inPort, vlan, ports):
|
|
outputs = ''
|
|
for i in ports:
|
|
str = "output:%s," % i
|
|
outputs += str
|
|
outputs = outputs[:-1]
|
|
flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=17 tp_dst=67 idle_timeout=0 hard_timeout=0 \
|
|
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
|
return flow
|
|
|
|
def format_dhcp_client_flow(bridge, inPort, vlan, ports):
|
|
outputs = ''
|
|
for i in ports:
|
|
str = "output:%s," % i
|
|
outputs += str
|
|
outputs = outputs[:-1]
|
|
flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=17 tp_dst=68 idle_timeout=0 hard_timeout=0 \
|
|
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
|
return flow
|
|
|
|
def format_arp_flow(bridge, inPort, vlan, ports):
|
|
outputs = ''
|
|
for i in ports:
|
|
str = "output:%s," % i
|
|
outputs += str
|
|
|
|
outputs = outputs[:-1]
|
|
flow = "in_port=%s dl_vlan=%s dl_type=0x0806 idle_timeout=0 hard_timeout=0 \
|
|
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
|
|
return flow
|
|
|
|
def create_flow (bridge, vifName, mac, vlans):
|
|
global result
|
|
|
|
output = get_vif_port(bridge, vifName)
|
|
if output == None:
|
|
pr("WARNING: cannot find ofport for %s" % vifName)
|
|
return errors["NO_OFPORT"]
|
|
return -1
|
|
if output == '[]':
|
|
pr("WARNING: ofport is [] for %s" % vifName)
|
|
return errors["NO_OFPORT"]
|
|
return -1
|
|
|
|
#set remap here, remap has format e.g. 1/22/200/13/16
|
|
pr("")
|
|
pr("Create flow for vlans=%s" % vlans)
|
|
for v in vlans.split(","):
|
|
try:
|
|
(vlan, inPort) = v.split(":")
|
|
flow = format_flow(inPort, vlan, mac, output)
|
|
add_flow(bridge, flow)
|
|
except Exception, e:
|
|
pr(e.__str__())
|
|
pr("invalid map")
|
|
|
|
# add normal flow make switch work as L2/L3 switch
|
|
flow = format_normal_flow()
|
|
add_flow(bridge, flow)
|
|
|
|
inports = get_gre_ports(bridge)
|
|
for i in inports:
|
|
add_drop_flow(bridge, i)
|
|
|
|
return errors["SUCCESS"]
|
|
######################## End Flow creation utils ##########################
|
|
|
|
def set_tag(bridge, vifName, vlan):
|
|
# The startVM command is slow, we may wait for a while for it creates vif on
|
|
# open vswitch
|
|
pr("Waiting for %s ..." % vifName)
|
|
waitPortCmd = [vsctlPath, "--timeout=10 wait-until port %s -- get port %s name" % \
|
|
(vifName, vifName)]
|
|
do_cmd (waitPortCmd)
|
|
pr("%s is here" % vifName)
|
|
|
|
if get_vif_port(bridge, vifName) == None:
|
|
pr("WARNING: %s is not on bridge %s" % (vifName, bridge))
|
|
return 0
|
|
|
|
pr("Set tag")
|
|
set_tagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan]
|
|
do_cmd (set_tagCmd)
|
|
return 0
|
|
|
|
def ask_ports(bridge, vifNames):
|
|
vifs = vifNames.split(",")
|
|
if len(vifs) == 0:
|
|
return ' '
|
|
|
|
ofports = []
|
|
for vif in vifs:
|
|
op = get_vif_port(bridge, vif)
|
|
if op == None:
|
|
pr("ask_ports: no port(bridge:%s, vif:%s)" % (bridge, vif))
|
|
continue
|
|
ofports.append(op)
|
|
|
|
return ",".join(ofports)
|
|
|
|
def delete_vm_flows(bridge, vmName, reCreate=True):
|
|
log = ovs_log(vmName)
|
|
log.read()
|
|
|
|
macs = log.macs;
|
|
for i in macs.split(","):
|
|
del_flow(bridge, i)
|
|
pr("Delete flows for %s" % i)
|
|
|
|
vlans = log.vlans
|
|
for v in vlans.split(","):
|
|
try:
|
|
(vlan, inPort) = v.split(":")
|
|
del_arp_and_dhcp_flow(bridge, vlan, inPort)
|
|
except Exception, e:
|
|
pr(e.__str__())
|
|
pr("invalid map")
|
|
|
|
if reCreate == False:
|
|
return
|
|
|
|
bridge = log.bridge
|
|
tag = log.tag
|
|
noneGreOfPorts = get_ofports_by_tag(bridge, tag)
|
|
|
|
try:
|
|
noneGreOfPorts.remove(log.ofports)
|
|
except Exception, e:
|
|
pr(e.__str__())
|
|
pr("ofport %s of %s is not on bridge %s" % (log.ofports, log.vmName,
|
|
bridge))
|
|
|
|
if len(noneGreOfPorts) != 0:
|
|
set_arp_and_dhcp_flow(bridge, vlans, tag, noneGreOfPorts)
|
|
|
|
# add normal flow make switch work as L2/L3 switch
|
|
flow = format_normal_flow()
|
|
add_flow(bridge, flow)
|
|
|
|
log.remove()
|
|
|
|
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
|
|
|
|
|
|
def ovs_handle_rebooted_vm(session, vmName):
|
|
curr_domid = '-1'
|
|
log = ovs_log(vmName)
|
|
log.read()
|
|
|
|
(curr_domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName)
|
|
|
|
old_id = log.domId;
|
|
if curr_domid == old_id:
|
|
util.SMlog("OvsInfo:%s is normal" % vmName)
|
|
return True
|
|
|
|
util.SMlog("%s rebooted, reset flow for it" % vmName)
|
|
vlans = log.vlans;
|
|
bridge = log.bridge
|
|
tag = log.tag
|
|
for vifr in vifrs:
|
|
vifName = "vif" + curr_domid + "." + vifr[0]
|
|
set_tag(bridge, vifName, tag)
|
|
create_flow(bridge, vifName, vifr[1], vlans)
|
|
|
|
log.domId = curr_domid
|
|
log.write()
|
|
|
|
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-'):
|
|
log = ovs_log(name)
|
|
info = log.get_common_info()
|
|
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):
|
|
log = ovs_log(vmName)
|
|
log.read()
|
|
log.bridge = bridge
|
|
log.vmName = vmName
|
|
log.domId = vmId
|
|
log.seqno = seqno
|
|
log.vifs = vifNames
|
|
log.macs = macs
|
|
log.tag = tag
|
|
log.vlans = vlans
|
|
log.ofports = ofports
|
|
log.write()
|
|
|
|
util.SMlog("Writing ovs log to " + log.name)
|
|
|
|
@echo
|
|
def ovs_delete_flow(session, args):
|
|
bridge = args.pop('bridge')
|
|
vmName = args.pop('vmName')
|
|
|
|
delete_vm_flows(bridge, vmName)
|
|
return 'SUCCESS'
|
|
|
|
def ovs_get_domid_vifrs_hostuuid(session, vmName):
|
|
def get_vif_field(name, field):
|
|
return session.xenapi.VIF.get_record(name).get(field)
|
|
|
|
try:
|
|
vm = session.xenapi.VM.get_by_name_label(vmName)
|
|
if len(vm) != 1:
|
|
return (-1, [], "-1")
|
|
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 ##" + vmName)
|
|
return (-1, [], "-1")
|
|
|
|
def add_flow(bridge, flow):
|
|
param = bridge + ' "%s"' % flow
|
|
addflow = ["ovs-ofctl add-flow", param]
|
|
do_cmd (addflow)
|
|
|
|
def set_arp_and_dhcp_flow(bridge, vlans, tag, ofports):
|
|
for v in vlans.split(","):
|
|
try:
|
|
(vlan, inPort) = v.split(":")
|
|
arpFlow = format_arp_flow(bridge, inPort, vlan, ofports)
|
|
add_flow(bridge, arpFlow)
|
|
|
|
dhcpFlow = format_dhcp_flow(bridge, inPort, vlan, ofports)
|
|
add_flow(bridge, dhcpFlow)
|
|
|
|
dhcpClientFlow = format_dhcp_client_flow(bridge, inPort, vlan, ofports)
|
|
add_flow(bridge, dhcpClientFlow)
|
|
except Exception, e:
|
|
pr(e.__str__())
|
|
pr("invalid map")
|
|
|
|
@echo
|
|
def ovs_set_arp_and_dhcp_flow(session, args):
|
|
vlans = args.pop('vlans')
|
|
bridge = args.pop('bridge')
|
|
tag = args.pop('tag')
|
|
|
|
pr("ovs_set_arp_and_dhcp_flow: bridge=%s, vlans=%s, tag=%s" % (bridge,
|
|
vlans, tag))
|
|
if vlans == '[]':
|
|
pr("No need to create arp and dhcp flow")
|
|
return 'SUCCESS'
|
|
|
|
ofports = get_ofports_by_tag(bridge, tag)
|
|
if len(ofports) == 0:
|
|
pr("No VMs, skip set arp and dhcp flow for tag=%s" % tag)
|
|
return 'SUCCESS'
|
|
|
|
set_arp_and_dhcp_flow(bridge, vlans, tag, ofports)
|
|
return 'SUCCESS'
|
|
|
|
@echo
|
|
def ovs_set_tag_and_flow(session, args):
|
|
bridge = args.pop('bridge')
|
|
vmName = args.pop('vmName')
|
|
vlans = args.pop('vlans')
|
|
tag = args.pop('tag')
|
|
seqno = args.pop('seqno')
|
|
|
|
(domid, vifrs, hostuuid) = ovs_get_domid_vifrs_hostuuid(session, vmName)
|
|
|
|
if domid == '-1':
|
|
util.SMlog("### Failed to get domid for vm (-1): " + vmName)
|
|
return 'NO_DOMID'
|
|
|
|
if len(vifrs) == 0:
|
|
return 'SUCCESS'
|
|
|
|
pr("ovs_set_tag_and_flow: bridge=%s, vmName=%s, vlans=%s, tag=%s, seqno=%s" %
|
|
(bridge, vmName, vlans, tag, seqno))
|
|
#delete old flows first
|
|
delete_vm_flows(bridge, vmName, False)
|
|
|
|
vifNames = []
|
|
vlans = strip(vlans, "both")
|
|
macs = []
|
|
for vifr in vifrs:
|
|
vifName = "vif" + domid + "." + vifr[0]
|
|
vifNames.append(vifName)
|
|
mac = vifr[1]
|
|
macs.append(mac)
|
|
set_tag(bridge, vifName, tag)
|
|
create_flow(bridge, vifName, mac, vlans)
|
|
|
|
vifs = ",".join(vifNames)
|
|
ofports = ask_ports(bridge, vifs)
|
|
ovs_write_vm_log(bridge, vmName, domid, seqno, vifs, ",".join(macs), tag, vlans, ofports)
|
|
|
|
#see if there is rebooted vm to handle
|
|
ovs_get_vm_log(session, {"host_uuid":hostuuid})
|
|
ovs_set_arp_and_dhcp_flow(session, {"bridge":bridge, "tag":tag, "vlans":vlans})
|
|
return 'SUCCESS'
|
|
|
|
if __name__ == "__main__":
|
|
open_log()
|
|
XenAPIPlugin.dispatch({"ovs_create_gre":ovs_create_gre, "ovs_set_tag_and_flow":ovs_set_tag_and_flow, "ovs_get_vm_log":ovs_get_vm_log,"ovs_delete_flow":ovs_delete_flow})
|
|
close_log()
|
|
|