From 7a40d6db82dc5fd7de026b39fdc2bc35887c4e07 Mon Sep 17 00:00:00 2001 From: Julien Tribino Date: Mon, 19 May 2014 16:56:45 +0200 Subject: [PATCH] Add documentation to various OVS RM and change the RM name OVSWitch to OVSSwitch --- examples/openvswitch/ovs_ping_2switches.py | 2 +- .../openvswitch/ovs_ping_3switches_line.py | 2 +- .../openvswitch/ovs_ping_3switches_loop.py | 2 +- .../resources/planetlab/openvswitch/ovs.py | 114 ++++--- .../planetlab/openvswitch/ovsport.py | 100 +++--- .../resources/planetlab/openvswitch/tunnel.py | 318 +++++++----------- test/resources/planetlab/ovs.py | 4 +- 7 files changed, 243 insertions(+), 299 deletions(-) diff --git a/examples/openvswitch/ovs_ping_2switches.py b/examples/openvswitch/ovs_ping_2switches.py index a7110e67..7fbb74b4 100644 --- a/examples/openvswitch/ovs_ping_2switches.py +++ b/examples/openvswitch/ovs_ping_2switches.py @@ -47,7 +47,7 @@ def add_node(ec, host, user, pl_user, pl_password): return node def add_ovs(ec, bridge_name, virtual_ip_pref, controller_ip, controller_port, node): - ovs = ec.register_resource("OVSWitch") + ovs = ec.register_resource("OVSSwitch") ec.set(ovs, "bridge_name", bridge_name) ec.set(ovs, "virtual_ip_pref", virtual_ip_pref) ec.set(ovs, "controller_ip", controller_ip) diff --git a/examples/openvswitch/ovs_ping_3switches_line.py b/examples/openvswitch/ovs_ping_3switches_line.py index 30909ffc..ca1ebeed 100644 --- a/examples/openvswitch/ovs_ping_3switches_line.py +++ b/examples/openvswitch/ovs_ping_3switches_line.py @@ -46,7 +46,7 @@ def add_node(ec, host, user, pl_user, pl_password): return node def add_ovs(ec, bridge_name, virtual_ip_pref, controller_ip, controller_port, node): - ovs = ec.register_resource("OVSWitch") + ovs = ec.register_resource("OVSSwitch") ec.set(ovs, "bridge_name", bridge_name) ec.set(ovs, "virtual_ip_pref", virtual_ip_pref) ec.set(ovs, "controller_ip", controller_ip) diff --git a/examples/openvswitch/ovs_ping_3switches_loop.py b/examples/openvswitch/ovs_ping_3switches_loop.py index 9caea39f..54b2083d 100644 --- a/examples/openvswitch/ovs_ping_3switches_loop.py +++ b/examples/openvswitch/ovs_ping_3switches_loop.py @@ -55,7 +55,7 @@ def add_node(ec, host, user, pl_user, pl_password): return node def add_ovs(ec, bridge_name, virtual_ip_pref, controller_ip, controller_port, node): - ovs = ec.register_resource("OVSWitch") + ovs = ec.register_resource("OVSSwitch") ec.set(ovs, "bridge_name", bridge_name) ec.set(ovs, "virtual_ip_pref", virtual_ip_pref) ec.set(ovs, "controller_ip", controller_ip) diff --git a/src/nepi/resources/planetlab/openvswitch/ovs.py b/src/nepi/resources/planetlab/openvswitch/ovs.py index 65a1ec59..a2111f47 100644 --- a/src/nepi/resources/planetlab/openvswitch/ovs.py +++ b/src/nepi/resources/planetlab/openvswitch/ovs.py @@ -29,8 +29,18 @@ import os 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" @@ -38,7 +48,7 @@ class OVSWitch(LinuxApplication): @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", @@ -63,18 +73,21 @@ class OVSWitch(LinuxApplication): :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) @@ -83,66 +96,60 @@ class OVSWitch(LinuxApplication): 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): - """ Wait until node is associated and deployed + """ 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(OVSWitch, self).do_deploy() + 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 = "" @@ -165,8 +172,7 @@ class OVSWitch(LinuxApplication): 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 """ # Start the server @@ -205,18 +211,12 @@ class OVSWitch(LinuxApplication): self.info("Server OVS Started Correctly") -# def del_old_br(self): -# # TODO: Delete old bridges that might exist maybe by adding atribute -# """ With ovs-vsctl list-br -# """ -# pass - 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" @@ -269,8 +269,9 @@ class OVSWitch(LinuxApplication): self.info("Controller assigned to the bridge %s" % self.get("bridge_name")) def ovs_status(self): - """ Print the status of the 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, @@ -284,11 +285,12 @@ class OVSWitch(LinuxApplication): self.error(msg) raise RuntimeError, msg - self.info(out) + self.debug(out) def do_release(self): - """ Delete the bridge and close the servers. - It need to wait for the others RM (OVSPort and OVSTunnel) + """ 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 """ @@ -315,5 +317,5 @@ class OVSWitch(LinuxApplication): self.error(msg, out, err) raise RuntimeError, msg - super(OVSWitch, self).do_release() + super(OVSSwitch, self).do_release() diff --git a/src/nepi/resources/planetlab/openvswitch/ovsport.py b/src/nepi/resources/planetlab/openvswitch/ovsport.py index 74a8baa0..554a1160 100644 --- a/src/nepi/resources/planetlab/openvswitch/ovsport.py +++ b/src/nepi/resources/planetlab/openvswitch/ovsport.py @@ -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 @@ 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): @@ -67,9 +67,14 @@ class OVSPort(LinuxApplication): 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()) @@ -77,9 +82,11 @@ class OVSPort(LinuxApplication): 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 @@ -87,33 +94,21 @@ class OVSPort(LinuxApplication): 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_ip(self): - """ Return the ip of the node. This data is necessary to - create the tunnel. + """ 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) - import socket - return socket.gethostbyname(self.node.get('hostname')) - def create_port(self): """ Create the desired port """ @@ -125,20 +120,20 @@ class OVSPort(LinuxApplication): self.error(msg) raise AttributeError, msg - if not self.ovswitch: + 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.ovswitch.get('bridge_name'), + cmd = "sliver-ovs create-port %s %s" % (self.ovsswitch.get('bridge_name'), self.get('port_name')) - self.node.run(cmd, self.ovswitch.ovs_checks, + 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.ovswitch.get('bridge_name'))) + self.ovsswitch.get('bridge_name'))) def get_local_end(self): """ Get the local_endpoint of the port @@ -150,7 +145,7 @@ class OVSPort(LinuxApplication): 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, + 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'), @@ -169,19 +164,29 @@ class OVSPort(LinuxApplication): self.info("The number of the %s is %s" % (self.get('port_name'), self.port_number)) - def set_port_info(self, ip): + 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.ovswitch.get('virtual_ip_pref')) + 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) @@ -192,22 +197,25 @@ class OVSPort(LinuxApplication): return command def do_deploy(self): - """ Wait until ovswitch is started + """ Deploy the OVS port after the OVS Switch """ - if not self.ovswitch or self.ovswitch.state < ResourceState.READY: - self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch 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() - ip = self.get_ip() + self.create_port() self.get_local_end() - self.ovswitch.ovs_status() - self.port_info = self.set_port_info(ip) + #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() @@ -224,7 +232,7 @@ class OVSPort(LinuxApplication): return 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') diff --git a/src/nepi/resources/planetlab/openvswitch/tunnel.py b/src/nepi/resources/planetlab/openvswitch/tunnel.py index c9c27119..23b08467 100644 --- a/src/nepi/resources/planetlab/openvswitch/tunnel.py +++ b/src/nepi/resources/planetlab/openvswitch/tunnel.py @@ -24,7 +24,7 @@ from nepi.execution.resource import ResourceManager, ResourceFactory, clsinit_co 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,7 +54,7 @@ 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", @@ -120,7 +120,7 @@ class OVSTunnel(LinuxApplication): @property def tap(self): - ''' Return the Tap RM if it exists ''' + """ 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) @@ -128,29 +128,29 @@ class OVSTunnel(LinuxApplication): return rm @property - def ovswitch(self): - ''' Return the 1st switch ''' + 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(OVSWitch.get_rtype()) + 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 latter. - ''' + """ 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. + """ Return the list with the two connected elements. Either Switch-Switch or Switch-Host - ''' + """ connected = [1, 1] position = 0 for guid in self.connections: @@ -162,32 +162,12 @@ class OVSTunnel(LinuxApplication): connected[1] = rm return connected -# def port_endpoints(self): -# # Switch-Switch connection -# connected = [] -# for guid in self.connections: -# rm = self.ec.get_resource(guid) -# if hasattr(rm, "create_port"): -# connected.append(rm) -# return connected - -# -# def mixed_endpoints(self): -# # Switch-Host connection -# connected = [1, 2] -# for guid in self.connections: -# rm = self.ec.get_resource(guid) -# if hasattr(rm, "create_port"): -# connected[0] = rm -# elif hasattr(rm, "udp_connect_command"): -# connected[1] = rm -# return connected - def get_node(self, endpoint): - # Get connected to the nodes + """ 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: @@ -198,26 +178,20 @@ class OVSTunnel(LinuxApplication): @property def endpoint1(self): - endpoint = self.endpoints() - return endpoint[0] + """ Return the first endpoint : Always a Switch + """ + endpoint = self.endpoints() + return endpoint[0] @property def endpoint2(self): - endpoint = self.endpoints() - return endpoint[1] - -# @property -# def check_endpoints(self): -# """ Check if the links are between switches -# or switch-host. Return False for latter. -# """ -# port_endpoints = self.port_endpoints() -# if len(port_endpoints) == 2: -# return True -# return False + """ Return the second endpoint : Either a Switch or a TAP + """ + endpoint = self.endpoints() + return endpoint[1] def get_port_info(self, endpoint1, endpoint2): - # Need to change it. Not good to have method that return different type of things !!!!! + #TODO : Need to change it. Really bad to have method that return different type of things !!!!! """ Retrieve the port_info list for each port """ @@ -230,111 +204,17 @@ class OVSTunnel(LinuxApplication): return pname0, ip1, pnumber1 - def host_to_switch_connect(self, tap_endpoint, sw_endpoint): - # Collect info from rem_endpoint - remote_ip = socket.gethostbyname(self.node_endpoint1.get("hostname")) - - # Collect info from endpoint - local_port_file = os.path.join(self.run_home(self.node_endpoint2), "local_port") - rem_port_file = os.path.join(self.run_home(self.node_endpoint2), "remote_port") - ret_file = os.path.join(self.run_home(self.node_endpoint2), "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( sw_endpoint,tap_endpoint)) - - # Upload the remote port in a file - self.node_endpoint2.upload(rem_port, rem_port_file, - text = True, - overwrite = False) - - udp_connect_command = tap_endpoint.udp_connect_command( - remote_ip, local_port_file, rem_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_endpoint2), "host_connect.sh") - self.node_endpoint2.upload(udp_connect_command, shfile, - text = True, - overwrite = False) - - # invoke connect script - cmd = "bash %s" % shfile - (out, err), proc = self.node_endpoint2.run(cmd, self.run_home(self.node_endpoint2), - sudo = True, - stdout = "udp_stdout", - stderr = "udp_stderr") - - # check if execution errors - if proc.poll(): - msg = "Failed to connect endpoints" - self.error(msg, out, err) - raise RuntimeError, msg - - msg = "Connection on host %s configured" % self.node_endpoint2.get("hostname") - self.debug(msg) - - # Wait for pid file to be generated - pid, ppid = self.node_endpoint2.wait_pid(self.run_home(self.node_endpoint2)) - - # 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_endpoint2.check_errors(self.run_home(self.node_endpoint2)) - # 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_to_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) - node_endpoint = self.get_node(endpoint) - - # Upload command to the file sw_connect.sh - shfile = os.path.join(self.app_home(node_endpoint), "sw_connect.sh") - node_endpoint.upload(switch_connect_command, - shfile, - text = True, - overwrite = False) - - #invoke connect script - cmd = "bash %s" % shfile - (out, err), proc = node_endpoint.run(cmd, self.run_home(node_endpoint), - 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) - - def wait_local_port(self): + 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_endpoint2.check_output(self.run_home(self.node_endpoint2), 'local_port') + (out, err), proc = node_endpoint.check_output(self.run_home(node_endpoint), 'local_port') if out: local_port = int(out) break @@ -348,28 +228,86 @@ class OVSTunnel(LinuxApplication): return local_port - def switch_to_host_connect(self, sw_endpoint, host_endpoint): - """Link switch--> host + def connection(self, local_endpoint, rm_endpoint): + """ Create the connect command for each case : + - Host - Switch, + - Switch - Switch, + - Switch - Host + """ + 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. """ - # Retrieve remote port number from sw_endpoint - local_port_name = sw_endpoint.get('port_name') - - out = err= '' - remote_port_num = self.wait_local_port() - remote_ip = socket.gethostbyname(self.node_endpoint2.get("hostname")) - switch_connect_command = sw_endpoint.switch_connect_command( - local_port_name, remote_ip, remote_port_num) - - # Upload command to the file sw_connect.sh - shfile = os.path.join(self.app_home(self.node_endpoint1), "sw_connect.sh") - self.node_endpoint1.upload(switch_connect_command, + 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_endpoint1.run(cmd, self.run_home(self.node_endpoint1), + (out, err), proc = node_endpoint.run(cmd, self.run_home(node_endpoint), sudo = True, stdout = "sw_stdout", stderr = "sw_stderr") @@ -382,44 +320,37 @@ class OVSTunnel(LinuxApplication): 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 - - ..note : Endpoint 1 is always a OVSPort. - Endpoint 2 can be either a OVSPort or a Tap - """ - self.node_endpoint1 = self.get_node(self.endpoint1) - self.node_endpoint1.mkdir(self.run_home(self.node_endpoint1)) - - self.node_endpoint2 = self.get_node(self.endpoint2) - self.node_endpoint2.mkdir(self.run_home(self.node_endpoint2)) + + #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) - if not self.check_switch_host_link: - # Invoke connect script between switches - self.switch_to_switch_connect(self.endpoint1, self.endpoint2) - self.switch_to_switch_connect(self.endpoint2, self.endpoint1) - else: - # Invoke connect script between switch & host - (self._pid, self._ppid) = self.host_to_switch_connect(self.endpoint2, self.endpoint1) - self.switch_to_host_connect(self.endpoint1, self.endpoint2) + def configure_route(self): + """ Configure the route for the tap device - #super(OVSTunnel, self).do_provision() + .. 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 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) @@ -427,20 +358,23 @@ class OVSTunnel(LinuxApplication): self.do_discover() self.do_provision() - self.configure() + 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() - #super(OVSTunnel, self).do_deploy() 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_switch_host_link: - # 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: - (out, err), proc = self.node_enpoint2.kill(self._pid, + (out, err), proc = tap_node.kill(self._pid, self._ppid, sudo = True) if err or proc.poll(): diff --git a/test/resources/planetlab/ovs.py b/test/resources/planetlab/ovs.py index d0720740..e76a6e66 100644 --- a/test/resources/planetlab/ovs.py +++ b/test/resources/planetlab/ovs.py @@ -52,7 +52,7 @@ class OvsTestCase(unittest.TestCase): ec.set(node1, "cleanHome", True) ec.set(node1, "cleanProcesses", True) - ovs1 = ec.register_resource("OVSWitch") + ovs1 = ec.register_resource("OVSSwitch") ec.set(ovs1, "bridge_name", "nepi_bridge") ec.set(ovs1, "virtual_ip_pref", "192.168.3.1/24") ec.set(ovs1, "controller_ip", "85.23.168.77") @@ -73,7 +73,7 @@ class OvsTestCase(unittest.TestCase): ec.set(node2, "cleanHome", True) ec.set(node2, "cleanProcesses", True) - ovs2 = ec.register_resource("OVSWitch") + ovs2 = ec.register_resource("OVSSwitch") ec.set(ovs2, "bridge_name", "nepi_bridge") ec.set(ovs2, "virtual_ip_pref", "192.168.3.2/24") ec.set(ovs2, "controller_ip", "85.23.168.77") -- 2.43.0