1 # Copyright (c) 2018 Amdocs
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 from keystoneauth1.identity import v2 as keystone_v2
17 from keystoneauth1.identity import v3 as keystone_v3
18 from keystoneauth1 import session
20 from pecan import rest
23 from azure.api_v2.api_definition import utils
24 from azure.pub import exceptions
25 from azure.pub.msapi import extsys
28 OBJ_IN_ARRAY = "(\w+)\[(\d+)\]\.(\w+)"
31 def _get_vim_auth_session(vim_id, tenant_id):
32 """ Get the auth session to the given backend VIM """
35 vim = extsys.get_vim_by_id(vim_id)
36 except exceptions.VimDriverAzureException as e:
37 return pecan.abort(500, str(e))
40 "auth_url": vim["url"],
41 "username": vim["userName"],
42 "password": vim["password"],
44 params["tenant_id"] = tenant_id
46 if '/v2' in params["auth_url"]:
47 auth = keystone_v2.Password(**params)
49 params["user_domain_name"] = vim["domain"]
50 params["project_domain_name"] = vim["domain"]
52 if 'tenant_id' in params:
53 params["project_id"] = params.pop("tenant_id")
54 if 'tenant_name' in params:
55 params["project_name"] = params.pop("tenant_name")
56 if '/v3' not in params["auth_url"]:
57 params["auth_url"] = params["auth_url"] + "/v3",
58 auth = keystone_v3.Password(**params)
60 return session.Session(auth=auth)
63 def _convert_default_value(default):
64 return {"None": None, "true": True, "false": False}[default]
67 def _property_exists(resource, attr, required=False):
68 if attr not in resource:
70 raise Exception("Required field %s is missed in VIM "
71 "resource %s", (attr, resource))
78 def _convert_vim_res_to_mc_res(vim_resource, res_properties):
80 for key in res_properties:
81 vim_res, attr = res_properties[key]["source"].split('.', 1)
82 # action = res_properties[key].get("action", "copy")
83 if re.match(OBJ_IN_ARRAY, attr):
84 attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups()
85 if _property_exists(vim_resource[vim_res], attr):
87 vim_resource[vim_res][attr][int(index)][sub_attr])
89 if _property_exists(vim_resource[vim_res], attr,
90 res_properties[key].get("required")):
91 mc_resource[key] = vim_resource[vim_res][attr]
93 if "default" in res_properties[key]:
94 mc_resource[key] = _convert_default_value(
95 res_properties[key]["default"])
100 def _convert_mc_res_to_vim_res(mc_resource, res_properties):
102 for key in res_properties:
103 vim_res, attr = res_properties[key]["source"].split('.', 1)
104 # action = res_properties[key].get("action", "copy")
105 if re.match(OBJ_IN_ARRAY, attr):
106 attr, index, sub_attr = re.match(OBJ_IN_ARRAY, attr).groups()
107 if _property_exists(mc_resource, key):
108 vim_resource[attr] = vim_resource.get(attr, [])
109 if vim_resource[attr]:
110 vim_resource[attr][0].update({sub_attr: mc_resource[key]})
112 vim_resource[attr].append({sub_attr: mc_resource[key]})
114 if _property_exists(mc_resource, key,
115 res_properties[key].get("required")):
116 vim_resource[attr] = mc_resource[key]
121 def _build_api_controller(api_meta):
122 # Assume that only one path
123 path, path_meta = api_meta['paths'].items()[0]
124 # url path is behind third slash. The first is vimid, the second is
126 path = path.split("/")[3]
127 controller_name = path.upper() + "Controller"
128 delimiter = path_meta["vim_path"].find("/", 1)
129 service_type = path_meta["vim_path"][1:delimiter]
130 resource_url = path_meta["vim_path"][delimiter:]
132 # Assume there is only one resource.
133 name, resource_meta = api_meta['definitions'].items()[0]
134 resource_properties = resource_meta['properties']
137 if "get" in path_meta:
138 # Add the get method to controller.
139 @pecan.expose("json")
140 def _get(self, vim_id, tenant_id, resource_id):
142 session = _get_vim_auth_session(vim_id, tenant_id)
143 service = {'service_type': service_type,
144 'interface': 'public'}
145 full_url = resource_url + "/%s" % resource_id
146 resp = session.get(full_url, endpoint_filter=service)
147 mc_res = _convert_vim_res_to_mc_res(resp.json(),
149 mc_res.update({"vimName": vim_id,
151 "tenantId": tenant_id,
155 controller_meta["get"] = _get
157 if "get_all" in path_meta:
158 # Add the get_all method to controller.
159 @pecan.expose("json")
160 def _get_all(self, vim_id, tenant_id):
161 """ General GET all """
162 session = _get_vim_auth_session(vim_id, tenant_id)
163 service = {'service_type': service_type,
164 'interface': 'public'}
165 resp = session.get(resource_url, endpoint_filter=service)
166 vim_res = resp.json()[resource_meta['plural_vim_resource']]
167 mc_res = [_convert_vim_res_to_mc_res(
168 {resource_meta['vim_resource']: v},
171 return {"vimName": vim_id,
172 resource_meta['plural']: mc_res,
173 "tenantId": tenant_id,
176 controller_meta["get_all"] = _get_all
178 if "post" in path_meta:
179 # Add the post method to controller.
180 @pecan.expose("json")
181 def _post(self, vim_id, tenant_id):
183 session = _get_vim_auth_session(vim_id, tenant_id)
184 service = {'service_type': service_type,
185 'interface': 'public'}
186 vim_res = _convert_mc_res_to_vim_res(pecan.request.json_body,
189 req_body = json.JSONEncoder().encode(
190 {resource_meta['vim_resource']: vim_res})
191 resp = session.post(resource_url,
193 endpoint_filter=service)
194 mc_res = _convert_vim_res_to_mc_res(resp.json(),
196 mc_res.update({"vimName": vim_id,
198 "tenantId": tenant_id,
202 controller_meta["post"] = _post
204 if "delete" in path_meta:
205 # Add the delete method to controller.
206 @pecan.expose("json")
207 def _delete(self, vim_id, tenant_id, resource_id):
208 """ General DELETE """
209 session = _get_vim_auth_session(vim_id, tenant_id)
210 service = {'service_type': service_type,
211 'interface': 'public'}
212 full_url = resource_url + "/%s" % resource_id
213 session.delete(full_url, endpoint_filter=service)
215 controller_meta["delete"] = _delete
217 return path, type(controller_name, (rest.RestController,), controller_meta)
220 def insert_dynamic_controller(root_controller):
221 api_defs = utils.get_definition_list()
223 path, con_class = _build_api_controller(d)
224 setattr(root_controller, path, con_class())