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