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