Modified create_slice() and get_rspec() to work with the new RSpec format
[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
194                 tree = etree.parse(StringIO(agg_rspec))
195                 root = tree.getroot()
196                 if root.get("type") in ["Planetlab", "VINI"]:
197                     # Validate the aggregate's RSpec?
198
199                     if rspec == None:
200                         rspec = root
201                     else:
202                         for network in root.iterfind("./network"):
203                             rspec.append(deepcopy(network))
204             except:
205                 # XX print out to some error log
206                 print >> log, "Error getting resources at aggregate %s" % agg
207                 traceback.print_exc(log)
208                 print >> log, "%s" % (traceback.format_exc())
209
210
211     return etree.tostring(rspec, xml_declaration=True, pretty_print=True)
212
213 """
214 Returns the request context required by sfatables. At some point, this
215 mechanism should be changed to refer to "contexts", which is the
216 information that sfatables is requesting. But for now, we just return
217 the basic information needed in a dict.
218 """
219 def fetch_context(slice_hrn, user_hrn, contexts):
220     #slice_hrn = urn_to_hrn(slice_xrn)[0]
221     #user_hrn = urn_to_hrn(user_xrn)[0]
222     base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
223     return base_context
224
225 def main():
226     r = RSpec()
227     r.parseFile(sys.argv[1])
228     rspec = r.toDict()
229     create_slice(None,'plc.princeton.tmacktestslice',rspec)
230
231 if __name__ == "__main__":
232     main()
233