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 as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 # Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
19 # Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
20 # Julien Tribino <julien.tribino@inria.fr>
23 from nepi.execution.resource import ResourceManager, clsinit_copy, \
25 from nepi.execution.attribute import Attribute, Flags
26 from nepi.resources.planetlab.node import PlanetlabNode
27 from nepi.resources.linux.application import LinuxApplication
31 class PlanetlabOVSSwitch(LinuxApplication):
33 .. class:: Class Args :
35 :param ec: The Experiment controller
36 :type ec: ExperimentController
37 :param guid: guid of the RM
42 _rtype = "planetlab::OVSSwitch"
43 _help = "Runs an OpenVSwitch on a PlanetLab host"
44 _platform = "planetlab"
46 _authorized_connections = ["planetlab::Node", "planetla::OVSPort", "linux::Node"]
49 def _register_attributes(cls):
50 """ Register the attributes of OVSSwitch RM
53 bridge_name = Attribute("bridge_name",
54 "Name of the switch/bridge",
56 virtual_ip_pref = Attribute("virtual_ip_pref",
57 "Virtual IP/PREFIX of the switch",
59 controller_ip = Attribute("controller_ip",
60 "IP of the controller",
62 controller_port = Attribute("controller_port",
63 "Port of the controller",
66 cls._register_attribute(bridge_name)
67 cls._register_attribute(virtual_ip_pref)
68 cls._register_attribute(controller_ip)
69 cls._register_attribute(controller_port)
71 def __init__(self, ec, guid):
73 :param ec: The Experiment controller
74 :type ec: ExperimentController
75 :param guid: guid of the RM
79 super(PlanetlabOVSSwitch, self).__init__(ec, guid)
80 self._home = "ovsswitch-%s" % self.guid
85 """ Node wthat run the switch
88 nodes = self.get_connected(PlanetlabNode.get_rtype())
89 if not nodes or len(nodes) != 1:
90 msg = "PlanetlabOVSSwitch must be connected to exactly one PlanetlabNode"
92 raise RuntimeError, msg
98 def valid_connection(self, guid):
99 """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.
101 :param guid: Guid of the current RM
106 rm = self.ec.get_resource(guid)
107 if rm.get_rtype() not in self._authorized_connections:
111 def do_provision(self):
112 self.node.mkdir(self.run_home)
114 self.check_sliver_ovs()
117 self.assign_controller()
120 self.set_provisioned()
123 """ Deploy the OVS Switch : Turn on the server, create the bridges
124 and assign the controller
127 if not self.node or self.node.state < ResourceState.READY:
128 self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.node.state)
129 self.ec.schedule(self.reschedule_delay, self.deploy)
136 def check_sliver_ovs(self):
137 """ Check if sliver-ovs exists. If it does not exist, the execution is stopped
139 command = "compgen -c | grep sliver-ovs"
140 shfile = os.path.join(self.app_home, "check_ovs_cmd.sh")
142 self.node.run_and_wait(command, self.run_home,
145 pidfile="check_ovs_cmd_pidfile",
146 ecodefile="check_ovs_cmd_exitcode",
147 stdout="check_ovs_cmd_stdout",
148 stderr="check_ovs_cmd_stderr")
150 msg = "Command sliver-ovs does not exist on the VM"
152 raise RuntimeError, msg
154 def servers_on(self):
155 """ Start the openvswitch servers and check it
157 # Make sure the server is not running
158 command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
159 shfile = os.path.join(self.app_home, "clean.sh")
160 self.node.run_and_wait(command, self.run_home,
163 raise_on_error=False,
164 pidfile="clean_pidfile",
165 ecodefile="clean_exitcode",
166 stdout="clean_stdout",
167 stderr="clean_stderr")
170 command = "sliver-ovs start"
171 shfile = os.path.join(self.app_home, "start.sh")
173 self.node.run_and_wait(command, self.run_home,
176 pidfile="start_pidfile",
177 ecodefile="start_exitcode",
178 stdout="start_stdout",
179 stderr="start_stderr")
181 msg = "Failed to start ovs-server on VM"
183 raise RuntimeError, msg
185 command = "ps -A | grep ovsdb-server"
186 shfile = os.path.join(self.app_home, "ovsdb_status.sh")
188 self.node.run_and_wait(command, self.run_home,
191 pidfile="ovsdb_status_pidfile",
192 ecodefile="ovsdb_status_exitcode",
193 stdout="ovsdb_status_stdout",
194 stderr="ovsdb_status_stderr")
196 msg = "ovsdb-server not running on VM"
198 raise RuntimeError, msg
200 self.info("Server OVS Started...")
202 def create_bridge(self):
203 """ Create the bridge/switch and check error during SSH connection
205 # TODO: Check if previous bridge exist and delete them. Use ovs-vsctl list-br
206 # TODO: Add check for virtual_ip belonging to vsys_tag
207 if not (self.get("bridge_name") and self.get("virtual_ip_pref")):
208 msg = "No assignment in one or both attributes"
210 raise AttributeError, msg
212 command = "sliver-ovs create-bridge '%s' '%s'" % (
213 self.get("bridge_name"),
214 self.get("virtual_ip_pref"))
216 shfile = os.path.join(self.app_home, "bridge_create.sh")
218 self.node.run_and_wait(command, self.run_home,
221 pidfile="bridge_create_pidfile",
222 ecodefile="bridge_create_exitcode",
223 stdout="bridge_create_stdout",
224 stderr="bridge_create_stderr")
226 msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error"
228 raise RuntimeError, msg
230 self.info(" Bridge %s Created and Assigned to %s" %\
231 (self.get("bridge_name"), self.get("virtual_ip_pref")) )
233 def assign_controller(self):
234 """ Set the controller IP
237 if not (self.get("controller_ip") and self.get("controller_port")):
241 if not (self.get("controller_ip") and self.get("controller_port")):
242 msg = "No assignment in one or both attributes"
244 raise AttributeError, msg
246 command = "ovs-vsctl set-controller %s tcp:%s:%s" % \
247 (self.get("bridge_name"),
248 self.get("controller_ip"),
249 self.get("controller_port"))
251 shfile = os.path.join(self.app_home, "set_controller.sh")
253 self.node.run_and_wait(command, self.run_home,
256 pidfile="set_controller_pidfile",
257 ecodefile="set_controller_exitcode",
258 stdout="set_controller_stdout",
259 stderr="set_controller_stderr")
261 msg = "SSH connection in the method assign_controller"
263 raise RuntimeError, msg
265 self.info("Controller assigned to the bridge %s" % self.get("bridge_name"))
267 def ovs_status(self):
268 """ Print the status of the bridge
270 command = "sliver-ovs show | tail -n +2"
271 shfile = os.path.join(self.app_home, "ovs_status.sh")
273 self.node.run_and_wait(command, self.run_home,
276 pidfile="ovs_status_pidfile",
277 ecodefile="ovs_status_exitcode",
278 stdout="ovs_status_stdout",
279 stderr="ovs_status_stderr")
281 msg = "Error when checking the status of the OpenVswitch"
283 raise RuntimeError, msg
285 def do_release(self):
286 """ Delete the bridge and close the server.
288 .. note : It need to wait for the others RM (OVSPort and OVSTunnel)
289 to be released before releasing itself
293 from nepi.resources.planetlab.openvswitch.ovsport import PlanetlabOVSPort
294 rms = self.get_connected(PlanetlabOVSPort.get_rtype())
297 if rm.state < ResourceState.RELEASED:
298 self.ec.schedule(self.reschedule_delay, self.release)
301 msg = "Deleting the bridge %s" % self.get('bridge_name')
304 command = "sliver-ovs del-bridge %s; sliver-ovs stop" % self.get('bridge_name')
305 shfile = os.path.join(self.app_home, "stop.sh")
307 self.node.run_and_wait(command, self.run_home,
310 pidfile="stop_pidfile",
311 ecodefile="stop_exitcode",
312 stdout="stop_stdout",
313 stderr="stop_stderr")
315 super(PlanetlabOVSSwitch, self).do_release()