Adding help and background class atrributes to ResourceManager
[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 as published by
7 #    the Free Software Foundation, either version 3 of the License, or
8 #    (at your option) any later version.
9 #
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.
14 #
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/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19 #             Alexandros Kouvakas <alexandros.kouvakas@gmail.com>
20
21 from nepi.execution.attribute import Attribute, Flags, Types
22 from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState       
23 from nepi.resources.planetlab.openvswitch.ovs import OVSWitch        
24 from nepi.resources.planetlab.node import PlanetlabNode        
25 from nepi.resources.linux.application import LinuxApplication
26
27 reschedule_delay = "0.5s"
28
29 @clsinit_copy                 
30 class OVSPort(LinuxApplication):
31     """
32     .. class:: Class Args :
33       
34         :param ec: The Experiment controller
35         :type ec: ExperimentController
36         :param guid: guid of the RM
37         :type guid: int
38
39     """
40     
41     _rtype = "OVSPort"
42     _help = "Runs an OpenVSwitch on a PlanetLab host"
43     _backend = "planetlab"
44
45     _authorized_connections = ["OVSWitch", "Tunnel"]      
46
47     @classmethod
48     def _register_attributes(cls):
49         """ Register the attributes of OVSPort RM 
50
51         """
52         port_name = Attribute("port_name", "Name of the port",
53             flags = Flags.ExecReadOnly)                 
54
55         cls._register_attribute(port_name)
56
57     def __init__(self, ec, guid):
58         """
59         :param ec: The Experiment controller
60         :type ec: ExperimentController
61         :param guid: guid of the RM
62         :type guid: int
63     
64         """
65         super(OVSPort, self).__init__(ec, guid)
66         self._port_number = None
67         self.port_info = []          
68
69     @property
70     def node(self):
71         rm_list = self.get_connected(OVSWitch.rtype())
72         if rm_list:
73             for elt in rm_list:
74                 node = elt.get_connected(PlanetlabNode.rtype())
75                 if node: return node[0]
76         return node[0]
77
78     @property
79     def ovswitch(self):
80         ovswitch = self.get_connected(OVSWitch.rtype())
81         if ovswitch: return ovswitch[0]
82         return None
83         
84     @property
85     def port_number(self):
86         return self._port_number
87
88     def valid_connection(self, guid):
89         # TODO: Validate!
90         return True
91
92 #    def valid_connection(self, guid):
93 #        """ Check if the connection is available.
94
95 #        :param guid: Guid of the current RM
96 #        :type guid: int
97 #        :rtype:  Boolean
98
99 #        """
100 #        rm = self.ec.get_resource(guid)
101 #        if rm.rtype() in self._authorized_connections:
102 #            msg = "Connection between %s %s and %s %s accepted" % (self.rtype(), self._guid, rm.rtype(), guid)
103 #            self.debug(msg)
104 #            return True
105 #        msg = "Connection between %s %s and %s %s refused" % (self.rtype(), self._guid, rm.rtype(), guid)
106 #        self.debug(msg)
107
108     def get_host_ip(self):
109         """ Get the hostname of the node that
110         the port belongs to. We use it for tunnel.
111         """
112         get_host_ip = self.node
113         if not get_host_ip: 
114             msg = "info_list is empty"
115             self.debug(msg)
116             raise RuntimeError, msg
117         import socket
118         self.port_info.append(get_host_ip.get('hostname'))
119         self.port_info.append(socket.gethostbyname(self.port_info[0]))   
120     
121     def create_port(self):
122         """ Create the desired port
123         """
124         port_name = self.get('port_name')
125         if not (port_name or self.ovswitch):
126             msg = "The rm_list is empty or the port name is not assigned\n Failed to create port"
127             self.error(msg)
128             self.debug("ovswitch_list = %s and port_name = %s" % (self.ovswitch, port_name) )
129             raise AttributeError, msg
130
131         self.info("Create the port %s on switch %s" % (port_name, self.ovswitch.get('bridge_name')))     
132         self.port_info.append(port_name)
133         self.port_info.append(self.ovswitch.get('virtual_ip_pref'))
134         cmd = "sliver-ovs create-port %s %s" % (self.ovswitch.get('bridge_name'), port_name)   
135         self.node.run(cmd, self.ovswitch.ovs_checks, 
136                 stderr = "stdout-%s" % port_name, 
137                 stdout = "stderr-%s" % port_name,
138                 sudo = True)
139             
140     def get_local_end(self):
141         """ Get the local_endpoint of the port
142         """
143         msg = "Discovering the number of the port %s"\
144             % self.get('port_name')
145         self.info(msg)
146
147         command = "sliver-ovs get-local-endpoint %s"\
148             % self.get('port_name')
149         out = err = ""
150         (out, err), proc = self.node.run_and_wait(command, self.ovswitch.ovs_checks, 
151                 shfile = "port_number-%s.sh" % self.get('port_name'),
152                 pidfile = "port_number_pidfile-%s" % self.get('port_name'),
153                 ecodefile = "port_number_exitcode-%s" % self.get('port_name'), 
154                 sudo = True, 
155                 stdout = "stdout-%s" % self.get('port_name'),    
156                 stderr = "stderr-%s" % self.get('port_name'))
157
158         if err != "":
159             msg = "No assignment in attribute port_name"
160             self.error(msg)
161             self.debug("You are in the method get_local_end and the port_name = %s" % self.get('port_name'))
162             raise AttributeError, msg
163         self._port_number = None
164         self._port_number = int(out)
165         self.port_info.append(self._port_number)                                
166         self.info("The number of the %s is %s" % (self.get('port_name'), self._port_number))
167    
168     def switch_connect_command(self, local_port_name, 
169             remote_ip, remote_port_num):
170         """ Script for switch links
171         """
172         command = ["sliver-ovs"]
173         command.append("set-remote-endpoint ")
174         command.append("%s " % local_port_name)
175         command.append("%s " % remote_ip)
176         command.append("%s " % remote_port_num)
177         command = " ".join(command)
178         command = self.replace_paths(command)
179         return command
180         
181     def provision(self):
182         """ Provision the ports.No meaning.
183         """
184         pass
185
186     def discover(self):
187         """ Discover the ports.No meaning
188         """     
189         pass
190
191     def deploy(self):
192         """ Wait until ovswitch is started
193         """
194         ovswitch = self.ovswitch
195         if not ovswitch or ovswitch.state < ResourceState.READY:       
196             self.debug("---- RESCHEDULING DEPLOY ---- node state %s " % self.ovswitch.state )  
197             self.ec.schedule(reschedule_delay, self.deploy)
198             
199         else:
200             try:
201                 self.discover()
202                 self.provision()
203                 self.get_host_ip()
204                 self.create_port()
205                 self.get_local_end()
206                 self.ovswitch.ovs_status()
207                 self._state = ResourceState.READY
208             except:
209                 self._state = ResourceState.FAILED
210                 raise
211
212     def start(self):
213         """ Start the RM. It means nothing special for 
214             ovsport for now.
215         """
216         pass
217         
218     def stop(self):
219         """ Stop the RM. It means nothing special for 
220             ovsport for now.        
221         """
222         pass
223         
224     def release(self):
225         """ Release the port RM means delete the ports
226         """
227         # OVS needs to wait until all associated RMs are released
228         # to be released
229         from nepi.resources.planetlab.openvswitch.tunnel import Tunnel
230         rm = self.get_connected(Tunnel.rtype())
231         if rm and rm[0].state < ResourceState.FINISHED:
232             self.ec.schedule(reschedule_delay, self.release)
233             return 
234             
235         msg = "Deleting the port %s" % self.get('port_name')
236         self.info(msg)
237         cmd = "sliver-ovs del_port %s" % self.get('port_name')
238         (out, err), proc = self.node.run(cmd, self.ovswitch.ovs_checks,
239                 sudo = True)
240
241         if proc.poll():
242             self.fail()
243             self.error(msg, out, err)
244             raise RuntimeError, msg
245
246         self._state = ResourceState.RELEASED