Initially working version of PlanetLab testbed implementation.
[nepi.git] / src / nepi / testbeds / planetlab / execute.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from constants import TESTBED_ID
5 from nepi.core import testbed_impl
6 import os
7
8 class TestbedController(testbed_impl.TestbedController):
9     def __init__(self, testbed_version):
10         super(TestbedController, self).__init__(TESTBED_ID, testbed_version)
11         self._home_directory = None
12         self.slicename = None
13         self._traces = dict()
14         
15         import node, interfaces, application
16         self._node = node
17         self._interfaces = interfaces
18         self._app = application
19
20     @property
21     def home_directory(self):
22         return self._home_directory
23     
24     @property
25     def plapi(self):
26         if not hasattr(self, '_plapi'):
27             import plcapi
28             
29             if self.authUser:
30                 self._plapi = plcapi.PLCAPI(
31                     username = self.authUser,
32                     password = self.authString)
33             else:
34                 # anonymous access - may not be enough for much
35                 self._plapi = plcapi.PLCAPI()
36         return self._plapi
37     
38     @property
39     def slice_id(self):
40         if not hasattr(self, '_slice_id'):
41             slices = self.plapi.GetSlices(self.slicename, fields=('slice_id',))
42             if slices:
43                 self._slice_id = slices[0]['slice_id']
44             else:
45                 # If it wasn't found, don't remember this failure, keep trying
46                 return None
47         return self._slice_id
48
49     def do_setup(self):
50         self._home_directory = self._attributes.\
51             get_attribute_value("homeDirectory")
52         self.slicename = self._attributes.\
53             get_attribute_value("slice")
54         self.authUser = self._attributes.\
55             get_attribute_value("authUser")
56         self.authString = self._attributes.\
57             get_attribute_value("authPass")
58         self.sliceSSHKey = self._attributes.\
59             get_attribute_value("sliceSSHKey")
60
61     def do_create(self):
62         # Create node elements per XML data
63         super(TestbedController, self).do_create()
64         
65         # Perform resource discovery if we don't have
66         # specific resources assigned yet
67         self.do_resource_discovery()
68         
69         # Create PlanetLab slivers
70         self.do_provisioning()
71         
72         # Wait for all nodes to be ready
73         self.wait_nodes()
74     
75     def do_resource_discovery(self):
76         # Do what?
77         pass
78
79     def do_provisioning(self):
80         # Que te recontra?
81         pass
82     
83     def wait_nodes(self):
84         # Suuure...
85         pass
86
87     def set(self, time, guid, name, value):
88         super(TestbedController, self).set(time, guid, name, value)
89         # TODO: take on account schedule time for the task 
90         element = self._elements[guid]
91         if element:
92             setattr(element, name, value)
93
94     def get(self, time, guid, name):
95         # TODO: take on account schedule time for the task
96         element = self._elements.get(guid)
97         if element:
98             try:
99                 if hasattr(element, name):
100                     # Runtime attribute
101                     return getattr(element, name)
102                 else:
103                     # Try design-time attributes
104                     return self.box_get(time, guid, name)
105             except KeyError, AttributeError:
106                 return None
107
108     def get_route(self, guid, index, attribute):
109         # TODO: fetch real data from planetlab
110         try:
111             return self.box_get_route(guid, int(index), attribute)
112         except KeyError, AttributeError:
113             return None
114
115     def get_address(self, guid, index, attribute='Address'):
116         # try the real stuff
117         iface = self._elements.get(guid)
118         if iface and index == 0:
119             if attribute == 'Address':
120                 return iface.address
121             elif attribute == 'NetPrefix':
122                 return iface.netprefix
123             elif attribute == 'Broadcast':
124                 return iface.broadcast
125         
126         # if all else fails, query box
127         try:
128             return self.box_get_address(guid, int(index), attribute)
129         except KeyError, AttributeError:
130             return None
131
132
133     def action(self, time, guid, action):
134         raise NotImplementedError
135
136     def shutdown(self):
137         for trace in self._traces.values():
138             trace.close()
139         for element in self._elements.values():
140             pass
141             #element.destroy()
142
143     def trace(self, guid, trace_id, attribute='value'):
144         app = self._elements[guid]
145         
146         if attribute == 'value':
147             path = app.sync_trace(self.home_directory, trace_id)
148             if path:
149                 fd = open(path, "r")
150                 content = fd.read()
151                 fd.close()
152             else:
153                 content = None
154         elif attribute == 'path':
155             content = app.remote_trace_path(trace_id)
156         else:
157             content = None
158         return content
159         
160     def follow_trace(self, trace_id, trace):
161         self._traces[trace_id] = trace
162
163     def _make_node(self, parameters):
164         node = self._node.Node(self.plapi)
165         
166         # Note: there is 1-to-1 correspondence between attribute names
167         #   If that changes, this has to change as well
168         for attr,val in parameters.iteritems():
169             setattr(node, attr, val)
170         
171         return node
172     
173     def _make_node_iface(self, parameters):
174         iface = self._interfaces.NodeIface(self.plapi)
175         
176         # Note: there is 1-to-1 correspondence between attribute names
177         #   If that changes, this has to change as well
178         for attr,val in parameters.iteritems():
179             setattr(iface, attr, val)
180         
181         return iface
182     
183     def _make_tun_iface(self, parameters):
184         iface = self._interfaces.TunIface(self.plapi)
185         
186         # Note: there is 1-to-1 correspondence between attribute names
187         #   If that changes, this has to change as well
188         for attr,val in parameters.iteritems():
189             setattr(iface, attr, val)
190         
191         return iface
192     
193     def _make_internet(self, parameters):
194         return self._interfaces.Internet(self.plapi)
195     
196     def _make_application(self, parameters):
197         app = self._app.Application(self.plapi)
198         
199         # Note: there is 1-to-1 correspondence between attribute names
200         #   If that changes, this has to change as well
201         for attr,val in parameters.iteritems():
202             setattr(app, attr, val)
203         
204         return app
205         
206
207