Revise FT of V2-API
This patch revise the FT of V2-API. The viewpoints of this revision are listed below: * Add some LCM operations in FT(such as Subscriptions and VNFLCM operation occurrences) * Revise VNF Package and request-body * Strengthen the check points by assertion * Fix the response-body related to the attribute that does not have the information to be returned Change-Id: I681800f52b4e2eb29c320c007ed1cf2901b61267
This commit is contained in:
parent
c6b0ca5fe3
commit
ff2e8da445
@ -273,6 +273,12 @@
|
||||
Multinodes job for SOL V2 devstack-based functional tests
|
||||
host-vars:
|
||||
controller-tacker:
|
||||
devstack_local_conf:
|
||||
post-config:
|
||||
# Skip notification endpoint testing in create subscription
|
||||
$TACKER_CONF:
|
||||
v2_nfvo:
|
||||
test_callback_uri: False
|
||||
tox_envlist: dsvm-functional-sol-v2
|
||||
|
||||
- job:
|
||||
|
@ -81,19 +81,24 @@ class VnfLcmControllerV2(sol_wsgi.SolAPIController):
|
||||
vnfSoftwareVersion=pkg_info.vnfSoftwareVersion,
|
||||
vnfdVersion=pkg_info.vnfdVersion,
|
||||
instantiationState='NOT_INSTANTIATED',
|
||||
# optional fields
|
||||
# NOTE: it is OK to absent but fill empty value to make them
|
||||
# handle easy.
|
||||
vnfInstanceName=body.get('vnfInstanceName', ""),
|
||||
vnfInstanceDescription=body.get('vnfInstanceDescription', ""),
|
||||
vnfConfigurableProperties=vnfd_prop['vnfConfigurableProperties'],
|
||||
metadata=metadata,
|
||||
extensions=vnfd_prop['extensions']
|
||||
# not set at the moment. will be set when instantiate.
|
||||
# vimConnectionInfo
|
||||
# instantiatedVnfInfo
|
||||
)
|
||||
|
||||
# set optional fields
|
||||
if body.get('vnfInstanceName'):
|
||||
inst.vnfInstanceName = body['vnfInstanceName']
|
||||
if body.get('vnfInstanceDescription'):
|
||||
inst.vnfInstanceDescription = body['vnfInstanceDescription']
|
||||
if vnfd_prop.get('vnfConfigurableProperties'):
|
||||
inst.vnfConfigurableProperties = vnfd_prop[
|
||||
'vnfConfigurableProperties']
|
||||
if metadata:
|
||||
inst.metadata = metadata
|
||||
if vnfd_prop.get('extensions'):
|
||||
inst.extensions = vnfd_prop['extensions']
|
||||
|
||||
inst.create(context)
|
||||
|
||||
self.nfvo_client.send_inst_create_notification(context, inst,
|
||||
|
@ -17,6 +17,7 @@ import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
import urllib
|
||||
import yaml
|
||||
|
||||
from oslo_config import cfg
|
||||
@ -38,7 +39,7 @@ VNF_PACKAGE_UPLOAD_TIMEOUT = 300
|
||||
|
||||
|
||||
class BaseSolV2Test(base.BaseTestCase):
|
||||
"""Base test case class for SOL v2 functionl tests."""
|
||||
"""Base test case class for SOL v2 functional tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
@ -63,6 +64,10 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||
cls.tacker_client = http_client.HttpClient(auth)
|
||||
cls.neutron_client = http_client.HttpClient(auth,
|
||||
service_type='network')
|
||||
cls.glance_client = http_client.HttpClient(auth,
|
||||
service_type='image')
|
||||
cls.nova_client = http_client.HttpClient(auth,
|
||||
service_type='compute')
|
||||
cls.heat_client = heat_utils.HeatClient(vim_info)
|
||||
|
||||
@classmethod
|
||||
@ -138,6 +143,11 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||
|
||||
cls.tacker_client.do_request(path, "DELETE")
|
||||
|
||||
def get_vnf_package(self, pkg_id):
|
||||
path = "/vnfpkgm/v1/vnf_packages/{}".format(pkg_id)
|
||||
resp, body = self.tacker_client.do_request(path, "GET")
|
||||
return body
|
||||
|
||||
def get_network_ids(self, networks):
|
||||
path = "/v2.0/networks"
|
||||
resp, body = self.neutron_client.do_request(path, "GET")
|
||||
@ -156,6 +166,100 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||
subnet_ids[subnet['name']] = subnet['id']
|
||||
return subnet_ids
|
||||
|
||||
def create_network(self, name):
|
||||
path = "/v2.0/networks"
|
||||
req_body = {
|
||||
"network": {
|
||||
# "admin_state_up": true,
|
||||
"name": name
|
||||
}
|
||||
}
|
||||
try:
|
||||
resp, resp_body = self.neutron_client.do_request(
|
||||
path, "POST", body=req_body)
|
||||
return resp_body['network']['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create network for name=<%s>, %s" %
|
||||
(name, e))
|
||||
|
||||
def delete_network(self, net_id):
|
||||
path = "/v2.0/networks/{}".format(net_id)
|
||||
try:
|
||||
self.neutron_client.do_request(path, "DELETE")
|
||||
except Exception as e:
|
||||
self.fail("Failed, delete network for id=<%s>, %s" %
|
||||
(net_id, e))
|
||||
|
||||
def create_subnet(self, net_id, sub_name, sub_range, ip_version):
|
||||
path = "/v2.0/subnets"
|
||||
req_body = {
|
||||
"subnet": {
|
||||
"name": sub_name,
|
||||
"network_id": net_id,
|
||||
"cidr": sub_range,
|
||||
"ip_version": ip_version
|
||||
}
|
||||
}
|
||||
try:
|
||||
resp, resp_body = self.neutron_client.do_request(
|
||||
path, "POST", body=req_body)
|
||||
return resp_body['subnet']['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create subnet for name=<%s>, %s" %
|
||||
(sub_name, e))
|
||||
|
||||
def delete_subnet(self, sub_id):
|
||||
path = "/v2.0/subnets/{}".format(sub_id)
|
||||
try:
|
||||
self.neutron_client.do_request(path, "DELETE")
|
||||
except Exception as e:
|
||||
self.fail("Failed, delete subnet for id=<%s>, %s" %
|
||||
(sub_id, e))
|
||||
|
||||
def create_port(self, network_id, name):
|
||||
path = "/v2.0/ports"
|
||||
req_body = {
|
||||
'port': {
|
||||
'network_id': network_id,
|
||||
'name': name
|
||||
}
|
||||
}
|
||||
try:
|
||||
resp, resp_body = self.neutron_client.do_request(
|
||||
path, "POST", body=req_body)
|
||||
return resp_body['port']['id']
|
||||
except Exception as e:
|
||||
self.fail("Failed, create port for net_id=<%s>, %s" %
|
||||
(network_id, e))
|
||||
|
||||
def delete_port(self, port_id):
|
||||
path = "/v2.0/ports/{}".format(port_id)
|
||||
try:
|
||||
self.neutron_client.do_request(path, "DELETE")
|
||||
except Exception as e:
|
||||
self.fail("Failed, delete port for id=<%s>, %s" %
|
||||
(port_id, e))
|
||||
|
||||
def get_image_id(self, image_name):
|
||||
path = "/v2.0/images"
|
||||
resp, resp_body = self.glance_client.do_request(path, "GET")
|
||||
|
||||
image_id = None
|
||||
for image in resp_body.get('images'):
|
||||
if image_name == image['name']:
|
||||
image_id = image['id']
|
||||
return image_id
|
||||
|
||||
def get_server_details(self, server_name):
|
||||
path = "/servers/detail"
|
||||
resp, resp_body = self.nova_client.do_request(path, "GET")
|
||||
|
||||
server_details = None
|
||||
for server in resp_body.get('servers'):
|
||||
if server_name == server['name']:
|
||||
server_details = server
|
||||
return server_details
|
||||
|
||||
def create_vnf_instance(self, req_body):
|
||||
path = "/vnflcm/v2/vnf_instances"
|
||||
return self.tacker_client.do_request(
|
||||
@ -171,6 +275,13 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def list_vnf_instance(self, filter_expr=None):
|
||||
path = "/vnflcm/v2/vnf_instances"
|
||||
if filter_expr:
|
||||
path = "{}?{}".format(path, urllib.parse.urlencode(filter_expr))
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def instantiate_vnf_instance(self, inst_id, req_body):
|
||||
path = "/vnflcm/v2/vnf_instances/{}/instantiate".format(inst_id)
|
||||
return self.tacker_client.do_request(
|
||||
@ -196,3 +307,92 @@ class BaseSolV2Test(base.BaseTestCase):
|
||||
continue
|
||||
else: # FAILED_TEMP or ROLLED_BACK
|
||||
raise Exception("Operation failed. state: %s" % state)
|
||||
|
||||
def wait_lcmocc_failed_temp(self, lcmocc_id):
|
||||
# NOTE: It is not necessary to set timeout because the operation
|
||||
# itself set timeout and the state will become 'FAILED_TEMP'.
|
||||
path = "/vnflcm/v2/vnf_lcm_op_occs/{}".format(lcmocc_id)
|
||||
while True:
|
||||
time.sleep(5)
|
||||
_, body = self.tacker_client.do_request(
|
||||
path, "GET", expected_status=[200], version="2.0.0")
|
||||
state = body['operationState']
|
||||
if state == 'FAILED_TEMP':
|
||||
return
|
||||
elif state in ['STARTING', 'PROCESSING']:
|
||||
continue
|
||||
elif state == 'COMPLETED':
|
||||
raise Exception("Operation unexpected COMPLETED.")
|
||||
else: # ROLLED_BACK
|
||||
raise Exception("Operation failed. state: %s" % state)
|
||||
|
||||
def show_lcmocc(self, lcmocc_id):
|
||||
path = "/vnflcm/v2/vnf_lcm_op_occs/{}".format(lcmocc_id)
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def list_lcmocc(self, filter_expr=None):
|
||||
path = "/vnflcm/v2/vnf_lcm_op_occs"
|
||||
if filter_expr:
|
||||
path = "{}?{}".format(path, urllib.parse.urlencode(filter_expr))
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def create_subscription(self, req_body):
|
||||
path = "/vnflcm/v2/subscriptions"
|
||||
return self.tacker_client.do_request(
|
||||
path, "POST", body=req_body, version="2.0.0")
|
||||
|
||||
def delete_subscription(self, sub_id):
|
||||
path = "/vnflcm/v2/subscriptions/{}".format(sub_id)
|
||||
return self.tacker_client.do_request(
|
||||
path, "DELETE", version="2.0.0")
|
||||
|
||||
def show_subscription(self, sub_id):
|
||||
path = "/vnflcm/v2/subscriptions/{}".format(sub_id)
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def list_subscriptions(self, filter_expr=None):
|
||||
path = "/vnflcm/v2/subscriptions"
|
||||
if filter_expr:
|
||||
path = "{}?{}".format(path, urllib.parse.urlencode(filter_expr))
|
||||
return self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
|
||||
def _check_resp_headers(self, resp, supported_headers):
|
||||
unsupported_headers = ['Link', 'Retry-After',
|
||||
'Content-Range', 'WWW-Authenticate']
|
||||
for s in supported_headers:
|
||||
if s not in resp.headers:
|
||||
raise Exception("Supported header doesn't exist: %s" % s)
|
||||
for u in unsupported_headers:
|
||||
if u in resp.headers:
|
||||
raise Exception("Unsupported header exist: %s" % u)
|
||||
|
||||
def check_resp_headers_in_create(self, resp):
|
||||
# includes location header and response body
|
||||
supported_headers = ['Version', 'Location', 'Content-Type',
|
||||
'Accept-Ranges']
|
||||
self._check_resp_headers(resp, supported_headers)
|
||||
|
||||
def check_resp_headers_in_operation_task(self, resp):
|
||||
# includes location header and no response body
|
||||
supported_headers = ['Version', 'Location']
|
||||
self._check_resp_headers(resp, supported_headers)
|
||||
|
||||
def check_resp_headers_in_get(self, resp):
|
||||
# includes response body and no location header
|
||||
supported_headers = ['Version', 'Content-Type',
|
||||
'Accept-Ranges']
|
||||
self._check_resp_headers(resp, supported_headers)
|
||||
|
||||
def check_resp_headers_in_delete(self, resp):
|
||||
# no location header and response body
|
||||
supported_headers = ['Version']
|
||||
self._check_resp_headers(resp, supported_headers)
|
||||
|
||||
def check_resp_body(self, body, expected_attrs):
|
||||
for attr in expected_attrs:
|
||||
if attr not in body:
|
||||
raise Exception("Expected attribute doesn't exist: %s" % attr)
|
||||
|
@ -16,226 +16,451 @@
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
|
||||
def sub1_create():
|
||||
# All attributes are set.
|
||||
# NOTE: All of the following cardinality attributes are set.
|
||||
# In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
# - 0..1 (1)
|
||||
# - 0..N (2 or more)
|
||||
# - 1
|
||||
# - 1..N (2 or more)
|
||||
vnf_provider_1 = {
|
||||
"vnfProvider": "dummy-vnfProvider-1",
|
||||
"vnfProducts": [
|
||||
{
|
||||
"vnfProductName": "dummy-vnfProductName-1-1",
|
||||
"versions": [
|
||||
{
|
||||
"vnfSoftwareVersion": 1.0,
|
||||
"vnfdVersions": [1.0, 2.0]
|
||||
},
|
||||
{
|
||||
"vnfSoftwareVersion": 1.1,
|
||||
"vnfdVersions": [1.1, 2.1]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"vnfProductName": "dummy-vnfProductName-1-2",
|
||||
"versions": [
|
||||
{
|
||||
"vnfSoftwareVersion": 1.0,
|
||||
"vnfdVersions": [1.0, 2.0]
|
||||
},
|
||||
{
|
||||
"vnfSoftwareVersion": 1.1,
|
||||
"vnfdVersions": [1.1, 2.1]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
vnf_provider_2 = {
|
||||
"vnfProvider": "dummy-vnfProvider-2",
|
||||
"vnfProducts": [
|
||||
{
|
||||
"vnfProductName": "dummy-vnfProductName-2-1",
|
||||
"versions": [
|
||||
{
|
||||
"vnfSoftwareVersion": 1.0,
|
||||
"vnfdVersions": [1.0, 2.0]
|
||||
},
|
||||
{
|
||||
"vnfSoftwareVersion": 1.1,
|
||||
"vnfdVersions": [1.1, 2.1]
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"vnfProductName": "dummy-vnfProductName-2-2",
|
||||
"versions": [
|
||||
{
|
||||
"vnfSoftwareVersion": 1.0,
|
||||
"vnfdVersions": [1.0, 2.0]
|
||||
},
|
||||
{
|
||||
"vnfSoftwareVersion": 1.1,
|
||||
"vnfdVersions": [1.1, 2.1]
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# NOTE: The following is omitted because authType is BASIC in this case
|
||||
# - "paramsOauth2ClientCredentials"
|
||||
return {
|
||||
"filter": {
|
||||
"vnfInstanceSubscriptionFilter": {
|
||||
"vnfdIds": [
|
||||
"dummy-vnfdId-1",
|
||||
"dummy-vnfdId-2"
|
||||
],
|
||||
"vnfProductsFromProviders": [
|
||||
vnf_provider_1,
|
||||
vnf_provider_2
|
||||
],
|
||||
"vnfInstanceIds": [
|
||||
"dummy-vnfInstanceId-1",
|
||||
"dummy-vnfInstanceId-2"
|
||||
],
|
||||
"vnfInstanceNames": [
|
||||
"dummy-vnfInstanceName-1",
|
||||
"dummy-vnfInstanceName-2"
|
||||
]
|
||||
},
|
||||
"notificationTypes": [
|
||||
"VnfIdentifierCreationNotification",
|
||||
"VnfLcmOperationOccurrenceNotification"
|
||||
],
|
||||
"operationTypes": [
|
||||
"INSTANTIATE",
|
||||
"TERMINATE"
|
||||
],
|
||||
"operationStates": [
|
||||
"COMPLETED",
|
||||
"FAILED"
|
||||
]
|
||||
},
|
||||
"callbackUri": "http://127.0.0.1/",
|
||||
"authentication": {
|
||||
"authType": [
|
||||
"BASIC"
|
||||
],
|
||||
"paramsBasic": {
|
||||
"password": "test_pass",
|
||||
"userName": "test_user"
|
||||
},
|
||||
# "paramsOauth2ClientCredentials": omitted,
|
||||
},
|
||||
"verbosity": "SHORT"
|
||||
}
|
||||
|
||||
|
||||
def sub2_create():
|
||||
# Omit except for required attributes
|
||||
# NOTE: Only the following cardinality attributes are set.
|
||||
# - 1
|
||||
# - 1..N (1)
|
||||
return {
|
||||
"callbackUri": "http://127.0.0.1/"
|
||||
}
|
||||
|
||||
|
||||
def sample1_create(vnfd_id):
|
||||
# All attributes are set.
|
||||
# NOTE: All of the following cardinality attributes are set.
|
||||
# In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
# - 0..1 (1)
|
||||
# - 0..N (2 or more)
|
||||
# - 1
|
||||
# - 1..N (2 or more)
|
||||
return {
|
||||
"vnfdId": vnfd_id,
|
||||
"vnfInstanceName": "sample1",
|
||||
"vnfInstanceDescription": "test sample1"
|
||||
"vnfInstanceDescription": "test sample1",
|
||||
"metadata": {"dummy-key": "dummy-val"}
|
||||
}
|
||||
|
||||
|
||||
def sample1_terminate():
|
||||
# All attributes are set.
|
||||
# NOTE: All of the following cardinality attributes are set.
|
||||
# In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
# - 0..1 (1)
|
||||
# - 0..N (2 or more)
|
||||
# - 1
|
||||
# - 1..N (2 or more)
|
||||
return {
|
||||
"terminationType": "GRACEFUL",
|
||||
"gracefulTerminationTimeout": 5,
|
||||
"additionalParams": {"dummy-key": "dummy-val"}
|
||||
}
|
||||
|
||||
|
||||
def sample1_instantiate(net_ids, subnets, ports, auth_url):
|
||||
# All attributes are set.
|
||||
# NOTE: All of the following cardinality attributes are set.
|
||||
# In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
# - 0..1 (1)
|
||||
# - 0..N (2 or more)
|
||||
# - 1
|
||||
# - 1..N (2 or more)
|
||||
|
||||
vim_id_1 = uuidutils.generate_uuid()
|
||||
vim_id_2 = uuidutils.generate_uuid()
|
||||
link_port_id_1 = uuidutils.generate_uuid()
|
||||
link_port_id_2 = uuidutils.generate_uuid()
|
||||
|
||||
# NOTE: The following is not supported so it is omitted
|
||||
# - "segmentationId"
|
||||
# - "addressRange"
|
||||
# - Multiple "cpProtocolData"
|
||||
# - Multiple "fixedAddresses"
|
||||
ext_vl_1 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vimConnectionId": vim_id_1,
|
||||
"resourceProviderId": "Company",
|
||||
"resourceId": net_ids['net0'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP1",
|
||||
"cpConfig": {
|
||||
"VDU1_CP1": {
|
||||
"parentCpConfigId": uuidutils.generate_uuid(),
|
||||
# "linkPortId": omitted,
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
# "macAddress": omitted,
|
||||
# "segmentationId": omitted,
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
# "fixedAddresses": omitted,
|
||||
"numDynamicAddresses": 1,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['subnet0']}]}}]
|
||||
},
|
||||
# { "VDU1_CP1_2": omitted }
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP1-1",
|
||||
"cpConfig": {
|
||||
"VDU2_CP1-1": {
|
||||
"parentCpConfigId": uuidutils.generate_uuid(),
|
||||
"linkPortId": link_port_id_1,
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
# "macAddress": omitted,
|
||||
# "segmentationId": omitted,
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
# "fixedAddresses": omitted,
|
||||
"numDynamicAddresses": 1,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['subnet0']
|
||||
}]
|
||||
}
|
||||
}]
|
||||
},
|
||||
# { "VDU2_CP1_2": omitted }
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP1-2",
|
||||
"cpConfig": {
|
||||
"VDU2_CP1-2": {
|
||||
"parentCpConfigId": uuidutils.generate_uuid(),
|
||||
"linkPortId": link_port_id_2,
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
# "macAddress": omitted,
|
||||
# "segmentationId": omitted,
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
# "fixedAddresses": omitted,
|
||||
"numDynamicAddresses": 1,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['subnet0']
|
||||
}]
|
||||
}
|
||||
}]
|
||||
},
|
||||
# { "VDU2_CP1_2": omitted }
|
||||
}
|
||||
}
|
||||
],
|
||||
"extLinkPorts": [
|
||||
{
|
||||
"id": link_port_id_1,
|
||||
"resourceHandle": {
|
||||
"resourceId": ports['VDU2_CP1-1']
|
||||
}
|
||||
},
|
||||
# NOTE: Set dummy value because it is set by "additionalParams"
|
||||
{
|
||||
"id": link_port_id_2,
|
||||
"resourceHandle": {
|
||||
"resourceId": "dummy-id"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# NOTE: The following is not supported so it is omitted
|
||||
# - "segmentationId"
|
||||
# - "addressRange"
|
||||
# - Multiple "cpProtocolData"
|
||||
# - Multiple "fixedAddresses"
|
||||
ext_vl_2 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vimConnectionId": vim_id_1,
|
||||
"resourceProviderId": "Company",
|
||||
"resourceId": net_ids['ft-net0'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP2",
|
||||
"cpConfig": {
|
||||
"VDU1_CP2": {
|
||||
"parentCpConfigId": uuidutils.generate_uuid(),
|
||||
# "linkPortId": omitted,
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
# "macAddress": omitted,
|
||||
# "segmentationId": omitted,
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
# "fixedAddresses": omitted,
|
||||
"numDynamicAddresses": 1,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['ft-ipv4-subnet0']}
|
||||
]}
|
||||
}]
|
||||
},
|
||||
# { "VDU1_CP2_2": omitted }
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP2",
|
||||
"cpConfig": {
|
||||
"VDU2_CP2": {
|
||||
"parentCpConfigId": uuidutils.generate_uuid(),
|
||||
# "linkPortId": omitted,
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"macAddress": "fa:16:3e:fa:22:75",
|
||||
# "segmentationId": omitted,
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": [
|
||||
"100.100.100.11",
|
||||
# omitted
|
||||
],
|
||||
# "numDynamicAddresses": omitted,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['ft-ipv4-subnet0']
|
||||
}, {
|
||||
"type": "IPV6",
|
||||
# "fixedAddresses": omitted,
|
||||
# "numDynamicAddresses": omitted,
|
||||
"numDynamicAddresses": 1,
|
||||
# "addressRange": omitted,
|
||||
"subnetId": subnets['ft-ipv6-subnet0']
|
||||
}]
|
||||
}
|
||||
}]
|
||||
},
|
||||
# { "VDU2_CP2_2": omitted }
|
||||
}
|
||||
}
|
||||
]
|
||||
# "extLinkPorts": omitted
|
||||
}
|
||||
# NOTE: "vnfLinkPort" is omitted because it is not supported
|
||||
ext_mngd_vl_1 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vnfVirtualLinkDescId": "internalVL1",
|
||||
"vimConnectionId": vim_id_1,
|
||||
"resourceProviderId": "Company",
|
||||
"resourceId": net_ids['net_mgmt'],
|
||||
# "vnfLinkPort": omitted,
|
||||
"extManagedMultisiteVirtualLinkId": uuidutils.generate_uuid()
|
||||
}
|
||||
# NOTE: "vnfLinkPort" is omitted because it is not supported
|
||||
ext_mngd_vl_2 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vnfVirtualLinkDescId": "internalVL2",
|
||||
"vimConnectionId": vim_id_1,
|
||||
"resourceProviderId": "Company",
|
||||
"resourceId": net_ids['net1'],
|
||||
# "vnfLinkPort": omitted,
|
||||
"extManagedMultisiteVirtualLinkId": uuidutils.generate_uuid()
|
||||
}
|
||||
vim_1 = {
|
||||
"vimId": vim_id_1,
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
|
||||
"interfaceInfo": {"endpoint": auth_url},
|
||||
"accessInfo": {
|
||||
"username": "nfv_user",
|
||||
"region": "RegionOne",
|
||||
"password": "devstack",
|
||||
"project": "nfv",
|
||||
"projectDomain": "Default",
|
||||
"userDomain": "Default"
|
||||
},
|
||||
"extra": {"dummy-key": "dummy-val"}
|
||||
}
|
||||
vim_2 = {
|
||||
"vimId": vim_id_2,
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
|
||||
"interfaceInfo": {"endpoint": auth_url},
|
||||
"accessInfo": {
|
||||
"username": "dummy_user",
|
||||
"region": "RegionOne",
|
||||
"password": "dummy_password",
|
||||
"project": "dummy_project",
|
||||
"projectDomain": "Default",
|
||||
"userDomain": "Default"
|
||||
},
|
||||
"extra": {"dummy-key": "dummy-val"}
|
||||
}
|
||||
addParams = {
|
||||
"lcm-operation-user-data": "./UserData/userdata.py",
|
||||
"lcm-operation-user-data-class": "UserData",
|
||||
"nfv": {"CP": {"VDU2_CP1-2": {"port": ports['VDU2_CP1-2']}}}
|
||||
}
|
||||
|
||||
return {
|
||||
"flavourId": "simple",
|
||||
"instantiationLevelId": "instantiation_level_1",
|
||||
"extVirtualLinks": [
|
||||
ext_vl_1,
|
||||
ext_vl_2
|
||||
],
|
||||
"extManagedVirtualLinks": [
|
||||
ext_mngd_vl_1,
|
||||
ext_mngd_vl_2
|
||||
],
|
||||
"vimConnectionInfo": {
|
||||
"vim1": vim_1,
|
||||
"vim2": vim_2
|
||||
},
|
||||
"localizationLanguage": "ja",
|
||||
"additionalParams": addParams,
|
||||
"extensions": {"dummy-key": "dummy-val"}
|
||||
}
|
||||
|
||||
|
||||
def sample2_create(vnfd_id):
|
||||
# Omit except for required attributes
|
||||
# NOTE: Only the following cardinality attributes are set.
|
||||
# - 1
|
||||
# - 1..N (1)
|
||||
return {
|
||||
"vnfdId": vnfd_id,
|
||||
}
|
||||
|
||||
|
||||
def sample2_terminate():
|
||||
# Omit except for required attributes
|
||||
# NOTE: Only the following cardinality attributes are set.
|
||||
# - 1
|
||||
# - 1..N (1)
|
||||
return {
|
||||
"terminationType": "FORCEFUL"
|
||||
}
|
||||
|
||||
|
||||
def sample1_instantiate(net_ids, subnet_ids, auth_url):
|
||||
ext_vl_1 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"resourceId": net_ids['net0'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP1",
|
||||
"cpConfig": {
|
||||
"VDU1_CP1_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1}]}}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP1",
|
||||
"cpConfig": {
|
||||
"VDU2_CP1_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": ["10.10.0.101"]}]}}]}
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
ext_vl_2 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"resourceId": net_ids['net1'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP2",
|
||||
"cpConfig": {
|
||||
"VDU1_CP2_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1,
|
||||
"subnetId": subnet_ids['subnet1']}]}}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP2",
|
||||
"cpConfig": {
|
||||
"VDU2_CP2_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": ["10.10.1.101"],
|
||||
"subnetId": subnet_ids['subnet1']}]}}]}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
def sample2_instantiate():
|
||||
# Omit except for required attributes
|
||||
# NOTE: Only the following cardinality attributes are set.
|
||||
# - 1
|
||||
# - 1..N (1)
|
||||
return {
|
||||
"flavourId": "simple",
|
||||
"instantiationLevelId": "instantiation_level_1",
|
||||
"extVirtualLinks": [
|
||||
ext_vl_1,
|
||||
ext_vl_2
|
||||
],
|
||||
"extManagedVirtualLinks": [
|
||||
{
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vnfVirtualLinkDescId": "internalVL1",
|
||||
"resourceId": net_ids['net_mgmt']
|
||||
},
|
||||
],
|
||||
"vimConnectionInfo": {
|
||||
"vim1": {
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
|
||||
"vimId": uuidutils.generate_uuid(),
|
||||
"interfaceInfo": {"endpoint": auth_url},
|
||||
"accessInfo": {
|
||||
"username": "nfv_user",
|
||||
"region": "RegionOne",
|
||||
"password": "devstack",
|
||||
"project": "nfv",
|
||||
"projectDomain": "Default",
|
||||
"userDomain": "Default"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def sample2_create(vnfd_id):
|
||||
return {
|
||||
"vnfdId": vnfd_id,
|
||||
"vnfInstanceName": "sample2",
|
||||
"vnfInstanceDescription": "test sample2"
|
||||
}
|
||||
|
||||
|
||||
def sample2_terminate():
|
||||
return {
|
||||
"terminationType": "GRACEFUL",
|
||||
"gracefulTerminationTimeout": 5
|
||||
}
|
||||
|
||||
|
||||
def sample2_instantiate(net_ids, subnet_ids, auth_url):
|
||||
ext_vl_1 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"resourceId": net_ids['net0'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP1",
|
||||
"cpConfig": {
|
||||
"VDU1_CP1_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1}]}}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP1",
|
||||
"cpConfig": {
|
||||
"VDU2_CP1_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": ["10.10.0.102"]}]}}]}
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
ext_vl_2 = {
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"resourceId": net_ids['net1'],
|
||||
"extCps": [
|
||||
{
|
||||
"cpdId": "VDU1_CP2",
|
||||
"cpConfig": {
|
||||
"VDU1_CP2_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"numDynamicAddresses": 1,
|
||||
"subnetId": subnet_ids['subnet1']}]}}]}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cpdId": "VDU2_CP2",
|
||||
"cpConfig": {
|
||||
"VDU2_CP2_1": {
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": [{
|
||||
"type": "IPV4",
|
||||
"fixedAddresses": ["10.10.1.102"],
|
||||
"subnetId": subnet_ids['subnet1']}]}}]}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return {
|
||||
"flavourId": "simple",
|
||||
"instantiationLevelId": "instantiation_level_1",
|
||||
"extVirtualLinks": [
|
||||
ext_vl_1,
|
||||
ext_vl_2
|
||||
],
|
||||
"extManagedVirtualLinks": [
|
||||
{
|
||||
"id": uuidutils.generate_uuid(),
|
||||
"vnfVirtualLinkDescId": "internalVL1",
|
||||
"resourceId": net_ids['net_mgmt']
|
||||
},
|
||||
],
|
||||
"vimConnectionInfo": {
|
||||
"vim1": {
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.V_3",
|
||||
"vimId": uuidutils.generate_uuid(),
|
||||
"interfaceInfo": {"endpoint": auth_url},
|
||||
"accessInfo": {
|
||||
"username": "nfv_user",
|
||||
"region": "RegionOne",
|
||||
"password": "devstack",
|
||||
"project": "nfv",
|
||||
"projectDomain": "Default",
|
||||
"userDomain": "Default"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalParams": {
|
||||
"lcm-operation-user-data": "./UserData/userdata_default.py",
|
||||
"lcm-operation-user-data-class": "DefaultUserData"
|
||||
}
|
||||
"flavourId": "simple"
|
||||
}
|
||||
|
@ -18,7 +18,9 @@ parameters:
|
||||
type: string
|
||||
net5:
|
||||
type: string
|
||||
subnet:
|
||||
subnet1:
|
||||
type: string
|
||||
subnet2:
|
||||
type: string
|
||||
|
||||
resources:
|
||||
@ -27,7 +29,7 @@ resources:
|
||||
properties:
|
||||
flavor: { get_param: flavor }
|
||||
name: VDU1
|
||||
block_device_mapping_v2: [{"volume_id": { get_resource: VirtualStorage }}]
|
||||
block_device_mapping_v2: [{"volume_id": { get_resource: VDU1-VirtualStorage }}]
|
||||
networks:
|
||||
- port:
|
||||
get_resource: VDU1_CP1
|
||||
@ -44,7 +46,7 @@ resources:
|
||||
|
||||
availability_zone: { get_param: zone }
|
||||
|
||||
VirtualStorage:
|
||||
VDU1-VirtualStorage:
|
||||
type: OS::Cinder::Volume
|
||||
properties:
|
||||
image: { get_param: image }
|
||||
@ -61,6 +63,8 @@ resources:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net1 }
|
||||
fixed_ips:
|
||||
- subnet: { get_param: subnet1}
|
||||
|
||||
# extVL with numDynamicAddresses and subnet
|
||||
VDU1_CP2:
|
||||
@ -68,7 +72,7 @@ resources:
|
||||
properties:
|
||||
network: { get_param: net2 }
|
||||
fixed_ips:
|
||||
- subnet: { get_param: subnet}
|
||||
- subnet: { get_param: subnet2}
|
||||
|
||||
# delete the following line when extmanagedVLs' Ports are specified in instantiatevnfrequest
|
||||
VDU1_CP3:
|
||||
|
@ -16,11 +16,12 @@ resources:
|
||||
type: VDU1.yaml
|
||||
properties:
|
||||
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
|
||||
image: { get_param: [ nfv, VDU, VirtualStorage, vcImageId ] }
|
||||
image: { get_param: [ nfv, VDU, VDU1-VirtualStorage, vcImageId ] }
|
||||
zone: { get_param: [ nfv, VDU, VDU1, locationConstraints] }
|
||||
net1: { get_param: [ nfv, CP, VDU1_CP1, network] }
|
||||
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }
|
||||
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet ]}
|
||||
subnet1: { get_param: [nfv, CP, VDU1_CP1, fixed_ips, 0, subnet ]}
|
||||
subnet2: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet ]}
|
||||
net3: { get_resource: internalVL1 }
|
||||
net4: { get_resource: internalVL2 }
|
||||
net5: { get_resource: internalVL3 }
|
||||
@ -44,11 +45,12 @@ resources:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] }
|
||||
image: { get_param: [ nfv, VDU, VDU2, vcImageId] }
|
||||
name: VDU2
|
||||
availability_zone: { get_param: [ nfv, VDU, VDU2, locationConstraints ] }
|
||||
block_device_mapping_v2: [{"volume_id": { get_resource: VDU2-VirtualStorage }}]
|
||||
networks:
|
||||
- port:
|
||||
get_resource: VDU2_CP1
|
||||
- port: { get_param: [ nfv, CP, VDU2_CP1-1, port ] }
|
||||
- port: { get_param: [ nfv, CP, VDU2_CP1-2, port ] }
|
||||
- port:
|
||||
get_resource: VDU2_CP2
|
||||
- port:
|
||||
@ -58,13 +60,17 @@ resources:
|
||||
- port:
|
||||
get_resource: VDU2_CP5
|
||||
|
||||
# extVL with FixedIP
|
||||
VDU2_CP1:
|
||||
type: OS::Neutron::Port
|
||||
VDU2-VirtualStorage:
|
||||
type: OS::Cinder::Volume
|
||||
properties:
|
||||
network: { get_param: [ nfv, CP, VDU2_CP1, network ] }
|
||||
fixed_ips:
|
||||
- ip_address: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, ip_address]}
|
||||
image: { get_param: [ nfv, VDU, VDU2-VirtualStorage, vcImageId] }
|
||||
size: 1
|
||||
volume_type: { get_resource: multi }
|
||||
multi:
|
||||
type: OS::Cinder::VolumeType
|
||||
properties:
|
||||
name: VDU2-multi
|
||||
metadata: { multiattach: "<is> True" }
|
||||
|
||||
# extVL with FixedIP and Subnet
|
||||
VDU2_CP2:
|
||||
@ -74,6 +80,7 @@ resources:
|
||||
fixed_ips:
|
||||
- ip_address: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, ip_address]}
|
||||
subnet: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, subnet]}
|
||||
- subnet: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 1, subnet]}
|
||||
|
||||
VDU2_CP3:
|
||||
type: OS::Neutron::Port
|
||||
|
@ -34,7 +34,8 @@ topology_template:
|
||||
flavour_id: simple
|
||||
requirements:
|
||||
virtual_link_external1_1: [ VDU1_CP1, virtual_link ]
|
||||
virtual_link_external1_2: [ VDU2_CP1, virtual_link ]
|
||||
virtual_link_external1_2: [ VDU2_CP1-1, virtual_link ]
|
||||
virtual_link_external1_3: [ VDU2_CP1-2, virtual_link ]
|
||||
virtual_link_external2_1: [ VDU1_CP2, virtual_link ]
|
||||
virtual_link_external2_2: [ VDU2_CP2, virtual_link ]
|
||||
|
||||
@ -79,7 +80,7 @@ topology_template:
|
||||
virtual_local_storage:
|
||||
- size_of_storage: 3 GB
|
||||
requirements:
|
||||
- virtual_storage: VirtualStorage
|
||||
- virtual_storage: VDU1-VirtualStorage
|
||||
|
||||
VDU2:
|
||||
type: tosca.nodes.nfv.Vdu.Compute
|
||||
@ -89,17 +90,6 @@ topology_template:
|
||||
vdu_profile:
|
||||
min_number_of_instances: 1
|
||||
max_number_of_instances: 1
|
||||
sw_image_data:
|
||||
name: VDU2-image
|
||||
version: '0.5.2'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||
container_format: bare
|
||||
disk_format: qcow2
|
||||
min_disk: 0 GB
|
||||
min_ram: 256 MB
|
||||
size: 12 GB
|
||||
capabilities:
|
||||
virtual_compute:
|
||||
properties:
|
||||
@ -115,19 +105,17 @@ topology_template:
|
||||
num_virtual_cpu: 1
|
||||
virtual_local_storage:
|
||||
- size_of_storage: 3 GB
|
||||
artifacts:
|
||||
sw_image:
|
||||
type: tosca.artifacts.nfv.SwImage
|
||||
file: ../Files/images/cirros-0.5.2-x86_64-disk.img
|
||||
requirements:
|
||||
- virtual_storage: VDU2-VirtualStorage
|
||||
|
||||
VirtualStorage:
|
||||
VDU1-VirtualStorage:
|
||||
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
|
||||
properties:
|
||||
virtual_block_storage_data:
|
||||
size_of_storage: 1 GB
|
||||
rdma_enabled: true
|
||||
sw_image_data:
|
||||
name: cirros-0.5.2-x86_64-disk
|
||||
name: VDU1-VirtualStorage-image
|
||||
version: '0.5.2'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
@ -137,6 +125,32 @@ topology_template:
|
||||
min_disk: 0 GB
|
||||
min_ram: 256 MB
|
||||
size: 12 GB
|
||||
artifacts:
|
||||
sw_image:
|
||||
type: tosca.artifacts.nfv.SwImage
|
||||
file: ../Files/images/cirros-0.5.2-x86_64-disk.img
|
||||
|
||||
VDU2-VirtualStorage:
|
||||
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
|
||||
properties:
|
||||
virtual_block_storage_data:
|
||||
size_of_storage: 1 GB
|
||||
rdma_enabled: true
|
||||
sw_image_data:
|
||||
name: VDU2-VirtualStorage-image
|
||||
version: '0.5.2'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||
container_format: bare
|
||||
disk_format: qcow2
|
||||
min_disk: 0 GB
|
||||
min_ram: 256 MB
|
||||
size: 12 GB
|
||||
artifacts:
|
||||
sw_image:
|
||||
type: tosca.artifacts.nfv.SwImage
|
||||
file: ../Files/images/cirros-0.5.2-x86_64-disk.img
|
||||
|
||||
VDU1_CP1:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
@ -181,7 +195,7 @@ topology_template:
|
||||
- virtual_binding: VDU1
|
||||
- virtual_link: internalVL3
|
||||
|
||||
VDU2_CP1:
|
||||
VDU2_CP1-1:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
@ -189,7 +203,7 @@ topology_template:
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
|
||||
VDU2_CP2:
|
||||
VDU2_CP1-2:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
@ -197,20 +211,28 @@ topology_template:
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
|
||||
VDU2_CP3:
|
||||
VDU2_CP2:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 2
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
|
||||
VDU2_CP3:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 3
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL1
|
||||
|
||||
VDU2_CP4:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 3
|
||||
order: 4
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL2
|
||||
@ -219,7 +241,7 @@ topology_template:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 4
|
||||
order: 5
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL3
|
||||
|
@ -0,0 +1,67 @@
|
||||
# Copyright (C) 2021 Nippon Telegraph and Telephone Corporation
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
|
||||
class SampleScript(object):
|
||||
|
||||
def __init__(self, req, inst, grant_req, grant, csar_dir):
|
||||
self.req = req
|
||||
self.inst = inst
|
||||
self.grant_req = grant_req
|
||||
self.grant = grant
|
||||
self.csar_dir = csar_dir
|
||||
|
||||
def instantiate_start(self):
|
||||
pass
|
||||
|
||||
def instantiate_end(self):
|
||||
pass
|
||||
|
||||
def terminate_start(self):
|
||||
pass
|
||||
|
||||
def terminate_end(self):
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
script_dict = pickle.load(sys.stdin.buffer)
|
||||
|
||||
operation = script_dict['operation']
|
||||
req = script_dict['request']
|
||||
inst = script_dict['vnf_instance']
|
||||
grant_req = script_dict['grant_request']
|
||||
grant = script_dict['grant_response']
|
||||
csar_dir = script_dict['tmp_csar_dir']
|
||||
|
||||
script = SampleScript(req, inst, grant_req, grant, csar_dir)
|
||||
try:
|
||||
getattr(script, operation)()
|
||||
except AttributeError:
|
||||
raise Exception("{} is not included in the script.".format(operation))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
os._exit(0)
|
||||
except Exception as ex:
|
||||
sys.stderr.write(str(ex))
|
||||
sys.stderr.flush()
|
||||
os._exit(1)
|
@ -19,10 +19,34 @@ from tacker.sol_refactored.common import vnf_instance_utils as inst_utils
|
||||
from tacker.sol_refactored.infra_drivers.openstack import userdata_utils
|
||||
|
||||
|
||||
class DefaultUserData(userdata_utils.AbstractUserData):
|
||||
class UserData(userdata_utils.AbstractUserData):
|
||||
|
||||
@staticmethod
|
||||
def instantiate(req, inst, grant_req, grant, tmp_csar_dir):
|
||||
def _get_param_port(cp_name, grant, req):
|
||||
# see grant first then instantiateVnfRequest
|
||||
vls = grant.get('extVirtualLinks', []) + req.get('extVirtualLinks',
|
||||
[])
|
||||
port_ids = []
|
||||
for vl in vls:
|
||||
link_port_ids = []
|
||||
for extcp in vl['extCps']:
|
||||
if extcp['cpdId'] == cp_name:
|
||||
link_port_ids = _get_link_port_ids_from_extcp(extcp)
|
||||
if 'extLinkPorts' not in vl:
|
||||
continue
|
||||
for extlp in vl['extLinkPorts']:
|
||||
if extlp['id'] in link_port_ids:
|
||||
port_ids.append(extlp['resourceHandle']['resourceId'])
|
||||
return port_ids
|
||||
|
||||
def _get_link_port_ids_from_extcp(extcp):
|
||||
link_port_ids = []
|
||||
for cp_conf in extcp['cpConfig'].values():
|
||||
if 'linkPortId' in cp_conf:
|
||||
link_port_ids.append(cp_conf['linkPortId'])
|
||||
return link_port_ids
|
||||
|
||||
vnfd = userdata_utils.get_vnfd(inst['vnfdId'], tmp_csar_dir)
|
||||
flavour_id = req['flavourId']
|
||||
|
||||
@ -65,6 +89,16 @@ class DefaultUserData(userdata_utils.AbstractUserData):
|
||||
'ip_address')
|
||||
fixed_ips.append(ips_i)
|
||||
cp_value['fixed_ips'] = fixed_ips
|
||||
# NOTE: In the case where multiple cpConfigs corresponding
|
||||
# to a single cpdId are defined, always get the first element
|
||||
# of cpConfig. This is because, according to the current
|
||||
# SOL definitions, the key of cpConfig is the ID managed by
|
||||
# the API consumer, and it is not possible to uniquely determine
|
||||
# which element of cpConfig should be selected by cpdId.
|
||||
# See SOL003 v3.3.1 4.4.1.10 Type: VnfExtCpData.
|
||||
if 'port' in cp_value:
|
||||
cp_value['port'] = _get_param_port(
|
||||
cp_name, grant, req).pop()
|
||||
|
||||
userdata_utils.apply_ext_managed_vls(top_hot, req, grant)
|
||||
|
@ -42,11 +42,22 @@ shutil.rmtree(tmp_dir)
|
||||
create_req = paramgen.sample1_create(vnfd_id)
|
||||
terminate_req = paramgen.sample1_terminate()
|
||||
|
||||
net_ids = utils.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||
subnet_ids = utils.get_subnet_ids(['subnet0', 'subnet1'])
|
||||
print('#####################################################################\n'
|
||||
'# Run pre.py if an error occurs #\n'
|
||||
'# - If an error occurs, run the pre.py script in advance #\n'
|
||||
'# to create the openstack resource required to run this script. #\n'
|
||||
'# Run post.py when you finish tests #\n'
|
||||
'# - When you no longer need these openstack resources #\n'
|
||||
'# after testing, run post.py and delete them. #\n'
|
||||
'#####################################################################')
|
||||
|
||||
net_ids = utils.get_network_ids(['net0', 'net1', 'net_mgmt', 'ft-net0'])
|
||||
subnet_ids = utils.get_subnet_ids(
|
||||
['subnet0', 'subnet1', 'ft-ipv4-subnet0', 'ft-ipv6-subnet0'])
|
||||
port_ids = utils.get_port_ids(['VDU2_CP1-1', 'VDU2_CP1-2'])
|
||||
|
||||
instantiate_req = paramgen.sample1_instantiate(
|
||||
net_ids, subnet_ids, "http://localhost/identity/v3")
|
||||
net_ids, subnet_ids, port_ids, "http://localhost/identity/v3")
|
||||
|
||||
with open("create_req", "w") as f:
|
||||
f.write(json.dumps(create_req, indent=2))
|
||||
|
20
tacker/tests/functional/sol_v2/samples/sample1/post.py
Normal file
20
tacker/tests/functional/sol_v2/samples/sample1/post.py
Normal file
@ -0,0 +1,20 @@
|
||||
# Copyright (C) 2021 Nippon Telegraph and Telephone Corporation
|
||||
# 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.
|
||||
from tacker.tests.functional.sol_v2 import utils
|
||||
|
||||
utils.delete_network('ft-net0')
|
||||
# NOTE: subnet is automatically deleted by network deletion
|
||||
utils.delete_port('VDU2_CP1-1')
|
||||
utils.delete_port('VDU2_CP1-2')
|
21
tacker/tests/functional/sol_v2/samples/sample1/pre.py
Normal file
21
tacker/tests/functional/sol_v2/samples/sample1/pre.py
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2021 Nippon Telegraph and Telephone Corporation
|
||||
# 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.
|
||||
from tacker.tests.functional.sol_v2 import utils
|
||||
|
||||
utils.create_network('ft-net0')
|
||||
utils.create_subnet('ft-ipv4-subnet0', 'ft-net0', '100.100.100.0/24', '4')
|
||||
utils.create_subnet('ft-ipv6-subnet0', 'ft-net0', '1111:2222:3333::/64', '6')
|
||||
utils.create_port('VDU2_CP1-1', 'net0')
|
||||
utils.create_port('VDU2_CP1-2', 'net0')
|
@ -6,84 +6,25 @@ parameters:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
net1:
|
||||
type: string
|
||||
net2:
|
||||
type: string
|
||||
net3:
|
||||
type: string
|
||||
net4:
|
||||
type: string
|
||||
net5:
|
||||
type: string
|
||||
subnet:
|
||||
affinity:
|
||||
type: string
|
||||
# uncomment when BUG "https://storyboard.openstack.org/#!/story/2009164" fixed
|
||||
# affinity:
|
||||
# type: string
|
||||
|
||||
resources:
|
||||
VDU1:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
flavor: { get_param: flavor }
|
||||
image: { get_param: image }
|
||||
name: VDU1
|
||||
block_device_mapping_v2: [{"volume_id": { get_resource: VirtualStorage }}]
|
||||
networks:
|
||||
- port:
|
||||
get_resource: VDU1_CP1
|
||||
- port:
|
||||
get_resource: VDU1_CP2
|
||||
# replace the following line to Port ID when extmanagedVLs' Ports are specified in instantiatevnfrequest
|
||||
- port:
|
||||
get_resource: VDU1_CP3
|
||||
- port:
|
||||
get_resource: VDU1_CP4
|
||||
- port:
|
||||
get_resource: VDU1_CP5
|
||||
scheduler_hints:
|
||||
group: {get_param: affinity }
|
||||
|
||||
# uncomment when BUG "https://storyboard.openstack.org/#!/story/2009164" fixed
|
||||
# scheduler_hints:
|
||||
# group: {get_param: affinity }
|
||||
|
||||
VirtualStorage:
|
||||
type: OS::Cinder::Volume
|
||||
properties:
|
||||
image: { get_param: image }
|
||||
size: 1
|
||||
volume_type: { get_resource: multi }
|
||||
multi:
|
||||
type: OS::Cinder::VolumeType
|
||||
properties:
|
||||
name: { get_resource: VDU1_CP1 }
|
||||
metadata: { multiattach: "<is> True" }
|
||||
|
||||
# extVL without FixedIP or with numDynamicAddresses
|
||||
VDU1_CP1:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net1 }
|
||||
|
||||
# extVL with numDynamicAddresses and subnet
|
||||
VDU1_CP2:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net2 }
|
||||
fixed_ips:
|
||||
- subnet: { get_param: subnet}
|
||||
|
||||
# CPs of internal VLs are deleted when extmangaedVLs and port are specified in instantiatevnfrequest
|
||||
VDU1_CP3:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net3 }
|
||||
|
||||
VDU1_CP4:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net4 }
|
||||
|
||||
VDU1_CP5:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: net5 }
|
||||
|
@ -16,15 +16,9 @@ resources:
|
||||
type: VDU1.yaml
|
||||
properties:
|
||||
flavor: { get_param: [ nfv, VDU, VDU1, computeFlavourId ] }
|
||||
image: { get_param: [ nfv, VDU, VirtualStorage, vcImageId ] }
|
||||
net1: { get_param: [ nfv, CP, VDU1_CP1, network ] }
|
||||
net2: { get_param: [ nfv, CP, VDU1_CP2, network ] }
|
||||
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet ]}
|
||||
net3: { get_resource: internalVL1 }
|
||||
net4: { get_resource: internalVL2 }
|
||||
image: { get_param: [ nfv, VDU, VDU1, vcImageId ] }
|
||||
net5: { get_resource: internalVL3 }
|
||||
# uncomment when BUG "https://storyboard.openstack.org/#!/story/2009164" fixed
|
||||
# affinity: { get_resource: nfvi_node_affinity }
|
||||
affinity: { get_resource: nfvi_node_affinity }
|
||||
VDU1_scale_out:
|
||||
type: OS::Heat::ScalingPolicy
|
||||
properties:
|
||||
@ -44,80 +38,23 @@ resources:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
flavor: { get_param: [ nfv, VDU, VDU2, computeFlavourId ] }
|
||||
name: VDU2
|
||||
image: { get_param: [ nfv, VDU, VDU2, vcImageId] }
|
||||
networks:
|
||||
- port:
|
||||
get_resource: VDU2_CP1
|
||||
- port:
|
||||
get_resource: VDU2_CP2
|
||||
- port:
|
||||
get_resource: VDU2_CP3
|
||||
- port:
|
||||
get_resource: VDU2_CP4
|
||||
- port:
|
||||
get_resource: VDU2_CP5
|
||||
# uncomment when BUG "https://storyboard.openstack.org/#!/story/2009164" fixed
|
||||
# scheduler_hints:
|
||||
# group: {get_resource: nfvi_node_affinity }
|
||||
scheduler_hints:
|
||||
group: {get_resource: nfvi_node_affinity }
|
||||
|
||||
# extVL with FixedIP
|
||||
VDU2_CP1:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: [ nfv, CP, VDU2_CP1, network ] }
|
||||
fixed_ips:
|
||||
- ip_address: { get_param: [nfv, CP, VDU2_CP1, fixed_ips, 0, ip_address]}
|
||||
|
||||
# extVL with FixedIP and Subnet
|
||||
VDU2_CP2:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
network: { get_param: [ nfv, CP, VDU2_CP2, network ] }
|
||||
fixed_ips:
|
||||
- ip_address: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, ip_address]}
|
||||
subnet: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, subnet]}
|
||||
|
||||
VDU2_CP3:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
|
||||
network: { get_resource: internalVL1 }
|
||||
|
||||
VDU2_CP4:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
|
||||
network: { get_resource: internalVL2 }
|
||||
|
||||
VDU2_CP5:
|
||||
type: OS::Neutron::Port
|
||||
properties:
|
||||
# replace the following line to VL's ID when extmanagedVLs are specified in instantiatevnfrequest
|
||||
network: { get_resource: internalVL3 }
|
||||
|
||||
# delete the following lines when extmanagedVLs are specified in instantiatevnfrequest
|
||||
internalVL1:
|
||||
type: OS::Neutron::Net
|
||||
internalVL2:
|
||||
type: OS::Neutron::Net
|
||||
internalVL3:
|
||||
type: OS::Neutron::Net
|
||||
|
||||
|
||||
internalVL1_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
ip_version: 4
|
||||
network:
|
||||
get_resource: internalVL1
|
||||
cidr: 192.168.3.0/24
|
||||
internalVL2_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
ip_version: 4
|
||||
network:
|
||||
get_resource: internalVL2
|
||||
cidr: 192.168.4.0/24
|
||||
internalVL3_subnet:
|
||||
type: OS::Neutron::Subnet
|
||||
properties:
|
||||
@ -126,11 +63,10 @@ resources:
|
||||
get_resource: internalVL3
|
||||
cidr: 192.168.5.0/24
|
||||
|
||||
# uncomment when BUG "https://storyboard.openstack.org/#!/story/2009164" fixed
|
||||
# nfvi_node_affinity:
|
||||
# type: OS::Nova::ServerGroup
|
||||
# properties:
|
||||
# name: nfvi_node_affinity
|
||||
# policies: [ 'affinity' ]
|
||||
nfvi_node_affinity:
|
||||
type: OS::Nova::ServerGroup
|
||||
properties:
|
||||
name: nfvi_node_affinity
|
||||
policies: [ 'affinity' ]
|
||||
|
||||
outputs: {}
|
||||
|
@ -32,11 +32,6 @@ topology_template:
|
||||
node_type: company.provider.VNF
|
||||
properties:
|
||||
flavour_id: simple
|
||||
requirements:
|
||||
virtual_link_external1_1: [ VDU1_CP1, virtual_link ]
|
||||
virtual_link_external1_2: [ VDU2_CP1, virtual_link ]
|
||||
virtual_link_external2_1: [ VDU1_CP2, virtual_link ]
|
||||
virtual_link_external2_2: [ VDU2_CP2, virtual_link ]
|
||||
|
||||
node_templates:
|
||||
VNF:
|
||||
@ -67,6 +62,17 @@ topology_template:
|
||||
vdu_profile:
|
||||
min_number_of_instances: 1
|
||||
max_number_of_instances: 3
|
||||
sw_image_data:
|
||||
name: cirros-0.5.2-x86_64-disk
|
||||
version: '0.5.2'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||
container_format: bare
|
||||
disk_format: qcow2
|
||||
min_disk: 0 GB
|
||||
min_ram: 256 MB
|
||||
size: 12 GB
|
||||
capabilities:
|
||||
virtual_compute:
|
||||
properties:
|
||||
@ -82,8 +88,6 @@ topology_template:
|
||||
num_virtual_cpu: 1
|
||||
virtual_local_storage:
|
||||
- size_of_storage: 3 GB
|
||||
requirements:
|
||||
- virtual_storage: VirtualStorage
|
||||
|
||||
VDU2:
|
||||
type: tosca.nodes.nfv.Vdu.Compute
|
||||
@ -120,59 +124,7 @@ topology_template:
|
||||
virtual_local_storage:
|
||||
- size_of_storage: 3 GB
|
||||
|
||||
VirtualStorage:
|
||||
type: tosca.nodes.nfv.Vdu.VirtualBlockStorage
|
||||
properties:
|
||||
virtual_block_storage_data:
|
||||
size_of_storage: 1 GB
|
||||
rdma_enabled: true
|
||||
sw_image_data:
|
||||
name: cirros-0.5.2-x86_64-disk
|
||||
version: '0.5.2'
|
||||
checksum:
|
||||
algorithm: sha-256
|
||||
hash: 932fcae93574e242dc3d772d5235061747dfe537668443a1f0567d893614b464
|
||||
container_format: bare
|
||||
disk_format: qcow2
|
||||
min_disk: 0 GB
|
||||
min_ram: 256 MB
|
||||
size: 12 GB
|
||||
|
||||
VDU1_CP1:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 0
|
||||
requirements:
|
||||
- virtual_binding: VDU1
|
||||
|
||||
VDU1_CP2:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 1
|
||||
requirements:
|
||||
- virtual_binding: VDU1
|
||||
|
||||
VDU1_CP3:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 2
|
||||
requirements:
|
||||
- virtual_binding: VDU1
|
||||
- virtual_link: internalVL1
|
||||
|
||||
VDU1_CP4:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 3
|
||||
requirements:
|
||||
- virtual_binding: VDU1
|
||||
- virtual_link: internalVL2
|
||||
|
||||
VDU1_CP5:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
@ -182,40 +134,6 @@ topology_template:
|
||||
- virtual_link: internalVL3
|
||||
|
||||
VDU2_CP1:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 0
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
|
||||
VDU2_CP2:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 1
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
|
||||
VDU2_CP3:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 2
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL1
|
||||
|
||||
VDU2_CP4:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
order: 3
|
||||
requirements:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL2
|
||||
|
||||
VDU2_CP5:
|
||||
type: tosca.nodes.nfv.VduCp
|
||||
properties:
|
||||
layer_protocols: [ ipv4 ]
|
||||
@ -224,44 +142,6 @@ topology_template:
|
||||
- virtual_binding: VDU2
|
||||
- virtual_link: internalVL3
|
||||
|
||||
internalVL1:
|
||||
type: tosca.nodes.nfv.VnfVirtualLink
|
||||
properties:
|
||||
connectivity_type:
|
||||
layer_protocols: [ ipv4 ]
|
||||
description: External Managed Virtual link in the VNF
|
||||
vl_profile:
|
||||
max_bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
min_bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
virtual_link_protocol_data:
|
||||
- associated_layer_protocol: ipv4
|
||||
l3_protocol_data:
|
||||
ip_version: ipv4
|
||||
cidr: 192.168.3.0/24
|
||||
|
||||
internalVL2:
|
||||
type: tosca.nodes.nfv.VnfVirtualLink
|
||||
properties:
|
||||
connectivity_type:
|
||||
layer_protocols: [ ipv4 ]
|
||||
description: External Managed Virtual link in the VNF
|
||||
vl_profile:
|
||||
max_bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
min_bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
virtual_link_protocol_data:
|
||||
- associated_layer_protocol: ipv4
|
||||
l3_protocol_data:
|
||||
ip_version: ipv4
|
||||
cidr: 192.168.4.0/24
|
||||
|
||||
internalVL3:
|
||||
type: tosca.nodes.nfv.VnfVirtualLink
|
||||
properties:
|
||||
@ -357,34 +237,6 @@ topology_template:
|
||||
number_of_instances: 1
|
||||
targets: [ VDU2 ]
|
||||
|
||||
- internalVL1_instantiation_levels:
|
||||
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||
properties:
|
||||
levels:
|
||||
instantiation_level_1:
|
||||
bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
instantiation_level_2:
|
||||
bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
targets: [ internalVL1 ]
|
||||
|
||||
- internalVL2_instantiation_levels:
|
||||
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||
properties:
|
||||
levels:
|
||||
instantiation_level_1:
|
||||
bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
instantiation_level_2:
|
||||
bitrate_requirements:
|
||||
root: 1048576
|
||||
leaf: 1048576
|
||||
targets: [ internalVL2 ]
|
||||
|
||||
- internalVL3_instantiation_levels:
|
||||
type: tosca.policies.nfv.VirtualLinkInstantiationLevels
|
||||
properties:
|
||||
|
@ -34,12 +34,7 @@ shutil.rmtree(tmp_dir)
|
||||
|
||||
create_req = paramgen.sample2_create(vnfd_id)
|
||||
terminate_req = paramgen.sample2_terminate()
|
||||
|
||||
net_ids = utils.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||
subnet_ids = utils.get_subnet_ids(['subnet0', 'subnet1'])
|
||||
|
||||
instantiate_req = paramgen.sample2_instantiate(
|
||||
net_ids, subnet_ids, "http://localhost/identity/v3")
|
||||
instantiate_req = paramgen.sample2_instantiate()
|
||||
|
||||
with open("create_req", "w") as f:
|
||||
f.write(json.dumps(create_req, indent=2))
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
import os
|
||||
import time
|
||||
|
||||
@ -20,6 +21,7 @@ from tacker.tests.functional.sol_v2 import base_v2
|
||||
from tacker.tests.functional.sol_v2 import paramgen
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
|
||||
@classmethod
|
||||
@ -53,10 +55,18 @@ class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
super(VnfLcmTest, self).setUp()
|
||||
|
||||
def test_api_versions(self):
|
||||
"""Test version operations
|
||||
|
||||
* About version operations:
|
||||
This test includes the following operations.
|
||||
- 1. List VNFLCM API versions
|
||||
- 2. Show VNFLCM API versions
|
||||
"""
|
||||
path = "/vnflcm/api_versions"
|
||||
resp, body = self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
expected_body = {
|
||||
"uriPrefix": "/vnflcm",
|
||||
"apiVersions": [
|
||||
@ -70,6 +80,7 @@ class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
resp, body = self.tacker_client.do_request(
|
||||
path, "GET", version="2.0.0")
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
expected_body = {
|
||||
"uriPrefix": "/vnflcm/v2",
|
||||
"apiVersions": [
|
||||
@ -78,29 +89,334 @@ class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
}
|
||||
self.assertEqual(body, expected_body)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_subscriptions(self, is_all):
|
||||
"""Test subscription operations
|
||||
|
||||
* About attributes:
|
||||
- is_all=True
|
||||
All of the following cardinality attributes are set.
|
||||
In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
- 0..1 (1)
|
||||
- 0..N (2 or more)
|
||||
- 1
|
||||
- 1..N (2 or more)
|
||||
- is_all=False
|
||||
Omit except for required attributes.
|
||||
Only the following cardinality attributes are set.
|
||||
- 1
|
||||
- 1..N (1)
|
||||
|
||||
* About subscription operations:
|
||||
This test includes the following operations.
|
||||
- 0. Pre-setting
|
||||
- 1. Create a new subscription
|
||||
- 2. Show subscription
|
||||
- 3. List subscription with attribute-based filtering
|
||||
- 4. Delete a subscription
|
||||
"""
|
||||
# NOTE: Skip notification endpoint testing in subscription creation
|
||||
# by setting "v2_nfvo.test_callback_uri = False" to 'tacker.conf'
|
||||
# in '.zuul.yaml'.
|
||||
|
||||
# 0. Pre-setting
|
||||
sub_req = paramgen.sub2_create()
|
||||
if is_all:
|
||||
sub_req = paramgen.sub1_create()
|
||||
|
||||
# 1. Create a new subscription
|
||||
resp, body = self.create_subscription(sub_req)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.check_resp_headers_in_create(resp)
|
||||
sub_id = body['id']
|
||||
|
||||
# 2. Show subscription
|
||||
expected_attrs = [
|
||||
'id', 'callbackUri', 'verbosity', '_links'
|
||||
]
|
||||
if is_all:
|
||||
additional_attrs = ['filter']
|
||||
expected_attrs.extend(additional_attrs)
|
||||
|
||||
resp, body = self.show_subscription(sub_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.check_resp_body(body, expected_attrs)
|
||||
|
||||
# 3. List subscription with attribute-based filtering
|
||||
filter_expr = {'filter': '(eq,id,%s)' % sub_id}
|
||||
resp, body = self.list_subscriptions(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for sbsc in body:
|
||||
self.check_resp_body(sbsc, expected_attrs)
|
||||
|
||||
# 4. Delete a subscription
|
||||
resp, body = self.delete_subscription(sub_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
self.check_resp_headers_in_delete(resp)
|
||||
|
||||
def test_sample1(self):
|
||||
"""Test LCM operations with all attributes set
|
||||
|
||||
* About attributes:
|
||||
All of the following cardinality attributes are set.
|
||||
In addition, 0..N or 1..N attributes are set to 2 or more.
|
||||
- 0..1 (1)
|
||||
- 0..N (2 or more)
|
||||
- 1
|
||||
- 1..N (2 or more)
|
||||
|
||||
* About LCM operations:
|
||||
This test includes the following operations.
|
||||
- 0. Pre-setting
|
||||
- 1. Create a new VNF instance resource
|
||||
- 2. Instantiate a VNF instance
|
||||
- 3. Show VNF instance
|
||||
- 4. List VNF instance with attribute-based filtering
|
||||
- 5. Show VNF LCM operation occurrence
|
||||
- 6. List VNF LCM operation occurrence with attribute-based filtering
|
||||
- 7. Terminate a VNF instance
|
||||
- 8. Delete a VNF instance
|
||||
"""
|
||||
# 0. Pre-setting
|
||||
# Create a new network and subnet to check the IP allocation of
|
||||
# IPv4 and IPv6
|
||||
ft_net0_name = 'ft-net0'
|
||||
ft_net0_subs = {
|
||||
'ft-ipv4-subnet0': {
|
||||
'range': '100.100.100.0/24',
|
||||
'ip_version': 4
|
||||
},
|
||||
'ft-ipv6-subnet0': {
|
||||
'range': '1111:2222:3333::/64',
|
||||
'ip_version': 6
|
||||
}
|
||||
}
|
||||
ft_net0_id = self.create_network(ft_net0_name)
|
||||
self.addCleanup(self.delete_network, ft_net0_id)
|
||||
for sub_name, val in ft_net0_subs.items():
|
||||
# subnet is automatically deleted with network deletion
|
||||
self.create_subnet(
|
||||
ft_net0_id, sub_name, val['range'], val['ip_version'])
|
||||
|
||||
net_ids = self.get_network_ids(
|
||||
['net0', 'net1', 'net_mgmt', 'ft-net0'])
|
||||
subnet_ids = self.get_subnet_ids(
|
||||
['subnet0', 'subnet1', 'ft-ipv4-subnet0', 'ft-ipv6-subnet0'])
|
||||
|
||||
port_names = ['VDU2_CP1-1', 'VDU2_CP1-2']
|
||||
port_ids = {}
|
||||
for port_name in port_names:
|
||||
port_id = self.create_port(net_ids['net0'], port_name)
|
||||
port_ids[port_name] = port_id
|
||||
self.addCleanup(self.delete_port, port_id)
|
||||
|
||||
# 1. Create a new VNF instance resource
|
||||
# NOTE: extensions and vnfConfigurableProperties are omitted
|
||||
# because they are commented out in etsi_nfv_sol001.
|
||||
expected_inst_attrs = [
|
||||
'id',
|
||||
'vnfInstanceName',
|
||||
'vnfInstanceDescription',
|
||||
'vnfdId',
|
||||
'vnfProvider',
|
||||
'vnfProductName',
|
||||
'vnfSoftwareVersion',
|
||||
'vnfdVersion',
|
||||
# 'vnfConfigurableProperties', # omitted
|
||||
# 'vimConnectionInfo', # omitted
|
||||
'instantiationState',
|
||||
# 'instantiatedVnfInfo', # omitted
|
||||
'metadata',
|
||||
# 'extensions', # omitted
|
||||
'_links'
|
||||
]
|
||||
create_req = paramgen.sample1_create(self.vnfd_id_1)
|
||||
resp, body = self.create_vnf_instance(create_req)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.check_resp_headers_in_create(resp)
|
||||
self.check_resp_body(body, expected_inst_attrs)
|
||||
inst_id = body['id']
|
||||
|
||||
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
|
||||
# check usageState of VNF Package
|
||||
usage_state = self.get_vnf_package(self.vnf_pkg_1).get('usageState')
|
||||
self.assertEqual('IN_USE', usage_state)
|
||||
|
||||
# 2. Instantiate a VNF instance
|
||||
instantiate_req = paramgen.sample1_instantiate(
|
||||
net_ids, subnet_ids, self.auth_url)
|
||||
net_ids, subnet_ids, port_ids, self.auth_url)
|
||||
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.check_resp_headers_in_operation_task(resp)
|
||||
|
||||
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||
self.wait_lcmocc_complete(lcmocc_id)
|
||||
|
||||
# check creation of Heat-stack
|
||||
stack_name = "vnf-{}".format(inst_id)
|
||||
stack_status, _ = self.heat_client.get_status(stack_name)
|
||||
self.assertEqual("CREATE_COMPLETE", stack_status)
|
||||
|
||||
# check creation of Glance-image
|
||||
image_name_list = ['VDU1-VirtualStorage-image',
|
||||
'VDU2-VirtualStorage-image']
|
||||
for image_name in image_name_list:
|
||||
image_id = self.get_image_id(image_name)
|
||||
self.assertIsNotNone(image_id)
|
||||
|
||||
# check that the servers set in "zone:Affinity" are
|
||||
# deployed on 'nova' AZ.
|
||||
# NOTE: local_nfvo returns this AZ
|
||||
vdu1_details = self.get_server_details('VDU1')
|
||||
vdu2_details = self.get_server_details('VDU2')
|
||||
vdu1_az = vdu1_details.get('OS-EXT-AZ:availability_zone')
|
||||
vdu2_az = vdu2_details.get('OS-EXT-AZ:availability_zone')
|
||||
self.assertEqual('nova', vdu1_az)
|
||||
self.assertEqual('nova', vdu2_az)
|
||||
|
||||
# 3. Show VNF instance
|
||||
additional_inst_attrs = [
|
||||
'vimConnectionInfo',
|
||||
'instantiatedVnfInfo'
|
||||
]
|
||||
expected_inst_attrs.extend(additional_inst_attrs)
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
# TODO(oda-g): check body
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.check_resp_body(body, expected_inst_attrs)
|
||||
|
||||
# 4. List VNF instance with attribute-based filtering
|
||||
# check attribute-based filtering on VNF instance
|
||||
# NOTE: extensions and vnfConfigurableProperties are omitted
|
||||
# because they are commented out in etsi_nfv_sol001.
|
||||
# * all_fields
|
||||
# -> check the attribute omitted in "exclude_default" is set.
|
||||
filter_expr = {'filter': '(eq,id,%s)' % inst_id, 'all_fields': ''}
|
||||
resp, body = self.list_vnf_instance(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for inst in body:
|
||||
self.assertIsNotNone(inst.get('vnfInstanceName'))
|
||||
self.assertIsNotNone(inst.get('vnfInstanceDescription'))
|
||||
self.assertIsNotNone(inst.get('vimConnectionInfo'))
|
||||
self.assertIsNotNone(inst.get('instantiatedVnfInfo'))
|
||||
self.assertIsNotNone(inst.get('metadata'))
|
||||
# * fields=<list>
|
||||
# -> check the attribute specified in "fields" is set
|
||||
filter_expr = {'filter': '(eq,id,%s)' % inst_id,
|
||||
'fields': 'metadata'}
|
||||
resp, body = self.list_vnf_instance(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for inst in body:
|
||||
self.assertIsNone(inst.get('vnfInstanceName'))
|
||||
self.assertIsNone(inst.get('vnfInstanceDescription'))
|
||||
self.assertIsNone(inst.get('vimConnectionInfo'))
|
||||
self.assertIsNone(inst.get('instantiatedVnfInfo'))
|
||||
self.assertIsNotNone(inst.get('metadata'))
|
||||
# * exclude_fields=<list>
|
||||
# -> check the attribute specified in "exclude_fields" is not set
|
||||
filter_expr = {'filter': '(eq,id,%s)' % inst_id,
|
||||
'exclude_fields': 'vnfInstanceName'}
|
||||
resp, body = self.list_vnf_instance(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for inst in body:
|
||||
self.assertIsNone(inst.get('vnfInstanceName'))
|
||||
self.assertIsNotNone(inst.get('vnfInstanceDescription'))
|
||||
self.assertIsNotNone(inst.get('vimConnectionInfo'))
|
||||
self.assertIsNotNone(inst.get('instantiatedVnfInfo'))
|
||||
self.assertIsNotNone(inst.get('metadata'))
|
||||
# * exclude_default
|
||||
# -> check the attribute omitted in "exclude_default" is not set.
|
||||
filter_expr = {'filter': '(eq,id,%s)' % inst_id, 'exclude_default': ''}
|
||||
resp, body = self.list_vnf_instance(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for inst in body:
|
||||
self.assertIsNotNone(inst.get('vnfInstanceName'))
|
||||
self.assertIsNotNone(inst.get('vnfInstanceDescription'))
|
||||
self.assertIsNone(inst.get('vimConnectionInfo'))
|
||||
self.assertIsNone(inst.get('instantiatedVnfInfo'))
|
||||
self.assertIsNone(inst.get('metadata'))
|
||||
|
||||
# 5. Show VNF LCM operation occurrence
|
||||
# NOTE: omitted values are not supported at that time
|
||||
expected_attrs = [
|
||||
'id',
|
||||
'operationState',
|
||||
'stateEnteredTime',
|
||||
'startTime',
|
||||
'vnfInstanceId',
|
||||
# 'grantId', # omitted
|
||||
'operation',
|
||||
'isAutomaticInvocation',
|
||||
'operationParams',
|
||||
'isCancelPending',
|
||||
# 'cancelMode', # omitted
|
||||
# 'error', # omitted
|
||||
'resourceChanges',
|
||||
# 'changedInfo', # omitted
|
||||
# 'changedExtConnectivity', # omitted
|
||||
# 'modificationsTriggeredByVnfPkgChange', # omitted
|
||||
# 'vnfSnapshotInfoId', # omitted
|
||||
'_links'
|
||||
]
|
||||
resp, body = self.show_lcmocc(lcmocc_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.check_resp_body(body, expected_attrs)
|
||||
|
||||
# 6. List VNF LCM operation occurrence with attribute-based filtering
|
||||
# check attribute-based filtering on vnf_lcm_op_occs
|
||||
# NOTE: error and changedInfo, changedExtConnectivity are omitted
|
||||
# because these values are not supported at that time
|
||||
# * all_fields
|
||||
# -> check the attribute omitted in "exclude_default" is set.
|
||||
filter_expr = {'filter': '(eq,id,%s)' % lcmocc_id, 'all_fields': ''}
|
||||
resp, body = self.list_lcmocc(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for lcmocc in body:
|
||||
self.assertIsNotNone(lcmocc.get('operationParams'))
|
||||
self.assertIsNotNone(lcmocc.get('resourceChanges'))
|
||||
# * fields=<list>
|
||||
# -> check the attribute specified in "fields" is set
|
||||
filter_expr = {'filter': '(eq,id,%s)' % lcmocc_id,
|
||||
'fields': 'operationParams'}
|
||||
resp, body = self.list_lcmocc(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for lcmocc in body:
|
||||
self.assertIsNotNone(lcmocc.get('operationParams'))
|
||||
self.assertIsNone(lcmocc.get('resourceChanges'))
|
||||
# * exclude_fields=<list>
|
||||
# -> check the attribute specified in "exclude_fields" is not set
|
||||
filter_expr = {'filter': '(eq,id,%s)' % inst_id,
|
||||
'exclude_fields': 'operationParams'}
|
||||
resp, body = self.list_lcmocc(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for lcmocc in body:
|
||||
self.assertIsNone(lcmocc.get('operationParams'))
|
||||
self.assertIsNotNone(lcmocc.get('resourceChanges'))
|
||||
# * exclude_default
|
||||
# -> check the attribute omitted in "exclude_default" is not set.
|
||||
filter_expr = {'filter': '(eq,id,%s)' % lcmocc_id,
|
||||
'exclude_default': ''}
|
||||
resp, body = self.list_lcmocc(filter_expr)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
self.check_resp_headers_in_get(resp)
|
||||
for lcmocc in body:
|
||||
self.assertIsNone(lcmocc.get('operationParams'))
|
||||
self.assertIsNone(lcmocc.get('resourceChanges'))
|
||||
|
||||
# 7. Terminate a VNF instance
|
||||
terminate_req = paramgen.sample1_terminate()
|
||||
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.check_resp_headers_in_operation_task(resp)
|
||||
|
||||
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||
self.wait_lcmocc_complete(lcmocc_id)
|
||||
@ -109,32 +425,113 @@ class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
# update and terminate completion.
|
||||
time.sleep(10)
|
||||
|
||||
# check deletion of Heat-stack
|
||||
stack_status, _ = self.heat_client.get_status(stack_name)
|
||||
self.assertIsNone(stack_status)
|
||||
|
||||
# check deletion of Glance-image
|
||||
for image_name in image_name_list:
|
||||
image_id = self.get_image_id(image_name)
|
||||
self.assertIsNone(image_id)
|
||||
|
||||
# 8. Delete a VNF instance
|
||||
resp, body = self.delete_vnf_instance(inst_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
self.check_resp_headers_in_delete(resp)
|
||||
|
||||
# check deletion of VNF instance
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(404, resp.status_code)
|
||||
|
||||
# check usageState of VNF Package
|
||||
usage_state = self.get_vnf_package(self.vnf_pkg_1).get('usageState')
|
||||
self.assertEqual('NOT_IN_USE', usage_state)
|
||||
|
||||
def test_sample2(self):
|
||||
"""Test LCM operations with omitting except for required attributes
|
||||
|
||||
* About attributes:
|
||||
Omit except for required attributes.
|
||||
Only the following cardinality attributes are set.
|
||||
- 1
|
||||
- 1..N (1)
|
||||
|
||||
* About LCM operations:
|
||||
This test includes the following operations.
|
||||
- 1. Create a new VNF instance resource
|
||||
- 2. Instantiate a VNF instance
|
||||
- 3. Show VNF instance
|
||||
- 4. Terminate a VNF instance
|
||||
- 5. Delete a VNF instance
|
||||
"""
|
||||
# 1. Create a new VNF instance resource
|
||||
expected_inst_attrs = [
|
||||
'id',
|
||||
# 'vnfInstanceName', # omitted
|
||||
# 'vnfInstanceDescription', # omitted
|
||||
'vnfdId',
|
||||
'vnfProvider',
|
||||
'vnfProductName',
|
||||
'vnfSoftwareVersion',
|
||||
'vnfdVersion',
|
||||
# 'vnfConfigurableProperties', # omitted
|
||||
# 'vimConnectionInfo', # omitted
|
||||
'instantiationState',
|
||||
# 'instantiatedVnfInfo', # omitted
|
||||
# 'metadata', # omitted
|
||||
# 'extensions', # omitted
|
||||
'_links'
|
||||
]
|
||||
create_req = paramgen.sample2_create(self.vnfd_id_2)
|
||||
resp, body = self.create_vnf_instance(create_req)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.check_resp_headers_in_create(resp)
|
||||
self.check_resp_body(body, expected_inst_attrs)
|
||||
inst_id = body['id']
|
||||
|
||||
net_ids = self.get_network_ids(['net0', 'net1', 'net_mgmt'])
|
||||
subnet_ids = self.get_subnet_ids(['subnet0', 'subnet1'])
|
||||
instantiate_req = paramgen.sample2_instantiate(
|
||||
net_ids, subnet_ids, self.auth_url)
|
||||
# check usageState of VNF Package
|
||||
usage_state = self.get_vnf_package(self.vnf_pkg_2).get('usageState')
|
||||
self.assertEqual('IN_USE', usage_state)
|
||||
|
||||
# 2. Instantiate a VNF instance
|
||||
instantiate_req = paramgen.sample2_instantiate()
|
||||
resp, body = self.instantiate_vnf_instance(inst_id, instantiate_req)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.check_resp_headers_in_operation_task(resp)
|
||||
|
||||
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||
self.wait_lcmocc_complete(lcmocc_id)
|
||||
|
||||
# check creation of Heat-stack
|
||||
stack_name = "vnf-{}".format(inst_id)
|
||||
stack_status, _ = self.heat_client.get_status(stack_name)
|
||||
self.assertEqual("CREATE_COMPLETE", stack_status)
|
||||
|
||||
# check that the servers set in "nfvi_node:Affinity" are
|
||||
# deployed on the same host.
|
||||
# NOTE: it's up to heat to decide which host to deploy to
|
||||
vdu1_details = self.get_server_details('VDU1')
|
||||
vdu2_details = self.get_server_details('VDU2')
|
||||
vdu1_host = vdu1_details['hostId']
|
||||
vdu2_host = vdu2_details['hostId']
|
||||
self.assertEqual(vdu1_host, vdu2_host)
|
||||
|
||||
# 3. Show VNF instance
|
||||
additional_inst_attrs = [
|
||||
'vimConnectionInfo',
|
||||
'instantiatedVnfInfo'
|
||||
]
|
||||
expected_inst_attrs.extend(additional_inst_attrs)
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
# TODO(oda-g): check body
|
||||
self.check_resp_headers_in_get(resp)
|
||||
self.check_resp_body(body, expected_inst_attrs)
|
||||
|
||||
# 4. Terminate a VNF instance
|
||||
terminate_req = paramgen.sample2_terminate()
|
||||
resp, body = self.terminate_vnf_instance(inst_id, terminate_req)
|
||||
self.assertEqual(202, resp.status_code)
|
||||
self.check_resp_headers_in_operation_task(resp)
|
||||
|
||||
lcmocc_id = os.path.basename(resp.headers['Location'])
|
||||
self.wait_lcmocc_complete(lcmocc_id)
|
||||
@ -143,5 +540,19 @@ class VnfLcmTest(base_v2.BaseSolV2Test):
|
||||
# update and terminate completion.
|
||||
time.sleep(10)
|
||||
|
||||
# check deletion of Heat-stack
|
||||
stack_status, _ = self.heat_client.get_status(stack_name)
|
||||
self.assertIsNone(stack_status)
|
||||
|
||||
# 5. Delete a VNF instance
|
||||
resp, body = self.delete_vnf_instance(inst_id)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
self.check_resp_headers_in_delete(resp)
|
||||
|
||||
# check deletion of VNF instance
|
||||
resp, body = self.show_vnf_instance(inst_id)
|
||||
self.assertEqual(404, resp.status_code)
|
||||
|
||||
# check usageState of VNF Package
|
||||
usage_state = self.get_vnf_package(self.vnf_pkg_2).get('usageState')
|
||||
self.assertEqual('NOT_IN_USE', usage_state)
|
||||
|
@ -50,6 +50,18 @@ def make_zip(sample_dir, tmp_dir, vnfd_id, image_path=None):
|
||||
shutil.make_archive(zip_file_path, "zip", tmp_contents)
|
||||
|
||||
|
||||
def create_network(network):
|
||||
# assume OS_* environment variables are already set
|
||||
subprocess.run(
|
||||
["openstack", "net", "create", network])
|
||||
|
||||
|
||||
def delete_network(network):
|
||||
# assume OS_* environment variables are already set
|
||||
subprocess.run(
|
||||
["openstack", "net", "delete", network])
|
||||
|
||||
|
||||
def get_network_ids(networks):
|
||||
# assume OS_* environment variables are already set
|
||||
net_ids = {}
|
||||
@ -61,6 +73,13 @@ def get_network_ids(networks):
|
||||
return net_ids
|
||||
|
||||
|
||||
def create_subnet(subnet, network, sub_range, version):
|
||||
# assume OS_* environment variables are already set
|
||||
subprocess.run(
|
||||
["openstack", "subnet", "create", subnet, "--network", network,
|
||||
"--subnet-range", sub_range, "--ip-version", version])
|
||||
|
||||
|
||||
def get_subnet_ids(subnets):
|
||||
# assume OS_* environment variables are already set
|
||||
subnet_ids = {}
|
||||
@ -70,3 +89,26 @@ def get_subnet_ids(subnets):
|
||||
capture_output=True, encoding='utf-8')
|
||||
subnet_ids[subnet] = json.loads(p.stdout)['id']
|
||||
return subnet_ids
|
||||
|
||||
|
||||
def create_port(port, network):
|
||||
# assume OS_* environment variables are already set
|
||||
subprocess.run(
|
||||
["openstack", "port", "create", port, "--network", network])
|
||||
|
||||
|
||||
def delete_port(port):
|
||||
# assume OS_* environment variables are already set
|
||||
subprocess.run(
|
||||
["openstack", "port", "delete", port])
|
||||
|
||||
|
||||
def get_port_ids(ports):
|
||||
# assume OS_* environment variables are already set
|
||||
port_ids = {}
|
||||
for port in ports:
|
||||
p = subprocess.run(
|
||||
["openstack", "port", "show", port, "-c", "id", "-f", "json"],
|
||||
capture_output=True, encoding='utf-8')
|
||||
port_ids[port] = json.loads(p.stdout)['id']
|
||||
return port_ids
|
||||
|
Loading…
Reference in New Issue
Block a user