b0033a18bcf030efa414382c8cda020c6885e5d6
[osm/osmclient.git] / osmclient / v1 / vim.py
1 # Copyright 2017 Sandvine
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.exceptions import ClientException
22 from osmclient.common.exceptions import NotFound
23 import json
24 import time
25
26
27 class Vim(object):
28 def __init__(self, http=None, ro_http=None, client=None):
29 self._client = client
30 self._ro_http = ro_http
31 self._http = http
32
33 def _attach(self, vim_name, vim_account):
34 tenant_name = 'osm'
35 tenant = self._get_ro_tenant()
36 if tenant is None:
37 raise ClientException("tenant {} not found".format(tenant_name))
38
39 datacenter = self._get_ro_datacenter(vim_name)
40 if datacenter is None:
41 raise Exception('datacenter {} not found'.format(vim_name))
42
43 return self._ro_http.post_cmd('openmano/{}/datacenters/{}'
44 .format(tenant['uuid'],
45 datacenter['uuid']), vim_account)
46
47 def _detach(self, vim_name):
48 tenant_name = 'osm'
49 tenant = self._get_ro_tenant()
50 if tenant is None:
51 raise ClientException("tenant {} not found".format(tenant_name))
52 return self._ro_http.delete_cmd('openmano/{}/datacenters/{}'
53 .format(tenant["uuid"], vim_name))
54
55 def create(self, name, vim_access):
56 vim_account = {}
57 vim_account['datacenter'] = {}
58
59 # currently assumes vim_acc
60 if ('vim-type' not in vim_access):
61 #'openstack' not in vim_access['vim-type']):
62 raise Exception("vim type not provided")
63
64 vim_account['datacenter']['name'] = name
65 vim_account['datacenter']['type'] = vim_access['vim-type']
66
67 vim_config = {}
68 vim_config['use_floating_ip'] = False
69
70 if ('floating_ip_pool' in vim_access and
71 vim_access['floating_ip_pool'] is not None):
72 vim_config['use_floating_ip'] = True
73
74 if 'keypair' in vim_access and vim_access['keypair'] is not None:
75 vim_config['keypair'] = vim_access['keypair']
76 elif 'config' in vim_access and vim_access['config'] is not None:
77 if any(var in vim_access['config'] for var in ["admin_password","admin_username","orgname","nsx_user","nsx_password","nsx_manager","vcenter_ip","vcenter_port","vcenter_user","vcenter_password"]):
78 vim_config = json.loads(vim_access['config'])
79
80 vim_account['datacenter']['config'] = vim_config
81
82 vim_account = self.update_vim_account_dict(vim_account, vim_access, vim_config)
83
84 resp = self._ro_http.post_cmd('openmano/datacenters', vim_account)
85 if resp and 'error' in resp:
86 raise ClientException("failed to create vim")
87 else:
88 self._attach(name, vim_account)
89 self._update_ro_accounts()
90
91
92 def _update_ro_accounts(self):
93 get_ro_accounts = self._http.get_cmd('api/operational/{}ro-account'
94 .format(self._client.so_rbac_project_path))
95 if not get_ro_accounts or 'rw-ro-account:ro-account' not in get_ro_accounts:
96 return
97 for account in get_ro_accounts['rw-ro-account:ro-account']['account']:
98 if account['ro-account-type'] == 'openmano':
99 # Refresh the Account Status
100 refresh_body = {"input": {
101 "ro-account": account['name'],
102 "project-name": self._client._so_project
103 }
104 }
105 refresh_status = self._http.post_cmd('api/operations/update-ro-account-status',
106 refresh_body)
107 if refresh_status and 'error' in refresh_status:
108 raise ClientException("Failed to refersh RO Account Status")
109
110
111 def update_vim_account_dict(self, vim_account, vim_access, vim_config):
112 if vim_access['vim-type'] == 'vmware':
113 if 'admin_username' in vim_config:
114 vim_account['datacenter']['admin_username'] = vim_config['admin_username']
115 if 'admin_password' in vim_config:
116 vim_account['datacenter']['admin_password'] = vim_config['admin_password']
117 if 'nsx_manager' in vim_config:
118 vim_account['datacenter']['nsx_manager'] = vim_config['nsx_manager']
119 if 'nsx_user' in vim_config:
120 vim_account['datacenter']['nsx_user'] = vim_config['nsx_user']
121 if 'nsx_password' in vim_config:
122 vim_account['datacenter']['nsx_password'] = vim_config['nsx_password']
123 if 'orgname' in vim_config:
124 vim_account['datacenter']['orgname'] = vim_config['orgname']
125 if 'vcenter_ip' in vim_config:
126 vim_account['datacenter']['vcenter_ip'] = vim_config['vcenter_ip']
127 if 'vcenter_user' in vim_config:
128 vim_account['datacenter']['vcenter_user'] = vim_config['vcenter_user']
129 if 'vcenter_password' in vim_config:
130 vim_account['datacenter']['vcenter_password'] = vim_config['vcenter_password']
131 if 'vcenter_port' in vim_config:
132 vim_account['datacenter']['vcenter_port'] = vim_config['vcenter_port']
133 vim_account['datacenter']['vim_url'] = vim_access['vim-url']
134 vim_account['datacenter']['vim_url_admin'] = vim_access['vim-url']
135 vim_account['datacenter']['description'] = vim_access['description']
136 vim_account['datacenter']['vim_username'] = vim_access['vim-username']
137 vim_account['datacenter']['vim_password'] = vim_access['vim-password']
138 vim_account['datacenter']['vim_tenant_name'] = vim_access['vim-tenant-name']
139 else:
140 vim_account['datacenter']['vim_url'] = vim_access['vim-url']
141 vim_account['datacenter']['vim_url_admin'] = vim_access['vim-url']
142 vim_account['datacenter']['description'] = vim_access['description']
143 vim_account['datacenter']['vim_username'] = vim_access['vim-username']
144 vim_account['datacenter']['vim_password'] = vim_access['vim-password']
145 vim_account['datacenter']['vim_tenant_name'] = vim_access['vim-tenant-name']
146 return vim_account
147
148 def delete(self, vim_name):
149 # first detach
150 self._detach(vim_name)
151 # detach. continue if error,
152 # it could be the datacenter is left without attachment
153 resp = self._ro_http.delete_cmd('openmano/datacenters/{}'
154 .format(vim_name))
155 if 'result' not in resp:
156 raise ClientException("failed to delete vim {} - {}".format(vim_name, resp))
157 self._update_ro_accounts()
158
159 def list(self, ro_update):
160 if ro_update:
161 self._update_ro_accounts()
162 # the ro_update needs to be made synchronous, for now this works around the issue
163 # and waits a resonable amount of time for the update to finish
164 time.sleep(2)
165
166 if self._client._so_version == 'v3':
167 resp = self._http.get_cmd('v1/api/operational/{}ro-account-state'
168 .format(self._client.so_rbac_project_path))
169 datacenters = []
170 if not resp or 'rw-ro-account:ro-account-state' not in resp:
171 return list()
172
173 ro_accounts = resp['rw-ro-account:ro-account-state']
174 for ro_account in ro_accounts['account']:
175 if 'datacenters' not in ro_account:
176 continue
177 if 'datacenters' not in ro_account['datacenters']:
178 continue
179 for datacenter in ro_account['datacenters']['datacenters']:
180 datacenters.append({"name": datacenter['name'], "uuid": datacenter['uuid']
181 if 'uuid' in datacenter else None})
182
183 vim_accounts = datacenters
184 return vim_accounts
185 else:
186 # Backwards Compatibility
187 resp = self._http.get_cmd('v1/api/operational/datacenters')
188 if not resp or 'rw-launchpad:datacenters' not in resp:
189 return list()
190
191 datacenters = resp['rw-launchpad:datacenters']
192
193 vim_accounts = list()
194 if 'ro-accounts' not in datacenters:
195 return vim_accounts
196
197 tenant = self._get_ro_tenant()
198 if tenant is None:
199 return vim_accounts
200
201 for roaccount in datacenters['ro-accounts']:
202 if 'datacenters' not in roaccount:
203 continue
204 for datacenter in roaccount['datacenters']:
205 vim_accounts.append(self._get_ro_datacenter(datacenter['name'],
206 tenant['uuid']))
207 return vim_accounts
208
209 def _get_ro_tenant(self, name='osm'):
210 resp = self._ro_http.get_cmd('openmano/tenants/{}'.format(name))
211
212 if not resp:
213 return None
214
215 if 'tenant' in resp and 'uuid' in resp['tenant']:
216 return resp['tenant']
217 else:
218 return None
219
220 def _get_ro_datacenter(self, name, tenant_uuid='any'):
221 resp = self._ro_http.get_cmd('openmano/{}/datacenters/{}'
222 .format(tenant_uuid, name))
223 if not resp:
224 raise NotFound("datacenter {} not found".format(name))
225
226 if 'datacenter' in resp and 'uuid' in resp['datacenter']:
227 return resp['datacenter']
228 else:
229 raise NotFound("datacenter {} not found".format(name))
230
231 def get(self, name):
232 tenant = self._get_ro_tenant()
233 if tenant is None:
234 raise NotFound("no ro tenant found")
235
236 return self._get_ro_datacenter(name, tenant['uuid'])
237
238 def get_datacenter(self, name):
239 if self._client._so_version == 'v3':
240 resp = self._http.get_cmd('v1/api/operational/{}ro-account-state'
241 .format(self._client.so_rbac_project_path))
242 if not resp:
243 return None, None
244
245 if not resp or 'rw-ro-account:ro-account-state' not in resp:
246 return None, None
247
248 ro_accounts = resp['rw-ro-account:ro-account-state']
249 for ro_account in ro_accounts['account']:
250 if 'datacenters' not in ro_account:
251 continue
252 if 'datacenters' not in ro_account['datacenters']:
253 continue
254 for datacenter in ro_account['datacenters']['datacenters']:
255 if datacenter['name'] == name:
256 return datacenter, ro_account['name']
257 return None, None
258 else:
259 # Backwards Compatibility
260 resp = self._http.get_cmd('v1/api/operational/datacenters')
261 if not resp:
262 return None
263
264 if not resp or 'rw-launchpad:datacenters' not in resp:
265 return None
266 if 'ro-accounts' not in resp['rw-launchpad:datacenters']:
267 return None
268 for roaccount in resp['rw-launchpad:datacenters']['ro-accounts']:
269 if 'datacenters' not in roaccount:
270 continue
271 for datacenter in roaccount['datacenters']:
272 if datacenter['name'] == name:
273 return datacenter
274 return None
275
276 def get_resource_orchestrator(self):
277 resp = self._http.get_cmd('v1/api/operational/{}resource-orchestrator'
278 .format(self._client.so_rbac_project_path))
279
280 if not resp or 'rw-launchpad:resource-orchestrator' not in resp:
281 return None
282 return resp['rw-launchpad:resource-orchestrator']