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