mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
CS-14605: OVS cleanup
pep8 fixes to python scripts removing superflous/unused code from python scripts
This commit is contained in:
parent
2bf0c7f7ff
commit
b6c2c4c506
@ -1,5 +1,5 @@
|
||||
# Common function for Cloudstack's XenAPI plugins
|
||||
#
|
||||
#
|
||||
# Copyright (C) 2012 Citrix Systems
|
||||
|
||||
import ConfigParser
|
||||
@ -13,20 +13,22 @@ DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
|
||||
DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||
DEFAULT_LOG_FILE = "/var/log/cloudstack_plugins.log"
|
||||
|
||||
PLUGIN_CONFIG_PATH='/etc/xensource/cloudstack_plugins.conf'
|
||||
PLUGIN_CONFIG_PATH = "/etc/xensource/cloudstack_plugins.conf"
|
||||
OVSDB_PID_PATH = "/var/run/openvswitch/ovsdb-server.pid"
|
||||
OVSDB_DAEMON_PATH = "ovsdb-server"
|
||||
OVS_PID_PATH = "/var/run/openvswitch/ovs-vswitchd.pid"
|
||||
OVS_DAEMON_PATH = "ovs-vswitchd"
|
||||
VSCTL_PATH='/usr/bin/ovs-vsctl'
|
||||
OFCTL_PATH='/usr/bin/ovs-ofctl'
|
||||
XE_PATH= "/opt/xensource/bin/xe"
|
||||
VSCTL_PATH = "/usr/bin/ovs-vsctl"
|
||||
OFCTL_PATH = "/usr/bin/ovs-ofctl"
|
||||
XE_PATH = "/opt/xensource/bin/xe"
|
||||
|
||||
|
||||
class PluginError(Exception):
|
||||
"""Base Exception class for all plugin errors."""
|
||||
def __init__(self, *args):
|
||||
Exception.__init__(self, *args)
|
||||
|
||||
|
||||
def setup_logging(log_file=None):
|
||||
debug = False
|
||||
verbose = False
|
||||
@ -39,15 +41,15 @@ def setup_logging(log_file=None):
|
||||
try:
|
||||
options = config.options('LOGGING')
|
||||
if 'debug' in options:
|
||||
debug = config.getboolean('LOGGING','debug')
|
||||
debug = config.getboolean('LOGGING', 'debug')
|
||||
if 'verbose' in options:
|
||||
verbose = config.getboolean('LOGGING','verbose')
|
||||
verbose = config.getboolean('LOGGING', 'verbose')
|
||||
if 'format' in options:
|
||||
log_format = config.get('LOGGING','format')
|
||||
log_format = config.get('LOGGING', 'format')
|
||||
if 'date_format' in options:
|
||||
log_date_format = config.get('LOGGING','date_format')
|
||||
log_date_format = config.get('LOGGING', 'date_format')
|
||||
if 'file' in options:
|
||||
log_file_2 = config.get('LOGGING','file')
|
||||
log_file_2 = config.get('LOGGING', 'file')
|
||||
except ValueError:
|
||||
# configuration file contained invalid attributes
|
||||
# ignore them
|
||||
@ -55,7 +57,7 @@ def setup_logging(log_file=None):
|
||||
except ConfigParser.NoSectionError:
|
||||
# Missing 'Logging' section in configuration file
|
||||
pass
|
||||
|
||||
|
||||
root_logger = logging.root
|
||||
if debug:
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
@ -66,7 +68,7 @@ def setup_logging(log_file=None):
|
||||
formatter = logging.Formatter(log_format, log_date_format)
|
||||
|
||||
log_filename = log_file or log_file_2 or DEFAULT_LOG_FILE
|
||||
|
||||
|
||||
logfile_handler = logging.FileHandler(log_filename)
|
||||
logfile_handler.setFormatter(formatter)
|
||||
root_logger.addHandler(logfile_handler)
|
||||
@ -94,60 +96,65 @@ def do_cmd(cmd):
|
||||
return output
|
||||
|
||||
|
||||
def _is_process_run (pidFile, name):
|
||||
def _is_process_run(pidFile, name):
|
||||
try:
|
||||
fpid = open (pidFile, "r")
|
||||
pid = fpid.readline ()
|
||||
fpid.close ()
|
||||
fpid = open(pidFile, "r")
|
||||
pid = fpid.readline()
|
||||
fpid.close()
|
||||
except IOError, e:
|
||||
return -1
|
||||
|
||||
pid = pid[:-1]
|
||||
ps = os.popen ("ps -ae")
|
||||
ps = os.popen("ps -ae")
|
||||
for l in ps:
|
||||
if pid in l and name in l:
|
||||
ps.close ()
|
||||
ps.close()
|
||||
return 0
|
||||
|
||||
ps.close ()
|
||||
ps.close()
|
||||
return -2
|
||||
|
||||
def _is_tool_exist (name):
|
||||
|
||||
def _is_tool_exist(name):
|
||||
if os.path.exists(name):
|
||||
return 0
|
||||
return -1
|
||||
|
||||
|
||||
def check_switch ():
|
||||
def check_switch():
|
||||
global result
|
||||
|
||||
ret = _is_process_run (OVSDB_PID_PATH, OVSDB_DAEMON_PATH)
|
||||
ret = _is_process_run(OVSDB_PID_PATH, OVSDB_DAEMON_PATH)
|
||||
if ret < 0:
|
||||
if ret == -1: return "NO_DB_PID_FILE"
|
||||
if ret == -2: return "DB_NOT_RUN"
|
||||
if ret == -1:
|
||||
return "NO_DB_PID_FILE"
|
||||
if ret == -2:
|
||||
return "DB_NOT_RUN"
|
||||
|
||||
ret = _is_process_run (OVS_PID_PATH, OVS_DAEMON_PATH)
|
||||
ret = _is_process_run(OVS_PID_PATH, OVS_DAEMON_PATH)
|
||||
if ret < 0:
|
||||
if ret == -1: return "NO_SWITCH_PID_FILE"
|
||||
if ret == -2: return "SWITCH_NOT_RUN"
|
||||
if ret == -1:
|
||||
return "NO_SWITCH_PID_FILE"
|
||||
if ret == -2:
|
||||
return "SWITCH_NOT_RUN"
|
||||
|
||||
if _is_tool_exist (VSCTL_PATH) < 0:
|
||||
if _is_tool_exist(VSCTL_PATH) < 0:
|
||||
return "NO_VSCTL"
|
||||
|
||||
if _is_tool_exist (OFCTL_PATH) < 0:
|
||||
if _is_tool_exist(OFCTL_PATH) < 0:
|
||||
return "NO_OFCTL"
|
||||
|
||||
return "SUCCESS"
|
||||
|
||||
|
||||
def _build_flow_expr(**kwargs):
|
||||
is_delete_expr = kwargs.get('delete', False)
|
||||
is_delete_expr = kwargs.get('delete', False)
|
||||
flow = ""
|
||||
if not is_delete_expr:
|
||||
flow = "hard_timeout=%s,idle_timeout=%s,priority=%s"\
|
||||
% (kwargs.get('hard_timeout','0'),
|
||||
kwargs.get('idle_timeout','0'),
|
||||
kwargs.get('priority','1'))
|
||||
% (kwargs.get('hard_timeout', '0'),
|
||||
kwargs.get('idle_timeout', '0'),
|
||||
kwargs.get('priority', '1'))
|
||||
in_port = 'in_port' in kwargs and ",in_port=%s" % kwargs['in_port'] or ''
|
||||
dl_type = 'dl_type' in kwargs and ",dl_type=%s" % kwargs['dl_type'] or ''
|
||||
dl_src = 'dl_src' in kwargs and ",dl_src=%s" % kwargs['dl_src'] or ''
|
||||
@ -156,7 +163,7 @@ def _build_flow_expr(**kwargs):
|
||||
nw_dst = 'nw_dst' in kwargs and ",nw_dst=%s" % kwargs['nw_dst'] or ''
|
||||
proto = 'proto' in kwargs and ",%s" % kwargs['proto'] or ''
|
||||
ip = ('nw_src' in kwargs or 'nw_dst' in kwargs) and ',ip' or ''
|
||||
flow = (flow + in_port + dl_type + dl_src + dl_dst +
|
||||
flow = (flow + in_port + dl_type + dl_src + dl_dst +
|
||||
(ip or proto) + nw_src + nw_dst)
|
||||
return flow
|
||||
|
||||
@ -174,17 +181,18 @@ def add_flow(bridge, **kwargs):
|
||||
|
||||
|
||||
def del_flows(bridge, **kwargs):
|
||||
"""
|
||||
"""
|
||||
Removes flows according to criteria passed as keyword.
|
||||
"""
|
||||
flow = _build_flow_expr(delete=True, **kwargs)
|
||||
# out_port condition does not exist for all flow commands
|
||||
out_port = 'out_port' in kwargs and ",out_port=%s" % kwargs['out_port'] or ''
|
||||
out_port = ("out_port" in kwargs and
|
||||
",out_port=%s" % kwargs['out_port'] or '')
|
||||
flow = flow + out_port
|
||||
delFlow = [OFCTL_PATH, 'del-flows', bridge, flow]
|
||||
do_cmd(delFlow)
|
||||
|
||||
|
||||
|
||||
|
||||
def del_all_flows(bridge):
|
||||
delFlow = [OFCTL_PATH, "del-flows", bridge]
|
||||
do_cmd(delFlow)
|
||||
|
||||
@ -1,794 +0,0 @@
|
||||
#!/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()
|
||||
|
||||
@ -1,300 +1,243 @@
|
||||
#!/usr/bin/python
|
||||
# Version @VERSION@
|
||||
#
|
||||
# A plugin for executing script needed by vmops cloud
|
||||
# Creates a tunnel mesh across xenserver hosts
|
||||
# Enforces broadcast drop rules on ingress GRE tunnels
|
||||
|
||||
import cloudstack_pluginlib as lib
|
||||
import logging
|
||||
import os, sys, time
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import time
|
||||
import XenAPIPlugin
|
||||
|
||||
sys.path.append("/opt/xensource/sm/")
|
||||
import util
|
||||
|
||||
from time import localtime as _localtime, asctime as _asctime
|
||||
|
||||
xePath= "/opt/xensource/bin/xe"
|
||||
xePath = "/opt/xensource/bin/xe"
|
||||
lib.setup_logging("/var/log/ovstunnel.log")
|
||||
|
||||
def find_vifs_v5(xs_nw_uuid):
|
||||
logging.debug("Fetching vifs on networks - for XS version 5.x")
|
||||
vif_uuids_cmd = [xePath, 'network-list', 'uuid=%s' %xs_nw_uuid,
|
||||
'params=VIF-uuids', '--minimal']
|
||||
vif_uuids_str = lib.do_cmd(vif_uuids_cmd)
|
||||
vif_uuids = vif_uuids_str.split(';')
|
||||
vifs = []
|
||||
for vif_uuid in vif_uuids:
|
||||
vif_uuid = vif_uuid.strip()
|
||||
is_attached_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid,
|
||||
'params=currently-attached', '--minimal']
|
||||
is_attached = lib.do_cmd(is_attached_cmd)
|
||||
# Consider only attached VIFs
|
||||
if is_attached == 'false':
|
||||
continue
|
||||
vm_uuid_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid,
|
||||
'params=vm-uuid', '--minimal']
|
||||
vm_uuid = lib.do_cmd(vm_uuid_cmd)
|
||||
dom_id_cmd = [xePath, 'vm-list', 'uuid=%s' %vm_uuid,
|
||||
'params=dom-id', '--minimal']
|
||||
dom_id = lib.do_cmd(dom_id_cmd)
|
||||
device_cmd = [xePath, 'vif-list', 'uuid=%s' %vif_uuid,
|
||||
'params=device', '--minimal']
|
||||
device = lib.do_cmd(device_cmd)
|
||||
vifs.append("vif%s.%s" % (dom_id, device))
|
||||
logging.debug("Vifs on network:%s" %vifs)
|
||||
vif_ofports = []
|
||||
for vif in vifs:
|
||||
vif_ofport_cmd=[lib.VSCTL_PATH, 'get', 'interface', vif, 'ofport']
|
||||
vif_ofport = lib.do_cmd(vif_ofport_cmd).strip()
|
||||
if vif_ofport.endswith('\n'):
|
||||
vif_ofport = vif_ofport[:-1]
|
||||
vif_ofports.append(vif_ofport.strip())
|
||||
return vif_ofports
|
||||
|
||||
|
||||
def find_vifs_v6(xs_nw_uuid):
|
||||
logging.debug("Fetching vifs on networks - for XS version 6.x")
|
||||
cmd_vif_ofports = [lib.VSCTL_PATH, "--", "--columns=ofport",
|
||||
"find", "interface",
|
||||
"external_ids:xs-network-uuid=%s" % xs_nw_uuid,
|
||||
"type!=gre"]
|
||||
vif_ofports_str = lib.do_cmd(cmd_vif_ofports)
|
||||
vif_ofports = []
|
||||
for line in vif_ofports_str.split('\n'):
|
||||
elements = line.split(':')
|
||||
if len(elements)==2:
|
||||
# ensure no trailing \n is returned
|
||||
if elements[1].endswith('\n'):
|
||||
elements[1] = elements[1][:-1]
|
||||
vif_ofports.append(elements[1].strip())
|
||||
return vif_ofports
|
||||
|
||||
vif_ofport_list_handlers = {
|
||||
'5': find_vifs_v5,
|
||||
'6': find_vifs_v6}
|
||||
|
||||
|
||||
def block_ipv6_v5(bridge):
|
||||
lib.add_flow(bridge, priority=65000, dl_type='0x86dd', actions='drop')
|
||||
lib.add_flow(bridge, priority=65000, dl_type='0x86dd', actions='drop')
|
||||
|
||||
|
||||
def block_ipv6_v6(bridge):
|
||||
lib.add_flow(bridge, priority=65000, proto='ipv6', actions='drop')
|
||||
lib.add_flow(bridge, priority=65000, proto='ipv6', actions='drop')
|
||||
|
||||
|
||||
block_ipv6_handlers = {
|
||||
'5': block_ipv6_v5,
|
||||
'6': block_ipv6_v6}
|
||||
|
||||
|
||||
class PluginError(Exception):
|
||||
"""Base Exception class for all plugin errors."""
|
||||
def __init__(self, *args):
|
||||
Exception.__init__(self, *args)
|
||||
'5': block_ipv6_v5,
|
||||
'6': block_ipv6_v6}
|
||||
|
||||
|
||||
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 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 setup_ovs_bridge(session, args):
|
||||
bridge = args.pop("bridge")
|
||||
key = args.pop("key")
|
||||
xs_nw_uuid = args.pop("xs_nw_uuid")
|
||||
cs_host_id = args.pop("cs_host_id")
|
||||
|
||||
res = lib.check_switch()
|
||||
if res != "SUCCESS":
|
||||
return "FAILURE:%s" %res
|
||||
bridge = args.pop("bridge")
|
||||
key = args.pop("key")
|
||||
xs_nw_uuid = args.pop("xs_nw_uuid")
|
||||
cs_host_id = args.pop("cs_host_id")
|
||||
|
||||
logging.debug("About to manually create the bridge:%s" %bridge)
|
||||
# create a bridge with the same name as the xapi network
|
||||
# also associate gre key in other config attribute
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "--", "--may-exist", "add-br", bridge,
|
||||
"--", "set", "bridge", bridge,
|
||||
"other_config:gre_key=%s" % key])
|
||||
logging.debug("Bridge has been manually created:%s" %res)
|
||||
# TODO: Make sure xs-network-uuid is set into external_ids
|
||||
lib.do_cmd([lib.VSCTL_PATH, "set", "Bridge", bridge,
|
||||
"external_ids:xs-network-uuid=%s" % xs_nw_uuid])
|
||||
# Non empty result means something went wrong
|
||||
if res:
|
||||
result = "FAILURE:%s" %res
|
||||
else:
|
||||
# Verify the bridge actually exists, with the gre_key properly set
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "get", "bridge",
|
||||
bridge, "other_config:gre_key"])
|
||||
if key in res:
|
||||
result = "SUCCESS:%s" %bridge
|
||||
else:
|
||||
result = "FAILURE:%s" %res
|
||||
# Finally note in the xenapi network object that the network has
|
||||
# been configured
|
||||
xs_nw_uuid = lib.do_cmd([lib.XE_PATH, "network-list",
|
||||
"bridge=%s" % bridge, "--minimal"])
|
||||
lib.do_cmd([lib.XE_PATH,"network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
"other-config:is-ovs-tun-network=True"])
|
||||
conf_hosts = lib.do_cmd([lib.XE_PATH,"network-param-get",
|
||||
"uuid=%s" % xs_nw_uuid,
|
||||
"param-name=other-config",
|
||||
"param-key=ovs-host-setup", "--minimal"])
|
||||
conf_hosts = cs_host_id + (conf_hosts and ',%s' % conf_hosts or '')
|
||||
lib.do_cmd([lib.XE_PATH,"network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
"other-config:ovs-host-setup=%s" %conf_hosts])
|
||||
|
||||
# BLOCK IPv6 - Flow spec changes with ovs version
|
||||
host_list_cmd = [lib.XE_PATH, 'host-list', '--minimal']
|
||||
host_list_str = lib.do_cmd(host_list_cmd)
|
||||
host_uuid = host_list_str.split(',')[0].strip()
|
||||
version_cmd = [lib.XE_PATH, 'host-param-get', 'uuid=%s' % host_uuid,
|
||||
'param-name=software-version',
|
||||
'param-key=product_version']
|
||||
version = lib.do_cmd(version_cmd).split('.')[0]
|
||||
block_ipv6_handlers[version](bridge)
|
||||
logging.debug("Setup_ovs_bridge completed with result:%s" %result)
|
||||
return result
|
||||
res = lib.check_switch()
|
||||
if res != "SUCCESS":
|
||||
return "FAILURE:%s" % res
|
||||
|
||||
logging.debug("About to manually create the bridge:%s" % bridge)
|
||||
# create a bridge with the same name as the xapi network
|
||||
# also associate gre key in other config attribute
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "--", "--may-exist", "add-br", bridge,
|
||||
"--", "set", "bridge", bridge,
|
||||
"other_config:gre_key=%s" % key])
|
||||
logging.debug("Bridge has been manually created:%s" % res)
|
||||
# TODO: Make sure xs-network-uuid is set into external_ids
|
||||
lib.do_cmd([lib.VSCTL_PATH, "set", "Bridge", bridge,
|
||||
"external_ids:xs-network-uuid=%s" % xs_nw_uuid])
|
||||
# Non empty result means something went wrong
|
||||
if res:
|
||||
result = "FAILURE:%s" % res
|
||||
else:
|
||||
# Verify the bridge actually exists, with the gre_key properly set
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "get", "bridge",
|
||||
bridge, "other_config:gre_key"])
|
||||
if key in res:
|
||||
result = "SUCCESS:%s" % bridge
|
||||
else:
|
||||
result = "FAILURE:%s" % res
|
||||
# Finally note in the xenapi network object that the network has
|
||||
# been configured
|
||||
xs_nw_uuid = lib.do_cmd([lib.XE_PATH, "network-list",
|
||||
"bridge=%s" % bridge, "--minimal"])
|
||||
lib.do_cmd([lib.XE_PATH, "network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
"other-config:is-ovs-tun-network=True"])
|
||||
conf_hosts = lib.do_cmd([lib.XE_PATH, "network-param-get",
|
||||
"uuid=%s" % xs_nw_uuid,
|
||||
"param-name=other-config",
|
||||
"param-key=ovs-host-setup", "--minimal"])
|
||||
conf_hosts = cs_host_id + (conf_hosts and ',%s' % conf_hosts or '')
|
||||
lib.do_cmd([lib.XE_PATH, "network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
"other-config:ovs-host-setup=%s" % conf_hosts])
|
||||
|
||||
# BLOCK IPv6 - Flow spec changes with ovs version
|
||||
host_list_cmd = [lib.XE_PATH, 'host-list', '--minimal']
|
||||
host_list_str = lib.do_cmd(host_list_cmd)
|
||||
host_uuid = host_list_str.split(',')[0].strip()
|
||||
version_cmd = [lib.XE_PATH, 'host-param-get', 'uuid=%s' % host_uuid,
|
||||
'param-name=software-version',
|
||||
'param-key=product_version']
|
||||
version = lib.do_cmd(version_cmd).split('.')[0]
|
||||
block_ipv6_handlers[version](bridge)
|
||||
logging.debug("Setup_ovs_bridge completed with result:%s" % result)
|
||||
return result
|
||||
|
||||
|
||||
@echo
|
||||
def destroy_ovs_bridge(session, args):
|
||||
bridge = args.pop("bridge")
|
||||
res = lib.check_switch()
|
||||
# TODO: Must complete this routine
|
||||
if res != "SUCCESS":
|
||||
return res
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "del-br", bridge])
|
||||
logging.debug("Bridge has been manually removed:%s" %res)
|
||||
if res:
|
||||
result = "FAILURE:%s" %res
|
||||
else:
|
||||
# Note that the bridge has been removed on xapi network object
|
||||
xs_nw_uuid = lib.do_cmd([xePath, "network-list",
|
||||
"bridge=%s" % bridge, "--minimal"])
|
||||
#lib.do_cmd([xePath,"network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
# "other-config:ovs-setup=False"])
|
||||
result = "SUCCESS:%s" %bridge
|
||||
bridge = args.pop("bridge")
|
||||
res = lib.check_switch()
|
||||
if res != "SUCCESS":
|
||||
return res
|
||||
res = lib.do_cmd([lib.VSCTL_PATH, "del-br", bridge])
|
||||
logging.debug("Bridge has been manually removed:%s" % res)
|
||||
if res:
|
||||
result = "FAILURE:%s" % res
|
||||
else:
|
||||
# Note that the bridge has been removed on xapi network object
|
||||
xs_nw_uuid = lib.do_cmd([xePath, "network-list",
|
||||
"bridge=%s" % bridge, "--minimal"])
|
||||
#FIXME: WOW, this an error
|
||||
#lib.do_cmd([xePath,"network-param-set", "uuid=%s" % xs_nw_uuid,
|
||||
# "other-config:ovs-setup=False"])
|
||||
result = "SUCCESS:%s" % bridge
|
||||
|
||||
logging.debug("Destroy_ovs_bridge completed with result:%s" % result)
|
||||
return result
|
||||
|
||||
|
||||
logging.debug("Destroy_ovs_bridge completed with result:%s" %result)
|
||||
return result
|
||||
|
||||
|
||||
@echo
|
||||
def create_tunnel(session, args):
|
||||
bridge = args.pop("bridge")
|
||||
remote_ip = args.pop("remote_ip")
|
||||
gre_key = args.pop("key")
|
||||
src_host = args.pop("from")
|
||||
dst_host = args.pop("to")
|
||||
|
||||
logging.debug("Entering create_tunnel")
|
||||
|
||||
res = lib.check_switch()
|
||||
if res != "SUCCESS":
|
||||
logging.debug("Openvswitch running: NO")
|
||||
return "FAILURE:%s" %res
|
||||
|
||||
# We need to keep the name below 14 characters
|
||||
# src and target are enough - consider a fixed length hash
|
||||
name = "t%s-%s-%s" % (gre_key, src_host, dst_host)
|
||||
|
||||
# Verify the xapi bridge to be created
|
||||
# NOTE: Timeout should not be necessary anymore
|
||||
wait = [lib.VSCTL_PATH, "--timeout=30", "wait-until", "bridge", bridge, "--",
|
||||
"get", "bridge", bridge, "name"]
|
||||
res = lib.do_cmd(wait)
|
||||
if bridge not in res:
|
||||
logging.debug("WARNING:Can't find bridge %s for creating " +
|
||||
"tunnel!" % bridge)
|
||||
return "FAILURE:NO_BRIDGE"
|
||||
logging.debug("bridge %s for creating tunnel - VERIFIED" % bridge)
|
||||
tunnel_setup = False
|
||||
drop_flow_setup = False
|
||||
try:
|
||||
# Create a port and configure the tunnel interface for it
|
||||
add_tunnel = [lib.VSCTL_PATH, "add-port", bridge, name, "--", "set", "interface",
|
||||
name, "type=gre", "options:key=%s" % gre_key,
|
||||
"options:remote_ip=%s" % remote_ip]
|
||||
lib.do_cmd(add_tunnel)
|
||||
tunnel_setup = True
|
||||
# verify port
|
||||
verify_port = [lib.VSCTL_PATH, "get", "port", name, "interfaces"]
|
||||
res = lib.do_cmd(verify_port)
|
||||
# Expecting python-style list as output
|
||||
iface_list = []
|
||||
if len(res) > 2:
|
||||
iface_list = res.strip()[1:-1].split(',')
|
||||
if len(iface_list) != 1:
|
||||
logging.debug("WARNING: Unexpected output while verifying " +
|
||||
"port %s on bridge %s" %(name, bridge))
|
||||
return "FAILURE:VERIFY_PORT_FAILED"
|
||||
|
||||
# verify interface
|
||||
iface_uuid = iface_list[0]
|
||||
verify_interface_key = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "options:key"]
|
||||
verify_interface_ip = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "options:remote_ip"]
|
||||
|
||||
key_validation = lib.do_cmd(verify_interface_key)
|
||||
ip_validation = lib.do_cmd(verify_interface_ip)
|
||||
|
||||
if not gre_key in key_validation or not remote_ip in ip_validation:
|
||||
logging.debug("WARNING: Unexpected output while verifying " +
|
||||
"interface %s on bridge %s" %(name, bridge))
|
||||
return "FAILURE:VERIFY_INTERFACE_FAILED"
|
||||
logging.debug("Tunnel interface validated:%s" %verify_interface_ip)
|
||||
cmd_tun_ofport = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "ofport"]
|
||||
tun_ofport = lib.do_cmd(cmd_tun_ofport)
|
||||
# Ensure no trailing LF
|
||||
if tun_ofport.endswith('\n'):
|
||||
tun_ofport = tun_ofport[:-1]
|
||||
# add flow entryies for dropping broadcast coming in from gre tunnel
|
||||
lib.add_flow(bridge, priority=1000, in_port=tun_ofport,
|
||||
dl_dst='ff:ff:ff:ff:ff:ff', actions='drop')
|
||||
lib.add_flow(bridge, priority=1000, in_port=tun_ofport,
|
||||
nw_dst='224.0.0.0/24', actions='drop')
|
||||
drop_flow_setup = True
|
||||
logging.debug("Broadcast drop rules added")
|
||||
return "SUCCESS:%s" % name
|
||||
except:
|
||||
logging.debug("An unexpected error occured. Rolling back")
|
||||
if tunnel_setup:
|
||||
logging.debug("Deleting GRE interface")
|
||||
# Destroy GRE port and interface
|
||||
lib.del_port(bridge, name)
|
||||
if drop_flow_setup:
|
||||
# Delete flows
|
||||
logging.debug("Deleting flow entries from GRE interface")
|
||||
lib.del_flows(bridge, in_port=tun_ofport)
|
||||
raise
|
||||
bridge = args.pop("bridge")
|
||||
remote_ip = args.pop("remote_ip")
|
||||
gre_key = args.pop("key")
|
||||
src_host = args.pop("from")
|
||||
dst_host = args.pop("to")
|
||||
|
||||
logging.debug("Entering create_tunnel")
|
||||
|
||||
res = lib.check_switch()
|
||||
if res != "SUCCESS":
|
||||
logging.debug("Openvswitch running: NO")
|
||||
return "FAILURE:%s" % res
|
||||
|
||||
# We need to keep the name below 14 characters
|
||||
# src and target are enough - consider a fixed length hash
|
||||
name = "t%s-%s-%s" % (gre_key, src_host, dst_host)
|
||||
|
||||
# Verify the xapi bridge to be created
|
||||
# NOTE: Timeout should not be necessary anymore
|
||||
wait = [lib.VSCTL_PATH, "--timeout=30", "wait-until", "bridge",
|
||||
bridge, "--", "get", "bridge", bridge, "name"]
|
||||
res = lib.do_cmd(wait)
|
||||
if bridge not in res:
|
||||
logging.debug("WARNING:Can't find bridge %s for creating " +
|
||||
"tunnel!" % bridge)
|
||||
return "FAILURE:NO_BRIDGE"
|
||||
logging.debug("bridge %s for creating tunnel - VERIFIED" % bridge)
|
||||
tunnel_setup = False
|
||||
drop_flow_setup = False
|
||||
try:
|
||||
# Create a port and configure the tunnel interface for it
|
||||
add_tunnel = [lib.VSCTL_PATH, "add-port", bridge,
|
||||
name, "--", "set", "interface",
|
||||
name, "type=gre", "options:key=%s" % gre_key,
|
||||
"options:remote_ip=%s" % remote_ip]
|
||||
lib.do_cmd(add_tunnel)
|
||||
tunnel_setup = True
|
||||
# verify port
|
||||
verify_port = [lib.VSCTL_PATH, "get", "port", name, "interfaces"]
|
||||
res = lib.do_cmd(verify_port)
|
||||
# Expecting python-style list as output
|
||||
iface_list = []
|
||||
if len(res) > 2:
|
||||
iface_list = res.strip()[1:-1].split(',')
|
||||
if len(iface_list) != 1:
|
||||
logging.debug("WARNING: Unexpected output while verifying " +
|
||||
"port %s on bridge %s" % (name, bridge))
|
||||
return "FAILURE:VERIFY_PORT_FAILED"
|
||||
|
||||
# verify interface
|
||||
iface_uuid = iface_list[0]
|
||||
verify_interface_key = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "options:key"]
|
||||
verify_interface_ip = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "options:remote_ip"]
|
||||
|
||||
key_validation = lib.do_cmd(verify_interface_key)
|
||||
ip_validation = lib.do_cmd(verify_interface_ip)
|
||||
|
||||
if not gre_key in key_validation or not remote_ip in ip_validation:
|
||||
logging.debug("WARNING: Unexpected output while verifying " +
|
||||
"interface %s on bridge %s" % (name, bridge))
|
||||
return "FAILURE:VERIFY_INTERFACE_FAILED"
|
||||
logging.debug("Tunnel interface validated:%s" % verify_interface_ip)
|
||||
cmd_tun_ofport = [lib.VSCTL_PATH, "get", "interface",
|
||||
iface_uuid, "ofport"]
|
||||
tun_ofport = lib.do_cmd(cmd_tun_ofport)
|
||||
# Ensure no trailing LF
|
||||
if tun_ofport.endswith('\n'):
|
||||
tun_ofport = tun_ofport[:-1]
|
||||
# add flow entryies for dropping broadcast coming in from gre tunnel
|
||||
lib.add_flow(bridge, priority=1000, in_port=tun_ofport,
|
||||
dl_dst='ff:ff:ff:ff:ff:ff', actions='drop')
|
||||
lib.add_flow(bridge, priority=1000, in_port=tun_ofport,
|
||||
nw_dst='224.0.0.0/24', actions='drop')
|
||||
drop_flow_setup = True
|
||||
logging.debug("Broadcast drop rules added")
|
||||
return "SUCCESS:%s" % name
|
||||
except:
|
||||
logging.debug("An unexpected error occured. Rolling back")
|
||||
if tunnel_setup:
|
||||
logging.debug("Deleting GRE interface")
|
||||
# Destroy GRE port and interface
|
||||
lib.del_port(bridge, name)
|
||||
if drop_flow_setup:
|
||||
# Delete flows
|
||||
logging.debug("Deleting flow entries from GRE interface")
|
||||
lib.del_flows(bridge, in_port=tun_ofport)
|
||||
# This will not cancel the original exception
|
||||
raise
|
||||
|
||||
|
||||
@echo
|
||||
def destroy_tunnel(session, args):
|
||||
bridge = args.pop("bridge")
|
||||
iface_name = args.pop("in_port")
|
||||
logging.debug("Destroying tunnel at port %s for bridge %s"
|
||||
% (iface_name, bridge))
|
||||
ofport = get_field_of_interface(iface_name, "ofport")
|
||||
lib.del_flows(bridge, in_port=ofport)
|
||||
lib.del_port(bridge, iface_name)
|
||||
return "SUCCESS"
|
||||
bridge = args.pop("bridge")
|
||||
iface_name = args.pop("in_port")
|
||||
logging.debug("Destroying tunnel at port %s for bridge %s"
|
||||
% (iface_name, bridge))
|
||||
ofport = get_field_of_interface(iface_name, "ofport")
|
||||
lib.del_flows(bridge, in_port=ofport)
|
||||
lib.del_port(bridge, iface_name)
|
||||
return "SUCCESS"
|
||||
|
||||
|
||||
def get_field_of_interface(iface_name, field):
|
||||
get_iface_cmd = [lib.VSCTL_PATH, "get","interface", iface_name, field]
|
||||
res = lib.do_cmd(get_iface_cmd)
|
||||
return res
|
||||
get_iface_cmd = [lib.VSCTL_PATH, "get", "interface", iface_name, field]
|
||||
res = lib.do_cmd(get_iface_cmd)
|
||||
return res
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
XenAPIPlugin.dispatch({"create_tunnel":create_tunnel,
|
||||
"destroy_tunnel":destroy_tunnel,
|
||||
"setup_ovs_bridge": setup_ovs_bridge,
|
||||
"destroy_ovs_bridge": destroy_ovs_bridge})
|
||||
XenAPIPlugin.dispatch({"create_tunnel": create_tunnel,
|
||||
"destroy_tunnel": destroy_tunnel,
|
||||
"setup_ovs_bridge": setup_ovs_bridge,
|
||||
"destroy_ovs_bridge": destroy_ovs_bridge})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user