spaces after comma
[nodemanager.git] / plugins / privatebridge.py
index f6d52f7..5ec15b9 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 """ Private Bridge configurator.  """
 
@@ -16,10 +16,15 @@ import tools
 
 priority = 9
 
+class OvsException (Exception) :
+    def __init__ (self, message="no message"):
+        self.message=message
+    def __repr__ (self): return message
+
 def start():
     logger.log('private bridge plugin starting up...')
 
-def log_call_read(command,timeout=logger.default_timeout_minutes*60,poll=1):
+def log_call_read(command, timeout=logger.default_timeout_minutes*60, poll=1):
     message=" ".join(command)
     logger.log("log_call: running command %s" % message)
     logger.verbose("log_call: timeout=%r s" % timeout)
@@ -32,7 +37,7 @@ def log_call_read(command,timeout=logger.default_timeout_minutes*60,poll=1):
         stdout = ""
         while True:
             # see if anything can be read within the poll interval
-            (r,w,x)=select.select([child.stdout],[],[],poll)
+            (r, w, x)=select.select([child.stdout], [], [], poll)
             if r: stdout = stdout + child.stdout.read(1)
             # is process over ?
             returncode=child.poll()
@@ -47,39 +52,53 @@ def log_call_read(command,timeout=logger.default_timeout_minutes*60,poll=1):
                     return (returncode, stdout)
                 # child has failed
                 else:
-                    log("log_call:end command (%s) returned with code %d" %(message,returncode))
+                    log("log_call:end command (%s) returned with code %d" %(message, returncode))
                     return (returncode, stdout)
             # no : still within timeout ?
             if time.time() >= trigger:
                 child.terminate()
-                logger.log("log_call:end terminating command (%s) - exceeded timeout %d s"%(message,timeout))
+                logger.log("log_call:end terminating command (%s) - exceeded timeout %d s"%(message, timeout))
                 return (-2, None)
                 break
-    except:
-        logger.log_exc("failed to run command %s" % message)
+    except Exception as e:
+        logger.log_exc("failed to run command %s -> %s" % (message, e))
 
     return (-1, None)
 
+### Thierry - 23 Sept 2014
+# regardless of this being shipped on lxc-only or on all nodes, 
+# it is safer to check for the availability of the ovs-vsctl command and just print 
+# out a warning when it's not there, instead of a nasty traceback
+def ovs_available ():
+    "return True if ovs-vsctl can be run"
+    try:
+        child = subprocess.Popen (['ovs-ovsctl', '--help'])
+        child.communicate()
+        return True
+    except:
+        return False
+
 def ovs_vsctl(args):
     return log_call_read(["ovs-vsctl"] + args)
 
 def ovs_listbridge():
     (returncode, stdout) = ovs_vsctl(["list-br"])
-    if (returncode != 0):
-        raise OvsException()
+    if (returncode != 0): raise OvsException("list-br")
     return stdout.split()
 
 def ovs_addbridge(name):
-    (returncode, stdout) = ovs_vsctl(["add-br",name])
-    if (returncode != 0):
-        raise OvsException()
+    (returncode, stdout) = ovs_vsctl(["add-br", name])
+    if (returncode != 0): raise OvsException("add-br")
 
 def ovs_listports(name):
     (returncode, stdout) = ovs_vsctl(["list-ports", name])
-    if (returncode != 0):
-        raise OvsException()
+    if (returncode != 0): raise OvsException("list-ports")
     return stdout.split()
 
+def ovs_delbridge(name):
+    (returncode, stdout) = ovs_vsctl(["del-br", name])
+    if (returncode != 0): raise OvsException("del-br")
+
 def ovs_addport(name, portname, type, remoteip, key):
     args = ["add-port", name, portname, "--", "set", "interface", portname, "type="+type]
     if remoteip:
@@ -88,13 +107,11 @@ def ovs_addport(name, portname, type, remoteip, key):
         args = args + ["options:key=" + str(key)]
 
     (returncode, stdout) = ovs_vsctl(args)
-    if (returncode != 0):
-        raise OvsException()
+    if (returncode != 0): raise OvsException("add-port")
 
 def ovs_delport(name, portname):
-    (returncode, stdout) = ovs_vsctl(["del-port",name,portname])
-    if (returncode != 0):
-        raise OvsException()
+    (returncode, stdout) = ovs_vsctl(["del-port", name, portname])
+    if (returncode != 0): raise OvsException("del-port")
 
 def ensure_slicebridge_created(name, addr):
     bridges = ovs_listbridge()
@@ -120,8 +137,8 @@ def ensure_slicebridge_neighbors(name, sliver_id, neighbors):
         if not portname in ports:
             ovs_addport(name, portname, "gre", neighbor_ip, sliver_id)
 
-    for port in ports:
-        if port.startswith("gre") and (port not in want_ports):
+    for portname in ports:
+        if portname.startswith("gre") and (portname not in want_ports):
             ovs_delport(name, portname)
 
 def configure_slicebridge(sliver, attributes):
@@ -146,12 +163,18 @@ def configure_slicebridge(sliver, attributes):
     ensure_slicebridge_neighbors(slice_bridge_name, sliver_id, slice_bridge_neighbors)
 
 def GetSlivers(data, conf = None, plc = None):
+
+    if not ovs_available():
+        logger.log ("privatebridge: warning, ovs-vsctl not found - exiting")
+        return
+
     node_id = tools.node_id()
 
     if 'slivers' not in data:
-        logger.log_missing_data("privatebridge.GetSlivers",'slivers')
+        logger.log_missing_data("privatebridge.GetSlivers", 'slivers')
         return
 
+    valid_bridges = []
     for sliver in data['slivers']:
         sliver_name = sliver['name']
 
@@ -160,7 +183,25 @@ def GetSlivers(data, conf = None, plc = None):
         for attribute in sliver['attributes']:
             attributes[attribute['tagname']] = attribute['value']
 
-        if attributes.get('slice_bridge_name',None):
+        bridge_name = attributes.get('slice_bridge_name', None)
+        if bridge_name:
             configure_slicebridge(sliver, attributes)
+            valid_bridges.append(bridge_name)
+
+    # now, delete the bridges that we don't want
+    bridges = ovs_listbridge()
+    for bridge_name in bridges:
+        if not bridge_name.startswith("br-slice-"):
+            # ignore ones we didn't create
+            continue
+
+        if bridge_name in valid_bridges:
+            # ignore ones we want to keep
+            continue
+
+        logger.log("privatebridge: deleting unused bridge %s" % bridge_name)
+
+        ovs_delbridge(bridge_name)
+