Update vim-create and vim-update to accept config and credential files
[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, name, vim_access, config={}, sdn_controller=None, sdn_port_mapping=None, wait=False
74 ):
75 vca_id = None
76
77 def get_vca_id(vca):
78 vca = self._client.vca.get(vca)
79 if vca is None:
80 raise NotFound("cannot find vca '{}'".format(vca))
81 return vca["_id"]
82
83 self._logger.debug("")
84 self._client.get_token()
85 if "vca" in vim_access:
86 vca_id = get_vca_id(vim_access["vca"])
87 if "vim-type" not in vim_access:
88 # 'openstack' not in vim_access['vim-type']):
89 raise Exception("vim type not provided")
90 vim_account = {}
91 vim_account["name"] = name
92 vim_account = self.update_vim_account_dict(vim_account, vim_access)
93 if vca_id:
94 vim_account["vca"] = vca_id
95 vim_config = config
96 if sdn_controller:
97 sdnc = self._client.sdnc.get(sdn_controller)
98 vim_config["sdn-controller"] = sdnc["_id"]
99 if sdn_port_mapping:
100 with open(sdn_port_mapping, "r") as f:
101 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read())
102 if vim_config:
103 vim_account["config"] = vim_config
104 # vim_account['config'] = json.dumps(vim_config)
105
106 http_code, resp = self._http.post_cmd(
107 endpoint=self._apiBase, postfields_dict=vim_account
108 )
109 # print('HTTP CODE: {}'.format(http_code))
110 # print('RESP: {}'.format(resp))
111 # if http_code in (200, 201, 202, 204):
112 if resp:
113 resp = json.loads(resp)
114 if not resp or "id" not in resp:
115 raise ClientException("unexpected response from server - {}".format(resp))
116 if wait:
117 # Wait for status for VIM instance creation
118 self._wait(resp.get("id"), wait)
119 print(resp["id"])
120 # else:
121 # msg = ""
122 # if resp:
123 # try:
124 # msg = json.loads(resp)
125 # except ValueError:
126 # msg = resp
127 # raise ClientException("failed to create vim {} - {}".format(name, msg))
128
129 def update(
130 self, vim_name, vim_account, config, sdn_controller, sdn_port_mapping, wait=False
131 ):
132 self._logger.debug("")
133 self._client.get_token()
134 vim = self.get(vim_name)
135 vim_id_for_wait = self._get_id_for_wait(vim_name)
136 vim_config = {}
137 if config is not None:
138 if not config and (sdn_controller or sdn_port_mapping):
139 # If config is empty (clearing config)
140 raise ClientException(
141 "clearing config is incompatible with updating SDN info"
142 )
143 vim_config = config
144 if sdn_controller == "":
145 vim_config["sdn-controller"] = None
146 vim_config["sdn-port-mapping"] = None
147 else:
148 if sdn_controller:
149 sdnc = self._client.sdnc.get(sdn_controller)
150 vim_config["sdn-controller"] = sdnc["_id"]
151 if sdn_port_mapping:
152 with open(sdn_port_mapping, "r") as f:
153 vim_config["sdn-port-mapping"] = yaml.safe_load(f.read())
154 vim_account["config"] = vim_config
155 # vim_account['config'] = json.dumps(vim_config)
156 http_code, resp = self._http.patch_cmd(
157 endpoint="{}/{}".format(self._apiBase, vim["_id"]),
158 postfields_dict=vim_account,
159 )
160 # print('HTTP CODE: {}'.format(http_code))
161 # print('RESP: {}'.format(resp))
162 # if http_code in (200, 201, 202, 204):
163 if wait:
164 # In this case, 'resp' always returns None, so 'resp['id']' cannot be used.
165 # Use the previously obtained id instead.
166 wait_id = vim_id_for_wait
167 # Wait for status for VI instance update
168 self._wait(wait_id, wait)
169 # else:
170 # pass
171 # else:
172 # msg = ""
173 # if resp:
174 # try:
175 # msg = json.loads(resp)
176 # except ValueError:
177 # msg = resp
178 # raise ClientException("failed to update vim {} - {}".format(vim_name, msg))
179
180 def update_vim_account_dict(self, vim_account, vim_access):
181 self._logger.debug("")
182 vim_account["vim_type"] = vim_access["vim-type"]
183 vim_account["description"] = vim_access["description"]
184 vim_account["vim_url"] = vim_access["vim-url"] or "null"
185 vim_account["vim_user"] = vim_access["vim-username"] or "null"
186 vim_account["vim_password"] = vim_access["vim-password"] or "null"
187 vim_account["vim_tenant_name"] = vim_access["vim-tenant-name"] or "null"
188 return vim_account
189
190 def get_id(self, name):
191 """Returns a VIM id from a VIM name"""
192 self._logger.debug("")
193 for vim in self.list():
194 if name == vim["name"]:
195 return vim["uuid"]
196 raise NotFound("vim {} not found".format(name))
197
198 def delete(self, vim_name, force=False, wait=False):
199 self._logger.debug("")
200 self._client.get_token()
201 vim_id = vim_name
202 if not utils.validate_uuid4(vim_name):
203 vim_id = self.get_id(vim_name)
204 querystring = ""
205 if force:
206 querystring = "?FORCE=True"
207 http_code, resp = self._http.delete_cmd(
208 "{}/{}{}".format(self._apiBase, vim_id, querystring)
209 )
210 # print('HTTP CODE: {}'.format(http_code))
211 # print('RESP: {}'.format(resp))
212 if http_code == 202:
213 if wait:
214 # When deleting an account, 'resp' may be None.
215 # In such a case, the 'id' from 'resp' cannot be used, so use 'vim_id' instead
216 wait_id = vim_id
217 if resp:
218 resp = json.loads(resp)
219 wait_id = resp.get("id")
220 # Wait for status for VIM account deletion
221 self._wait(wait_id, wait, deleteFlag=True)
222 else:
223 print("Deletion in progress")
224 elif http_code == 204:
225 print("Deleted")
226 else:
227 msg = resp or ""
228 # if resp:
229 # try:
230 # msg = json.loads(resp)
231 # except ValueError:
232 # msg = resp
233 raise ClientException("failed to delete vim {} - {}".format(vim_name, msg))
234
235 def list(self, filter=None):
236 """Returns a list of VIM accounts"""
237 self._logger.debug("")
238 self._client.get_token()
239 filter_string = ""
240 if filter:
241 filter_string = "?{}".format(filter)
242 _, resp = self._http.get2_cmd("{}{}".format(self._apiBase, filter_string))
243 if not resp:
244 return list()
245 vim_accounts = json.loads(resp)
246 for datacenter in vim_accounts:
247 datacenter["uuid"] = datacenter.get("_id") # backward compatibility?
248 return vim_accounts
249
250 def get(self, name):
251 """Returns a VIM account based on name or id"""
252 self._logger.debug("")
253 self._client.get_token()
254 vim_id = name
255 if not utils.validate_uuid4(name):
256 vim_id = self.get_id(name)
257 try:
258 _, resp = self._http.get2_cmd("{}/{}".format(self._apiBase, vim_id))
259 if resp:
260 resp = json.loads(resp)
261 if not resp or "_id" not in resp:
262 raise ClientException("failed to get vim info: {}".format(resp))
263 return resp
264 except NotFound:
265 raise NotFound("vim '{}' not found".format(name))