summaryrefslogtreecommitdiffstats
path: root/lcm/pub/nfvi/vim
diff options
context:
space:
mode:
Diffstat (limited to 'lcm/pub/nfvi/vim')
-rw-r--r--lcm/pub/nfvi/vim/__init__.py13
-rw-r--r--lcm/pub/nfvi/vim/api/__init__.py10
-rw-r--r--lcm/pub/nfvi/vim/api/multivim/__init__.py10
-rw-r--r--lcm/pub/nfvi/vim/api/multivim/api.py321
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/__init__.py13
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/api.py60
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/auth.py46
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/glancebase.py43
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/image.py106
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/network.py423
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/neutronbase.py46
-rw-r--r--lcm/pub/nfvi/vim/api/openstack/project.py27
-rw-r--r--lcm/pub/nfvi/vim/const.py26
-rw-r--r--lcm/pub/nfvi/vim/lib/__init__.py13
-rw-r--r--lcm/pub/nfvi/vim/lib/syscomm.py20
-rw-r--r--lcm/pub/nfvi/vim/lib/vimexception.py17
-rw-r--r--lcm/pub/nfvi/vim/test/__init__.py13
-rw-r--r--lcm/pub/nfvi/vim/test/openstack/__init__.py13
-rw-r--r--lcm/pub/nfvi/vim/test/openstack/pub.py23
-rw-r--r--lcm/pub/nfvi/vim/test/openstack/test_image.py91
-rw-r--r--lcm/pub/nfvi/vim/test/openstack/test_network.py245
-rw-r--r--lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2bin0 -> 11075584 bytes
-rw-r--r--lcm/pub/nfvi/vim/vimadaptor.py120
23 files changed, 1699 insertions, 0 deletions
diff --git a/lcm/pub/nfvi/vim/__init__.py b/lcm/pub/nfvi/vim/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/lcm/pub/nfvi/vim/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/pub/nfvi/vim/api/__init__.py b/lcm/pub/nfvi/vim/api/__init__.py
new file mode 100644
index 00000000..f5e43792
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/__init__.py
@@ -0,0 +1,10 @@
+# Copyright 2016 ZTE Corporation.
+# 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.
diff --git a/lcm/pub/nfvi/vim/api/multivim/__init__.py b/lcm/pub/nfvi/vim/api/multivim/__init__.py
new file mode 100644
index 00000000..8d66b23f
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/multivim/__init__.py
@@ -0,0 +1,10 @@
+# Copyright 2017 ZTE Corporation.
+# 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.
diff --git a/lcm/pub/nfvi/vim/api/multivim/api.py b/lcm/pub/nfvi/vim/api/multivim/api.py
new file mode 100644
index 00000000..f3bdd30a
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/multivim/api.py
@@ -0,0 +1,321 @@
+# Copyright 2017 ZTE Corporation.
+#
+# 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.
+import json
+import logging
+
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+from lcm.pub.utils.restcall import req_by_msb
+from lcm.pub.nfvi.vim import const
+
+logger = logging.getLogger(__name__)
+
+VIM_DRIVER_BASE_URL = "openoapi/multivim/v1"
+
+def call(vim_id, tenant_id, res, method, data=''):
+ if data and not isinstance(data, (str, unicode)):
+ data = json.JSONEncoder().encode(data)
+ url = "{base_url}/{vim_id}{tenant_id}/{res}".format(
+ base_url=VIM_DRIVER_BASE_URL,
+ vim_id=vim_id,
+ tenant_id="/" + tenant_id if tenant_id else "",
+ res=res)
+ ret = req_by_msb(url, method, data)
+ if ret[0] > 0:
+ raise VimException(ret[1], ret[2])
+ return json.JSONDecoder().decode(ret[1]) if ret[1] else {}
+
+######################################################################
+
+def create_image(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "images", "POST", data)
+
+def delete_image(vim_id, tenant_id, image_id):
+ return call(vim_id, tenant_id, "images/%s" % image_id, "DELETE")
+
+def get_image(vim_id, tenant_id, image_id):
+ return call(vim_id, tenant_id, "images/%s" % image_id, "GET")
+
+def list_image(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "images", "GET")
+
+######################################################################
+
+def create_network(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "networks", "POST", data)
+
+def delete_network(vim_id, tenant_id, network_id):
+ return call(vim_id, tenant_id, "networks/%s" % network_id, "DELETE")
+
+def get_network(vim_id, tenant_id, network_id):
+ return call(vim_id, tenant_id, "networks/%s" % network_id, "GET")
+
+def list_network(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "networks", "GET")
+
+######################################################################
+
+def create_subnet(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "subnets", "POST", data)
+
+def delete_subnet(vim_id, tenant_id, subnet_id):
+ return call(vim_id, tenant_id, "subnets/%s" % subnet_id, "DELETE")
+
+def get_subnet(vim_id, tenant_id, subnet_id):
+ return call(vim_id, tenant_id, "subnets/%s" % subnet_id, "GET")
+
+def list_subnet(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "subnets", "GET")
+
+######################################################################
+
+def create_port(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "ports", "POST", data)
+
+def delete_port(vim_id, tenant_id, port_id):
+ return call(vim_id, tenant_id, "ports/%s" % port_id, "DELETE")
+
+def get_port(vim_id, tenant_id, port_id):
+ return call(vim_id, tenant_id, "ports/%s" % port_id, "GET")
+
+def list_port(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "ports", "GET")
+
+######################################################################
+
+def create_flavor(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "flavors", "POST", data)
+
+def delete_flavor(vim_id, tenant_id, flavor_id):
+ return call(vim_id, tenant_id, "flavors/%s" % flavor_id, "DELETE")
+
+def get_flavor(vim_id, tenant_id, flavor_id):
+ return call(vim_id, tenant_id, "flavors/%s" % flavor_id, "GET")
+
+def list_flavor(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "flavors", "GET")
+
+######################################################################
+
+def create_vm(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "servers", "POST", data)
+
+def delete_vm(vim_id, tenant_id, vm_id):
+ return call(vim_id, tenant_id, "servers/%s" % vm_id, "DELETE")
+
+def get_vm(vim_id, tenant_id, vm_id):
+ return call(vim_id, tenant_id, "servers/%s" % vm_id, "GET")
+
+def list_vm(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "servers", "GET")
+
+######################################################################
+
+def create_volume(vim_id, tenant_id, data):
+ return call(vim_id, tenant_id, "volumes", "POST", data)
+
+def delete_volume(vim_id, tenant_id, volume_id):
+ return call(vim_id, tenant_id, "volumes/%s" % volume_id, "DELETE")
+
+def get_volume(vim_id, tenant_id, volume_id):
+ return call(vim_id, tenant_id, "volumes/%s" % volume_id, "GET")
+
+def list_volume(vim_id, tenant_id):
+ return call(vim_id, tenant_id, "volumes", "GET")
+
+######################################################################
+
+def list_tenant(vim_id, tenant_name=""):
+ res = "tenants"
+ if tenant_name:
+ res = "%s?name=%s" % (res, tenant_name)
+ return call(vim_id, "", res, "GET")
+
+######################################################################
+
+
+class MultiVimApi:
+
+ def login(self, connect_info):
+ self.vim_id = connect_info["vimid"]
+ self.tenant_name = connect_info["tenant"]
+ tenants = list_tenant(self.vim_id)
+ for tenant in tenants["tenants"]:
+ if self.tenant_name == tenant["name"]:
+ self.tenant_id = tenant["id"]
+ return [0, connect_info]
+ raise VimException(1, "Tenant(%s) not exist" % self.tenant_name)
+
+ def query_net(self, auth_info, net_id):
+ net = get_network(self.vim_id, self.tenant_id, net_id)
+ return [0, {
+ "id": net.get("id", ""),
+ "name": net.get("name", ""),
+ "status": net.get("status", ""),
+ "admin_state_up": net.get("admin_state_up", True),
+ "network_type": net.get("networkType", ""),
+ "physical_network": net.get("physicalNetwork", ""),
+ "segmentation_id": net.get("segmentationId", ""),
+ "tenant_id": self.tenant_id,
+ "tenant_name": self.tenant_name,
+ "subnets": net.get("subnets", []),
+ "shared": net.get("shared", True),
+ "router_external": net.get("routerExternal", "")
+ }]
+
+ def query_nets(self, auth_info):
+ nets = list_network(self.vim_id, self.tenant_id)
+ return [0, {"networks": [{
+ "id": net.get("id", ""),
+ "name": net.get("name", ""),
+ "status": net.get("status", ""),
+ "admin_state_up": net.get("admin_state_up", True),
+ "network_type": net.get("networkType", ""),
+ "physical_network": net.get("physicalNetwork", ""),
+ "segmentation_id": net.get("segmentationId", ""),
+ "tenant_id": self.tenant_id,
+ "tenant_name": self.tenant_name,
+ "subnets": net.get("subnets", []),
+ "shared": net.get("shared", True),
+ "router_external": net.get("routerExternal", "")
+ } for net in nets["networks"]]}]
+
+ def query_subnet(self, auth_info, subnet_id):
+ subnet_info = get_subnet(self.vim_id, self.tenant_id, subnet_id)
+ ret = [0, {}]
+ ret[1]["id"] = subnet_id
+ ret[1]["name"] = subnet_info.get("name", "")
+ ret[1]["status"] = ""
+ ret[1]["ip_version"] = subnet_info.get("ipVersion", 4)
+ ret[1]["cidr"] = subnet_info.get("cidr", "")
+ ret[1]["allocation_pools"] = subnet_info.get("allocationPools", [])
+ ret[1]["enable_dhcp"] = subnet_info.get("enableDhcp", False)
+ ret[1]["gateway_ip"] = subnet_info.get("gatewayIp", "")
+ ret[1]["host_routes"] = subnet_info.get("hostRoutes", [])
+ ret[1]["dns_nameservers"] = subnet_info.get("dnsNameservers", [])
+ return ret
+
+ def query_port(self, auth_info, port_id):
+ port_info = get_port(self.vim_id, self.tenant_id, port_id)
+ ret = [0, {}]
+ ret[1]["id"] = port_id
+ ret[1]["name"] = port_info.get("name", "")
+ ret[1]["network_id"] = port_info.get("networkId", "")
+ ret[1]["tenant_id"] = self.tenant_id,
+ ret[1]["ip"] = port_info.get("ip", "")
+ ret[1]["subnet_id"] = port_info.get("subnetId", "")
+ ret[1]["mac_address"] = port_info.get("macAddress", "")
+ ret[1]["status"] = port_info.get("status", "")
+ ret[1]["admin_state_up"] = port_info.get("admin_state_up", True)
+ ret[1]["device_id"] = port_info.get("device_id", "")
+ return ret
+
+ def create_port(self, auth_info, data):
+ return [0, data]
+
+ def delete_port(self, auth_info, port_id):
+ return [0, ""]
+
+ def create_image(self, auth_info, data):
+ image_data = {
+ "name": data["image_name"],
+ "imagePath": data["image_url"],
+ "imageType": data["image_type"],
+ "containerFormat": "bare",
+ "visibility": "public",
+ "properties": []
+ }
+ image = create_image(self.vim_id, self.tenant_id, image_data)
+ return [0, {
+ "id": image["id"],
+ "name": image["name"],
+ const.RES_TYPE_KEY: image["returnCode"]}]
+
+ def get_image(self, auth_info, image_id):
+ image = get_image(self.vim_id, self.tenant_id, image_id)
+ return [0, {
+ "id": image["id"],
+ "name": image["name"],
+ "size": image["size"],
+ "status": image["status"]}]
+
+ def get_images(self, auth_info):
+ images = list_image(self.vim_id, self.tenant_id)
+ return [0, {"image_list": [{
+ "id": img["id"],
+ "name": img["name"],
+ "size": img["size"],
+ "status": img["status"]
+ } for img in images["images"]]}]
+
+ def delete_image(self, auth_info, image_id):
+ return [0, ""]
+
+ def create_network(self, auth_info, data):
+ net_data = {
+ "name": data["network_name"],
+ "shared": True,
+ "networkType": data["network_type"]
+ }
+ if "physical_network" in data and data['physical_network']:
+ net_data["physicalNetwork"] = data['physical_network']
+ if "vlan_transparent" in data and data["vlan_transparent"]:
+ net_data["vlanTransparent"] = data["vlan_transparent"]
+ if "segmentation_id" in data and data['segmentation_id']:
+ net_data["segmentationId"] = data["segmentation_id"]
+ if "routerExternal" in data and data['routerExternal']:
+ net_data["routerExternal"] = data["routerExternal"]
+ net = create_network(self.vim_id, self.tenant_id, net_data)
+ network_id = net["id"]
+ ret_net = {
+ "status": net.get("status", ""),
+ "id": network_id,
+ "name": net.get("name", ""),
+ "provider:segmentation_id": net.get("segmentationId", ""),
+ "provider:network_type": net.get("networkType", ""),
+ const.RES_TYPE_KEY: net["returnCode"],
+ "subnet_list": []
+ }
+ if "subnet_list" in data and data["subnet_list"]:
+ subnet = data["subnet_list"][0]
+ subnet_data = {
+ "networkId": network_id,
+ "name": subnet["subnet_name"],
+ "cidr": subnet["cidr"],
+ "ipVersion": const.IPV4,
+ "enableDhcp": False
+ }
+ if "ip_version" in subnet and subnet["ip_version"]:
+ subnet_data["ipVersion"] = int(subnet["ip_version"])
+ if "enable_dhcp" in subnet and subnet["enable_dhcp"]:
+ subnet_data["enableDhcp"] = int(subnet["enable_dhcp"]) == const.ENABLE_DHCP
+ if "gateway_ip" in subnet and subnet["gateway_ip"]:
+ subnet_data["gatewayIp"] = subnet["gateway_ip"]
+ if "dns_nameservers" in subnet and subnet["dns_nameservers"]:
+ subnet_data["dnsNameservers"] = subnet["dns_nameservers"]
+ if "allocation_pools" in subnet and subnet["allocation_pools"]:
+ subnet_data["allocationPools"] = subnet["allocation_pools"]
+ if "host_routes" in subnet and subnet["host_routes"]:
+ subnet_data["hostRoutes"] = subnet["host_routes"]
+ subnet_create = create_subnet(self.vim_id, self.tenant_id, subnet_data)
+ ret_net["subnet_list"].append({
+ "id": subnet_create["id"],
+ "name": subnet_create["name"],
+ const.RES_TYPE_KEY: net["returnCode"]})
+ return [0, ret_net]
+
+ def delete_network(self, auth_info, network_id):
+ return delete_network(self.vim_id, self.tenant_id, network_id)
+
+ def delete_subnet(self, auth_info, subnet_id):
+ return delete_subnet(self.vim_id, self.tenant_id, subnet_id)
diff --git a/lcm/pub/nfvi/vim/api/openstack/__init__.py b/lcm/pub/nfvi/vim/api/openstack/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/pub/nfvi/vim/api/openstack/api.py b/lcm/pub/nfvi/vim/api/openstack/api.py
new file mode 100644
index 00000000..f781e475
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/api.py
@@ -0,0 +1,60 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+from lcm.pub.nfvi.vim.api.openstack import auth, network, image
+
+
+class OpenstackApi:
+
+ def login(self, connect_info):
+ return auth.login(connect_info)
+
+ def query_net(self, auth_info, net_id):
+ return network.query_net(auth_info, net_id)
+
+ def query_nets(self, auth_info):
+ return network.query_nets(auth_info)
+
+ def query_subnet(self, auth_info, subnet_id):
+ return network.query_subnet(auth_info, subnet_id)
+
+ def query_port(self, auth_info, port_id):
+ return network.query_port(auth_info, port_id)
+
+ def create_port(self, auth_info, data):
+ return network.create_port(auth_info, data)
+
+ def delete_port(self, auth_info, port_id):
+ return network.delete_port(auth_info, port_id)
+
+ def create_image(self, auth_info, data):
+ return image.create_image(auth_info, data)
+
+ def get_image(self, auth_info, image_id):
+ return image.get_image(auth_info, image_id)
+
+ def get_images(self, auth_info):
+ return image.get_images(auth_info)
+
+ def delete_image(self, auth_info, image_id):
+ return image.delete_image(auth_info, image_id)
+
+ def create_network(self, auth_info, data):
+ return network.create_network(auth_info, data)
+
+ def delete_network(self, auth_info, network_id):
+ return network.delete_network(auth_info, network_id)
+
+ def delete_subnet(self, auth_info, subnet_id):
+ return network.delete_subnet(auth_info, subnet_id)
diff --git a/lcm/pub/nfvi/vim/api/openstack/auth.py b/lcm/pub/nfvi/vim/api/openstack/auth.py
new file mode 100644
index 00000000..b662c51f
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/auth.py
@@ -0,0 +1,46 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+import logging
+
+from keystoneclient.v2_0 import client
+
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+
+logger = logging.getLogger(__name__)
+
+OPENSTACK_CA_CERT = '/etc/httpd/conf.d/cert/vim/ca.cert'
+OPENSTACK_CLIENT_CERT = '/etc/httpd/conf.d/cert/vim/client.cert'
+OPENSTACK_CLIENT_KEY = '/etc/httpd/conf.d/cert/vim/client.key'
+
+
+def login(connect_info):
+ url, user = connect_info["url"], connect_info["user"]
+ passwd, tenant = connect_info["passwd"], connect_info["tenant"]
+ cacert, clientcert, clientkey = None, None, None
+ insecure = url.startswith('https')
+ logger.info(
+ "[%s]client.Client(auth_url='%s',"
+ "username='%s',password='%s',"
+ "tenant_name='%s',insecure=%s,cert='%s',key='%s',cacert='%s')" %
+ (fun_name(), url, user, passwd, tenant, insecure, clientcert, clientkey, cacert))
+ connect_info["cacert"] = cacert
+ connect_info["clientcert"] = clientcert
+ connect_info["clientkey"] = clientkey
+ connect_info["insecure"] = insecure
+ connect_info["keystone"] = client.Client(auth_url=url, username=user, password=passwd, interface='public',
+ tenant_name=tenant, insecure=insecure, cert=clientcert, key=clientkey,
+ cacert=cacert, debug=True)
+ ret = [0, connect_info]
+ return ret
diff --git a/lcm/pub/nfvi/vim/api/openstack/glancebase.py b/lcm/pub/nfvi/vim/api/openstack/glancebase.py
new file mode 100644
index 00000000..cfcde4fd
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/glancebase.py
@@ -0,0 +1,43 @@
+# Copyright 2016 ZTE Corporation.
+# 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.
+
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+def get_glance(funname, auth_info, ver='v2'):
+ import glanceclient.v1.client as glanceclient1
+ import glanceclient.v2.client as glanceclient2
+ keystone = auth_info["keystone"]
+ cacert = auth_info["cacert"]
+ clientcert = auth_info["clientcert"]
+ clientkey = auth_info["clientkey"]
+ insecure = auth_info["insecure"]
+ glance_endpoint = keystone.service_catalog.url_for(service_type='image')
+ logger.info("[%s]call glanceclient.Client('%s',token='%s',insecure=%s,cert_file='%s',key_file='%s',cacert='%s')"
+ % (funname, glance_endpoint, keystone.auth_token, insecure, clientcert, clientkey, cacert))
+ if 'v1' == ver:
+ logger.info("return glanceclient1")
+ return glanceclient1.Client(glance_endpoint,
+ token=keystone.auth_token,
+ insecure=insecure,
+ cert_file=clientcert,
+ key_file=clientkey,
+ cacert=cacert)
+ else:
+ logger.info("return glanceclient2")
+ return glanceclient2.Client(glance_endpoint,
+ token=keystone.auth_token,
+ insecure=insecure,
+ cert_file=clientcert,
+ key_file=clientkey,
+ cacert=cacert)
diff --git a/lcm/pub/nfvi/vim/api/openstack/image.py b/lcm/pub/nfvi/vim/api/openstack/image.py
new file mode 100644
index 00000000..2a04cb9a
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/image.py
@@ -0,0 +1,106 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+import logging
+import sys
+import traceback
+import threading
+
+from lcm.pub.nfvi.vim.api.openstack import glancebase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim import const
+
+logger = logging.getLogger(__name__)
+
+
+class ImageUploadThread(threading.Thread):
+ def __init__(self, glance, image_id, image_path):
+ threading.Thread.__init__(self)
+ self.glance = glance
+ self.image_id = image_id
+ self.image_path = image_path
+
+ def run(self):
+ try:
+ self.glance.images.upload(self.image_id, open(self.image_path, 'rb'))
+ except Exception as ex:
+ logger.error(traceback.format_exc())
+ err_msg = ex.message if ex.message else str(sys.exc_info())
+ logger.error("Failed to upload image(%s): %s", self.image_id, err_msg)
+ except:
+ logger.error(traceback.format_exc())
+ logger.error("Failed to upload image(%s): [%s]", self.image_id, str(sys.exc_info()))
+
+
+def create_image(auth_info, data):
+ ret = None
+ glance = glancebase.get_glance(fun_name(), auth_info)
+
+ exist_img = [img for img in glance.images.list() if img.name == data["image_name"]]
+ if exist_img:
+ ret = [0, {"id": exist_img[0].id, "name": data["image_name"], const.RES_TYPE_KEY: const.RES_TYPE_EXIST}]
+ else:
+ img = glance.images.create(
+ name=data["image_name"],
+ disk_format=data["image_type"],
+ visibility='public',
+ container_format='bare')
+ ret = [0, {"id": img.id, "name": data["image_name"], const.RES_TYPE_KEY: const.RES_TYPE_NEW}]
+ try:
+ ImageUploadThread(glance, img.id, data["image_path"]).start()
+ except:
+ logger.error(traceback.format_exc())
+ logger.error(str(sys.exc_info()))
+ return ret
+
+
+def get_image(auth_info, image_id):
+ from glanceclient.exc import HTTPNotFound
+ glance = glancebase.get_glance(fun_name(), auth_info)
+ img = None
+ try:
+ img = glance.images.get(image_id)
+ except HTTPNotFound:
+ logger.warn("Exception: %s" % str(sys.exc_info()))
+ return [2, "Image(%s) does not exist" % image_id]
+ ret_img_info = get_single_image(img)
+ if 'status' in ret_img_info and 'deleted' == ret_img_info["status"]:
+ return [2, "Image(%s) is deleted" % image_id]
+ return [0, ret_img_info]
+
+
+def delete_image(auth_info, image_id):
+ from glanceclient.exc import HTTPNotFound
+ glance = glancebase.get_glance(fun_name(), auth_info)
+ try:
+ glance.images.delete(image_id)
+ except HTTPNotFound:
+ logger.warn("Exception: %s" % str(sys.exc_info()))
+ return [0, "Image(%s) does not exist" % image_id]
+ return [0, "Image(%s) has been deleted" % image_id]
+
+
+def get_images(auth_info):
+ glance = glancebase.get_glance(fun_name(), auth_info)
+ imgs = glance.images.list()
+ return [0, {"image_list": [get_single_image(img) for img in imgs]}]
+
+
+def get_single_image(img):
+ img_size = 0
+ try:
+ img_size = img.size / 1024
+ except:
+ pass
+ return {"id": img.id, "name": img.name, "size": img_size, "status": img.status}
diff --git a/lcm/pub/nfvi/vim/api/openstack/network.py b/lcm/pub/nfvi/vim/api/openstack/network.py
new file mode 100644
index 00000000..ebfdf660
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/network.py
@@ -0,0 +1,423 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+import logging
+import sys
+import traceback
+
+from neutronclient.common.exceptions import NeutronClientException
+from neutronclient.common.exceptions import NetworkNotFoundClient
+from neutronclient.common.exceptions import NotFound as SubnetNotFound
+
+from lcm.pub.nfvi.vim.api.openstack import neutronbase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim.api.openstack import project
+from lcm.pub.nfvi.vim import const
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+
+logger = logging.getLogger(__name__)
+
+
+def query_net(auth_info, net_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ net = None
+ try:
+ net = neutron.show_network(net_id)["network"]
+ keystone = auth_info["keystone"]
+ tenant = keystone.tenants.get(tenant_id=net["tenant_id"])
+ except NetworkNotFoundClient as e:
+ logger.warn("NetworkNotFoundClient: %s", e.message)
+ return [2, e.message]
+ return [0, {
+ "id": net["id"],
+ "name": net["name"],
+ "status": net["status"],
+ "admin_state_up": net["admin_state_up"],
+ "network_type": net["provider:network_type"],
+ "physical_network": net["provider:physical_network"],
+ "segmentation_id": net["provider:segmentation_id"],
+ "tenant_id": net["tenant_id"],
+ "tenant_name": tenant.name,
+ "subnets": net["subnets"],
+ "shared": net["shared"],
+ "router_external": net["router:external"]
+ }]
+
+
+def query_nets(auth_info):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ keystone = auth_info["keystone"]
+ tenants_map = {}
+ tenants = keystone.tenants.list()
+ for tenant in tenants:
+ tenants_map[tenant.id] = tenant.name
+
+ nets = neutron.list_networks()
+ return [0, {"networks": [{
+ "id": net["id"],
+ "name": net["name"],
+ "status": net["status"],
+ "admin_state_up": net["admin_state_up"],
+ "network_type": net["provider:network_type"],
+ "physical_network": net["provider:physical_network"],
+ "segmentation_id": net["provider:segmentation_id"],
+ "tenant_id": net["tenant_id"],
+ "tenant_name": tenants_map[net["tenant_id"]] if net["tenant_id"] in tenants_map else "unknown",
+ "subnets": net["subnets"],
+ "shared": net["shared"],
+ "router_external": net["router:external"]
+ } for net in nets["networks"]]}]
+
+
+def query_subnet(auth_info, subnet_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ subnet_info = None
+ try:
+ subnet_info = neutron.show_subnet(subnet_id)["subnet"]
+ except SubnetNotFound as e:
+ logger.warn("SubnetNotFound: %s", e.message)
+ return [2, e.message]
+ ret = [0, {}]
+ ret[1]["id"] = subnet_id
+ ret[1]["name"] = subnet_info["name"]
+ ret[1]["status"] = ""
+ ret[1]["ip_version"] = subnet_info["ip_version"]
+ ret[1]["cidr"] = subnet_info["cidr"]
+ ret[1]["allocation_pools"] = subnet_info["allocation_pools"]
+ ret[1]["enable_dhcp"] = subnet_info["enable_dhcp"]
+ ret[1]["gateway_ip"] = subnet_info["gateway_ip"]
+ ret[1]["host_routes"] = subnet_info["host_routes"]
+ ret[1]["dns_nameservers"] = subnet_info["dns_nameservers"]
+ return ret
+
+
+def query_port(auth_info, port_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ port_info = None
+ try:
+ port_info = neutron.show_port(port_id)["port"]
+ except NeutronClientException as e:
+ logger.warn("NeutronClientException: %s", e.message)
+ return [2, e.message]
+ ret = [0, {}]
+ ret[1]["id"] = port_id
+ ret[1]["name"] = port_info["name"]
+ ret[1]["network_id"] = port_info["network_id"]
+ ret[1]["tenant_id"] = port_info["tenant_id"]
+ if "fixed_ips" in port_info and port_info["fixed_ips"]:
+ ret[1]["ip"] = port_info["fixed_ips"][0]["ip_address"]
+ ret[1]["subnet_id"] = port_info["fixed_ips"][0]["subnet_id"]
+ else:
+ ret[1]["ip"] = ""
+ ret[1]["subnet_id"] = ""
+ ret[1]["mac_address"] = port_info["mac_address"]
+ ret[1]["status"] = port_info["status"]
+ ret[1]["admin_state_up"] = port_info["admin_state_up"]
+ ret[1]["device_id"] = port_info["device_id"]
+ return ret
+
+
+def get_subnet_id(neutron, data, network_id):
+ subnet_id = None
+ if "subnet_name" in data and data["subnet_name"]:
+ all_subnets = neutron.list_subnets()
+ filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["name"] == data["subnet_name"]
+ and subnet["network_id"] == network_id]
+ count_filter_subnets = len(filter_subnets)
+ if 1 > count_filter_subnets:
+ logger.error("Subnet name(%s) does not exist" % data["subnet_name"])
+ raise VimException("Subnet name(%s) does not exist" % data["subnet_name"])
+ if 1 < count_filter_subnets:
+ for subnet in filter_subnets:
+ logger.error("subnet_id=%s", subnet["id"])
+ raise VimException("%d subnet(%s) exist in network(%s)"
+ % (count_filter_subnets, data["subnet_name"], data["network_name"]))
+ subnet_id = filter_subnets[0]['id']
+ else:
+ subnets = neutron.list_subnets()
+ filter_subnets = [subnet for subnet in subnets["subnets"] if subnet["network_id"] == network_id]
+ if filter_subnets:
+ subnet_id = filter_subnets[0]["id"]
+ return subnet_id
+
+
+def create_port(auth_info, data):
+ tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant_name"])
+
+ neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
+ all_nets = neutron_admin.list_networks()
+ filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
+ sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
+ (net['tenant_id'] != tenant_id and net['shared'])]
+ count_sel_nets = len(sel_nets)
+ if 1 > count_sel_nets:
+ logger.error("Network(%s) does not exist" % data["network_name"])
+ raise VimException("Network(%s) does not exist" % data["network_name"])
+ if 1 < count_sel_nets:
+ for net in sel_nets:
+ logger.error("net_id=%s", net["id"])
+ raise VimException("%d networks(%s) exist in tenant(%s)"
+ % (count_sel_nets, data["network_name"], data["tenant_name"]))
+ network_id = sel_nets[0]['id']
+ if tenant_id != sel_nets[0]['tenant_id']:
+ neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
+ else:
+ neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant_name"])
+
+ # get subnet id
+ subnet_id = get_subnet_id(neutron_admin, data, network_id)
+
+ # check port
+ port_data = None
+ ports = neutron.list_ports()
+ sel_ports = [port for port in ports['ports'] if port['tenant_id'] == tenant_id
+ and port['network_id'] == network_id]
+ filter_ports = []
+ for port in sel_ports:
+ if port['name'] == data["port_name"] and port['fixed_ips']:
+ for fixed_ip in port['fixed_ips']:
+ if fixed_ip['subnet_id'] == subnet_id:
+ filter_ports.append(port)
+ break
+ count_filter_ports = len(filter_ports)
+ if 1 < count_filter_ports:
+ for port in filter_ports:
+ logger.error("port_id=%s", port["id"])
+ raise VimException("%d port(%s) exist in subnet(%s)"
+ % (count_filter_ports, data["port_name"], data["subnet_name"]))
+ if 1 == len(filter_ports):
+ logger.debug("Port(%s) is exist!" % data["port_name"])
+ port_data = {'status': filter_ports[0]['status'],
+ 'id': filter_ports[0]['id'],
+ 'name': filter_ports[0]['name'],
+ 'network_id': filter_ports[0]['network_id'],
+ const.RES_TYPE_KEY: const.RES_TYPE_EXIST}
+ return [0, port_data]
+
+ # create port
+ create_param = {'port': {
+ 'name': data["port_name"],
+ 'admin_state_up': True,
+ 'network_id': network_id,
+ 'security_groups': [],
+ 'tenant_id': tenant_id}}
+ if "mac_address" in data and data["mac_address"]:
+ create_param['port']['mac_address'] = data["mac_address"]
+ if "vnic_type" in data and data["vnic_type"]:
+ create_param['port']['binding:vnic_type'] = data["vnic_type"]
+ if "bandwidth" in data and data["bandwidth"]:
+ create_param['port']['bandwidth'] = int(data["bandwidth"])
+ if "bond" in data and data["bond"]:
+ create_param['port']['bond'] = int(data["bond"])
+ if "macbond" in data and data["macbond"]:
+ if 'mac_address' in create_param['port']:
+ create_param['port']['mac_address'] += (',' + data["macbond"])
+ else:
+ create_param['port']['mac_address'] = data["macbond"]
+ if "ip" in data and data["ip"]:
+ if subnet_id:
+ create_param['port']['fixed_ips'] = [{"subnet_id": subnet_id, "ip_address": data["ip"]}]
+
+ if "allowed_address_pairs" in data and data["allowed_address_pairs"]:
+ create_param['port']['allowed_address_pairs'] = data["allowed_address_pairs"]
+ logger.info("[%s]call neutron.create_port(%s)" % (fun_name(), str(create_param)))
+ port_created = None
+ try:
+ port_created = neutron.create_port(create_param)
+ except NeutronClientException as ex:
+ logger.info("create_port exception: %s, %s", str(sys.exc_info()), ex.message)
+ create_param['port'].pop('security_groups')
+ if 'allowed_address_pairs' in create_param['port']:
+ create_param['port'].pop('allowed_address_pairs')
+ logger.info("[%s]recall neutron.create_port(%s)" % (fun_name(), str(create_param)))
+ port_created = neutron.create_port(create_param)
+ if port_created:
+ port_data = {'status': port_created['port']['status'],
+ 'id': port_created['port']['id'],
+ 'name': port_created['port']['name'],
+ 'network_id': port_created['port']['network_id'],
+ const.RES_TYPE_KEY: const.RES_TYPE_NEW}
+ return [0, port_data]
+
+
+def create_network(auth_info, data):
+ neutron = neutronbase.get_neutron(fun_name(), auth_info, data["tenant"])
+ tenant_id = project.get_tenant_id(fun_name(), auth_info, data["tenant"])
+
+ neutron_admin = neutronbase.get_neutron_default(fun_name(), auth_info)
+ all_nets = neutron_admin.list_networks()
+ filter_nets = [net for net in all_nets['networks'] if net['name'] == data["network_name"]]
+ sel_nets = [net for net in filter_nets if net['tenant_id'] == tenant_id or
+ (net['tenant_id'] != tenant_id and net['shared'])]
+ count_sel_nets = len(sel_nets)
+ if 1 < count_sel_nets:
+ for sel_net in sel_nets:
+ logger.info("net_id=%s, net_tenant_id=%s", sel_net["id"], sel_net['tenant_id'])
+ raise VimException("Already %d networks are found with name %s" % (count_sel_nets, data["network_name"]))
+
+ network_data = None
+ if sel_nets:
+ if sel_nets[0]['tenant_id'] != tenant_id:
+ neutron = neutronbase.get_neutron_by_tenant_id(fun_name(), auth_info, sel_nets[0]['tenant_id'])
+ all_subnets = neutron_admin.list_subnets()
+ filter_subnets = [subnet for subnet in all_subnets["subnets"] if subnet["network_id"] == sel_nets[0]["id"]]
+ network_data = {"status": sel_nets[0]["status"],
+ "id": sel_nets[0]["id"],
+ "name": data["network_name"],
+ "provider:segmentation_id": sel_nets[0]["provider:segmentation_id"],
+ "provider:network_type": sel_nets[0]["provider:network_type"],
+ const.RES_TYPE_KEY: const.RES_TYPE_EXIST,
+ "subnet_list": [{
+ "id": subnet["id"],
+ "name": subnet["name"],
+ const.RES_TYPE_KEY: const.RES_TYPE_EXIST
+ } for subnet in filter_subnets]}
+ else:
+ create_params = {
+ 'network': {
+ 'name': data["network_name"],
+ 'admin_state_up': True,
+ 'tenant_id': tenant_id,
+ 'shared': "shared" in data and int(data["shared"]) == const.SHARED_NET}}
+ if "mtu" in data and int(data["mtu"]) != const.DEFAULT_MTU:
+ create_params['network']['mtu'] = int(data["mtu"])
+ if "vlan_transparent" in data and int(data["vlan_transparent"]) == const.SUPPORT_VLAN_TRANSPARENT:
+ create_params['network']['vlan-transparent'] = True
+ if "network_type" in data and data['network_type']:
+ create_params['network']['provider:network_type'] = data['network_type']
+ if "segmentation_id" in data and data['segmentation_id']:
+ create_params['network']['provider:segmentation_id'] = int(data['segmentation_id'])
+ if "physical_network" in data and data['physical_network']:
+ create_params['network']['provider:physical_network'] = data['physical_network']
+
+ logger.info("[%s]call neutron.create_network(%s)" % (fun_name(), str(create_params)))
+ network_created = neutron.create_network(create_params)
+ network_data = {"status": network_created['network']['status'],
+ "id": network_created['network']['id'],
+ "name": data["network_name"],
+ "provider:segmentation_id": network_created['network']['provider:segmentation_id'],
+ "provider:network_type": network_created['network']['provider:network_type'],
+ const.RES_TYPE_KEY: const.RES_TYPE_NEW,
+ "subnet_list": []}
+
+ # subnet create
+ exist_subnet_names = [subnet["name"] for subnet in network_data["subnet_list"]]
+ need_rollback, ret_error = False, None
+ if "subnet_list" in data and data["subnet_list"]:
+ for subnet_data in data["subnet_list"]:
+ if subnet_data["subnet_name"] in exist_subnet_names:
+ continue
+ ret = create_subnet(neutron, network_data["id"], subnet_data)
+ if ret[0] != 0:
+ need_rollback, ret_error = True, ret
+ break
+ network_data["subnet_list"].append(ret[1])
+
+ # rollback when failed to create subnet
+ if need_rollback:
+ rollback(neutron_admin, network_data)
+ return ret_error
+
+ return [0, network_data]
+
+
+def create_subnet(neutron, network_id, data):
+ all_subnets = neutron.list_subnets()
+ filter_subnets = [subnet for subnet in all_subnets["subnets"]
+ if subnet["network_id"] == network_id and subnet["name"] == data["subnet_name"]]
+ if filter_subnets:
+ return [0, {
+ "id": filter_subnets[0]["id"],
+ "name": data["subnet_name"],
+ const.RES_TYPE_KEY: const.RES_TYPE_EXIST}]
+ try:
+ create_params = {
+ 'subnet': {
+ 'network_id': network_id,
+ 'name': data["subnet_name"],
+ 'cidr': data["cidr"],
+ 'ip_version': int(data["ip_version"]) if "ip_version" in data else const.IPV4, }}
+ create_params["subnet"]["enable_dhcp"] = ("enable_dhcp" in data
+ and int(data["enable_dhcp"]) == const.ENABLE_DHCP)
+ if "gateway_ip" in data and data["gateway_ip"]:
+ create_params["subnet"]["gateway_ip"] = data["gateway_ip"]
+ else:
+ create_params["subnet"]["gateway_ip"] = None
+ if "dns_nameservers" in data and data["dns_nameservers"]:
+ create_params["subnet"]["dns_nameservers"] = data["dns_nameservers"]
+ if "allocation_pools" in data and data["allocation_pools"]:
+ create_params["subnet"]["allocation_pools"] = data["allocation_pools"]
+ if "host_routes" in data and data["host_routes"]:
+ create_params["subnet"]["host_routes"] = data["host_routes"]
+
+ logger.info("[%s]call neutron.create_subnet(%s)" % (fun_name(), str(create_params)))
+ subnet_created = neutron.create_subnet(create_params)
+ return [0, {"id": subnet_created["subnet"]["id"],
+ "name": data["subnet_name"],
+ const.RES_TYPE_KEY: const.RES_TYPE_NEW}]
+ except Exception as ex:
+ logger.error(traceback.format_exc())
+ logger.error(str(sys.exc_info()))
+ return [1, ex.message if ex.message else str(sys.exc_info())]
+
+
+def rollback(neutron, network_data):
+ for subnet_data in network_data["subnet_list"]:
+ if subnet_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
+ try:
+ logger.info("[%s]call neutron.delete_subnet(%s)" % (fun_name(), subnet_data["id"]))
+ neutron.delete_subnet(subnet_data["subnet_id"])
+ except:
+ logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
+
+ if network_data and network_data[const.RES_TYPE_KEY] == const.RES_TYPE_NEW:
+ try:
+ logger.info("[%s]call neutron.delete_network(%s)" % (fun_name(), network_data["id"]))
+ neutron.delete_network(network_data["id"])
+ except:
+ logger.error("[%s]%s", fun_name(), str(sys.exc_info()))
+
+
+def delete_network(auth_info, network_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ try:
+ neutron.delete_network(network_id)
+ except Exception as ex:
+ logger.error(traceback.format_exc())
+ msg = ex.message if ex.message else str(sys.exc_info())
+ logger.error(msg)
+ if 404 == ex.status_code:
+ return [0, ex.message]
+ return [1, "Vim exception."]
+ return [0, "Network(%s) is deleted" % network_id]
+
+
+def delete_subnet(auth_info, subnet_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ try:
+ neutron.delete_subnet(subnet_id)
+ except NeutronClientException as e:
+ logger.warn("[%s]NetworkNotFoundClient: %s", fun_name(), e.message)
+ return [0, e.message]
+ return [0, "Subnet(%s) is deleted" % subnet_id]
+
+
+def delete_port(auth_info, port_id):
+ neutron = neutronbase.get_neutron_default(fun_name(), auth_info)
+ try:
+ neutron.delete_port(port_id)
+ except NeutronClientException as e:
+ logger.warn("[%s]NeutronClientException: %s", fun_name(), e.message)
+ return [0, e.message]
+ return [0, "Port(%s) is deleted" % port_id]
diff --git a/lcm/pub/nfvi/vim/api/openstack/neutronbase.py b/lcm/pub/nfvi/vim/api/openstack/neutronbase.py
new file mode 100644
index 00000000..1a755cc8
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/neutronbase.py
@@ -0,0 +1,46 @@
+# Copyright 2016 ZTE Corporation.
+# 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.
+
+import logging
+
+import neutronclient.v2_0.client as neutronclient
+
+logger = logging.getLogger(__name__)
+
+
+def get_neutron(funname, auth_info, tenant_name):
+ username = auth_info["user"]
+ passwd = auth_info["passwd"]
+ url = auth_info["url"]
+ cacert = auth_info["cacert"]
+ insecure = auth_info["insecure"]
+ logger.info("[%s]call neutronclient.Client(auth_url='%s',"
+ "username='%s',password='%s',tenant_name='%s',insecure=%s,ca_cert='%s')"
+ % (funname, url, username, passwd, tenant_name, insecure, cacert))
+ return neutronclient.Client(username=username, password=passwd, tenant_name=tenant_name,
+ insecure=insecure, auth_url=url, ca_cert=cacert)
+
+
+def get_neutron_by_tenant_id(funname, auth_info, tenant_id):
+ username = auth_info["user"]
+ passwd = auth_info["passwd"]
+ url = auth_info["url"]
+ cacert = auth_info["cacert"]
+ logger.info("[%s]call neutronclient.Client(auth_url='%s',"
+ "username='%s',password='%s',tenant_id='%s',ca_cert='%s')"
+ % (funname, url, username, passwd, tenant_id, cacert))
+ return neutronclient.Client(username=username, password=passwd, tenant_id=tenant_id, auth_url=url, ca_cert=cacert)
+
+
+def get_neutron_default(funname, auth_info):
+ return get_neutron(funname, auth_info, auth_info["tenant"])
diff --git a/lcm/pub/nfvi/vim/api/openstack/project.py b/lcm/pub/nfvi/vim/api/openstack/project.py
new file mode 100644
index 00000000..b0c079ad
--- /dev/null
+++ b/lcm/pub/nfvi/vim/api/openstack/project.py
@@ -0,0 +1,27 @@
+# Copyright 2016 ZTE Corporation.
+# 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.
+
+import logging
+
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+
+
+logger = logging.getLogger(__name__)
+
+
+def get_tenant_id(funname, auth_info, tenant):
+ logger.debug("[%s]call get_tenant_id(%s)", funname, tenant)
+ keystone = auth_info["keystone"]
+ tids = [t.id for t in keystone.tenants.list() if t.name == tenant]
+ if not tids:
+ raise VimException("Tenant(%s) does not exist." % tenant)
+ logger.debug("[%s]tenant_id=%s", funname, tids[0])
+ return tids[0]
diff --git a/lcm/pub/nfvi/vim/const.py b/lcm/pub/nfvi/vim/const.py
new file mode 100644
index 00000000..e8798689
--- /dev/null
+++ b/lcm/pub/nfvi/vim/const.py
@@ -0,0 +1,26 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+
+VIM_OPENSTACK = "openstack"
+VIM_VMWARE = "vmware"
+RES_TYPE_KEY = "res_type"
+RES_TYPE_NEW = 1
+RES_TYPE_EXIST = 0
+SHARED_NET = 1
+SUPPORT_VLAN_TRANSPARENT = 1
+DEFAULT_MTU = 1500
+IPV4 = 4
+IPV6 = 6
+ENABLE_DHCP = 1
diff --git a/lcm/pub/nfvi/vim/lib/__init__.py b/lcm/pub/nfvi/vim/lib/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/lcm/pub/nfvi/vim/lib/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/pub/nfvi/vim/lib/syscomm.py b/lcm/pub/nfvi/vim/lib/syscomm.py
new file mode 100644
index 00000000..447bf4ee
--- /dev/null
+++ b/lcm/pub/nfvi/vim/lib/syscomm.py
@@ -0,0 +1,20 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+
+import inspect
+
+
+def fun_name():
+ return inspect.stack()[1][3]
diff --git a/lcm/pub/nfvi/vim/lib/vimexception.py b/lcm/pub/nfvi/vim/lib/vimexception.py
new file mode 100644
index 00000000..b2b09cc3
--- /dev/null
+++ b/lcm/pub/nfvi/vim/lib/vimexception.py
@@ -0,0 +1,17 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+
+class VimException(Exception):
+ pass
diff --git a/lcm/pub/nfvi/vim/test/__init__.py b/lcm/pub/nfvi/vim/test/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/pub/nfvi/vim/test/openstack/__init__.py b/lcm/pub/nfvi/vim/test/openstack/__init__.py
new file mode 100644
index 00000000..5580cc3d
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/openstack/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
diff --git a/lcm/pub/nfvi/vim/test/openstack/pub.py b/lcm/pub/nfvi/vim/test/openstack/pub.py
new file mode 100644
index 00000000..6c36f43e
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/openstack/pub.py
@@ -0,0 +1,23 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+
+from lcm.pub.nfvi.vim import const
+
+connect_info = {
+ "vimtype": const.VIM_OPENSTACK,
+ "url": "http://10.43.35.131:5000/v2.0",
+ "user": "admin",
+ "passwd": "keystone",
+ "tenant": "admin"}
diff --git a/lcm/pub/nfvi/vim/test/openstack/test_image.py b/lcm/pub/nfvi/vim/test/openstack/test_image.py
new file mode 100644
index 00000000..004d737b
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/openstack/test_image.py
@@ -0,0 +1,91 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+"""
+import unittest
+import os
+import time
+
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.nfvi.vim.test.openstack import pub
+from lcm.pub.nfvi.vim import const
+
+
+class TestImage(unittest.TestCase):
+ def setUp(self):
+ self.api = vimadaptor.VimAdaptor(pub.connect_info)
+ self.currentdir = os.path.dirname(os.path.abspath(__file__))
+ def tearDown(self):
+ pass
+ def createImg(self, data):
+ return self.api.create_image(data)
+
+ def test_image_all(self):
+ image_data = {
+ "image_name": "cirros",
+ "image_path": self.currentdir + "/testdata/cirros.qcow2",
+ "image_type": "qcow2"
+ }
+
+ # create image
+ ret = self.createImg(image_data)
+ self.assertEqual(0, ret[0])
+ if ret[1][const.RES_TYPE_KEY] == const.RES_TYPE_EXIST:
+ self.api.delete_image(image_id = ret[1]["id"])
+ ret = self.createImg(image_data)
+ self.assertEqual(0, ret[0])
+ imageid = ret[1]["id"]
+ retryTimes = 0
+ while retryTimes < 10:
+ ret = self.api.get_image(image_id = imageid)
+ self.assertEqual(0, ret[0])
+ if ret[1]["status"] == 'active':
+ break
+ time.sleep(2)
+
+ # image is exist
+ ret = self.createImg(image_data)
+ self.assertEqual(0, ret[0])
+ self.assertEqual(const.RES_TYPE_EXIST, ret[1][const.RES_TYPE_KEY])
+
+ # get all images
+ ret = self.api.get_images()
+ self.assertEqual(0, ret[0])
+ flag = False
+ for image in ret[1]['image_list']:
+ if image_data["image_name"] == image["name"]:
+ flag = True
+ break
+ self.assertTrue(flag)
+
+ # delete image
+ ret = self.api.delete_image(image_id = imageid)
+ self.assertEqual(0, ret[0])
+
+ # get_image except
+ ret = self.api.get_image(image_id = imageid)
+ self.assertEqual(2, ret[0])
+
+ # delete image except
+ ret = self.api.delete_image(image_id = imageid)
+ self.assertEqual(0, ret[0])
+
+ # Exception
+ image_data["image_path"] = "aaaa"
+ ret = self.createImg(image_data)
+ self.assertEqual(0, ret[0])
+
+ imageid = ret[1]["id"]
+ self.api.delete_image(image_id = imageid)
+"""
diff --git a/lcm/pub/nfvi/vim/test/openstack/test_network.py b/lcm/pub/nfvi/vim/test/openstack/test_network.py
new file mode 100644
index 00000000..54ed68d6
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/openstack/test_network.py
@@ -0,0 +1,245 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+"""
+import unittest
+from lcm.pub.nfvi.vim import vimadaptor
+from lcm.pub.nfvi.vim.api.openstack import neutronbase
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim.test.openstack import pub
+from lcm.pub.nfvi.vim import const
+
+class TestNetwork(unittest.TestCase):
+ def setUp(self):
+ self.api = vimadaptor.VimAdaptor(pub.connect_info)
+ self.network_data = {
+ "tenant": "admin",
+ "network_name": "testnet1",
+ "shared": const.SHARED_NET,
+ "network_type": "",
+ "mtu": 1523,
+ "subnet_list": [{
+ "subnet_name": "subnet1",
+ "cidr": "192.168.1.0/24",
+ "ip_version": const.IPV4,
+ "enable_dhcp": 0,
+ "gateway_ip": "192.168.1.1",
+ "dns_nameservers": [],
+ "allocation_pools":[],
+ "host_routes": []
+ }]
+ }
+
+ self.port_data = {
+ "port_name":"port_test",
+ "tenant_name":"test",
+ "network_name":"testnet1",
+ "mac_address":"fa:16:3e:c9:cb:f5",
+ "vnic_type":"normal",
+ "bandwidth":"100",
+ "bond":"0",
+ "macbond":"",
+ "ip":"192.168.1.10",
+ "subnet_name":"subnet1",
+ "allowed_address_pairs":[{'ip_address':'192.168.1.11','mac_address':'fa:16:3e:c9:cb:f6'}]
+ }
+
+ self.port_data_no_subname = {
+ "port_name":"port_test_no_subname",
+ "tenant_name":"admin",
+ "network_name":"testnet1",
+ "mac_address":"fa:16:3e:c9:cb:f7",
+ "vnic_type":"normal",
+ "bandwidth":"100",
+ "bond":"0",
+ "macbond":"",
+ "ip":"192.168.1.12",
+ "allowed_address_pairs":[{'ip_address':'192.168.1.13','mac_address':'fa:16:3e:c9:cb:f8'}]
+ }
+
+ self.network_data_rollback = {
+ "tenant": "admin",
+ "network_name": "testnet1",
+ "shared": const.SHARED_NET,
+ "network_type": "",
+ "mtu": 1523,
+ "subnet_list": [{
+ "subnet_name": "subnet1",
+ "cidr": "192.168.1.0/24",
+ "ip_version": const.IPV4,
+ "enable_dhcp": 0,
+ "gateway_ip": "192.168.1.1",
+ "dns_nameservers": [],
+ "allocation_pools":[],
+ "host_routes": []
+ },
+ {
+ "subnet_name": "subnet2",
+ "cidr": "191.168.1.0/24",
+ "ip_version": const.IPV6,
+ "enable_dhcp": 0,
+ "gateway_ip": "191.168.1.1",
+ "dns_nameservers": [],
+ "allocation_pools":[],
+ "host_routes": []
+ }]
+ }
+ def tearDown(self):
+ pass
+
+ def test_network_all(self):
+ neutron = neutronbase.get_neutron_default(fun_name(), pub.connect_info)
+
+ # create network
+ ret = self.api.create_network(self.network_data)
+ self.assertEqual(0, ret[0], ret[1])
+ if ret[1][const.RES_TYPE_KEY] == const.RES_TYPE_EXIST:
+ for subnet in ret[1]["subnet_list"]:
+ ports = neutron.list_ports()
+ for port in ports['ports']:
+ for fixed_ip in port['fixed_ips']:
+ if fixed_ip['subnet_id'] == subnet["id"]:
+ self.api.delete_port(port['id'])
+ break
+ ret_del = self.api.delete_subnet(subnet_id = subnet["id"])
+ self.assertEqual(0, ret_del[0])
+ ret_del = self.api.delete_network(network_id = ret[1]["id"])
+ self.assertEqual(0, ret_del[0])
+ ret = self.api.create_network(self.network_data)
+ self.assertEqual(0, ret[0])
+
+ # network exist
+ ret = self.api.create_network(self.network_data)
+ self.assertEqual(0, ret[0])
+ self.assertEqual(ret[1][const.RES_TYPE_KEY], const.RES_TYPE_EXIST)
+
+ # query subnet
+ q_subnet_ret = self.api.query_subnet(ret[1]["subnet_list"][0]["id"])
+ self.assertEqual(0, q_subnet_ret[0])
+
+ # query net
+ q_net_ret = self.api.query_net(ret[1]["id"])
+ self.assertEqual(0, q_net_ret[0])
+
+ # query nets
+ q_nets_ret = self.api.query_nets()
+ self.assertEqual(0, q_nets_ret[0])
+ flag = False
+ for network in q_nets_ret[1]['networks']:
+ if ret[1]["id"] == network["id"]:
+ flag = True
+ break
+ self.assertTrue(flag)
+
+ # create port
+ create_port_ret = self.api.create_port(self.port_data)
+ self.assertEqual(0, create_port_ret[0], create_port_ret[1])
+
+ # port exist
+ create_port_ret = self.api.create_port(self.port_data)
+ self.assertEqual(0, create_port_ret[0])
+ self.assertEqual(create_port_ret[1][const.RES_TYPE_KEY], const.RES_TYPE_EXIST)
+
+ # create port no subname
+ ret_no_subname = self.api.create_port(self.port_data_no_subname)
+ self.assertEqual(0, ret_no_subname[0], ret_no_subname[1])
+ self.api.delete_port(ret_no_subname[1]['id'])
+
+ # create port except, networks not exist
+ network_name = self.port_data["network_name"]
+ self.port_data["network_name"] = "no_network"
+ create_port_except_ret = self.api.create_port(self.port_data)
+ self.assertEqual(1, create_port_except_ret[0])
+ self.port_data["network_name"] = network_name
+
+ # create port except, subnet not exist
+ subnet_name = self.port_data["subnet_name"]
+ self.port_data["subnet_name"] = "no_subnet"
+ create_port_except_ret = self.api.create_port(self.port_data)
+ self.assertEqual(1, create_port_except_ret[0])
+ self.port_data["subnet_name"] = subnet_name
+
+ # query port
+ q_port_ret = self.api.query_port(create_port_ret[1]['id'])
+ self.assertEqual(0, q_port_ret[0], q_port_ret[1])
+
+ # delete port
+ ret_port_del = self.api.delete_port(create_port_ret[1]['id'])
+ self.assertEqual(0, ret_port_del[0])
+
+ # delete network
+ for subnet in ret[1]["subnet_list"]:
+ ret_del = self.api.delete_subnet(subnet_id = subnet["id"])
+ self.assertEqual(0, ret_del[0])
+ ret_del = self.api.delete_network(network_id = ret[1]["id"])
+ self.assertEqual(0, ret_del[0])
+
+ # query net except
+ q_net_ret = self.api.query_net(ret[1]["id"])
+ self.assertEqual(2, q_net_ret[0])
+
+ # query subnet except
+ q_subnet_ret = self.api.query_subnet(ret[1]["subnet_list"][0]["id"])
+ self.assertEqual(2, q_subnet_ret[0])
+
+ # rollback test
+ ret_roolback = self.api.create_network(self.network_data_rollback)
+ self.assertEqual(1, ret_roolback[0])
+
+ # delete except
+ ret_del = self.api.delete_subnet(subnet_id = "11111")
+ self.assertEqual(0, ret_del[0])
+
+ ret_del = self.api.delete_network(network_id = "11111")
+ self.assertEqual(0, ret_del[0])
+
+ ret_del = self.api.delete_port(port_id = "11111")
+ self.assertEqual(0, ret_del[0])
+
+ # query except
+ q_del = self.api.query_port(port_id = "11111")
+ self.assertEqual(2, q_del[0])
+
+ # multiple network except
+ tenant = self.network_data["tenant"]
+ network = self.network_data["network_name"]
+ self.network_data["tenant"] = "test"
+ self.network_data["network_name"] = "ut_test_network"
+ ret = self.api.create_network(self.network_data)
+ self.network_data["tenant"] = tenant
+ self.network_data["network_name"] = network
+ self.assertEqual(1, ret[0])
+
+ tenant = self.port_data["tenant_name"]
+ network = self.port_data["network_name"]
+ self.port_data["tenant_name"] = "test"
+ self.port_data["network_name"] = "ut_test_network"
+ ret = self.api.create_port(self.port_data)
+ self.port_data["tenant_name"] = tenant
+ self.port_data["network_name"] = network
+ self.assertEqual(1, ret[0])
+
+ # multiple subnet except
+ tenant = self.port_data["tenant_name"]
+ network = self.port_data["network_name"]
+ subnet = self.port_data["subnet_name"]
+ self.port_data["tenant_name"] = "test"
+ self.port_data["network_name"] = "ut_test_subnet_except"
+ self.port_data["subnet_name"] = "ut_test_same_subnet"
+ ret = self.api.create_port(self.port_data)
+ self.port_data["tenant_name"] = tenant
+ self.port_data["network_name"] = network
+ self.port_data["subnet_name"] = subnet
+ self.assertEqual(1, ret[0])
+"""
diff --git a/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2 b/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2
new file mode 100644
index 00000000..afe3ca37
--- /dev/null
+++ b/lcm/pub/nfvi/vim/test/openstack/testdata/cirros.qcow2
Binary files differ
diff --git a/lcm/pub/nfvi/vim/vimadaptor.py b/lcm/pub/nfvi/vim/vimadaptor.py
new file mode 100644
index 00000000..5f08d0b1
--- /dev/null
+++ b/lcm/pub/nfvi/vim/vimadaptor.py
@@ -0,0 +1,120 @@
+# Copyright 2016 ZTE Corporation.
+#
+# 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.
+
+import logging
+import sys
+import traceback
+
+from requests import RequestException
+
+from lcm.pub.nfvi.vim.lib.syscomm import fun_name
+from lcm.pub.nfvi.vim import const
+from lcm.pub.nfvi.vim.lib.vimexception import VimException
+
+logger = logging.getLogger(__name__)
+
+
+class VimAdaptor:
+ def __init__(self, connectInfo):
+ logger.info("[VimAdaptor]connectInfo=%s" % connectInfo)
+ self.apiImpl, self.authInfo = None, [1, "No auth info"]
+ self.create_api(connectInfo)
+ self.force_login(connectInfo)
+
+ def create_api(self, connectInfo):
+ vimtype = connectInfo['vimtype'] if 'vimtype' in connectInfo else None
+ logger.info("call %s, vimtype=%s" % (fun_name(), vimtype))
+ if vimtype == const.VIM_OPENSTACK:
+ from lcm.pub.nfvi.vim.api.openstack.api import OpenstackApi
+ self.apiImpl = OpenstackApi()
+ elif vimtype == const.VIM_VMWARE:
+ from lcm.pub.nfvi.vim.api.multivim.api import MultiVimApi
+ self.apiImpl = MultiVimApi()
+ else:
+ self.authInfo = [1, "Unsupported vimtype(%s)" % vimtype]
+
+ def api_call(self, funname, fun, *args):
+ logger.info("call %s%s" % (funname, str(args)))
+ ret = None
+ try:
+ ret = fun(self.authInfo[1], *args) if self.authInfo[0] == 0 else self.authInfo
+ except VimException as e:
+ ret = [1, e.message]
+ except RequestException as e:
+ logger.error("request=%s, url=%s" % (e.request.headers._store, e.request.url))
+ logger.error(traceback.format_exc())
+ ret = [1, e.message if e.message else str(sys.exc_info())]
+ except Exception as ex:
+ logger.error(traceback.format_exc())
+ ret = [1, ex.message if ex.message else str(sys.exc_info())]
+ except:
+ logger.error(traceback.format_exc())
+ ret = [1, str(sys.exc_info())]
+ logger.info("[%s]ret=%s" % (funname, ret))
+ return ret
+
+ def force_login(self, connectInfo):
+ if self.apiImpl:
+ logger.info("call %s(%s)" % (fun_name(), connectInfo))
+ try:
+ self.authInfo = self.apiImpl.login(connectInfo)
+ except VimException as e:
+ self.authInfo = [1, e.message]
+ except Exception as ex:
+ logger.error(traceback.format_exc())
+ logger.error(str(sys.exc_info()))
+ self.authInfo = [1, ex.message if ex.message else str(sys.exc_info())]
+ except:
+ logger.error(traceback.format_exc())
+ self.authInfo = [1, str(sys.exc_info())]
+ logger.info("self.authInfo=%s" % self.authInfo)
+
+ def query_net(self, net_id):
+ return self.api_call(fun_name(), self.apiImpl.query_net, net_id)
+
+ def query_nets(self):
+ return self.api_call(fun_name(), self.apiImpl.query_nets)
+
+ def query_subnet(self, subnet_id):
+ return self.api_call(fun_name(), self.apiImpl.query_subnet, subnet_id)
+
+ def query_port(self, port_id):
+ return self.api_call(fun_name(), self.apiImpl.query_port, port_id)
+
+ def create_image(self, data):
+ return self.api_call(fun_name(), self.apiImpl.create_image, data)
+
+ def get_image(self, image_id):
+ return self.api_call(fun_name(), self.apiImpl.get_image, image_id)
+
+ def get_images(self):
+ return self.api_call(fun_name(), self.apiImpl.get_images)
+
+ def delete_image(self, image_id):
+ return self.api_call(fun_name(), self.apiImpl.delete_image, image_id)
+
+ def create_network(self, data):
+ return self.api_call(fun_name(), self.apiImpl.create_network, data)
+
+ def delete_network(self, network_id):
+ return self.api_call(fun_name(), self.apiImpl.delete_network, network_id)
+
+ def delete_subnet(self, subnet_id):
+ return self.api_call(fun_name(), self.apiImpl.delete_subnet, subnet_id)
+
+ def create_port(self, data):
+ return self.api_call(fun_name(), self.apiImpl.create_port, data)
+
+ def delete_port(self, port_id):
+ return self.api_call(fun_name(), self.apiImpl.delete_port, port_id)