applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / planetlab / openvswitch / ovsport.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
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;
8 #
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.
13 #
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/>.
16 #
17 # Authors: Alina Quereilhac <alina.quereilhac@inria.fr>
18 #         Alexandros Kouvakas <alexandros.kouvakas@inria.fr>
19 #         Julien Tribino <julien.tribino@inria.fr>
20
21 from nepi.execution.attribute import Attribute, Flags, Types
22 from nepi.execution.resource import ResourceManager, clsinit_copy, \
23         ResourceState
24 from nepi.resources.planetlab.openvswitch.ovs import PlanetlabOVSSwitch        
25 from nepi.resources.planetlab.node import PlanetlabNode        
26 from nepi.resources.linux.application import LinuxApplication
27
28 import os
29
30 @clsinit_copy                 
31 class PlanetlabOVSPort(LinuxApplication):
32     """
33     .. class:: Class Args :
34       
35         :param ec: The Experiment controller
36         :type ec: ExperimentController
37         :param guid: guid of the RM
38         :type guid: int
39
40     """
41     
42     _rtype = "planetlab::OVSPort"
43     _help = "Runs an OpenVSwitch on a PlanetLab host"
44     _platform = "planetlab"
45
46     _authorized_connections = ["planetlab::OVSSwitch", "linux::UdpTunnel", "linux::Tunnel"]      
47
48     @classmethod
49     def _register_attributes(cls):
50         """ Register the attributes of OVSPort RM 
51
52         """
53         port_name = Attribute("port_name", "Name of the port",
54             flags = Flags.Design)                       
55         ip = Attribute("ip", "IP of the endpoint. This is the attribute " 
56                                 "you should use to establish a tunnel or a remote "
57                                 "connection between endpoint",
58             flags = Flags.Design)
59         network = Attribute("network", "Network used by the port",
60             flags = Flags.Design)       
61
62         cls._register_attribute(port_name)
63         cls._register_attribute(ip)
64         cls._register_attribute(network)
65
66     def __init__(self, ec, guid):
67         """
68         :param ec: The Experiment controller
69         :type ec: ExperimentController
70         :param guid: guid of the RM
71         :type guid: int
72     
73         """
74         super(PlanetlabOVSPort, self).__init__(ec, guid)
75         self._home = "ovsport-%s" % self.guid
76         self._port_number = None
77
78     @property
79     def node(self):
80         """ Node that run the switch and the ports
81         """
82         return self.ovsswitch.node
83
84     @property
85     def ovsswitch(self):
86         """ Switch where the port is created
87         """
88         ovsswitch = self.get_connected(PlanetlabOVSSwitch.get_rtype())
89         if ovsswitch: return ovsswitch[0]
90         return None
91         
92     @property
93     def port_number(self):
94         return self._port_number
95
96     def valid_connection(self, guid):
97         """ Check if the connection is available.
98
99         :param guid: Guid of the current RM
100         :type guid: int
101         :rtype:  Boolean
102
103         """
104         rm = self.ec.get_resource(guid)
105         if rm.get_rtype() not in self._authorized_connections:
106             return False
107
108         return True
109
110     def create_port(self):
111         """ Create the desired port
112         """
113         msg = "Creating the port %s" % self.get('port_name')
114         self.debug(msg)
115
116         if not self.get('port_name'):
117             msg = "The port name is not assigned"
118             self.error(msg)
119             raise AttributeError(msg)
120
121         if not self.ovsswitch:
122             msg = "The OVSwitch RM is not running"
123             self.error(msg)
124             raise AttributeError(msg)
125
126         command = "sliver-ovs create-port %s %s" % (
127                 self.ovsswitch.get('bridge_name'),
128                 self.get('port_name'))   
129         
130         shfile = os.path.join(self.app_home, "create_port.sh")
131         try:
132             self.node.run_and_wait(command, self.run_home,
133                     shfile=shfile,
134                     sudo = True,
135                     stderr="port_stdout", 
136                     stdout="port_stderr",
137                     pidfile="port_pidfile",
138                     ecodefile="port_exitcode")
139         except RuntimeError:
140             msg = "Could not create ovs-port"            
141             self.debug(msg)
142             raise RuntimeError(msg)
143
144         self.info("Created port %s on switch %s" % (
145             self.get('port_name'),
146             self.ovsswitch.get('bridge_name')))     
147             
148     def initiate_udp_connection(self, remote_endpoint, connection_app_home, 
149             connection_run_home, cipher, cipher_key, bwlimit, txqueuelen):
150         """ Get the local_endpoint of the port
151         """
152         msg = "Discovering the port number for %s" % self.get('port_name')
153         self.info(msg)
154
155         command = "sliver-ovs get-local-endpoint %s" % self.get('port_name')
156
157         shfile = os.path.join(connection_app_home, "get_port.sh")
158         (out, err), proc = self.node.run_and_wait(command, connection_run_home,
159                 shfile=shfile,
160                 sudo=True, 
161                 overwrite = True,
162                 pidfile="get_port_pidfile",
163                 ecodefile="get_port_exitcode", 
164                 stdout="get_port_stdout",    
165                 stderr="get_port_stderr")
166
167         if err != "":
168             msg = "Error retrieving the local endpoint of the port"
169             self.error(msg)
170             raise RuntimeError(msg)
171
172         if out:
173             self._port_number = out.strip()
174
175         self.info("The number of the %s is %s" % (self.get('port_name'), 
176            self.port_number))
177
178         # Must set a routing rule in the ovs client nodes so they know
179         # that the LAN can be found through the switch
180         if remote_endpoint.is_rm_instance("planetlab::Tap"):
181             self._vroute = self.ec.register_resource("planetlab::Vroute")
182             self.ec.set(self._vroute, "action", "add")
183             self.ec.set(self._vroute, "prefix", remote_endpoint.get("prefix"))
184             self.ec.set(self._vroute, "nexthop", remote_endpoint.get("pointopoint"))
185             self.ec.set(self._vroute, "network", self.get("network"))
186
187             self.ec.register_connection(self._vroute, remote_endpoint.guid)
188             self.ec.deploy(guids=[self._vroute], group = self.deployment_group)
189
190             # For debugging
191             msg = "Route for the tap configured"
192             self.debug(msg)
193
194         return self.port_number
195
196     def establish_udp_connection(self, remote_endpoint,
197             connection_app_home,
198             connection_run_home, 
199             port):
200         remote_ip = remote_endpoint.node.get("ip")
201         command = self._establish_connection_command(port, remote_ip)
202
203         shfile = os.path.join(connection_app_home, "connect_port.sh")
204         (out, err), proc = self.node.run_and_wait(command, connection_run_home,
205                 shfile=shfile,
206                 sudo=True, 
207                 overwrite = True,
208                 pidfile="connect_port_pidfile",
209                 ecodefile="connect_port_exitcode", 
210                 stdout="connect_port_stdout",    
211                 stderr="connect_port_stderr")
212
213         # For debugging
214         msg = "Connection on port configured"
215         self.debug(msg)
216
217     def _establish_connection_command(self, port, remote_ip):
218         """ Script to create the connection from a switch to a 
219              remote endpoint
220         """
221         local_port_name = self.get('port_name')
222
223         command = ["sliver-ovs"]
224         command.append("set-remote-endpoint")
225         command.append(local_port_name)
226         command.append(remote_ip)
227         command.append(port)
228         command = " ".join(command)
229         command = self.replace_paths(command)
230         return command
231        
232     def verify_connection(self, remote_endpoint, connection_app_home, 
233                 connection_run_home):
234         self.ovsswitch.ovs_status()
235
236     def terminate_connection(self, endpoint, connection_app_home, 
237                 connection_run_home):
238         return True
239
240     def check_status(self):
241         return self.node.status(self._pid, self._ppid)
242
243     def do_provision(self):
244         self.node.mkdir(self.run_home)
245
246         self.create_port()
247         end_ip = self.ovsswitch.get('virtual_ip_pref').split('/')
248         self.set("ip", end_ip[0])
249
250         #Check the status of the OVS Switch
251         self.ovsswitch.ovs_status()
252     
253         self.set_provisioned()
254                 
255     def do_deploy(self):
256         """ Deploy the OVS port after the OVS Switch
257         """
258         if not self.ovsswitch or self.ovsswitch.state < ResourceState.READY:       
259             self.debug("---- RESCHEDULING DEPLOY ---- OVSwitch state %s " % self.ovsswitch.state )  
260             self.ec.schedule(self.reschedule_delay, self.deploy)
261         else:
262             self.do_discover()
263             self.do_provision()
264
265             self.set_ready()
266
267     def do_release(self):
268         """ Delete the port on the OVSwitch. It needs to wait for the tunnel
269         to be released.
270         """
271         from nepi.resources.linux.udptunnel import LinuxUdpTunnel
272         rm = self.get_connected(LinuxUdpTunnel.get_rtype())
273
274         if rm and rm[0].state < ResourceState.STOPPED:
275             self.ec.schedule(self.reschedule_delay, self.release)
276             return 
277             
278         msg = "Deleting the port %s" % self.get('port_name')
279         self.info(msg)
280
281         command = "sliver-ovs del_port %s" % self.get('port_name')
282
283         shfile = os.path.join(self.app_home, "stop.sh")
284         self.node.run_and_wait(command, self.run_home,
285                 shfile=shfile,
286                 sudo=True, 
287                 pidfile="stop_pidfile",
288                 ecodefile="stop_exitcode", 
289                 stdout="stop_stdout", 
290                 stderr="stop_stderr")
291
292         super(PlanetlabOVSPort, self).do_release()
293