Merge "Move get network configs action to utils"

This commit is contained in:
Zuul 2020-09-16 11:20:47 +00:00 committed by Gerrit Code Review
commit 7885485d61
5 changed files with 271 additions and 351 deletions

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import logging
from mistral_lib import actions
@ -24,7 +23,6 @@ from tripleo_common import constants
from tripleo_common import exception
from tripleo_common.utils import parameters as parameter_utils
from tripleo_common.utils import stack_parameters as stack_param_utils
from tripleo_common.utils import template as template_utils
LOG = logging.getLogger(__name__)
@ -155,79 +153,11 @@ class GetNetworkConfigAction(base.TripleOAction):
self.role_name = role_name
def run(self, context):
swift = self.get_object_client(context)
heat = self.get_orchestration_client(context)
processed_data = template_utils.process_templates(
swift, heat, container=self.container
)
# Default temporary value is used when no user input for any
# interface routes for the role networks to find network config.
role_networks = processed_data['template'].get('resources', {}).get(
self.role_name + 'GroupVars', {}).get('properties', {}).get(
'value', {}).get('role_networks', [])
for nw in role_networks:
rt = nw + 'InterfaceRoutes'
if rt not in processed_data['environment']['parameter_defaults']:
processed_data['environment']['parameter_defaults'][rt] = [[]]
# stacks.preview method raises validation message if stack is
# already deployed. here renaming container to get preview data.
container_temp = self.container + "-TEMP"
fields = {
'template': processed_data['template'],
'files': processed_data['files'],
'environment': processed_data['environment'],
'stack_name': container_temp,
}
orc = self.get_orchestration_client(context)
preview_data = orc.stacks.preview(**fields)
try:
result = self.get_network_config(preview_data, container_temp,
self.role_name)
return result
except exception.DeriveParamsError as err:
LOG.exception('Derive Params Error: %s' % err)
return actions.Result(error=str(err))
def get_network_config(self, preview_data, stack_name, role_name):
result = None
if preview_data:
for res in preview_data.resources:
net_script = self.process_preview_list(res,
stack_name,
role_name)
if net_script:
ns_len = len(net_script)
start_index = (net_script.find(
"echo '{\"network_config\"", 0, ns_len) + 6)
# In file network/scripts/run-os-net-config.sh
end_str = "' > /etc/os-net-config/config.json"
end_index = net_script.find(end_str, start_index, ns_len)
if (end_index > start_index):
net_config = net_script[start_index:end_index]
if net_config:
result = json.loads(net_config)
break
if not result:
err_msg = ("Unable to determine network config for role '%s'."
% self.role_name)
raise exception.DeriveParamsError(err_msg)
return result
def process_preview_list(self, res, stack_name, role_name):
if type(res) == list:
for item in res:
out = self.process_preview_list(item, stack_name, role_name)
if out:
return out
elif type(res) == dict:
res_stack_name = stack_name + '-' + role_name
if res['resource_name'] == "OsNetConfigImpl" and \
res['resource_identity'] and \
res_stack_name in res['resource_identity']['stack_name']:
return res['properties']['config']
return None
return stack_param_utils.get_network_configs(
self.get_baremetal_client(context),
self.get_compute_client(context),
self.container, self.role_name)
except Exception as err:
LOG.exception(six.text_type(err))
return actions.Result(six.text_type(err))

View File

@ -14,10 +14,6 @@
# under the License.
from unittest import mock
import yaml
from swiftclient import exceptions as swiftexceptions
from tripleo_common.actions import parameters
from tripleo_common import exception
from tripleo_common.tests import base
@ -49,273 +45,3 @@ class GetProfileOfFlavorActionTest(base.TestCase):
result = action.run(mock_ctx)
self.assertTrue(result.is_error())
mock_get_profile_of_flavor.assert_called_once()
class GetNetworkConfigActionTest(base.TestCase):
@mock.patch('tripleo_common.utils.plan.'
'cache_set')
@mock.patch('tripleo_common.utils.plan.'
'cache_get')
@mock.patch('heatclient.common.template_utils.'
'process_multiple_environments_and_files')
@mock.patch('heatclient.common.template_utils.get_template_contents')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={},
files={},
template={'heat_template_version': '2016-04-30'},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.plan.'
'cache_set')
@mock.patch('tripleo_common.utils.plan.'
'cache_get')
@mock.patch('heatclient.common.template_utils.'
'process_multiple_environments_and_files')
@mock.patch('heatclient.common.template_utils.get_template_contents')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config_with_no_interface_routes_inputs(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}
}
}}
})
mock_process_multiple_environments_and_files.return_value = (
{}, {'parameter_defaults': {}})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={'parameter_defaults': {
'InternalApiInterfaceRoutes': [[]],
'StorageInterfaceRoutes': [[]]}},
files={},
template={'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {
'properties': {'value': {
'role_networks': ['InternalApi',
'Storage']}}}}},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.plan.'
'cache_set')
@mock.patch('tripleo_common.utils.plan.'
'cache_get')
@mock.patch('heatclient.common.template_utils.'
'process_multiple_environments_and_files')
@mock.patch('heatclient.common.template_utils.get_template_contents')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_valid_network_config_with_interface_routes_inputs(
self, mock_get_object_client, mock_get_workflow_client,
mock_get_orchestration_client, mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get,
mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}}}}
})
mock_process_multiple_environments_and_files.return_value = (
{}, {'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']}})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
expected = {"network_config": {}}
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']}},
files={},
template={'heat_template_version': '2016-04-30',
'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi',
'Storage']}}}}},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.plan.'
'cache_set')
@mock.patch('tripleo_common.utils.plan.'
'cache_get')
@mock.patch('heatclient.common.template_utils.'
'process_multiple_environments_and_files')
@mock.patch('heatclient.common.template_utils.get_template_contents')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_orchestration_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.'
'get_workflow_client')
@mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client')
def test_run_invalid_network_config(
self, mock_get_object_client,
mock_get_workflow_client, mock_get_orchestration_client,
mock_get_template_contents,
mock_process_multiple_environments_and_files,
mock_cache_get, mock_cache_set):
mock_ctx = mock.MagicMock()
swift = mock.MagicMock(url="http://test.com")
mock_env = yaml.safe_dump({
'temp_environment': 'temp_environment',
'template': 'template',
'environments': [{u'path': u'environments/test.yaml'}]
}, default_flow_style=False)
swift.get_object.side_effect = (
({}, mock_env),
swiftexceptions.ClientException('atest2'),
({}, mock_env)
)
mock_get_object_client.return_value = swift
mock_get_template_contents.return_value = ({}, {
'heat_template_version': '2016-04-30'
})
mock_process_multiple_environments_and_files.return_value = ({}, {})
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": ""}
}])
mock_get_orchestration_client.return_value = mock_heat
mock_cache_get.return_value = None
# Test
action = parameters.GetNetworkConfigAction(container='overcloud',
role_name='Compute')
result = action.run(mock_ctx)
self.assertTrue(result.is_error())
mock_heat.stacks.preview.assert_called_once_with(
environment={},
files={},
template={'heat_template_version': '2016-04-30'},
stack_name='overcloud-TEMP',
)

View File

@ -680,3 +680,182 @@ class StackParametersTest(base.TestCase):
"pcmk_host_list": "compute_name_5"
}
})
@mock.patch('tripleo_common.utils.template.process_templates')
def test_run_valid_network_config(self, mock_process_templates):
swift = mock.MagicMock(url="http://test.com")
mock_env = {
'template': {},
'files': {},
'environment': [{'path': 'environments/test.yaml'}]
}
mock_process_templates.return_value = mock_env
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_heat.stacks.get.return_value = mock.Mock(
stack_name="overcloud-TEMP")
expected = {"network_config": {}}
# Test
result = stack_parameters.get_network_configs(
swift, mock_heat, container='overcloud', role_name='Compute')
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment=[{'path': 'environments/test.yaml'}],
files={},
template={},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.template.process_templates')
def test_run_invalid_network_config(self, mock_process_templates):
swift = mock.MagicMock(url="http://test.com")
mock_env = {
'template': {},
'files': {},
'environment': [{'path': 'environments/test.yaml'}]
}
mock_process_templates.return_value = mock_env
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": ""}
}])
mock_heat.stacks.get.return_value = mock.Mock(
stack_name="overcloud-TEMP")
# Test
self.assertRaises(RuntimeError,
stack_parameters.get_network_configs, swift,
mock_heat, container='overcloud',
role_name='Compute')
mock_heat.stacks.preview.assert_called_once_with(
environment=[{'path': 'environments/test.yaml'}],
files={},
template={},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.template.process_templates')
def test_run_valid_network_config_with_no_if_routes_inputs(
self, mock_process_templates):
swift = mock.MagicMock(url="http://test.com")
mock_env = {
'template': {
'resources': {
'ComputeGroupVars': {
'properties': {
'value': {
'role_networks': ['InternalApi',
'Storage']}
}
}
}
},
'files': {},
'environment': {'parameter_defaults': {}}
}
mock_process_templates.return_value = mock_env
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_heat.stacks.get.return_value = mock.Mock(
stack_name="overcloud-TEMP")
expected = {"network_config": {}}
# Test
result = stack_parameters.get_network_configs(
swift, mock_heat, container='overcloud', role_name='Compute')
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={
'parameter_defaults': {
'InternalApiInterfaceRoutes': [[]],
'StorageInterfaceRoutes': [[]]
}
},
files={},
template={'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}
}}}},
stack_name='overcloud-TEMP',
)
@mock.patch('tripleo_common.utils.template.process_templates')
def test_run_valid_network_config_with_if_routes_inputs(
self, mock_process_templates):
swift = mock.MagicMock(url="http://test.com")
mock_env = {
'template': {
'resources': {
'ComputeGroupVars': {
'properties': {
'value': {
'role_networks': ['InternalApi',
'Storage']}
}
}
}
},
'files': {},
'environment': {
'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']
}}
}
mock_process_templates.return_value = mock_env
mock_heat = mock.MagicMock()
mock_heat.stacks.preview.return_value = mock.Mock(resources=[{
"resource_identity": {"stack_name": "overcloud-TEMP-Compute-0"},
"resource_name": "OsNetConfigImpl",
"properties": {"config": "echo \'{\"network_config\": {}}\'"
" > /etc/os-net-config/config.json"}
}])
mock_heat.stacks.get.return_value = mock.Mock(
stack_name="overcloud-TEMP")
expected = {"network_config": {}}
# Test
result = stack_parameters.get_network_configs(
swift, mock_heat, container='overcloud', role_name='Compute')
self.assertEqual(expected, result)
mock_heat.stacks.preview.assert_called_once_with(
environment={
'parameter_defaults': {
'InternalApiInterfaceRoutes': ['test1'],
'StorageInterfaceRoutes': ['test2']
}
},
files={},
template={'resources': {'ComputeGroupVars': {'properties': {
'value': {'role_networks': ['InternalApi', 'Storage']}
}}}},
stack_name='overcloud-TEMP',
)

View File

@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import logging
import time
import uuid
@ -278,3 +279,67 @@ def get_local_cacert(local_ca_path):
return None
except Exception:
raise
def preview_stack_and_network_configs(heat, processed_data,
container, role_name):
# stacks.preview method raises validation message if stack is
# already deployed. here renaming container to get preview data.
container_temp = container + "-TEMP"
fields = {
'template': processed_data['template'],
'files': processed_data['files'],
'environment': processed_data['environment'],
'stack_name': container_temp,
}
preview_data = heat.stacks.preview(**fields)
try:
stack = heat.stacks.get(container_temp)
except heat_exc.HTTPNotFound:
msg = "Error retrieving stack: %s" % container_temp
LOG.exception(msg)
raise RuntimeError(msg)
return get_network_config(preview_data, stack.stack_name, role_name)
def get_network_config(preview_data, stack_name, role_name):
result = None
if preview_data:
for res in preview_data.resources:
net_script = process_preview_list(res, stack_name,
role_name)
if net_script:
ns_len = len(net_script)
start_index = (net_script.find(
"echo '{\"network_config\"", 0, ns_len) + 6)
# In file network/scripts/run-os-net-config.sh
end_str = "' > /etc/os-net-config/config.json"
end_index = net_script.find(end_str, start_index, ns_len)
if (end_index > start_index):
net_config = net_script[start_index:end_index]
if net_config:
result = json.loads(net_config)
break
if not result:
err_msg = ("Unable to determine network config for role '%s'."
% role_name)
LOG.exception(err_msg)
raise RuntimeError(err_msg)
return result
def process_preview_list(res, stack_name, role_name):
if type(res) == list:
for item in res:
out = process_preview_list(item, stack_name, role_name)
if out:
return out
elif type(res) == dict:
res_stack_name = stack_name + '-' + role_name
if res['resource_name'] == "OsNetConfigImpl" and \
res['resource_identity'] and \
res_stack_name in res['resource_identity']['stack_name']:
return res['properties']['config']
return None

View File

@ -220,3 +220,23 @@ def generate_fencing_parameters(ironic, compute, nodes_json, delay,
fence_params["FencingConfig"]["devices"] = devices
return {"parameter_defaults": fence_params}
def get_network_configs(swift, heat, container, role_name):
processed_data = template_utils.process_templates(
swift, heat, container=container
)
# Default temporary value is used when no user input for any
# interface routes for the role networks to find network config.
role_networks = processed_data['template'].get('resources', {}).get(
role_name + 'GroupVars', {}).get('properties', {}).get(
'value', {}).get('role_networks', [])
for nw in role_networks:
rt = nw + 'InterfaceRoutes'
if rt not in processed_data['environment']['parameter_defaults']:
processed_data['environment']['parameter_defaults'][rt] = [[]]
network_configs = stack_utils.preview_stack_and_network_configs(
heat, processed_data, container, role_name)
return network_configs