sfadump more usable
[sfa.git] / sfa / managers / aggregate_manager_pl.py
1 import datetime
2 import time
3 import traceback
4 import sys
5 import re
6 from types import StringTypes
7
8 from sfa.util.namespace import get_authority, urn_to_hrn, slicename_to_hrn, hrn_to_pl_slicename, hrn_to_urn
9 from sfa.util.rspec import *
10 from sfa.util.specdict import *
11 from sfa.util.faults import *
12 from sfa.util.record import SfaRecord
13 from sfa.util.policy import Policy
14 from sfa.util.record import *
15 from sfa.util.sfaticket import SfaTicket
16 from sfa.plc.slices import Slices
17 from sfa.trust.credential import Credential
18 import sfa.plc.peers as peers
19 from sfa.plc.network import *
20 from sfa.plc.api import SfaAPI
21 from sfa.plc.slices import *
22
23
24 def __get_registry_objects(slice_xrn, creds, users):
25     """
26
27     """
28     hrn, type = urn_to_hrn(slice_xrn)
29
30     hrn_auth = get_authority(hrn)
31
32     # Build up objects that an SFA registry would return if SFA
33     # could contact the slice's registry directly
34     reg_objects = None
35
36     if users:
37         # dont allow special characters in the site login base
38         #only_alphanumeric = re.compile('[^a-zA-Z0-9]+')
39         #login_base = only_alphanumeric.sub('', hrn_auth[:20]).lower()
40         slicename = hrn_to_pl_slicename(hrn)
41         login_base = slicename.split('_')[0]
42         reg_objects = {}
43
44         site = {}
45         site['site_id'] = 0
46         site['name'] = 'geni.%s' % login_base 
47         site['enabled'] = True
48         site['max_slices'] = 100
49
50         # Note:
51         # Is it okay if this login base is the same as one already at this myplc site?
52         # Do we need uniqueness?  Should use hrn_auth instead of just the leaf perhaps?
53         site['login_base'] = login_base
54         site['abbreviated_name'] = login_base
55         site['max_slivers'] = 1000
56         reg_objects['site'] = site
57
58         slice = {}
59         slice['expires'] = int(time.mktime(Credential(string=creds[0]).get_lifetime().timetuple()))
60         slice['hrn'] = hrn
61         slice['name'] = hrn_to_pl_slicename(hrn)
62         slice['url'] = hrn
63         slice['description'] = hrn
64         slice['pointer'] = 0
65         reg_objects['slice_record'] = slice
66
67         reg_objects['users'] = {}
68         for user in users:
69             user['key_ids'] = []
70             hrn, _ = urn_to_hrn(user['urn'])
71             user['email'] = hrn_to_pl_slicename(hrn) + "@geni.net"
72             user['first_name'] = hrn
73             user['last_name'] = hrn
74             reg_objects['users'][user['email']] = user
75
76         return reg_objects
77
78 def __get_hostnames(nodes):
79     hostnames = []
80     for node in nodes:
81         hostnames.append(node.hostname)
82     return hostnames
83
84 def get_version():
85     version = {}
86     version['geni_api'] = 1
87     version['sfa'] = 1
88     return version
89
90 def slice_status(api, slice_xrn, creds):
91     result = {}
92     result['geni_urn'] = slice_xrn
93     result['geni_status'] = 'unknown'
94     result['geni_resources'] = {}
95     return result
96
97 def create_slice(api, slice_xrn, creds, rspec, users):
98     """
99     Create the sliver[s] (slice) at this aggregate.    
100     Verify HRN and initialize the slice record in PLC if necessary.
101     """
102
103     reg_objects = __get_registry_objects(slice_xrn, creds, users)
104
105     hrn, type = urn_to_hrn(slice_xrn)
106     peer = None
107     slices = Slices(api)
108     peer = slices.get_peer(hrn)
109     sfa_peer = slices.get_sfa_peer(hrn)
110     registry = api.registries[api.hrn]
111     credential = api.getCredential()
112     site_id, remote_site_id = slices.verify_site(registry, credential, hrn, 
113                                                  peer, sfa_peer, reg_objects)
114
115     slice_record = slices.verify_slice(registry, credential, hrn, site_id, 
116                                 remote_site_id, peer, sfa_peer, reg_objects)
117      
118     network = Network(api)
119
120     slice = network.get_slice(api, hrn)
121     slice.peer_id = slice_record['peer_slice_id']
122     current = __get_hostnames(slice.get_nodes())
123     
124     network.addRSpec(rspec, api.config.SFA_AGGREGATE_RSPEC_SCHEMA)
125     request = __get_hostnames(network.nodesWithSlivers())
126     
127     # remove nodes not in rspec
128     deleted_nodes = list(set(current).difference(request))
129
130     # add nodes from rspec
131     added_nodes = list(set(request).difference(current))
132
133     try:
134         if peer:
135             api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice.id, peer)
136
137         api.plshell.AddSliceToNodes(api.plauth, slice.name, added_nodes) 
138         api.plshell.DeleteSliceFromNodes(api.plauth, slice.name, deleted_nodes)
139
140         network.updateSliceTags()
141
142     finally:
143         if peer:
144             api.plshell.BindObjectToPeer(api.plauth, 'slice', slice.id, peer, 
145                                          slice.peer_id)
146
147     # print network.toxml()
148
149     return True
150
151
152 def renew_slice(api, xrn, creds, exipration_time):
153     hrn, type = urn_to_hrn(xrn)
154     slicename = hrn_to_pl_slicename(hrn)
155     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
156     if not slices:
157         raise RecordNotFound(hrn)
158     slice = slices[0]
159     slice['expires'] = expiration_time
160     api.plshell.UpdateSlice(api.plauth, slice['slice_id'], slice)
161     return 1         
162
163 def start_slice(api, xrn, creds):
164     hrn, type = urn_to_hrn(xrn)
165     slicename = hrn_to_pl_slicename(hrn)
166     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
167     if not slices:
168         raise RecordNotFound(hrn)
169     slice_id = slices[0]['slice_id']
170     slice_tags = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'tagname': 'enabled'}, ['slice_tag_id'])
171     # just remove the tag if it exists
172     if slice_tags:
173         api.plshell.DeleteSliceTag(api.plauth, slice_tags[0]['slice_tag_id'])
174
175     return 1
176  
177 def stop_slice(api, xrn, creds):
178     hrn, type = urn_to_hrn(xrn)
179     slicename = hrn_to_pl_slicename(hrn)
180     slices = api.plshell.GetSlices(api.plauth, {'name': slicename}, ['slice_id'])
181     if not slices:
182         raise RecordNotFound(hrn)
183     slice_id = slices[0]['slice_id']
184     slice_tags = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'tagname': 'enabled'})
185     if not slice_tags:
186         api.plshell.AddSliceTag(api.plauth, slice_id, 'enabled', '0')
187     elif slice_tags[0]['value'] != "0":
188         tag_id = attributes[0]['slice_tag_id']
189         api.plshell.UpdateSliceTag(api.plauth, tag_id, '0')
190     return 1
191
192 def reset_slice(api, xrn):
193     # XX not implemented at this interface
194     return 1
195
196 def delete_slice(api, xrn, creds):
197     hrn, type = urn_to_hrn(xrn)
198     slicename = hrn_to_pl_slicename(hrn)
199     slices = api.plshell.GetSlices(api.plauth, {'name': slicename})
200     if not slices:
201         return 1
202     slice = slices[0]
203
204     # determine if this is a peer slice
205     peer = peers.get_peer(api, hrn)
206     try:
207         if peer:
208             api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice['slice_id'], peer)
209         api.plshell.DeleteSliceFromNodes(api.plauth, slicename, slice['node_ids'])
210     finally:
211         if peer:
212             api.plshell.BindObjectToPeer(api.plauth, 'slice', slice['slice_id'], peer, slice['peer_slice_id'])
213     return 1
214
215 def get_slices(api, creds):
216     # look in cache first
217     if api.cache:
218         slices = api.cache.get('slices')
219         if slices:
220             return slices
221
222     # get data from db 
223     slices = api.plshell.GetSlices(api.plauth, {'peer_id': None}, ['name'])
224     slice_hrns = [slicename_to_hrn(api.hrn, slice['name']) for slice in slices]
225     slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
226
227     # cache the result
228     if api.cache:
229         api.cache.add('slices', slice_urns) 
230
231     return slice_urns
232     
233 def get_rspec(api, creds, options):
234     # get slice's hrn from options
235     xrn = options.get('geni_slice_urn', None)
236     hrn, type = urn_to_hrn(xrn)
237
238     # look in cache first
239     if api.cache and not xrn:
240         rspec = api.cache.get('nodes')
241         if rspec:
242             return rspec 
243
244     network = Network(api)
245     if (hrn):
246         if network.get_slice(api, hrn):
247             network.addSlice()
248
249     rspec = network.toxml()
250
251     # cache the result
252     if api.cache and not xrn:
253         api.cache.add('nodes', rspec)
254
255     return rspec
256
257
258 def get_ticket(api, xrn, creds, rspec, users):
259
260     reg_objects = __get_registry_objects(xrn, creds, users)
261
262     slice_hrn, type = urn_to_hrn(xrn)
263     slices = Slices(api)
264     peer = slices.get_peer(slice_hrn)
265     sfa_peer = slices.get_sfa_peer(slice_hrn)
266
267     # get the slice record
268     registry = api.registries[api.hrn]
269     credential = api.getCredential()
270     records = registry.Resolve(xrn, credential)
271
272     # similar to create_slice, we must verify that the required records exist
273     # at this aggregate before we can issue a ticket
274     site_id, remote_site_id = slices.verify_site(registry, credential, slice_hrn,
275                                                  peer, sfa_peer, reg_objects)
276     slice = slices.verify_slice(registry, credential, slice_hrn, site_id,
277                                 remote_site_id, peer, sfa_peer, reg_objects)
278
279     # make sure we get a local slice record
280     record = None
281     for tmp_record in records:
282         if tmp_record['type'] == 'slice' and \
283            not tmp_record['peer_authority']:
284             record = SliceRecord(dict=tmp_record)
285     if not record:
286         raise RecordNotFound(slice_hrn)
287
288     # get sliver info
289     slivers = Slices(api).get_slivers(slice_hrn)
290     if not slivers:
291         raise SliverDoesNotExist(slice_hrn)
292
293     # get initscripts
294     initscripts = []
295     data = {
296         'timestamp': int(time.time()),
297         'initscripts': initscripts,
298         'slivers': slivers
299     }
300
301     # create the ticket
302     object_gid = record.get_gid_object()
303     new_ticket = SfaTicket(subject = object_gid.get_subject())
304     new_ticket.set_gid_caller(api.auth.client_gid)
305     new_ticket.set_gid_object(object_gid)
306     new_ticket.set_issuer(key=api.key, subject=api.hrn)
307     new_ticket.set_pubkey(object_gid.get_pubkey())
308     new_ticket.set_attributes(data)
309     new_ticket.set_rspec(rspec)
310     #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
311     new_ticket.encode()
312     new_ticket.sign()
313
314     return new_ticket.save_to_string(save_parents=True)
315
316
317
318 def main():
319     api = SfaAPI()
320     """
321     rspec = get_rspec(api, "plc.princeton.sapan", None)
322     #rspec = get_rspec(api, "plc.princeton.coblitz", None)
323     #rspec = get_rspec(api, "plc.pl.sirius", None)
324     print rspec
325     """
326     f = open(sys.argv[1])
327     xml = f.read()
328     f.close()
329     create_slice(api, "plc.princeton.sapan", xml)
330
331 if __name__ == "__main__":
332     main()