2 # NEPI, a framework to manage network experiments
3 # Copyright (C) 2013 INRIA
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License version 2 as
7 # published by the Free Software Foundation;
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
18 # Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
19 # Julien Tribino <julien.tribino@inria.fr>
22 from nepi.execution.resource import ResourceManager, clsinit_copy, \
24 from nepi.execution.attribute import Attribute, Flags
25 from nepi.resources.planetlab.node import PlanetlabNode
26 from nepi.resources.linux.application import LinuxApplication
30 class PlanetlabOVSSwitch(LinuxApplication):
32 .. class:: Class Args :
34 :param ec: The Experiment controller
35 :type ec: ExperimentController
36 :param guid: guid of the RM
41 _rtype = "planetlab::OVSSwitch"
42 _help = "Runs an OpenVSwitch on a PlanetLab host"
43 _platform = "planetlab"
45 _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"]
48 def _register_attributes(cls):
49 """ Register the attributes of OVSSwitch RM
52 bridge_name = Attribute("bridge_name",
53 "Name of the switch/bridge",
55 virtual_ip_pref = Attribute("virtual_ip_pref",
56 "Virtual IP/PREFIX of the switch",
58 controller_ip = Attribute("controller_ip",
59 "IP of the controller",
61 controller_port = Attribute("controller_port",
62 "Port of the controller",
65 cls._register_attribute(bridge_name)
66 cls._register_attribute(virtual_ip_pref)
67 cls._register_attribute(controller_ip)
68 cls._register_attribute(controller_port)
70 def __init__(self, ec, guid):
72 :param ec: The Experiment controller
73 :type ec: ExperimentController
74 :param guid: guid of the RM
78 super(PlanetlabOVSSwitch, self).__init__(ec, guid)
79 self._home = "ovsswitch-%s" % self.guid
84 """ Node wthat run the switch
87 nodes = self.get_connected(PlanetlabNode.get_rtype())
88 if not nodes or len(nodes) != 1:
89 msg = "PlanetlabOVSSwitch must be connected to exactly one PlanetlabNode"
91 raise RuntimeError, msg
97 def valid_connection(self, guid):
98 """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.
100 :param guid: Guid of the current RM
105 rm = self.ec.get_resource(guid)
106 if rm.get_rtype() not in self._authorized_connections:
110 def do_provision(self):
111 self.node.mkdir(self.run_home)
113 self.check_sliver_ovs()
116 self.assign_controller()
119 self.set_provisioned()
122 """ Deploy the OVS Switch : Turn on the server, create the bridges
123 and assign the controller
126 if not self.node or self.node.state < ResourceState.READY:
127 self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state)
128 self.ec.schedule(self.reschedule_delay, self.deploy)
135 def check_sliver_ovs(self):
136 """ Check if sliver-ovs exists. If it does not exist, the execution is stopped
138 command = "compgen -c | grep sliver-ovs"
139 shfile = os.path.join(self.app_home, "check_ovs_cmd.sh")
141 self.node.run_and_wait(command, self.run_home,
144 pidfile="check_ovs_cmd_pidfile",
145 ecodefile="check_ovs_cmd_exitcode",
146 stdout="check_ovs_cmd_stdout",
147 stderr="check_ovs_cmd_stderr")
149 msg = "Command sliver-ovs does not exist on the VM"
151 raise RuntimeError, msg
153 def servers_on(self):
154 """ Start the openvswitch servers and check it
156 # Make sure the server is not running
157 command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
158 shfile = os.path.join(self.app_home, "clean.sh")
159 self.node.run_and_wait(command, self.run_home,
162 raise_on_error=False,
163 pidfile="clean_pidfile",
164 ecodefile="clean_exitcode",
165 stdout="clean_stdout",
166 stderr="clean_stderr")
169 command = "sliver-ovs start"
170 shfile = os.path.join(self.app_home, "start.sh")
172 self.node.run_and_wait(command, self.run_home,
175 pidfile="start_pidfile",
176 ecodefile="start_exitcode",
177 stdout="start_stdout",
178 stderr="start_stderr")
180 msg = "Failed to start ovs-server on VM"
182 raise RuntimeError, msg
184 command = "ps -A | grep ovsdb-server"
185 shfile = os.path.join(self.app_home, "ovsdb_status.sh")
187 self.node.run_and_wait(command, self.run_home,
190 pidfile="ovsdb_status_pidfile",
191 ecodefile="ovsdb_status_exitcode",
192 stdout="ovsdb_status_stdout",
193 stderr="ovsdb_status_stderr")
195 msg = "ovsdb-server not running on VM"
197 raise RuntimeError, msg
199 self.info("Server OVS Started...")
201 def create_bridge(self):
202 """ Create the bridge/switch and check error during SSH connection
204 # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br
205 # TODO: Add check for virtual_ip belonging to vsys_tag
206 if not (self.get("bridge_name") and self.get("virtual_ip_pref")):
207 msg = "No assignment in one or both attributes"
209 raise AttributeError, msg
211 command = "sliver-ovs create-bridge '%s' '%s'" % (
212 self.get("bridge_name"),
213 self.get("virtual_ip_pref"))
215 shfile = os.path.join(self.app_home, "bridge_create.sh")
217 self.node.run_and_wait(command, self.run_home,
220 pidfile="bridge_create_pidfile",
221 ecodefile="bridge_create_exitcode",
222 stdout="bridge_create_stdout",
223 stderr="bridge_create_stderr")
225 msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error"
227 raise RuntimeError, msg
229 self.info(" Bridge %s Created and Assigned to %s" %\
230 (self.get("bridge_name"), self.get("virtual_ip_pref")) )
232 def assign_controller(self):
233 """ Set the controller IP
236 if not (self.get("controller_ip") and self.get("controller_port")):
240 if not (self.get("controller_ip") and self.get("controller_port")):
241 msg = "No assignment in one or both attributes"
243 raise AttributeError, msg
245 command = "ovs-vsctl set-controller %s tcp:%s:%s" % \
246 (self.get("bridge_name"),
247 self.get("controller_ip"),
248 self.get("controller_port"))
250 shfile = os.path.join(self.app_home, "set_controller.sh")
252 self.node.run_and_wait(command, self.run_home,
255 pidfile="set_controller_pidfile",
256 ecodefile="set_controller_exitcode",
257 stdout="set_controller_stdout",
258 stderr="set_controller_stderr")
260 msg = "SSH connection in the method assign_controller"
262 raise RuntimeError, msg
264 self.info("Controller assigned to the bridge %s" % self.get("bridge_name"))
266 def ovs_status(self):
267 """ Print the status of the bridge
269 command = "sliver-ovs show | tail -n +2"
270 shfile = os.path.join(self.app_home, "ovs_status.sh")
272 self.node.run_and_wait(command, self.run_home,
275 pidfile="ovs_status_pidfile",
276 ecodefile="ovs_status_exitcode",
277 stdout="ovs_status_stdout",
278 stderr="ovs_status_stderr")
280 msg = "Error when checking the status of the OpenVswitch"
282 raise RuntimeError, msg
284 def do_release(self):
285 """ Delete the bridge and close the server.
287 .. note : It need to wait for the others RM (OVSPort and OVSTunnel)
288 to be released before releasing itself
292 from nepi.resources.planetlab.openvswitch.ovsport import PlanetlabOVSPort
293 rms = self.get_connected(PlanetlabOVSPort.get_rtype())
296 if rm.state < ResourceState.RELEASED:
297 self.ec.schedule(self.reschedule_delay, self.release)
300 msg = "Deleting the bridge %s" % self.get('bridge_name')
303 command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
304 shfile = os.path.join(self.app_home, "stop.sh")
306 self.node.run_and_wait(command, self.run_home,
309 pidfile="stop_pidfile",
310 ecodefile="stop_exitcode",
311 stdout="stop_stdout",
312 stderr="stop_stderr")
314 super(PlanetlabOVSSwitch, self).do_release()