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 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 # Alexandros Kouvakas <alexandros.kouvakas@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
29 reschedule_delay = "0.5s"
32 class OVSWitch(LinuxApplication):
34 _help = "Runs an OpenVSwitch on a PlanetLab host"
35 _backend = "planetlab"
37 _authorized_connections = ["PlanetlabNode", "OVSPort", "LinuxNode"]
40 def _register_attributes(cls):
41 """ Register the attributes of OVSWitch RM
44 bridge_name = Attribute("bridge_name", "Name of the switch/bridge",
45 flags = Flags.ExecReadOnly)
46 virtual_ip_pref = Attribute("virtual_ip_pref", "Virtual IP/PREFIX of the switch",
47 flags = Flags.ExecReadOnly)
48 controller_ip = Attribute("controller_ip", "IP of the controller",
49 flags = Flags.ExecReadOnly)
50 controller_port = Attribute("controller_port", "Port of the controller",
51 flags = Flags.ExecReadOnly)
53 cls._register_attribute(bridge_name)
54 cls._register_attribute(virtual_ip_pref)
55 cls._register_attribute(controller_ip)
56 cls._register_attribute(controller_port)
58 def __init__(self, ec, guid):
60 :param ec: The Experiment controller
61 :type ec: ExperimentController
62 :param guid: guid of the RM
66 super(OVSWitch, self).__init__(ec, guid)
69 self._home = "ovswitch-%s" % self.guid
70 self._checks = "ovsChecks-%s" % self.guid
74 node = self.get_connected(PlanetlabNode.get_rtype())
75 if node: return node[0]
80 return os.path.join(self.node.exp_home, self._home)
84 return os.path.join(self.ovs_home, self._checks)
94 # def valid_connection(self, guid):
95 # """ Check if the connection with the guid in parameter is possible. Only meaningful connections are allowed.
97 # :param guid: Guid of the current RM
102 # rm = self.ec.get_resource(guid)
103 # if rm.get_rtype() in self._authorized_connections:
104 # msg = "Connection between %s %s and %s %s accepted" % \
105 # (self.get_rtype(), self._guid, rm.get_rtype(), guid)
108 # msg = "Connection between %s %s and %s %s refused" % \
109 # (self.get_rtype(), self._guid, rm.get_rtype(), guid)
113 def valid_connection(self, guid):
117 def do_provision(self):
118 # create home dir for ovs
119 self.node.mkdir(self.ovs_home)
120 # create dir for ovs checks
121 self.node.mkdir(self.ovs_checks)
123 super(OVSWitch, self).do_provision()
126 """ Wait until node is associated and deployed
128 if not self.node or self.node.state < ResourceState.READY:
129 self.ec.schedule(reschedule_delay, self.deploy)
134 self.check_sliver_ovs()
137 self.assign_controller()
140 super(OVSWitch, self).do_deploy()
142 def check_sliver_ovs(self):
143 """ Check if sliver-ovs exists. If it does not exist, we interrupt
144 the execution immediately.
146 cmd = "compgen -c | grep sliver-ovs"
149 (out,err), proc = self.node.run_and_wait(cmd, self.ovs_checks,
150 shfile = "check_cmd.sh",
151 pidfile = "check_cmd_pidfile",
152 ecodefile = "check_cmd_exitcode",
154 stdout = "check_cmd_stdout",
155 stderr = "check_cmd_stderr")
157 (out, err), proc = self.node.check_output(self.ovs_checks, 'check_cmd_exitcode')
160 msg = "Command sliver-ovs does not exist on the VM"
162 raise RuntimeError, msg
164 msg = "Command sliver-ovs exists"
167 def servers_on(self):
168 """ Start the openvswitch servers and also checking
169 if they started successfully
173 command = "sliver-ovs start"
175 (out, err), proc = self.node.run_and_wait(command, self.ovs_checks,
176 shfile = "start_srv.sh",
177 pidfile = "start_srv_pidfile",
178 ecodefile = "start_srv_exitcode",
180 raise_on_error = True,
181 stdout = "start_srv_stdout",
182 stderr = "start_srv_stderr")
183 (out, err), proc = self.node.check_output(self.ovs_checks, 'start_srv_exitcode')
186 self.error("Servers have not started")
187 raise RuntimeError, msg
189 # Check if the servers are running or not
190 cmd = "ps -A | grep ovsdb-server"
192 (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks,
193 shfile = "status_srv.sh",
194 pidfile = "status_srv_pidfile",
195 ecodefile = "status_srv_exitcode",
197 stdout = "status_srv_stdout",
198 stderr = "status_srv_stderr")
199 (out, err), proc = self.node.check_output(self.ovs_checks, 'status_srv_exitcode')
202 msg = "Servers are not running"
204 raise RuntimeError, msg
206 self.info("Server OVS Started Correctly")
208 # def del_old_br(self):
209 # # TODO: Delete old bridges that might exist maybe by adding atribute
210 # """ With ovs-vsctl list-br
214 def create_bridge(self):
215 """ Create the bridge/switch and we check if we have any
216 error during the SSH connection
218 # TODO: Add check for virtual_ip belonging to vsys_tag
221 if not (self.get("bridge_name") and self.get("virtual_ip_pref")):
222 msg = "No assignment in one or both attributes"
224 raise AttributeError, msg
226 cmd = "sliver-ovs create-bridge '%s' '%s'" %\
227 (self.get("bridge_name"), self.get("virtual_ip_pref"))
229 (out, err), proc = self.node.run_and_wait(cmd, self.ovs_checks,
230 shfile = "create_br.sh",
231 pidfile = "create_br_pidfile",
232 ecodefile = "create_br_exitcode",
234 stdout = "create_br_stdout",
235 stderr = "create_br_stderr")
236 (out, err), proc = self.node.check_output(self.ovs_checks, 'create_br_exitcode')
239 msg = "No such pltap netdev\novs-appctl: ovs-vswitchd: server returned an error"
241 raise RuntimeError, msg
243 self.info(" Bridge %s Created and Assigned to %s" %\
244 (self.get("bridge_name"), self.get("virtual_ip_pref")) )
247 def assign_controller(self):
248 """ Set the controller IP
251 if not (self.get("controller_ip") and self.get("controller_port")):
252 msg = "No assignment in one or both attributes"
254 raise AttributeError, msg
256 cmd = "ovs-vsctl set-controller %s tcp:%s:%s" %\
257 (self.get("bridge_name"), self.get("controller_ip"), self.get("controller_port"))
259 (out, err), proc = self.node.run(cmd, self.ovs_checks,
265 msg = "SSH connection in the method assign_controller"
267 raise RuntimeError, msg
269 self.info("Controller assigned to the bridge %s" % self.get("bridge_name"))
271 def ovs_status(self):
272 """ Print the status of the bridge
274 cmd = "sliver-ovs show | tail -n +2"
276 (out, err), proc = self.node.run_and_wait(cmd, self.ovs_home,
278 stdout = "show_stdout",
279 stderr = "show_stderr")
280 (out, err), proc = self.node.check_output(self.ovs_home, 'show_stdout')
283 msg = "Error when checking the status of the OpenVswitch"
285 raise RuntimeError, msg
289 def do_release(self):
290 """ Delete the bridge and close the servers.
291 It need to wait for the others RM (OVSPort and OVSTunnel)
292 to be released before releasing itself
296 from nepi.resources.planetlab.openvswitch.ovsport import OVSPort
297 rm = self.get_connected(OVSPort.get_rtype())
299 if rm[0].state < ResourceState.RELEASED:
300 self.ec.schedule(reschedule_delay, self.release)
303 cmd = "sliver-ovs del-bridge %s" % self.get('bridge_name')
304 (out, err), proc = self.node.run(cmd, self.ovs_checks,
307 cmd = "sliver-ovs stop"
308 (out, err), proc = self.node.run(cmd, self.ovs_checks,
311 msg = "Deleting the bridge %s" % self.get('bridge_name')
315 self.error(msg, out, err)
316 raise RuntimeError, msg
318 super(OVSWitch, self).do_release()