Optional override of the plan environment file
This change is to add optional override of the plan-environment.yaml file with custom plan environment file. Implements: blueprint tripleo-derive-parameters Change-Id: I45e8103826fdee76a8ec40aebd95cb5551cc5fed
This commit is contained in:
parent
e1a4458061
commit
b0de593246
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Adds optional override of the plan environment file with custom
|
||||||
|
plan environment file.
|
@ -291,6 +291,142 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
|||||||
mock_tarball.tarball_extract_to_swift_container.assert_called_with(
|
mock_tarball.tarball_extract_to_swift_container.assert_called_with(
|
||||||
clients.tripleoclient.object_store, mock.ANY, 'overcloud')
|
clients.tripleoclient.object_store, mock.ANY, 'overcloud')
|
||||||
|
|
||||||
|
@mock.patch('shutil.rmtree', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_deploy_postconfig', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.workflows.plan_management.tarball',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleo_common.update.add_breakpoints_cleanup_into_env',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_validate_args')
|
||||||
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
|
'_create_parameters_env', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.create_tempest_deployer_input',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.workflows.deployment.overcloudrc',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.write_overcloudrc', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.remove_known_hosts', autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.wait_for_stack_ready',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('heatclient.common.template_utils.get_template_contents',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('tripleoclient.utils.check_hypervisor_stats',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch('uuid.uuid1', autospec=True)
|
||||||
|
@mock.patch('time.time', autospec=True)
|
||||||
|
@mock.patch('shutil.copytree', autospec=True)
|
||||||
|
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||||
|
def test_tht_deploy_with_plan_environment_file(
|
||||||
|
self, mock_tmpdir, mock_copy, mock_time, mock_uuid1,
|
||||||
|
mock_check_hypervisor_stats, mock_get_template_contents,
|
||||||
|
wait_for_stack_ready_mock, mock_remove_known_hosts,
|
||||||
|
mock_overcloudrc, mock_write_overcloudrc,
|
||||||
|
mock_create_tempest_deployer, mock_create_parameters_env,
|
||||||
|
mock_validate_args, mock_breakpoints_cleanup,
|
||||||
|
mock_tarball, mock_postconfig,
|
||||||
|
mock_get_overcloud_endpoint, mock_shutil_rmtree):
|
||||||
|
arglist = ['--templates', '-p', 'the-plan-environment.yaml']
|
||||||
|
verifylist = [
|
||||||
|
('templates', '/usr/share/openstack-tripleo-heat-templates/'),
|
||||||
|
('plan_environment_file', 'the-plan-environment.yaml')
|
||||||
|
]
|
||||||
|
|
||||||
|
mock_tmpdir.return_value = "/tmp/tht"
|
||||||
|
mock_uuid1.return_value = "uuid"
|
||||||
|
mock_time.return_value = 123456789
|
||||||
|
|
||||||
|
clients = self.app.client_manager
|
||||||
|
orchestration_client = clients.orchestration
|
||||||
|
mock_stack = fakes.create_tht_stack()
|
||||||
|
orchestration_client.stacks.get.side_effect = [None, mock.Mock()]
|
||||||
|
workflow_client = clients.workflow_engine
|
||||||
|
workflow_client.environments.get.return_value = mock.MagicMock(
|
||||||
|
variables={'environments': []})
|
||||||
|
workflow_client.action_executions.create.return_value = mock.MagicMock(
|
||||||
|
output='{"result":[]}')
|
||||||
|
|
||||||
|
def _orch_clt_create(**kwargs):
|
||||||
|
orchestration_client.stacks.get.return_value = mock_stack
|
||||||
|
|
||||||
|
orchestration_client.stacks.create.side_effect = _orch_clt_create
|
||||||
|
|
||||||
|
object_client = clients.tripleoclient.object_store
|
||||||
|
object_client.get_object = mock.Mock()
|
||||||
|
mock_env = yaml.safe_dump({'environments': []})
|
||||||
|
object_client.get_object.return_value = ({}, mock_env)
|
||||||
|
|
||||||
|
mock_check_hypervisor_stats.return_value = {
|
||||||
|
'count': 4,
|
||||||
|
'memory_mb': 4096,
|
||||||
|
'vcpus': 8,
|
||||||
|
}
|
||||||
|
clients.network.api.find_attr.return_value = {
|
||||||
|
"id": "network id"
|
||||||
|
}
|
||||||
|
mock_get_template_contents.return_value = [{}, "template"]
|
||||||
|
wait_for_stack_ready_mock.return_value = True
|
||||||
|
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
baremetal = clients.baremetal
|
||||||
|
baremetal.node.list.return_value = range(10)
|
||||||
|
|
||||||
|
expected_parameters = {
|
||||||
|
'CephClusterFSID': 'uuid',
|
||||||
|
'CephStorageCount': 3,
|
||||||
|
'ExtraConfig': '{}',
|
||||||
|
'HypervisorNeutronPhysicalBridge': 'br-ex',
|
||||||
|
'HypervisorNeutronPublicInterface': 'nic1',
|
||||||
|
'NeutronDnsmasqOptions': 'dhcp-option-force=26,1400',
|
||||||
|
'NeutronFlatNetworks': 'datacentre',
|
||||||
|
'NeutronNetworkType': 'gre',
|
||||||
|
'NeutronPublicInterface': 'nic1',
|
||||||
|
'NeutronTunnelTypes': 'gre',
|
||||||
|
'NtpServer': '',
|
||||||
|
'SnmpdReadonlyUserPassword': 'PASSWORD',
|
||||||
|
'DeployIdentifier': 123456789,
|
||||||
|
'UpdateIdentifier': '',
|
||||||
|
'StackAction': 'CREATE',
|
||||||
|
}
|
||||||
|
|
||||||
|
testcase = self
|
||||||
|
|
||||||
|
def _custom_create_params_env(self, parameters):
|
||||||
|
for key, value in six.iteritems(parameters):
|
||||||
|
testcase.assertEqual(value, expected_parameters[key])
|
||||||
|
parameter_defaults = {"parameter_defaults": parameters}
|
||||||
|
return parameter_defaults
|
||||||
|
|
||||||
|
mock_create_parameters_env.side_effect = _custom_create_params_env
|
||||||
|
|
||||||
|
mock_open_context = mock.mock_open()
|
||||||
|
with mock.patch('six.moves.builtins.open', mock_open_context):
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.assertFalse(orchestration_client.stacks.create.called)
|
||||||
|
|
||||||
|
mock_get_template_contents.assert_called_with(
|
||||||
|
object_request=mock.ANY,
|
||||||
|
template_object=constants.OVERCLOUD_YAML_NAME)
|
||||||
|
|
||||||
|
mock_create_tempest_deployer.assert_called_with()
|
||||||
|
mock_validate_args.assert_called_once_with(parsed_args)
|
||||||
|
|
||||||
|
mock_tarball.create_tarball.assert_called_with(
|
||||||
|
'/tmp/tht/tripleo-heat-templates', mock.ANY)
|
||||||
|
mock_tarball.tarball_extract_to_swift_container.assert_called_with(
|
||||||
|
clients.tripleoclient.object_store, mock.ANY, 'overcloud')
|
||||||
|
|
||||||
|
workflow_client.action_executions.create.assert_called()
|
||||||
|
workflow_client.executions.create.assert_called()
|
||||||
|
|
||||||
|
mock_open_context.assert_has_calls(
|
||||||
|
[mock.call('the-plan-environment.yaml')])
|
||||||
|
clients.tripleoclient.object_store.put_object.assert_called()
|
||||||
|
|
||||||
@mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True)
|
@mock.patch('tripleoclient.utils.get_overcloud_endpoint', autospec=True)
|
||||||
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||||
'_deploy_postconfig', autospec=True)
|
'_deploy_postconfig', autospec=True)
|
||||||
|
@ -273,6 +273,50 @@ class TestOvercloudCreatePlan(utils.TestCommand):
|
|||||||
mock.call('overcast', u'all-nodes-validation.yaml'),
|
mock.call('overcast', u'all-nodes-validation.yaml'),
|
||||||
], any_order=True)
|
], any_order=True)
|
||||||
|
|
||||||
|
@mock.patch("tripleoclient.workflows.plan_management.tarball")
|
||||||
|
def test_create_custom_plan_plan_environment_file(self,
|
||||||
|
mock_tarball):
|
||||||
|
# Setup
|
||||||
|
arglist = ['overcast', '--templates', '/fake/path',
|
||||||
|
'-p', 'the_plan_environment.yaml']
|
||||||
|
verifylist = [
|
||||||
|
('name', 'overcast'),
|
||||||
|
('templates', '/fake/path'),
|
||||||
|
('plan_environment_file', 'the_plan_environment.yaml')
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
self.websocket.wait_for_messages.return_value = iter([{
|
||||||
|
"execution": {"id": "IDID"},
|
||||||
|
"status": "SUCCESS"
|
||||||
|
}])
|
||||||
|
mock_result = mock.Mock(output='{"result": null}')
|
||||||
|
self.workflow.action_executions.create.return_value = mock_result
|
||||||
|
|
||||||
|
mock_open_context = mock.mock_open()
|
||||||
|
with mock.patch('six.moves.builtins.open', mock_open_context):
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
self.workflow.action_executions.create.assert_called_once_with(
|
||||||
|
'tripleo.plan.create_container', {"container": "overcast"},
|
||||||
|
run_sync=True, save_result=True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.plan_management.v1.create_deployment_plan',
|
||||||
|
workflow_input={
|
||||||
|
'container': 'overcast',
|
||||||
|
'queue_name': 'UUID4',
|
||||||
|
'generate_passwords': True
|
||||||
|
})
|
||||||
|
|
||||||
|
mock_open_context.assert_has_calls(
|
||||||
|
[mock.call('the_plan_environment.yaml')])
|
||||||
|
|
||||||
|
self.tripleoclient.object_store.put_object.assert_called_once_with(
|
||||||
|
'overcast', 'plan-environment.yaml', mock_open_context())
|
||||||
|
|
||||||
def test_create_default_plan_with_password_gen_disabled(self):
|
def test_create_default_plan_with_password_gen_disabled(self):
|
||||||
|
|
||||||
# Setup
|
# Setup
|
||||||
|
@ -118,6 +118,38 @@ class TestPlanCreationWorkflows(utils.TestCommand):
|
|||||||
self.tripleoclient.object_store.put_object.assert_called_once_with(
|
self.tripleoclient.object_store.put_object.assert_called_once_with(
|
||||||
'test-overcloud', 'roles_data.yaml', mock_open_context())
|
'test-overcloud', 'roles_data.yaml', mock_open_context())
|
||||||
|
|
||||||
|
@mock.patch('tripleoclient.workflows.plan_management.tarball',
|
||||||
|
autospec=True)
|
||||||
|
def test_create_plan_from_templates_plan_env_data(self, mock_tarball):
|
||||||
|
output = mock.Mock(output='{"result": ""}')
|
||||||
|
self.workflow.action_executions.create.return_value = output
|
||||||
|
self.websocket.wait_for_messages.return_value = self.message_success
|
||||||
|
|
||||||
|
mock_open_context = mock.mock_open()
|
||||||
|
with mock.patch('six.moves.builtins.open', mock_open_context):
|
||||||
|
plan_management.create_plan_from_templates(
|
||||||
|
self.app.client_manager,
|
||||||
|
'test-overcloud',
|
||||||
|
'/tht-root/',
|
||||||
|
plan_env_file='the-plan-environment.yaml')
|
||||||
|
|
||||||
|
self.workflow.action_executions.create.assert_called_once_with(
|
||||||
|
'tripleo.plan.create_container',
|
||||||
|
{'container': 'test-overcloud'},
|
||||||
|
run_sync=True, save_result=True)
|
||||||
|
|
||||||
|
self.workflow.executions.create.assert_called_once_with(
|
||||||
|
'tripleo.plan_management.v1.create_deployment_plan',
|
||||||
|
workflow_input={'queue_name': 'UUID4',
|
||||||
|
'container': 'test-overcloud',
|
||||||
|
'generate_passwords': True})
|
||||||
|
|
||||||
|
mock_open_context.assert_has_calls(
|
||||||
|
[mock.call('the-plan-environment.yaml')])
|
||||||
|
|
||||||
|
self.tripleoclient.object_store.put_object.assert_called_once_with(
|
||||||
|
'test-overcloud', 'plan-environment.yaml', mock_open_context())
|
||||||
|
|
||||||
def test_delete_plan(self):
|
def test_delete_plan(self):
|
||||||
self.workflow.action_executions.create.return_value = (
|
self.workflow.action_executions.create.return_value = (
|
||||||
mock.Mock(output='{"result": null}'))
|
mock.Mock(output='{"result": null}'))
|
||||||
|
@ -388,11 +388,13 @@ class DeployOvercloud(command.Command):
|
|||||||
# templates.
|
# templates.
|
||||||
plan_management.update_plan_from_templates(
|
plan_management.update_plan_from_templates(
|
||||||
self.clients, parsed_args.stack, tht_root,
|
self.clients, parsed_args.stack, tht_root,
|
||||||
parsed_args.roles_file, generate_passwords)
|
parsed_args.roles_file, generate_passwords,
|
||||||
|
parsed_args.plan_environment_file)
|
||||||
else:
|
else:
|
||||||
plan_management.create_plan_from_templates(
|
plan_management.create_plan_from_templates(
|
||||||
self.clients, parsed_args.stack, tht_root,
|
self.clients, parsed_args.stack, tht_root,
|
||||||
parsed_args.roles_file, generate_passwords)
|
parsed_args.roles_file, generate_passwords,
|
||||||
|
parsed_args.plan_environment_file)
|
||||||
|
|
||||||
# Get any missing (e.g j2 rendered) files from the plan to tht_root
|
# Get any missing (e.g j2 rendered) files from the plan to tht_root
|
||||||
self._download_missing_files_from_plan(
|
self._download_missing_files_from_plan(
|
||||||
@ -685,6 +687,11 @@ class DeployOvercloud(command.Command):
|
|||||||
help=_('Roles file, overrides the default %s in the --templates '
|
help=_('Roles file, overrides the default %s in the --templates '
|
||||||
'directory') % constants.OVERCLOUD_ROLES_FILE
|
'directory') % constants.OVERCLOUD_ROLES_FILE
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--plan-environment-file', '-p',
|
||||||
|
help=_('Plan Environment file, overrides the default %s in the '
|
||||||
|
'--templates directory') % constants.PLAN_ENVIRONMENT
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--no-cleanup', action='store_true',
|
'--no-cleanup', action='store_true',
|
||||||
help=_('Don\'t cleanup temporary files, just log their location')
|
help=_('Don\'t cleanup temporary files, just log their location')
|
||||||
|
@ -19,6 +19,7 @@ from osc_lib.command import command
|
|||||||
from osc_lib.i18n import _
|
from osc_lib.i18n import _
|
||||||
from six.moves.urllib import request
|
from six.moves.urllib import request
|
||||||
|
|
||||||
|
from tripleoclient import constants
|
||||||
from tripleoclient import exceptions
|
from tripleoclient import exceptions
|
||||||
from tripleoclient import utils
|
from tripleoclient import utils
|
||||||
from tripleoclient.workflows import deployment
|
from tripleoclient.workflows import deployment
|
||||||
@ -94,6 +95,11 @@ class CreatePlan(command.Command):
|
|||||||
'If this or --source_url isn\'t provided, the templates '
|
'If this or --source_url isn\'t provided, the templates '
|
||||||
'packaged on the Undercloud will be used.'),
|
'packaged on the Undercloud will be used.'),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--plan-environment-file', '-p',
|
||||||
|
help=_('Plan Environment file, overrides the default %s in the '
|
||||||
|
'--templates directory') % constants.PLAN_ENVIRONMENT
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--disable-password-generation',
|
'--disable-password-generation',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
@ -125,7 +131,8 @@ class CreatePlan(command.Command):
|
|||||||
if parsed_args.templates:
|
if parsed_args.templates:
|
||||||
plan_management.create_plan_from_templates(
|
plan_management.create_plan_from_templates(
|
||||||
clients, name, parsed_args.templates,
|
clients, name, parsed_args.templates,
|
||||||
generate_passwords=generate_passwords)
|
generate_passwords=generate_passwords,
|
||||||
|
plan_env_file=parsed_args.plan_environment_file)
|
||||||
else:
|
else:
|
||||||
plan_management.create_deployment_plan(
|
plan_management.create_deployment_plan(
|
||||||
clients, container=name, queue_name=str(uuid.uuid4()),
|
clients, container=name, queue_name=str(uuid.uuid4()),
|
||||||
|
@ -30,7 +30,8 @@ LOG = logging.getLogger(__name__)
|
|||||||
_WORKFLOW_TIMEOUT = 360 # 6 * 60 seconds
|
_WORKFLOW_TIMEOUT = 360 # 6 * 60 seconds
|
||||||
|
|
||||||
|
|
||||||
def _upload_templates(swift_client, container_name, tht_root, roles_file=None):
|
def _upload_templates(swift_client, container_name, tht_root, roles_file=None,
|
||||||
|
plan_env_file=None):
|
||||||
"""tarball up a given directory and upload it to Swift to be extracted"""
|
"""tarball up a given directory and upload it to Swift to be extracted"""
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile() as tmp_tarball:
|
with tempfile.NamedTemporaryFile() as tmp_tarball:
|
||||||
@ -44,6 +45,15 @@ def _upload_templates(swift_client, container_name, tht_root, roles_file=None):
|
|||||||
swift_client.put_object(container_name,
|
swift_client.put_object(container_name,
|
||||||
constants.OVERCLOUD_ROLES_FILE,
|
constants.OVERCLOUD_ROLES_FILE,
|
||||||
rf)
|
rf)
|
||||||
|
# Optional override of the plan-environment.yaml file
|
||||||
|
if plan_env_file:
|
||||||
|
# TODO(jpalanis): Instead of overriding default file,
|
||||||
|
# merging the user override plan-environment with default
|
||||||
|
# plan-environment file will avoid explict merging issues.
|
||||||
|
with open(plan_env_file) as pf:
|
||||||
|
swift_client.put_object(container_name,
|
||||||
|
constants.PLAN_ENVIRONMENT,
|
||||||
|
pf)
|
||||||
|
|
||||||
|
|
||||||
def create_default_plan(clients, **workflow_input):
|
def create_default_plan(clients, **workflow_input):
|
||||||
@ -139,7 +149,7 @@ def create_container(workflow_client, **input_):
|
|||||||
|
|
||||||
|
|
||||||
def create_plan_from_templates(clients, name, tht_root, roles_file=None,
|
def create_plan_from_templates(clients, name, tht_root, roles_file=None,
|
||||||
generate_passwords=True):
|
generate_passwords=True, plan_env_file=None):
|
||||||
workflow_client = clients.workflow_engine
|
workflow_client = clients.workflow_engine
|
||||||
swift_client = clients.tripleoclient.object_store
|
swift_client = clients.tripleoclient.object_store
|
||||||
|
|
||||||
@ -152,7 +162,7 @@ def create_plan_from_templates(clients, name, tht_root, roles_file=None,
|
|||||||
"Unable to create plan. {}".format(result))
|
"Unable to create plan. {}".format(result))
|
||||||
|
|
||||||
print("Creating plan from template files in: {}".format(tht_root))
|
print("Creating plan from template files in: {}".format(tht_root))
|
||||||
_upload_templates(swift_client, name, tht_root, roles_file)
|
_upload_templates(swift_client, name, tht_root, roles_file, plan_env_file)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
create_deployment_plan(clients, container=name,
|
create_deployment_plan(clients, container=name,
|
||||||
@ -164,7 +174,7 @@ def create_plan_from_templates(clients, name, tht_root, roles_file=None,
|
|||||||
|
|
||||||
|
|
||||||
def update_plan_from_templates(clients, name, tht_root, roles_file=None,
|
def update_plan_from_templates(clients, name, tht_root, roles_file=None,
|
||||||
generate_passwords=True):
|
generate_passwords=True, plan_env_file=None):
|
||||||
swift_client = clients.tripleoclient.object_store
|
swift_client = clients.tripleoclient.object_store
|
||||||
|
|
||||||
# If the plan environment was migrated to Swift, save the generated
|
# If the plan environment was migrated to Swift, save the generated
|
||||||
@ -195,7 +205,7 @@ def update_plan_from_templates(clients, name, tht_root, roles_file=None,
|
|||||||
# need to special-case plan-environment.yaml to avoid this.
|
# need to special-case plan-environment.yaml to avoid this.
|
||||||
|
|
||||||
print("Uploading new plan files")
|
print("Uploading new plan files")
|
||||||
_upload_templates(swift_client, name, tht_root, roles_file)
|
_upload_templates(swift_client, name, tht_root, roles_file, plan_env_file)
|
||||||
_update_passwords(swift_client, name, passwords)
|
_update_passwords(swift_client, name, passwords)
|
||||||
update_deployment_plan(clients, container=name,
|
update_deployment_plan(clients, container=name,
|
||||||
queue_name=str(uuid.uuid4()),
|
queue_name=str(uuid.uuid4()),
|
||||||
|
Loading…
Reference in New Issue
Block a user