Adds detection for legacy API network resource
Currently in network_data.yaml there is compat_name which is used as a workaround for upgrades with regards to a bug where the Heat resource for API network was being created as InternalNetwork instead of InternalApiNetwork. This workaround does work for upgrades, but consequently also causes all future new deployments to have the wrong resource name. This patch adds detection, so that if the legacy resource is detected already in the overcloud stack, then the compatibility will be enabled if not already set in network_data.yaml. This allows for the removal of compat_name from the network in network_data.yaml and thus removing the incorrect name for future deployments. Partial-Bug: 1718764 Change-Id: I695259ad87e2303f948875078bccb619786470e0 Signed-off-by: Tim Rozet <trozet@redhat.com>
This commit is contained in:
parent
5af31b876e
commit
602b481804
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes compatibility between older deployments with Heat resource network
|
||||
"InternalNetwork" and corrected "InternalApiNetwork". Upgrades from
|
||||
previous versions will still use the old naming scheme, while new
|
||||
deployments will use the correct name of "InternalApiNetwork".
|
@ -157,6 +157,26 @@ class ProcessTemplatesAction(base.TripleOAction):
|
||||
"the J2 excludes list to: %s" % j2_excl_data)
|
||||
return j2_excl_data
|
||||
|
||||
def _heat_resource_exists(self, resource_name, context):
|
||||
heatclient = self.get_orchestration_client(context)
|
||||
stack_exists = False
|
||||
for stack in heatclient.stacks.list():
|
||||
if self.container == str(stack.stack_name):
|
||||
stack_exists = True
|
||||
break
|
||||
if not stack_exists:
|
||||
LOG.debug("Resource does not exist because stack does not exist")
|
||||
return False
|
||||
|
||||
resources = heatclient.resources.list(self.container, nested_depth=6)
|
||||
for resource in resources:
|
||||
if str(resource.resource_name) == resource_name:
|
||||
LOG.debug("Resource exists: {}".format(resource_name))
|
||||
return True
|
||||
|
||||
LOG.debug("Resource does not exist: {}".format(resource_name))
|
||||
return False
|
||||
|
||||
def _process_custom_roles(self, context):
|
||||
swift = self.get_object_client(context)
|
||||
|
||||
@ -199,10 +219,19 @@ class ProcessTemplatesAction(base.TripleOAction):
|
||||
|
||||
n_map = {}
|
||||
for n in network_data:
|
||||
if (n.get('enabled') is not False):
|
||||
if n.get('enabled') is not False:
|
||||
n_map[n.get('name')] = n
|
||||
if not n.get('name_lower'):
|
||||
n_map[n.get('name')]['name_lower'] = n.get('name').lower()
|
||||
if n.get('name') == constants.API_NETWORK and 'compat_name' \
|
||||
not in n.keys():
|
||||
# Check to see if legacy named API network exists
|
||||
# and if so we need to set compat_name
|
||||
api_net = "{}Network".format(constants.LEGACY_API_NETWORK)
|
||||
if self._heat_resource_exists(api_net, context):
|
||||
n['compat_name'] = 'Internal'
|
||||
LOG.info("Upgrade compatibility enabled for legacy "
|
||||
"network resource Internal.")
|
||||
else:
|
||||
LOG.info("skipping %s network: network is disabled." %
|
||||
n.get('name'))
|
||||
|
@ -141,6 +141,9 @@ TRIPLEO_CACHE_CONTAINER = "__cache__"
|
||||
TRIPLEO_UI_LOG_FILE_SIZE = 1e7 # 10MB
|
||||
TRIPLEO_UI_LOG_FILENAME = 'tripleo-ui.logs'
|
||||
|
||||
API_NETWORK = 'InternalApi'
|
||||
LEGACY_API_NETWORK = 'Internal'
|
||||
|
||||
# Default nested depth when recursing Heat stacks
|
||||
NESTED_DEPTH = 7
|
||||
|
||||
|
@ -43,7 +43,7 @@ ROLE_DATA_YAML = r"""
|
||||
|
||||
NETWORK_DATA_YAML = r"""
|
||||
-
|
||||
name: anetwork
|
||||
name: InternalApi
|
||||
"""
|
||||
|
||||
EXPECTED_JINJA_RESULT = r"""
|
||||
@ -86,7 +86,7 @@ ROLE_DATA_DISABLE_CONSTRAINTS_YAML = r"""
|
||||
ROLE_DATA_ENABLE_NETWORKS = r"""
|
||||
- name: RoleWithNetworks
|
||||
networks:
|
||||
- anetwork
|
||||
- InternalApi
|
||||
"""
|
||||
|
||||
JINJA_SNIPPET_DISABLE_CONSTRAINTS_OLD = r"""
|
||||
@ -125,8 +125,8 @@ JINJA_SNIPPET_ROLE_NETWORKS = r"""
|
||||
"""
|
||||
|
||||
EXPECTED_JINJA_RESULT_ROLE_NETWORKS = r"""
|
||||
anetworkPort:
|
||||
type: RoleWithNetworks::anetwork::Port
|
||||
InternalApiPort:
|
||||
type: RoleWithNetworks::InternalApi::Port
|
||||
"""
|
||||
|
||||
|
||||
@ -285,8 +285,12 @@ class ProcessTemplatesActionTest(base.TestCase):
|
||||
side_effect=return_container_files)
|
||||
return swift
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._heat_resource_exists')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_process_custom_roles(self, get_obj_client_mock):
|
||||
def test_process_custom_roles(self, get_obj_client_mock,
|
||||
resource_exists_mock):
|
||||
resource_exists_mock.return_value = False
|
||||
swift = self._custom_roles_mock_objclient(
|
||||
'foo.j2.yaml', JINJA_SNIPPET)
|
||||
get_obj_client_mock.return_value = swift
|
||||
@ -315,9 +319,12 @@ class ProcessTemplatesActionTest(base.TestCase):
|
||||
swift.put_object.assert_has_calls(
|
||||
put_object_mock_calls, any_order=True)
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._heat_resource_exists')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def _process_custom_roles_disable_constraints(
|
||||
self, snippet, get_obj_client_mock):
|
||||
self, snippet, get_obj_client_mock, resource_exists_mock):
|
||||
resource_exists_mock.return_value = False
|
||||
swift = self._custom_roles_mock_objclient(
|
||||
'disable-constraints.role.j2.yaml', snippet,
|
||||
ROLE_DATA_DISABLE_CONSTRAINTS_YAML)
|
||||
@ -352,8 +359,12 @@ class ProcessTemplatesActionTest(base.TestCase):
|
||||
self._process_custom_roles_disable_constraints(
|
||||
JINJA_SNIPPET_DISABLE_CONSTRAINTS)
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._heat_resource_exists')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_custom_roles_networks(self, get_obj_client_mock):
|
||||
def test_custom_roles_networks(self, get_obj_client_mock,
|
||||
resource_exists_mock):
|
||||
resource_exists_mock.return_value = False
|
||||
swift = self._custom_roles_mock_objclient(
|
||||
'role-networks.role.j2.yaml', JINJA_SNIPPET_ROLE_NETWORKS,
|
||||
ROLE_DATA_ENABLE_NETWORKS)
|
||||
@ -486,3 +497,104 @@ class ProcessTemplatesActionTest(base.TestCase):
|
||||
# Test - J2 exclude file empty
|
||||
action = templates.ProcessTemplatesAction()
|
||||
self.assertTrue({'name': []} == action._get_j2_excludes_file(mock_ctx))
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_heat_resource_exists(self, client_mock):
|
||||
mock_ctx = mock.MagicMock()
|
||||
heat_client = mock.MagicMock()
|
||||
heat_client.stacks.list.return_value = [
|
||||
mock.MagicMock(stack_name='overcloud')
|
||||
]
|
||||
heat_client.resources.list.return_value = [
|
||||
mock.MagicMock(
|
||||
links=[{'rel': 'stack',
|
||||
'href': 'http://192.0.2.1:8004/v1/'
|
||||
'a959ac7d6a4a475daf2428df315c41ef/'
|
||||
'stacks/overcloud/123'}],
|
||||
logical_resource_id='logical_id',
|
||||
physical_resource_id='resource_id',
|
||||
resource_type='OS::Heat::ResourceGroup',
|
||||
resource_name='InternalNetwork'
|
||||
),
|
||||
]
|
||||
client_mock.return_value = heat_client
|
||||
action = templates.ProcessTemplatesAction()
|
||||
self.assertTrue(action._heat_resource_exists('InternalNetwork',
|
||||
mock_ctx))
|
||||
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.'
|
||||
'get_orchestration_client')
|
||||
def test_no_heat_resource_exists(self, client_mock):
|
||||
mock_ctx = mock.MagicMock()
|
||||
heat_client = mock.MagicMock()
|
||||
heat_client.stacks.list.return_value = [
|
||||
mock.MagicMock(stack_name='overcloud')
|
||||
]
|
||||
heat_client.resources.list.return_value = [
|
||||
mock.MagicMock(
|
||||
links=[{'rel': 'stack',
|
||||
'href': 'http://192.0.2.1:8004/v1/'
|
||||
'a959ac7d6a4a475daf2428df315c41ef/'
|
||||
'stacks/overcloud/123'}],
|
||||
logical_resource_id='logical_id',
|
||||
physical_resource_id='resource_id',
|
||||
resource_type='OS::Heat::ResourceGroup',
|
||||
resource_name='InternalApiNetwork'
|
||||
),
|
||||
]
|
||||
client_mock.return_value = heat_client
|
||||
action = templates.ProcessTemplatesAction()
|
||||
self.assertFalse(action._heat_resource_exists('InternalNetwork',
|
||||
mock_ctx))
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._heat_resource_exists')
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._j2_render_and_put')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_legacy_api_network_exists(self, get_obj_client_mock, j2_mock,
|
||||
resource_exists_mock):
|
||||
resource_exists_mock.return_value = True
|
||||
swift = self._custom_roles_mock_objclient(
|
||||
'role-networks.role.j2.yaml', JINJA_SNIPPET_ROLE_NETWORKS,
|
||||
ROLE_DATA_ENABLE_NETWORKS)
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# Test
|
||||
action = templates.ProcessTemplatesAction()
|
||||
mock_ctx = mock.MagicMock()
|
||||
action._process_custom_roles(mock_ctx)
|
||||
expected_j2_template = get_obj_client_mock.get_object(
|
||||
action.container, 'foo.j2.yaml')[1]
|
||||
expected_j2_data = {'roles': [{'name': 'CustomRole'}],
|
||||
'networks': [{'name': 'InternalApi',
|
||||
'compat_name': 'Internal'}]
|
||||
}
|
||||
assert j2_mock.called_with(expected_j2_template, expected_j2_data,
|
||||
'foo.yaml', mock_ctx)
|
||||
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._heat_resource_exists')
|
||||
@mock.patch('tripleo_common.actions.templates.ProcessTemplatesAction'
|
||||
'._j2_render_and_put')
|
||||
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
|
||||
def test_no_legacy_api_network_exists(self, get_obj_client_mock, j2_mock,
|
||||
resource_exists_mock):
|
||||
resource_exists_mock.return_value = False
|
||||
swift = self._custom_roles_mock_objclient(
|
||||
'role-networks.role.j2.yaml', JINJA_SNIPPET_ROLE_NETWORKS,
|
||||
ROLE_DATA_ENABLE_NETWORKS)
|
||||
get_obj_client_mock.return_value = swift
|
||||
|
||||
# Test
|
||||
action = templates.ProcessTemplatesAction()
|
||||
mock_ctx = mock.MagicMock()
|
||||
action._process_custom_roles(mock_ctx)
|
||||
expected_j2_template = get_obj_client_mock.get_object(
|
||||
action.container, 'foo.j2.yaml')[1]
|
||||
expected_j2_data = {'roles': [{'name': 'CustomRole'}],
|
||||
'networks': [{'name': 'InternalApi'}]
|
||||
}
|
||||
assert j2_mock.called_with(expected_j2_template, expected_j2_data,
|
||||
'foo.yaml', mock_ctx)
|
||||
|
Loading…
Reference in New Issue
Block a user