if the slice is renewed in the local aggregate, we have to make corresponding change...
[sfa.git] / sfa / plc / slices.py
1 ### $Id$
2 ### $URL$
3
4 import datetime
5 import time
6 import traceback
7 import sys
8
9 from types import StringTypes
10 from sfa.util.misc import *
11 from sfa.util.rspec import *
12 from sfa.util.specdict import *
13 from sfa.util.faults import *
14 from sfa.util.storage import *
15 from sfa.util.record import GeniRecord
16 from sfa.util.policy import Policy
17 from sfa.util.prefixTree import prefixTree
18 from sfa.util.debug import log
19 from sfa.server.aggregate import Aggregates
20 from sfa.server.registry import Registries
21
22 MAXINT =  2L**31-1
23
24 class Slices(SimpleStorage):
25
26     rspec_to_slice_tag = {'max_rate':'net_max_rate'}
27
28     def __init__(self, api, ttl = .5, origin_hrn=None):
29         self.api = api
30         self.ttl = ttl
31         self.threshold = None
32         path = self.api.config.SFA_DATA_DIR
33         filename = ".".join([self.api.interface, self.api.hrn, "slices"])
34         filepath = path + os.sep + filename
35         self.slices_file = filepath
36         SimpleStorage.__init__(self, self.slices_file)
37         self.policy = Policy(self.api)    
38         self.load()
39         self.origin_hrn=origin_hrn
40
41     def get_slivers(self, hrn, node=None):
42          
43         slice_name = hrn_to_pl_slicename(hrn)
44         # XX Should we just call PLCAPI.GetSliceTicket(slice_name) instead
45         # of doing all of this?
46         #return self.api.GetSliceTicket(self.auth, slice_name) 
47         
48         # from PLCAPI.GetSlivers.get_slivers()
49         slice_fields = ['slice_id', 'name', 'instantiation', 'expires', 'person_ids', 'slice_tag_ids']
50         slices = self.api.plshell.GetSlices(self.api.plauth, slice_name, slice_fields)
51         # Build up list of users and slice attributes
52         person_ids = set()
53         all_slice_tag_ids = set()
54         for slice in slices:
55             person_ids.update(slice['person_ids'])
56             all_slice_tag_ids.update(slice['slice_tag_ids'])
57         person_ids = list(person_ids)
58         all_slice_tag_ids = list(all_slice_tag_ids)
59         # Get user information
60         all_persons_list = self.api.plshell.GetPersons(self.api.plauth, {'person_id':person_ids,'enabled':True}, ['person_id', 'enabled', 'key_ids'])
61         all_persons = {}
62         for person in all_persons_list:
63             all_persons[person['person_id']] = person        
64
65         # Build up list of keys
66         key_ids = set()
67         for person in all_persons.values():
68             key_ids.update(person['key_ids'])
69         key_ids = list(key_ids)
70         # Get user account keys
71         all_keys_list = self.api.plshell.GetKeys(self.api.plauth, key_ids, ['key_id', 'key', 'key_type'])
72         all_keys = {}
73         for key in all_keys_list:
74             all_keys[key['key_id']] = key
75         # Get slice attributes
76         all_slice_tags_list = self.api.plshell.GetSliceTags(self.api.plauth, all_slice_tag_ids)
77         all_slice_tags = {}
78         for slice_tag in all_slice_tags_list:
79             all_slice_tags[slice_tag['slice_tag_id']] = slice_tag
80            
81         slivers = []
82         for slice in slices:
83             keys = []
84             for person_id in slice['person_ids']:
85                 if person_id in all_persons:
86                     person = all_persons[person_id]
87                     if not person['enabled']:
88                         continue
89                     for key_id in person['key_ids']:
90                         if key_id in all_keys:
91                             key = all_keys[key_id]
92                             keys += [{'key_type': key['key_type'],
93                                     'key': key['key']}]
94             attributes = []
95             # All (per-node and global) attributes for this slice
96             slice_tags = []
97             for slice_tag_id in slice['slice_tag_ids']:
98                 if slice_tag_id in all_slice_tags:
99                     slice_tags.append(all_slice_tags[slice_tag_id]) 
100             # Per-node sliver attributes take precedence over global
101             # slice attributes, so set them first.
102             # Then comes nodegroup slice attributes
103             # Followed by global slice attributes
104             sliver_attributes = []
105
106             if node is not None:
107                 for sliver_attribute in filter(lambda a: a['node_id'] == node['node_id'], slice_tags):
108                     sliver_attributes.append(sliver_attribute['tagname'])
109                     attributes.append({'tagname': sliver_attribute['tagname'],
110                                     'value': sliver_attribute['value']})
111
112             # set nodegroup slice attributes
113             for slice_tag in filter(lambda a: a['nodegroup_id'] in node['nodegroup_ids'], slice_tags):
114                 # Do not set any nodegroup slice attributes for
115                 # which there is at least one sliver attribute
116                 # already set.
117                 if slice_tag not in slice_tags:
118                     attributes.append({'tagname': slice_tag['tagname'],
119                         'value': slice_tag['value']})
120
121             for slice_tag in filter(lambda a: a['node_id'] is None, slice_tags):
122                 # Do not set any global slice attributes for
123                 # which there is at least one sliver attribute
124                 # already set.
125                 if slice_tag['tagname'] not in sliver_attributes:
126                     attributes.append({'tagname': slice_tag['tagname'],
127                                    'value': slice_tag['value']})
128
129             # XXX Sanity check; though technically this should be a system invariant
130             # checked with an assertion
131             if slice['expires'] > MAXINT:  slice['expires']= MAXINT
132             
133             slivers.append({
134                 'hrn': hrn,
135                 'name': slice['name'],
136                 'slice_id': slice['slice_id'],
137                 'instantiation': slice['instantiation'],
138                 'expires': slice['expires'],
139                 'keys': keys,
140                 'attributes': attributes
141             })
142
143         return slivers
144  
145     def get_peer(self, hrn):
146         # Becaues of myplc federation,  we first need to determine if this
147         # slice belongs to out local plc or a myplc peer. We will assume it 
148         # is a local site, unless we find out otherwise  
149         peer = None
150
151         # get this slice's authority (site)
152         slice_authority = get_authority(hrn)
153
154         # get this site's authority (sfa root authority or sub authority)
155         site_authority = get_authority(slice_authority).lower()
156
157         # check if we are already peered with this site_authority, if so
158         peers = self.api.plshell.GetPeers(self.api.plauth, {}, ['peer_id', 'peername', 'shortname', 'hrn_root'])
159         for peer_record in peers:
160             names = [name.lower() for name in peer_record.values() if isinstance(name, StringTypes)]
161             if site_authority in names:
162                 peer = peer_record['shortname']
163
164         return peer
165
166     def get_sfa_peer(self, hrn):
167         # return the authority for this hrn or None if we are the authority
168         sfa_peer = None
169         slice_authority = get_authority(hrn)
170         site_authority = get_authority(slice_authority)
171
172         if site_authority != self.api.hrn:
173             sfa_peer = site_authority
174
175         return sfa_peer 
176
177     def refresh(self):
178         """
179         Update the cached list of slices
180         """
181         # Reload components list
182         now = datetime.datetime.now()
183         if not self.has_key('threshold') or not self.has_key('timestamp') or \
184            now > datetime.datetime.fromtimestamp(time.mktime(time.strptime(self['threshold'], self.api.time_format))):
185             if self.api.interface in ['aggregate']:
186                 self.refresh_slices_aggregate()
187             elif self.api.interface in ['slicemgr']:
188                 self.refresh_slices_smgr()
189
190     def refresh_slices_aggregate(self):
191         slices = self.api.plshell.GetSlices(self.api.plauth, {'peer_id': None}, ['name'])
192         slice_hrns = [slicename_to_hrn(self.api.hrn, slice['name']) for slice in slices]
193
194          # update timestamp and threshold
195         timestamp = datetime.datetime.now()
196         hr_timestamp = timestamp.strftime(self.api.time_format)
197         delta = datetime.timedelta(hours=self.ttl)
198         threshold = timestamp + delta
199         hr_threshold = threshold.strftime(self.api.time_format)
200         
201         slice_details = {'hrn': slice_hrns,
202                          'timestamp': hr_timestamp,
203                          'threshold': hr_threshold
204                         }
205         self.update(slice_details)
206         self.write()     
207         
208
209     def refresh_slices_smgr(self):
210         slice_hrns = []
211         aggregates = Aggregates(self.api)
212         credential = self.api.getCredential()
213         for aggregate in aggregates:
214             success = False
215             # request hash is optional so lets try the call without it 
216             try:
217                 request_hash=None
218                 slices = aggregates[aggregate].get_slices(credential, request_hash)
219                 slice_hrns.extend(slices)
220                 success = True
221             except:
222                 print >> log, "%s" % (traceback.format_exc())
223                 print >> log, "Error calling slices at aggregate %(aggregate)s" % locals()
224
225             # try sending the request hash if the previous call failed 
226             if not success:
227                 arg_list = [credential]
228                 request_hash = self.api.key.compute_hash(arg_list)
229                 try:
230                     slices = aggregates[aggregate].get_slices(credential, request_hash)
231                     slice_hrns.extend(slices)
232                     success = True
233                 except:
234                     print >> log, "%s" % (traceback.format_exc())
235                     print >> log, "Error calling slices at aggregate %(aggregate)s" % locals()
236
237         # update timestamp and threshold
238         timestamp = datetime.datetime.now()
239         hr_timestamp = timestamp.strftime(self.api.time_format)
240         delta = datetime.timedelta(hours=self.ttl)
241         threshold = timestamp + delta
242         hr_threshold = threshold.strftime(self.api.time_format)
243
244         slice_details = {'hrn': slice_hrns,
245                          'timestamp': hr_timestamp,
246                          'threshold': hr_threshold
247                         }
248         self.update(slice_details)
249         self.write()
250
251
252     def delete_slice(self, hrn):
253         if self.api.interface in ['aggregate']:
254             self.delete_slice_aggregate(hrn)
255         elif self.api.interface in ['slicemgr']:
256             self.delete_slice_smgr(hrn)
257         
258     def delete_slice_aggregate(self, hrn):
259
260         slicename = hrn_to_pl_slicename(hrn)
261         slices = self.api.plshell.GetSlices(self.api.plauth, {'name': slicename})
262         if not slices:
263             return 1        
264         slice = slices[0]
265
266         # determine if this is a peer slice
267         peer = self.get_peer(hrn)
268         if peer:
269             self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'slice', slice['slice_id'], peer)
270         self.api.plshell.DeleteSliceFromNodes(self.api.plauth, slicename, slice['node_ids'])
271         if peer:
272             self.api.plshell.BindObjectToPeer(self.api.plauth, 'slice', slice['slice_id'], peer, slice['peer_slice_id'])
273         return 1
274
275     def delete_slice_smgr(self, hrn):
276         credential = self.api.getCredential()
277         origin_hrn = self.origin_hrn
278         aggregates = Aggregates(self.api)
279         for aggregate in aggregates:
280             success = False
281             # request hash is optional so lets try the call without it
282             try:
283                 request_hash=None       
284                 aggregates[aggregate].delete_slice(credential, hrn, request_hash, origin_hrn)
285                 success = True
286             except:
287                 print >> log, "%s" % (traceback.format_exc())
288                 print >> log, "Error calling list nodes at aggregate %s" % aggregate
289             
290             # try sending the request hash if the previous call failed 
291             if not success:
292                 try:
293                     arg_list = [credential, hrn]
294                     request_hash = self.api.key.compute_hash(arg_list)
295                     aggregates[aggregate].delete_slice(credential, hrn, request_hash, origin_hrn)
296                     success = True
297                 except:
298                     print >> log, "%s" % (traceback.format_exc())
299                     print >> log, "Error calling list nodes at aggregate %s" % aggregate
300                         
301     def create_slice(self, hrn, rspec):
302         
303         # check our slice policy before we procede
304         whitelist = self.policy['slice_whitelist']     
305         blacklist = self.policy['slice_blacklist']
306        
307         if whitelist and hrn not in whitelist or \
308            blacklist and hrn in blacklist:
309             policy_file = self.policy.policy_file
310             print >> log, "Slice %(hrn)s not allowed by policy %(policy_file)s" % locals()
311             return 1
312
313         if self.api.interface in ['aggregate']:     
314             self.create_slice_aggregate(hrn, rspec)
315         elif self.api.interface in ['slicemgr']:
316             self.create_slice_smgr(hrn, rspec)
317
318     def verify_site(self, registry, credential, slice_hrn, peer, sfa_peer):
319         authority = get_authority(slice_hrn)
320         try:
321             site_records = registry.resolve(credential, authority)
322         except:
323             arg_list = [credential, authority]
324             request_hash = self.api.key.compute_hash(arg_list)
325             site_records = registry.resolve(credential, authority, request_hash)
326             
327         site = {}
328         for site_record in site_records:
329             if site_record['type'] == 'authority':
330                 site = site_record
331         if not site:
332             raise RecordNotFound(authority)
333         remote_site_id = site.pop('site_id')    
334                 
335         login_base = get_leaf(authority)
336         sites = self.api.plshell.GetSites(self.api.plauth, login_base)
337         if not sites:
338             site_id = self.api.plshell.AddSite(self.api.plauth, site)
339             if peer:
340                 self.api.plshell.BindObjectToPeer(self.api.plauth, 'site', site_id, peer, remote_site_id)   
341             # mark this site as an sfa peer record
342             if sfa_peer:
343                 peer_dict = {'type': 'authority', 'hrn': authority, 'peer_authority': sfa_peer, 'pointer': site_id}
344                 try:
345                     registry.register_peer_object(credential, peer_dict)
346                 except:
347                     arg_list = [credential]
348                     request_hash = self.api.key.compute_hash(arg_list) 
349                     registry.register_peer_object(credential, peer_dict, request_hash)
350         else:
351             site_id = sites[0]['site_id']
352             remote_site_id = sites[0]['peer_site_id']
353
354
355         return (site_id, remote_site_id) 
356
357     def verify_slice(self, registry, credential, slice_hrn, site_id, remote_site_id, peer, sfa_peer):
358         slice = {}
359         slice_record = None
360         authority = get_authority(slice_hrn)
361         try:
362             slice_records = registry.resolve(credential, slice_hrn)
363         except:    
364             arg_list = [credential, slice_hrn]
365             request_hash = self.api.key.compute_hash(arg_list)
366             slice_records = registry.resolve(credential, slice_hrn, request_hash)
367
368         for record in slice_records:
369             if record['type'] in ['slice']:
370                 slice_record = record
371         if not slice_record:
372             raise RecordNotFound(hrn)
373         slicename = hrn_to_pl_slicename(slice_hrn)
374         parts = slicename.split("_")
375         login_base = parts[0]
376         slices = self.api.plshell.GetSlices(self.api.plauth, [slicename]) 
377         if not slices:
378             slice_fields = {}
379             slice_keys = ['name', 'url', 'description']
380             for key in slice_keys:
381                 if key in slice_record and slice_record[key]:
382                     slice_fields[key] = slice_record[key]
383
384             # add the slice  
385             slice_id = self.api.plshell.AddSlice(self.api.plauth, slice_fields)
386             slice = slice_fields
387             slice['slice_id'] = slice_id
388
389             # mark this slice as an sfa peer record
390             if sfa_peer:
391                 peer_dict = {'type': 'slice', 'hrn': slice_hrn, 'peer_authority': sfa_peer, 'pointer': slice_id}
392                 try:
393                     registry.register_peer_object(credential, peer_dict)
394                 except:
395                     arg_list = [credential]
396                     request_hash = self.api.key.compute_hash(arg_list) 
397                     registry.register_peer_object(credential, peer_dict, request_hash)
398
399             #this belongs to a peer
400             if peer:
401                 self.api.plshell.BindObjectToPeer(self.api.plauth, 'slice', slice_id, peer, slice_record['pointer'])
402             slice['node_ids'] = []
403         else:
404             slice = slices[0]
405             slice_id = slice['slice_id']
406             site_id = slice['site_id']
407             #the slice is alredy on the remote agg. Let us update(e.g. expires field) it with the latest info.
408             self.sync_slice(slice, slice_record, peer)
409
410         slice['peer_slice_id'] = slice_record['pointer']
411         self.verify_persons(registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer)
412     
413         return slice        
414
415     def verify_persons(self, registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer):
416         # get the list of valid slice users from the registry and make 
417         # sure they are added to the slice 
418         slicename = hrn_to_pl_slicename(slice_record['hrn'])
419         researchers = slice_record.get('researcher', [])
420         for researcher in researchers:
421             person_record = {}
422             try:
423                 person_records = registry.resolve(credential, researcher)
424             except:
425                 arg_list = [credential, researcher]
426                 request_hash = self.api.key.compute_hash(arg_list) 
427                 person_records = registry.resolve(credential, researcher, request_hash)
428             for record in person_records:
429                 if record['type'] in ['user']:
430                     person_record = record
431             if not person_record:
432                 pass
433             person_dict = person_record
434             local_person=False
435             if peer:
436                 peer_id = self.api.plshell.GetPeers(self.api.plauth, {'shortname': peer}, ['peer_id'])[0]['peer_id']
437                 persons = self.api.plshell.GetPersons(self.api.plauth, {'email': [person_dict['email']], 'peer_id': peer_id}, ['person_id', 'key_ids'])
438                 if not persons:
439                     persons = self.api.plshell.GetPersons(self.api.plauth, [person_dict['email']], ['person_id', 'key_ids'])
440                     if persons:
441                        local_person=True
442
443             else:
444                 persons = self.api.plshell.GetPersons(self.api.plauth, [person_dict['email']], ['person_id', 'key_ids'])   
445         
446             if not persons:
447                 person_id=self.api.plshell.AddPerson(self.api.plauth, person_dict)
448                 self.api.plshell.UpdatePerson(self.api.plauth, person_id, {'enabled' : True})
449                 
450                 # mark this person as an sfa peer record
451                 if sfa_peer:
452                     peer_dict = {'type': 'user', 'hrn': researcher, 'peer_authority': sfa_peer, 'pointer': person_id}
453                     try:
454                         registry.register_peer_object(credential, peer_dict)
455                     except:
456                         arg_list = [credential]
457                         request_hash = self.api.key.compute_hash(arg_list) 
458                         registry.register_peer_object(credential, peer_dict, request_hash)
459
460                 if peer:
461                     self.api.plshell.BindObjectToPeer(self.api.plauth, 'person', person_id, peer, person_dict['pointer'])
462                 key_ids = []
463             else:
464                 person_id = persons[0]['person_id']
465                 key_ids = persons[0]['key_ids']
466
467
468             # if this is a peer person, we must unbind them from the peer or PLCAPI will throw
469             # an error
470             if peer:
471                 self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'person', person_id, peer)
472                 self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'site', site_id,  peer)
473
474             self.api.plshell.AddPersonToSlice(self.api.plauth, person_dict['email'], slicename)
475             self.api.plshell.AddPersonToSite(self.api.plauth, person_dict['email'], site_id)
476             if peer and not local_person:
477                 self.api.plshell.BindObjectToPeer(self.api.plauth, 'person', person_id, peer, person_dict['pointer'])
478             if peer:
479                 self.api.plshell.BindObjectToPeer(self.api.plauth, 'site', site_id, peer, remote_site_id)
480             
481             self.verify_keys(registry, credential, person_dict, key_ids, person_id, peer, local_person)
482
483     def verify_keys(self, registry, credential, person_dict, key_ids, person_id,  peer, local_person):
484         keylist = self.api.plshell.GetKeys(self.api.plauth, key_ids, ['key'])
485         keys = [key['key'] for key in keylist]
486         
487         #add keys that arent already there
488         key_ids = person_dict['key_ids']
489         for personkey in person_dict['keys']:
490             if personkey not in keys:
491                 key = {'key_type': 'ssh', 'key': personkey}
492                 if peer:
493                     self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'person', person_id, peer)
494                 key_id = self.api.plshell.AddPersonKey(self.api.plauth, person_dict['email'], key)
495                 if peer and not local_person:
496                     self.api.plshell.BindObjectToPeer(self.api.plauth, 'person', person_id, peer, person_dict['pointer'])
497                 if peer:
498                     try: self.api.plshell.BindObjectToPeer(self.api.plauth, 'key', key_id, peer, key_ids.pop(0))
499
500                     except: pass   
501
502     def create_slice_aggregate(self, hrn, rspec):
503
504         # Determine if this is a peer slice
505         peer = self.get_peer(hrn)
506         sfa_peer = self.get_sfa_peer(hrn)
507
508         spec = RSpec(rspec)
509         # Get the slice record from sfa
510         slicename = hrn_to_pl_slicename(hrn) 
511         slice = {}
512         slice_record = None
513         registries = Registries(self.api)
514         registry = registries[self.api.hrn]
515         credential = self.api.getCredential()
516
517         site_id, remote_site_id = self.verify_site(registry, credential, hrn, peer, sfa_peer)
518         slice = self.verify_slice(registry, credential, hrn, site_id, remote_site_id, peer, sfa_peer)
519
520         # find out where this slice is currently running
521         nodelist = self.api.plshell.GetNodes(self.api.plauth, slice['node_ids'], ['hostname'])
522         hostnames = [node['hostname'] for node in nodelist]
523
524         # get netspec details
525         nodespecs = spec.getDictsByTagName('NodeSpec')
526
527         # dict in which to store slice attributes to set for the nodes
528         nodes = {}
529         for nodespec in nodespecs:
530             if isinstance(nodespec['name'], list):
531                 for nodename in nodespec['name']:
532                     nodes[nodename] = {}
533                     for k in nodespec.keys():
534                         rspec_attribute_value = nodespec[k]
535                         if (self.rspec_to_slice_tag.has_key(k)):
536                             slice_tag_name = self.rspec_to_slice_tag[k]
537                             nodes[nodename][slice_tag_name] = rspec_attribute_value
538             elif isinstance(nodespec['name'], StringTypes):
539                 nodename = nodespec['name']
540                 nodes[nodename] = {}
541                 for k in nodespec.keys():
542                     rspec_attribute_value = nodespec[k]
543                     if (self.rspec_to_slice_tag.has_key(k)):
544                         slice_tag_name = self.rspec_to_slice_tag[k]
545                         nodes[nodename][slice_tag_name] = rspec_attribute_value
546
547                 for k in nodespec.keys():
548                     rspec_attribute_value = nodespec[k]
549                     if (self.rspec_to_slice_tag.has_key(k)):
550                         slice_tag_name = self.rspec_to_slice_tag[k]
551                         nodes[nodename][slice_tag_name] = rspec_attribute_value
552
553         node_names = nodes.keys()
554         # remove nodes not in rspec
555         deleted_nodes = list(set(hostnames).difference(node_names))
556         # add nodes from rspec
557         added_nodes = list(set(node_names).difference(hostnames))
558
559         if peer:
560             self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'slice', slice['slice_id'], peer)
561
562         self.api.plshell.AddSliceToNodes(self.api.plauth, slicename, added_nodes) 
563
564         # Add recognized slice tags
565         for node_name in node_names:
566             node = nodes[node_name]
567             for slice_tag in node.keys():
568                 value = node[slice_tag]
569                 if (isinstance(value, list)):
570                     value = value[0]
571
572                 self.api.plshell.AddSliceTag(self.api.plauth, slicename, slice_tag, value, node_name)
573
574         self.api.plshell.DeleteSliceFromNodes(self.api.plauth, slicename, deleted_nodes)
575         if peer:
576             self.api.plshell.BindObjectToPeer(self.api.plauth, 'slice', slice['slice_id'], peer, slice['peer_slice_id'])
577
578         return 1
579
580     def create_slice_smgr(self, hrn, rspec):
581         spec = RSpec()
582         tempspec = RSpec()
583         spec.parseString(rspec)
584         slicename = hrn_to_pl_slicename(hrn)
585         specDict = spec.toDict()
586         if specDict.has_key('RSpec'): specDict = specDict['RSpec']
587         if specDict.has_key('start_time'): start_time = specDict['start_time']
588         else: start_time = 0
589         if specDict.has_key('end_time'): end_time = specDict['end_time']
590         else: end_time = 0
591
592         rspecs = {}
593         aggregates = Aggregates(self.api)
594         credential = self.api.getCredential()
595
596         # split the netspecs into individual rspecs
597         netspecs = spec.getDictsByTagName('NetSpec')
598         for netspec in netspecs:
599             net_hrn = netspec['name']
600             resources = {'start_time': start_time, 'end_time': end_time, 'networks': netspec}
601             resourceDict = {'RSpec': resources}
602             tempspec.parseDict(resourceDict)
603             rspecs[net_hrn] = tempspec.toxml()
604
605         # send each rspec to the appropriate aggregate/sm
606         origin_hrn = self.origin_hrn
607         for net_hrn in rspecs:
608             try:
609                 # if we are directly connected to the aggregate then we can just send them the rspec
610                 # if not, then we may be connected to an sm thats connected to the aggregate
611                 if net_hrn in aggregates:
612                     # send the whloe rspec to the local aggregate
613                     if net_hrn in [self.api.hrn]:
614                         try:
615                             request_hash = None
616                             aggregates[net_hrn].create_slice(credential, hrn, rspec, request_hash, origin_hrn)
617                         except:
618                             arg_list = [credential,hrn,rspec]
619                             request_hash = self.api.key.compute_hash(arg_list)
620                             aggregates[net_hrn].create_slice(credential, hrn, rspec, request_hash, origin_hrn)
621                     else:
622                         try:
623                             request_hash = None
624                             aggregates[net_hrn].create_slice(credential, hrn, rspecs[net_hrn], request_hash, origin_hrn)
625                         except:
626                             arg_list = [credential,hrn,rspecs[net_hrn]]
627                             request_hash = self.api.key.compute_hash(arg_list)
628                             aggregates[net_hrn].create_slice(credential, hrn, rspecs[net_hrn], request_hash, origin_hrn)
629                 else:
630                     # lets forward this rspec to a sm that knows about the network
631                     arg_list = [credential, net_hrn]
632                     request_hash = self.api.compute_hash(arg_list)    
633                     for aggregate in aggregates:
634                         try:
635                             network_found = aggregates[aggregate].get_aggregates(credential, net_hrn)
636                         except:
637                             network_found = aggregates[aggregate].get_aggregates(credential, net_hrn, request_hash)
638                         if network_networks:
639                             try:
640                                 request_hash = None
641                                 aggregates[aggregate].create_slice(credential, hrn, rspecs[net_hrn], request_hash, origin_hrn)
642                             except:
643                                 arg_list = [credential, hrn, rspecs[net_hrn]]
644                                 request_hash = self.api.key.compute_hash(arg_list) 
645                                 aggregates[aggregate].create_slice(credential, hrn, rspecs[net_hrn], request_hash, origin_hrn)
646                      
647             except:
648                 print >> log, "Error creating slice %(hrn)s at aggregate %(net_hrn)s" % locals()
649                 traceback.print_exc()
650         return 1
651
652
653     def start_slice(self, hrn):
654         if self.api.interface in ['aggregate']:
655             self.start_slice_aggregate(hrn)
656         elif self.api.interface in ['slicemgr']:
657             self.start_slice_smgr(hrn)
658
659     def start_slice_aggregate(self, hrn):
660         slicename = hrn_to_pl_slicename(hrn)
661         slices = self.api.plshell.GetSlices(self.api.plauth, {'name': slicename}, ['slice_id'])
662         if not slices:
663             raise RecordNotFound(hrn)
664         slice_id = slices[0]
665         attributes = self.api.plshell.GetSliceAttributes(self.api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
666         attribute_id = attreibutes[0]['slice_attribute_id']
667         self.api.plshell.UpdateSliceAttribute(self.api.plauth, attribute_id, "1" )
668         return 1
669
670     def start_slice_smgr(self, hrn):
671         credential = self.api.getCredential()
672         aggregates = Aggregates(self.api)
673         for aggregate in aggregates:
674             aggregates[aggregate].start_slice(credential, hrn)
675         return 1
676
677
678     def stop_slice(self, hrn):
679         if self.api.interface in ['aggregate']:
680             self.stop_slice_aggregate(hrn)
681         elif self.api.interface in ['slicemgr']:
682             self.stop_slice_smgr(hrn)
683
684     def stop_slice_aggregate(self, hrn):
685         slicename = hrn_to_pl_slicename(hrn)
686         slices = self.api.plshell.GetSlices(self.api.plauth, {'name': slicename}, ['slice_id'])
687         if not slices:
688             raise RecordNotFound(hrn)
689         slice_id = slices[0]['slice_id']
690         attributes = self.api.plshell.GetSliceAttributes(self.api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
691         attribute_id = attributes[0]['slice_attribute_id']
692         self.api.plshell.UpdateSliceAttribute(self.api.plauth, attribute_id, "0")
693         return 1
694
695     def stop_slice_smgr(self, hrn):
696         credential = self.api.getCredential()
697         aggregates = Aggregates(self.api)
698         arg_list = [credential, hrn]
699         request_hash = self.api.key.compute_hash(arg_list)
700         for aggregate in aggregates:
701             try:
702                 aggregates[aggregate].stop_slice(credential, hrn)
703             except:  
704                 aggregates[aggregate].stop_slice(credential, hrn, request_hash)
705
706     def sync_slice(self, old_record, new_record, peer):
707         if old_record['expires'] != new_record['expires']:
708            if peer:
709             self.api.plshell.UnBindObjectFromPeer(self.api.plauth, 'slice', old_record['slice_id'], peer)
710             self.api.plshell.UpdateSlice(self.api.plauth, old_record['slice_id'], {'expires' : new_record['expires']})
711         if peer:
712             self.api.plshell.BindObjectToPeer(self.api.plauth, 'slice', old_record['slice_id'], peer, old_record['peer_slice_id'])
713         return 1