Support Placement Constraints for Grant

Grant for 3rd-party NFVO is improved. Process related to placement
constraints is supported. This enables interoperability with
3rd-party NFVO which enables them to deploy each VM in the VNF after
setting the zone information based on the grant response from NFVO.

Co-authored-By: Yasufumi Ogawa <yasufum.o@gmail.com>
Implements: blueprint support-placement-constraints
Change-Id: Ibd8c5cae985766d5bd5e73276920fd4c28d6e87f
This commit is contained in:
Aldinson Esto 2021-03-08 14:08:02 +09:00 committed by Koichi Edagawa
parent a6811d2c59
commit 3859ade824
10 changed files with 584 additions and 63 deletions

View File

@ -0,0 +1,5 @@
---
features:
- Add placement constraints support so that the VNFM may interoperate with 3rd
party NFVO, it enables to deploy each VM in the VNF after setting the zone
information based on the grant response from NFVO.

View File

@ -1084,12 +1084,15 @@ class Conductor(manager.Manager):
placement_obj_list = []
topo_temp = vnfd_dict.get('topology_template', {})
for policy in topo_temp.get('policies', []):
affinity_type = {
'tosca.policies.nfv.AntiAffinityRule': 'ANTI_AFFINITY',
'tosca.policies.nfv.AffinityRule': 'AFFINITY'}
for policy_name, policy_dict in policy.items():
key_type = 'tosca.policies.nfv.AntiAffinityRule'
if policy_dict['type'] == key_type:
if policy_dict['type'] in affinity_type.keys():
placement_constraint = objects.PlacementConstraint()
placement_constraint.affinity_or_anti_affinity = \
'ANTI_AFFINITY'
key = policy_dict['type']
placement_constraint.affinity_or_anti_affinity = (
affinity_type[key])
placement_constraint.scope = 'ZONE'
placement_constraint.resource = []
placement_constraint.fallback_best_effort = True

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_out:
type: OS::Heat::ScalingPolicy
properties:
@ -41,20 +42,21 @@ resources:
type: OS::Heat::AutoScalingGroup
depends_on: VDU1
properties:
min_size: 2
max_size: 2
desired_capacity: 2
min_size: 1
max_size: 1
desired_capacity: 1
resource:
type: VDU2.yaml
properties:
flavor: { get_param: [ nfv, VDU, VDU2, flavor ] }
image: { get_param: [ nfv, VDU, VDU2, image ] }
zone: { get_param: [ nfv, vdu, VDU2, zone ] }
net1: { get_param: [ nfv, CP, VDU2_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU2_CP2, network ] }
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_out:
type: OS::Heat::ScalingPolicy
properties:

View File

@ -18,6 +18,8 @@ parameters:
type: string
net5:
type: string
subnet:
type: string
resources:
VDU1:
@ -47,6 +49,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

@ -6,8 +6,6 @@ parameters:
type: string
image:
type: string
zone:
type: string
net1:
type: string
net2:
@ -18,6 +16,10 @@ parameters:
type: string
net5:
type: string
ip1:
type: string
subnet:
type: string
resources:
VDU2:
@ -37,7 +39,6 @@ resources:
get_resource: VDU2_CP4
- port:
get_resource: VDU2_CP5
availability_zone: { get_param: zone }
VDU2_CP1:
type: OS::Neutron::Port
@ -47,6 +48,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

@ -96,8 +96,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'
@ -291,7 +291,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:
@ -334,9 +334,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

@ -626,6 +626,14 @@ class BaseVnfLcmTest(base.BaseTackerTest):
return resource
def _get_heat_stack_template(self, stack_id, nested_depth=0):
try:
template = self.h_client.stacks.template(stack_id)
except Exception:
return None
return template
def _get_image_id_from_resource_attributes(self, stack_resource_details):
if stack_resource_details is None:
return None

View File

@ -108,8 +108,7 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
- Delete subscription.
- Show subscription.
"""
vnf_package_info = self._register_vnf_package_mock_response(
package_dir="functional5")
vnf_package_info = self._register_vnf_package_mock_response()
glance_image = self._list_glance_image()[0]
# Create subscription and register it.
@ -143,9 +142,10 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
self.vim['tenant_id'], glance_image.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)
@ -284,12 +284,14 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
self.vim['tenant_id'], glance_image.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)
self._assert_stack_template(vnf_instance_id)
# Show vnf instance
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id)
@ -303,15 +305,19 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
self.vim['tenant_id'], glance_image.id))
# Heal vnf (exists vnfc_instace_id)
vnfc_instance_id_list = [
vnfc.get('id') for vnfc in vnf_instance.get(
'instantiatedVnfInfo', {}).get(
'vnfcResourceInfo', [])]
vnfc_instance_id_list = []
for vnfc in vnf_instance.get('instantiatedVnfInfo', {}).\
get('vnfcResourceInfo', []):
if vnfc.get('vduId') == 'VDU1':
vnfc_instance_id_list.append(vnfc.get('id'))
request_body = fake_vnflcm.VnfInstances.make_heal_request_body(
vnfc_instance_id_list)
resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self._assert_heal_vnf(resp, vnf_instance_id)
self._assert_stack_template(vnf_instance_id)
# Set Fake server response for Grant-Req(Terminate)
vnflcm_base.FAKE_SERVER_MANAGER.set_callback('POST',
@ -522,3 +528,14 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
ans_list.append(detail.attributes['fixed_ips'])
return ans_list
def _assert_stack_template(self, vnf_instance_id):
stack = self._get_heat_stack(vnf_instance_id)
resources_list\
= self._get_heat_resource_list(stack.id, nested_depth=2)
stack_name_wd = vnf_instance_id + "-VDU2"
physical_resource_id = [r.physical_resource_id for r
in resources_list if stack_name_wd in r.stack_name]
template = self._get_heat_stack_template(physical_resource_id[0])
template_count = str(template).count("zone")
self.assertEqual(template_count, 3)

View File

@ -264,10 +264,18 @@ class TestOpenStack(base.FixturedTestCase):
vnf_resource = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}}
nested_hot_dict = {'parameters': {'vnf': 'test'}}
nested_hot_dict = {
'VDU1.yaml': {'parameters': {'vnf': 'test',
'zone': {'type': 'string'}},
'resources': {'VDU1': {'properties':
{'availability_zone': {'get_param': 'zone'}}}}}}
base_hot_dict = self._read_file()
base_hot_dict['resources']['VDU1']['properties'].setdefault(
'resource', {'properties': {'zone':
{'get_param': ['nfv', 'vdu', 'VDU1', 'zone']}}})
mock_get_base_hot_dict.return_value = \
self._read_file(), nested_hot_dict
vimAssets = {'compute_resource_flavours': [
base_hot_dict, nested_hot_dict
vim_assets = {'compute_resource_flavours': [
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_virtual_compute_desc_id': 'VDU1',
'vim_flavour_id': 'm1.tiny'}],
@ -275,27 +283,27 @@ class TestOpenStack(base.FixturedTestCase):
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_software_image_id': 'VDU1',
'vim_software_image_id': 'cirros'}]}
resAddResource = []
res_add_resource = []
resource = {
'resource_definition_id': '2c6e5cc7-240d-4458-a683-1fe648351280',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource)
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa9',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource)
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa0',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource)
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa1',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource)
res_add_resource.append(resource)
zone = {
'id': '5e4da3c3-4a55-412a-b624-843921f8b51d',
'zone_id': 'nova',
@ -313,8 +321,224 @@ class TestOpenStack(base.FixturedTestCase):
grant_dict['vnf_instance_id'] = uuidsentinel.vnf_instance_id
grant_dict['vnf_lcm_op_occ_id'] = uuidsentinel.vnf_lcm_op_occ_id
grant_dict['add_resources'] = []
grant_dict['add_resources'].extend(resAddResource)
grant_dict['vim_assets'] = vimAssets
grant_dict['add_resources'].extend(res_add_resource)
grant_dict['vim_assets'] = vim_assets
grant_dict['zones'] = [zone]
grant_dict['vim_connections'] = [vim_obj]
grant_obj = objects.Grant.obj_from_primitive(
grant_dict, context=self.context)
vnf['grant'] = grant_obj
vnf_instance = fd_utils.get_vnf_instance_object()
vnf_instance.instantiated_vnf_info.reinitialize()
vnfc_obj = objects.VnfcResourceInfo()
vnfc_obj.id = '2c6e5cc7-240d-4458-a683-1fe648351280'
vnfc_obj.vdu_id = 'VDU1'
vnfc_obj.storage_resource_ids = \
['faf14707-da7c-4eec-be99-8099fa1e9fa0']
compute_resource = objects.ResourceHandle(
vim_connection_id=uuidsentinel.vim_id,
resource_id='6e1c286d-c023-4b34-8369-831c6e84cce2')
vnfc_obj.compute_resource = compute_resource
vnf_instance.instantiated_vnf_info.vnfc_resource_info = [vnfc_obj]
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, inst_req_info=inst_req_info_test,
vnf_package_path=vnf_package_path_test,
grant_info=grant_info_test,
vnf_instance=vnf_instance)
@mock.patch('tacker.vnfm.vim_client.VimClient.get_vim')
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._format_base_hot')
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_grant_zone_add(self, mock_OpenstackClients_heat,
mock_get_base_hot_dict,
mock_format_base_hot,
mock_get_vim):
mock_get_vim.return_value = {
'vim_id': uuidsentinel.vnfd_id,
'vim_type': 'test',
'vim_auth': {'username': 'test', 'password': 'test'},
'placement_attr': {'region': 'TestRegionOne'},
'tenant': 'test'
}
vnf = utils.get_dummy_vnf_etsi(instance_id=self.instance_uuid,
flavour='simple')
vnf['placement_attr'] = {'region_name': 'dummy_region'}
vnf_package_path_test = os.path.abspath(
os.path.join(os.path.dirname(__file__),
"../../../../etc/samples/etsi/nfv",
"user_data_sample_normal"))
inst_req_info_test = type('', (), {})
test_json = self._json_load(
'instantiate_vnf_request_lcm_userdata.json')
inst_req_info_test.additional_params = test_json['additionalParams']
inst_req_info_test.ext_virtual_links = None
inst_req_info_test.flavour_id = 'simple'
vnf_resource = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}}
nested_hot_dict = {
'VDU1.yaml': {'parameters': {'vnf': 'test'},
'resources': {'VDU1': {'properties': {}}}}}
mock_get_base_hot_dict.return_value = \
self._read_file(), nested_hot_dict
vim_assets = {'compute_resource_flavours': [
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_virtual_compute_desc_id': 'VDU1',
'vim_flavour_id': 'm1.tiny'}],
'softwareImages': [
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_software_image_id': 'VDU1',
'vim_software_image_id': 'cirros'}]}
res_add_resource = []
resource = {
'resource_definition_id': '2c6e5cc7-240d-4458-a683-1fe648351280',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa9',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa0',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa1',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
zone = {
'id': '5e4da3c3-4a55-412a-b624-843921f8b51d',
'zone_id': 'nova',
'vim_connection_id': uuidsentinel.vim_id}
vim_obj = {'id': '0b9c66bb-9e1f-4bb2-92c3-913074e52e2b',
'vim_id': uuidsentinel.vim_id,
'vim_type': 'openstack',
'access_info': {
'password': 'test_pw',
'username': 'test_user',
'region': 'test_region',
'tenant': uuidsentinel.tenant}}
grant_dict = {}
grant_dict['id'] = 'c213e465-8220-487e-9464-f79104e81e96'
grant_dict['vnf_instance_id'] = uuidsentinel.vnf_instance_id
grant_dict['vnf_lcm_op_occ_id'] = uuidsentinel.vnf_lcm_op_occ_id
grant_dict['add_resources'] = []
grant_dict['add_resources'].extend(res_add_resource)
grant_dict['vim_assets'] = vim_assets
grant_dict['zones'] = [zone]
grant_dict['vim_connections'] = [vim_obj]
grant_obj = objects.Grant.obj_from_primitive(
grant_dict, context=self.context)
vnf['grant'] = grant_obj
vnf_instance = fd_utils.get_vnf_instance_object()
vnf_instance.instantiated_vnf_info.reinitialize()
vnfc_obj = objects.VnfcResourceInfo()
vnfc_obj.id = '2c6e5cc7-240d-4458-a683-1fe648351280'
vnfc_obj.vdu_id = 'VDU1'
vnfc_obj.storage_resource_ids = \
['faf14707-da7c-4eec-be99-8099fa1e9fa0']
compute_resource = objects.ResourceHandle(
vim_connection_id=uuidsentinel.vim_id,
resource_id='6e1c286d-c023-4b34-8369-831c6e84cce2')
vnfc_obj.compute_resource = compute_resource
vnf_instance.instantiated_vnf_info.vnfc_resource_info = [vnfc_obj]
self.openstack.create(self.plugin, self.context, vnf,
self.auth_attr, inst_req_info=inst_req_info_test,
vnf_package_path=vnf_package_path_test,
grant_info=grant_info_test,
vnf_instance=vnf_instance)
@mock.patch('tacker.vnfm.vim_client.VimClient.get_vim')
@mock.patch('tacker.vnfm.infra_drivers.openstack.openstack'
'.OpenStack._format_base_hot')
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
@mock.patch('tacker.common.clients.OpenstackClients')
def test_create_grant_zone_id_none(self, mock_OpenstackClients_heat,
mock_get_base_hot_dict,
mock_format_base_hot,
mock_get_vim):
mock_get_vim.return_value = {
'vim_id': uuidsentinel.vnfd_id,
'vim_type': 'test',
'vim_auth': {'username': 'test', 'password': 'test'},
'placement_attr': {'region': 'TestRegionOne'},
'tenant': 'test'
}
vnf = utils.get_dummy_vnf_etsi(instance_id=self.instance_uuid,
flavour='simple')
vnf['placement_attr'] = {'region_name': 'dummy_region'}
vnf_package_path_test = os.path.abspath(
os.path.join(os.path.dirname(__file__),
"../../../../etc/samples/etsi/nfv",
"user_data_sample_normal"))
inst_req_info_test = type('', (), {})
test_json = self._json_load(
'instantiate_vnf_request_lcm_userdata.json')
inst_req_info_test.additional_params = test_json['additionalParams']
inst_req_info_test.ext_virtual_links = None
inst_req_info_test.flavour_id = 'simple'
vnf_resource = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}}
nested_hot_dict = {
'VDU1.yaml': {'parameters': {'vnf': 'test'},
'resources': {'VDU1': {'properties': {}}}}}
mock_get_base_hot_dict.return_value = \
self._read_file(), nested_hot_dict
vim_assets = {'compute_resource_flavours': [
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_virtual_compute_desc_id': 'VDU1',
'vim_flavour_id': 'm1.tiny'}],
'softwareImages': [
{'vim_connection_id': uuidsentinel.vim_id,
'vnfd_software_image_id': 'VDU1',
'vim_software_image_id': 'cirros'}]}
res_add_resource = []
resource = {
'resource_definition_id': '2c6e5cc7-240d-4458-a683-1fe648351280',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa9',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa0',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa1',
'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
res_add_resource.append(resource)
zone = {
'id': '5e4da3c3-4a55-412a-b624-843921f8b51d',
'zone_id': '',
'vim_connection_id': uuidsentinel.vim_id}
vim_obj = {'id': '0b9c66bb-9e1f-4bb2-92c3-913074e52e2b',
'vim_id': uuidsentinel.vim_id,
'vim_type': 'openstack',
'access_info': {
'password': 'test_pw',
'username': 'test_user',
'region': 'test_region',
'tenant': uuidsentinel.tenant}}
grant_dict = {}
grant_dict['id'] = 'c213e465-8220-487e-9464-f79104e81e96'
grant_dict['vnf_instance_id'] = uuidsentinel.vnf_instance_id
grant_dict['vnf_lcm_op_occ_id'] = uuidsentinel.vnf_lcm_op_occ_id
grant_dict['add_resources'] = []
grant_dict['add_resources'].extend(res_add_resource)
grant_dict['vim_assets'] = vim_assets
grant_dict['zones'] = [zone]
grant_dict['vim_connections'] = [vim_obj]
grant_obj = objects.Grant.obj_from_primitive(
@ -2085,6 +2309,199 @@ class TestOpenStack(base.FixturedTestCase):
region_name=None
)
@mock.patch.object(hc.HeatClient, "update")
def test_scale_out_initial_zone_none(self, mock_update):
scale_vnf_request = objects.ScaleVnfRequest(type='SCALE_OUT',
aspect_id='SP1',
number_of_steps=1)
vnf_info = {}
add_resources = []
resource = objects.ResourceDefinition(
id='2c6e5cc7-240d-4458-a683-1fe648351280',
type='COMPUTE',
vdu_id='VDU1',
resource_template_id='VDU1')
add_resources.append(resource)
resource = objects.ResourceDefinition(
id='faf14707-da7c-4eec-be99-8099fa1e9fa9',
type='LINKPORT',
vdu_id='VDU1',
resource_template_id='PORT1')
add_resources.append(resource)
resource = objects.ResourceDefinition(
id='faf14707-da7c-4eec-be99-8099fa1e9fa9',
type='STORAGE',
vdu_id='VDU1',
resource_template_id='ST1')
add_resources.append(resource)
vnf_info['addResources'] = add_resources
vnf_info['attributes'] = {}
vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \
'{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \
'1, \"maxLevel\": 3, \"initialNum\": 0, ' + \
'\"initialLevel\": 0, \"default\": 0 }}}'
vnf_info['attributes']['heat_template'] = \
utils.get_dummy_scale_initial_hot()
vnf_info['attributes']['SP1_res.yaml'] = \
utils.get_dummy_scale_nest_initial_hot()
stack_param_dict = {}
stack_param_dict['nfv'] = {}
stack_param_dict['nfv']['VDU'] = {}
stack_param_dict['nfv']['VDU']['VDU1'] = {}
stack_param_dict['nfv']['VDU']['VDU1']['flavor'] = ''
stack_param_dict['nfv']['VDU']['VDU1']['image'] = ''
vnf_info['attributes'].update({'stack_param': str(stack_param_dict)})
vnf_info['instance_id'] = uuidsentinel.stack_id
testjson = '{"id": "c213e465-8220-487e-9464-f79104e81e96", ' + \
'"vnf_instance_id": ' + \
'"47101fb6-bd18-4e04-b2b5-22370a023448", ' + \
'"vnf_lcm_op_occ_id": ' + \
'"f26f181d-7891-4720-b022-b074ec1733ef", ' + \
'"zones": [{' + \
'"id": ' + \
'"5e4da3c3-4a55-412a-b624-843921f8b51d", ' + \
'"zone_id": ' + \
'"nova", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187"}], ' + \
'"add_resources": [{"resource_definition_id": ' + \
'"2c6e5cc7-240d-4458-a683-1fe648351280", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": "5e4da3c3-4a55-412a-b624-843921f8b51d"}' + \
', {"resource_definition_id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": "5e4da3c3-4a55-412a-b624-843921f8b51d"}' + \
', {"resource_definition_id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": ' + \
'"5e4da3c3-4a55-412a-b624-843921f8b51d"}], ' + \
'"vim_assets": {"compute_resource_flavours": ' + \
'[{"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"vnfd_virtual_compute_desc_id": "VDU1", ' + \
'"vim_flavour_id": "m1.tiny"}], "software_images": ' + \
'[{"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"vnfd_software_image_id": "VDU1", ' + \
'"vim_software_image_id": "cirros"}]}}'
res_body = jsonutils.loads(testjson)
res_dict = cutils.convert_camelcase_to_snakecase(res_body)
grant_obj = objects.Grant.obj_from_primitive(
res_dict, context=context)
vnf_info['grant'] = grant_obj
self.openstack.scale_out_initial(context=self.context,
plugin=self,
auth_attr=None,
vnf_info=vnf_info,
scale_vnf_request=scale_vnf_request,
region_name=None
)
@mock.patch.object(hc.HeatClient, "update")
def test_scale_out_initial_zone_id_none(self, mock_update):
scale_vnf_request = objects.ScaleVnfRequest(type='SCALE_OUT',
aspect_id='SP1',
number_of_steps=1)
vnf_info = {}
add_resources = []
resource = objects.ResourceDefinition(
id='2c6e5cc7-240d-4458-a683-1fe648351280',
type='COMPUTE',
vdu_id='VDU1',
resource_template_id='VDU1')
add_resources.append(resource)
resource = objects.ResourceDefinition(
id='faf14707-da7c-4eec-be99-8099fa1e9fa9',
type='LINKPORT',
vdu_id='VDU1',
resource_template_id='PORT1')
add_resources.append(resource)
resource = objects.ResourceDefinition(
id='faf14707-da7c-4eec-be99-8099fa1e9fa9',
type='STORAGE',
vdu_id='VDU1',
resource_template_id='ST1')
add_resources.append(resource)
vnf_info['addResources'] = add_resources
vnf_info['attributes'] = {}
vnf_info['attributes']['scale_group'] = '{\"scaleGroupDict\": ' + \
'{ \"SP1\": { \"vdu\": [\"VDU1\"], \"num\": ' + \
'1, \"maxLevel\": 3, \"initialNum\": 0, ' + \
'\"initialLevel\": 0, \"default\": 0 }}}'
vnf_info['attributes']['heat_template'] = \
utils.get_dummy_scale_initial_hot()
vnf_info['attributes']['SP1_res.yaml'] = \
utils.get_dummy_scale_nest_initial_hot()
stack_param_dict = {}
stack_param_dict['nfv'] = {}
stack_param_dict['nfv']['VDU'] = {}
stack_param_dict['nfv']['VDU']['VDU1'] = {}
stack_param_dict['nfv']['VDU']['VDU1']['zone'] = ''
stack_param_dict['nfv']['VDU']['VDU1']['flavor'] = ''
stack_param_dict['nfv']['VDU']['VDU1']['image'] = ''
vnf_info['attributes'].update({'stack_param': str(stack_param_dict)})
vnf_info['instance_id'] = uuidsentinel.stack_id
testjson = '{"id": "c213e465-8220-487e-9464-f79104e81e96", ' + \
'"vnf_instance_id": ' + \
'"47101fb6-bd18-4e04-b2b5-22370a023448", ' + \
'"vnf_lcm_op_occ_id": ' + \
'"f26f181d-7891-4720-b022-b074ec1733ef", ' + \
'"zones": [{' + \
'"id": ' + \
'"5e4da3c3-4a55-412a-b624-843921f8b51d", ' + \
'"zone_id": ' + \
'"", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187"}], ' + \
'"add_resources": [{"resource_definition_id": ' + \
'"2c6e5cc7-240d-4458-a683-1fe648351280", ' + \
'"id": ' + \
'"2c6e5cc7-240d-4458-a683-1fe648351280", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": "5e4da3c3-4a55-412a-b624-843921f8b51d"}' + \
', {"resource_definition_id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": "5e4da3c3-4a55-412a-b624-843921f8b51d"}' + \
', {"resource_definition_id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"id": ' + \
'"faf14707-da7c-4eec-be99-8099fa1e9fa9", ' + \
'"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"zone_id": ' + \
'"5e4da3c3-4a55-412a-b624-843921f8b51d"}], ' + \
'"vim_assets": {"compute_resource_flavours": ' + \
'[{"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"vnfd_virtual_compute_desc_id": "VDU1", ' + \
'"vim_flavour_id": "m1.tiny"}], "software_images": ' + \
'[{"vim_connection_id": ' + \
'"b6eacd1b-5a9e-41ea-a33b-9d7196cd9187", ' + \
'"vnfd_software_image_id": "VDU1", ' + \
'"vim_software_image_id": "cirros"}]}}'
res_body = jsonutils.loads(testjson)
res_dict = cutils.convert_camelcase_to_snakecase(res_body)
grant_obj = objects.Grant.obj_from_primitive(
res_dict, context=context)
vnf_info['grant'] = grant_obj
self.openstack.scale_out_initial(context=self.context,
plugin=self,
auth_attr=None,
vnf_info=vnf_info,
scale_vnf_request=scale_vnf_request,
region_name=None
)
@mock.patch.object(hc.HeatClient, "resource_get")
@mock.patch.object(hc.HeatClient, "resource_get_list")
def test_get_rollback_ids(self, mock_list, mock_resource):

View File

@ -264,29 +264,9 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
scale_status_list.append(scale_status)
vnf['scale_status'] = scale_status_list
if vnf.get('grant'):
grant = vnf['grant']
ins_inf = vnf_instance.instantiated_vnf_info.vnfc_resource_info
for addrsc in grant.add_resources:
for zone in grant.zones:
if zone.id == addrsc.zone_id:
vdu_name = None
for rsc in ins_inf:
if addrsc.resource_definition_id == rsc.id:
vdu_name = rsc.vdu_id
break
if not vdu_name:
continue
hot_param_dict['nfv']['VDU'][vdu_name]['zone'] = \
zone.zone_id
if 'vim_assets' in grant and grant.vim_assets:
for flavour in grant.vim_assets.compute_resource_flavours:
vdu_name = flavour.vnfd_virtual_compute_desc_id
hot_param_dict['nfv']['VDU'][vdu_name]['flavor'] = \
flavour.vim_flavour_id
for image in grant.vim_assets.software_images:
vdu_name = image.vnfd_software_image_id
hot_param_dict['nfv']['VDU'][vdu_name]['image'] = \
image.vim_software_image_id
base_hot_dict, nested_hot_dict, hot_param_dict = \
self._setup_hot_for_grant_resources(vnf, vnf_instance,
base_hot_dict, nested_hot_dict, hot_param_dict)
# Add stack param to vnf_attributes
vnf['attributes'].update({'stack_param': str(hot_param_dict)})
@ -366,6 +346,79 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
return stack['stack']['id']
@log.log
def _setup_hot_for_grant_resources(self, vnf, vnf_instance,
base_hot_dict, nested_hot_dict, hot_param_dict):
"""Setup HOT related params for grant resources
Update base_hot_dict, nested_hot_dict and hot_param_dict as HOT related
params for grant resources.
:param vnf:
:param vnf_instance:
:param base_hot_dict:
:param nested_hot_dict:
:param hot_param_dict:
:returns: updated base_hot_dict, nested_hot_dict and hot_param_dict
"""
# Rename for readability
grant = vnf['grant']
bh = base_hot_dict
nh = nested_hot_dict
hparam = hot_param_dict
ins_inf = vnf_instance.instantiated_vnf_info.vnfc_resource_info
for addrsc in grant.add_resources:
for zone in grant.zones:
if zone.id == addrsc.zone_id:
vdu_name = None
for rsc in ins_inf:
if addrsc.resource_definition_id == rsc.id:
vdu_name = rsc.vdu_id
break
if not vdu_name:
continue
vdu_prop = bh['resources'][vdu_name]['properties']
if not vdu_prop.get('resource'):
vdu_prop['resource'] = {'properties': {}}
vdu_rsrc_prop = vdu_prop['resource']['properties']
if not vdu_rsrc_prop.get('zone'):
vdu_rsrc_prop['zone'] = {'get_param':
['nfv', 'vdu', vdu_name, 'zone']}
if nh:
for yaml_name in nh:
if not (vdu_name in yaml_name):
continue
if not nh[yaml_name]['parameters'].get('zone'):
nh[yaml_name]['parameters']['zone'] = {
'type': 'string'}
vdu_props = nh[yaml_name]['resources'][vdu_name][
'properties']
if not (vdu_props.get('availability_zone')):
vdu_props['availability_zone'] = {
'get_param': 'zone'}
h_vdu = hparam['nfv']['VDU'][vdu_name]
if not h_vdu.get('zone') and zone.zone_id:
hparam['nfv']['VDU'][vdu_name]['zone'] = zone.zone_id
if h_vdu.get('zone') and not zone.zone_id:
del hparam['nfv']['VDU'][vdu_name]['zone']
if 'vim_assets' in grant and grant.vim_assets:
h_vdus = hparam['nfv']['VDU']
for flv in grant.vim_assets.compute_resource_flavours:
vdu_name = flv.vnfd_virtual_compute_desc_id
h_vdus[vdu_name]['flavor'] = flv.vim_flavour_id
for img in grant.vim_assets.software_images:
vdu_name = img.vnfd_software_image_id
h_vdus[vdu_name]['image'] = img.vim_software_image_id
return bh, nh, hparam
@log.log
def _delete_user_data_module(self, user_data_module):
# Delete module recursively.
@ -1674,10 +1727,18 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for zone in grant.zones:
if zone.id == addrsc.zone_id:
for rsc in vnf_info['addResources']:
if addrsc.id == rsc.id:
if addrsc.resource_definition_id == rsc.id:
vdu_name = rsc.vdu_id
break
stack_param['nfv']['VDU'][vdu_name]['zone'] = zone.zone_id
if not (stack_param['nfv']['VDU']
[vdu_name]).get('zone') and\
zone.zone_id:
stack_param['nfv']['VDU'][vdu_name]['zone'] = \
zone.zone_id
if (stack_param['nfv']['VDU']
[vdu_name]).get('zone') and\
not zone.zone_id:
del stack_param['nfv']['VDU'][vdu_name]['zone']
if 'vim_assets' in grant and grant.vim_assets:
for flavour in grant.vim_assets.compute_resource_flavours:
vdu_name = flavour.vnfd_virtual_compute_desc_id