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