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