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