Merge "Support Placement Constraints for Grant"

This commit is contained in:
Zuul 2021-04-02 01:12:13 +00:00 committed by Gerrit Code Review
commit 6fc64560e2
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 = [] placement_obj_list = []
topo_temp = vnfd_dict.get('topology_template', {}) topo_temp = vnfd_dict.get('topology_template', {})
for policy in topo_temp.get('policies', []): 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(): for policy_name, policy_dict in policy.items():
key_type = 'tosca.policies.nfv.AntiAffinityRule' if policy_dict['type'] in affinity_type.keys():
if policy_dict['type'] == key_type:
placement_constraint = objects.PlacementConstraint() placement_constraint = objects.PlacementConstraint()
placement_constraint.affinity_or_anti_affinity = \ key = policy_dict['type']
'ANTI_AFFINITY' placement_constraint.affinity_or_anti_affinity = (
affinity_type[key])
placement_constraint.scope = 'ZONE' placement_constraint.scope = 'ZONE'
placement_constraint.resource = [] placement_constraint.resource = []
placement_constraint.fallback_best_effort = True placement_constraint.fallback_best_effort = True

View File

@ -23,6 +23,7 @@ resources:
net3: { get_resource: extmanageNW_1 } net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 } net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 } net5: { get_resource: internalNW_1 }
subnet: { get_param: [nfv, CP, VDU1_CP2, fixed_ips, 0, subnet]}
VDU1_scale_out: VDU1_scale_out:
type: OS::Heat::ScalingPolicy type: OS::Heat::ScalingPolicy
properties: properties:
@ -41,20 +42,21 @@ resources:
type: OS::Heat::AutoScalingGroup type: OS::Heat::AutoScalingGroup
depends_on: VDU1 depends_on: VDU1
properties: properties:
min_size: 2 min_size: 1
max_size: 2 max_size: 1
desired_capacity: 2 desired_capacity: 1
resource: resource:
type: VDU2.yaml type: VDU2.yaml
properties: properties:
flavor: { get_param: [ nfv, VDU, VDU2, flavor ] } flavor: { get_param: [ nfv, VDU, VDU2, flavor ] }
image: { get_param: [ nfv, VDU, VDU2, image ] } image: { get_param: [ nfv, VDU, VDU2, image ] }
zone: { get_param: [ nfv, vdu, VDU2, zone ] }
net1: { get_param: [ nfv, CP, VDU2_CP1, network ] } net1: { get_param: [ nfv, CP, VDU2_CP1, network ] }
net2: { get_param: [ nfv, CP, VDU2_CP2, network ] } net2: { get_param: [ nfv, CP, VDU2_CP2, network ] }
net3: { get_resource: extmanageNW_1 } net3: { get_resource: extmanageNW_1 }
net4: { get_resource: extmanageNW_2 } net4: { get_resource: extmanageNW_2 }
net5: { get_resource: internalNW_1 } 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: VDU2_scale_out:
type: OS::Heat::ScalingPolicy type: OS::Heat::ScalingPolicy
properties: properties:

View File

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

View File

@ -6,8 +6,6 @@ parameters:
type: string type: string
image: image:
type: string type: string
zone:
type: string
net1: net1:
type: string type: string
net2: net2:
@ -18,6 +16,10 @@ parameters:
type: string type: string
net5: net5:
type: string type: string
ip1:
type: string
subnet:
type: string
resources: resources:
VDU2: VDU2:
@ -37,7 +39,6 @@ resources:
get_resource: VDU2_CP4 get_resource: VDU2_CP4
- port: - port:
get_resource: VDU2_CP5 get_resource: VDU2_CP5
availability_zone: { get_param: zone }
VDU2_CP1: VDU2_CP1:
type: OS::Neutron::Port type: OS::Neutron::Port
@ -47,6 +48,9 @@ resources:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:
network: { get_param: net2 } network: { get_param: net2 }
fixed_ips:
- ip_address: { get_param: ip1}
subnet: { get_param: subnet}
VDU2_CP3: VDU2_CP3:
type: OS::Neutron::Port type: OS::Neutron::Port
properties: properties:

View File

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

View File

@ -626,6 +626,14 @@ class BaseVnfLcmTest(base.BaseTackerTest):
return resource 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): def _get_image_id_from_resource_attributes(self, stack_resource_details):
if stack_resource_details is None: if stack_resource_details is None:
return None return None

View File

@ -108,8 +108,7 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
- Delete subscription. - Delete subscription.
- Show subscription. - Show subscription.
""" """
vnf_package_info = self._register_vnf_package_mock_response( vnf_package_info = self._register_vnf_package_mock_response()
package_dir="functional5")
glance_image = self._list_glance_image()[0] glance_image = self._list_glance_image()[0]
# Create subscription and register it. # Create subscription and register it.
@ -143,9 +142,10 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
self.vim['tenant_id'], glance_image.id)) self.vim['tenant_id'], glance_image.id))
# Instantiate vnf instance # Instantiate vnf instance
request_body = fake_vnflcm.VnfInstances.make_inst_request_body( request_body = fake_vnflcm.VnfInstances.\
self.vim['tenant_id'], self.ext_networks, self.ext_mngd_networks, make_inst_request_body_include_num_dynamic(
self.ext_link_ports, self.ext_subnets) 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) resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id) self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self._assert_instantiate_vnf(resp, 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)) self.vim['tenant_id'], glance_image.id))
# Instantiate vnf instance # Instantiate vnf instance
request_body = fake_vnflcm.VnfInstances.make_inst_request_body( request_body = fake_vnflcm.VnfInstances.\
self.vim['tenant_id'], self.ext_networks, self.ext_mngd_networks, make_inst_request_body_include_num_dynamic(
self.ext_link_ports, self.ext_subnets) 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) resp, _ = self._instantiate_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id) self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self._assert_instantiate_vnf(resp, vnf_instance_id) self._assert_instantiate_vnf(resp, vnf_instance_id)
self._assert_stack_template(vnf_instance_id)
# Show vnf instance # Show vnf instance
resp, vnf_instance = self._show_vnf_instance(vnf_instance_id) 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)) self.vim['tenant_id'], glance_image.id))
# Heal vnf (exists vnfc_instace_id) # Heal vnf (exists vnfc_instace_id)
vnfc_instance_id_list = [ vnfc_instance_id_list = []
vnfc.get('id') for vnfc in vnf_instance.get(
'instantiatedVnfInfo', {}).get( for vnfc in vnf_instance.get('instantiatedVnfInfo', {}).\
'vnfcResourceInfo', [])] get('vnfcResourceInfo', []):
if vnfc.get('vduId') == 'VDU1':
vnfc_instance_id_list.append(vnfc.get('id'))
request_body = fake_vnflcm.VnfInstances.make_heal_request_body( request_body = fake_vnflcm.VnfInstances.make_heal_request_body(
vnfc_instance_id_list) vnfc_instance_id_list)
resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body) resp, _ = self._heal_vnf_instance(vnf_instance_id, request_body)
self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id) self._wait_lcm_done('COMPLETED', vnf_instance_id=vnf_instance_id)
self._assert_heal_vnf(resp, 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) # Set Fake server response for Grant-Req(Terminate)
vnflcm_base.FAKE_SERVER_MANAGER.set_callback('POST', vnflcm_base.FAKE_SERVER_MANAGER.set_callback('POST',
@ -522,3 +528,14 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
ans_list.append(detail.attributes['fixed_ips']) ans_list.append(detail.attributes['fixed_ips'])
return ans_list 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 = type('', (), {})
vnf_resource.resource_identifier = constants.INVALID_UUID vnf_resource.resource_identifier = constants.INVALID_UUID
grant_info_test = {'vdu_name': {vnf_resource}} 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 = \ mock_get_base_hot_dict.return_value = \
self._read_file(), nested_hot_dict base_hot_dict, nested_hot_dict
vimAssets = {'compute_resource_flavours': [ vim_assets = {'compute_resource_flavours': [
{'vim_connection_id': uuidsentinel.vim_id, {'vim_connection_id': uuidsentinel.vim_id,
'vnfd_virtual_compute_desc_id': 'VDU1', 'vnfd_virtual_compute_desc_id': 'VDU1',
'vim_flavour_id': 'm1.tiny'}], 'vim_flavour_id': 'm1.tiny'}],
@ -275,27 +283,27 @@ class TestOpenStack(base.FixturedTestCase):
{'vim_connection_id': uuidsentinel.vim_id, {'vim_connection_id': uuidsentinel.vim_id,
'vnfd_software_image_id': 'VDU1', 'vnfd_software_image_id': 'VDU1',
'vim_software_image_id': 'cirros'}]} 'vim_software_image_id': 'cirros'}]}
resAddResource = [] res_add_resource = []
resource = { resource = {
'resource_definition_id': '2c6e5cc7-240d-4458-a683-1fe648351280', 'resource_definition_id': '2c6e5cc7-240d-4458-a683-1fe648351280',
'vim_connection_id': uuidsentinel.vim_id, 'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'} 'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource) res_add_resource.append(resource)
resource = { resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa9', 'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa9',
'vim_connection_id': uuidsentinel.vim_id, 'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'} 'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource) res_add_resource.append(resource)
resource = { resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa0', 'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa0',
'vim_connection_id': uuidsentinel.vim_id, 'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'} 'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource) res_add_resource.append(resource)
resource = { resource = {
'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa1', 'resource_definition_id': 'faf14707-da7c-4eec-be99-8099fa1e9fa1',
'vim_connection_id': uuidsentinel.vim_id, 'vim_connection_id': uuidsentinel.vim_id,
'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'} 'zone_id': '5e4da3c3-4a55-412a-b624-843921f8b51d'}
resAddResource.append(resource) res_add_resource.append(resource)
zone = { zone = {
'id': '5e4da3c3-4a55-412a-b624-843921f8b51d', 'id': '5e4da3c3-4a55-412a-b624-843921f8b51d',
'zone_id': 'nova', 'zone_id': 'nova',
@ -313,8 +321,224 @@ class TestOpenStack(base.FixturedTestCase):
grant_dict['vnf_instance_id'] = uuidsentinel.vnf_instance_id grant_dict['vnf_instance_id'] = uuidsentinel.vnf_instance_id
grant_dict['vnf_lcm_op_occ_id'] = uuidsentinel.vnf_lcm_op_occ_id grant_dict['vnf_lcm_op_occ_id'] = uuidsentinel.vnf_lcm_op_occ_id
grant_dict['add_resources'] = [] grant_dict['add_resources'] = []
grant_dict['add_resources'].extend(resAddResource) grant_dict['add_resources'].extend(res_add_resource)
grant_dict['vim_assets'] = vimAssets 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['zones'] = [zone]
grant_dict['vim_connections'] = [vim_obj] grant_dict['vim_connections'] = [vim_obj]
grant_obj = objects.Grant.obj_from_primitive( grant_obj = objects.Grant.obj_from_primitive(
@ -2085,6 +2309,199 @@ class TestOpenStack(base.FixturedTestCase):
region_name=None 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")
@mock.patch.object(hc.HeatClient, "resource_get_list") @mock.patch.object(hc.HeatClient, "resource_get_list")
def test_get_rollback_ids(self, mock_list, mock_resource): 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) scale_status_list.append(scale_status)
vnf['scale_status'] = scale_status_list vnf['scale_status'] = scale_status_list
if vnf.get('grant'): if vnf.get('grant'):
grant = vnf['grant'] base_hot_dict, nested_hot_dict, hot_param_dict = \
ins_inf = vnf_instance.instantiated_vnf_info.vnfc_resource_info self._setup_hot_for_grant_resources(vnf, vnf_instance,
for addrsc in grant.add_resources: base_hot_dict, nested_hot_dict, hot_param_dict)
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
# Add stack param to vnf_attributes # Add stack param to vnf_attributes
vnf['attributes'].update({'stack_param': str(hot_param_dict)}) vnf['attributes'].update({'stack_param': str(hot_param_dict)})
@ -366,6 +346,79 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
return stack['stack']['id'] 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 @log.log
def _delete_user_data_module(self, user_data_module): def _delete_user_data_module(self, user_data_module):
# Delete module recursively. # Delete module recursively.
@ -1674,10 +1727,18 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
for zone in grant.zones: for zone in grant.zones:
if zone.id == addrsc.zone_id: if zone.id == addrsc.zone_id:
for rsc in vnf_info['addResources']: for rsc in vnf_info['addResources']:
if addrsc.id == rsc.id: if addrsc.resource_definition_id == rsc.id:
vdu_name = rsc.vdu_id vdu_name = rsc.vdu_id
break 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: if 'vim_assets' in grant and grant.vim_assets:
for flavour in grant.vim_assets.compute_resource_flavours: for flavour in grant.vim_assets.compute_resource_flavours:
vdu_name = flavour.vnfd_virtual_compute_desc_id vdu_name = flavour.vnfd_virtual_compute_desc_id