Enhancement IpOverEthernet in API Parameter

In this implementation, tacker support only "fixedAddresses" parameter.
This patch support "numDynamicAddresses" parameter in
IpOverEthernetAddress, modify to be accepted API Request.
*In this patch, support for addressRange has been postponed.

It is defined into ipAddress parameter by
ETSI SOL003 -> v2.6.1 -> 4.4.1.10c.

IpOverEthernetAddressData
-> ipAddresses
   -> numDynamicAddresses

And, modify the LCM user data route so that it can use
IpOverEthernetAddressData.

Change-Id: I3f6ba1f4e1bacf1fc5295726afc7ffd8626db444
This commit is contained in:
Wataru Juso 2021-01-25 08:47:34 +09:00
parent 87ea725784
commit d7669a3e37
17 changed files with 353 additions and 134 deletions

View File

@ -647,8 +647,9 @@ fixed_addresses:
description: |
Fixed addresses to assign (from the subnet defined by "subnetId"
if provided).
Exactly one of "fixedAddresses" or "numDynamicAddresses" shall be present.
in: body
required: true
required: false
type: array
flavour_id:
description: |
@ -805,6 +806,13 @@ mac_address_cp_info:
in: body
required: false
type: string
num_dynamic_addresses:
description: |
Number of set the dynamic address.
Exactly one of "fixedAddresses" or "numDynamicAddresses" shall be present.
in: body
required: false
type: int
number_of_steps:
description: |
Number of scaling steps to be executed as part of this

View File

@ -12,7 +12,15 @@
"linkPortId": "1d868d02-ecd4-4402-8e6b-54e77ebdcc28",
"cpProtocolData": [
{
"layerProtocol": "IP_OVER_ETHERNET"
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses":[
{
"type": "IPV4",
"numDynamicAddresses": 1
}
]
}
}
]
}

View File

@ -23,7 +23,18 @@
{
"cpProtocolInfo": [
{
"layerProtocol": "IP_OVER_ETHERNET"
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"addresses": [
"192.168.0.20"
],
"isDynamic": "true"
}
]
}
}
],
"cpdId": "CP2",

View File

@ -22,7 +22,18 @@
{
"cpProtocolInfo": [
{
"layerProtocol": "IP_OVER_ETHERNET"
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [
{
"type": "IPV4",
"addresses": [
"192.168.0.20"
],
"isDynamic": "true"
}
]
}
}
],
"cpdId": "CP2",

View File

@ -123,6 +123,7 @@ Request Parameters
- ipAddresses: ip_addresses
- type: ip_address_type
- fixedAddresses: fixed_addresses
- numDynamicAddresses: num_dynamic_addresses
- subnetId: subnet_id
- extLinkPorts: ext_link_ports
- id: ext_link_port_id

View File

@ -43,7 +43,8 @@ _ipaddresses = {
'properties': {
'type': {'enum': fields.IpAddressType.ALL},
'subnetId': parameter_types.identifier_in_vim,
'fixedAddresses': {'type': 'array'}
'fixedAddresses': {'type': 'array'},
'numDynamicAddresses': parameter_types.positive_integer
},
'if': {'properties': {'type': {'const': fields.IpAddressType.IPV4}}},
'then': {
@ -62,7 +63,11 @@ _ipaddresses = {
}
}
},
'required': ['type', 'fixedAddresses'],
'required': ['type'],
'oneOf': [
{'required': ['numDynamicAddresses']},
{'required': ['fixedAddresses']}
],
'additionalProperties': True
}
}

View File

@ -99,18 +99,17 @@ def _get_cp_protocol_data_list(ext_cp_info):
cp_protocol_data_list = []
def _get_ip_addresses(ip_addresses):
ip_addresses = []
ip_addresses_list = []
for ip_address in ip_addresses:
# TODO(nitin-uikey): How to determine num_dynamic_addresses
# back from InstantiatedVnfInfo->IpAddressReq.
ip_address_data = IpAddressReq(
type=ip_address.type,
subnet_id=ip_address.subnet_id,
fixed_addresses=ip_address.addresses)
fixed_addresses=ip_address.addresses,
num_dynamic_addresses=1 if ip_address.is_dynamic else 0)
ip_addresses.append(ip_address_data)
ip_addresses_list.append(ip_address_data)
return ip_addresses
return ip_addresses_list
for cp_protocol_info in ext_cp_info.cp_protocol_info:
if cp_protocol_info.ip_over_ethernet:
@ -532,7 +531,8 @@ class IpAddressReq(base.TackerObject):
'type': fields.IpAddressTypeField(nullable=False),
'subnet_id': fields.StringField(nullable=True, default=None),
'fixed_addresses': fields.ListOfStringsField(nullable=True,
default=[])
default=[]),
'num_dynamic_addresses': fields.IntegerField(nullable=True, default=0)
}
@classmethod
@ -540,9 +540,11 @@ class IpAddressReq(base.TackerObject):
type = data_dict.get('type')
subnet_id = data_dict.get('subnet_id')
fixed_addresses = data_dict.get('fixed_addresses', [])
num_dynamic_addresses = data_dict.get('num_dynamic_addresses')
obj = cls(type=type, subnet_id=subnet_id,
fixed_addresses=fixed_addresses)
fixed_addresses=fixed_addresses,
num_dynamic_addresses=num_dynamic_addresses)
return obj

View File

@ -23,6 +23,7 @@ resources:
net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 }
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet]}
VDU1_scale_scale_out:
type: OS::Heat::ScalingPolicy
properties:
@ -40,9 +41,9 @@ resources:
VDU2_scale_group:
type: OS::Heat::AutoScalingGroup
properties:
min_size: 2
max_size: 2
desired_capacity: 2
min_size: 1
max_size: 1
desired_capacity: 1
resource:
type: VDU2.yaml
properties:
@ -54,6 +55,8 @@ resources:
net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 }
ip1: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, ip_address]}
subnet: { get_param: [nfv, CP, VDU2_CP2, fixed_ips, 0, subnet]}
VDU2_scale_scale_out:
type: OS::Heat::ScalingPolicy
properties:

View File

@ -18,6 +18,8 @@ parameters:
type: string
net5:
type: string
subnet:
type: string
resources:
VDU1:
@ -58,6 +60,8 @@ resources:
type: OS::Neutron::Port
properties:
network: { get_param: net2 }
fixed_ips:
- subnet: { get_param: subnet}
VDU1_CP3:
type: OS::Neutron::Port
properties:

View File

@ -18,6 +18,10 @@ parameters:
type: string
net5:
type: string
ip1:
type: string
subnet:
type: string
resources:
VDU2:
@ -47,6 +51,9 @@ resources:
type: OS::Neutron::Port
properties:
network: { get_param: net2 }
fixed_ips:
- ip_address: { get_param: ip1}
subnet: { get_param: subnet}
VDU2_CP3:
type: OS::Neutron::Port
properties:

View File

@ -87,8 +87,8 @@ topology_template:
name: VDU2
description: VDU2 compute node
vdu_profile:
min_number_of_instances: 2
max_number_of_instances: 2
min_number_of_instances: 1
max_number_of_instances: 1
sw_image_data:
name: cirros-0.4.0-x86_64-disk
version: '0.4.0'
@ -300,7 +300,7 @@ topology_template:
type: tosca.policies.nfv.VduInitialDelta
properties:
initial_delta:
number_of_instances: 2
number_of_instances: 1
targets: [ VDU2 ]
- VDU1_scaling_aspect_deltas:
@ -343,9 +343,9 @@ topology_template:
properties:
levels:
instantiation_level_1:
number_of_instances: 2
number_of_instances: 1
instantiation_level_2:
number_of_instances: 2
number_of_instances: 1
targets: [ VDU2 ]
- internalVL1_instantiation_levels:

View File

@ -253,12 +253,19 @@ class BaseVnfLcmTest(base.BaseTackerTest):
self.ext_networks = list()
# Create external managed networks
self.ext_mngd_networks = list() # Store ids for cleaning.
# Create external link ports in net0
self.ext_link_ports = list()
# Create external subnet in net1
self.ext_subnets = list() # Store ids for cleaning.
networks = self.neutronclient().list_networks()
for nw in networks.get('networks'):
if nw['name'] == 'net0':
self.ext_networks.append(nw['id'])
self.ext_vl = _get_external_virtual_links(nw['id'])
self.ext_subnets.append(nw['subnets'][0])
self.ext_link_ports.append(self._create_port(nw['id']))
self.ext_link_ports.append(self._create_port(nw['id']))
elif nw['name'] == 'net1':
self.ext_mngd_networks.append(nw['id'])
@ -270,22 +277,12 @@ class BaseVnfLcmTest(base.BaseTackerTest):
self._create_network("external_managed_internal_net")
self.ext_mngd_networks.append(ext_mngd_net_id)
# Create external link ports in net0
self.ext_link_ports = list()
# Create external subnet in net1
self.ext_subnets = list() # Store ids for cleaning.
# Chack how many networks are created.
networks = self.neutronclient().list_networks()
for nw in networks.get('networks'):
if nw['name'] not in ['net0', ext_net_name]:
if nw['name'] not in [ext_net_name]:
continue
if nw['name'] == 'net0':
self.ext_subnets.append(nw['subnets'][0])
else:
self.ext_subnets.append(self._create_subnet(nw))
self.ext_link_ports.append(self._create_port(nw['id']))
self.ext_subnets.append(self._create_subnet(nw))
@classmethod
def _list_glance_image(cls, filter_name='cirros-0.4.0-x86_64-disk'):
@ -1131,7 +1128,7 @@ class BaseVnfLcmTest(base.BaseTackerTest):
(uniq_name, e))
def _create_subnet(self, network):
cidr_prefix = "22.22.{}".format(str(len(self.ext_subnets) + 1))
cidr_prefix = "22.22.{}".format(str(len(self.ext_subnets)))
body = {'subnet': {'network_id': network['id'],
'name': "subnet-%s" % uuidutils.generate_uuid(),
'cidr': "{}.0/24".format(cidr_prefix),

View File

@ -47,6 +47,167 @@ class Subscription:
}
ext_vdu1_cp1 = {
"cpdId": "VDU1_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp1_id
}],
}
ext_vdu2_cp1 = {
"cpdId": "VDU2_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp2_id
}]
}
def _set_ext_link_port1(external_ports_id):
ext_link_port1 = {
"id": uuidsentinel.elp1_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[0]
}
}
return ext_link_port1
def _set_ext_link_port2(external_ports_id):
ext_link_port2 = {
"id": uuidsentinel.elp2_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[1]
}
}
return ext_link_port2
def _set_ext_virtual_link_cp1(networks_id, external_ports_id):
ext_virtual_link_cp1 = {
"id": uuidsentinel.evl1_id,
"resourceId": networks_id[0],
"extCps": [ext_vdu1_cp1, ext_vdu2_cp1],
"extLinkPorts": [
_set_ext_link_port1(external_ports_id),
_set_ext_link_port2(external_ports_id)]
}
return ext_virtual_link_cp1
def _set_ext_cps_vdu1_cp2(external_subnets_id):
ext_cps_vdu1_cp2 = {
"cpdId": "VDU1_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.1.10"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu1_cp2
def _set_ext_cps_vdu2_cp2(external_subnets_id):
ext_cps_vdu2_cp2 = {
"cpdId": "VDU2_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.1.20"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu2_cp2
def _set_ext_cps_vdu1_cp2_in_num_dynamic(external_subnets_id):
ext_cps_vdu1_cp2_in_num_dynamic = {
"cpdId": "VDU1_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"numDynamicAddresses": 1,
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu1_cp2_in_num_dynamic
def _set_ext_cps_vdu2_cp2_in_num_dynamic(external_subnets_id):
ext_cps_vdu2_cp2_in_num_dynamic = {
"cpdId": "VDU2_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.1.200"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
return ext_cps_vdu2_cp2_in_num_dynamic
def _set_ext_virtual_link_cp2(networks_id, external_subnets_id):
ext_virtual_link_cp2 = {
"id": uuidsentinel.evl2_id,
"resourceId": networks_id[1],
"extCps": [
_set_ext_cps_vdu1_cp2(external_subnets_id),
_set_ext_cps_vdu2_cp2(external_subnets_id)
]
}
return ext_virtual_link_cp2
def _set_ext_virtual_link_cp2_in_num_dynamic(networks_id, external_subnets_id):
ext_virtual_link_cp2_in_num_dynamic = {
"id": uuidsentinel.evl2_id,
"resourceId": networks_id[1],
"extCps": [
_set_ext_cps_vdu1_cp2_in_num_dynamic(external_subnets_id),
_set_ext_cps_vdu2_cp2_in_num_dynamic(external_subnets_id)
]
}
return ext_virtual_link_cp2_in_num_dynamic
def _set_ext_mng_vtl_lnks(ext_mngd_networks_id):
ext_mng_vtl_lnks = [{
"id": uuidsentinel.emvl1_id,
"vnfVirtualLinkDescId": "internalVL1",
"resourceId": ext_mngd_networks_id[0]
}, {
"id": uuidsentinel.emvl2_id,
"vnfVirtualLinkDescId": "internalVL2",
"resourceId": ext_mngd_networks_id[1]
}]
return ext_mng_vtl_lnks
class VnfInstances:
@staticmethod
@ -67,101 +228,56 @@ class VnfInstances:
ext_mngd_networks_id,
external_ports_id,
external_subnets_id):
ext_vdu1_cp1 = {
"cpdId": "VDU1_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp1_id
}],
}
ext_vdu2_cp1 = {
"cpdId": "VDU2_CP1",
"cpConfig": [{
"linkPortId": uuidsentinel.elp2_id
}]
}
# set external port_id on vim.
ext_link_port1 = {
"id": uuidsentinel.elp1_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[0]
}
}
ext_link_port2 = {
"id": uuidsentinel.elp2_id,
"resourceHandle": {
"vimConnectionId": uuidsentinel.vim_connection_id,
"resourceId": external_ports_id[1]
}
}
ext_virtual_link_cp1 = {
"id": uuidsentinel.evl1_id,
# set external nw_id on vim.
"resourceId": networks_id[0],
"extCps": [ext_vdu1_cp1, ext_vdu2_cp1],
"extLinkPorts": [ext_link_port1, ext_link_port2]
}
# set external subet_id on vim.
ext_cps_vdu1_cp2 = {
"cpdId": "VDU1_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.2.10"],
"subnetId": external_subnets_id[0]
}]
}
}]
}]
}
# set external subet_id on vim.
ext_cps_vdu2_cp2 = {
"cpdId": "VDU2_CP2",
"cpConfig": [{
"cpProtocolData": [{
"layerProtocol": "IP_OVER_ETHERNET",
"ipOverEthernet": {
"ipAddresses": [{
"type": "IPV4",
"fixedAddresses": ["22.22.2.20"],
"subnetId": external_subnets_id[1]
}]
}
}]
}]
}
ext_virtual_link_cp2 = {
"id": uuidsentinel.evl2_id,
"resourceId": networks_id[1],
"extCps": [
ext_cps_vdu1_cp2, ext_cps_vdu2_cp2
]
}
# set extManaged internal nw_id on vim.
ext_mng_vtl_lnks = [{
"id": uuidsentinel.emvl1_id,
"vnfVirtualLinkDescId": "internalVL1",
"resourceId": ext_mngd_networks_id[0]
}, {
"id": uuidsentinel.emvl2_id,
"vnfVirtualLinkDescId": "internalVL2",
"resourceId": ext_mngd_networks_id[1]
}]
data = {
"flavourId": "simple",
"instantiationLevelId": "instantiation_level_1",
"extVirtualLinks": [
ext_virtual_link_cp1, ext_virtual_link_cp2
_set_ext_virtual_link_cp1(
networks_id, external_ports_id),
_set_ext_virtual_link_cp2(
networks_id, external_subnets_id)
],
"extManagedVirtualLinks": ext_mng_vtl_lnks,
"extManagedVirtualLinks": _set_ext_mng_vtl_lnks(
ext_mngd_networks_id),
"vimConnectionInfo": [{
"id": uuidsentinel.vim_connection_id,
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",
"vimConnectionId": uuidsentinel.vim_connection_id,
"interfaceInfo": {
"endpoint": "http://127.0.0.1/identity"
},
"accessInfo": {
"username": "nfv_user",
"region": "RegionOne",
"password": "devstack",
"tenant": tenant_id
}
}],
"additionalParams": {
"lcm-operation-user-data": "./UserData/lcm_user_data.py",
"lcm-operation-user-data-class": "SampleUserData"
}
}
return data
@staticmethod
def make_inst_request_body_include_num_dynamic(
tenant_id,
networks_id,
ext_mngd_networks_id,
external_ports_id,
external_subnets_id):
data = {
"flavourId": "simple",
"instantiationLevelId": "instantiation_level_1",
"extVirtualLinks": [
_set_ext_virtual_link_cp1(networks_id, external_ports_id),
_set_ext_virtual_link_cp2_in_num_dynamic(
networks_id, external_subnets_id)
],
"extManagedVirtualLinks": _set_ext_mng_vtl_lnks(
ext_mngd_networks_id),
"vimConnectionInfo": [{
"id": uuidsentinel.vim_connection_id,
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2",

View File

@ -151,9 +151,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
self.addCleanup(self._delete_vnf_instance, vnf_instance_id)
# Instantiate vnf instance
request_body = fake_vnflcm.VnfInstances.make_inst_request_body(
self.vim['tenant_id'], self.ext_networks, self.ext_mngd_networks,
self.ext_link_ports, self.ext_subnets)
request_body = fake_vnflcm.VnfInstances.\
make_inst_request_body_include_num_dynamic(
self.vim['tenant_id'], self.ext_networks,
self.ext_mngd_networks, self.ext_link_ports, self.ext_subnets)
resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self.assert_instantiate_vnf(resp, vnf_instance_id, vnf_package_id)

View File

@ -81,8 +81,14 @@ class TestUtils(testtools.TestCase):
}
vdu_flavor_dict = {'VDU1': {'ram': 'vdu1_flavor_ram_change'}}
vdu_image_dict = {'VDU1': 'vdu1_image_uuid_change'}
cpd_vl_dict = {'CP1': {'cp1_network_id_change_1',
'cp1_network_id_change_2'}}
cpd_vl_dict = {
'CP1': {
'network': {
'cp1_network_id_change_1',
'cp1_network_id_change_2'
}
}
}
expected_final_param_dict = {
'nfv': {
'CP': {

View File

@ -869,7 +869,7 @@ def _build_ip_over_ethernet_address_info(cp_protocol_data):
ip_address_info = objects.vnf_instantiated_info.IpAddress(
type=ip_address.type,
addresses=ip_address.fixed_addresses,
is_dynamic=(False if ip_address.fixed_addresses else True),
is_dynamic=True if ip_address.num_dynamic_addresses else False,
subnet_id=ip_address.subnet_id)
ip_address_list.append(ip_address_info)

View File

@ -199,8 +199,15 @@ def create_final_param_dict(param_dict, vdu_flavor_dict,
vdus[target_vdu]['image'] = vdu_image_dict.get(target_vdu)
cps = final_param_dict.get('nfv', {}).get('CP', {})
for target_cp in cps:
cps[target_cp]['network'] = cpd_vl_dict.get(target_cp)
if cpd_vl_dict:
for target_cp in cps:
if 'network' in cpd_vl_dict.get(target_cp):
cps[target_cp]['network'] = cpd_vl_dict.get(
target_cp).get('network')
if 'fixed_ips' in cpd_vl_dict.get(target_cp):
cps[target_cp]['fixed_ips'] = []
for fixed_ip in cpd_vl_dict.get(target_cp).get("fixed_ips"):
cps[target_cp]['fixed_ips'].append(fixed_ip)
LOG.info('final_param_dict: %s', final_param_dict)
return final_param_dict
@ -369,7 +376,39 @@ def create_network_dict(inst_req_info, param_dict):
for ext_vl in ext_vl_param:
for ext_cp in ext_vl.ext_cps:
if ext_cp.cpd_id in cp_param.keys():
cp_data[ext_cp.cpd_id] = ext_vl.resource_id
cp_data[ext_cp.cpd_id] = {}
cp_data[ext_cp.cpd_id]["network"] = ext_vl.resource_id
cp_data[ext_cp.cpd_id]["fixed_ips"] =\
_create_fixed_ips_list(ext_cp)
LOG.info('cp_data: %s', cp_data)
return cp_data
def _create_fixed_ips_list(ext_cp):
"""Create a list containing information about IP information.
:param ext_cp: dict(ExtCp data of Instantiation request)
:return: list(List structured of fixed_ips)
"""
fixed_ips_lst = []
for cp_config in ext_cp.cp_config:
for cp_protocol_data in cp_config.cp_protocol_data:
for ip_address in cp_protocol_data.ip_over_ethernet.ip_addresses:
# TODO(w-juso):
# Currently, I have not found a way to specify multiple
# numDynamicAddresses to HOT, so I create a list of fixed_ips
# with numDynamicAddress=1.
# Needs to be considered in the future.
fixed_ips = {}
if ip_address.subnet_id:
fixed_ips['subnet'] = ip_address.subnet_id
if ip_address.fixed_addresses:
for fixed_address in ip_address.fixed_addresses:
fixed_ips['ip_address'] = fixed_address
if fixed_ips:
fixed_ips_lst.append(fixed_ips)
return fixed_ips_lst