995e694a3d9a20a291ab52f2f31a19253f4184f1
[sfa.git] / sfa / managers / aggregate_manager.py
1 import time
2 import sys
3
4 from sfa.util.sfalogging import logger
5 from sfa.util.faults import RecordNotFound, SliverDoesNotExist
6 from sfa.util.xrn import Xrn, get_authority, hrn_to_urn, urn_to_hrn, urn_to_sliver_id
7 from sfa.util.plxrn import slicename_to_hrn, hrn_to_pl_slicename
8 from sfa.util.version import version_core
9 from sfa.util.sfatime import utcparse
10 from sfa.util.callids import Callids
11
12 from sfa.trust.sfaticket import SfaTicket
13 from sfa.trust.credential import Credential
14
15 from sfa.rspecs.version_manager import VersionManager
16 from sfa.rspecs.rspec import RSpec
17
18 from sfa.server.sfaapi import SfaApi
19
20 import sfa.plc.peers as peers
21 from sfa.plc.plaggregate import PlAggregate
22 from sfa.plc.plslices import PlSlices
23
24 class AggregateManager:
25
26     def __init__ (self):
27         # xxx Thierry : caching at the aggregate level sounds wrong...
28         self.caching=True
29         #self.caching=False
30     
31     # essentially a union of the core version, the generic version (this code) and
32     # whatever the driver needs to expose
33     def GetVersion(self, api, options):
34     
35         xrn=Xrn(api.hrn)
36         version = version_core()
37         version_generic = {'interface':'aggregate',
38                            'sfa': 2,
39                            'geni_api': 2,
40                            'hrn':xrn.get_hrn(),
41                            'urn':xrn.get_urn(),
42                            }
43         version.update(version_generic)
44         testbed_version = self.driver.aggregate_version()
45         version.update(testbed_version)
46         return version
47     
48     def SliverStatus (self, api, slice_xrn, creds, options):
49         call_id = options.get('call_id')
50         if Callids().already_handled(call_id): return {}
51     
52         xrn = Xrn(slice_xrn)
53         slice_urn=xrn.get_urn()
54         slice_hrn=xrn.get_hrn()
55
56         return self.driver.sliver_status (slice_urn, slice_hrn)
57     
58     def CreateSliver(self, api, slice_xrn, creds, rspec_string, users, options):
59         """
60         Create the sliver[s] (slice) at this aggregate.    
61         Verify HRN and initialize the slice record in PLC if necessary.
62         """
63         call_id = options.get('call_id')
64         if Callids().already_handled(call_id): return ""
65     
66         xrn = Xrn(slice_xrn)
67         slice_urn=xrn.get_urn()
68         slice_hrn=xrn.get_hrn()
69
70         return self.driver.create_sliver (slice_urn, slice_hrn, creds, rspec_string, users, options)
71     
72     def RenewSliver(self, api, xrn, creds, expiration_time, options):
73         call_id = options.get('call_id')
74         if Callids().already_handled(call_id): return True
75         
76         xrn = Xrn(slice_xrn)
77         slice_urn=xrn.get_urn()
78         slice_hrn=xrn.get_hrn()
79
80         return self.driver.renew_sliver (slice_urn, slice_hrn, creds, expiration_time, options)
81     
82     def start_slice(self, api, xrn, creds):
83         (hrn, _) = urn_to_hrn(xrn)
84         slicename = hrn_to_pl_slicename(hrn)
85         slices = api.driver.GetSlices({'name': slicename}, ['slice_id'])
86         if not slices:
87             raise RecordNotFound(hrn)
88         slice_id = slices[0]['slice_id']
89         slice_tags = api.driver.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'}, ['slice_tag_id'])
90         # just remove the tag if it exists
91         if slice_tags:
92             api.driver.DeleteSliceTag(slice_tags[0]['slice_tag_id'])
93     
94         return 1
95      
96     def stop_slice(self, api, xrn, creds):
97         hrn, _ = urn_to_hrn(xrn)
98         slicename = hrn_to_pl_slicename(hrn)
99         slices = api.driver.GetSlices({'name': slicename}, ['slice_id'])
100         if not slices:
101             raise RecordNotFound(hrn)
102         slice_id = slices[0]['slice_id']
103         slice_tags = api.driver.GetSliceTags({'slice_id': slice_id, 'tagname': 'enabled'})
104         if not slice_tags:
105             api.driver.AddSliceTag(slice_id, 'enabled', '0')
106         elif slice_tags[0]['value'] != "0":
107             tag_id = slice_tags[0]['slice_tag_id']
108             api.driver.UpdateSliceTag(tag_id, '0')
109         return 1
110     
111     def reset_slice(self, api, xrn):
112         # XX not implemented at this interface
113         return 1
114     
115     def DeleteSliver(self, api, xrn, creds, options):
116         call_id = options.get('call_id')
117         if Callids().already_handled(call_id): return ""
118         (hrn, _) = urn_to_hrn(xrn)
119         slicename = hrn_to_pl_slicename(hrn)
120         slices = api.driver.GetSlices({'name': slicename})
121         if not slices:
122             return 1
123         slice = slices[0]
124     
125         # determine if this is a peer slice
126         peer = peers.get_peer(api, hrn)
127         try:
128             if peer:
129                 api.driver.UnBindObjectFromPeer('slice', slice['slice_id'], peer)
130             api.driver.DeleteSliceFromNodes(slicename, slice['node_ids'])
131         finally:
132             if peer:
133                 api.driver.BindObjectToPeer('slice', slice['slice_id'], peer, slice['peer_slice_id'])
134         return 1
135     
136     def ListSlices(self, api, creds, options):
137         call_id = options.get('call_id')
138         if Callids().already_handled(call_id): return []
139         # look in cache first
140         if self.caching and api.cache:
141             slices = api.cache.get('slices')
142             if slices:
143                 return slices
144     
145         # get data from db 
146         slices = api.driver.GetSlices({'peer_id': None}, ['name'])
147         slice_hrns = [slicename_to_hrn(api.hrn, slice['name']) for slice in slices]
148         slice_urns = [hrn_to_urn(slice_hrn, 'slice') for slice_hrn in slice_hrns]
149     
150         # cache the result
151         if self.caching and api.cache:
152             api.cache.add('slices', slice_urns) 
153     
154         return slice_urns
155         
156     def ListResources(self, api, creds, options):
157         call_id = options.get('call_id')
158         if Callids().already_handled(call_id): return ""
159         # get slice's hrn from options
160         xrn = options.get('geni_slice_urn', None)
161         cached = options.get('cached', True) 
162         (hrn, _) = urn_to_hrn(xrn)
163     
164         version_manager = VersionManager()
165         # get the rspec's return format from options
166         rspec_version = version_manager.get_version(options.get('geni_rspec_version'))
167         version_string = "rspec_%s" % (rspec_version)
168     
169         #panos adding the info option to the caching key (can be improved)
170         if options.get('info'):
171             version_string = version_string + "_"+options.get('info', 'default')
172     
173         # look in cache first
174         if self.caching and api.cache and not xrn and cached:
175             rspec = api.cache.get(version_string)
176             if rspec:
177                 api.logger.info("aggregate.ListResources: returning cached value for hrn %s"%hrn)
178                 return rspec 
179     
180         #panos: passing user-defined options
181         #print "manager options = ",options
182         aggregate = PlAggregate(self.driver)
183         rspec =  aggregate.get_rspec(slice_xrn=xrn, version=rspec_version, options=options)
184     
185         # cache the result
186         if self.caching and api.cache and not xrn:
187             api.cache.add(version_string, rspec)
188     
189         return rspec
190     
191     
192     def GetTicket(self, api, xrn, creds, rspec, users, options):
193     
194         (slice_hrn, _) = urn_to_hrn(xrn)
195         slices = PlSlices(self.driver)
196         peer = slices.get_peer(slice_hrn)
197         sfa_peer = slices.get_sfa_peer(slice_hrn)
198     
199         # get the slice record
200         credential = api.getCredential()
201         interface = api.registries[api.hrn]
202         registry = api.server_proxy(interface, credential)
203         records = registry.Resolve(xrn, credential)
204     
205         # make sure we get a local slice record
206         record = None
207         for tmp_record in records:
208             if tmp_record['type'] == 'slice' and \
209                not tmp_record['peer_authority']:
210     #Error (E0602, GetTicket): Undefined variable 'SliceRecord'
211                 record = SliceRecord(dict=tmp_record)
212         if not record:
213             raise RecordNotFound(slice_hrn)
214         
215         # similar to CreateSliver, we must verify that the required records exist
216         # at this aggregate before we can issue a ticket
217         # parse rspec
218         rspec = RSpec(rspec_string)
219         requested_attributes = rspec.version.get_slice_attributes()
220     
221         # ensure site record exists
222         site = slices.verify_site(hrn, slice_record, peer, sfa_peer)
223         # ensure slice record exists
224         slice = slices.verify_slice(hrn, slice_record, peer, sfa_peer)
225         # ensure person records exists
226         persons = slices.verify_persons(hrn, slice, users, peer, sfa_peer)
227         # ensure slice attributes exists
228         slices.verify_slice_attributes(slice, requested_attributes)
229         
230         # get sliver info
231         slivers = slices.get_slivers(slice_hrn)
232     
233         if not slivers:
234             raise SliverDoesNotExist(slice_hrn)
235     
236         # get initscripts
237         initscripts = []
238         data = {
239             'timestamp': int(time.time()),
240             'initscripts': initscripts,
241             'slivers': slivers
242         }
243     
244         # create the ticket
245         object_gid = record.get_gid_object()
246         new_ticket = SfaTicket(subject = object_gid.get_subject())
247         new_ticket.set_gid_caller(api.auth.client_gid)
248         new_ticket.set_gid_object(object_gid)
249         new_ticket.set_issuer(key=api.key, subject=api.hrn)
250         new_ticket.set_pubkey(object_gid.get_pubkey())
251         new_ticket.set_attributes(data)
252         new_ticket.set_rspec(rspec)
253         #new_ticket.set_parent(api.auth.hierarchy.get_auth_ticket(auth_hrn))
254         new_ticket.encode()
255         new_ticket.sign()
256     
257         return new_ticket.save_to_string(save_parents=True)