Merging the openflow part to the nepi-3-dev branch
authorJulien Tribino <julien.tribino@inria.fr>
Mon, 19 May 2014 15:13:24 +0000 (17:13 +0200)
committerJulien Tribino <julien.tribino@inria.fr>
Mon, 19 May 2014 15:13:24 +0000 (17:13 +0200)
1  2 
src/nepi/resources/linux/udptunnel.py
src/nepi/resources/planetlab/openvswitch/ovs.py
src/nepi/resources/planetlab/openvswitch/ovsport.py
src/nepi/resources/planetlab/openvswitch/tunnel.py
src/nepi/resources/planetlab/tap.py

@@@ -43,25 -43,25 +43,25 @@@ class UdpTunnel(LinuxApplication)
                  default = None,
                  allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"],
                  type = Types.Enumerate, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          cipher_key = Attribute("cipherKey",
                  "Specify a symmetric encryption key with which to protect "
                  "packets across the tunnel. python-crypto must be installed "
                  "on the system." ,
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          txqueuelen = Attribute("txQueueLen",
                  "Specifies the interface's transmission queue length. "
                  "Defaults to 1000. ", 
                  type = Types.Integer, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          bwlimit = Attribute("bwLimit",
                  "Specifies the interface's emulated bandwidth in bytes "
                  "per second.",
                  type = Types.Integer, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          cls._register_attribute(cipher)
          cls._register_attribute(cipher_key)
              self.do_discover()
              self.do_provision()
   
 -            self.debug("----- READY ---- ")
              self.set_ready()
  
      def do_start(self):
          result = None
          delay = 1.0
  
-         for i in xrange(4):
+         for i in xrange(20):
              (out, err), proc = endpoint.node.check_output(
                      self.run_home(endpoint), filename)
  
@@@ -29,9 -29,18 +29,18 @@@ import o
  reschedule_delay = "0.5s"
  
  @clsinit_copy                    
- class OVSWitch(LinuxApplication):
-     
-     _rtype = "OVSWitch"
+ class OVSSwitch(LinuxApplication):
+     """
+     .. class:: Class Args :
+       
+         :param ec: The Experiment controller
+         :type ec: ExperimentController
+         :param guid: guid of the RM
+         :type guid: int
+     """
+     _rtype = "OVSSwitch"
      _help = "Runs an OpenVSwitch on a PlanetLab host"
      _backend = "planetlab"
  
  
      @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)   
 +                flags = Flags.Design) 
          virtual_ip_pref = Attribute("virtual_ip_pref", "Virtual IP/PREFIX of the switch",
 -                flags = Flags.ExecReadOnly)       
 +                flags = Flags.Design) 
          controller_ip = Attribute("controller_ip", "IP of the controller",
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design) 
          controller_port = Attribute("controller_port", "Port of the controller",
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design) 
  
          cls._register_attribute(bridge_name)
          cls._register_attribute(virtual_ip_pref)
          :type guid: int
      
          """
-         super(OVSWitch, self).__init__(ec, guid)
-         self._pid = None
-         self._ppid = None
-         self._home = "ovswitch-%s" % self.guid
+         super(OVSSwitch, self).__init__(ec, guid)
+         self._home = "ovsswitch-%s" % self.guid
          self._checks = "ovsChecks-%s" % self.guid
  
      @property
      def node(self):
+         """ Node wthat run the switch
+         """
          node = self.get_connected(PlanetlabNode.get_rtype())
          if node: return node[0]
          return None
  
+     def log_message(self, msg):
+         return " guid %d - OVSSwitch - %s " % (self.guid, msg)
      @property
      def ovs_home(self):
          return os.path.join(self.node.exp_home, self._home)
      def ovs_checks(self):
          return os.path.join(self.ovs_home, self._checks)
  
-     @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.get_rtype() in self._authorized_connections:
- #            msg = "Connection between %s %s and %s %s accepted" % \
- #                (self.get_rtype(), self._guid, rm.get_rtype(), guid)
- #            self.debug(msg)
- #            return True
- #        msg = "Connection between %s %s and %s %s refused" % \
- #             (self.get_rtype(), self._guid, rm.get_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!
-         return True
+         """
+         rm = self.ec.get_resource(guid)
+         if rm.get_rtype() in self._authorized_connections:
+             msg = "Connection between %s %s and %s %s accepted" % \
+                 (self.get_rtype(), self._guid, rm.get_rtype(), guid)
+             self.debug(msg)
+             return True
+         msg = "Connection between %s %s and %s %s refused" % \
+              (self.get_rtype(), self._guid, rm.get_rtype(), guid)
+         self.debug(msg)
+         return False
  
      def do_provision(self):
+         """ Create the different OVS folder.
+         """
          # create home dir for ovs
          self.node.mkdir(self.ovs_home)
          # create dir for ovs checks
          self.node.mkdir(self.ovs_checks)
          
-         super(OVSWitch, self).do_provision()
+         super(OVSSwitch, self).do_provision()
+                               
+     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.ec.schedule(reschedule_delay, self.deploy)
+             return
+         self.do_discover()
+         self.do_provision()
+         self.check_sliver_ovs()
+         self.servers_on()
+         self.create_bridge()
+         self.assign_controller()
+         self.ovs_status()
+             
+         super(OVSSwitch, self).do_deploy()
  
      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 = ""
  
              raise RuntimeError, msg
  
          msg = "Command sliver-ovs exists" 
-         self.debug(msg)                                               
-     def do_deploy(self):
-         """ Wait until node is associated and deployed
-         """
-         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)
-             return
-         self.do_discover()
-         self.do_provision()
-         self.check_sliver_ovs()
-         self.servers_on()
-         self.create_bridge()
-         self.assign_controller()
-         self.ovs_status()
-             
-         super(OVSWitch, self).do_deploy()
+         self.debug(msg)
  
      def servers_on(self):
-         """ Start the openvswitch servers and also checking 
-             if they started successfully 
+         """ Start the openvswitch servers and check it
          """
-         self.info("Starting the OVSWitch servers")
-         command = ("sliver-ovs start") 
-                               
+         # Start the server
+         command = "sliver-ovs start"                  
          out = err = ""                                                                        
          (out, err), proc = self.node.run_and_wait(command, self.ovs_checks,   
                  shfile = "start_srv.sh",
                  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.error("Servers have not started")
              raise RuntimeError, msg   
                                
+         # Check if the servers are running or not
          cmd = "ps -A | grep ovsdb-server"
          out = err = ""
          (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks, 
                  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.error("Servers are not running")
+             msg = "Servers are not running"
+             self.error(msg)
              raise RuntimeError, msg
          
-         self.info("Servers started")  
-     def del_old_br(self):
-         # TODO: Delete old bridges that might exist maybe by adding atribute
-         """ With ovs-vsctl list-br
-         """
-         pass
+         self.info("Server OVS Started Correctly")  
  
      def create_bridge(self):
-         """ Create the bridge/switch and we check if we have any 
-             error during the SSH connection         
+         """ Create the bridge/switch and check error during SSH connection
          """
+         # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br
          # TODO: Add check for virtual_ip belonging to vsys_tag
-         self.del_old_br()
        
          if not (self.get("bridge_name") and self.get("virtual_ip_pref")):
              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
-       
-         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
+             (self.get("bridge_name"), self.get("virtual_ip_pref")
          out = err = ""
          (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks,
                  shfile = "create_br.sh",
                  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")                  
+             self.error(msg)                   
              raise RuntimeError, msg
  
-         self.info("Bridge %s created" % bridge_name)
+         self.info(" Bridge %s Created and Assigned to %s" %\
+             (self.get("bridge_name"), self.get("virtual_ip_pref")) )
            
  
      def assign_controller(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")
+         if not (self.get("controller_ip") and self.get("controller_port")):
+             msg = "No assignment in one or both attributes"
+             self.error(msg)
+             raise AttributeError, msg
+         cmd = "ovs-vsctl set-controller %s tcp:%s:%s" %\
+             (self.get("bridge_name"), self.get("controller_ip"), self.get("controller_port"))
+         out = err = ""
+         (out, err), proc = self.node.run(cmd, self.ovs_checks,
+                 sudo = True, 
+                 stdout = "stdout", 
+                 stderr = "stderr")
+         if err != "":
+             msg = "SSH connection in the method assign_controller"
+             self.error(msg)
+             raise RuntimeError, msg
+         self.info("Controller assigned to the bridge %s" % self.get("bridge_name"))
            
      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,
                  stdout = "show_stdout", 
                  stderr = "show_stderr") 
          (out, err), proc = self.node.check_output(self.ovs_home, 'show_stdout')
-         self.info(out)
+         
+         if out == "":
+             msg = "Error when checking the status of the OpenVswitch"
+             self.error(msg)
+             raise RuntimeError, msg
+         
+         self.debug(out)
  
      def do_release(self):
-         """ Delete the bridge and 
-             close the servers
+         """ 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
          """
-         # Node needs to wait until all associated RMs are released
-         # to be released
          from nepi.resources.planetlab.openvswitch.ovsport import OVSPort
          rm = self.get_connected(OVSPort.get_rtype())
  
-         if rm[0].state < ResourceState.STOPPED:
+         if rm[0].state < ResourceState.RELEASED:
              self.ec.schedule(reschedule_delay, self.release)
              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)
+         msg = "Deleting the bridge %s" % self.get('bridge_name')
+         self.info(msg)
          
          if proc.poll():
              self.error(msg, out, err)
              raise RuntimeError, msg
  
-         super(OVSWitch, self).do_release()
+         super(OVSSwitch, self).do_release()
  
@@@ -21,7 -21,7 +21,7 @@@
  from nepi.execution.attribute import Attribute, Flags, Types
  from nepi.execution.resource import ResourceManager, clsinit_copy, \
          ResourceState
- from nepi.resources.planetlab.openvswitch.ovs import OVSWitch        
+ from nepi.resources.planetlab.openvswitch.ovs import OVSSwitch        
  from nepi.resources.planetlab.node import PlanetlabNode        
  from nepi.resources.linux.application import LinuxApplication
  
@@@ -43,7 -43,7 +43,7 @@@ class OVSPort(LinuxApplication)
      _help = "Runs an OpenVSwitch on a PlanetLab host"
      _backend = "planetlab"
  
-     _authorized_connections = ["OVSWitch", "Tunnel"]      
+     _authorized_connections = ["OVSSwitch", "OVSTunnel"]      
  
      @classmethod
      def _register_attributes(cls):
@@@ -51,7 -51,7 +51,7 @@@
  
          """
          port_name = Attribute("port_name", "Name of the port",
 -            flags = Flags.ExecReadOnly)                       
 +            flags = Flags.Design)                     
  
          cls._register_attribute(port_name)
  
          self._port_number = None
          self.port_info = []        
  
+     def log_message(self, msg):
+         return " guid %d - OVSPort - %s " % (self.guid, msg)
      @property
      def node(self):
-         rm_list = self.get_connected(OVSWitch.get_rtype())
+         """ Node that run the switch and the ports
+         """
+         rm_list = self.get_connected(OVSSwitch.get_rtype())
          if rm_list:
              for elt in rm_list:
                  node = elt.get_connected(PlanetlabNode.get_rtype())
          return node[0]
  
      @property
-     def ovswitch(self):
-         ovswitch = self.get_connected(OVSWitch.get_rtype())
-         if ovswitch: return ovswitch[0]
+     def ovsswitch(self):
+         """ Switch where the port is created
+         """
+         ovsswitch = self.get_connected(OVSSwitch.get_rtype())
+         if ovsswitch: return ovsswitch[0]
          return None
          
      @property
          return self._port_number
  
      def valid_connection(self, guid):
-         # TODO: Validate!
-         return True
- #    def valid_connection(self, guid):
- #        """ Check if the connection is available.
- #        :param guid: Guid of the current RM
- #        :type guid: int
- #        :rtype:  Boolean
- #        """
- #        rm = self.ec.get_resource(guid)
- #        if rm.get_rtype() in self._authorized_connections:
- #            msg = "Connection between %s %s and %s %s accepted" % (self.get_rtype(), self._guid, rm.get_rtype(), guid)
- #            self.debug(msg)
- #            return True
- #        msg = "Connection between %s %s and %s %s refused" % (self.get_rtype(), self._guid, rm.get_rtype(), guid)
- #        self.debug(msg)
-     def get_host_ip(self):
-         """ Get the hostname of the node that
-         the port belongs to. We use it for tunnel.
+         """ Check if the connection is available.
+         :param guid: Guid of the current RM
+         :type guid: int
+         :rtype:  Boolean
          """
-         get_host_ip = self.node
-         if not get_host_ip: 
-             msg = "info_list is empty"
+         rm = self.ec.get_resource(guid)
+         if rm.get_rtype() in self._authorized_connections:
+             msg = "Connection between %s %s and %s %s accepted" % (self.get_rtype(), self._guid, rm.get_rtype(), guid)
              self.debug(msg)
-             raise RuntimeError, msg
+             return True
+         msg = "Connection between %s %s and %s %s refused" % (self.get_rtype(), self._guid, rm.get_rtype(), guid)
+         self.debug(msg)
  
-         import socket
-         self.port_info.append(get_host_ip.get('hostname'))
-         self.port_info.append(socket.gethostbyname(self.port_info[0]))   
-     
      def create_port(self):
          """ Create the desired port
          """
-         port_name = self.get('port_name')
+         msg = "Creating the port %s" % self.get('port_name')
+         self.debug(msg)
  
-         if not (port_name or self.ovswitch):
-             msg = "The rm_list is empty or the port name is not assigned\n Failed to create port"
+         if not self.get('port_name'):
+             msg = "The port name is not assigned"
              self.error(msg)
-             self.debug("ovswitch_list = %s and port_name = %s" % (self.ovswitch, port_name) )
              raise AttributeError, msg
  
-         self.info("Create the port %s on switch %s" % (port_name, self.ovswitch.get('bridge_name')))     
-         self.port_info.append(port_name)
-         self.port_info.append(self.ovswitch.get('virtual_ip_pref'))
-         cmd = "sliver-ovs create-port %s %s" % (self.ovswitch.get('bridge_name'), port_name)   
-         self.node.run(cmd, self.ovswitch.ovs_checks, 
-                 stderr = "stdout-%s" % port_name, 
-                 stdout = "stderr-%s" % port_name,
+         if not self.ovsswitch:
+             msg = "The OVSwitch RM is not running"
+             self.error(msg)
+             raise AttributeError, msg
+         cmd = "sliver-ovs create-port %s %s" % (self.ovsswitch.get('bridge_name'),
+                                                 self.get('port_name'))   
+         self.node.run(cmd, self.ovsswitch.ovs_checks, 
+                 stderr = "stdout-%s" % self.get('port_name'), 
+                 stdout = "stderr-%s" % self.get('port_name'),
                  sudo = True)
+         self.info("Created the port %s on switch %s" % (self.get('port_name'),
+                                              self.ovsswitch.get('bridge_name')))     
            
      def get_local_end(self):
          """ Get the local_endpoint of the port
          """
-         msg = "Discovering the number of the port %s"\
-             % self.get('port_name')
-         self.info(msg)
  
-         command = "sliver-ovs get-local-endpoint %s"\
-             % self.get('port_name')
+         msg = "Discovering the number of the port %s" % self.get('port_name')
+         self.debug(msg)
+         command = "sliver-ovs get-local-endpoint %s" % self.get('port_name')
          out = err = ""
-         (out, err), proc = self.node.run_and_wait(command, self.ovswitch.ovs_checks, 
+         (out, err), proc = self.node.run_and_wait(command, 
+                 self.ovsswitch.ovs_checks,
                  shfile = "port_number-%s.sh" % self.get('port_name'),
                  pidfile = "port_number_pidfile-%s" % self.get('port_name'),
                  ecodefile = "port_number_exitcode-%s" % self.get('port_name'), 
                  stderr = "stderr-%s" % self.get('port_name'))
  
          if err != "":
-             msg = "No assignment in attribute port_name"
+             msg = "Error retrieving the local endpoint of the port"
              self.error(msg)
-             self.debug("You are in the method get_local_end and the port_name = %s" % self.get('port_name'))
              raise AttributeError, msg
  
-         self._port_number = None
-         self._port_number = int(out)
-         self.port_info.append(self._port_number)                              
-         self.info("The number of the %s is %s" % (self.get('port_name'), self._port_number))
+         if out:
+             self._port_number = int(out)
+         self.info("The number of the %s is %s" % (self.get('port_name'), 
+            self.port_number))
     
+     def set_port_info(self):
+         """ Set all the information about the port inside a list
+         """
+         info = []
+         info.append(self.node.get('hostname'))
+         #Return the ip of the node
+         import socket
+         ip = socket.gethostbyname(self.node.get('hostname'))
+         info.append(ip)
+         info.append(self.get('port_name'))
+         info.append(self.ovsswitch.get('virtual_ip_pref'))
+         info.append(self.port_number)
+         return info
      def switch_connect_command(self, local_port_name, 
              remote_ip, remote_port_num):
-         """ Script for switch links
+         """ Script to create the connection from a switch to a 
+              remote endpoint
          """
          command = ["sliver-ovs"]
          command.append("set-remote-endpoint ")
          command.append("%s " % local_port_name)
          return command
          
      def do_deploy(self):
-         """ Wait until ovswitch is started
+         """ Deploy the OVS port after the OVS Switch
          """
-         ovswitch = self.ovswitch
  
-         if not ovswitch or ovswitch.state < ResourceState.READY:       
-             self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.ovswitch.state )  
+         if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY:       
+             self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state )  
              self.ec.schedule(reschedule_delay, self.deploy)
              return
  
          self.do_discover()
          self.do_provision()
-         self.get_host_ip()
          self.create_port()
          self.get_local_end()
-         self.ovswitch.ovs_status()
+         #Check the status of the OVS Switch
+         self.ovsswitch.ovs_status()
+         # Save all the information inside a list
+         self.port_info = self.set_port_info()
  
          super(OVSPort, self).do_deploy()
  
      def do_release(self):
-         """ Release the port RM means delete the ports
+         """ Delete the port on the OVSwitch. It needs to wait for the tunnel
+         to be released.
          """
-         # OVS needs to wait until all associated RMs are released
-         # to be released
          from nepi.resources.planetlab.openvswitch.tunnel import OVSTunnel
          rm = self.get_connected(OVSTunnel.get_rtype())
  
-         if rm and rm[0].state < ResourceState.STOPPED:
+         if rm and rm[0].state < ResourceState.RELEASED:
              self.ec.schedule(reschedule_delay, self.release)
              return 
              
-         msg = "Deleting the port %s" % self.get('port_name')
-         self.info(msg)
          cmd = "sliver-ovs del_port %s" % self.get('port_name')
-         (out, err), proc = self.node.run(cmd, self.ovswitch.ovs_checks,
+         (out, err), proc = self.node.run(cmd, self.ovsswitch.ovs_checks,
                  sudo = True)
  
+         msg = "Deleting the port %s" % self.get('port_name')
+         self.info(msg)
          if proc.poll():
              self.error(msg, out, err)
              raise RuntimeError, msg
@@@ -24,7 -24,7 +24,7 @@@ from nepi.execution.resource import Res
          ResourceState
  from nepi.resources.linux.application import LinuxApplication
  from nepi.resources.planetlab.node import PlanetlabNode            
- from nepi.resources.planetlab.openvswitch.ovs import OVSWitch   
+ from nepi.resources.planetlab.openvswitch.ovs import OVSSwitch   
  from nepi.util.timefuncs import tnow, tdiffsec    
  from nepi.resources.planetlab.vroute import PlanetlabVroute
  from nepi.resources.planetlab.tap import PlanetlabTap
@@@ -54,11 -54,11 +54,11 @@@ class OVSTunnel(LinuxApplication)
  
      @classmethod
      def _register_attributes(cls):
-         """ Register the attributes of Connection RM 
+         """ Register the attributes of OVSTunnel RM 
  
          """
          network = Attribute("network", "IPv4 Network Address",
 -               flags = Flags.ExecReadOnly)
 +               flags = Flags.Design)
  
          cipher = Attribute("cipher",
                 "Cipher to encript communication. "
                  default = None,
                  allowed = ["PLAIN", "AES", "Blowfish", "DES", "DES3"],
                  type = Types.Enumerate, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          cipher_key = Attribute("cipherKey",
                  "Specify a symmetric encryption key with which to protect "
                  "packets across the tunnel. python-crypto must be installed "
                  "on the system." ,
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          txqueuelen = Attribute("txQueueLen",
                  "Specifies the interface's transmission queue length. "
                  "Defaults to 1000. ", 
                  type = Types.Integer, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          bwlimit = Attribute("bwLimit",
                  "Specifies the interface's emulated bandwidth in bytes "
                  "per second.",
                  type = Types.Integer, 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          cls._register_attribute(network)
          cls._register_attribute(cipher)
          super(OVSTunnel, self).__init__(ec, guid)
          self._home = "tunnel-%s" % self.guid
          self.port_info_tunl = []
-         self._nodes = []
          self._pid = None
          self._ppid = None
          self._vroute = None
+         self._node_endpoint1 = None
+         self._node_endpoint2 = None
  
      def log_message(self, msg):
          return " guid %d - Tunnel - %s " % (self.guid, msg)
  
-     @property
-     def node(self):
-         if self._nodes:
-             return self._nodes[0]
      def app_home(self, node):
-         return os.path.join(self.node.exp_home, self._home)
+         return os.path.join(node.exp_home, self._home)
  
      def run_home(self, node):
          return os.path.join(self.app_home(node), self.ec.run_id)
  
-     def port_endpoints(self):
-         # Switch-Switch connection
-         connected = []
+     @property
+     def tap(self):
+         """ Return the Tap RM if it exists """
+         rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype())
          for guid in self.connections:
              rm = self.ec.get_resource(guid)
-             if hasattr(rm, "create_port"):
-                 connected.append(rm)
-         return connected
+             if isinstance(rm, rclass):
+                 return rm
  
-     
-     def mixed_endpoints(self):
-         # Switch-Host connection
-         connected = [1, 2]
+     @property
+     def ovsswitch(self):
+         """ Return the 1st switch """
+         for guid in self.connections:
+             rm_port = self.ec.get_resource(guid)
+             if hasattr(rm_port, "create_port"):
+                 rm_list = rm_port.get_connected(OVSSwitch.get_rtype())
+                 if rm_list:
+                     return rm_list[0]
+     @property         
+     def check_switch_host_link(self):
+         """ Check if the links are between switches
+             or switch-host. Return False for the latter.
+         """
+         if self.tap :
+             return True
+         return False
+     def endpoints(self):
+         """ Return the list with the two connected elements.
+         Either Switch-Switch or Switch-Host
+         """
+         connected = [1, 1]
+         position = 0
          for guid in self.connections:
              rm = self.ec.get_resource(guid)
              if hasattr(rm, "create_port"):
-                 connected[0] = rm
+                 connected[position] = rm
+                 position += 1
              elif hasattr(rm, "udp_connect_command"):
                  connected[1] = rm
          return connected
  
      def get_node(self, endpoint):
-         # Get connected to the nodes
-         res = []
+         """ Get the nodes of the endpoint
+         """
+         rm = []
          if hasattr(endpoint, "create_port"):
-             rm_list = endpoint.get_connected(OVSWitch.get_rtype())
+             rm_list = endpoint.get_connected(OVSSwitch.get_rtype())
              if rm_list:
                  rm = rm_list[0].get_connected(PlanetlabNode.get_rtype())
          else:
              rm = endpoint.get_connected(PlanetlabNode.get_rtype())
  
          if rm :
-             res.append(rm[0])
-         return res
+             return rm[0]
  
      @property
      def endpoint1(self):
-         if self.check_endpoints:
-             port_endpoints = self.port_endpoints()
-             if port_endpoints: return port_endpoints[0]
-         else:
-             mixed_endpoints = self.mixed_endpoints()
-             if mixed_endpoints: return mixed_endpoints[0]
+         """ Return the first endpoint : Always a Switch
+         """
+         endpoint = self.endpoints()
+         return endpoint[0]
  
      @property
      def endpoint2(self):
-         if self.check_endpoints:
-             port_endpoints = self.port_endpoints()
-             if port_endpoints: return port_endpoints[1]
-         else:
-             mixed_endpoints = self.mixed_endpoints()
-             if mixed_endpoints: return mixed_endpoints[1]
-     @property          
-     def check_endpoints(self):
-         """ Check if the links are between switches
-             or switch-host. Return False for latter.
+         """ Return the second endpoint : Either a Switch or a TAP
          """
-         port_endpoints = self.port_endpoints()
-         if len(port_endpoints) == 2:
-             return True
-         return False
+         endpoint = self.endpoints()
+         return endpoint[1]
  
-     def get_port_info(self, endpoint, rem_endpoint):
+     def get_port_info(self, endpoint1, endpoint2):
+         #TODO : Need to change it. Really bad to have method that return different type of things !!!!!
          """ Retrieve the port_info list for each port
        
-             :param port_info_tunl: [hostname, publ_IP_addr, port_name,
-                 virtual_ip, local_port_Numb]
-             :type port_info_tunl: list
-         """
-         self.port_info_tunl = []
-         if self.check_endpoints:
-             # Use for the link switch-->switch
-             self.port_info_tunl.append(endpoint.port_info)
-             host0, ip0, pname0, virt_ip0, pnumber0 = self.port_info_tunl[0]
-             self.port_info_tunl.append(rem_endpoint.port_info)
-             host1, ip1, pname1, virt_ip1, pnumber1 = self.port_info_tunl[1]
-             return (pname0, ip1, pnumber1)      
-          
-         # Use for the link host-->switch
-         self.port_info_tunl.append(endpoint.port_info)
-         host0, ip0, pname0, virt_ip0, pnumber0 = self.port_info_tunl[0]
-         return pnumber0
-     
-     def udp_connect(self, endpoint, rem_endpoint):     
-         # Collect info from rem_endpoint
-         self._nodes = self.get_node(rem_endpoint)
-         remote_ip = socket.gethostbyname(self.node.get("hostname"))
-         # Collect info from endpoint
-         self._nodes = self.get_node(endpoint) 
-         local_port_file = os.path.join(self.run_home(self.node), 
-                 "local_port")
-         remote_port_file = os.path.join(self.run_home(self.node), 
-                 "remote_port")
-         ret_file = os.path.join(self.run_home(self.node), 
-                 "ret_file")
-         cipher = self.get("cipher")
-         cipher_key = self.get("cipherKey")
-         bwlimit = self.get("bwLimit")
-         txqueuelen = self.get("txQueueLen")
-         rem_port = str(self.get_port_info(rem_endpoint, endpoint))           
-         # Upload the remote port in a file
-         self.node.upload(rem_port,
-                 remote_port_file,
-                 text = True,
-                 overwrite = False)
-        
-         udp_connect_command = endpoint.udp_connect_command(
-                 remote_ip, local_port_file, remote_port_file,
-                 ret_file, cipher, cipher_key, bwlimit, txqueuelen) 
-         # upload command to host_connect.sh script
-         shfile = os.path.join(self.app_home(self.node), "host_connect.sh")
-         self.node.upload(udp_connect_command,
-                 shfile,
-                 text = True,
-                 overwrite = False)
-         # invoke connect script
-         cmd = "bash %s" % shfile
-         (out, err), proc = self.node.run(cmd, self.run_home(self.node),
-                 sudo  = True,
-                 stdout = "udp_stdout",
-                 stderr = "udp_stderr")
-         # check if execution errors
-         msg = "Failed to connect endpoints"
-         if proc.poll():
-             self.error(msg, out, err)
-             raise RuntimeError, msg
-         msg = "Connection on host %s configured" \
-             % self.node.get("hostname")
-         self.debug(msg)
-          
-         # Wait for pid file to be generated
-         self._nodes = self.get_node(endpoint) 
-         pid, ppid = self.node.wait_pid(self.run_home(self.node))
-         
-         # If the process is not running, check for error information
-         # on the remote machine
-         if not pid or not ppid:
-             (out, err), proc = self.node.check_errors(self.run_home(self.node))
-             # Out is what was written in the stderr file
-             if err:
-                 msg = " Failed to start command '%s' " % command
-                 self.error(msg, out, err)
-                 raise RuntimeError, msg
-                 
-         return (pid, ppid)
-     def switch_connect(self, endpoint, rem_endpoint):
-         """ Get switch connect command
          """
-         # Get and configure switch connection command
-         (local_port_name, remote_ip, remote_port_num) = self.get_port_info(
-                 endpoint, rem_endpoint)
-         switch_connect_command = endpoint.switch_connect_command(
-                 local_port_name, remote_ip, remote_port_num)
-         self._nodes = self.get_node(endpoint) 
-         # Upload command to the file sw_connect.sh
-         shfile = os.path.join(self.app_home(self.node), "sw_connect.sh")
-         self.node.upload(switch_connect_command,
-                 shfile,
-                 text = True,
-                 overwrite = False)
+         if self.check_switch_host_link :
+             host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info
+             return pnumber0
  
-         #invoke connect script
-         cmd = "bash %s" % shfile
-         (out, err), proc = self.node.run(cmd, self.run_home(self.node),
-                 sudo  = True,
-                 stdout = "sw_stdout",
-                 stderr = "sw_stderr")
-         
-         # check if execution errors occured
-         if proc.poll():
-             msg = "Failed to connect endpoints"
-             self.error(msg, out, err)
-             raise RuntimeError, msg
-         # For debugging
-         msg = "Connection on port %s configured" % local_port_name
-         self.info(msg)
+         host0, ip0, pname0, virt_ip0, pnumber0 = endpoint1.port_info
+         host1, ip1, pname1, virt_ip1, pnumber1 = endpoint2.port_info
  
-     def wait_local_port(self):
+         return pname0, ip1, pnumber1
+     
+     def wait_local_port(self, node_endpoint):
          """ Waits until the if_name file for the command is generated, 
              and returns the if_name for the device """
          local_port = None
          delay = 1.0
  
+         #TODO : Need to change it with reschedule to avoid the problem 
+         #        of the order of connection
          for i in xrange(10):
-             (out, err), proc = self.node.check_output(self.run_home(self.node), 'local_port')
+             (out, err), proc = node_endpoint.check_output(self.run_home(node_endpoint), 'local_port')
              if out:
                  local_port = int(out)
                  break
  
          return local_port
  
-     def sw_host_connect(self, endpoint, rem_endpoint):
-         """Link switch--> host
+     def connection(self, local_endpoint, rm_endpoint):
+         """ Create the connect command for each case : 
+               - Host - Switch,  
+               - Switch - Switch,  
+               - Switch - Host
          """
-         # Retrieve remote port number from rem_endpoint
-         local_port_name = endpoint.get('port_name')
-         self._nodes = self.get_node(rem_endpoint)
-      #   time.sleep(4) # Without this, sometimes I get nothing in remote_port_num
-         out = err= ''
-         remote_port_num = self.wait_local_port()
-         remote_ip = socket.gethostbyname(self.node.get("hostname"))
-         switch_connect_command = endpoint.switch_connect_command(
-                 local_port_name, remote_ip, remote_port_num)
-         # Upload command to the file sw_connect.sh
-         self._nodes = self.get_node(endpoint) 
-         shfile = os.path.join(self.app_home(self.node), "sw_connect.sh")
-         self.node.upload(switch_connect_command,
+         local_node = self.get_node(local_endpoint)
+         local_node.mkdir(self.run_home(local_node))
+         rm_node = self.get_node(rm_endpoint)
+         rm_node.mkdir(self.run_home(rm_node))
+         # Host to switch
+         if self.check_switch_host_link and local_endpoint == self.endpoint2 :
+         # Collect info from rem_endpoint
+             remote_ip = socket.gethostbyname(rm_node.get("hostname"))
+         # Collect info from endpoint
+             local_port_file = os.path.join(self.run_home(local_node), "local_port")
+             rem_port_file = os.path.join(self.run_home(local_node), "remote_port")
+             ret_file = os.path.join(self.run_home(local_node), "ret_file")
+             cipher = self.get("cipher")
+             cipher_key = self.get("cipherKey")
+             bwlimit = self.get("bwLimit")
+             txqueuelen = self.get("txQueueLen")
+             rem_port = str(self.get_port_info(rm_endpoint,local_endpoint))
+    
+         # Upload the remote port in a file
+             local_node.upload(rem_port, rem_port_file,
+                  text = True,
+                  overwrite = False)
+        
+             connect_command = local_endpoint.udp_connect_command(
+                  remote_ip, local_port_file, rem_port_file,
+                  ret_file, cipher, cipher_key, bwlimit, txqueuelen) 
+             self.connection_command(connect_command, local_node, rm_node)
+         # Wait for pid file to be generated
+             self._pid, self._ppid = local_node.wait_pid(self.run_home(local_node))
+             if not self._pid or not self._ppid:
+                 (out, err), proc = local_node.check_errors(self.run_home(local_node))
+                 # Out is what was written in the stderr file
+                 if err:
+                     msg = " Failed to start connection of the OVS Tunnel "
+                     self.error(msg, out, err)
+                     raise RuntimeError, msg
+             return
+         # Switch to Host
+         if self.check_switch_host_link and local_endpoint == self.endpoint1:
+             local_port_name = local_endpoint.get('port_name')
+             remote_port_num = self.wait_local_port(rm_node)
+             remote_ip = socket.gethostbyname(rm_node.get("hostname"))
+   
+         # Switch to Switch
+         if not self.check_switch_host_link :
+             local_port_name, remote_ip, remote_port_num = self.get_port_info(local_endpoint, rm_endpoint)
+         connect_command = local_endpoint.switch_connect_command(
+                     local_port_name, remote_ip, remote_port_num)
+         self.connection_command(connect_command, local_node, rm_node)       
+     def connection_command(self, command, node_endpoint, rm_node_endpoint):
+         """ Execute the connection command on the node and check if the processus is
+             correctly running on the node.
+         """
+         shfile = os.path.join(self.app_home(node_endpoint), "sw_connect.sh")
+         node_endpoint.upload(command,
                  shfile,
                  text = True,
                  overwrite = False)
  
          # Invoke connect script
+         out = err= ''       
          cmd = "bash %s" % shfile
-         (out, err), proc = self.node.run(cmd, self.run_home(self.node),
+         (out, err), proc = node_endpoint.run(cmd, self.run_home(node_endpoint),
                  sudo  = True,
                  stdout = "sw_stdout",
                  stderr = "sw_stderr")
              raise RuntimeError, msg
  
          # For debugging
-         msg = "Connection on port %s configured" % local_port_name
-         self.debug(msg)                                                   
+         msg = "Connection on port configured"
+         self.debug(msg)
  
      def do_provision(self):
          """ Provision the tunnel
          """
-         # Create folders
-         self._nodes = self.get_node(self.endpoint1)
-         self.node.mkdir(self.run_home(self.node))
-         self._nodes = self.get_node(self.endpoint2)
-         self.node.mkdir(self.run_home(self.node))
-         if self.check_endpoints:
-             #Invoke connect script between switches
-             self.switch_connect(self.endpoint1, self.endpoint2)
-             self.switch_connect(self.endpoint2, self.endpoint1)
-         else: 
-             # Invoke connect script between switch & host
-             (self._pid, self._ppid) = self.udp_connect(self.endpoint2, self.endpoint1)
-             self.sw_host_connect(self.endpoint1, self.endpoint2)
-         super(OVSTunnel, self).do_provision()
+         
+         #TODO : The order of the connection is important for now ! 
+         # Need to change the code of wait local port
+         self.connection(self.endpoint2, self.endpoint1)
+         self.connection(self.endpoint1, self.endpoint2)
  
-     @property
-     def tap(self):
-         rclass = ResourceFactory.get_resource_type(PlanetlabTap.get_rtype())
-         for guid in self.connections:
-             rm = self.ec.get_resource(guid)
-             if isinstance(rm, rclass):
-                 return rm
+     def configure_route(self):
+         """ Configure the route for the tap device
  
-     @property
-     def ovswitch(self):
-         for guid in self.connections:
-             rm_port = self.ec.get_resource(guid)
-             if hasattr(rm_port, "create_port"):
-                 rm_list = rm_port.get_connected(OVSWitch.get_rtype())
-                 if rm_list:
-                     return rm_list[0]
+             .. note : In case of a conection between a switch and a host, a route
+                       was missing on the node with the Tap Device. This method create
+                       the missing route. 
+         """
  
-     def configure(self):
-         if not self.check_endpoints:
+         if  self.check_switch_host_link:
              self._vroute = self.ec.register_resource("PlanetlabVroute")
              self.ec.set(self._vroute, "action", "add")
              self.ec.set(self._vroute, "network", self.get("network"))
  
              self.ec.register_connection(self._vroute, self.tap.guid)
-             # schedule deploy
              self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
  
      def do_deploy(self):
+         """ Deploy the tunnel after the endpoint get ready
+         """
          if (not self.endpoint1 or self.endpoint1.state < ResourceState.READY) or \
              (not self.endpoint2 or self.endpoint2.state < ResourceState.READY):
              self.ec.schedule(reschedule_delay, self.deploy)
  
          self.do_discover()
          self.do_provision()
-         self.configure()
-         super(OVSTunnel, self).do_deploy()
+         self.configure_route()
+         # Cannot call the deploy of the linux application 
+         #         because of a log error.
+         # Need to investigate if it is right that the tunnel 
+         #    inherits from the linux application
+         #  super(OVSTunnel, self).do_deploy()
+         self.set_ready()
   
      def do_release(self):
-         """ Release the udp_tunnel on endpoint2.
-             On endpoint1 means nothing special.        
+         """ Release the tunnel by releasing the Tap Device if exists
          """
-         if not self.check_endpoints:
-             # Kill the TAP devices
+         if self.check_switch_host_link:
              # TODO: Make more generic Release method of PLTAP
+             tap_node = self.get_node(self.endpoint2)
              if self._pid and self._ppid:
-                 self._nodes = self.get_node(self.endpoint2) 
-                 (out, err), proc = self.node.kill(self._pid,
+                 (out, err), proc = tap_node.kill(self._pid,
                          self._ppid, sudo = True)
                  if err or proc.poll():
-                     # check if execution errors occurred
                      msg = " Failed to delete TAP device"
-                     self.error(msg, err, err)
+                     self.error(msg, out, err)
  
          super(OVSTunnel, self).do_release()
  
@@@ -42,35 -42,35 +42,35 @@@ class PlanetlabTap(LinuxApplication)
      @classmethod
      def _register_attributes(cls):
          ip4 = Attribute("ip4", "IPv4 Address",
 -              flags = Flags.ExecReadOnly)
 +              flags = Flags.Design)
  
          mac = Attribute("mac", "MAC Address",
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          prefix4 = Attribute("prefix4", "IPv4 network prefix",
                  type = Types.Integer,
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          mtu = Attribute("mtu", "Maximum transmition unit for device",
                  type = Types.Integer)
  
          devname = Attribute("deviceName", 
                  "Name of the network interface (e.g. eth0, wlan0, etc)",
 -                flags = Flags.ReadOnly)
 +                flags = Flags.NoWrite)
  
          up = Attribute("up", "Link up", 
                  type = Types.Bool)
          
          snat = Attribute("snat", "Set SNAT=1", 
                  type = Types.Bool,
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
          
          pointopoint = Attribute("pointopoint", "Peer IP address", 
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          tear_down = Attribute("tearDown", "Bash script to be executed before " + \
                  "releasing the resource",
 -                flags = Flags.ExecReadOnly)
 +                flags = Flags.Design)
  
          cls._register_attribute(ip4)
          cls._register_attribute(mac)
              self.do_discover()
              self.do_provision()
  
 -            self.debug("----- READY ---- ")
              self.set_ready()
  
      def do_start(self):
          if_name = None
          delay = 1.0
  
-         for i in xrange(10):
+         for i in xrange(20):
              (out, err), proc = self.node.check_output(self.run_home, "if_name")
  
              if out: