getAutorities is now using rest/sfa_api avoiding cache pb in Manifold
[myslice.git] / rest / sfa_api.py
1 import os
2 import json
3 import ConfigParser 
4 import datetime
5 from time                       import mktime
6 import xmltodict
7
8 from django.shortcuts           import render_to_response
9 from django.http                import HttpResponse
10
11 from sfa.trust.certificate      import Keypair, Certificate
12 from sfa.client.sfaserverproxy  import SfaServerProxy
13 from sfa.client.return_value    import ReturnValue
14 from sfa.util.xrn               import Xrn, get_leaf, get_authority, hrn_to_urn, urn_to_hrn
15
16 from manifold.core.query        import Query
17 from manifold.models            import db
18 from manifold.models.platform   import Platform
19 from manifold.models.user       import User
20
21 from unfold.loginrequired       import LoginRequiredView
22
23 from myslice.settings           import logger, config
24
25 from rest.json_encoder          import MyEncoder
26
27 def dispatch(request, method):
28
29     hrn = ''
30     urn = ''
31     object_type = ''
32     rspec = ''
33     recursive = False
34     options   = dict()
35     platforms = list()
36
37     results = dict()
38     display = None
39
40     if request.method == 'POST':
41         req_items = request.POST
42     elif request.method == 'GET':
43         req_items = request.GET
44
45     for el in req_items.items():
46         if el[0].startswith('rspec'):
47             rspec += el[1]
48         elif el[0].startswith('platform'):
49             platforms += req_items.getlist('platform[]')
50         #elif el[0].startswith('options'):
51         #    options += req_items.getlist('options[]')
52         elif el[0].startswith('hrn'):
53             hrn = el[1]
54         elif el[0].startswith('urn'):
55             urn = el[1]
56         elif el[0].startswith('type'):
57             object_type = el[1]
58         elif el[0].startswith('recursive'):
59             if el[1] == '1':
60                 recursive = True
61             else:
62                 recursive = False
63         elif el[0].startswith('display'):
64             display = el[1]
65
66     results = sfa_client(request, method, hrn, urn, object_type, recursive, options, platforms)
67
68     if display == 'table':
69         return render_to_response('table-default.html', {'data' : data, 'fields' : columns, 'id' : '@component_id', 'options' : None})
70     else:
71         return HttpResponse(json.dumps(results, cls=MyEncoder), content_type="application/json")
72
73 def get_user_account(user_email, platform_name):
74     """
75     Returns the user configuration for a given platform.
76     This function does not resolve references.
77     """
78     user = db.query(User).filter(User.email == user_email).one()
79     platform = db.query(Platform).filter(Platform.platform == platform_name).one()
80     accounts = [a for a in user.accounts if a.platform == platform]
81     if not accounts:
82         raise Exception, "this account does not exist"
83
84     if accounts[0].auth_type == 'reference':
85         pf = json.loads(accounts[0].config)['reference_platform']
86         return get_user_account(user_email, pf)
87
88     return accounts[0]
89
90 def sfa_client(request, method, hrn=None, urn=None, object_type=None, rspec=None, recursive=None, options=None, platforms=None, admin=False):
91
92     Config = ConfigParser.ConfigParser()
93     Config.read(os.getcwd() + "/myslice/monitor.ini")
94
95     if admin:
96         user_email, admin_password = config.manifold_admin_user_password()
97     else:
98         #logger.debug(request.session['user']['email'])
99         user_email = request.session['user']['email']
100
101     results = dict()
102
103     if hrn is None:
104         hrn = ''
105     if urn is None:
106         urn = ''
107     if object_type is None:
108         object_type = ''
109     if rspec is None:
110         rspec = ''
111     if recursive is None:
112         recursive = False
113     if options is None:
114         options  = dict()
115     if platforms is None:
116         platforms = list()
117
118     if method not in ['GetVersion','ListResources']:
119         try:
120             if not hrn:
121                 hrn = urn_to_hrn(urn)
122             else:
123                 urn = hrn_to_urn(hrn, object_type) 
124         except Exception,e:
125             logger.error(e)
126             raise Exception, "Provide urn OR hrn + type as parameters of method %s" % method
127
128     if len(platforms)==0:
129         platforms = get_platforms()
130         #platforms.append('myslice')
131     #results = {'method':method,'platforms':platforms,'rspec':rspec,'options':options}
132
133     result = []
134     dict_result = {}
135     data = []
136     columns = []
137     api_options = {}
138     api_options['geni_rspec_version'] = {'type': 'GENI', 'version': '3'}
139     api_options['list_leases'] = 'all'
140     server_am = False
141     from manifoldapi.manifoldapi    import execute_admin_query
142     for pf in platforms:
143         platform = get_platform_config(pf)
144         logger.debug("platform={}".format(platform))
145         if 'sm' in platform and len(platform['sm']) > 0:
146             logger.debug('sm')
147             server_am = True
148             server_url = platform['sm']
149         if 'rm' in platform and len(platform['rm']) > 0:
150             logger.debug('rm')
151             server_am = False
152             server_url = platform['rm']
153         if 'registry' in platform and len(platform['registry']) > 0:
154             logger.debug('registry')
155             server_am = False
156             server_url = platform['registry']
157     
158         if not Config.has_option('monitor', 'cert') :
159              return HttpResponse(json.dumps({'error' : '-1'}), content_type="application/json")
160
161         cert = os.path.abspath(Config.get('monitor', 'cert'))
162         if not os.path.isfile(cert) :
163              return HttpResponse(json.dumps({'error' : '-1'}), content_type="application/json")
164
165         if not Config.has_option('monitor', 'pkey') :
166              return HttpResponse(json.dumps({'error' : '-2'}), content_type="application/json")
167
168         pkey = os.path.abspath(Config.get('monitor', 'pkey'))
169         if not os.path.isfile(pkey) :
170              return HttpResponse(json.dumps({'error' : '-2'}), content_type="application/json")
171  
172         server = SfaServerProxy(server_url, pkey, cert)
173
174         try:
175             # Get user config from Manifold
176             user_config = get_user_config(user_email, pf)
177             if 'delegated_user_credential' in user_config:
178                 user_cred = user_config['delegated_user_credential']
179             elif 'user_credential' in user_config:
180                 user_cred = user_config['user_credential']
181             else:
182                 user_cred = {}
183
184             if object_type:
185                 if 'delegated_%s_credentials'%object_type in user_config:
186                     for obj_name, cred in user_config['delegated_%s_credentials'%object_type].items():
187                         if obj_name == hrn:
188                             object_cred = cred
189                 elif '%s_credentials'%object_type in user_config:
190                     for obj_name, cred in user_config['%s_credentials'%object_type].items():
191                         if obj_name == hrn:
192                             object_cred = cred
193
194             # Both AM & Registry
195             if method == "GetVersion": 
196                 result = server.GetVersion()
197             else:
198                 # AM API Calls
199                 if server_am:
200                     if method == "ListResources":
201                         result = server.ListResources([user_cred], api_options)
202                         dict_result = xmltodict.parse(result['value'])
203                         result['json'] = json.dumps(dict_result)
204                         if isinstance(dict_result['rspec']['node'], list):
205                             columns.extend(dict_result['rspec']['node'][0].keys())
206                         else:
207                             columns.extend(dict_result['rspec']['node'].keys())
208
209                     elif method == "Describe":
210                         version = server.GetVersion()
211                         logger.debug(version['geni_api'])
212                         # if GetVersion = v2
213                         if version['geni_api'] == 2:
214                             # ListResources(slice_hrn)
215                             api_options['geni_slice_urn'] = urn
216                             result = server.ListResources([object_cred], api_options)
217                             dict_result = xmltodict.parse(result['value'])
218                         # else GetVersion = v3
219                         else:
220                             result = server.Describe([urn] ,[object_cred], api_options)
221                             dict_result = xmltodict.parse(result['value']['geni_rspec'])
222
223                         result['json'] = json.dumps(dict_result)
224                         if isinstance(dict_result['rspec']['node'], list):
225                             columns.extend(dict_result['rspec']['node'][0].keys())
226                         else:
227                             columns.extend(dict_result['rspec']['node'].keys())
228
229                     elif method == 'Renew':
230                         # Renew till 1 month from now
231                         d = datetime.datetime.utcnow() + datetime.timedelta(365/12)
232                         date = d.isoformat("T") + "Z"
233                         result = server.Renew([urn] ,[object_cred], date, api_options)
234                     elif method == 'Delete':
235                         result = server.Delete([urn] ,[object_cred], api_options)
236                     elif method == 'Allocate':
237                         # if GetVersion = v2
238                         # CreateSliver(slice_hrn)
239                         # else GetVersion = v3
240                         api_options['call_id']    = unique_call_id()
241                         # List of users comes from the Registry
242                         api_options['sfa_users']  = sfa_users
243                         api_options['geni_users'] = geni_users
244                         result = server.Allocate([urn] ,[object_cred], rspec, api_options)
245                     elif method == 'Provision':
246                         # if GetVersion = v2
247                         # Nothing it is not supported by v2 AMs
248                         api_options['call_id']    = unique_call_id()
249                         # List of users comes from the Registry
250                         api_options['sfa_users']  = sfa_users
251                         api_options['geni_users'] = geni_users
252                         result = server.Provision([urn] ,[object_cred], api_options)
253                     elif method == 'Status':
254                         result = server.Status([urn] ,[object_cred], api_options)
255                     elif method == 'PerformOperationalAction':
256                         # if GetVersion = v2
257                         # Nothing it is not supported by v2 AMs
258                         result = server.PerformOperationalAction([urn] ,[object_cred], action, api_options)
259                     elif method == 'Shutdown':
260                         result = server.Shutdown(urn ,[object_cred], api_options)
261                     else:
262                         #return HttpResponse(json.dumps({'error' : '-3','msg':'method not supported by AM'}), content_type="application/json")
263                         logger.debug('method %s not handled by AM' % method)
264                         result = []
265
266                 # Registry API Calls 
267                 else:
268                     record_dict = {'urn': urn, 'hrn': hrn, 'type': object_type}
269                     if method == "List":
270                         # hrn is required
271                         api_options['recursive'] = recursive
272                         result = server.List(hrn, user_cred, api_options)
273                         if object_type:
274                             result = filter_records(object_type, result)
275                     elif method == "Resolve":
276                         # hrn is required
277                         # details can be True or False
278                         api_options['details']=True
279                         result = server.Resolve(hrn, user_cred, api_options)
280                         if object_type:
281                             result = filter_records(object_type, result)
282                     elif method == "Register":
283                         # record_dict must be crafted
284                         # auth_cred must be selected in the list of auth_creds from user's account
285                         result = server.Register(record_dict, auth_cred)
286                     elif method == "Update":
287                         # record_dict must be crafted
288                         # object_cred must be selected in the list of creds for the object type
289                         # from user's account
290                         result = server.Update(record_dict, object_cred)
291                     elif method == "Remove":
292                         # hrn is required
293                         # auth_cred must be selected in the list of auth_creds from user's account
294                         # object_type is required
295                         result = server.Remove(hrn, auth_cred, object_type)
296                     else:
297                         #return HttpResponse(json.dumps({'error' : '-3','msg':'method not supported by Registry'}), content_type="application/json")
298                         logger.debug('method %s not handled by Registry' % method)
299                         result = []
300
301             results[pf] = result
302             if dict_result:
303                 if isinstance(dict_result['rspec']['node'], list):
304                     data = data + dict_result['rspec']['node']
305                 else:
306                     data.append(dict_result['rspec']['node'])
307         except Exception,e:
308             import traceback
309             logger.error(traceback.format_exc())
310             logger.error(e)
311             results[pf] = {'error':'-3', 'error_msg': str(e)}
312
313     results['columns'] = columns
314     return results
315
316 def get_user_config(user_email, platform_name):
317     account = get_user_account(user_email, platform_name)
318     return json.loads(account.config) if account.config else {}
319
320 def get_platforms():
321     ret = list()
322     platforms = db.query(Platform).filter(Platform.gateway_type == 'sfa', Platform.disabled == 0).all()
323     for p in platforms:
324         ret.append(p.platform)
325     return ret
326
327
328 def get_platform_config(platform_name):
329     platform = db.query(Platform).filter(Platform.platform == platform_name).one()
330     return json.loads(platform.config) if platform.config else {}
331
332 def filter_records(type, records):
333     filtered_records = []
334     for record in records:
335         if (record['type'] == type) or (type == "all"):
336             filtered_records.append(record)
337     return filtered_records