applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / planetlab / openvswitch / ovs.py
index 51628fd..a3cf2fa 100644 (file)
@@ -3,9 +3,8 @@
 #    Copyright (C) 2013 INRIA
 #
 #    This program is free software: you can redistribute it and/or modify
 #    Copyright (C) 2013 INRIA
 #
 #    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
+#    it under the terms of the GNU General Public License version 2 as
+#    published by the Free Software Foundation;
 #
 #    This program is distributed in the hope that it will be useful,
 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
 #
 #    This program is distributed in the hope that it will be useful,
 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
-# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+# Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
 #         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
 #         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
+#         Julien Tribino <julien.tribino@inria.fr>
 
 
 from nepi.execution.resource import ResourceManager, clsinit_copy, \
 
 
 from nepi.execution.resource import ResourceManager, clsinit_copy, \
-        ResourceState, failtrap
+        ResourceState
 from nepi.execution.attribute import Attribute, Flags
 from nepi.resources.planetlab.node import PlanetlabNode        
 from nepi.resources.linux.application import LinuxApplication
 import os
 
 from nepi.execution.attribute import Attribute, Flags
 from nepi.resources.planetlab.node import PlanetlabNode        
 from nepi.resources.linux.application import LinuxApplication
 import os
 
-reschedule_delay = "0.5s"
-
 @clsinit_copy                    
 @clsinit_copy                    
-class OVSWitch(LinuxApplication):
-    
-    _rtype = "OVSWitch"
+class PlanetlabOVSSwitch(LinuxApplication):
+    """
+    .. class:: Class Args :
+      
+        :param ec: The Experiment controller
+        :type ec: ExperimentController
+        :param guid: guid of the RM
+        :type guid: int
+
+    """
+
+    _rtype = "planetlab::OVSSwitch"
     _help = "Runs an OpenVSwitch on a PlanetLab host"
     _help = "Runs an OpenVSwitch on a PlanetLab host"
-    _backend = "planetlab"
+    _platform = "planetlab"
 
 
-    _authorized_connections = ["PlanetlabNode", "OVSPort", "LinuxNode"]       
+    _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"]       
 
     @classmethod
     def _register_attributes(cls):
 
     @classmethod
     def _register_attributes(cls):
-        """ Register the attributes of OVSWitch RM 
+        """ Register the attributes of OVSSwitch RM 
 
         """
 
         """
-        bridge_name = Attribute("bridge_name", "Name of the switch/bridge",
-                flags = Flags.ExecReadOnly)    
-        virtual_ip_pref = Attribute("virtual_ip_pref", "Virtual IP/PREFIX of the switch",
-                flags = Flags.ExecReadOnly)       
-        controller_ip = Attribute("controller_ip", "IP of the controller",
-                flags = Flags.ExecReadOnly)
-        controller_port = Attribute("controller_port", "Port of the controller",
-                flags = Flags.ExecReadOnly)
+        bridge_name = Attribute("bridge_name", 
+                "Name of the switch/bridge",
+                flags = Flags.Design)  
+        virtual_ip_pref = Attribute("virtual_ip_pref", 
+                "Virtual IP/PREFIX of the switch",
+                flags = Flags.Design)  
+        controller_ip = Attribute("controller_ip", 
+                "IP of the controller",
+                flags = Flags.Design)  
+        controller_port = Attribute("controller_port", 
+                "Port of the controller",
+                flags = Flags.Design)  
 
         cls._register_attribute(bridge_name)
         cls._register_attribute(virtual_ip_pref)
 
         cls._register_attribute(bridge_name)
         cls._register_attribute(virtual_ip_pref)
@@ -64,255 +75,241 @@ class OVSWitch(LinuxApplication):
         :type guid: int
     
         """
         :type guid: int
     
         """
-        super(OVSWitch, self).__init__(ec, guid)
-        self._pid = None
-        self._ppid = None
-        self._home = "ovswitch-%s" % self.guid
-        self._checks = "ovsChecks-%s" % self.guid
+        super(PlanetlabOVSSwitch, self).__init__(ec, guid)
+        self._home = "ovsswitch-%s" % self.guid
+        self._node = None
 
     @property
     def node(self):
 
     @property
     def node(self):
-        node = self.get_connected(PlanetlabNode.rtype())
-        if node: return node[0]
-        return None
+        """ Node wthat run the switch
+        """
+        if not self._node:
+            nodes = self.get_connected(PlanetlabNode.get_rtype())
+            if not nodes or len(nodes) != 1: 
+                msg = "PlanetlabOVSSwitch must be connected to exactly one PlanetlabNode"
+                #self.error(msg)
+                raise RuntimeError(msg)
 
 
-    @property
-    def ovs_home(self):
-        return os.path.join(self.node.exp_home, self._home)
+            self._node = nodes[0]
 
 
-    @property
-    def ovs_checks(self):
-        return os.path.join(self.ovs_home, self._checks)
+        return self._node
 
 
-    @property
-    def pid(self):
-        return self._pid
+    def valid_connection(self, guid):
+        """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.
 
 
-    @property
-    def ppid(self):
-        return self._ppid
-
-#    def valid_connection(self, guid):
-#        """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.
-
-#        :param guid: Guid of the current RM
-#        :type guid: int
-#        :rtype:  Boolean
-
-#        """
-#        rm = self.ec.get_resource(guid)
-#        if rm.rtype() in self._authorized_connections:
-#            msg = "Connection between %s %s and %s %s accepted" % \
-#                (self.rtype(), self._guid, rm.rtype(), guid)
-#            self.debug(msg)
-#            return True
-#        msg = "Connection between %s %s and %s %s refused" % \
-#             (self.rtype(), self._guid, rm.rtype(), guid)
-#        self.debug(msg)
-#        return False
+        :param guid: Guid of the current RM
+        :type guid: int
+        :rtype:  Boolean
 
 
-    def valid_connection(self, guid):
-        # TODO: Validate!
+        """
+        rm = self.ec.get_resource(guid)
+        if rm.get_rtype() not in self._authorized_connections:
+            return False
         return True
 
         return True
 
-    @failtrap
-    def provision(self):
-        # create home dir for ovs
-        self.node.mkdir(self.ovs_home)
-        # create dir for ovs checks
-        self.node.mkdir(self.ovs_checks)
+    def do_provision(self):
+        self.node.mkdir(self.run_home)
+
+        self.check_sliver_ovs()
+        self.servers_on()
+        self.create_bridge()
+        self.assign_controller()
+        self.ovs_status()
+        
+        self.set_provisioned()
+                               
+    def do_deploy(self):
+        """ Deploy the OVS Switch : Turn on the server, create the bridges
+            and assign the controller
+        """
+
+        if not self.node or self.node.state < ResourceState.READY:
+            self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state)
+            self.ec.schedule(self.reschedule_delay, self.deploy)
+        else:
+            self.do_discover()
+            self.do_provision()
+               
+            self.set_ready()
 
     def check_sliver_ovs(self):  
 
     def check_sliver_ovs(self):  
-        """ Check if sliver-ovs exists. If it does not exist, we interrupt
-        the execution immediately. 
+        """ Check if sliver-ovs exists. If it does not exist, the execution is stopped
         """
         """
-        cmd = "compgen -c | grep sliver-ovs"                   
-        out = err = ""
-
-        (out,err), proc = self.node.run_and_wait(cmd, self.ovs_checks, 
-                   shfile = "check_cmd.sh",
-                pidfile = "check_cmd_pidfile",
-                ecodefile = "check_cmd_exitcode", 
-                sudo = True, 
-                stdout = "check_cmd_stdout", 
-                stderr = "check_cmd_stderr")
-
-        (out, err), proc = self.node.check_output(self.ovs_checks, 'check_cmd_exitcode')
-        
-        if out != "0\n":
+        command = "compgen -c | grep sliver-ovs"                       
+        shfile = os.path.join(self.app_home, "check_ovs_cmd.sh")
+        try:
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo = True, 
+                    pidfile="check_ovs_cmd_pidfile",
+                    ecodefile="check_ovs_cmd_exitcode", 
+                    stdout="check_ovs_cmd_stdout", 
+                    stderr="check_ovs_cmd_stderr")
+        except RuntimeError:
             msg = "Command sliver-ovs does not exist on the VM"         
             self.debug(msg)
             msg = "Command sliver-ovs does not exist on the VM"         
             self.debug(msg)
-            raise RuntimeError, msg
-
-        msg = "Command sliver-ovs exists" 
-        self.debug(msg)                                                
+            raise RuntimeError(msg)
 
 
-    @failtrap
-    def deploy(self):
-        """ Wait until node is associated and deployed
+    def servers_on(self):
+        """ Start the openvswitch servers and check it
         """
         """
-        node = self.node
-        if not node or node.state < ResourceState.READY:
-            self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state )
-            self.ec.schedule(reschedule_delay, self.deploy)
+        # Make sure the server is not running        
+        command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
+        shfile = os.path.join(self.app_home, "clean.sh")
+        self.node.run_and_wait(command, self.run_home,
+                shfile=shfile,
+                sudo=True,
+                raise_on_error=False,
+                pidfile="clean_pidfile",
+                ecodefile="clean_exitcode", 
+                stdout="clean_stdout", 
+                stderr="clean_stderr")
+
+        # start the server        
+        command = "sliver-ovs start"                   
+        shfile = os.path.join(self.app_home, "start.sh")
+        try:
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo=True, 
+                    pidfile="start_pidfile",
+                    ecodefile="start_exitcode", 
+                    stdout="start_stdout", 
+                    stderr="start_stderr")
+        except RuntimeError:
+            msg = "Failed to start ovs-server on VM"            
+            self.debug(msg)
+            raise RuntimeError(msg)
 
 
-        else:
-            self.discover()
-            self.provision()
-            self.check_sliver_ovs()
-            self.servers_on()
-            self.create_bridge()
-            self.assign_contr()
-            self.ovs_status()
-            
-            super(OVSWitch, self).deploy()
+        command = "ps -A | grep ovsdb-server"
+        shfile = os.path.join(self.app_home, "ovsdb_status.sh")
+        try:
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo=True, 
+                    pidfile="ovsdb_status_pidfile",
+                    ecodefile="ovsdb_status_exitcode", 
+                    stdout="ovsdb_status_stdout", 
+                    stderr="ovsdb_status_stderr")
+        except RuntimeError:
+            msg = "ovsdb-server not running on VM"      
+            self.debug(msg)
+            raise RuntimeError(msg)
+        
+        self.info("Server OVS Started...")  
 
 
-    def servers_on(self):
-        """ Start the openvswitch servers and also checking 
-            if they started successfully 
+    def create_bridge(self):
+        """ Create the bridge/switch and check error during SSH connection
         """
         """
-        self.info("Starting the OVSWitch servers")
-        command = ("sliver-ovs start") 
-                               
-        out = err = ""                                                                 
-        (out, err), proc = self.node.run_and_wait(command, self.ovs_checks,   
-                shfile = "start_srv.sh",
-                pidfile = "start_srv_pidfile",
-                ecodefile = "start_srv_exitcode", 
-                sudo = True, 
-                raise_on_error = True,
-                stdout = "start_srv_stdout", 
-                stderr = "start_srv_stderr")
-
-        (out, err), proc = self.node.check_output(self.ovs_checks, 'start_srv_exitcode')
-
-        if out != "0\n":
-            self.debug("Servers have not started")
-            raise RuntimeError, msg    
-                               
-        cmd = "ps -A | grep ovsdb-server"
-        out = err = ""
-        (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks, 
-                shfile = "status_srv.sh",
-                pidfile = "status_srv_pidfile",
-                ecodefile = "status_srv_exitcode", 
-                sudo = True, 
-                stdout = "status_srv_stdout", 
-                stderr = "status_srv_stderr")
-
-        # Check if the servers are running or not
-        (out, err), proc = self.node.check_output(self.ovs_checks, 'status_srv_exitcode')
-        
-        if out != "0\n":
-            self.debug("Servers are not running")
-            raise RuntimeError, msg
+        # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br
+        # TODO: Add check for virtual_ip belonging to vsys_tag
+        if not (self.get("bridge_name") and self.get("virtual_ip_pref")):
+            msg = "No assignment in one or both attributes"
+            self.error(msg)
+            raise AttributeError(msg)
+
+        command = "sliver-ovs create-bridge '%s' '%s'" % (
+                          self.get("bridge_name"), 
+                          self.get("virtual_ip_pref")) 
         
         
-        self.info("Servers started")  
+        shfile = os.path.join(self.app_home, "bridge_create.sh")
+        try:
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo=True, 
+                    pidfile="bridge_create_pidfile",
+                    ecodefile="bridge_create_exitcode", 
+                    stdout="bridge_create_stdout", 
+                    stderr="bridge_create_stderr")
+        except RuntimeError:
+            msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error"
+            self.debug(msg)
+            raise RuntimeError(msg)
+
+        self.info(" Bridge %s Created and Assigned to %s" %\
+            (self.get("bridge_name"), self.get("virtual_ip_pref")) )
 
 
-    def del_old_br(self):
-        # TODO: Delete old bridges that might exist maybe by adding atribute
-        """ With ovs-vsctl list-br
+    def assign_controller(self):
+        """ Set the controller IP
         """
         """
-        pass
 
 
-    def create_bridge(self):
-        """ Create the bridge/switch and we check if we have any 
-            error during the SSH connection         
+        if not (self.get("controller_ip") and self.get("controller_port")):
+            return 
+
         """
         """
-        # TODO: Add check for virtual_ip belonging to vsys_tag
-        self.del_old_br()
-       
-        if self.get("bridge_name") and self.get("virtual_ip_pref"):    
-            bridge_name = self.get("bridge_name")
-            virtual_ip_pref = self.get("virtual_ip_pref")
-            self.info(" Creating the bridge %s and assigning %s" %\
-                (bridge_name, virtual_ip_pref) )
-            cmd = "sliver-ovs create-bridge '%s' '%s'" %\
-                (bridge_name, virtual_ip_pref) 
-            out = err = ""
-            (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks,
-                    shfile = "create_br.sh",
-                    pidfile = "create_br_pidfile",
-                    ecodefile = "create_br_exitcode", 
-                    sudo = True, 
-                    stdout = "create_br_stdout", 
-                    stderr = "create_br_stderr") 
-            (out, err), proc = self.node.check_output(self.ovs_checks, 'create_br_exitcode')
-            if out != "0\n":
-                msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error"
-                self.debug("Check again the virtual IP")                       
-                raise RuntimeError, msg
-            self.info("Bridge %s created" % bridge_name)
-          
-        else:  
+        if not (self.get("controller_ip") and self.get("controller_port")):
             msg = "No assignment in one or both attributes"
             self.error(msg)
             msg = "No assignment in one or both attributes"
             self.error(msg)
-            self.debug("Bridge name is %s and virtual_ip_pref is %s" %\
-                (self.get("bridge_name"), self.get("virtual_ip_pref")) )
             raise AttributeError, msg
             raise AttributeError, msg
-
-    def assign_contr(self):
-        """ Set the controller IP
         """
         """
-        if self.get("controller_ip") and self.get("controller_port"):
-            controller_ip = self.get("controller_ip")
-            controller_port = self.get("controller_port")
-            self.info("Assigning the controller to the %s" % self.get("bridge_name"))
-            cmd = "ovs-vsctl set-controller %s tcp:%s:%s" %\
-                (self.get("bridge_name"), controller_ip, controller_port)
-            out = err = ""
-            (out, err), proc = self.node.run(cmd, self.ovs_checks,
-                    sudo = True, 
-                    stdout = "stdout", 
-                    stderr = "stderr")
-            if err != "":
-                self.debug("SSH connection refusing in assign_contr")
-                raise RuntimeError, msg
-            self.info("Controller assigned")
+        command = "ovs-vsctl set-controller %s tcp:%s:%s" % \
+                (self.get("bridge_name"), 
+                        self.get("controller_ip"), 
+                        self.get("controller_port"))
+        
+        shfile = os.path.join(self.app_home, "set_controller.sh")
+        try:
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo=True, 
+                    pidfile="set_controller_pidfile",
+                    ecodefile="set_controller_exitcode", 
+                    stdout="set_controller_stdout", 
+                    stderr="set_controller_stderr")
+        except RuntimeError:
+            msg = "SSH connection in the method assign_controller"
+            self.debug(msg)
+            raise RuntimeError(msg)
+
+        self.info("Controller assigned to the bridge %s" % self.get("bridge_name"))
            
     def ovs_status(self):
            
     def ovs_status(self):
-        """ Print the status of the created bridge                                     
+        """ Print the status of the bridge                             
         """
         """
-        cmd = "sliver-ovs show | tail -n +2"
-        out = err = ""
-        (out, err), proc = self.node.run_and_wait(cmd, self.ovs_home,
-                sudo = True, 
-                stdout = "show_stdout", 
-                stderr = "show_stderr") 
-        (out, err), proc = self.node.check_output(self.ovs_home, 'show_stdout')
-        self.info(out)
-
-    def release(self):
-        """ Delete the bridge and 
-            close the servers
-        """
-        # Node needs to wait until all associated RMs are released
-        # to be released
+        command = "sliver-ovs show | tail -n +2"
+        shfile = os.path.join(self.app_home, "ovs_status.sh")
         try:
         try:
-            from nepi.resources.planetlab.openvswitch.ovsport import OVSPort
-            rm = self.get_connected(OVSPort.rtype())
+            self.node.run_and_wait(command, self.run_home,
+                    shfile=shfile,
+                    sudo=True, 
+                    pidfile="ovs_status_pidfile",
+                    ecodefile="ovs_status_exitcode", 
+                    stdout="ovs_status_stdout", 
+                    stderr="ovs_status_stderr")
+        except RuntimeError:
+            msg = "Error when checking the status of the OpenVswitch"
+            self.debug(msg)
+            raise RuntimeError(msg)
+
+    def do_release(self):
+        """ Delete the bridge and close the server.  
+
+          .. note : It need to wait for the others RM (OVSPort and OVSTunnel)
+        to be released before releasing itself
 
 
-            if rm[0].state < ResourceState.FINISHED:
-                self.ec.schedule(reschedule_delay, self.release)
+        """
+
+        from nepi.resources.planetlab.openvswitch.ovsport import PlanetlabOVSPort
+        rms = self.get_connected(PlanetlabOVSPort.get_rtype())
+
+        for rm in rms:
+            if rm.state < ResourceState.RELEASED:
+                self.ec.schedule(self.reschedule_delay, self.release)
                 return 
                 return 
-                
-            msg = "Deleting the bridge %s" % self.get('bridge_name')
-            self.info(msg)
-            cmd = "sliver-ovs del-bridge %s" % self.get('bridge_name')
-            (out, err), proc = self.node.run(cmd, self.ovs_checks,
-                    sudo = True)
-            cmd = "sliver-ovs stop"
-            (out, err), proc = self.node.run(cmd, self.ovs_checks,
-                    sudo = True)
             
             
-            if proc.poll():
-                self.fail()
-                self.error(msg, out, err)
-                raise RuntimeError, msg
-        except:
-            import traceback
-            err = traceback.format_exc()
-            self.error(err)
-
-        super(OVSWitch, self).release()
+        msg = "Deleting the bridge %s" % self.get('bridge_name')
+        self.info(msg)
+        
+        command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
+        shfile = os.path.join(self.app_home, "stop.sh")
+
+        self.node.run_and_wait(command, self.run_home,
+                shfile=shfile,
+                sudo=True, 
+                pidfile="stop_pidfile",
+                ecodefile="stop_exitcode", 
+                stdout="stop_stdout", 
+                stderr="stop_stderr")
+
+        super(PlanetlabOVSSwitch, self).do_release()