dd6a5e03387fae0806d1765cf53317cab89bbfc8
[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 yaml
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 if 'config' in vim_access and vim_access['config'] is not None:
69 vim_config = yaml.load(vim_access['config'])
70
71 vim_account['datacenter']['config'] = vim_config
72
73 vim_account = self.update_vim_account_dict(vim_account, vim_access, vim_config)
74
75 resp = self._ro_http.post_cmd('openmano/datacenters', vim_account)
76 if resp and 'error' in resp:
77 raise ClientException("failed to create vim")
78 else:
79 self._attach(name, vim_account)
80 self._update_ro_accounts()
81
82
83 def _update_ro_accounts(self):
84 get_ro_accounts = self._http.get_cmd('api/operational/{}ro-account'
85 .format(self._client.so_rbac_project_path))
86 if not get_ro_accounts or 'rw-ro-account:ro-account' not in get_ro_accounts:
87 return
88 for account in get_ro_accounts['rw-ro-account:ro-account']['account']:
89 if account['ro-account-type'] == 'openmano':
90 # Refresh the Account Status
91 refresh_body = {"input": {
92 "ro-account": account['name'],
93 "project-name": self._client._so_project
94 }
95 }
96 refresh_status = self._http.post_cmd('api/operations/update-ro-account-status',
97 refresh_body)
98 if refresh_status and 'error' in refresh_status:
99 raise ClientException("Failed to refersh RO Account Status")
100
101
102 def update_vim_account_dict(self, vim_account, vim_access, vim_config):
103 if vim_access['vim-type'] == 'vmware':
104 if 'admin_username' in vim_config:
105 vim_account['datacenter']['admin_username'] = vim_config['admin_username']
106 if 'admin_password' in vim_config:
107 vim_account['datacenter']['admin_password'] = vim_config['admin_password']
108 if 'nsx_manager' in vim_config:
109 vim_account['datacenter']['nsx_manager'] = vim_config['nsx_manager']
110 if 'nsx_user' in vim_config:
111 vim_account['datacenter']['nsx_user'] = vim_config['nsx_user']
112 if 'nsx_password' in vim_config:
113 vim_account['datacenter']['nsx_password'] = vim_config['nsx_password']
114 if 'orgname' in vim_config:
115 vim_account['datacenter']['orgname'] = vim_config['orgname']
116 if 'vcenter_ip' in vim_config:
117 vim_account['datacenter']['vcenter_ip'] = vim_config['vcenter_ip']
118 if 'vcenter_user' in vim_config:
119 vim_account['datacenter']['vcenter_user'] = vim_config['vcenter_user']
120 if 'vcenter_password' in vim_config:
121 vim_account['datacenter']['vcenter_password'] = vim_config['vcenter_password']
122 if 'vcenter_port' in vim_config:
123 vim_account['datacenter']['vcenter_port'] = vim_config['vcenter_port']
124 vim_account['datacenter']['vim_url'] = vim_access['vim-url']
125 vim_account['datacenter']['vim_url_admin'] = vim_access['vim-url']
126 vim_account['datacenter']['description'] = vim_access['description']
127 vim_account['datacenter']['vim_username'] = vim_access['vim-username']
128 vim_account['datacenter']['vim_password'] = vim_access['vim-password']
129 vim_account['datacenter']['vim_tenant_name'] = vim_access['vim-tenant-name']
130 else:
131 vim_account['datacenter']['vim_url'] = vim_access['vim-url']
132 vim_account['datacenter']['vim_url_admin'] = vim_access['vim-url']
133 vim_account['datacenter']['description'] = vim_access['description']
134 vim_account['datacenter']['vim_username'] = vim_access['vim-username']
135 vim_account['datacenter']['vim_password'] = vim_access['vim-password']
136 vim_account['datacenter']['vim_tenant_name'] = vim_access['vim-tenant-name']
137 return vim_account
138
139 def delete(self, vim_name):
140 # first detach
141 self._detach(vim_name)
142 # detach. continue if error,
143 # it could be the datacenter is left without attachment
144 resp = self._ro_http.delete_cmd('openmano/datacenters/{}'
145 .format(vim_name))
146 if 'result' not in resp:
147 raise ClientException("failed to delete vim {} - {}".format(vim_name, resp))
148 self._update_ro_accounts()
149
150 def list(self, ro_update):
151 if ro_update:
152 self._update_ro_accounts()
153 # the ro_update needs to be made synchronous, for now this works around the issue
154 # and waits a resonable amount of time for the update to finish
155 time.sleep(2)
156
157 if self._client._so_version == 'v3':
158 resp = self._http.get_cmd('v1/api/operational/{}ro-account-state'
159 .format(self._client.so_rbac_project_path))
160 datacenters = []
161 if not resp or 'rw-ro-account:ro-account-state' not in resp:
162 return list()
163
164 ro_accounts = resp['rw-ro-account:ro-account-state']
165 for ro_account in ro_accounts['account']:
166 if 'datacenters' not in ro_account:
167 continue
168 if 'datacenters' not in ro_account['datacenters']:
169 continue
170 for datacenter in ro_account['datacenters']['datacenters']:
171 datacenters.append({"name": datacenter['name'], "uuid": datacenter['uuid']
172 if 'uuid' in datacenter else None})
173
174 vim_accounts = datacenters
175 return vim_accounts
176 else:
177 # Backwards Compatibility
178 resp = self._http.get_cmd('v1/api/operational/datacenters')
179 if not resp or 'rw-launchpad:datacenters' not in resp:
180 return list()
181
182 datacenters = resp['rw-launchpad:datacenters']
183
184 vim_accounts = list()
185 if 'ro-accounts' not in datacenters:
186 return vim_accounts
187
188 tenant = self._get_ro_tenant()
189 if tenant is None:
190 return vim_accounts
191
192 for roaccount in datacenters['ro-accounts']:
193 if 'datacenters' not in roaccount:
194 continue
195 for datacenter in roaccount['datacenters']:
196 vim_accounts.append(self._get_ro_datacenter(datacenter['name'],
197 tenant['uuid']))
198 return vim_accounts
199
200 def _get_ro_tenant(self, name='osm'):
201 resp = self._ro_http.get_cmd('openmano/tenants/{}'.format(name))
202
203 if not resp:
204 return None
205
206 if 'tenant' in resp and 'uuid' in resp['tenant']:
207 return resp['tenant']
208 else:
209 return None
210
211 def _get_ro_datacenter(self, name, tenant_uuid='any'):
212 resp = self._ro_http.get_cmd('openmano/{}/datacenters/{}'
213 .format(tenant_uuid, name))
214 if not resp:
215 raise NotFound("datacenter {} not found".format(name))
216
217 if 'datacenter' in resp and 'uuid' in resp['datacenter']:
218 return resp['datacenter']
219 else:
220 raise NotFound("datacenter {} not found".format(name))
221
222 def get(self, name):
223 tenant = self._get_ro_tenant()
224 if tenant is None:
225 raise NotFound("no ro tenant found")
226
227 return self._get_ro_datacenter(name, tenant['uuid'])
228
229 def get_datacenter(self, name):
230 if self._client._so_version == 'v3':
231 resp = self._http.get_cmd('v1/api/operational/{}ro-account-state'
232 .format(self._client.so_rbac_project_path))
233 if not resp:
234 return None, None
235
236 if not resp or 'rw-ro-account:ro-account-state' not in resp:
237 return None, None
238
239 ro_accounts = resp['rw-ro-account:ro-account-state']
240 for ro_account in ro_accounts['account']:
241 if 'datacenters' not in ro_account:
242 continue
243 if 'datacenters' not in ro_account['datacenters']:
244 continue
245 for datacenter in ro_account['datacenters']['datacenters']:
246 if datacenter['name'] == name:
247 return datacenter, ro_account['name']
248 return None, None
249 else:
250 # Backwards Compatibility
251 resp = self._http.get_cmd('v1/api/operational/datacenters')
252 if not resp:
253 return None
254
255 if not resp or 'rw-launchpad:datacenters' not in resp:
256 return None
257 if 'ro-accounts' not in resp['rw-launchpad:datacenters']:
258 return None
259 for roaccount in resp['rw-launchpad:datacenters']['ro-accounts']:
260 if 'datacenters' not in roaccount:
261 continue
262 for datacenter in roaccount['datacenters']:
263 if datacenter['name'] == name:
264 return datacenter
265 return None
266
267 def get_resource_orchestrator(self):
268 resp = self._http.get_cmd('v1/api/operational/{}resource-orchestrator'
269 .format(self._client.so_rbac_project_path))
270
271 if not resp or 'rw-launchpad:resource-orchestrator' not in resp:
272 return None
273 return resp['rw-launchpad:resource-orchestrator']