Remove plan/plan-role management commands
This removes all the plan related commands as we won't have a plan. Change-Id: I77d4fa6e0fa88f3e0429e7dea9115f0460a16c5c
This commit is contained in:
parent
6e802d23e3
commit
1603ed45db
@ -0,0 +1,8 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
``openstack overcloud plan *`` commands have been removed.
|
||||
These commands are irrelevant as overcloud deploy/update/upgrade
|
||||
does not create/update swift plan anymore. Also, some of the
|
||||
``openstack overcloud role`` commands that use swift plan have
|
||||
been removed.
|
@ -67,19 +67,12 @@ openstack.tripleoclient.v2 =
|
||||
overcloud_node_unprovision = tripleoclient.v2.overcloud_node:UnprovisionNode
|
||||
overcloud_node_extract_provisioned = tripleoclient.v1.overcloud_node:ExtractProvisionedNode
|
||||
overcloud_parameters_set = tripleoclient.v1.overcloud_parameters:SetParameters
|
||||
overcloud_plan_create = tripleoclient.v1.overcloud_plan:CreatePlan
|
||||
overcloud_plan_delete = tripleoclient.v1.overcloud_plan:DeletePlan
|
||||
overcloud_plan_deploy = tripleoclient.v1.overcloud_plan:DeployPlan
|
||||
overcloud_plan_list = tripleoclient.v1.overcloud_plan:ListPlans
|
||||
overcloud_plan_export = tripleoclient.v1.overcloud_plan:ExportPlan
|
||||
overcloud_profiles_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
|
||||
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
|
||||
overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID
|
||||
overcloud_role_show= tripleoclient.v1.overcloud_roles:RoleShow
|
||||
overcloud_role_list = tripleoclient.v1.overcloud_roles:RoleList
|
||||
overcloud_roles_generate = tripleoclient.v1.overcloud_roles:RolesGenerate
|
||||
overcloud_roles_list = tripleoclient.v1.overcloud_plan_roles:ListRoles
|
||||
overcloud_roles_show = tripleoclient.v1.overcloud_plan_roles:ShowRole
|
||||
overcloud_support_report_collect = tripleoclient.v2.overcloud_support:ReportExecute
|
||||
overcloud_update_prepare= tripleoclient.v1.overcloud_update:UpdatePrepare
|
||||
overcloud_update_run = tripleoclient.v1.overcloud_update:UpdateRun
|
||||
|
@ -204,16 +204,6 @@ try:
|
||||
except (configparser.NoOptionError, FileNotFoundError):
|
||||
UNDERCLOUD_OUTPUT_DIR = CLOUD_HOME_DIR
|
||||
|
||||
# regex patterns to exclude when looking for unused params
|
||||
# - exclude *Image params as they may be unused because the service is not
|
||||
# enabled
|
||||
# - exclude SwiftFetchDir*Tempurl because it's used by ceph and generated by us
|
||||
# - exclude PythonInterpreter because it's generated by us and only used
|
||||
# in some custom scripts
|
||||
UNUSED_PARAMETER_EXCLUDES_RE = ['^(Docker|Container).*Image$',
|
||||
'^SwiftFetchDir(Get|Put)Tempurl$',
|
||||
'^PythonInterpreter$']
|
||||
|
||||
EXPORT_PASSWORD_EXCLUDE_PATTERNS = [
|
||||
'ceph.*'
|
||||
]
|
||||
|
@ -27,8 +27,6 @@ from osc_lib.tests import utils
|
||||
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import plugin
|
||||
from tripleoclient.tests import fakes as ooofakes
|
||||
from tripleoclient.tests.fixture_data import deployment
|
||||
from tripleoclient.tests.v1.overcloud_deploy import fakes
|
||||
from tripleoclient.v1 import overcloud_deploy
|
||||
@ -91,53 +89,6 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
mock_run_command.start()
|
||||
self.addCleanup(mock_run_command.stop)
|
||||
|
||||
plan_list = mock.patch(
|
||||
"tripleoclient.workflows.plan_management.list_deployment_plans",
|
||||
autospec=True
|
||||
)
|
||||
plan_list.start()
|
||||
plan_list.return_value = ([
|
||||
"test-plan-1",
|
||||
"test-plan-2",
|
||||
])
|
||||
self.addCleanup(plan_list.stop)
|
||||
roles = mock.patch(
|
||||
'tripleoclient.workflows.roles.list_available_roles',
|
||||
autospec=True,
|
||||
return_value=[
|
||||
{
|
||||
'TestRole1': {
|
||||
'TestParameter1': {}
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
roles.start()
|
||||
self.addCleanup(roles.stop)
|
||||
flatten = mock.patch(
|
||||
'tripleo_common.utils.stack_parameters.get_flattened_parameters',
|
||||
autospec=True,
|
||||
return_value={
|
||||
'environment_parameters': {
|
||||
'TestParameter1': {},
|
||||
'TestRole1': 'TestParameter2'
|
||||
},
|
||||
'heat_resource_tree': {
|
||||
'parameters': {
|
||||
'TestParameter2': {
|
||||
'name': 'TestParameter2',
|
||||
'tags': [
|
||||
'role_specific'
|
||||
]
|
||||
}
|
||||
},
|
||||
'resources': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
flatten.start()
|
||||
self.addCleanup(flatten.stop)
|
||||
|
||||
# Mock playbook runner
|
||||
playbook_runner = mock.patch(
|
||||
'tripleoclient.utils.run_ansible_playbook',
|
||||
@ -400,8 +351,6 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
return_value='192.168.0.1 uc.ctlplane.localhost uc.ctlplane')
|
||||
@mock.patch('tripleoclient.utils.check_stack_network_matches_env_files')
|
||||
@mock.patch('tripleoclient.utils.check_ceph_fsid_matches_env_files')
|
||||
@mock.patch('tripleoclient.workflows.parameters.'
|
||||
'check_deprecated_parameters', autospec=True)
|
||||
@mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
|
||||
'_deploy_postconfig', autospec=True)
|
||||
@mock.patch('tripleo_common.update.add_breakpoints_cleanup_into_env',
|
||||
@ -419,7 +368,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
mock_get_template_contents,
|
||||
mock_create_parameters_env, mock_validate_args,
|
||||
mock_breakpoints_cleanup,
|
||||
mock_postconfig, mock_deprecated_params, mock_stack_network_check,
|
||||
mock_postconfig, mock_stack_network_check,
|
||||
mock_ceph_fsid, mock_get_undercloud_host_entry, mock_copy,
|
||||
mock_chdir, mock_overcloudrc,
|
||||
mock_process_env, mock_roles_data,
|
||||
@ -1265,10 +1214,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
|
||||
@mock.patch('tripleoclient.utils.check_stack_network_matches_env_files')
|
||||
@mock.patch('tripleoclient.utils.check_ceph_fsid_matches_env_files')
|
||||
@mock.patch('heatclient.common.template_utils.deep_update', autospec=True)
|
||||
@mock.patch('tripleoclient.workflows.plan_management.'
|
||||
'create_plan_from_templates', autospec=True)
|
||||
def test_config_download_timeout(
|
||||
self, mock_plan_man, mock_hc, mock_stack_network_check,
|
||||
self, mock_hc, mock_stack_network_check,
|
||||
mock_ceph_fsid, mock_hd,
|
||||
mock_get_undercloud_host_entry, mock_copy,
|
||||
mock_get_ctlplane_attrs, mock_nic_ansible,
|
||||
@ -1624,14 +1571,6 @@ class TestGetDeploymentStatus(utils.TestCommand):
|
||||
super(TestGetDeploymentStatus, self).setUp()
|
||||
self.cmd = overcloud_deploy.GetDeploymentStatus(self.app, None)
|
||||
self.app.client_manager = mock.Mock()
|
||||
clients = self.clients = self.app.client_manager
|
||||
tc = clients.tripleoclient = ooofakes.FakeClientWrapper()
|
||||
tc.create_mistral_context = plugin.ClientWrapper(
|
||||
instance=ooofakes.FakeInstanceData
|
||||
).create_mistral_context
|
||||
obj = tc.object_store = mock.Mock()
|
||||
obj.put_object = mock.Mock()
|
||||
obj.put_container = mock.Mock()
|
||||
|
||||
@mock.patch("tripleoclient.workflows.deployment.get_deployment_status")
|
||||
def test_get_deployment_status(self, mock_get_deployment_status):
|
||||
@ -1643,10 +1582,10 @@ class TestGetDeploymentStatus(utils.TestCommand):
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
expected = (
|
||||
'+-----------+-------------------+\n'
|
||||
'| Plan Name | Deployment Status |\n'
|
||||
'+-----------+-------------------+\n'
|
||||
'+------------+-------------------+\n'
|
||||
'| Stack Name | Deployment Status |\n'
|
||||
'+------------+-------------------+\n'
|
||||
'| overcloud | DEPLOY_SUCCESS |\n'
|
||||
'+-----------+-------------------+\n')
|
||||
'+------------+-------------------+\n')
|
||||
|
||||
self.assertEqual(expected, self.cmd.app.stdout.getvalue())
|
||||
|
@ -1,412 +0,0 @@
|
||||
# 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.
|
||||
import mock
|
||||
|
||||
from osc_lib.tests import utils
|
||||
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import plugin
|
||||
from tripleoclient.tests import fakes
|
||||
from tripleoclient.v1 import overcloud_plan
|
||||
|
||||
|
||||
class TestStringCapture(object):
|
||||
def __init__(self):
|
||||
self.capture_string = ''
|
||||
|
||||
def write(self, msg):
|
||||
self.capture_string = self.capture_string + msg
|
||||
|
||||
def getvalue(self):
|
||||
return self.capture_string
|
||||
|
||||
def flush(self):
|
||||
return
|
||||
|
||||
|
||||
class TestOvercloudPlanList(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudPlanList, self).setUp()
|
||||
self.app.client_manager.tripleoclient = plugin.ClientWrapper(
|
||||
instance=fakes.FakeInstanceData
|
||||
)
|
||||
self.cmd = overcloud_plan.ListPlans(self.app, None)
|
||||
|
||||
@mock.patch("tripleoclient.workflows.plan_management."
|
||||
"list_deployment_plans",
|
||||
autospec=True)
|
||||
def test_list_empty(self, mock_list_plans):
|
||||
mock_list_plans.return_value = []
|
||||
|
||||
result = self.cmd.take_action(None)
|
||||
|
||||
self.assertEqual(0, len(result[1]))
|
||||
|
||||
@mock.patch("tripleoclient.workflows.plan_management."
|
||||
"list_deployment_plans",
|
||||
autospec=True)
|
||||
def test_list(self, mock_list_plans):
|
||||
mock_list_plans.return_value = (['test-plan-1', 'test-plan-2'])
|
||||
|
||||
result = self.cmd.take_action(None)
|
||||
|
||||
self.assertEqual(1, len(result[0]))
|
||||
self.assertEqual([('test-plan-1',), ('test-plan-2',)], result[1])
|
||||
|
||||
|
||||
class TestOvercloudDeletePlan(fakes.FakePlaybookExecution):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudDeletePlan, self).setUp()
|
||||
|
||||
self.cmd = overcloud_plan.DeletePlan(self.app, None)
|
||||
|
||||
@mock.patch("tripleo_common.actions.plan.DeletePlanAction.run",
|
||||
return_value=None)
|
||||
def test_delete_plan(self, mock_run):
|
||||
parsed_args = self.check_parser(self.cmd, ['test-plan'],
|
||||
[('plans', ['test-plan'])])
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
@mock.patch("tripleo_common.actions.plan.DeletePlanAction.run",
|
||||
return_value=None)
|
||||
def test_delete_multiple_plans(self, mock_run):
|
||||
argslist = ['test-plan1', 'test-plan2']
|
||||
verifylist = [('plans', ['test-plan1', 'test-plan2'])]
|
||||
parsed_args = self.check_parser(self.cmd, argslist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
|
||||
class TestOvercloudCreatePlan(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudCreatePlan, self).setUp()
|
||||
|
||||
app_args = mock.Mock()
|
||||
app_args.verbose_level = 1
|
||||
self.app.options = fakes.FakeOptions()
|
||||
self.cmd = overcloud_plan.CreatePlan(self.app, app_args)
|
||||
self.app.client_manager.workflow_engine = mock.Mock()
|
||||
self.tripleoclient = mock.Mock()
|
||||
self.app.client_manager.tripleoclient = self.tripleoclient
|
||||
|
||||
self.swift = self.app.client_manager.tripleoclient.object_store
|
||||
self.swift.get_account = mock.MagicMock()
|
||||
self.mock_tar = mock.patch(
|
||||
'tripleo_common.utils.tarball.create_tarball',
|
||||
autospec=True
|
||||
)
|
||||
self.mock_tar.start()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestOvercloudCreatePlan, self).tearDown()
|
||||
self.mock_tar.stop()
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_default_plan(self, mock_tmp, mock_cd, mock_run_playbook):
|
||||
|
||||
# Setup
|
||||
arglist = ['overcast']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('templates', None)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# Run
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
# Verify
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": True,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_custom_plan(self, mock_tmp, mock_cd,
|
||||
mock_run_playbook):
|
||||
|
||||
# Setup
|
||||
arglist = ['overcast', '--templates', '/fake/path']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('templates', '/fake/path')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# Run
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
# Verify
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
self.swift.get_account.assert_called_once()
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_custom_plan_plan_environment_file(
|
||||
self, mock_tmp, mock_cd, mock_run_playbook):
|
||||
# Setup
|
||||
arglist = ['overcast', '--templates', '/fake/path',
|
||||
'-p', 'the_plan_environment.yaml']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('templates', '/fake/path'),
|
||||
('plan_environment_file', 'the_plan_environment.yaml')
|
||||
]
|
||||
self.app.options = fakes.FakeOptions()
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
mock_open = mock.mock_open()
|
||||
# Run
|
||||
with mock.patch('six.moves.builtins.open', mock_open):
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_open.assert_has_calls(
|
||||
[mock.call('the_plan_environment.yaml', 'rb')])
|
||||
|
||||
# Verify
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"generate_passwords": True,
|
||||
"plan_environment": "the_plan_environment.yaml",
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
self.swift.get_account.assert_called_once()
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_default_plan_with_password_gen_disabled(
|
||||
self, mock_tmp, mock_cd, mock_run_playbook):
|
||||
|
||||
# Setup
|
||||
arglist = ['overcast', '--disable-password-generation',
|
||||
'--disable-container-prepare']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('templates', None),
|
||||
('disable_password_generation', True),
|
||||
('disable_container_prepare', True)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# Run
|
||||
self.app.options = fakes.FakeOptions()
|
||||
self.cmd.take_action(parsed_args)
|
||||
# Verify
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"generate_passwords": False,
|
||||
"use_default_templates": True,
|
||||
"disable_image_params_prepare": True,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_custom_plan_from_source_url(
|
||||
self, mock_tmp, mock_cd, mock_run_playbook):
|
||||
|
||||
# Setup
|
||||
arglist = ['overcast', '--source-url', 'http://tripleo.org/templates']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('templates', None),
|
||||
('source_url', 'http://tripleo.org/templates')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# Run
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
# Verify
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": False,
|
||||
"source_url": "http://tripleo.org/templates",
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
|
||||
|
||||
class TestOvercloudDeployPlan(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudDeployPlan, self).setUp()
|
||||
|
||||
app_args = mock.Mock()
|
||||
app_args.verbose_level = 1
|
||||
self.app.options = fakes.FakeOptions()
|
||||
self.cmd = overcloud_plan.DeployPlan(self.app, app_args)
|
||||
|
||||
sleep_patch = mock.patch('time.sleep')
|
||||
self.addCleanup(sleep_patch.stop)
|
||||
sleep_patch.start()
|
||||
|
||||
@mock.patch("tripleoclient.utils.update_deployment_status", autospec=True)
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('tripleoclient.utils.wait_for_stack_ready', autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_overcloud_deploy_plan(self, mock_tmp, mock_cd,
|
||||
mock_for_stack_ready,
|
||||
mock_run_playbook,
|
||||
mock_update_status):
|
||||
|
||||
# Setup
|
||||
arglist = ['--run-validations', 'overcast']
|
||||
verifylist = [
|
||||
('name', 'overcast'),
|
||||
('run_validations', True),
|
||||
('timeout', 240)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.orch = self.app.client_manager.orchestration = mock.Mock()
|
||||
# No existing stack, this is a new deploy.
|
||||
self.orch.stacks.get.return_value = None
|
||||
|
||||
mock_for_stack_ready.return_value = True
|
||||
|
||||
# Run
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-deploy-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
timeout=240,
|
||||
extra_vars={
|
||||
"container": "overcast",
|
||||
"run_validations": True,
|
||||
"skip_deploy_identifier": False,
|
||||
},
|
||||
verbosity=3,
|
||||
)
|
||||
mock_update_status.assert_called()
|
||||
|
||||
|
||||
class TestOvercloudExportPlan(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudExportPlan, self).setUp()
|
||||
self.cmd = overcloud_plan.ExportPlan(self.app, None)
|
||||
self.app.client_manager = mock.Mock()
|
||||
self.clients = self.app.client_manager
|
||||
|
||||
# Mock urlopen
|
||||
f = mock.Mock()
|
||||
f.read.return_value = 'tarball contents'
|
||||
urlopen_patcher = mock.patch('six.moves.urllib.request.urlopen',
|
||||
return_value=f)
|
||||
self.mock_urlopen = urlopen_patcher.start()
|
||||
self.addCleanup(self.mock_urlopen.stop)
|
||||
|
||||
@mock.patch(
|
||||
'tripleoclient.workflows.plan_management.export_deployment_plan',
|
||||
autospec=True)
|
||||
def test_export_plan(self, export_deployment_plan_mock):
|
||||
parsed_args = self.check_parser(self.cmd, ['test-plan'],
|
||||
[('plan', 'test-plan')])
|
||||
|
||||
export_deployment_plan_mock.return_value = 'http://fake-url.com'
|
||||
|
||||
with mock.patch('six.moves.builtins.open', mock.mock_open()):
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
export_deployment_plan_mock.assert_called_once_with(
|
||||
self.clients, 'test-plan')
|
||||
|
||||
@mock.patch('os.path.exists')
|
||||
def test_export_plan_outfile_exists(self, exists_mock):
|
||||
parsed_args = self.check_parser(self.cmd, ['test-plan'],
|
||||
[('plan', 'test-plan')])
|
||||
|
||||
exists_mock.return_value = True
|
||||
|
||||
self.assertRaises(exceptions.PlanExportError,
|
||||
self.cmd.take_action, parsed_args)
|
||||
|
||||
@mock.patch(
|
||||
'tripleoclient.workflows.plan_management.export_deployment_plan',
|
||||
autospec=True)
|
||||
@mock.patch('os.path.exists')
|
||||
def test_export_plan_outfile_exists_with_overwrite(
|
||||
self, exists_mock, export_deployment_plan_mock):
|
||||
arglist = ['-f', 'test-plan']
|
||||
verifylist = [
|
||||
('plan', 'test-plan'),
|
||||
('force_overwrite', True)
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
exists_mock.return_value = True
|
||||
export_deployment_plan_mock.return_value = 'http://fake-url.com'
|
||||
|
||||
with mock.patch('six.moves.builtins.open', mock.mock_open()):
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
export_deployment_plan_mock.assert_called_once_with(
|
||||
self.clients, 'test-plan')
|
@ -1,169 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import mock
|
||||
|
||||
from osc_lib import exceptions
|
||||
from osc_lib.tests import utils
|
||||
|
||||
from tripleoclient.v1 import overcloud_plan_roles
|
||||
|
||||
|
||||
class BaseTestCommand(utils.TestCommand):
|
||||
def setUp(self):
|
||||
super(BaseTestCommand, self).setUp()
|
||||
|
||||
tc = self.app.client_manager.tripleoclient = mock.Mock()
|
||||
tc.object_store.get_object.return_value = (
|
||||
{},
|
||||
'{"result": [{"name":"Controller","description":"Test desc",'
|
||||
'"random": "abcd"},{"name":"Test"}]}'
|
||||
)
|
||||
tc.object_store.get_container.return_value = (
|
||||
'container',
|
||||
[
|
||||
{
|
||||
"name": "Controller",
|
||||
"description": "Test desc",
|
||||
"random": "abcd",
|
||||
"efg": "123",
|
||||
"ServicesDefault": [
|
||||
"b",
|
||||
"c",
|
||||
"a"
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
self.tripleoclient = tc
|
||||
|
||||
|
||||
class TestOvercloudListCurrentRoles(BaseTestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudListCurrentRoles, self).setUp()
|
||||
|
||||
self.cmd = overcloud_plan_roles.ListRoles(self.app, None)
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=[]
|
||||
)
|
||||
def test_list_empty_on_non_default_plan(self, mock_list):
|
||||
arglist = ['--name', 'overcast', '--current']
|
||||
verifylist = [('name', 'overcast'), ('current', True)]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(0, len(result[1]))
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=["ObjectStorage", "Controller"]
|
||||
)
|
||||
def test_list(self, mock_list):
|
||||
arglist = ['--current']
|
||||
verifylist = [('name', 'overcloud'), ('current', True)]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(2, len(result[1]))
|
||||
self.assertEqual([('Controller',), ('ObjectStorage',)], result[1])
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=[
|
||||
{
|
||||
"name": "Controller",
|
||||
"description": "Test desc",
|
||||
"random": "abcd"
|
||||
},
|
||||
{"name": "Test"}
|
||||
]
|
||||
)
|
||||
def test_list_with_details(self, mock_list):
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--current', '--detail'],
|
||||
[])
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
data = result[1]
|
||||
self.assertEqual(2, len(data))
|
||||
|
||||
self.assertEqual(data[0][0], "Controller")
|
||||
self.assertEqual(data[0][3], "random: abcd")
|
||||
self.assertEqual(data[1][0], "Test")
|
||||
self.assertEqual(data[1][3], "")
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=[]
|
||||
)
|
||||
def test_list_with_details_empty(self, mock_list):
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--current', '--detail'],
|
||||
[])
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(0, len(result[1]))
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=[
|
||||
{"name": "Compute"},
|
||||
{"name": "Random"},
|
||||
{"name": "BlockStorage", "ServicesDefault": ["c", "b", "a"]}
|
||||
]
|
||||
)
|
||||
def test_list_with_details_sorted(self, mock_list):
|
||||
|
||||
parsed_args = self.check_parser(self.cmd,
|
||||
['--current', '--detail'],
|
||||
[])
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(3, len(result[1]))
|
||||
|
||||
# Test main list sorted
|
||||
self.assertEqual(result[1][0][0], "BlockStorage")
|
||||
self.assertEqual(result[1][1][0], "Compute")
|
||||
self.assertEqual(result[1][2][0], "Random")
|
||||
|
||||
# Test service sublist sorted
|
||||
self.assertEqual(result[1][0][2], "a\nb\nc")
|
||||
|
||||
|
||||
class TestOvercloudShowRole(BaseTestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestOvercloudShowRole, self).setUp()
|
||||
|
||||
self.cmd = overcloud_plan_roles.ShowRole(self.app, None)
|
||||
|
||||
self.app.client_manager.tripleoclient = self.tripleoclient
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.actions.plan.ListRolesAction.run',
|
||||
autospec=True,
|
||||
return_value=[]
|
||||
)
|
||||
def test_role_not_found(self, mock_list):
|
||||
arglist = ['--name', 'overcast', 'doesntexist']
|
||||
verifylist = [('name', 'overcast'), ('role', 'doesntexist')]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.assertRaises(exceptions.CommandError,
|
||||
self.cmd.take_action,
|
||||
parsed_args)
|
@ -174,46 +174,6 @@ class TestParameterWorkflows(utils.TestCommand):
|
||||
]
|
||||
mock_playbook.assert_has_calls(calls, any_order=True)
|
||||
|
||||
def test_check_deprecated_params_no_output(self):
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
|
||||
def test_check_deprecated_params_user_defined(self):
|
||||
with mock.patch('tripleoclient.workflows.parameters.LOG') as mock_log:
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
|
||||
def test_check_deprecated_params_user_not_defined(self):
|
||||
with mock.patch('tripleoclient.workflows.parameters.LOG') as mock_log:
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
self.assertFalse(mock_log.log.warning.called)
|
||||
|
||||
def test_check_deprecated_multiple_parameters(self):
|
||||
with mock.patch('tripleoclient.workflows.parameters.LOG') as mock_log:
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
|
||||
def test_check_unused_multiple_parameters(self):
|
||||
with mock.patch('tripleoclient.workflows.parameters.LOG') as mock_log:
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
|
||||
def test_check_invalid_role_specific_parameters(self):
|
||||
with mock.patch('tripleoclient.workflows.parameters.LOG') as mock_log:
|
||||
parameters.check_deprecated_parameters(
|
||||
self.app.client_manager,
|
||||
container='container-name')
|
||||
self.assertTrue(mock_log.warning.called)
|
||||
|
||||
@mock.patch(
|
||||
'tripleo_common.utils.stack_parameters.generate_fencing_parameters',
|
||||
return_value={})
|
||||
|
@ -1,397 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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.
|
||||
import mock
|
||||
|
||||
from osc_lib.tests import utils
|
||||
|
||||
from tripleoclient import constants
|
||||
from tripleoclient.tests import base
|
||||
from tripleoclient.workflows import plan_management
|
||||
|
||||
|
||||
class TestPlanCreationWorkflows(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPlanCreationWorkflows, self).setUp()
|
||||
self.tripleoclient = mock.Mock()
|
||||
self.app.client_manager.tripleoclient = self.tripleoclient
|
||||
self.tripleoclient.object_store.get_account = mock.MagicMock()
|
||||
self.mock_tar = mock.patch(
|
||||
'tripleo_common.utils.tarball.create_tarball',
|
||||
autospec=True
|
||||
)
|
||||
self.mock_tar.start()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestPlanCreationWorkflows, self).tearDown()
|
||||
self.mock_tar.stop()
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_plan_from_templates_success(self, mock_tmp, mock_cd,
|
||||
mock_run_playbook):
|
||||
plan_management.create_plan_from_templates(
|
||||
self.app.client_manager,
|
||||
'test-overcloud',
|
||||
'/tht-root/')
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=0,
|
||||
)
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('tripleoclient.utils.rel_or_abs_path')
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_plan_from_templates_roles_data(self, mock_tmp, mock_cd,
|
||||
mock_norm_path,
|
||||
mock_run_playbook):
|
||||
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/',
|
||||
'the_roles_file.yaml')
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=0,
|
||||
)
|
||||
|
||||
self.assertIn(mock.call('the_roles_file.yaml', '/tht-root/'),
|
||||
mock_norm_path.call_args_list)
|
||||
|
||||
self.tripleoclient.object_store.put_object.assert_called_with(
|
||||
'test-overcloud', 'roles_data.yaml', mock_open_context())
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_plan_from_templates_plan_env_data(self, mock_tmp, mock_cd,
|
||||
mock_run_playbook):
|
||||
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')
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"plan_environment": "the-plan-environment.yaml",
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=0,
|
||||
)
|
||||
mock_open_context.assert_has_calls(
|
||||
[mock.call('the-plan-environment.yaml', 'rb')])
|
||||
|
||||
self.tripleoclient.object_store.put_object.assert_called_with(
|
||||
'test-overcloud', 'plan-environment.yaml', mock_open_context())
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_plan_from_templates_networks_data(self, mock_tmp, mock_cd,
|
||||
mock_run_playbook):
|
||||
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/',
|
||||
networks_file='the-network-data.yaml')
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=0,
|
||||
)
|
||||
mock_open_context.assert_has_calls(
|
||||
[mock.call('the-network-data.yaml', 'rb')])
|
||||
|
||||
self.tripleoclient.object_store.put_object.assert_called_with(
|
||||
'test-overcloud', 'network_data.yaml', mock_open_context())
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_create_plan_with_password_gen_disabled(self, mock_tmp, mock_cd,
|
||||
mock_run_playbook):
|
||||
plan_management.create_plan_from_templates(
|
||||
self.app.client_manager,
|
||||
'test-overcloud',
|
||||
'/tht-root/',
|
||||
generate_passwords=False,
|
||||
disable_image_params_prepare=True)
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-create-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": False,
|
||||
"use_default_templates": False,
|
||||
"disable_image_params_prepare": True,
|
||||
},
|
||||
verbosity=0,
|
||||
)
|
||||
|
||||
|
||||
class TestPlanUpdateWorkflows(base.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPlanUpdateWorkflows, self).setUp()
|
||||
self.app.client_manager.tripleoclient = self.tripleoclient = \
|
||||
mock.Mock()
|
||||
self.tripleoclient.object_store = self.object_store = mock.Mock()
|
||||
|
||||
self.object_store.get_container.return_value = (
|
||||
{},
|
||||
[
|
||||
{'name': 'plan-environment.yaml'},
|
||||
{'name': 'user-environment.yaml'},
|
||||
{'name': 'roles_data.yaml'},
|
||||
{'name': 'network_data.yaml'},
|
||||
{'name': 'user-files/somecustomfile.yaml'},
|
||||
{'name': 'user-files/othercustomfile.yaml'},
|
||||
{'name': 'this-should-not-be-persisted.yaml'},
|
||||
]
|
||||
)
|
||||
|
||||
def get_object(*args, **kwargs):
|
||||
if args[0] != 'test-overcloud':
|
||||
raise RuntimeError('Unexpected container')
|
||||
if args[1] == 'plan-environment.yaml':
|
||||
return {}, ('passwords: somepasswords\n'
|
||||
'plan-environment.yaml: mock content\n')
|
||||
# Generic return valuebased on param,
|
||||
# e.g. 'plan-environment.yaml: mock content'
|
||||
return {}, '{0}: mock content\n'.format(args[1])
|
||||
self.object_store.get_object.side_effect = get_object
|
||||
self.mock_tar = mock.patch(
|
||||
'tripleo_common.utils.tarball.create_tarball',
|
||||
autospec=True
|
||||
)
|
||||
self.mock_tar.start()
|
||||
|
||||
def tearDown(self):
|
||||
super(TestPlanUpdateWorkflows, self).tearDown()
|
||||
self.mock_tar.stop()
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('tripleo_common.utils.swift.empty_container',
|
||||
autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_update_plan_from_templates_keep_env(
|
||||
self, mock_tmp, mock_cd, mock_empty_container,
|
||||
mock_run_playbook):
|
||||
|
||||
plan_management.update_plan_from_templates(
|
||||
self.app.client_manager,
|
||||
'test-overcloud',
|
||||
'/tht-root/',
|
||||
keep_env=True)
|
||||
|
||||
mock_empty_container.assert_called_once_with(
|
||||
self.object_store, 'test-overcloud')
|
||||
|
||||
# make sure we're pushing the saved files back to plan
|
||||
self.object_store.put_object.assert_has_calls(
|
||||
[
|
||||
mock.call('test-overcloud', 'plan-environment.yaml',
|
||||
'passwords: somepasswords\n'
|
||||
'plan-environment.yaml: mock content\n'),
|
||||
mock.call('test-overcloud', 'user-environment.yaml',
|
||||
'user-environment.yaml: mock content\n'),
|
||||
mock.call('test-overcloud', 'roles_data.yaml',
|
||||
'roles_data.yaml: mock content\n'),
|
||||
mock.call('test-overcloud', 'network_data.yaml',
|
||||
'network_data.yaml: mock content\n'),
|
||||
mock.call('test-overcloud', 'user-files/somecustomfile.yaml',
|
||||
'user-files/somecustomfile.yaml: mock content\n'),
|
||||
mock.call('test-overcloud', 'user-files/othercustomfile.yaml',
|
||||
'user-files/othercustomfile.yaml: mock content\n'),
|
||||
],
|
||||
any_order=True,
|
||||
)
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-update-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=1,
|
||||
)
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('tripleo_common.utils.swift.empty_container',
|
||||
autospec=True)
|
||||
def test_update_plan_from_templates_recreate_env(
|
||||
self, mock_empty_container, mock_run_playbook):
|
||||
|
||||
plan_management.update_plan_from_templates(
|
||||
self.app.client_manager,
|
||||
'test-overcloud',
|
||||
'/tht-root/')
|
||||
|
||||
mock_empty_container.assert_called_once_with(
|
||||
self.object_store, 'test-overcloud')
|
||||
|
||||
# make sure passwords got persisted
|
||||
self.object_store.put_object.assert_called_with(
|
||||
'test-overcloud', 'plan-environment.yaml',
|
||||
'passwords: somepasswords\n'
|
||||
'plan-environment.yaml: mock content\n'
|
||||
)
|
||||
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-update-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"disable_image_params_prepare": False,
|
||||
},
|
||||
verbosity=1,
|
||||
)
|
||||
|
||||
@mock.patch("tripleoclient.utils.run_ansible_playbook", autospec=True)
|
||||
@mock.patch('tripleoclient.workflows.plan_management._update_passwords',
|
||||
autospec=True)
|
||||
@mock.patch('yaml.safe_load',
|
||||
autospec=True)
|
||||
@mock.patch('tripleo_common.utils.swift.empty_container',
|
||||
autospec=True)
|
||||
@mock.patch('os.chdir', autospec=True)
|
||||
@mock.patch('tempfile.mkdtemp', autospec=True)
|
||||
def test_update_plan_from_templates_recreate_env_missing_passwords(
|
||||
self, mock_tmp, mock_cd, mock_empty_container,
|
||||
mock_yaml_safe_load, mock_update_passwords, mock_run_playbook):
|
||||
plan_management.update_plan_from_templates(
|
||||
self.app.client_manager,
|
||||
'test-overcloud',
|
||||
'/tht-root/',
|
||||
disable_image_params_prepare=True)
|
||||
# A dictionary without the "passwords" key is provided in
|
||||
# the _load_passwords method.
|
||||
mock_yaml_safe_load.return_value = {}
|
||||
# Ensure that the passwords variable is passed with a value of None.
|
||||
mock_update_passwords.assert_called_with(
|
||||
mock.ANY, 'test-overcloud', None)
|
||||
mock_run_playbook.assert_called_with(
|
||||
'cli-update-deployment-plan.yaml',
|
||||
'undercloud,',
|
||||
mock.ANY,
|
||||
constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": "test-overcloud",
|
||||
"generate_passwords": True,
|
||||
"disable_image_params_prepare": True,
|
||||
},
|
||||
verbosity=1,
|
||||
)
|
||||
|
||||
|
||||
class TestUpdatePasswords(base.TestCase):
|
||||
|
||||
YAML_CONTENTS = """version: 1.0
|
||||
name: overcloud
|
||||
template: overcloud.yaml
|
||||
parameter_defaults:
|
||||
ControllerCount: 7
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestUpdatePasswords, self).setUp()
|
||||
self.swift_client = mock.MagicMock()
|
||||
self.swift_client.get_object.return_value = ({}, self.YAML_CONTENTS)
|
||||
|
||||
self.plan_name = "overcast"
|
||||
|
||||
def test_update_passwords(self):
|
||||
plan_management._update_passwords(self.swift_client,
|
||||
self.plan_name,
|
||||
{'AdminPassword': "1234"})
|
||||
|
||||
result = self.swift_client.put_object.call_args_list[0][0][2]
|
||||
|
||||
# Check new data is in
|
||||
self.assertIn("passwords:\n", result)
|
||||
self.assertIn("\n AdminPassword: '1234'", result)
|
||||
# Check previous data still is too
|
||||
self.assertIn("name: overcloud", result)
|
||||
|
||||
def test_no_passwords(self):
|
||||
plan_management._update_passwords(self.swift_client,
|
||||
self.plan_name,
|
||||
[])
|
||||
|
||||
self.swift_client.put_object.assert_not_called()
|
||||
|
||||
def test_no_plan_environment(self):
|
||||
self.swift_client.get_object.side_effect = (
|
||||
Exception("404"))
|
||||
|
||||
plan_management._update_passwords(self.swift_client,
|
||||
self.plan_name,
|
||||
{'SecretPassword': 'abcd'})
|
||||
|
||||
self.swift_client.put_object.assert_not_called()
|
@ -275,9 +275,6 @@ class DeployOvercloud(command.Command):
|
||||
template_file=template_path)
|
||||
files = dict(list(template_files.items()) + list(env_files.items()))
|
||||
|
||||
# Fix if required
|
||||
# workflow_params.check_deprecated_parameters(self.clients, stack_name)
|
||||
|
||||
self.log.info("Deploying templates in the directory {0}".format(
|
||||
os.path.abspath(tht_root)))
|
||||
deployment.deploy_without_plan(
|
||||
@ -1055,18 +1052,18 @@ class GetDeploymentStatus(command.Command):
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
plan = parsed_args.plan
|
||||
stack = parsed_args.plan
|
||||
|
||||
status = deployment.get_deployment_status(
|
||||
self.app.client_manager,
|
||||
plan
|
||||
stack
|
||||
)
|
||||
|
||||
if not status:
|
||||
self.log.info('No deployment was found for %s' % plan)
|
||||
self.log.info('No deployment was found for %s' % stack)
|
||||
return
|
||||
|
||||
table = PrettyTable(
|
||||
['Plan Name', 'Deployment Status'])
|
||||
table.add_row([plan, status])
|
||||
['Stack Name', 'Deployment Status'])
|
||||
table.add_row([stack, status])
|
||||
print(table, file=self.app.stdout)
|
||||
|
@ -1,227 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
|
||||
from osc_lib.i18n import _
|
||||
from six.moves.urllib import request
|
||||
|
||||
from tripleoclient import command
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import utils
|
||||
from tripleoclient.workflows import deployment
|
||||
from tripleoclient.workflows import plan_management
|
||||
|
||||
|
||||
class ListPlans(command.Lister):
|
||||
"""List overcloud deployment plans."""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListPlans")
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
|
||||
clients = self.app.client_manager
|
||||
|
||||
plans = plan_management.list_deployment_plans(clients)
|
||||
|
||||
result = []
|
||||
for r in plans:
|
||||
result.append((r,))
|
||||
|
||||
return (("Plan Name",), result)
|
||||
|
||||
|
||||
class DeletePlan(command.Command):
|
||||
"""Delete an overcloud deployment plan.
|
||||
|
||||
The plan will not be deleted if a stack exists with the same name.
|
||||
"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeletePlan")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeletePlan, self).get_parser(prog_name)
|
||||
parser.add_argument('plans', metavar='<name>', nargs="+",
|
||||
help=_('Name of the plan(s) to delete'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
|
||||
clients = self.app.client_manager
|
||||
|
||||
for plan in parsed_args.plans:
|
||||
print("Deleting plan %s..." % plan)
|
||||
plan_management.delete_deployment_plan(clients,
|
||||
container=plan)
|
||||
|
||||
|
||||
class CreatePlan(command.Command):
|
||||
"""Create a deployment plan"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".CreatePlan")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreatePlan, self).get_parser(prog_name)
|
||||
source_group = parser.add_mutually_exclusive_group()
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help=_('The name of the plan, which is used for the object '
|
||||
'storage container, workflow environment and orchestration '
|
||||
'stack names.'))
|
||||
source_group.add_argument(
|
||||
'--templates',
|
||||
help=_('The directory containing the Heat templates to deploy. '
|
||||
'If this or --source_url isn\'t provided, the templates '
|
||||
'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(
|
||||
'--disable-password-generation',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Disable password generation.')
|
||||
)
|
||||
source_group.add_argument(
|
||||
'--source-url',
|
||||
help=_('The url of a git repository containing the Heat templates '
|
||||
'to deploy. If this or --templates isn\'t provided, the '
|
||||
'templates packaged on the Undercloud will be used.')
|
||||
)
|
||||
parser.add_argument(
|
||||
'--disable-container-prepare',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Disable the container preparation actions to prevent '
|
||||
'container tags from being updated and new containers '
|
||||
'from being fetched. If you skip this but do not have '
|
||||
'the container parameters configured, the deployment '
|
||||
'action may fail.')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
clients = self.app.client_manager
|
||||
|
||||
name = parsed_args.name
|
||||
use_default_templates = False
|
||||
generate_passwords = not parsed_args.disable_password_generation
|
||||
source_url = parsed_args.source_url
|
||||
# if the templates and source_url params are not used, then
|
||||
# use the default templates
|
||||
if not parsed_args.templates and not parsed_args.source_url:
|
||||
use_default_templates = True
|
||||
|
||||
# Needs this to avoid too long lines
|
||||
disable_container_prepare = parsed_args.disable_container_prepare
|
||||
|
||||
if parsed_args.templates:
|
||||
plan_management.create_plan_from_templates(
|
||||
clients, name, parsed_args.templates,
|
||||
generate_passwords=generate_passwords,
|
||||
plan_env_file=parsed_args.plan_environment_file,
|
||||
verbosity_level=utils.playbook_verbosity(self=self),
|
||||
disable_image_params_prepare=disable_container_prepare
|
||||
)
|
||||
else:
|
||||
plan_management.create_deployment_plan(
|
||||
container=name,
|
||||
generate_passwords=generate_passwords,
|
||||
source_url=source_url,
|
||||
use_default_templates=use_default_templates,
|
||||
verbosity_level=utils.playbook_verbosity(self=self),
|
||||
disable_image_params_prepare=disable_container_prepare
|
||||
)
|
||||
|
||||
|
||||
class DeployPlan(command.Command):
|
||||
"""Deploy a deployment plan"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeployPlan")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeployPlan, self).get_parser(prog_name)
|
||||
parser.add_argument('name', help=_('The name of the plan to deploy.'))
|
||||
parser.add_argument('--timeout', '-t', metavar='<TIMEOUT>',
|
||||
type=int, default=240,
|
||||
help=_('Deployment timeout in minutes.'))
|
||||
parser.add_argument('--run-validations', action='store_true',
|
||||
default=False,
|
||||
help=_('Run the pre-deployment validations. These '
|
||||
'external validations are from the TripleO '
|
||||
'Validations project.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
|
||||
clients = self.app.client_manager
|
||||
orchestration_client = clients.orchestration
|
||||
stack = utils.get_stack(orchestration_client, parsed_args.name)
|
||||
|
||||
print("Starting to deploy plan: {}".format(parsed_args.name))
|
||||
deployment.deploy_and_wait(
|
||||
log=self.log,
|
||||
clients=clients,
|
||||
stack=stack,
|
||||
plan_name=parsed_args.name,
|
||||
verbose_level=utils.playbook_verbosity(self=self),
|
||||
timeout=parsed_args.timeout,
|
||||
run_validations=parsed_args.run_validations,
|
||||
)
|
||||
|
||||
|
||||
class ExportPlan(command.Command):
|
||||
"""Export a deployment plan"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ExportPlan")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ExportPlan, self).get_parser(prog_name)
|
||||
parser.add_argument('plan', metavar='<name>',
|
||||
help=_('Name of the plan to export.'))
|
||||
parser.add_argument('--output-file', '-o', metavar='<output file>',
|
||||
help=_('Name of the output file for export. '
|
||||
'It will default to "<name>.tar.gz".'))
|
||||
parser.add_argument('--force-overwrite', '-f', action='store_true',
|
||||
default=False,
|
||||
help=_('Overwrite output file if it exists.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
plan = parsed_args.plan
|
||||
outfile = parsed_args.output_file or '%s.tar.gz' % plan
|
||||
|
||||
if os.path.exists(outfile) and not parsed_args.force_overwrite:
|
||||
raise exceptions.PlanExportError(
|
||||
"File '%s' already exists, not exporting." % outfile)
|
||||
|
||||
print("Exporting plan %s..." % plan)
|
||||
|
||||
tempurl = plan_management.export_deployment_plan(
|
||||
self.app.client_manager, plan
|
||||
)
|
||||
f = request.urlopen(tempurl)
|
||||
tarball_contents = f.read()
|
||||
f.close()
|
||||
|
||||
with open(outfile, 'wb') as f:
|
||||
f.write(tarball_contents)
|
@ -1,158 +0,0 @@
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib.i18n import _
|
||||
|
||||
from tripleoclient.workflows import roles
|
||||
|
||||
|
||||
class ListRoles(command.Lister):
|
||||
"""List the current and available roles in a given plan"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListRoles")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListRoles, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
dest='name',
|
||||
default='overcloud',
|
||||
help=_('The name of the plan, which is used for the object '
|
||||
'storage container, workflow environment and orchestration '
|
||||
'stack names.'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--detail',
|
||||
action='store_true',
|
||||
help=_('Include details about each role'))
|
||||
parser.add_argument(
|
||||
'--current',
|
||||
action='store_true',
|
||||
help=_('Only show the information for the roles currently enabled '
|
||||
'for the plan.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action({})'.format(parsed_args))
|
||||
|
||||
if parsed_args.current:
|
||||
result = roles.list_roles(
|
||||
self.app.client_manager,
|
||||
container=parsed_args.name,
|
||||
detail=parsed_args.detail)
|
||||
else:
|
||||
result = roles.list_available_roles(
|
||||
self.app.client_manager,
|
||||
container=parsed_args.name)
|
||||
# The workflow returns all the details by default, trim
|
||||
# them down if not required.
|
||||
if not parsed_args.detail:
|
||||
result = [r['name'] for r in result]
|
||||
|
||||
if parsed_args.detail:
|
||||
if result:
|
||||
result.sort(key=lambda r: r['name'])
|
||||
|
||||
role_list = self.format_role_details(result)
|
||||
column_names = ("Role Name",
|
||||
"Description",
|
||||
"Services Default",
|
||||
"Other Details")
|
||||
return (column_names, role_list)
|
||||
else:
|
||||
if result:
|
||||
result.sort()
|
||||
return (("Role Name",), [(r,) for r in result])
|
||||
|
||||
def format_role_details(self, result):
|
||||
role_list = []
|
||||
for r in result:
|
||||
name = r.pop('name')
|
||||
description = service_defaults = ''
|
||||
detail = []
|
||||
|
||||
if 'description' in r:
|
||||
description = r.pop('description')
|
||||
if 'ServicesDefault' in r:
|
||||
r['ServicesDefault'].sort()
|
||||
service_defaults = '\n'.join(r.pop('ServicesDefault'))
|
||||
for k, v in r.items():
|
||||
detail.append("%s: %s" % (k, v))
|
||||
|
||||
role_list.append((name, description, service_defaults,
|
||||
'\n'.join(detail)))
|
||||
return role_list
|
||||
|
||||
|
||||
class ShowRole(command.ShowOne):
|
||||
"""Show details for a specific role, given a plan"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ShowRole")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowRole, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
dest='name',
|
||||
default='overcloud',
|
||||
help=_('The name of the plan, which is used for the object '
|
||||
'storage container, workflow environment and orchestration '
|
||||
'stack names.'),
|
||||
)
|
||||
parser.add_argument('role',
|
||||
metavar="<role>",
|
||||
help=_('Name of the role to look up.'))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action({})'.format(parsed_args))
|
||||
|
||||
role = self.get_role_details(parsed_args.name, parsed_args.role)
|
||||
if not role:
|
||||
raise exceptions.CommandError(
|
||||
"Could not find role %s" % parsed_args.role)
|
||||
|
||||
return self.format_role(role)
|
||||
|
||||
def get_role_details(self, name, role_name):
|
||||
result = roles.list_available_roles(
|
||||
self.app.client_manager,
|
||||
container=name)
|
||||
|
||||
for r in result:
|
||||
if r['name'] == role_name:
|
||||
return r
|
||||
return []
|
||||
|
||||
def format_role(self, role):
|
||||
column_names = ['Name']
|
||||
data = [role.pop('name')]
|
||||
|
||||
if 'description' in role:
|
||||
column_names.append('Description')
|
||||
data.append(role.pop('description'))
|
||||
if 'ServicesDefault' in role:
|
||||
column_names.append('Services Default')
|
||||
role['ServicesDefault'].sort()
|
||||
data.append('\n'.join(role.pop('ServicesDefault')))
|
||||
|
||||
other_fields = list(role.keys())
|
||||
other_fields.sort()
|
||||
for field in other_fields:
|
||||
column_names.append(field)
|
||||
data.append(role[field])
|
||||
|
||||
return column_names, data
|
@ -30,96 +30,6 @@ from tripleoclient import utils
|
||||
_WORKFLOW_TIMEOUT = 360 # 6 * 60 seconds
|
||||
|
||||
|
||||
def deploy(container, run_validations, skip_deploy_identifier,
|
||||
timeout, verbosity=0):
|
||||
"""Run the deployment playbook.
|
||||
|
||||
:param container: Name of the container
|
||||
:type container: String
|
||||
|
||||
:param run_validations: Enable or disable validations
|
||||
:type run_validations: Boolean
|
||||
|
||||
:param skip_deploy_identifier: Enable or disable validations
|
||||
:type skip_deploy_identifier: Boolean
|
||||
|
||||
:param timeout: Deployment timeout (minutes).
|
||||
:type timeout: Integer
|
||||
|
||||
:param verbosity: Verbosity level
|
||||
:type verbosity: Integer
|
||||
"""
|
||||
with utils.TempDirs() as tmp:
|
||||
utils.run_ansible_playbook(
|
||||
"cli-deploy-deployment-plan.yaml",
|
||||
'undercloud,',
|
||||
workdir=tmp,
|
||||
playbook_dir=ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
verbosity=verbosity,
|
||||
timeout=timeout,
|
||||
extra_vars={
|
||||
"container": container,
|
||||
"run_validations": run_validations,
|
||||
"skip_deploy_identifier": skip_deploy_identifier,
|
||||
}
|
||||
)
|
||||
|
||||
print("Success.")
|
||||
|
||||
|
||||
def deploy_and_wait(log, clients, stack, plan_name, verbose_level,
|
||||
timeout=None, run_validations=False,
|
||||
skip_deploy_identifier=False, deployment_options={}):
|
||||
"""Start the deploy and wait for it to finish"""
|
||||
|
||||
orchestration_client = clients.orchestration
|
||||
|
||||
if stack is None:
|
||||
log.info("Performing Heat stack create")
|
||||
action = 'CREATE'
|
||||
marker = None
|
||||
else:
|
||||
log.info("Performing Heat stack update")
|
||||
# Make sure existing parameters for stack are reused
|
||||
# Find the last top-level event to use for the first marker
|
||||
events = event_utils.get_events(orchestration_client,
|
||||
stack_id=plan_name,
|
||||
event_args={'sort_dir': 'desc',
|
||||
'limit': 1})
|
||||
marker = events[0].id if events else None
|
||||
action = 'UPDATE'
|
||||
|
||||
set_deployment_status(plan_name,
|
||||
status='DEPLOYING')
|
||||
|
||||
try:
|
||||
deploy(
|
||||
container=plan_name,
|
||||
run_validations=run_validations,
|
||||
skip_deploy_identifier=skip_deploy_identifier,
|
||||
timeout=timeout,
|
||||
verbosity=verbose_level)
|
||||
except Exception:
|
||||
set_deployment_status(plan_name,
|
||||
status='DEPLOY_FAILED')
|
||||
raise
|
||||
|
||||
# TODO(rabi) Simplify call to get events as we don't need to wait
|
||||
# for stack to be ready anymore i.e just get the events.
|
||||
create_result = utils.wait_for_stack_ready(
|
||||
orchestration_client, plan_name, marker, action)
|
||||
if not create_result:
|
||||
shell.OpenStackShell().run(["stack", "failures", "list", plan_name])
|
||||
set_deployment_status(
|
||||
plan_name,
|
||||
status='DEPLOY_FAILED'
|
||||
)
|
||||
if stack is None:
|
||||
raise exceptions.DeploymentError("Heat Stack create failed.")
|
||||
else:
|
||||
raise exceptions.DeploymentError("Heat Stack update failed.")
|
||||
|
||||
|
||||
def create_overcloudrc(stack, rc_params, no_proxy='',
|
||||
output_dir=CLOUD_HOME_DIR):
|
||||
overcloudrcs = rc_utils._create_overcloudrc(
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import yaml
|
||||
|
||||
from heatclient.common import template_utils
|
||||
@ -20,7 +19,6 @@ from tripleo_common.utils import stack_parameters as stk_parameters
|
||||
|
||||
from tripleoclient.constants import ANSIBLE_TRIPLEO_PLAYBOOKS
|
||||
from tripleoclient.constants import OVERCLOUD_YAML_NAME
|
||||
from tripleoclient.constants import UNUSED_PARAMETER_EXCLUDES_RE
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import utils
|
||||
from tripleoclient.workflows import roles
|
||||
@ -111,118 +109,6 @@ def build_derived_params_environment(clients, stack_name,
|
||||
)
|
||||
|
||||
|
||||
def check_deprecated_parameters(clients, container):
|
||||
"""Checks for deprecated parameters in plan and adds warning if present.
|
||||
|
||||
:param clients: application client object.
|
||||
:type clients: Object
|
||||
|
||||
:param container: Name of the stack container.
|
||||
:type container: String
|
||||
"""
|
||||
role_name_list = roles.list_available_roles(
|
||||
clients=clients,
|
||||
container=container
|
||||
)
|
||||
flattened_parms = stk_parameters.get_flattened_parameters(
|
||||
clients.tripleoclient.object_store,
|
||||
clients.orchestration, container=container)
|
||||
user_params = flattened_parms.get('environment_parameters', {})
|
||||
heat_resource_tree = flattened_parms.get('heat_resource_tree', {})
|
||||
heat_resource_tree_params = heat_resource_tree.get('parameters', {})
|
||||
heat_resource_tree_resources = heat_resource_tree.get('resources', {})
|
||||
plan_params = heat_resource_tree_params.keys()
|
||||
parameter_groups = [
|
||||
i.get('parameter_groups')
|
||||
for i in heat_resource_tree_resources.values()
|
||||
if i.get('parameter_groups')
|
||||
]
|
||||
params_role_specific_tag = [
|
||||
i.get('name')
|
||||
for i in heat_resource_tree_params.values()
|
||||
if 'tags' in i and 'role_specific' in i['tags']
|
||||
]
|
||||
|
||||
r = re.compile(".*Count")
|
||||
filtered_names = list(filter(r.match, plan_params))
|
||||
valid_role_name_list = list()
|
||||
for name in filtered_names:
|
||||
default = heat_resource_tree_params[name].get('default', 0)
|
||||
if default and int(default) > 0:
|
||||
role_name = name.rstrip('Count')
|
||||
if [i for i in role_name_list if i.get('name') == role_name]:
|
||||
valid_role_name_list.append(role_name)
|
||||
|
||||
deprecated_params = [
|
||||
i[0] for i in parameter_groups
|
||||
if i[0].get('label') == 'deprecated'
|
||||
]
|
||||
# We are setting a frozenset here because python 3 complains that dict is
|
||||
# a unhashable type.
|
||||
# On user_defined, we check if the size is higher than 0 because an empty
|
||||
# frozenset still is a subset of a frozenset, so we can't use issubset
|
||||
# here.
|
||||
user_params_keys = frozenset(user_params.keys())
|
||||
deprecated_result = [
|
||||
{
|
||||
'parameter': i,
|
||||
'deprecated': True,
|
||||
'user_defined': len(
|
||||
[x for x in frozenset(i) if x in user_params_keys]) > 0
|
||||
}
|
||||
for i in deprecated_params
|
||||
]
|
||||
unused_params = [i for i in user_params.keys() if i not in plan_params]
|
||||
user_provided_role_specific = [
|
||||
v for i in role_name_list
|
||||
for k, v in user_params.items()
|
||||
if k in i
|
||||
]
|
||||
invalid_role_specific_params = [
|
||||
i for i in user_provided_role_specific
|
||||
if i in params_role_specific_tag
|
||||
]
|
||||
deprecated_parameters = [
|
||||
param['parameter'] for param in deprecated_result
|
||||
if param.get('user_defined')
|
||||
]
|
||||
|
||||
if deprecated_parameters:
|
||||
deprecated_join = ', '.join(deprecated_parameters)
|
||||
LOG.warning(
|
||||
'WARNING: Following parameter(s) are deprecated and still '
|
||||
'defined. Deprecated parameters will be removed soon!'
|
||||
' {deprecated_join}'.format(
|
||||
deprecated_join=deprecated_join
|
||||
)
|
||||
)
|
||||
|
||||
# exclude our known params that may not be used
|
||||
ignore_re = re.compile('|'.join(UNUSED_PARAMETER_EXCLUDES_RE))
|
||||
unused_params = [p for p in unused_params if not ignore_re.search(p)]
|
||||
|
||||
if unused_params:
|
||||
unused_join = ', '.join(unused_params)
|
||||
LOG.warning(
|
||||
'WARNING: Following parameter(s) are defined but not '
|
||||
'currently used in the deployment plan. These parameters '
|
||||
'may be valid but not in use due to the service or '
|
||||
'deployment configuration.'
|
||||
' {unused_join}'.format(
|
||||
unused_join=unused_join
|
||||
)
|
||||
)
|
||||
|
||||
if invalid_role_specific_params:
|
||||
invalid_join = ', '.join(invalid_role_specific_params)
|
||||
LOG.warning(
|
||||
'WARNING: Following parameter(s) are not supported as '
|
||||
'role-specific inputs. {invalid_join}'.format(
|
||||
invalid_join=invalid_join
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def generate_fencing_parameters(clients, nodes_json, delay, ipmi_level,
|
||||
ipmi_cipher, ipmi_lanplus):
|
||||
"""Generate and return fencing parameters.
|
||||
|
@ -1,412 +0,0 @@
|
||||
# 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.
|
||||
import logging
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from tripleo_common.actions import plan
|
||||
from tripleo_common.utils import plan as plan_utils
|
||||
from tripleo_common.utils import swift as swiftutils
|
||||
from tripleo_common.utils import template as temputils
|
||||
|
||||
from tripleoclient import constants
|
||||
from tripleoclient import exceptions
|
||||
from tripleoclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
# Plan management workflows should generally be quick. However, the creation
|
||||
# of the default plan in instack has demonstrated that sometimes it can take
|
||||
# several minutes. The previous timeout of 6 minutes from Instack does not
|
||||
# seem to be sufficient anymore. Bumping this to 20 minutes. It doesn't mean
|
||||
# that it will take 20 minutes, but just that the listen for completion will
|
||||
# timeout after 20 minutes. If it takes longer than that, something is really
|
||||
# wrong.
|
||||
_WORKFLOW_TIMEOUT = 20 * 60 # 20 minutes * 60 seconds
|
||||
|
||||
|
||||
def _upload_templates(swift_client, container_name, tht_root, roles_file=None,
|
||||
plan_env_file=None, networks_file=None):
|
||||
"""tarball up a given directory and upload it to Swift to be extracted"""
|
||||
|
||||
temputils.upload_templates_as_tarball(
|
||||
swift=swift_client,
|
||||
dir_to_upload=tht_root,
|
||||
container=container_name
|
||||
)
|
||||
|
||||
# Optional override of the roles_data.yaml file
|
||||
if roles_file:
|
||||
_upload_file(swift_client, container_name,
|
||||
constants.OVERCLOUD_ROLES_FILE,
|
||||
utils.rel_or_abs_path(roles_file, tht_root))
|
||||
|
||||
# Optional override of the network_data.yaml file
|
||||
if networks_file:
|
||||
_upload_file(swift_client, container_name,
|
||||
constants.OVERCLOUD_NETWORKS_FILE, networks_file)
|
||||
|
||||
# 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.
|
||||
_upload_file(swift_client, container_name,
|
||||
constants.PLAN_ENVIRONMENT, plan_env_file)
|
||||
|
||||
|
||||
def create_deployment_plan(container, generate_passwords,
|
||||
use_default_templates=False, source_url=None,
|
||||
verbosity_level=0, plan_env_file=None,
|
||||
disable_image_params_prepare=False):
|
||||
"""Create a deployment plan.
|
||||
|
||||
:param container: Container name to push to.
|
||||
:type container: String
|
||||
|
||||
:param generate_passwords: Whether to generate password
|
||||
:type generate_passwords: Boolean
|
||||
|
||||
:param use_default_templates: Whether to use default template files
|
||||
:type use_default_templates: Boolean
|
||||
|
||||
:param source_url: The url of a git repository containing the Heat
|
||||
templates to deploy
|
||||
:type source_url: String
|
||||
|
||||
:param verbosity_level: Verbosity level used in playbook execution
|
||||
:type verbosity_level: Integer
|
||||
|
||||
:param plan_env_file: Path to plan environment file
|
||||
:type plan_env_file: String
|
||||
|
||||
:param disable_image_params_prepare: Disable container params prepare task
|
||||
:type disable_image_params_prepare: Boolean
|
||||
"""
|
||||
|
||||
extra_vars = {
|
||||
"container": container,
|
||||
"generate_passwords": generate_passwords,
|
||||
"use_default_templates": use_default_templates,
|
||||
"disable_image_params_prepare": disable_image_params_prepare
|
||||
}
|
||||
|
||||
if source_url:
|
||||
extra_vars['source_url'] = source_url
|
||||
|
||||
if plan_env_file:
|
||||
extra_vars['plan_environment'] = plan_env_file
|
||||
|
||||
with utils.TempDirs() as tmp:
|
||||
utils.run_ansible_playbook(
|
||||
"cli-create-deployment-plan.yaml",
|
||||
'undercloud,',
|
||||
workdir=tmp,
|
||||
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars=extra_vars,
|
||||
verbosity=verbosity_level
|
||||
)
|
||||
|
||||
print("Success.")
|
||||
|
||||
|
||||
def delete_deployment_plan(clients, container):
|
||||
"""Delete a deployment plan.
|
||||
|
||||
:param clients: Application client object.
|
||||
:type clients: Object
|
||||
|
||||
:param container: Container name to pull from.
|
||||
:type container: String
|
||||
"""
|
||||
|
||||
context = clients.tripleoclient.create_mistral_context()
|
||||
result = plan.DeletePlanAction(container=container).run(context=context)
|
||||
# The action returns None if there are no errors.
|
||||
if result:
|
||||
raise RuntimeError(result)
|
||||
|
||||
|
||||
def update_deployment_plan(clients, container, generate_passwords,
|
||||
verbosity_level=0,
|
||||
disable_image_params_prepare=False):
|
||||
"""Update a deployment plan.
|
||||
|
||||
:param clients: Application client object.
|
||||
:type clients: Object
|
||||
|
||||
:param container: Container name to pull from.
|
||||
:type container: String
|
||||
|
||||
:param generate_passwords: Whether to generate password
|
||||
:type generate_passwords: Boolean
|
||||
|
||||
:param verbosity_level: Verbosity level used in playbook execution
|
||||
:type verbosity_level: Integer
|
||||
|
||||
:param disable_image_params_prepare: Disable container params prepare task
|
||||
:type disable_image_params_prepare: Boolean
|
||||
"""
|
||||
|
||||
with utils.TempDirs() as tmp:
|
||||
utils.run_ansible_playbook(
|
||||
"cli-update-deployment-plan.yaml",
|
||||
'undercloud,',
|
||||
workdir=tmp,
|
||||
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"container": container,
|
||||
"generate_passwords": generate_passwords,
|
||||
"disable_image_params_prepare": disable_image_params_prepare
|
||||
},
|
||||
verbosity=verbosity_level
|
||||
)
|
||||
|
||||
print("Success.")
|
||||
|
||||
|
||||
def list_deployment_plans(clients):
|
||||
mistral_context = clients.tripleoclient.create_mistral_context()
|
||||
return plan.ListPlansAction().run(mistral_context)
|
||||
|
||||
|
||||
def create_plan_from_templates(clients, name, tht_root, roles_file=None,
|
||||
generate_passwords=True, plan_env_file=None,
|
||||
networks_file=None, verbosity_level=0,
|
||||
disable_image_params_prepare=False):
|
||||
|
||||
with utils.TempDirs() as tmp:
|
||||
utils.run_ansible_playbook(
|
||||
"cli-undercloud-local-artifacts.yaml",
|
||||
'undercloud,',
|
||||
workdir=tmp,
|
||||
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"stack": name,
|
||||
},
|
||||
verbosity=verbosity_level
|
||||
)
|
||||
|
||||
swift_client = clients.tripleoclient.object_store
|
||||
|
||||
print("Creating Swift container to store the plan")
|
||||
plan_utils.create_plan_container(swift_client, name)
|
||||
|
||||
print("Creating plan from template files in: {}".format(tht_root))
|
||||
_upload_templates(swift_client, name, tht_root,
|
||||
utils.rel_or_abs_path(roles_file, tht_root),
|
||||
plan_env_file, networks_file)
|
||||
|
||||
try:
|
||||
create_deployment_plan(
|
||||
container=name,
|
||||
generate_passwords=generate_passwords,
|
||||
plan_env_file=plan_env_file,
|
||||
verbosity_level=verbosity_level,
|
||||
disable_image_params_prepare=disable_image_params_prepare)
|
||||
except exceptions.WorkflowServiceError:
|
||||
swiftutils.delete_container(swift_client, name)
|
||||
raise
|
||||
|
||||
|
||||
def update_plan_from_templates(clients, name, tht_root, roles_file=None,
|
||||
generate_passwords=True, plan_env_file=None,
|
||||
networks_file=None, keep_env=False,
|
||||
verbosity_level=1,
|
||||
disable_image_params_prepare=False):
|
||||
|
||||
with utils.TempDirs() as tmp:
|
||||
utils.run_ansible_playbook(
|
||||
"cli-undercloud-local-artifacts.yaml",
|
||||
'undercloud,',
|
||||
workdir=tmp,
|
||||
playbook_dir=constants.ANSIBLE_TRIPLEO_PLAYBOOKS,
|
||||
extra_vars={
|
||||
"stack": name,
|
||||
},
|
||||
verbosity=verbosity_level
|
||||
)
|
||||
|
||||
swift_client = clients.tripleoclient.object_store
|
||||
passwords = None
|
||||
keep_file_contents = {}
|
||||
roles_file = utils.rel_or_abs_path(roles_file, tht_root)
|
||||
|
||||
if keep_env:
|
||||
# Dict items are (remote_name, local_name). local_name may be
|
||||
# None in which case we only try to load from Swift (remote).
|
||||
keep_map = {
|
||||
constants.PLAN_ENVIRONMENT: plan_env_file,
|
||||
constants.USER_ENVIRONMENT: None,
|
||||
constants.OVERCLOUD_ROLES_FILE: roles_file,
|
||||
constants.OVERCLOUD_NETWORKS_FILE: networks_file,
|
||||
}
|
||||
# Also try to fetch any files under 'user-files/'
|
||||
# dir. local_name is always None for these
|
||||
keep_map.update(dict(map(
|
||||
lambda path: (path, None),
|
||||
_list_user_files(swift_client, name))))
|
||||
keep_file_contents = _load_content_or_file(
|
||||
swift_client, name, keep_map)
|
||||
else:
|
||||
passwords = _load_passwords(swift_client, name)
|
||||
|
||||
# TODO(dmatthews): Removing the existing plan files should probably be
|
||||
# a Mistral action.
|
||||
print("Removing the current plan files")
|
||||
swiftutils.empty_container(swift_client, name)
|
||||
|
||||
# Until we have a well defined plan update workflow in
|
||||
# tripleo-common we need to manually reset the environments and
|
||||
# parameter_defaults here. This is to ensure that no environments
|
||||
# are in the plan environment but not actually in swift.
|
||||
# See bug: https://bugs.launchpad.net/tripleo/+bug/1623431
|
||||
#
|
||||
# Currently this is being done incidentally because we overwrite
|
||||
# the existing plan-environment.yaml with the skeleton one in THT
|
||||
# when updating the templates. Once LP#1623431 is resolved we may
|
||||
# need to special-case plan-environment.yaml to avoid this.
|
||||
|
||||
print("Uploading new plan files")
|
||||
if keep_env:
|
||||
_upload_templates(swift_client, name, tht_root)
|
||||
for filename in keep_file_contents:
|
||||
_upload_file_content(swift_client, name, filename,
|
||||
keep_file_contents[filename])
|
||||
else:
|
||||
_upload_templates(swift_client, name, tht_root, roles_file,
|
||||
plan_env_file, networks_file)
|
||||
_update_passwords(swift_client, name, passwords)
|
||||
|
||||
update_deployment_plan(
|
||||
clients, container=name,
|
||||
generate_passwords=generate_passwords,
|
||||
verbosity_level=verbosity_level,
|
||||
disable_image_params_prepare=disable_image_params_prepare)
|
||||
|
||||
|
||||
def _load_content_or_file(swift_client, container, remote_and_local_map):
|
||||
# mapping (remote_name, content)
|
||||
file_contents = {}
|
||||
|
||||
plan_files = _list_plan_files(swift_client, container)
|
||||
|
||||
for remote_name in remote_and_local_map:
|
||||
LOG.debug("Attempting to load {0}".format(remote_name))
|
||||
local_name = remote_and_local_map[remote_name]
|
||||
# it's possible that the file doesn't exist in Swift and isn't
|
||||
# passed on filesystem, in which case we won't do anything
|
||||
content = None
|
||||
# local override takes priority
|
||||
if local_name:
|
||||
LOG.debug("Using provided file {0}".format(local_name))
|
||||
with open(os.path.abspath(local_name)) as local_content:
|
||||
content = local_content.read()
|
||||
elif remote_name in plan_files:
|
||||
LOG.debug("Preserving plan file {0}".format(remote_name))
|
||||
content = swift_client.get_object(container, remote_name)[1]
|
||||
|
||||
if content:
|
||||
file_contents[remote_name] = content
|
||||
|
||||
return file_contents
|
||||
|
||||
|
||||
def _list_user_files(swift_client, container):
|
||||
return list(filter(lambda path: path.startswith('user-files/'),
|
||||
_list_plan_files(swift_client, container)))
|
||||
|
||||
|
||||
def _list_plan_files(swift_client, container):
|
||||
return list(map(lambda i: i['name'],
|
||||
swift_client.get_container(
|
||||
container, full_listing=True)[1]))
|
||||
|
||||
|
||||
def _upload_file(swift_client, container, filename, local_filename):
|
||||
with open(local_filename, 'rb') as file_content:
|
||||
swiftutils.put_object_string(
|
||||
swift=swift_client,
|
||||
container=container,
|
||||
object_name=filename,
|
||||
contents=file_content
|
||||
)
|
||||
|
||||
|
||||
# short function, just alias for interface parity with _upload_plan_file
|
||||
def _upload_file_content(swift_client, container, filename, content):
|
||||
LOG.debug("Uploading {0} to plan".format(filename))
|
||||
swiftutils.put_object_string(
|
||||
swift=swift_client,
|
||||
container=container,
|
||||
object_name=filename,
|
||||
contents=content
|
||||
)
|
||||
|
||||
|
||||
def _load_passwords(swift_client, name):
|
||||
plan_env = yaml.safe_load(swift_client.get_object(
|
||||
name, constants.PLAN_ENVIRONMENT)[1])
|
||||
|
||||
if "passwords" in plan_env:
|
||||
return plan_env['passwords']
|
||||
else:
|
||||
LOG.warning("No passwords found in existing plan {}. "
|
||||
"Updating plan with passwords.".format(name))
|
||||
|
||||
|
||||
def _update_passwords(swift_client, name, passwords):
|
||||
# Update the plan environment with the generated passwords. This
|
||||
# will be solved more elegantly once passwords are saved in a
|
||||
# separate environment (https://review.opendev.org/#/c/467909/)
|
||||
if passwords:
|
||||
try:
|
||||
env = yaml.safe_load(swift_client.get_object(
|
||||
name, constants.PLAN_ENVIRONMENT)[1])
|
||||
env['passwords'] = passwords
|
||||
swiftutils.put_object_string(
|
||||
swift=swift_client,
|
||||
container=name,
|
||||
object_name=constants.PLAN_ENVIRONMENT,
|
||||
contents=yaml.safe_dump(env, default_flow_style=False)
|
||||
)
|
||||
except Exception as exp:
|
||||
# The plan likely has not been migrated to using Swift yet.
|
||||
LOG.debug("Could not find plan environment %s in %s - error: %s",
|
||||
constants.PLAN_ENVIRONMENT, name, exp)
|
||||
|
||||
|
||||
def export_deployment_plan(clients, plan_name):
|
||||
|
||||
plan_path = os.path.join('/var/lib/tripleo/stacks', plan_name)
|
||||
if os.path.exists(plan_path):
|
||||
print("Plan information can be found here: {}".format(plan_path))
|
||||
return plan_path
|
||||
else:
|
||||
# NOTE(cloudnull): When swift is no longer in service remove this.
|
||||
export_container = "plan-exports"
|
||||
delete_after = 3600
|
||||
|
||||
mistral_context = clients.tripleoclient.create_mistral_context()
|
||||
action = plan.ExportPlanAction(plan_name, delete_after=delete_after,
|
||||
exports_container=export_container)
|
||||
result = action.run(mistral_context)
|
||||
if result:
|
||||
raise exceptions.WorkflowServiceError(
|
||||
'Exception exporting plan: {}'.format(result.error))
|
||||
|
||||
url = swiftutils.get_temp_url(
|
||||
clients.tripleoclient.object_store,
|
||||
container=export_container,
|
||||
object_name="{}.tar.gz".format(plan_name)
|
||||
)
|
||||
print(url)
|
||||
return url
|
@ -14,10 +14,6 @@ import logging
|
||||
|
||||
import yaml
|
||||
|
||||
from tripleo_common.actions import plan
|
||||
# TODO(cloudnull): Convert to a swiftutils in tripleo-common
|
||||
# from tripleo_common.utils import swift as swiftutils
|
||||
|
||||
from tripleoclient import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -60,54 +56,3 @@ def get_roles(clients, roles_file, tht_root,
|
||||
valid_roles.append(name)
|
||||
|
||||
return valid_roles
|
||||
|
||||
|
||||
def list_available_roles(clients, container='overcloud'):
|
||||
"""Return a list of available roles.
|
||||
|
||||
:param clients: openstack clients
|
||||
:type clients: Object
|
||||
|
||||
:param container: Name of swift object container
|
||||
:type container: String
|
||||
|
||||
:returns: List
|
||||
"""
|
||||
|
||||
LOG.info('Pulling role list from: {}'.format(container))
|
||||
obj_client = clients.tripleoclient.object_store
|
||||
available_yaml_roles = list()
|
||||
LOG.info('Indexing roles from: {}'.format(container))
|
||||
# TODO(cloudnull): Convert to a swiftutils in tripleo-common
|
||||
for obj in obj_client.get_container(container)[-1]:
|
||||
name = obj['name']
|
||||
if name.startswith('roles/') and name.endswith(('yml', 'yaml')):
|
||||
role_data = yaml.safe_load(
|
||||
obj_client.get_object(container, name)[-1]
|
||||
)
|
||||
available_yaml_roles.append(role_data[0])
|
||||
|
||||
return available_yaml_roles
|
||||
|
||||
|
||||
def list_roles(clients, container, detail=False):
|
||||
"""Return a list of roles.
|
||||
|
||||
:param clients: openstack clients
|
||||
:type clients: Object
|
||||
|
||||
:param container: Name of swift object container
|
||||
:type container: String
|
||||
|
||||
:param detail: Enable or disable extra detail
|
||||
:type detail: Boolean
|
||||
|
||||
:returns: List
|
||||
"""
|
||||
|
||||
context = clients.tripleoclient.create_mistral_context()
|
||||
LOG.info('Pulling roles from: {}'.format(container))
|
||||
return plan.ListRolesAction(
|
||||
container=container,
|
||||
detail=detail
|
||||
).run(context=context)
|
||||
|
Loading…
Reference in New Issue
Block a user