X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=src%2Fnepi%2Fresources%2Fplanetlab%2Fopenvswitch%2Fovs.py;h=a3cf2faeeaa2cbc64f7bca88fb6e1b3e7d56e3fc;hb=6285ca51026efb69642eea9dfc7c480e722d84a9;hp=e8b8011e89ef0764607e0ff51447cac654765b0c;hpb=98404dbb5666f17408ed6166d47bba12110a12f1;p=nepi.git diff --git a/src/nepi/resources/planetlab/openvswitch/ovs.py b/src/nepi/resources/planetlab/openvswitch/ovs.py index e8b8011e..a3cf2fae 100644 --- a/src/nepi/resources/planetlab/openvswitch/ovs.py +++ b/src/nepi/resources/planetlab/openvswitch/ovs.py @@ -3,9 +3,8 @@ # 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 @@ -15,37 +14,53 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -# Author: Alina Quereilhac +# Authors: Alina Quereilhac # Alexandros Kouvakas +# Julien Tribino -from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState +from nepi.execution.resource import ResourceManager, clsinit_copy, \ + ResourceState 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 -class OVSWitch(LinuxApplication): - - _rtype = "OVSWitch" - _authorized_connections = ["PlanetlabNode", "OVSPort", "LinuxNode"] +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" + _platform = "planetlab" + + _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"] @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) @@ -58,264 +73,243 @@ class OVSWitch(LinuxApplication): :type ec: ExperimentController :param guid: guid of the RM :type guid: int - :param creds: Credentials to communicate with the rm - :type creds: dict """ - 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): - 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 - 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): - """ 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) - raise RuntimeError, msg - msg = "Command sliver-ovs exists" - self.debug(msg) - - def 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) - - else: - try: - self.discover() - self.provision() - self.check_sliver_ovs() - self.servers_on() - self.create_bridge() - self.assign_contr() - self.ovs_status() - except: - self._state = ResourceState.FAILED - raise - - self._state = ResourceState.READY + raise RuntimeError(msg) def servers_on(self): - """ Start the openvswitch servers and also checking - if they started successfully - """ - 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 - 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 + """ Start the openvswitch servers and check it """ - pass + # 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) + + 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 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 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("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 + raise AttributeError(msg) + + command = "sliver-ovs create-bridge '%s' '%s'" % ( + self.get("bridge_name"), + self.get("virtual_ip_pref")) + + 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) - def assign_contr(self): + 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") - - def ovs_status(self): - """ Print the status of the created bridge + + if not (self.get("controller_ip") and self.get("controller_port")): + return + """ - 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 start(self): - """ Start the RM. It means nothing special for - ovswitch for now. + 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 """ - pass + 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) - def stop(self): - """ Stop the RM.It means nothing - for ovswitch for now. + self.info("Controller assigned to the bridge %s" % self.get("bridge_name")) + + def ovs_status(self): + """ Print the status of the bridge """ - pass + command = "sliver-ovs show | tail -n +2" + shfile = os.path.join(self.app_home, "ovs_status.sh") + try: + 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 - def release(self): - """ Delete the bridge and - close the servers """ - # 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.rtype()) - if rm[0].state < ResourceState.FINISHED: - self.ec.schedule(reschedule_delay, self.release) - return + 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 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 - - self._state = ResourceState.RELEASED + 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() +