Feature 10955: Osmclient changes related to VIM configuration with a Prometheus TSDB...
[osm/osmclient.git] / osmclient / sol005 / vim.py
1 # Copyright 2018 Telefonica
2 #
3 # All Rights Reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16
17 """
18 OSM vim API handling
19 """
20
21 from osmclient.common import utils
22 from osmclient.common import wait as WaitForStatus
23 from osmclient.common.exceptions import ClientException
24 from osmclient.common.exceptions import NotFound
25 import yaml
26 import json
27 import logging
28
29
30 class Vim(object):
31 def __init__(self, http=None, client=None):
32 self._http = http
33 self._client = client
34 self._logger = logging.getLogger("osmclient")
35 self._apiName = "/admin"
36 self._apiVersion = "/v1"
37 self._apiResource = "/vim_accounts"
38 self._apiBase = "{}{}{}".format(
39 self._apiName, self._apiVersion, self._apiResource
40 )
41
42 # VIM '--wait' option
43 def _wait(self, id, wait_time, deleteFlag=False):
44 self._logger.debug("")
45 self._client.get_token()
46 # Endpoint to get operation status
47 apiUrlStatus = "{}{}{}".format(self._apiName, self._apiVersion, "/vim_accounts")
48 # Wait for status for VIM instance creation/deletion
49 if isinstance(wait_time, bool):
50 wait_time = WaitForStatus.TIMEOUT_VIM_OPERATION
51 WaitForStatus.wait_for_status(
52 "VIM",
53 str(id),
54 wait_time,
55 apiUrlStatus,
56 self._http.get2_cmd,
57 deleteFlag=deleteFlag,
58 )
59
60 def _get_id_for_wait(self, name):
61 """Returns id of name, or the id itself if given as argument"""
62 self._logger.debug("")
63 self._client.get_token()
64 for vim in self.list():
65 if name == vim["uuid"]:
66 return vim["uuid"]
67 for vim in self.list():
68 if name == vim["name"]:
69 return vim["uuid"]
70 return ""
71
72 def create(
73 self,
74 name,
75 vim_access,
76 config={},
77 sdn_controller=None,
78 sdn_port_mapping=None,
79 wait=False,
80 ):
81 vca_id = None
82
83 def get_vca_id(vca):
84 vca = self._client.vca.get(vca)
85 if vca is None:
86 raise NotFound("cannot find vca '{}'".format(vca))
87 return vca["_id"]
88
89 self._logger.debug("")
90 self._client.get_token()
91 if "vca" in vim_access:
92 vca_id = get_vca_id(vim_access["vca"])
93 if "vim-type" not in vim_access:
94 # 'openstack' not in vim_access['vim-type']):
95 raise Exception("vim type not provided")
96 vim_account = {}
97 vim_account["name"] = name
98 vim_account = self.update_vim_account_dict(vim_account, vim_access)
99 if vca_id:
100 vim_account["vca"] = vca_id
101 vim_config = config
102 if sdn_controller:
103 sdnc = self._client.sdnc.get(sdn_controller)
104 vim_config["sdn-controller"] = sdnc["_id"]
105 if sdn_port_mapping:
106 with open(sdn_port_mapping, "r") as f:
107 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read())
108 if vim_config:
109 vim_account["config"] = vim_config
110 # vim_account['config'] = json.dumps(vim_config)
111 http_code, resp = self._http.post_cmd(
112 endpoint=self._apiBase, postfields_dict=vim_account
113 )
114 # print('HTTP CODE: {}'.format(http_code))
115 # print('RESP: {}'.format(resp))
116 # if http_code in (200, 201, 202, 204):
117 if resp:
118 resp = json.loads(resp)
119 if not resp or "id" not in resp:
120 raise ClientException("unexpected response from server - {}".format(resp))
121 if wait:
122 # Wait for status for VIM instance creation
123 self._wait(resp.get("id"), wait)
124 print(resp["id"])
125 # else:
126 # msg = ""
127 # if resp:
128 # try:
129 # msg = json.loads(resp)
130 # except ValueError:
131 # msg = resp
132 # raise ClientException("failed to create vim {} - {}".format(name, msg))
133
134 def update(
135 self,
136 vim_name,
137 vim_account,
138 config,
139 sdn_controller,
140 sdn_port_mapping,
141 wait=False,
142 ):
143 self._logger.debug("")
144 self._client.get_token()
145 vim = self.get(vim_name)
146 vim_id_for_wait = self._get_id_for_wait(vim_name)
147 vim_config = {}
148 if config is not None:
149 if not config and (sdn_controller or sdn_port_mapping):
150 # If config is empty (clearing config)
151 raise ClientException(
152 "clearing config is incompatible with updating SDN info"
153 )
154 vim_config = config
155 if sdn_controller == "":
156 vim_config["sdn-controller"] = None
157 vim_config["sdn-port-mapping"] = None
158 else:
159 if sdn_controller:
160 sdnc = self._client.sdnc.get(sdn_controller)
161 vim_config["sdn-controller"] = sdnc["_id"]
162 if sdn_port_mapping:
163 with open(sdn_port_mapping, "r") as f:
164 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read())
165 vim_account["config"] = vim_config
166 # vim_account['config'] = json.dumps(vim_config)
167 http_code, resp = self._http.patch_cmd(
168 endpoint="{}/{}".format(self._apiBase, vim["_id"]),
169 postfields_dict=vim_account,
170 )
171 # print('HTTP CODE: {}'.format(http_code))
172 # print('RESP: {}'.format(resp))
173 # if http_code in (200, 201, 202, 204):
174 if wait:
175 # In this case, 'resp' always returns None, so 'resp['id']' cannot be used.
176 # Use the previously obtained id instead.
177 wait_id = vim_id_for_wait
178 # Wait for status for VI instance update
179 self._wait(wait_id, wait)
180 # else:
181 # pass
182 # else:
183 # msg = ""
184 # if resp:
185 # try:
186 # msg = json.loads(resp)
187 # except ValueError:
188 # msg = resp
189 # raise ClientException("failed to update vim {} - {}".format(vim_name, msg))
190
191 def update_vim_account_dict(self, vim_account, vim_access):
192 self._logger.debug("")
193 vim_account["vim_type"] = vim_access["vim-type"]
194 vim_account["description"] = vim_access["description"]
195 vim_account["vim_url"] = vim_access["vim-url"] or "null"
196 vim_account["vim_user"] = vim_access["vim-username"] or "null"
197 vim_account["vim_password"] = vim_access["vim-password"] or "null"
198 vim_account["vim_tenant_name"] = vim_access["vim-tenant-name"] or "null"
199 if "prometheus-config" in vim_access:
200 vim_account["prometheus_config"] = vim_access["prometheus-config"]
201 return vim_account
202
203 def get_id(self, name):
204 """Returns a VIM id from a VIM name"""
205 self._logger.debug("")
206 for vim in self.list():
207 if name == vim["name"]:
208 return vim["uuid"]
209 raise NotFound("vim {} not found".format(name))
210
211 def delete(self, vim_name, force=False, wait=False):
212 self._logger.debug("")
213 self._client.get_token()
214 vim_id = vim_name
215 if not utils.validate_uuid4(vim_name):
216 vim_id = self.get_id(vim_name)
217 querystring = ""
218 if force:
219 querystring = "?FORCE=True"
220 http_code, resp = self._http.delete_cmd(
221 "{}/{}{}".format(self._apiBase, vim_id, querystring)
222 )
223 # print('HTTP CODE: {}'.format(http_code))
224 # print('RESP: {}'.format(resp))
225 if http_code == 202:
226 if wait:
227 # When deleting an account, 'resp' may be None.
228 # In such a case, the 'id' from 'resp' cannot be used, so use 'vim_id' instead
229 wait_id = vim_id
230 if resp:
231 resp = json.loads(resp)
232 wait_id = resp.get("id")
233 # Wait for status for VIM account deletion
234 self._wait(wait_id, wait, deleteFlag=True)
235 else:
236 print("Deletion in progress")
237 elif http_code == 204:
238 print("Deleted")
239 else:
240 msg = resp or ""
241 # if resp:
242 # try:
243 # msg = json.loads(resp)
244 # except ValueError:
245 # msg = resp
246 raise ClientException("failed to delete vim {} - {}".format(vim_name, msg))
247
248 def list(self, filter=None):
249 """Returns a list of VIM accounts"""
250 self._logger.debug("")
251 self._client.get_token()
252 filter_string = ""
253 if filter:
254 filter_string = "?{}".format(filter)
255 _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string))
256 if not resp:
257 return list()
258 vim_accounts = json.loads(resp)
259 for datacenter in vim_accounts:
260 datacenter["uuid"] = datacenter.get("_id") # backward compatibility?
261 return vim_accounts
262
263 def get(self, name):
264 """Returns a VIM account based on name or id"""
265 self._logger.debug("")
266 self._client.get_token()
267 vim_id = name
268 if not utils.validate_uuid4(name):
269 vim_id = self.get_id(name)
270 try:
271 _, resp = self._http.get2_cmd("{}/{}".format(self._apiBase, vim_id))
272 if resp:
273 resp = json.loads(resp)
274 if not resp or "_id" not in resp:
275 raise ClientException("failed to get vim info: {}".format(resp))
276 return resp
277 except NotFound:
278 raise NotFound("vim '{}' not found".format(name))