fix threading, ignore operation in decode_authentication when it is none
[sfa.git] / plc / aggregate.py
1 import os
2 import sys
3 import datetime
4 import time
5 import xmlrpclib
6
7 from geniserver import *
8 from excep import *
9 from misc import *
10 from config import Config
11
12 conf = Config()
13 basedir = conf.GENI_BASE_DIR + os.sep 
14 server_basedir = basedir + os.sep + "plc" + os.sep 
15 agg_hrn = conf.GENI_INTERFACE_HRN
16
17 class Aggregate:
18
19     hrn = None
20     aggregate_file = None
21     components_file = None
22     slices_file = None  
23     components_ttl = None
24     components = []
25     slices = [] 
26     policies = {}
27     timestamp = None
28     threshold = None    
29     server = None
30      
31
32     def __init__(self, hrn = agg_hrn, components_ttl = 1):
33         self.hrn = hrn
34         self.components_file = os.sep.join([server_basedir, 'components', hrn + '.comp'])
35         self.slices_file = os.sep.join([server_basedir, 'components', hrn + '.slices'])
36         self.timestamp_file = os.sep.join([server_basedir, 'components', hrn + '.timestamp']) 
37         self.components_ttl = components_ttl
38
39     def connect(self):
40         """
41         Connect to the plc api interface. First attempt to impor thte shell, if that fails
42         try to connect to the xmlrpc server.
43         """
44         self.auth = {'Username': conf.GENI_PLC_USER,
45                      'AuthMethod': 'password',
46                      'AuthString': conf.GENI_PLC_PASSWORD}
47
48         try:
49             # try to import PLC.Shell directly
50             sys.path.append(conf.GENI_PLC_SHELL_PATH) 
51             import PLC.Shell
52             self.shell = PLC.Shell.Shell(globals())
53             self.shell.AuthCheck()
54         except ImportError:
55             # connect to plc api via xmlrpc
56             plc_host = conf.GENI_PLC_HOST
57             plc_port = conf.GENI_PLC_PORT
58             plc_api_path = conf.GENI_PLC_API_PATH                    
59             url = "https://%(plc_host)s:%(plc_port)s/%(plc_api_path)s/" % locals()
60             self.auth = {'Username': conf.GENI_PLC_USER,
61                          'AuthMethod': 'password',
62                          'AuthString': conf.GENI_PLC_PASSWORD} 
63
64             self.shell = xmlrpclib.Server(url, verbose = 0, allow_none = True) 
65             self.shell.AuthCheck(self.auth) 
66
67     def hostname_to_hrn(self, login_base, hostname):
68         """
69         Convert hrn to plantelab name.
70         """
71         genihostname = "_".join(hostname.split("."))
72         return ".".join([self.hrn, login_base, genihostname])
73
74     def slicename_to_hrn(self, slicename):
75         """
76         Convert hrn to planetlab name.
77         """
78         slicename = slicename.replace("_", ".")
79         return ".".join([self.hrn, slicename])
80
81     def refresh_components(self):
82         """
83         Update the cached list of nodes and slices.
84         """
85         print "refreshing"      
86         # resolve component hostnames 
87         nodes = self.shell.GetNodes(self.auth, {}, ['hostname', 'site_id'])
88         
89         # resolve slices
90         slices = self.shell.GetSlices(self.auth, {}, ['name', 'site_id'])
91    
92         # resolve site login_bases
93         site_ids = [node['site_id'] for node in nodes]
94         sites = self.shell.GetSites(self.auth, site_ids, ['site_id', 'login_base'])
95         site_dict = {}
96         for site in sites:
97             site_dict[site['site_id']] = site['login_base']
98
99         # convert plc names to geni hrn
100         self.components = [self.hostname_to_hrn(site_dict[node['site_id']], node['hostname']) for node in nodes]
101         self.slices = [self.slicename_to_hrn(slice['name']) for slice in slices]
102                 
103         # update timestamp and threshold
104         self.timestamp = datetime.datetime.now()
105         delta = datetime.timedelta(hours=self.components_ttl)
106         self.threshold = self.timestamp + delta 
107         
108         f = open(self.components_file, 'w')
109         f.write(str(self.components))
110         f.close()
111         f = open(self.slices_file, 'w')
112         f.write(str(self.slices))
113         f.close()
114         f = open(self.timestamp_file, 'w')
115         f.write(str(self.threshold))
116         f.close()
117  
118     def load_components(self):
119         """
120         Read cached list of nodes and slices.
121         """
122         print "loading"
123         # Read component list from cached file 
124         if os.path.exists(self.components_file):
125             f = open(self.components_file, 'r')
126             self.components = eval(f.read())
127             f.close()
128         
129         if os.path.exists(self.slices_file):
130             f = open(self.components_file, 'r')
131             self.slices = eval(f.read())
132             f.close()
133
134         time_format = "%Y-%m-%d %H:%M:%S"
135         if os.path.exists(self.timestamp_file):
136             f = open(self.timestamp_file, 'r')
137             timestamp = str(f.read()).split(".")[0]
138             self.timestamp = datetime.datetime.fromtimestamp(time.mktime(time.strptime(timestamp, time_format)))
139             delta = datetime.timedelta(hours=self.components_ttl)
140             self.threshold = self.timestamp + delta
141             f.close()   
142
143     def get_components(self):
144         """
145         Return a list of components at this aggregate.
146         """
147         # Reload components list
148         now = datetime.datetime.now()
149         #self.load_components()
150         if not self.threshold or not self.timestamp or now > self.threshold:
151             self.refresh_components()
152         elif now < self.threshold and not self.components: 
153             self.load_components()
154         return self.components
155    
156      
157     def get_slices(self):
158         """
159         Return a list of instnatiated slices at this aggregate.
160         """
161         now = datetime.datetime.now()
162         #self.load_components()
163         if not self.threshold or not self.timestamp or now > self.threshold:
164             self.refresh_components()
165         elif now < self.threshold and not self.slices:
166             self.load_components()
167         return self.slices
168
169     def get_rspec(self, hrn, type):
170         #rspec = Rspec()
171         if type in ['node']:
172             nodes = self.shell.GetNodes(self.auth)
173         elif type in ['slice']:
174             slices = self.shell.GetSlices(self.auth)
175         elif type in ['aggregate']:
176             pass
177
178     get_slice_rspec = get_rspec(hrn, 'slice')
179     get_node_rspec = get_rspec(hrn, 'node')
180     get_aggregate_rspec = get_rpsec(hrn, 'aggregate')           
181
182     def get_resources(self, slice_hrn):
183         """
184         Return the current rspec for the specified slice.
185         """
186         slicename = hrn_to_plcslicename(slice_hrn)
187         rspec = self.get_slice_rspec(slicename)
188         
189         return rspec
190  
191     def create_slice(self, slice_hrn, rspec):
192         """
193         Instantiate the specified slice according to whats defined in the rspec.
194         """
195         slicename = hrn_to_plcslicename(slice_hrn)
196         #spec = Rspec(rspec)
197         #components = spec.components()
198         #shell.AddSliceToNodes(self.auth, slicename, components)
199         return 1
200         
201     def delete_slice_(self, slice_hrn):
202         """
203         Remove this slice from all components it was previouly associated with and 
204         free up the resources it was using.
205         """
206         slicename = hrn_to_plcslicename(slice_hrn)
207         rspec = self.get_resources(slice_hrn)
208         components = rspec.components()
209         shell.DeleteSliceFromNodes(self.auth, slicename, components)
210         return 1
211
212     def start_slice(self, slice_hrn):
213         """
214         Stop the slice at plc.
215         """
216         slicename = hrn_to_plcslicename(slice_hrn)
217         slices = self.shell.GetSlices(self.auth, {'name': slicename}, ['slice_id'])
218         if not slices:
219             raise RecordNotFound(slice_hrn)
220         slice_id = slices[0]
221         atrribtes = self.shell.GetSliceAttributes({'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
222         attribute_id = attreibutes[0] 
223         self.shell.UpdateSliceAttribute(self.auth, attribute_id, "1" })
224         return 1
225
226     def stop_slice(self, slice_hrn):
227         """
228         Stop the slice at plc
229         """
230         slicename = hrn_to_plcslicename(slice_hrn)
231         slices = self.shell.GetSlices(self.auth, {'name': slicename}, ['slice_id'])
232         if not slices:
233             raise RecordNotFound(slice_hrn)
234         slice_id = slices[0]
235         atrribtes = self.shell.GetSliceAttributes({'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
236         attribute_id = attreibutes[0]
237         self.shell.UpdateSliceAttribute(self.auth, attribute_id, "0"})
238         return 1
239
240     def reset_slice(self, slice_hrn):
241         """
242         Reset the slice
243         """
244         slicename = hrn_to_plcslicename(slice_hrn)
245         return 1
246
247     def get_policy(self):
248         """
249         Return this aggregates policy as an rspec
250         """
251         rspec = get_aggregate_rspec(self.hrn):
252         return rspec
253         
254