Merge "Support TOSCA route for ChgExternalConnectivity"
This commit is contained in:
commit
c6c8c7b6ba
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import time
|
||||
import yaml
|
||||
|
||||
@ -447,3 +448,31 @@ class BaseTackerTest(base.BaseTestCase):
|
||||
self.validate_vnf_instance(vnfd_instance, vnf_instance)
|
||||
|
||||
return vnf_instance, tosca_dict
|
||||
|
||||
def _list_op_occs(self, filter_string=''):
|
||||
show_url = os.path.join(
|
||||
self.base_vnf_lcm_op_occs_url)
|
||||
resp, response_body = self.http_client.do_request(
|
||||
show_url + filter_string, "GET")
|
||||
return resp, response_body
|
||||
|
||||
def _assert_occ_list(self, resp, op_occs_list):
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Only check required parameters.
|
||||
for op_occs_info in op_occs_list:
|
||||
self.assertIsNotNone(op_occs_info.get('id'))
|
||||
self.assertIsNotNone(op_occs_info.get('operationState'))
|
||||
self.assertIsNotNone(op_occs_info.get('stateEnteredTime'))
|
||||
self.assertIsNotNone(op_occs_info.get('vnfInstanceId'))
|
||||
self.assertIsNotNone(op_occs_info.get('operation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isAutomaticInvocation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isCancelPending'))
|
||||
|
||||
_links = op_occs_info.get('_links')
|
||||
self.assertIsNotNone(_links.get('self'))
|
||||
self.assertIsNotNone(_links.get('self').get('href'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance').get('href'))
|
||||
self.assertIsNotNone(_links.get('grant'))
|
||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||
|
@ -527,14 +527,6 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
|
||||
return resp, response_body
|
||||
|
||||
def _list_op_occs(self, filter_string=''):
|
||||
show_url = os.path.join(
|
||||
self.base_vnf_lcm_op_occs_url)
|
||||
resp, response_body = self.http_client.do_request(
|
||||
show_url + filter_string, "GET")
|
||||
|
||||
return resp, response_body
|
||||
|
||||
def _wait_terminate_vnf_instance(self, id, timeout=None):
|
||||
start_time = int(time.time())
|
||||
|
||||
|
@ -30,6 +30,7 @@ VNF_PACKAGE_UPLOAD_TIMEOUT = 300
|
||||
VNF_INSTANTIATE_TIMEOUT = 600
|
||||
VNF_TERMINATE_TIMEOUT = 600
|
||||
VNF_HEAL_TIMEOUT = 600
|
||||
VNF_CHANGE_EXT_CONN_TIMEOUT = 600
|
||||
RETRY_WAIT_TIME = 5
|
||||
|
||||
|
||||
@ -47,9 +48,68 @@ def generate_mac_address():
|
||||
return ':'.join(map(lambda x: "%02x" % x, mac))
|
||||
|
||||
|
||||
def generate_ip_addresses(
|
||||
type_='IPV4',
|
||||
fixed_addresses=None,
|
||||
subnet_id=None):
|
||||
if fixed_addresses:
|
||||
ip_addr = {
|
||||
'type': type_,
|
||||
'fixedAddresses': fixed_addresses
|
||||
}
|
||||
if subnet_id:
|
||||
ip_addr.update({'subnetId': subnet_id})
|
||||
return [ip_addr]
|
||||
|
||||
|
||||
def get_ext_cp_with_external_link_port(nw_resource_id, port_uuid):
|
||||
ext_cp = {
|
||||
"id": "external_network",
|
||||
"resourceId": nw_resource_id,
|
||||
"extCps": [{
|
||||
"cpdId": "CP2",
|
||||
"cpConfig": [{
|
||||
"linkPortId": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET"
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
"extLinkPorts": [{
|
||||
"id": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||
"resourceHandle": {
|
||||
"resourceId": port_uuid,
|
||||
"vimLevelResourceType": "LINKPORT"
|
||||
}
|
||||
}]
|
||||
}
|
||||
return ext_cp
|
||||
|
||||
|
||||
def get_ext_cp_with_fixed_address(nw_resource_id, fixed_addresses, subnet_id):
|
||||
ext_cp = {
|
||||
"id": "external_network",
|
||||
"resourceId": nw_resource_id,
|
||||
"extCps": [{
|
||||
"cpdId": "CP2",
|
||||
"cpConfig": [{
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET",
|
||||
"ipOverEthernet": {
|
||||
"ipAddresses": generate_ip_addresses(
|
||||
fixed_addresses=fixed_addresses,
|
||||
subnet_id=subnet_id)
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
return ext_cp
|
||||
|
||||
|
||||
def get_external_virtual_links(net_0_resource_id, net_mgmt_resource_id,
|
||||
port_uuid):
|
||||
return [
|
||||
port_uuid, fixed_addresses=None, subnet_id=None):
|
||||
ext_vl = [
|
||||
{
|
||||
"id": "net0",
|
||||
"resourceId": net_0_resource_id,
|
||||
@ -63,28 +123,18 @@ def get_external_virtual_links(net_0_resource_id, net_mgmt_resource_id,
|
||||
}
|
||||
}]
|
||||
}]
|
||||
}]},
|
||||
{
|
||||
"id": "external_network",
|
||||
"resourceId": net_mgmt_resource_id,
|
||||
"extCps": [{
|
||||
"cpdId": "CP2",
|
||||
"cpConfig": [{
|
||||
"linkPortId": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||
"cpProtocolData": [{
|
||||
"layerProtocol": "IP_OVER_ETHERNET"
|
||||
}]
|
||||
}]
|
||||
}],
|
||||
"extLinkPorts": [{
|
||||
"id": "413f4e46-21cf-41b1-be0f-de8d23f76cfe",
|
||||
"resourceHandle": {
|
||||
"resourceId": port_uuid,
|
||||
"vimLevelResourceType": "LINKPORT"
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
if fixed_addresses:
|
||||
ext_cp = get_ext_cp_with_fixed_address(
|
||||
net_mgmt_resource_id, fixed_addresses, subnet_id)
|
||||
else:
|
||||
ext_cp = get_ext_cp_with_external_link_port(
|
||||
net_mgmt_resource_id, port_uuid)
|
||||
ext_vl.append(ext_cp)
|
||||
|
||||
return ext_vl
|
||||
|
||||
|
||||
def _create_and_upload_vnf_package(tacker_client, csar_package_name,
|
||||
@ -170,6 +220,7 @@ class VnfLcmTest(base.BaseTackerTest):
|
||||
def setUp(self):
|
||||
super(VnfLcmTest, self).setUp()
|
||||
self.base_url = "/vnflcm/v1/vnf_instances"
|
||||
self.base_vnf_lcm_op_occs_url = "/vnflcm/v1/vnf_lcm_op_occs"
|
||||
|
||||
vim_list = self.client.list_vims()
|
||||
if not vim_list:
|
||||
@ -254,8 +305,8 @@ class VnfLcmTest(base.BaseTackerTest):
|
||||
self.assertEqual(200, resp.status_code)
|
||||
return vnf_instances
|
||||
|
||||
def _stack_update_wait(self, stack_id, expected_status):
|
||||
timeout = VNF_HEAL_TIMEOUT
|
||||
def _stack_update_wait(self, stack_id, expected_status,
|
||||
timeout=VNF_HEAL_TIMEOUT):
|
||||
start_time = int(time.time())
|
||||
while True:
|
||||
stack = self.h_client.stacks.get(stack_id)
|
||||
@ -403,6 +454,115 @@ class VnfLcmTest(base.BaseTackerTest):
|
||||
# in nova.
|
||||
self._get_server(vdu_resource_id_current)
|
||||
|
||||
def _change_ext_conn_vnf_request(self, vim_id=None, ext_vl=None):
|
||||
request_body = {}
|
||||
if ext_vl:
|
||||
request_body["extVirtualLinks"] = ext_vl
|
||||
|
||||
if vim_id:
|
||||
request_body["vimConnectionInfo"] = [
|
||||
{"id": uuidutils.generate_uuid(),
|
||||
"vimId": vim_id,
|
||||
"vimType": "ETSINFV.OPENSTACK_KEYSTONE.v_2"}]
|
||||
|
||||
return request_body
|
||||
|
||||
def _change_ext_conn_vnf_instance(self, vnf_instance, request_body,
|
||||
expected_stack_status=infra_cnst.STACK_UPDATE_COMPLETE):
|
||||
url = os.path.join(self.base_url, vnf_instance['id'],
|
||||
"change_ext_conn")
|
||||
resp, body = self.http_client.do_request(url, "POST",
|
||||
body=jsonutils.dumps(request_body))
|
||||
self.assertEqual(202, resp.status_code)
|
||||
|
||||
stack = self.h_client.stacks.get(vnf_instance['vnfInstanceName'])
|
||||
# Wait until tacker changes the stack resources as requested
|
||||
# in the change_ext_conn request
|
||||
self._stack_update_wait(stack.id, expected_stack_status,
|
||||
VNF_CHANGE_EXT_CONN_TIMEOUT)
|
||||
|
||||
def _get_heat_stack(self, vnf_instance_id, stack_name):
|
||||
heatclient = self.heatclient()
|
||||
try:
|
||||
stacks = heatclient.stacks.list()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
target_stakcs = list(
|
||||
filter(
|
||||
lambda x: x.stack_name == stack_name,
|
||||
stacks))
|
||||
|
||||
if len(target_stakcs) == 0:
|
||||
return None
|
||||
|
||||
return target_stakcs[0]
|
||||
|
||||
def _get_heat_resource_info(self, stack_id, nested_depth=0,
|
||||
resource_name=None):
|
||||
heatclient = self.heatclient()
|
||||
try:
|
||||
if resource_name is None:
|
||||
resources = heatclient.resources.list(stack_id,
|
||||
nested_depth=nested_depth)
|
||||
else:
|
||||
resources = heatclient.resources.get(stack_id,
|
||||
resource_name)
|
||||
except Exception:
|
||||
return None
|
||||
return resources
|
||||
|
||||
def _get_fixed_ips(self, vnf_instance, request_body):
|
||||
vnf_instance_id = vnf_instance['id']
|
||||
vnf_instance_name = vnf_instance['vnfInstanceName']
|
||||
res_name = None
|
||||
for extvirlink in request_body['extVirtualLinks']:
|
||||
if 'extCps' not in extvirlink:
|
||||
continue
|
||||
for extcps in extvirlink['extCps']:
|
||||
if 'cpdId' in extcps:
|
||||
if res_name is None:
|
||||
res_name = list()
|
||||
res_name.append(extcps['cpdId'])
|
||||
break
|
||||
if res_name is None:
|
||||
return []
|
||||
|
||||
stack = self._get_heat_stack(vnf_instance_id,
|
||||
vnf_instance_name)
|
||||
stack_id = stack.id
|
||||
|
||||
stack_resource = self._get_heat_resource_info(
|
||||
stack_id, nested_depth=2)
|
||||
|
||||
releations = dict()
|
||||
for elmt in stack_resource:
|
||||
if elmt.resource_type != 'OS::Neutron::Port':
|
||||
continue
|
||||
if elmt.resource_name not in res_name:
|
||||
continue
|
||||
parent = getattr(elmt, 'parent_resource', None)
|
||||
releations[parent] = elmt.resource_name
|
||||
|
||||
details = dict()
|
||||
for (parent_name, resource_name) in releations.items():
|
||||
for elmt in stack_resource:
|
||||
if parent_name is None:
|
||||
detail_stack = self._get_heat_resource_info(
|
||||
stack_id, resource_name=resource_name)
|
||||
elif parent_name != elmt.resource_name:
|
||||
continue
|
||||
else:
|
||||
detail_stack = self._get_heat_resource_info(
|
||||
elmt.physical_resource_id, resource_name=resource_name)
|
||||
details[resource_name] = detail_stack
|
||||
|
||||
ans_list = list()
|
||||
for detail in details.values():
|
||||
ans_list.append(detail.attributes['fixed_ips'])
|
||||
|
||||
return ans_list
|
||||
|
||||
def test_create_show_delete_vnf_instance(self):
|
||||
"""Create, show and delete a vnf instance."""
|
||||
|
||||
@ -881,3 +1041,100 @@ class VnfLcmTest(base.BaseTackerTest):
|
||||
self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body)
|
||||
|
||||
self._delete_vnf_instance(vnf_instance['id'])
|
||||
|
||||
def test_inst_chgextconn_term(self):
|
||||
"""Test change external vnf connectivity.
|
||||
|
||||
This test will instantiate vnf with external virtual link and
|
||||
change the IP address on virtual link.
|
||||
"""
|
||||
|
||||
# Create vnf instance
|
||||
vnf_instance_name = "vnf_with_ext_vl_and_ext_managed_vl-%s" % \
|
||||
uuidutils.generate_uuid()
|
||||
vnf_instance_description = "vnf_with_ext_vl_and_ext_managed_vl"
|
||||
resp, vnf_instance = self._create_vnf_instance(self.vnfd_id_3,
|
||||
vnf_instance_name=vnf_instance_name,
|
||||
vnf_instance_description=vnf_instance_description)
|
||||
|
||||
self.assertIsNotNone(vnf_instance['id'])
|
||||
self.assertEqual(201, resp.status_code)
|
||||
|
||||
neutron_client = self.neutronclient()
|
||||
net = neutron_client.list_networks()
|
||||
networks = {}
|
||||
for network in net['networks']:
|
||||
networks[network['name']] = network['id']
|
||||
subnet_list = neutron_client.list_subnets()
|
||||
subnets = {}
|
||||
for subnet in subnet_list['subnets']:
|
||||
subnets[subnet['name']] = subnet['id']
|
||||
|
||||
net1_id = networks.get('net1')
|
||||
if not net1_id:
|
||||
self.fail("net1 network is not available")
|
||||
|
||||
net0_id = networks.get('net0')
|
||||
if not net0_id:
|
||||
self.fail("net0 network is not available")
|
||||
|
||||
net_mgmt_id = networks.get('net_mgmt')
|
||||
if not net_mgmt_id:
|
||||
self.fail("net_mgmt network is not available")
|
||||
|
||||
subnet_mgmt_id = subnets.get('subnet_mgmt')
|
||||
if not subnet_mgmt_id:
|
||||
self.fail("subnet_mgmt subnet is not available")
|
||||
|
||||
ext_managed_vl = get_ext_managed_virtual_link("net1", "VL3",
|
||||
net1_id)
|
||||
|
||||
network_uuid = self._create_network(neutron_client,
|
||||
"external_network")
|
||||
subnet_uuid = self._create_subnet(neutron_client, network_uuid)
|
||||
|
||||
# Instantiate vnf
|
||||
ext_vl = get_external_virtual_links(
|
||||
net0_id, net_mgmt_id, None,
|
||||
fixed_addresses=['192.168.120.100'],
|
||||
subnet_id=subnet_mgmt_id)
|
||||
|
||||
request_body = self._instantiate_vnf_request("simple",
|
||||
vim_id=self.vim_id, ext_vl=ext_vl, ext_managed_vl=ext_managed_vl)
|
||||
|
||||
self._instantiate_vnf_instance(vnf_instance['id'], request_body)
|
||||
|
||||
vnf_instance = self._show_vnf_instance(vnf_instance['id'])
|
||||
vdu_count = len(vnf_instance['instantiatedVnfInfo']
|
||||
['vnfcResourceInfo'])
|
||||
self.assertEqual(1, vdu_count)
|
||||
|
||||
# Change external vnf connectivity
|
||||
changed_ext_vl = get_external_virtual_links(
|
||||
net0_id, network_uuid, None,
|
||||
fixed_addresses=['22.22.0.100'],
|
||||
subnet_id=subnet_uuid)
|
||||
change_ext_conn_req_body = self._change_ext_conn_vnf_request(
|
||||
vim_id=self.vim_id, ext_vl=changed_ext_vl)
|
||||
before_fixed_ips = self._get_fixed_ips(vnf_instance, request_body)
|
||||
self._change_ext_conn_vnf_instance(
|
||||
vnf_instance, change_ext_conn_req_body)
|
||||
after_fixed_ips = self._get_fixed_ips(vnf_instance, request_body)
|
||||
self.assertNotEqual(before_fixed_ips, after_fixed_ips)
|
||||
|
||||
# Get op-occs
|
||||
resp, op_occs_info = self._list_op_occs()
|
||||
self._assert_occ_list(resp, op_occs_info)
|
||||
|
||||
# Wait for operation state completed
|
||||
time.sleep(10)
|
||||
|
||||
# Terminate vnf gracefully with graceful timeout set to 60
|
||||
terminate_req_body = {
|
||||
"terminationType": fields.VnfInstanceTerminationType.GRACEFUL,
|
||||
'gracefulTerminationTimeout': 60
|
||||
}
|
||||
|
||||
self._terminate_vnf_instance(vnf_instance['id'], terminate_req_body)
|
||||
|
||||
self._delete_vnf_instance(vnf_instance['id'])
|
||||
|
@ -1860,27 +1860,6 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
self.assertIsNotNone(_links.get('grant'))
|
||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||
|
||||
def _assert_occ_list(self, resp, op_occs_list):
|
||||
self.assertEqual(200, resp.status_code)
|
||||
|
||||
# Only check required parameters.
|
||||
for op_occs_info in op_occs_list:
|
||||
self.assertIsNotNone(op_occs_info.get('id'))
|
||||
self.assertIsNotNone(op_occs_info.get('operationState'))
|
||||
self.assertIsNotNone(op_occs_info.get('stateEnteredTime'))
|
||||
self.assertIsNotNone(op_occs_info.get('vnfInstanceId'))
|
||||
self.assertIsNotNone(op_occs_info.get('operation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isAutomaticInvocation'))
|
||||
self.assertIsNotNone(op_occs_info.get('isCancelPending'))
|
||||
|
||||
_links = op_occs_info.get('_links')
|
||||
self.assertIsNotNone(_links.get('self'))
|
||||
self.assertIsNotNone(_links.get('self').get('href'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance'))
|
||||
self.assertIsNotNone(_links.get('vnfInstance').get('href'))
|
||||
self.assertIsNotNone(_links.get('grant'))
|
||||
self.assertIsNotNone(_links.get('grant').get('href'))
|
||||
|
||||
def _assert_fail_vnf_response(self, fail_response):
|
||||
|
||||
# Only check parameters with cardinality = 1
|
||||
|
@ -558,6 +558,134 @@ def get_vnf_attribute_dict():
|
||||
return vnf_attribute_dict
|
||||
|
||||
|
||||
def get_stack_template():
|
||||
stack_template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'VDU1': {
|
||||
'type': 'OS::Nova::Server',
|
||||
'properties': {
|
||||
'name': 'VDU1',
|
||||
'flavor': 'm1.tiny',
|
||||
'image': 'None',
|
||||
'networks': [
|
||||
{
|
||||
'port': {'get_resource': 'VDU1_CP1'},
|
||||
}, {
|
||||
'port': {'get_resource': 'VDU1_CP2'},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
'VDU1_CP1': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': "nw-resource-id-1",
|
||||
'fixed_ips': [{
|
||||
'ip_address': '10.10.0.1',
|
||||
}],
|
||||
},
|
||||
},
|
||||
'VDU1_CP2': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': "nw-resource-id-1",
|
||||
'fixed_ips': [{
|
||||
'ip_address': '10.10.0.2',
|
||||
'subnet': 'subnet-id-2',
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return stack_template
|
||||
|
||||
|
||||
def get_stack_nested_template():
|
||||
stack_nested_template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'VDU2': {
|
||||
'type': 'OS::Nova::Server',
|
||||
'properties': {
|
||||
'name': 'VDU2',
|
||||
'flavor': 'm1.tiny',
|
||||
'image': 'cirros-0.4.0-x86_64-disk',
|
||||
'networks': [
|
||||
{
|
||||
'port': {'get_resource': 'VDU2_CP1'},
|
||||
}, {
|
||||
'port': {'get_resource': 'VDU2_CP2'},
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
'VDU2_CP1': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': 'nw-resource-id-2',
|
||||
'fixed_ips': [{
|
||||
'subnet': 'subnet-id-2',
|
||||
}],
|
||||
},
|
||||
},
|
||||
'VDU2_CP2': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': 'nw-resource-id-2',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return stack_nested_template
|
||||
|
||||
|
||||
def get_expected_update_resource_property_calls():
|
||||
calls = {
|
||||
'VDU1_CP1': {
|
||||
'resource_types': ['OS::Neutron::Port'],
|
||||
'network': 'nw-resource-id-1',
|
||||
'fixed_ips': [{
|
||||
'ip_address': '20.0.0.1'
|
||||
}],
|
||||
},
|
||||
'VDU1_CP2': {
|
||||
'resource_types': ['OS::Neutron::Port'],
|
||||
'network': 'nw-resource-id-1',
|
||||
'fixed_ips': [{
|
||||
'ip_address': '30.0.0.2',
|
||||
'subnet': 'changed-subnet-id-1',
|
||||
}],
|
||||
},
|
||||
'VDU1_CP3': {
|
||||
'resource_types': ['OS::Neutron::Port'],
|
||||
'network': 'nw-resource-id-1',
|
||||
'fixed_ips': [{
|
||||
'ip_address': '10.0.0.1'
|
||||
}],
|
||||
},
|
||||
'VDU2_CP1': {
|
||||
'resource_types': ['OS::Neutron::Port'],
|
||||
'network': 'changed-nw-resource-id-2',
|
||||
'fixed_ips': [{
|
||||
'subnet': 'changed-subnet-id-2',
|
||||
}],
|
||||
},
|
||||
'VDU2_CP2': {
|
||||
'resource_types': ['OS::Neutron::Port'],
|
||||
'network': 'changed-nw-resource-id-2',
|
||||
'fixed_ips': None,
|
||||
},
|
||||
}
|
||||
return calls
|
||||
|
||||
|
||||
def get_lcm_op_occs_object(operation="INSTANTIATE",
|
||||
error_point=0):
|
||||
vnf_lcm_op_occs = objects.VnfLcmOpOcc(
|
||||
|
@ -2912,19 +2912,16 @@ class TestOpenStack(base.FixturedTestCase):
|
||||
self.assertEqual('30435eb8-1472-4cbc-abbe-00b395165ce7', grp_id)
|
||||
|
||||
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||
@mock.patch('tacker.vnflcm.utils.get_base_nest_hot_dict')
|
||||
def test_change_ext_conn_vnf(self,
|
||||
mock_get_base_hot_dict,
|
||||
mock_mock_OpenstackClients_heat):
|
||||
@mock.patch('tacker.vnfm.infra_drivers.openstack.update_template.'
|
||||
'HOTUpdater')
|
||||
def test_change_ext_conn_vnf_with_userdata(self,
|
||||
mock_hot_updater,
|
||||
mock_OpenstackClients_heat):
|
||||
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||
|
||||
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||
instantiated_vnf_info=inst_vnf_info)
|
||||
|
||||
nested_hot_dict = {'parameters': {'vnf': 'test'}}
|
||||
mock_get_base_hot_dict.return_value = \
|
||||
self._read_file(), nested_hot_dict
|
||||
|
||||
vnf_dict['vnfd'] = fd_utils.get_vnfd_dict()
|
||||
vnf_dict['attributes'] = fd_utils.get_vnf_attribute_dict()
|
||||
|
||||
@ -2939,6 +2936,38 @@ class TestOpenStack(base.FixturedTestCase):
|
||||
str(fd_utils.get_expect_stack_param()),
|
||||
vnf_dict['attributes']['stack_param'])
|
||||
|
||||
@mock.patch('tacker.common.clients.OpenstackClients')
|
||||
@mock.patch('tacker.vnfm.infra_drivers.openstack.update_template'
|
||||
'.HOTUpdater')
|
||||
def test_change_ext_conn_vnf_without_userdata(self,
|
||||
mock_hot_updater,
|
||||
mock_OpenstackClients_heat):
|
||||
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||
|
||||
vnf_instance = fd_utils.get_vnf_instance_object(
|
||||
instantiated_vnf_info=inst_vnf_info)
|
||||
|
||||
vnf_dict['vnfd'] = fd_utils.get_vnfd_dict()
|
||||
vnf_dict['attributes'] = {}
|
||||
|
||||
vim_connection_info = fd_utils.get_vim_connection_info_object()
|
||||
change_ext_conn_request = fd_utils.get_change_ext_conn_request()
|
||||
|
||||
hot_instance = mock_hot_updater.return_value
|
||||
hot_instance.template = fd_utils.get_stack_template()
|
||||
hot_instance.nested_templates = {
|
||||
'VDU2.yaml': fd_utils.get_stack_nested_template(),
|
||||
}
|
||||
|
||||
self.openstack.change_ext_conn_vnf(
|
||||
self.context, vnf_instance, vnf_dict,
|
||||
vim_connection_info, change_ext_conn_request)
|
||||
hot_instance.get_templates_from_stack.assert_called_once()
|
||||
for resource, args in (fd_utils.
|
||||
get_expected_update_resource_property_calls().items()):
|
||||
hot_instance.update_resource_property.assert_any_call(
|
||||
resource, **args)
|
||||
|
||||
def test_change_ext_conn_vnf_wait(self):
|
||||
inst_vnf_info = fd_utils.get_vnf_instantiated_info()
|
||||
|
||||
|
@ -0,0 +1,227 @@
|
||||
# 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 unittest import mock
|
||||
|
||||
from heatclient.v1 import resources
|
||||
from tacker.tests.unit import base
|
||||
from tacker.tests import uuidsentinel
|
||||
from tacker.vnfm.infra_drivers.openstack.heat_client import HeatClient
|
||||
from tacker.vnfm.infra_drivers.openstack.update_template import HOTUpdater
|
||||
|
||||
|
||||
class TestUpdateTemplate(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestUpdateTemplate, self).setUp()
|
||||
self.maxDiff = None
|
||||
self._mock_heatclient()
|
||||
self.stack_id = uuidsentinel.stack_id
|
||||
self.hot_updater = HOTUpdater(self.heatclient)
|
||||
|
||||
def _mock_heatclient(self):
|
||||
self.heatclient = mock.Mock(spec=HeatClient)
|
||||
self.heatclient.stacks = mock.Mock()
|
||||
self.heatclient.stacks.template.side_effect = [
|
||||
self._get_template(),
|
||||
self._get_intermediate_template1(),
|
||||
self._get_nested_template1(),
|
||||
self._get_intermediate_template2(),
|
||||
self._get_nested_template2()
|
||||
]
|
||||
self.heatclient.resource_get_list.return_value = \
|
||||
self._get_stack_resources()
|
||||
|
||||
def test_get_templates_from_stack(self):
|
||||
self.hot_updater.get_templates_from_stack(self.stack_id)
|
||||
|
||||
self.assertDictEqual(self._get_template(), self.hot_updater.template)
|
||||
self.assertDictEqual(
|
||||
{'VDU1.yaml': self._get_nested_template1(),
|
||||
'VDU2.yaml': self._get_nested_template2()},
|
||||
self.hot_updater.nested_templates)
|
||||
|
||||
def test_update_resource_property(self):
|
||||
self.hot_updater.get_templates_from_stack(self.stack_id)
|
||||
|
||||
# Test pattern 1: Change network and CP1(DHCP) address to fixed.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CP1', ['OS::Neutron::Port'],
|
||||
network=uuidsentinel.network_id_cp1_changed,
|
||||
fixed_ips=[{'ip_address': '20.20.0.100'}])
|
||||
expected = {
|
||||
'network': uuidsentinel.network_id_cp1_changed,
|
||||
'fixed_ips': [{'ip_address': '20.20.0.100'}]
|
||||
}
|
||||
self.assertEqual(
|
||||
expected,
|
||||
self.hot_updater.template['resources']['CP1']['properties'])
|
||||
|
||||
# Test pattern 2: Change network and fixed address.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CP2', ['OS::Neutron::Port'],
|
||||
network=uuidsentinel.network_id_cp2_changed,
|
||||
fixed_ips=[{
|
||||
'ip_address': '20.20.0.200',
|
||||
'subnet': uuidsentinel.subnet_id_cp2_changed
|
||||
}])
|
||||
expected = {
|
||||
'network': uuidsentinel.network_id_cp2_changed,
|
||||
'fixed_ips': [{
|
||||
'ip_address': '20.20.0.200',
|
||||
'subnet': uuidsentinel.subnet_id_cp2_changed,
|
||||
}]
|
||||
}
|
||||
self.assertEqual(
|
||||
expected,
|
||||
self.hot_updater.template['resources']['CP2']['properties'])
|
||||
|
||||
# Test Pattern 3: Delete fixed_ips property.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CP3', ['OS::Neutron::Port'],
|
||||
network=uuidsentinel.network_id_cp3_changed,
|
||||
fixed_ips=None)
|
||||
self.assertIsNone(self.hot_updater.nested_templates[
|
||||
'VDU1.yaml']['resources']['CP3']['properties'].get('fixed_ips'))
|
||||
|
||||
def test_update_resource_property_not_found(self):
|
||||
self.hot_updater.get_templates_from_stack(self.stack_id)
|
||||
|
||||
# Test Pattern 4: Resource does not exist.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CPX', ['OS::Neutron::Port'],
|
||||
network=uuidsentinel.network_id_cpx,
|
||||
fixed_ips=[{'ip_address': '20.20.0.100'}])
|
||||
self.assertEqual(self._get_template(), self.hot_updater.template)
|
||||
|
||||
# Test Pattern 5: Resource type does not exist.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CP1', ['OS::Sahara::Cluster'],
|
||||
network=uuidsentinel.network_id_cp1_changed,
|
||||
fixed_ips=[{'ip_address': '20.20.0.100'}])
|
||||
self.assertEqual(self._get_template(), self.hot_updater.template)
|
||||
|
||||
# Test Pattern 6: Resource doess not have properties.
|
||||
self.hot_updater.update_resource_property(
|
||||
'CP5', ['OS::Neutron::Port'],
|
||||
network=uuidsentinel.network_id_cp5,
|
||||
fixed_ips=[{'ip_address': '20.20.0.100'}])
|
||||
self.assertEqual(self._get_template(), self.hot_updater.template)
|
||||
|
||||
def _get_template(self):
|
||||
return {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'CP1': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': uuidsentinel.network_id_cp1,
|
||||
},
|
||||
},
|
||||
'CP2': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': uuidsentinel.network_id_cp2,
|
||||
'fixed_ips': [{
|
||||
'ip_address': '10.10.0.200',
|
||||
'subnet': uuidsentinel.subnet_id_cp2,
|
||||
}],
|
||||
},
|
||||
},
|
||||
'CP5': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _get_intermediate_template1(self):
|
||||
return {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'xxxxxxxx': {
|
||||
'type': 'VDU1.yaml',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _get_intermediate_template2(self):
|
||||
return {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'yyyyyyyy': {
|
||||
'type': 'VDU2.yaml',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _get_nested_template1(self):
|
||||
return {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'CP3': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': uuidsentinel.network_id_cp3,
|
||||
'fixed_ips': [{
|
||||
'subnet': uuidsentinel.subnet_id_cp3,
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _get_nested_template2(self):
|
||||
return {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'description': 'Simple deployment flavour for Sample VNF',
|
||||
'parameters': {},
|
||||
'resources': {
|
||||
'CP4': {
|
||||
'type': 'OS::Neutron::Port',
|
||||
'properties': {
|
||||
'network': uuidsentinel.network_id_cp4,
|
||||
'fixed_ips': [{
|
||||
'subnet': uuidsentinel.subnet_id_cp4,
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def _get_stack_resources(self):
|
||||
def _create_resource(resource_name, resource_type):
|
||||
return resources.Resource(None, {
|
||||
'resource_name': resource_name,
|
||||
'resource_type': resource_type,
|
||||
'resource_status': 'CREATE_COMPLETE',
|
||||
'physical_resource_id': uuidsentinel.uuid,
|
||||
})
|
||||
|
||||
data = [
|
||||
('VDU1_scale_group', 'OS::Heat::AutoScalingGroup'),
|
||||
('xxxxxxxx', 'VDU1.yaml'),
|
||||
('VDU2_scale_group', 'OS::Heat::AutoScalingGroup'),
|
||||
('yyyyyyyy', 'VDU2.yaml'),
|
||||
('CP1', 'OS::Neutron::Port'),
|
||||
('CP2', 'OS::Neutron::Port'),
|
||||
('CP3', 'OS::Neutron::Port'),
|
||||
('CP4', 'OS::Neutron::Port')
|
||||
]
|
||||
return [_create_resource(row[0], row[1]) for row in data]
|
@ -49,6 +49,7 @@ from tacker.vnfm.infra_drivers.openstack import constants as infra_cnst
|
||||
from tacker.vnfm.infra_drivers.openstack import glance_client as gc
|
||||
from tacker.vnfm.infra_drivers.openstack import heat_client as hc
|
||||
from tacker.vnfm.infra_drivers.openstack import translate_template
|
||||
from tacker.vnfm.infra_drivers.openstack import update_template as ut
|
||||
from tacker.vnfm.infra_drivers.openstack import vdu
|
||||
from tacker.vnfm.infra_drivers import scale_driver
|
||||
from tacker.vnfm.lcm_user_data.constants import USER_DATA_TIMEOUT
|
||||
@ -58,6 +59,7 @@ eventlet.monkey_patch(time=True)
|
||||
|
||||
SCALING_GROUP_RESOURCE = "OS::Heat::AutoScalingGroup"
|
||||
NOVA_SERVER_RESOURCE = "OS::Nova::Server"
|
||||
NEUTRON_PORT_RESOURCE = "OS::Neutron::Port"
|
||||
|
||||
VNF_PACKAGE_HOT_DIR = 'Files'
|
||||
|
||||
@ -1725,6 +1727,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||
ip_addr, vnfc_rsc.id)
|
||||
raise exceptions.InvalidIpAddr(
|
||||
id=vnfc_rsc.id)
|
||||
ip_addr = fixed_ip.get('ip_address')
|
||||
ip_addresses.addresses.append(ip_addr)
|
||||
ip_addresses.subnet_id = fixed_ip.get(
|
||||
'subnet_id')
|
||||
@ -1743,7 +1746,7 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||
resource.resource_id =\
|
||||
rsc_info.physical_resource_id
|
||||
resource.vim_level_resource_type =\
|
||||
'OS::Neutron::Port'
|
||||
NEUTRON_PORT_RESOURCE
|
||||
if not vl.vnf_link_ports:
|
||||
vl.vnf_link_ports = []
|
||||
link_port_info = objects.\
|
||||
@ -2264,14 +2267,61 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||
def change_ext_conn_vnf(self, context, vnf_instance, vnf_dict,
|
||||
vim_connection_info, change_ext_conn_req):
|
||||
|
||||
base_hot_dict, nested_hot_dict = \
|
||||
vnflcm_utils.get_base_nest_hot_dict(
|
||||
context,
|
||||
vnf_instance.instantiated_vnf_info.flavour_id,
|
||||
vnf_instance.vnfd_id)
|
||||
stack_param = yaml.safe_load(
|
||||
vnf_dict['attributes']['stack_param'])
|
||||
access_info = vim_connection_info.access_info
|
||||
heatclient = hc.HeatClient(access_info,
|
||||
region_name=access_info.get('region'))
|
||||
|
||||
hot_updater = ut.HOTUpdater(heatclient)
|
||||
hot_updater.get_templates_from_stack(
|
||||
vnf_instance.instantiated_vnf_info.instance_id)
|
||||
|
||||
if 'stack_param' in vnf_dict['attributes']:
|
||||
LOG.debug('Target VNF instantiated with userdata.')
|
||||
self._change_ext_conn_vnf_with_userdata(
|
||||
context,
|
||||
hot_updater,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
vim_connection_info,
|
||||
change_ext_conn_req)
|
||||
else:
|
||||
LOG.debug('Target VNF instantiated with '
|
||||
'translating heat-template.')
|
||||
self._change_ext_conn_vnf_with_tosca(
|
||||
context,
|
||||
hot_updater,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
vim_connection_info,
|
||||
change_ext_conn_req)
|
||||
|
||||
def _get_fixed_ips_from_ip_addr(self, ip_addr):
|
||||
fixed_ips = dict()
|
||||
updated_fixed_ips = []
|
||||
if ip_addr.fixed_addresses:
|
||||
for address in ip_addr.fixed_addresses:
|
||||
fixed_ips = dict(ip_address=address)
|
||||
if ip_addr.subnet_id:
|
||||
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||
updated_fixed_ips.append(fixed_ips)
|
||||
elif ip_addr.num_dynamic_addresses > 0:
|
||||
if ip_addr.subnet_id:
|
||||
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||
updated_fixed_ips.append(fixed_ips)
|
||||
else:
|
||||
updated_fixed_ips = None
|
||||
|
||||
return updated_fixed_ips
|
||||
|
||||
def _change_ext_conn_vnf_with_userdata(
|
||||
self,
|
||||
context,
|
||||
hot_updater,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
vim_connection_info,
|
||||
change_ext_conn_req):
|
||||
stack_param = yaml.safe_load(vnf_dict['attributes']['stack_param'])
|
||||
LOG.debug('before stack_param: {}'.format(stack_param))
|
||||
cp_param = stack_param['nfv']['CP']
|
||||
|
||||
@ -2293,34 +2343,65 @@ class OpenStack(abstract_driver.VnfAbstractDriver,
|
||||
# and ip_addresses cannot get, do nothing
|
||||
continue
|
||||
|
||||
fixed_ips = dict()
|
||||
updated_fixed_ips = []
|
||||
if ip_addr.fixed_addresses:
|
||||
for address in ip_addr.fixed_addresses:
|
||||
fixed_ips = dict(ip_address=address)
|
||||
if ip_addr.subnet_id:
|
||||
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||
updated_fixed_ips.append(fixed_ips)
|
||||
elif ip_addr.num_dynamic_addresses > 0:
|
||||
if ip_addr.subnet_id:
|
||||
fixed_ips.update(dict(subnet=ip_addr.subnet_id))
|
||||
updated_fixed_ips.append(fixed_ips)
|
||||
updated_fixed_ips = self._get_fixed_ips_from_ip_addr(ip_addr)
|
||||
if updated_fixed_ips:
|
||||
cp_param[cpd_id].update(
|
||||
dict(fixed_ips=updated_fixed_ips))
|
||||
|
||||
LOG.debug('after stack_param: {}'.format(stack_param))
|
||||
|
||||
access_info = vim_connection_info.access_info
|
||||
heatclient = hc.HeatClient(access_info,
|
||||
region_name=access_info.get('region'))
|
||||
|
||||
# Update heat-stack with BaseHOT and parameters
|
||||
self._update_stack_with_user_data(
|
||||
heatclient, vnf_instance, base_hot_dict, nested_hot_dict,
|
||||
stack_param, vnf_instance.instantiated_vnf_info.instance_id)
|
||||
hot_updater.heatclient,
|
||||
vnf_instance,
|
||||
hot_updater.template,
|
||||
hot_updater.nested_templates,
|
||||
stack_param,
|
||||
vnf_instance.instantiated_vnf_info.instance_id)
|
||||
vnf_dict['attributes'].update({'stack_param': str(stack_param)})
|
||||
|
||||
def _change_ext_conn_vnf_with_tosca(
|
||||
self,
|
||||
context,
|
||||
hot_updater,
|
||||
vnf_instance,
|
||||
vnf_dict,
|
||||
vim_connection_info,
|
||||
change_ext_conn_req):
|
||||
for ext_virtual_link in change_ext_conn_req.ext_virtual_links:
|
||||
for ext_cp in ext_virtual_link.ext_cps:
|
||||
cpd_id = ext_cp.cpd_id
|
||||
|
||||
try:
|
||||
ip_addr = ext_cp.cp_config[0].cp_protocol_data[0].\
|
||||
ip_over_ethernet.ip_addresses[0]
|
||||
except IndexError:
|
||||
# If the element under ext_cp does not exist,
|
||||
# and ip_addresses cannot get, do nothing
|
||||
continue
|
||||
|
||||
updated_fixed_ips = self._get_fixed_ips_from_ip_addr(ip_addr)
|
||||
hot_updater.update_resource_property(
|
||||
cpd_id,
|
||||
resource_types=[NEUTRON_PORT_RESOURCE],
|
||||
network=ext_virtual_link.resource_id,
|
||||
fixed_ips=updated_fixed_ips)
|
||||
|
||||
# Set parameters to update heat-stack
|
||||
update_parameters = {
|
||||
'template': self._format_base_hot(hot_updater.template),
|
||||
}
|
||||
if hot_updater.nested_templates:
|
||||
files_dict = dict()
|
||||
for name, value in hot_updater.nested_templates.items():
|
||||
files_dict[name] = self._format_base_hot(value)
|
||||
update_parameters['files'] = files_dict
|
||||
|
||||
# Update heat-stack
|
||||
self._update_stack(
|
||||
hot_updater.heatclient,
|
||||
vnf_instance.instantiated_vnf_info.instance_id,
|
||||
update_parameters)
|
||||
|
||||
@log.log
|
||||
def change_ext_conn_vnf_wait(self, context, vnf_instance,
|
||||
vim_connection_info):
|
||||
|
98
tacker/vnfm/infra_drivers/openstack/update_template.py
Normal file
98
tacker/vnfm/infra_drivers/openstack/update_template.py
Normal file
@ -0,0 +1,98 @@
|
||||
# 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 oslo_log import log as logging
|
||||
|
||||
from tacker.common import log
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HOTUpdater(object):
|
||||
"""Update HOT template."""
|
||||
|
||||
def __init__(self, heatclient):
|
||||
self.heatclient = heatclient
|
||||
self.template = {}
|
||||
self.nested_templates = dict()
|
||||
|
||||
@log.log
|
||||
def get_templates_from_stack(self, stack_id):
|
||||
"""Get template information from the stack.
|
||||
|
||||
Get the template from stack specified by stack_id,
|
||||
if stack has scalable resource, get the its child
|
||||
template.
|
||||
"""
|
||||
|
||||
def _get_resource(name, resources):
|
||||
for resource in resources:
|
||||
if resource.resource_name == name:
|
||||
return resource
|
||||
|
||||
self.template = self.heatclient.stacks.template(stack_id)
|
||||
LOG.debug('got main template for stack({}). template={}'.format(
|
||||
stack_id, self.template))
|
||||
|
||||
stack_resources = self.heatclient.resource_get_list(stack_id,
|
||||
nested_depth=2)
|
||||
for resource in stack_resources:
|
||||
if resource.resource_type == 'OS::Heat::AutoScalingGroup':
|
||||
intermediate_template = self.heatclient.stacks.template(
|
||||
resource.physical_resource_id)
|
||||
|
||||
for resource_id in intermediate_template['resources'].keys():
|
||||
corresponding_resource = _get_resource(resource_id,
|
||||
stack_resources)
|
||||
nested_template = self.heatclient.stacks.template(
|
||||
corresponding_resource.physical_resource_id)
|
||||
LOG.debug('got nested template for stack({}). template={}'
|
||||
.format(corresponding_resource.physical_resource_id,
|
||||
nested_template))
|
||||
if nested_template:
|
||||
self.nested_templates[
|
||||
corresponding_resource.resource_type] = nested_template
|
||||
|
||||
@log.log
|
||||
def update_resource_property(self,
|
||||
resource_id,
|
||||
resource_types=[],
|
||||
**kwargs):
|
||||
"""Update attributes of resource properties.
|
||||
|
||||
Get the resource information from template's resources section,
|
||||
and update properties using kwargs information.
|
||||
If resource type does not include in resource_types, nothing to do.
|
||||
"""
|
||||
|
||||
def _update(template, resource_id, resource_types, kwargs):
|
||||
resource = template.get('resources', {}).get(resource_id)
|
||||
if not resource:
|
||||
return
|
||||
if resource.get('type', {}) not in resource_types:
|
||||
return
|
||||
|
||||
resource_properties = resource.get('properties', {})
|
||||
if not resource_properties:
|
||||
return
|
||||
|
||||
for key, value in kwargs.items():
|
||||
if value is not None:
|
||||
resource_properties.update({key: value})
|
||||
elif resource_properties.get(key):
|
||||
del resource_properties[key]
|
||||
|
||||
_update(self.template, resource_id, resource_types, kwargs)
|
||||
|
||||
for value in self.nested_templates.values():
|
||||
nested_template = value
|
||||
_update(nested_template, resource_id, resource_types, kwargs)
|
Loading…
x
Reference in New Issue
Block a user