modify accept arguments for get_rspec, preparing to switch to protogeni api spec
[sfa.git] / sfa / managers / aggregate_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.record import *
17 from sfa.util.sfaticket import SfaTicket
18 from sfa.util.debug import log
19 from sfa.plc.slices import Slices
20 from sfa.trust.credential import Credential
21 import sfa.plc.peers as peers
22 from sfa.plc.network import *
23 from sfa.plc.api import SfaAPI
24 from sfa.plc.slices import *
25
26 def get_version():
27     version = {}
28     version['geni_api'] = 1
29     return version
30
31 def delete_slice(api, xrn):
32     hrn, type = urn_to_hrn(xrn)
33     slicename = hrn_to_pl_slicename(hrn)
34     slices = api.plshell.GetSlices(api.plauth, {'name': slicename})
35     if not slices:
36         return 1
37     slice = slices[0]
38
39     # determine if this is a peer slice
40     peer = peers.get_peer(api, hrn)
41     if peer:
42         api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice['slice_id'], peer)
43     api.plshell.DeleteSliceFromNodes(api.plauth, slicename, slice['node_ids'])
44     if peer:
45         api.plshell.BindObjectToPeer(api.plauth, 'slice', slice['slice_id'], peer, slice['peer_slice_id'])
46     return 1
47
48 def __get_hostnames(nodes):
49     hostnames = []
50     for node in nodes:
51         hostnames.append(node.hostname)
52     return hostnames
53     
54 def create_slice(api, xrn, xml, reg_objects=None):
55     """
56     Verify HRN and initialize the slice record in PLC if necessary.
57     """
58
59     hrn, type = urn_to_hrn(xrn)
60     peer = None
61     slices = Slices(api)
62     peer = slices.get_peer(hrn)
63     sfa_peer = slices.get_sfa_peer(hrn)
64     registry = api.registries[api.hrn]
65     credential = api.getCredential()
66     site_id, remote_site_id = slices.verify_site(registry, credential, hrn, 
67                                                  peer, sfa_peer, reg_objects)
68
69     slice = slices.verify_slice(registry, credential, hrn, site_id, 
70                                 remote_site_id, peer, sfa_peer, reg_objects)
71
72     network = Network(api)
73
74     slice = network.get_slice(api, hrn)
75     current = __get_hostnames(slice.get_nodes())
76     
77     network.addRSpec(xml, api.config.SFA_AGGREGATE_RSPEC_SCHEMA)
78     request = __get_hostnames(network.nodesWithSlivers())
79     
80     # remove nodes not in rspec
81     deleted_nodes = list(set(current).difference(request))
82
83     # add nodes from rspec
84     added_nodes = list(set(request).difference(current))
85     
86
87
88     if peer:
89         api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice.id, peer)
90
91     api.plshell.AddSliceToNodes(api.plauth, slice.name, added_nodes) 
92     api.plshell.DeleteSliceFromNodes(api.plauth, slice.name, deleted_nodes)
93
94     network.updateSliceTags()
95
96     if peer:
97         api.plshell.BindObjectToPeer(api.plauth, 'slice', slice.id, peer, 
98                                      slice.peer_id)
99
100     # print network.toxml()
101
102     return True
103
104
105 def get_ticket(api, xrn, rspec, origin_hrn=None, reg_objects=None):
106
107     slice_hrn, type = urn_to_hrn(xrn)
108     slices = Slices(api)
109     peer = slices.get_peer(slice_hrn)
110     sfa_peer = slices.get_sfa_peer(slice_hrn)
111     
112     # get the slice record
113     registry = api.registries[api.hrn]
114     credential = api.getCredential()
115     records = registry.resolve(credential, xrn)
116
117     # similar to create_slice, we must verify that the required records exist
118     # at this aggregate before we can issue a ticket   
119     site_id, remote_site_id = slices.verify_site(registry, credential, slice_hrn,
120                                                  peer, sfa_peer, reg_objects)
121     slice = slices.verify_slice(registry, credential, slice_hrn, site_id,
122                                 remote_site_id, peer, sfa_peer, reg_objects)
123
124     # make sure we get a local slice record
125     record = None  
126     for tmp_record in records:
127         if tmp_record['type'] == 'slice' and \
128            not tmp_record['peer_authority']:
129             record = SliceRecord(dict=tmp_record)
130     if not record:
131         raise RecordNotFound(slice_hrn)
132
133     # get sliver info
134     slivers = Slices(api).get_slivers(slice_hrn)
135     if not slivers:
136         raise SliverDoesNotExist(slice_hrn)
137     
138     # get initscripts
139     initscripts = []
140     data = {
141         'timestamp': int(time.time()),
142         'initscripts': initscripts,
143         'slivers': slivers
144     }
145
146     # create the ticket
147     object_gid = record.get_gid_object()
148     new_ticket = SfaTicket(subject = object_gid.get_subject())
149     new_ticket.set_gid_caller(api.auth.client_gid)
150     new_ticket.set_gid_object(object_gid)
151     new_ticket.set_issuer(key=api.key, subject=api.hrn)
152     new_ticket.set_pubkey(object_gid.get_pubkey())
153     new_ticket.set_attributes(data)
154     new_ticket.set_rspec(rspec)
155     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
156     new_ticket.encode()
157     new_ticket.sign()
158     
159     return new_ticket.save_to_string(save_parents=True)
160
161 def start_slice(api, xrn):
162     hrn, type = urn_to_hrn(xrn)
163     slicename = hrn_to_pl_slicename(hrn)
164     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
165     if not slices:
166         raise RecordNotFound(hrn)
167     slice_id = slices[0]
168     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
169     attribute_id = attributes[0]['slice_attribute_id']
170     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "1" )
171
172     return 1
173  
174 def stop_slice(api, xrn):
175     hrn, type = urn_to_hrn(xrn)
176     slicename = hrn_to_pl_slicename(hrn)
177     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
178     if not slices:
179         raise RecordNotFound(hrn)
180     slice_id = slices[0]['slice_id']
181     attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
182     attribute_id = attributes[0]['slice_attribute_id']
183     api.plshell.UpdateSliceTag(api.plauth, attribute_id, "0")
184     return 1
185
186 def reset_slice(api, xrn):
187     # XX not implemented at this interface
188     return 1
189
190 def get_slices(api):
191     # look in cache first
192     if api.cache:
193         slices = api.cache.get('slices')
194         if slices:
195             return slices
196
197     # get data from db 
198     slices = api.plshell.GetSlices(api.plauth, {'peer_id': None}, ['name'])
199     slice_hrns = [slicename_to_hrn(api.hrn, slice['name']) for slice in slices]
200     slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
201
202     # cache the result
203     if api.cache:
204         api.cache.add('slices', slice_urns) 
205
206     return slice_urns
207     
208 def get_rspec(api, creds, options):
209     # get slice's hrn from options
210     xrn = options.get('geni_slice_urn', None)
211     hrn, type = urn_to_hrn(xrn)
212
213     # get hrn of the original caller
214     origin_hrn = options.get('origin_hrn', None)
215     if not origin_hrn:
216         origin_hrn = Credential(string=creds[0]).get_gid_caller().get_hrn()
217     
218     # look in cache first
219     if api.cache and not xrn:
220         rspec = api.cache.get('nodes')
221         if rspec:
222             return rspec 
223
224     network = Network(api)
225     if (hrn):
226         if network.get_slice(api, hrn):
227             network.addSlice()
228
229     rspec = network.toxml()
230
231     # cache the result
232     if api.cache and not xrn:
233         api.cache.add('nodes', rspec)
234
235     return rspec
236
237
238 """
239 Returns the request context required by sfatables. At some point, this
240 mechanism should be changed to refer to "contexts", which is the
241 information that sfatables is requesting. But for now, we just return
242 the basic information needed in a dict.
243 """
244 def fetch_context(slice_xrn, user_xrn, contexts):
245     slice_hrn, type = urn_to_hrn(slice_xrn)
246     user_hrn, type = urn_to_hrn(user_xrn)
247     base_context = {'sfa':{'user':{'hrn':user_hrn}, 'slice':{'hrn':slice_hrn}}}
248     return base_context
249
250 def main():
251     api = SfaAPI()
252     """
253     rspec = get_rspec(api, "plc.princeton.sapan", None)
254     #rspec = get_rspec(api, "plc.princeton.coblitz", None)
255     #rspec = get_rspec(api, "plc.pl.sirius", None)
256     print rspec
257     """
258     f = open(sys.argv[1])
259     xml = f.read()
260     f.close()
261     create_slice(api, "plc.princeton.sapan", xml)
262
263 if __name__ == "__main__":
264     main()