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