Change the type of all RSPecs to 'SFA'
[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
44     # Validate the RSpec against PlanetLab's schema --disabled for now
45     # The schema used here needs to aggregate the PL and VINI schemas
46     # schema = "/var/www/html/schemas/pl.rng"
47     schema = None
48     if schema:
49         try:
50             tree = etree.parse(StringIO(rspec))
51         except etree.XMLSyntaxError:
52             message = str(sys.exc_info()[1])
53             raise InvalidRSpec(message)
54
55         relaxng_doc = etree.parse(schema)
56         relaxng = etree.RelaxNG(relaxng_doc)
57         
58         if not relaxng(tree):
59             error = relaxng.error_log.last_error
60             message = "%s (line %s)" % (error.message, error.line)
61             raise InvalidRSpec(message)
62
63     aggs = Aggregates(api)
64     cred = api.getCredential()                                                 
65     for agg in aggs:
66         if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]:      
67             try:
68                 # Just send entire RSpec to each aggregate
69                 aggs[agg].create_slice(cred, xrn, rspec, origin_hrn)
70             except:
71                 print >> log, "Error creating slice %s at %s" % (hrn, agg)
72                 traceback.print_exc()
73
74     return True
75
76 def get_ticket(api, xrn, rspec, origin_hrn=None):
77     slice_hrn, type = urn_to_hrn(xrn)
78     # get the netspecs contained within the clients rspec
79     client_rspec = RSpec(xml=rspec)
80     netspecs = client_rspec.getDictsByTagName('NetSpec')
81     
82     # create an rspec for each individual rspec 
83     rspecs = {}
84     temp_rspec = RSpec()
85     for netspec in netspecs:
86         net_hrn = netspec['name']
87         resources = {'start_time': 0, 'end_time': 0 , 
88                      'network': {'NetSpec' : netspec}}
89         resourceDict = {'RSpec': resources}
90         temp_rspec.parseDict(resourceDict)
91         rspecs[net_hrn] = temp_rspec.toxml() 
92     
93     # send the rspec to the appropiate aggregate/sm
94     aggregates = Aggregates(api)
95     credential = api.getCredential()
96     tickets = {}
97     for net_hrn in rspecs:
98         net_urn = urn_to_hrn(net_hrn)     
99         try:
100             # if we are directly connected to the aggregate then we can just
101             # send them the request. if not, then we may be connected to an sm
102             # thats connected to the aggregate
103             if net_hrn in aggregates:
104                 ticket = aggregates[net_hrn].get_ticket(credential, xrn, \
105                             rspecs[net_hrn], origin_hrn)
106                 tickets[net_hrn] = ticket
107             else:
108                 # lets forward this rspec to a sm that knows about the network
109                 for agg in aggregates:
110                     network_found = aggregates[agg].get_aggregates(credential, net_urn)
111                     if network_found:
112                         ticket = aggregates[aggregate].get_ticket(credential, \
113                                         slice_hrn, rspecs[net_hrn], origin_hrn)
114                         tickets[aggregate] = ticket
115         except:
116             print >> log, "Error getting ticket for %(slice_hrn)s at aggregate %(net_hrn)s" % \
117                            locals()
118             
119     # create a new ticket
120     new_ticket = SfaTicket(subject = slice_hrn)
121     new_ticket.set_gid_caller(api.auth.client_gid)
122     new_ticket.set_issuer(key=api.key, subject=api.hrn)
123    
124     tmp_rspec = RSpec()
125     networks = []
126     valid_data = {
127         'timestamp': int(time.time()),
128         'initscripts': [],
129         'slivers': [] 
130     } 
131     # merge data from aggregate ticket into new ticket 
132     for agg_ticket in tickets.values():
133         # get data from this ticket
134         agg_ticket = SfaTicket(string=agg_ticket)
135         attributes = agg_ticket.get_attributes()
136         if attributes.get('initscripts', []) != None:
137             valid_data['initscripts'].extend(attributes.get('initscripts', []))
138         if attributes.get('slivers', []) != None:
139             valid_data['slivers'].extend(attributes.get('slivers', []))
140  
141         # set the object gid
142         object_gid = agg_ticket.get_gid_object()
143         new_ticket.set_gid_object(object_gid)
144         new_ticket.set_pubkey(object_gid.get_pubkey())
145
146         # build the rspec
147         tmp_rspec.parseString(agg_ticket.get_rspec())
148         networks.extend([{'NetSpec': tmp_rspec.getDictsByTagName('NetSpec')}])
149     
150     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
151     new_ticket.set_attributes(valid_data)
152     resources = {'networks': networks, 'start_time': 0, 'duration': 0}
153     resourceDict = {'RSpec': resources}
154     tmp_rspec.parseDict(resourceDict)
155     new_ticket.set_rspec(tmp_rspec.toxml())
156     new_ticket.encode()
157     new_ticket.sign()          
158     return new_ticket.save_to_string(save_parents=True)
159
160 def start_slice(api, xrn):
161     hrn, type = urn_to_hrn(xrn)
162     slicename = hrn_to_pl_slicename(hrn)
163     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
164     if not slices:
165         raise RecordNotFound(hrn)
166     slice_id = slices[0]
167     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
168     attribute_id = attreibutes[0]['slice_attribute_id']
169     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "1" )
170
171     return 1
172  
173 def stop_slice(api, xrn):
174     hrn, type = urn_to_hrn(xrn)
175     slicename = hrn_to_pl_slicename(hrn)
176     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
177     if not slices:
178         raise RecordNotFound(hrn)
179     slice_id = slices[0]['slice_id']
180     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
181     attribute_id = attributes[0]['slice_attribute_id']
182     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "0")
183     return 1
184
185 def reset_slice(api, xrn):
186     # XX not implemented at this interface
187     return 1
188
189 def get_slices(api):
190     # XX just import the legacy module and excute that until
191     # we transition the code to this module
192     from sfa.plc.slices import Slices
193     slices = Slices(api)
194     slices.refresh()
195     return [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slices['hrn']]
196      
197 def get_rspec(api, xrn=None, origin_hrn=None):
198     hrn, type = urn_to_hrn(xrn)
199     rspec = None
200
201     aggs = Aggregates(api)
202     cred = api.getCredential()                                                 
203     for agg in aggs:
204         if agg not in [api.auth.client_cred.get_gid_caller().get_hrn()]:      
205             try:
206                 # get the rspec from the aggregate
207                 agg_rspec = aggs[agg].get_resources(cred, xrn, origin_hrn)
208             except:
209                 # XX print out to some error log
210                 print >> log, "Error getting resources at aggregate %s" % agg
211                 traceback.print_exc(log)
212                 print >> log, "%s" % (traceback.format_exc())
213
214                 
215             try:
216                 tree = etree.parse(StringIO(agg_rspec))
217             except etree.XMLSyntaxError:
218                 message = agg + ": " + str(sys.exc_info()[1])
219                 raise InvalidRSpec(message)
220
221             root = tree.getroot()
222             if root.get("type") in ["SFA"]:
223                 if rspec == None:
224                     rspec = root
225                 else:
226                     for network in root.iterfind("./network"):
227                         rspec.append(deepcopy(network))
228                     for request in root.iterfind("./request"):
229                         rspec.append(deepcopy(request))
230
231     return etree.tostring(rspec, xml_declaration=True, pretty_print=True)
232
233 """
234 Returns the request context required by sfatables. At some point, this
235 mechanism should be changed to refer to "contexts", which is the
236 information that sfatables is requesting. But for now, we just return
237 the basic information needed in a dict.
238 """
239 def fetch_context(slice_hrn, user_hrn, contexts):
240     #slice_hrn = urn_to_hrn(slice_xrn)[0]
241     #user_hrn = urn_to_hrn(user_xrn)[0]
242     base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
243     return base_context
244
245 def main():
246     r = RSpec()
247     r.parseFile(sys.argv[1])
248     rspec = r.toDict()
249     create_slice(None,'plc.princeton.tmacktestslice',rspec)
250
251 if __name__ == "__main__":
252     main()
253