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