(no commit message)
[sfa.git] / sfa / managers / slice_manager_pl.py
1 ### $Id: slices.py 15842 2009-11-22 09:56:13Z anil $
2 ### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/plc/slices.py $
3
4 import datetime
5 import time
6 import traceback
7 import sys
8 from copy import deepcopy
9 from lxml import etree
10 from StringIO import StringIO
11 from types import StringTypes
12
13 from sfa.util.namespace import *
14 from sfa.util.rspec import *
15 from sfa.util.specdict import *
16 from sfa.util.faults import *
17 from sfa.util.record import SfaRecord
18 from sfa.util.policy import Policy
19 from sfa.util.prefixTree import prefixTree
20 from sfa.util.rspec import *
21 from sfa.util.sfaticket import *
22 from sfa.util.debug import log
23 from sfa.server.registry import Registries
24 from sfa.server.aggregate import Aggregates
25 import sfa.plc.peers as peers
26
27 def delete_slice(api, xrn, origin_hrn=None):
28     credential = api.getCredential()
29     aggregates = Aggregates(api)
30     for aggregate in aggregates:
31         success = False
32         # request hash is optional so lets try the call without it
33         try:
34             aggregates[aggregate].delete_slice(credential, xrn, origin_hrn)
35             success = True
36         except:
37             print >> log, "%s" % (traceback.format_exc())
38             print >> log, "Error calling delete slice at aggregate %s" % aggregate
39     return 1
40
41 def create_slice(api, xrn, rspec, origin_hrn=None):
42     hrn, type = urn_to_hrn(xrn)
43     aggs = Aggregates(api)
44     cred = api.getCredential()
45
46     # Validate the RSpec here against PlanetLab's schema
47
48     aggs = Aggregates(api)
49     cred = api.getCredential()                                                 
50     for agg in aggs:
51         if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]:      
52             try:
53                 # Just send entire RSpec to each aggregate
54                 aggs[agg].create_slice(cred, xrn, rspec, origin_hrn)
55             except:
56                 print >> log, "Error creating slice %s at %s" % (hrn, agg)
57                 traceback.print_exc()
58
59     return True
60
61 def get_ticket(api, xrn, rspec, origin_hrn=None):
62     slice_hrn, type = urn_to_hrn(xrn)
63     # get the netspecs contained within the clients rspec
64     client_rspec = RSpec(xml=rspec)
65     netspecs = client_rspec.getDictsByTagName('NetSpec')
66     
67     # create an rspec for each individual rspec 
68     rspecs = {}
69     temp_rspec = RSpec()
70     for netspec in netspecs:
71         net_hrn = netspec['name']
72         resources = {'start_time': 0, 'end_time': 0 , 
73                      'network': {'NetSpec' : netspec}}
74         resourceDict = {'RSpec': resources}
75         temp_rspec.parseDict(resourceDict)
76         rspecs[net_hrn] = temp_rspec.toxml() 
77     
78     # send the rspec to the appropiate aggregate/sm
79     aggregates = Aggregates(api)
80     credential = api.getCredential()
81     tickets = {}
82     for net_hrn in rspecs:
83         net_urn = urn_to_hrn(net_hrn)     
84         try:
85             # if we are directly connected to the aggregate then we can just
86             # send them the request. if not, then we may be connected to an sm
87             # thats connected to the aggregate
88             if net_hrn in aggregates:
89                 ticket = aggregates[net_hrn].get_ticket(credential, xrn, \
90                             rspecs[net_hrn], origin_hrn)
91                 tickets[net_hrn] = ticket
92             else:
93                 # lets forward this rspec to a sm that knows about the network
94                 for agg in aggregates:
95                     network_found = aggregates[agg].get_aggregates(credential, net_urn)
96                     if network_found:
97                         ticket = aggregates[aggregate].get_ticket(credential, \
98                                         slice_hrn, rspecs[net_hrn], origin_hrn)
99                         tickets[aggregate] = ticket
100         except:
101             print >> log, "Error getting ticket for %(slice_hrn)s at aggregate %(net_hrn)s" % \
102                            locals()
103             
104     # create a new ticket
105     new_ticket = SfaTicket(subject = slice_hrn)
106     new_ticket.set_gid_caller(api.auth.client_gid)
107     new_ticket.set_issuer(key=api.key, subject=api.hrn)
108    
109     tmp_rspec = RSpec()
110     networks = []
111     valid_data = {
112         'timestamp': int(time.time()),
113         'initscripts': [],
114         'slivers': [] 
115     } 
116     # merge data from aggregate ticket into new ticket 
117     for agg_ticket in tickets.values():
118         # get data from this ticket
119         agg_ticket = SfaTicket(string=agg_ticket)
120         attributes = agg_ticket.get_attributes()
121         if attributes.get('initscripts', []) != None:
122             valid_data['initscripts'].extend(attributes.get('initscripts', []))
123         if attributes.get('slivers', []) != None:
124             valid_data['slivers'].extend(attributes.get('slivers', []))
125  
126         # set the object gid
127         object_gid = agg_ticket.get_gid_object()
128         new_ticket.set_gid_object(object_gid)
129         new_ticket.set_pubkey(object_gid.get_pubkey())
130
131         # build the rspec
132         tmp_rspec.parseString(agg_ticket.get_rspec())
133         networks.extend([{'NetSpec': tmp_rspec.getDictsByTagName('NetSpec')}])
134     
135     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
136     new_ticket.set_attributes(valid_data)
137     resources = {'networks': networks, 'start_time': 0, 'duration': 0}
138     resourceDict = {'RSpec': resources}
139     tmp_rspec.parseDict(resourceDict)
140     new_ticket.set_rspec(tmp_rspec.toxml())
141     new_ticket.encode()
142     new_ticket.sign()          
143     return new_ticket.save_to_string(save_parents=True)
144
145 def start_slice(api, xrn):
146     hrn, type = urn_to_hrn(xrn)
147     slicename = hrn_to_pl_slicename(hrn)
148     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
149     if not slices:
150         raise RecordNotFound(hrn)
151     slice_id = slices[0]
152     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
153     attribute_id = attreibutes[0]['slice_attribute_id']
154     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "1" )
155
156     return 1
157  
158 def stop_slice(api, xrn):
159     hrn, type = urn_to_hrn(xrn)
160     slicename = hrn_to_pl_slicename(hrn)
161     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
162     if not slices:
163         raise RecordNotFound(hrn)
164     slice_id = slices[0]['slice_id']
165     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
166     attribute_id = attributes[0]['slice_attribute_id']
167     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "0")
168     return 1
169
170 def reset_slice(api, xrn):
171     # XX not implemented at this interface
172     return 1
173
174 def get_slices(api):
175     # XX just import the legacy module and excute that until
176     # we transition the code to this module
177     from sfa.plc.slices import Slices
178     slices = Slices(api)
179     slices.refresh()
180     return [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slices['hrn']]
181      
182 def get_rspec(api, xrn=None, origin_hrn=None):
183     hrn, type = urn_to_hrn(xrn)
184     rspec = None
185
186     aggs = Aggregates(api)
187     cred = api.getCredential()                                                 
188     for agg in aggs:
189         if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]:      
190             try:
191                 # get the rspec from the aggregate
192                 agg_rspec = aggs[agg].get_resources(cred, xrn, origin_hrn)
193             except:
194                 # XX print out to some error log
195                 print >> log, "Error getting resources at aggregate %s" % agg
196                 traceback.print_exc(log)
197                 print >> log, "%s" % (traceback.format_exc())
198
199                 
200             try:
201                 tree = etree.parse(StringIO(agg_rspec))
202             except etree.XMLSyntaxError:
203                 message = agg + ": " + str(sys.exc_info()[1])
204                 raise InvalidRSpec(message)
205
206             root = tree.getroot()
207             if root.get("type") in ["Planetlab", "VINI"]:
208                 if rspec == None:
209                     rspec = root
210                 else:
211                     for network in root.iterfind("./network"):
212                         rspec.append(deepcopy(network))
213
214     return etree.tostring(rspec, xml_declaration=True, pretty_print=True)
215
216 """
217 Returns the request context required by sfatables. At some point, this
218 mechanism should be changed to refer to "contexts", which is the
219 information that sfatables is requesting. But for now, we just return
220 the basic information needed in a dict.
221 """
222 def fetch_context(slice_hrn, user_hrn, contexts):
223     #slice_hrn = urn_to_hrn(slice_xrn)[0]
224     #user_hrn = urn_to_hrn(user_xrn)[0]
225     base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
226     return base_context
227
228 def main():
229     r = RSpec()
230     r.parseFile(sys.argv[1])
231     rspec = r.toDict()
232     create_slice(None,'plc.princeton.tmacktestslice',rspec)
233
234 if __name__ == "__main__":
235     main()
236