Feature 10296 Pip Standardization
[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(
44 "openmano/{}/datacenters/{}".format(tenant["uuid"], datacenter["uuid"]),
45 vim_account,
46 )
47
48 def _detach(self, vim_name):
49 tenant_name = "osm"
50 tenant = self._get_ro_tenant()
51 if tenant is None:
52 raise ClientException("tenant {} not found".format(tenant_name))
53 return self._ro_http.delete_cmd(
54 "openmano/{}/datacenters/{}".format(tenant["uuid"], vim_name)
55 )
56
57 def create(self, name, vim_access):
58 vim_account = {}
59 vim_account["datacenter"] = {}
60
61 # currently assumes vim_acc
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["datacenter"]["name"] = name
67 vim_account["datacenter"]["type"] = vim_access["vim-type"]
68
69 vim_config = {}
70 if "config" in vim_access and vim_access["config"] is not None:
71 vim_config = yaml.safe_load(vim_access["config"])
72
73 if vim_config:
74 vim_account["datacenter"]["config"] = vim_config
75
76 vim_account = self.update_vim_account_dict(vim_account, vim_access, vim_config)
77
78 resp = self._ro_http.post_cmd("openmano/datacenters", vim_account)
79 if resp and "error" in resp:
80 raise ClientException("failed to create vim")
81 else:
82 self._attach(name, vim_account)
83 self._update_ro_accounts()
84
85 def _update_ro_accounts(self):
86 get_ro_accounts = self._http.get_cmd(
87 "api/operational/{}ro-account".format(self._client.so_rbac_project_path)
88 )
89 if not get_ro_accounts or "rw-ro-account:ro-account" not in get_ro_accounts:
90 return
91 for account in get_ro_accounts["rw-ro-account:ro-account"]["account"]:
92 if account["ro-account-type"] == "openmano":
93 # Refresh the Account Status
94 refresh_body = {
95 "input": {
96 "ro-account": account["name"],
97 "project-name": self._client._so_project,
98 }
99 }
100 refresh_status = self._http.post_cmd(
101 "api/operations/update-ro-account-status", refresh_body
102 )
103 if refresh_status and "error" in refresh_status:
104 raise ClientException("Failed to refersh RO Account Status")
105
106 def update_vim_account_dict(self, vim_account, vim_access, vim_config):
107 if vim_access["vim-type"] == "vmware":
108 if "admin_username" in vim_config:
109 vim_account["datacenter"]["admin_username"] = vim_config[
110 "admin_username"
111 ]
112 if "admin_password" in vim_config:
113 vim_account["datacenter"]["admin_password"] = vim_config[
114 "admin_password"
115 ]
116 if "nsx_manager" in vim_config:
117 vim_account["datacenter"]["nsx_manager"] = vim_config["nsx_manager"]
118 if "nsx_user" in vim_config:
119 vim_account["datacenter"]["nsx_user"] = vim_config["nsx_user"]
120 if "nsx_password" in vim_config:
121 vim_account["datacenter"]["nsx_password"] = vim_config["nsx_password"]
122 if "orgname" in vim_config:
123 vim_account["datacenter"]["orgname"] = vim_config["orgname"]
124 if "vcenter_ip" in vim_config:
125 vim_account["datacenter"]["vcenter_ip"] = vim_config["vcenter_ip"]
126 if "vcenter_user" in vim_config:
127 vim_account["datacenter"]["vcenter_user"] = vim_config["vcenter_user"]
128 if "vcenter_password" in vim_config:
129 vim_account["datacenter"]["vcenter_password"] = vim_config[
130 "vcenter_password"
131 ]
132 if "vcenter_port" in vim_config:
133 vim_account["datacenter"]["vcenter_port"] = vim_config["vcenter_port"]
134 vim_account["datacenter"]["vim_url"] = vim_access["vim-url"]
135 vim_account["datacenter"]["vim_url_admin"] = vim_access["vim-url"]
136 vim_account["datacenter"]["description"] = vim_access["description"]
137 vim_account["datacenter"]["vim_username"] = vim_access["vim-username"]
138 vim_account["datacenter"]["vim_password"] = vim_access["vim-password"]
139 vim_account["datacenter"]["vim_tenant_name"] = vim_access["vim-tenant-name"]
140 else:
141 vim_account["datacenter"]["vim_url"] = vim_access["vim-url"]
142 vim_account["datacenter"]["vim_url_admin"] = vim_access["vim-url"]
143 vim_account["datacenter"]["description"] = vim_access["description"]
144 vim_account["datacenter"]["vim_username"] = vim_access["vim-username"]
145 vim_account["datacenter"]["vim_password"] = vim_access["vim-password"]
146 vim_account["datacenter"]["vim_tenant_name"] = vim_access["vim-tenant-name"]
147 return vim_account
148
149 def delete(self, vim_name):
150 # first detach
151 self._detach(vim_name)
152 # detach. continue if error,
153 # it could be the datacenter is left without attachment
154 resp = self._ro_http.delete_cmd("openmano/datacenters/{}".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(
168 "v1/api/operational/{}ro-account-state".format(
169 self._client.so_rbac_project_path
170 )
171 )
172 datacenters = []
173 if not resp or "rw-ro-account:ro-account-state" not in resp:
174 return list()
175
176 ro_accounts = resp["rw-ro-account:ro-account-state"]
177 for ro_account in ro_accounts["account"]:
178 if "datacenters" not in ro_account:
179 continue
180 if "datacenters" not in ro_account["datacenters"]:
181 continue
182 for datacenter in ro_account["datacenters"]["datacenters"]:
183 datacenters.append(
184 {
185 "name": datacenter["name"],
186 "uuid": datacenter["uuid"]
187 if "uuid" in datacenter
188 else None,
189 }
190 )
191
192 vim_accounts = datacenters
193 return vim_accounts
194 else:
195 # Backwards Compatibility
196 resp = self._http.get_cmd("v1/api/operational/datacenters")
197 if not resp or "rw-launchpad:datacenters" not in resp:
198 return list()
199
200 datacenters = resp["rw-launchpad:datacenters"]
201
202 vim_accounts = list()
203 if "ro-accounts" not in datacenters:
204 return vim_accounts
205
206 tenant = self._get_ro_tenant()
207 if tenant is None:
208 return vim_accounts
209
210 for roaccount in datacenters["ro-accounts"]:
211 if "datacenters" not in roaccount:
212 continue
213 for datacenter in roaccount["datacenters"]:
214 vim_accounts.append(
215 self._get_ro_datacenter(datacenter["name"], tenant["uuid"])
216 )
217 return vim_accounts
218
219 def _get_ro_tenant(self, name="osm"):
220 resp = self._ro_http.get_cmd("openmano/tenants/{}".format(name))
221
222 if not resp:
223 return None
224
225 if "tenant" in resp and "uuid" in resp["tenant"]:
226 return resp["tenant"]
227 else:
228 return None
229
230 def _get_ro_datacenter(self, name, tenant_uuid="any"):
231 resp = self._ro_http.get_cmd(
232 "openmano/{}/datacenters/{}".format(tenant_uuid, name)
233 )
234 if not resp:
235 raise NotFound("datacenter {} not found".format(name))
236
237 if "datacenter" in resp and "uuid" in resp["datacenter"]:
238 return resp["datacenter"]
239 else:
240 raise NotFound("datacenter {} not found".format(name))
241
242 def get(self, name):
243 tenant = self._get_ro_tenant()
244 if tenant is None:
245 raise NotFound("no ro tenant found")
246
247 return self._get_ro_datacenter(name, tenant["uuid"])
248
249 def get_datacenter(self, name):
250 if self._client._so_version == "v3":
251 resp = self._http.get_cmd(
252 "v1/api/operational/{}ro-account-state".format(
253 self._client.so_rbac_project_path
254 )
255 )
256 if not resp:
257 return None, None
258
259 if not resp or "rw-ro-account:ro-account-state" not in resp:
260 return None, None
261
262 ro_accounts = resp["rw-ro-account:ro-account-state"]
263 for ro_account in ro_accounts["account"]:
264 if "datacenters" not in ro_account:
265 continue
266 if "datacenters" not in ro_account["datacenters"]:
267 continue
268 for datacenter in ro_account["datacenters"]["datacenters"]:
269 if datacenter["name"] == name:
270 return datacenter, ro_account["name"]
271 return None, None
272 else:
273 # Backwards Compatibility
274 resp = self._http.get_cmd("v1/api/operational/datacenters")
275 if not resp:
276 return None
277
278 if not resp or "rw-launchpad:datacenters" not in resp:
279 return None
280 if "ro-accounts" not in resp["rw-launchpad:datacenters"]:
281 return None
282 for roaccount in resp["rw-launchpad:datacenters"]["ro-accounts"]:
283 if "datacenters" not in roaccount:
284 continue
285 for datacenter in roaccount["datacenters"]:
286 if datacenter["name"] == name:
287 return datacenter
288 return None
289
290 def get_resource_orchestrator(self):
291 resp = self._http.get_cmd(
292 "v1/api/operational/{}resource-orchestrator".format(
293 self._client.so_rbac_project_path
294 )
295 )
296
297 if not resp or "rw-launchpad:resource-orchestrator" not in resp:
298 return None
299 return resp["rw-launchpad:resource-orchestrator"]