X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osmclient%2Fv1%2Fvim.py;fp=osmclient%2Fv1%2Fvim.py;h=1e8b604996722f64591d059972bc3966cc3e8161;hb=d1ccf0e88aeacb065b97a6c5cb82e6de53537b94;hp=0000000000000000000000000000000000000000;hpb=ea593ec357b5e83ac373f3f3fe341449116e5e2d;p=osm%2Fosmclient.git diff --git a/osmclient/v1/vim.py b/osmclient/v1/vim.py new file mode 100644 index 0000000..1e8b604 --- /dev/null +++ b/osmclient/v1/vim.py @@ -0,0 +1,299 @@ +# Copyright 2017 Sandvine +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +OSM vim API handling +""" + +from osmclient.common.exceptions import ClientException +from osmclient.common.exceptions import NotFound +import yaml +import time + + +class Vim(object): + def __init__(self, http=None, ro_http=None, client=None): + self._client = client + self._ro_http = ro_http + self._http = http + + def _attach(self, vim_name, vim_account): + tenant_name = "osm" + tenant = self._get_ro_tenant() + if tenant is None: + raise ClientException("tenant {} not found".format(tenant_name)) + + datacenter = self._get_ro_datacenter(vim_name) + if datacenter is None: + raise Exception("datacenter {} not found".format(vim_name)) + + return self._ro_http.post_cmd( + "openmano/{}/datacenters/{}".format(tenant["uuid"], datacenter["uuid"]), + vim_account, + ) + + def _detach(self, vim_name): + tenant_name = "osm" + tenant = self._get_ro_tenant() + if tenant is None: + raise ClientException("tenant {} not found".format(tenant_name)) + return self._ro_http.delete_cmd( + "openmano/{}/datacenters/{}".format(tenant["uuid"], vim_name) + ) + + def create(self, name, vim_access): + vim_account = {} + vim_account["datacenter"] = {} + + # currently assumes vim_acc + if "vim-type" not in vim_access: + # 'openstack' not in vim_access['vim-type']): + raise Exception("vim type not provided") + + vim_account["datacenter"]["name"] = name + vim_account["datacenter"]["type"] = vim_access["vim-type"] + + vim_config = {} + if "config" in vim_access and vim_access["config"] is not None: + vim_config = yaml.safe_load(vim_access["config"]) + + if vim_config: + vim_account["datacenter"]["config"] = vim_config + + vim_account = self.update_vim_account_dict(vim_account, vim_access, vim_config) + + resp = self._ro_http.post_cmd("openmano/datacenters", vim_account) + if resp and "error" in resp: + raise ClientException("failed to create vim") + else: + self._attach(name, vim_account) + self._update_ro_accounts() + + def _update_ro_accounts(self): + get_ro_accounts = self._http.get_cmd( + "api/operational/{}ro-account".format(self._client.so_rbac_project_path) + ) + if not get_ro_accounts or "rw-ro-account:ro-account" not in get_ro_accounts: + return + for account in get_ro_accounts["rw-ro-account:ro-account"]["account"]: + if account["ro-account-type"] == "openmano": + # Refresh the Account Status + refresh_body = { + "input": { + "ro-account": account["name"], + "project-name": self._client._so_project, + } + } + refresh_status = self._http.post_cmd( + "api/operations/update-ro-account-status", refresh_body + ) + if refresh_status and "error" in refresh_status: + raise ClientException("Failed to refersh RO Account Status") + + def update_vim_account_dict(self, vim_account, vim_access, vim_config): + if vim_access["vim-type"] == "vmware": + if "admin_username" in vim_config: + vim_account["datacenter"]["admin_username"] = vim_config[ + "admin_username" + ] + if "admin_password" in vim_config: + vim_account["datacenter"]["admin_password"] = vim_config[ + "admin_password" + ] + if "nsx_manager" in vim_config: + vim_account["datacenter"]["nsx_manager"] = vim_config["nsx_manager"] + if "nsx_user" in vim_config: + vim_account["datacenter"]["nsx_user"] = vim_config["nsx_user"] + if "nsx_password" in vim_config: + vim_account["datacenter"]["nsx_password"] = vim_config["nsx_password"] + if "orgname" in vim_config: + vim_account["datacenter"]["orgname"] = vim_config["orgname"] + if "vcenter_ip" in vim_config: + vim_account["datacenter"]["vcenter_ip"] = vim_config["vcenter_ip"] + if "vcenter_user" in vim_config: + vim_account["datacenter"]["vcenter_user"] = vim_config["vcenter_user"] + if "vcenter_password" in vim_config: + vim_account["datacenter"]["vcenter_password"] = vim_config[ + "vcenter_password" + ] + if "vcenter_port" in vim_config: + vim_account["datacenter"]["vcenter_port"] = vim_config["vcenter_port"] + vim_account["datacenter"]["vim_url"] = vim_access["vim-url"] + vim_account["datacenter"]["vim_url_admin"] = vim_access["vim-url"] + vim_account["datacenter"]["description"] = vim_access["description"] + vim_account["datacenter"]["vim_username"] = vim_access["vim-username"] + vim_account["datacenter"]["vim_password"] = vim_access["vim-password"] + vim_account["datacenter"]["vim_tenant_name"] = vim_access["vim-tenant-name"] + else: + vim_account["datacenter"]["vim_url"] = vim_access["vim-url"] + vim_account["datacenter"]["vim_url_admin"] = vim_access["vim-url"] + vim_account["datacenter"]["description"] = vim_access["description"] + vim_account["datacenter"]["vim_username"] = vim_access["vim-username"] + vim_account["datacenter"]["vim_password"] = vim_access["vim-password"] + vim_account["datacenter"]["vim_tenant_name"] = vim_access["vim-tenant-name"] + return vim_account + + def delete(self, vim_name): + # first detach + self._detach(vim_name) + # detach. continue if error, + # it could be the datacenter is left without attachment + resp = self._ro_http.delete_cmd("openmano/datacenters/{}".format(vim_name)) + if "result" not in resp: + raise ClientException("failed to delete vim {} - {}".format(vim_name, resp)) + self._update_ro_accounts() + + def list(self, ro_update): + if ro_update: + self._update_ro_accounts() + # the ro_update needs to be made synchronous, for now this works around the issue + # and waits a resonable amount of time for the update to finish + time.sleep(2) + + if self._client._so_version == "v3": + resp = self._http.get_cmd( + "v1/api/operational/{}ro-account-state".format( + self._client.so_rbac_project_path + ) + ) + datacenters = [] + if not resp or "rw-ro-account:ro-account-state" not in resp: + return list() + + ro_accounts = resp["rw-ro-account:ro-account-state"] + for ro_account in ro_accounts["account"]: + if "datacenters" not in ro_account: + continue + if "datacenters" not in ro_account["datacenters"]: + continue + for datacenter in ro_account["datacenters"]["datacenters"]: + datacenters.append( + { + "name": datacenter["name"], + "uuid": datacenter["uuid"] + if "uuid" in datacenter + else None, + } + ) + + vim_accounts = datacenters + return vim_accounts + else: + # Backwards Compatibility + resp = self._http.get_cmd("v1/api/operational/datacenters") + if not resp or "rw-launchpad:datacenters" not in resp: + return list() + + datacenters = resp["rw-launchpad:datacenters"] + + vim_accounts = list() + if "ro-accounts" not in datacenters: + return vim_accounts + + tenant = self._get_ro_tenant() + if tenant is None: + return vim_accounts + + for roaccount in datacenters["ro-accounts"]: + if "datacenters" not in roaccount: + continue + for datacenter in roaccount["datacenters"]: + vim_accounts.append( + self._get_ro_datacenter(datacenter["name"], tenant["uuid"]) + ) + return vim_accounts + + def _get_ro_tenant(self, name="osm"): + resp = self._ro_http.get_cmd("openmano/tenants/{}".format(name)) + + if not resp: + return None + + if "tenant" in resp and "uuid" in resp["tenant"]: + return resp["tenant"] + else: + return None + + def _get_ro_datacenter(self, name, tenant_uuid="any"): + resp = self._ro_http.get_cmd( + "openmano/{}/datacenters/{}".format(tenant_uuid, name) + ) + if not resp: + raise NotFound("datacenter {} not found".format(name)) + + if "datacenter" in resp and "uuid" in resp["datacenter"]: + return resp["datacenter"] + else: + raise NotFound("datacenter {} not found".format(name)) + + def get(self, name): + tenant = self._get_ro_tenant() + if tenant is None: + raise NotFound("no ro tenant found") + + return self._get_ro_datacenter(name, tenant["uuid"]) + + def get_datacenter(self, name): + if self._client._so_version == "v3": + resp = self._http.get_cmd( + "v1/api/operational/{}ro-account-state".format( + self._client.so_rbac_project_path + ) + ) + if not resp: + return None, None + + if not resp or "rw-ro-account:ro-account-state" not in resp: + return None, None + + ro_accounts = resp["rw-ro-account:ro-account-state"] + for ro_account in ro_accounts["account"]: + if "datacenters" not in ro_account: + continue + if "datacenters" not in ro_account["datacenters"]: + continue + for datacenter in ro_account["datacenters"]["datacenters"]: + if datacenter["name"] == name: + return datacenter, ro_account["name"] + return None, None + else: + # Backwards Compatibility + resp = self._http.get_cmd("v1/api/operational/datacenters") + if not resp: + return None + + if not resp or "rw-launchpad:datacenters" not in resp: + return None + if "ro-accounts" not in resp["rw-launchpad:datacenters"]: + return None + for roaccount in resp["rw-launchpad:datacenters"]["ro-accounts"]: + if "datacenters" not in roaccount: + continue + for datacenter in roaccount["datacenters"]: + if datacenter["name"] == name: + return datacenter + return None + + def get_resource_orchestrator(self): + resp = self._http.get_cmd( + "v1/api/operational/{}resource-orchestrator".format( + self._client.so_rbac_project_path + ) + ) + + if not resp or "rw-launchpad:resource-orchestrator" not in resp: + return None + return resp["rw-launchpad:resource-orchestrator"]