refactored sfalogging to be less awkward and more reliable
[sfa.git] / sfa / managers / aggregate_manager.py
1 # pylint: disable=c0111, c0103, r0201
2
3 from sfa.rspecs.version_manager import VersionManager
4 from sfa.util.version import version_core
5 from sfa.util.xrn import Xrn
6 from sfa.util.callids import Callids
7 from sfa.util.sfalogging import logger
8 from sfa.util.faults import SfaInvalidArgument, InvalidRSpecVersion
9 from sfa.server.api_versions import ApiVersions
10
11
12 class AggregateManager:
13
14     def __init__(self, config):
15         pass
16
17     # essentially a union of the core version, the generic version (this code) and
18     # whatever the driver needs to expose
19
20     def rspec_versions(self):
21         version_manager = VersionManager()
22         ad_rspec_versions = []
23         request_rspec_versions = []
24         for rspec_version in version_manager.versions:
25             # avoid publishing non-relevant entries
26             # but stay safe however
27             try:
28                 if not rspec_version.extensions \
29                   and not rspec_version.namespace \
30                   and not rspec_version.schema:
31                     continue
32             except Exception as exc:
33                 pass
34             if rspec_version.content_type in ['*', 'ad']:
35                 ad_rspec_versions.append(rspec_version.to_dict())
36             if rspec_version.content_type in ['*', 'request']:
37                 request_rspec_versions.append(rspec_version.to_dict())
38         return {
39             'geni_request_rspec_versions': request_rspec_versions,
40             'geni_ad_rspec_versions': ad_rspec_versions,
41         }
42
43     def get_rspec_version_string(self, rspec_version, options=None):
44         if options is None:
45             options = {}
46         version_string = "rspec_%s" % (rspec_version)
47
48         # panos adding the info option to the caching key (can be improved)
49         if options.get('info'):
50             version_string = version_string + \
51                 "_" + options.get('info', 'default')
52
53         # Adding the list_leases option to the caching key
54         if options.get('list_leases'):
55             version_string = version_string + "_" + \
56                 options.get('list_leases', 'default')
57
58         # Adding geni_available to caching key
59         if options.get('geni_available'):
60             version_string = version_string + "_" + \
61                 str(options.get('geni_available'))
62
63         return version_string
64
65     def GetVersion(self, api, options):
66         xrn = Xrn(api.hrn, type='authority+am')
67         version = version_core()
68         cred_types = [{'geni_type': 'geni_sfa',
69                        'geni_version': str(i)} for i in range(4)[-2:]]
70         geni_api_versions = ApiVersions().get_versions()
71         geni_api_versions['3'] = \
72             'https://%s:%s' % (api.config.sfa_aggregate_host, api.config.sfa_aggregate_port)
73         version_generic = {
74             'testbed': api.driver.testbed_name(),
75             'interface': 'aggregate',
76             'sfa': 3,
77             'hrn': xrn.get_hrn(),
78             'urn': xrn.get_urn(),
79             'geni_api': 3,
80             'geni_api_versions': geni_api_versions,
81             # Accept operations that act on as subset of slivers in a given
82             # state.
83             'geni_single_allocation': 0,
84             # Multiple slivers can exist and be incrementally added, including
85             # those which connect or overlap in some way.
86             'geni_allocate': 'geni_many',
87             'geni_credential_types': cred_types,
88             'geni_handles_speaksfor': True,     # supports 'speaks for' credentials
89         }
90         version.update(version_generic)
91         version.update(self.rspec_versions())
92         testbed_version = api.driver.aggregate_version()
93         version.update(testbed_version)
94         return version
95
96     def ListResources(self, api, creds, options):
97         call_id = options.get('call_id')
98         if Callids().already_handled(call_id):
99             return ""
100
101         # get the rspec's return format from options
102         version_manager = VersionManager()
103         rspec_version = version_manager.get_version(
104             options.get('geni_rspec_version'))
105         version_string = self.get_rspec_version_string(rspec_version, options)
106
107         # look in cache first
108         cached_requested = options.get('cached', True)
109         if cached_requested and api.driver.cache:
110             rspec = api.driver.cache.get(version_string)
111             if rspec:
112                 logger.debug("%s.ListResources returning cached advertisement" % (
113                     api.driver.__module__))
114                 return rspec
115
116         rspec = api.driver.list_resources(rspec_version, options)
117         if api.driver.cache:
118             logger.debug("%s.ListResources stores advertisement in cache" % (
119                 api.driver.__module__))
120             api.driver.cache.add(version_string, rspec)
121         return rspec
122
123     def Describe(self, api, creds, urns, options):
124         call_id = options.get('call_id')
125         if Callids().already_handled(call_id):
126             return ""
127
128         version_manager = VersionManager()
129         rspec_version = version_manager.get_version(
130             options.get('geni_rspec_version'))
131         return api.driver.describe(urns, rspec_version, options)
132
133     def Status(self, api, urns, creds, options):
134         call_id = options.get('call_id')
135         if Callids().already_handled(call_id):
136             return {}
137         return api.driver.status(urns, options=options)
138
139     def Allocate(self, api, xrn, creds, rspec_string, expiration, options):
140         """
141         Allocate resources as described in a request RSpec argument
142         to a slice with the named URN.
143         """
144         call_id = options.get('call_id')
145         if Callids().already_handled(call_id):
146             return ""
147         return api.driver.allocate(xrn, rspec_string, expiration, options)
148
149     def Provision(self, api, xrns, creds, options):
150         """
151         Create the sliver[s] (slice) at this aggregate.
152         Verify HRN and initialize the slice record in PLC if necessary.
153         """
154         call_id = options.get('call_id')
155         if Callids().already_handled(call_id):
156             return ""
157
158         # make sure geni_rspec_version is specified in options
159         if 'geni_rspec_version' not in options:
160             msg = 'geni_rspec_version is required and must be set in options struct'
161             raise SfaInvalidArgument(msg, 'geni_rspec_version')
162         # make sure we support the requested rspec version
163         version_manager = VersionManager()
164         rspec_version = version_manager.get_version(
165             options['geni_rspec_version'])
166         if not rspec_version:
167             raise InvalidRSpecVersion(options['geni_rspec_version'])
168
169         return api.driver.provision(xrns, options)
170
171     def Delete(self, api, xrns, creds, options):
172         call_id = options.get('call_id')
173         if Callids().already_handled(call_id):
174             return True
175         return api.driver.delete(xrns, options)
176
177     def Renew(self, api, xrns, creds, expiration_time, options):
178         call_id = options.get('call_id')
179         if Callids().already_handled(call_id):
180             return True
181
182         return api.driver.renew(xrns, expiration_time, options)
183
184     def PerformOperationalAction(self, api, xrns, creds, action, options=None):
185         if options is None:
186             options = {}
187         call_id = options.get('call_id')
188         if Callids().already_handled(call_id):
189             return True
190         return api.driver.perform_operational_action(xrns, action, options)
191
192     def Shutdown(self, api, xrn, creds, options=None):
193         if options is None:
194             options = {}
195         call_id = options.get('call_id')
196         if Callids().already_handled(call_id):
197             return True
198         return api.driver.shutdown(xrn, options)