Merge "Remove plan/plan-role management commands"

This commit is contained in:
Zuul 2021-02-04 12:47:48 +00:00 committed by Gerrit Code Review
commit 28ce651e85
15 changed files with 20 additions and 2167 deletions

View File

@ -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.

View File

@ -67,19 +67,12 @@ openstack.tripleoclient.v2 =
overcloud_node_unprovision = tripleoclient.v2.overcloud_node:UnprovisionNode overcloud_node_unprovision = tripleoclient.v2.overcloud_node:UnprovisionNode
overcloud_node_extract_provisioned = tripleoclient.v1.overcloud_node:ExtractProvisionedNode overcloud_node_extract_provisioned = tripleoclient.v1.overcloud_node:ExtractProvisionedNode
overcloud_parameters_set = tripleoclient.v1.overcloud_parameters:SetParameters 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_match = tripleoclient.v1.overcloud_profiles:MatchProfiles
overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles overcloud_profiles_list = tripleoclient.v1.overcloud_profiles:ListProfiles
overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID overcloud_raid_create = tripleoclient.v1.overcloud_raid:CreateRAID
overcloud_role_show= tripleoclient.v1.overcloud_roles:RoleShow overcloud_role_show= tripleoclient.v1.overcloud_roles:RoleShow
overcloud_role_list = tripleoclient.v1.overcloud_roles:RoleList overcloud_role_list = tripleoclient.v1.overcloud_roles:RoleList
overcloud_roles_generate = tripleoclient.v1.overcloud_roles:RolesGenerate 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_support_report_collect = tripleoclient.v2.overcloud_support:ReportExecute
overcloud_update_prepare= tripleoclient.v1.overcloud_update:UpdatePrepare overcloud_update_prepare= tripleoclient.v1.overcloud_update:UpdatePrepare
overcloud_update_run = tripleoclient.v1.overcloud_update:UpdateRun overcloud_update_run = tripleoclient.v1.overcloud_update:UpdateRun

View File

@ -205,16 +205,6 @@ try:
except (configparser.NoOptionError, FileNotFoundError): except (configparser.NoOptionError, FileNotFoundError):
UNDERCLOUD_OUTPUT_DIR = CLOUD_HOME_DIR 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 = [ EXPORT_PASSWORD_EXCLUDE_PATTERNS = [
'ceph.*' 'ceph.*'
] ]

View File

@ -27,8 +27,6 @@ from osc_lib.tests import utils
from tripleoclient import constants from tripleoclient import constants
from tripleoclient import exceptions 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.fixture_data import deployment
from tripleoclient.tests.v1.overcloud_deploy import fakes from tripleoclient.tests.v1.overcloud_deploy import fakes
from tripleoclient.v1 import overcloud_deploy from tripleoclient.v1 import overcloud_deploy
@ -91,53 +89,6 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_run_command.start() mock_run_command.start()
self.addCleanup(mock_run_command.stop) 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 # Mock playbook runner
playbook_runner = mock.patch( playbook_runner = mock.patch(
'tripleoclient.utils.run_ansible_playbook', 'tripleoclient.utils.run_ansible_playbook',
@ -404,8 +355,6 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
return_value='192.168.0.1 uc.ctlplane.localhost uc.ctlplane') 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_stack_network_matches_env_files')
@mock.patch('tripleoclient.utils.check_ceph_fsid_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.' @mock.patch('tripleoclient.v1.overcloud_deploy.DeployOvercloud.'
'_deploy_postconfig', autospec=True) '_deploy_postconfig', autospec=True)
@mock.patch('tripleo_common.update.add_breakpoints_cleanup_into_env', @mock.patch('tripleo_common.update.add_breakpoints_cleanup_into_env',
@ -423,7 +372,7 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_get_template_contents, mock_get_template_contents,
mock_create_parameters_env, mock_validate_args, mock_create_parameters_env, mock_validate_args,
mock_breakpoints_cleanup, 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_ceph_fsid, mock_get_undercloud_host_entry, mock_copy,
mock_chdir, mock_overcloudrc, mock_chdir, mock_overcloudrc,
mock_process_env, mock_roles_data, mock_process_env, mock_roles_data,
@ -1274,10 +1223,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
@mock.patch('tripleoclient.utils.check_stack_network_matches_env_files') @mock.patch('tripleoclient.utils.check_stack_network_matches_env_files')
@mock.patch('tripleoclient.utils.check_ceph_fsid_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('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( 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_ceph_fsid, mock_hd,
mock_get_undercloud_host_entry, mock_copy, mock_get_undercloud_host_entry, mock_copy,
mock_get_ctlplane_attrs, mock_nic_ansible, mock_get_ctlplane_attrs, mock_nic_ansible,
@ -1633,14 +1580,6 @@ class TestGetDeploymentStatus(utils.TestCommand):
super(TestGetDeploymentStatus, self).setUp() super(TestGetDeploymentStatus, self).setUp()
self.cmd = overcloud_deploy.GetDeploymentStatus(self.app, None) self.cmd = overcloud_deploy.GetDeploymentStatus(self.app, None)
self.app.client_manager = mock.Mock() 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") @mock.patch("tripleoclient.workflows.deployment.get_deployment_status")
def test_get_deployment_status(self, mock_get_deployment_status): def test_get_deployment_status(self, mock_get_deployment_status):
@ -1652,10 +1591,10 @@ class TestGetDeploymentStatus(utils.TestCommand):
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
expected = ( expected = (
'+-----------+-------------------+\n' '+------------+-------------------+\n'
'| Plan Name | Deployment Status |\n' '| Stack Name | Deployment Status |\n'
'+-----------+-------------------+\n' '+------------+-------------------+\n'
'| overcloud | DEPLOY_SUCCESS |\n' '| overcloud | DEPLOY_SUCCESS |\n'
'+-----------+-------------------+\n') '+------------+-------------------+\n')
self.assertEqual(expected, self.cmd.app.stdout.getvalue()) self.assertEqual(expected, self.cmd.app.stdout.getvalue())

View File

@ -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')

View File

@ -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)

View File

@ -174,46 +174,6 @@ class TestParameterWorkflows(utils.TestCommand):
] ]
mock_playbook.assert_has_calls(calls, any_order=True) 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( @mock.patch(
'tripleo_common.utils.stack_parameters.generate_fencing_parameters', 'tripleo_common.utils.stack_parameters.generate_fencing_parameters',
return_value={}) return_value={})

View File

@ -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()

View File

@ -280,9 +280,6 @@ class DeployOvercloud(command.Command):
template_file=template_path) template_file=template_path)
files = dict(list(template_files.items()) + list(env_files.items())) 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( self.log.info("Deploying templates in the directory {0}".format(
os.path.abspath(tht_root))) os.path.abspath(tht_root)))
deployment.deploy_without_plan( deployment.deploy_without_plan(
@ -1081,18 +1078,18 @@ class GetDeploymentStatus(command.Command):
def take_action(self, parsed_args): def take_action(self, parsed_args):
self.log.debug("take_action(%s)" % parsed_args) self.log.debug("take_action(%s)" % parsed_args)
plan = parsed_args.plan stack = parsed_args.plan
status = deployment.get_deployment_status( status = deployment.get_deployment_status(
self.app.client_manager, self.app.client_manager,
plan stack
) )
if not status: if not status:
self.log.info('No deployment was found for %s' % plan) self.log.info('No deployment was found for %s' % stack)
return return
table = PrettyTable( table = PrettyTable(
['Plan Name', 'Deployment Status']) ['Stack Name', 'Deployment Status'])
table.add_row([plan, status]) table.add_row([stack, status])
print(table, file=self.app.stdout) print(table, file=self.app.stdout)

View File

@ -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)

View File

@ -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

View File

@ -30,96 +30,6 @@ from tripleoclient import utils
_WORKFLOW_TIMEOUT = 360 # 6 * 60 seconds _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='', def create_overcloudrc(stack, rc_params, no_proxy='',
output_dir=CLOUD_HOME_DIR): output_dir=CLOUD_HOME_DIR):
overcloudrcs = rc_utils._create_overcloudrc( overcloudrcs = rc_utils._create_overcloudrc(

View File

@ -12,7 +12,6 @@
import logging import logging
import os import os
import re
import yaml import yaml
from heatclient.common import template_utils 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 ANSIBLE_TRIPLEO_PLAYBOOKS
from tripleoclient.constants import OVERCLOUD_YAML_NAME from tripleoclient.constants import OVERCLOUD_YAML_NAME
from tripleoclient.constants import UNUSED_PARAMETER_EXCLUDES_RE
from tripleoclient import exceptions from tripleoclient import exceptions
from tripleoclient import utils from tripleoclient import utils
from tripleoclient.workflows import roles 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, def generate_fencing_parameters(clients, nodes_json, delay, ipmi_level,
ipmi_cipher, ipmi_lanplus): ipmi_cipher, ipmi_lanplus):
"""Generate and return fencing parameters. """Generate and return fencing parameters.

View File

@ -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

View File

@ -14,10 +14,6 @@ import logging
import yaml 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 from tripleoclient import utils
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -60,54 +56,3 @@ def get_roles(clients, roles_file, tht_root,
valid_roles.append(name) valid_roles.append(name)
return valid_roles 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)