Merge "Convert enable-ssh-admin.sh to python"

This commit is contained in:
Zuul 2018-05-17 21:56:26 +00:00 committed by Gerrit Code Review
commit f35e4c2453
5 changed files with 292 additions and 49 deletions

@ -63,3 +63,7 @@ UPGRADE_CONVERGE_ENV = "environments/lifecycle/upgrade-converge.yaml"
FFWD_UPGRADE_PREPARE_ENV = "environments/lifecycle/ffwd-upgrade-prepare.yaml" FFWD_UPGRADE_PREPARE_ENV = "environments/lifecycle/ffwd-upgrade-prepare.yaml"
FFWD_UPGRADE_CONVERGE_ENV = "environments/lifecycle/ffwd-upgrade-converge.yaml" FFWD_UPGRADE_CONVERGE_ENV = "environments/lifecycle/ffwd-upgrade-converge.yaml"
CEPH_UPGRADE_PREPARE_ENV = "environments/lifecycle/ceph-upgrade-prepare.yaml" CEPH_UPGRADE_PREPARE_ENV = "environments/lifecycle/ceph-upgrade-prepare.yaml"
ENABLE_SSH_ADMIN_TIMEOUT = 300
ENABLE_SSH_ADMIN_STATUS_INTERVAL = 5
ENABLE_SSH_ADMIN_SSH_PORT_TIMEOUT = 300

@ -70,6 +70,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd._download_missing_files_from_plan = self.real_download_missing self.cmd._download_missing_files_from_plan = self.real_download_missing
shutil.rmtree = self.real_shutil shutil.rmtree = self.real_shutil
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -109,7 +111,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_events, mock_tarball, mock_events, mock_tarball,
mock_get_horizon_url, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--ceph-storage-scale', '3'] arglist = ['--templates', '--ceph-storage-scale', '3']
verifylist = [ verifylist = [
@ -182,6 +186,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_create_tempest_deployer_input.assert_called_with() mock_create_tempest_deployer_input.assert_called_with()
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -227,7 +233,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_invoke_plan_env_wf, mock_invoke_plan_env_wf,
mock_get_horizon_url, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--ceph-storage-scale', '3', arglist = ['--templates', '--ceph-storage-scale', '3',
'--control-flavor', 'oooq_control', '--no-cleanup'] '--control-flavor', 'oooq_control', '--no-cleanup']
@ -324,6 +332,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertEqual(env_map.get('parameter_defaults'), self.assertEqual(env_map.get('parameter_defaults'),
parameters_env.get('parameter_defaults')) parameters_env.get('parameter_defaults'))
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -369,7 +379,10 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_tarball, mock_postconfig, mock_tarball, mock_postconfig,
mock_get_overcloud_endpoint, mock_shutil_rmtree, mock_get_overcloud_endpoint, mock_shutil_rmtree,
mock_invoke_plan_env_wf, mock_get_horizon_url, mock_invoke_plan_env_wf, mock_get_horizon_url,
mock_list_plans, mock_config_download): mock_list_plans, mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '-p', 'the-plan-environment.yaml'] arglist = ['--templates', '-p', 'the-plan-environment.yaml']
verifylist = [ verifylist = [
('templates', '/usr/share/openstack-tripleo-heat-templates/'), ('templates', '/usr/share/openstack-tripleo-heat-templates/'),
@ -468,6 +481,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
clients.tripleoclient.object_store.put_object.assert_called() clients.tripleoclient.object_store.put_object.assert_called()
self.assertTrue(mock_invoke_plan_env_wf.called) self.assertTrue(mock_invoke_plan_env_wf.called)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -514,7 +529,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_breakpoints_cleanup, mock_tarball, mock_breakpoints_cleanup, mock_tarball,
mock_postconfig, mock_get_overcloud_endpoint, mock_postconfig, mock_get_overcloud_endpoint,
mock_deprecated_params, mock_get_horizon_url, mock_deprecated_params, mock_get_horizon_url,
mock_list_plans, mock_config_downlad): mock_list_plans, mock_config_downlad,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--skip-deploy-identifier'] arglist = ['--templates', '--skip-deploy-identifier']
verifylist = [ verifylist = [
@ -574,6 +591,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
deploy_plan_call_input = deploy_plan_call[1]['workflow_input'] deploy_plan_call_input = deploy_plan_call[1]['workflow_input']
self.assertTrue(deploy_plan_call_input['skip_deploy_identifier']) self.assertTrue(deploy_plan_call_input['skip_deploy_identifier'])
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -608,7 +627,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_events, mock_tarball, mock_events, mock_tarball,
mock_get_horizon_url, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '/home/stack/tripleo-heat-templates'] arglist = ['--templates', '/home/stack/tripleo-heat-templates']
verifylist = [ verifylist = [
@ -693,6 +714,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd.take_action, parsed_args) self.cmd.take_action, parsed_args)
self.assertFalse(mock_deploy_tht.called) self.assertFalse(mock_deploy_tht.called)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -717,7 +740,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_utils_endpoint, mock_utils_createrc, mock_utils_endpoint, mock_utils_createrc,
mock_utils_tempest, mock_tarball, mock_utils_tempest, mock_tarball,
mock_get_horizon_url, mock_list_plans, mock_get_horizon_url, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
mock_list_plans.return_value = [] mock_list_plans.return_value = []
@ -937,6 +962,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
parsed_args) parsed_args)
self.assertIn('/tmp/notthere', str(error)) self.assertIn('/tmp/notthere', str(error))
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch('tripleoclient.workflows.deployment.get_horizon_url', @mock.patch('tripleoclient.workflows.deployment.get_horizon_url',
autospec=True) autospec=True)
@ -952,7 +979,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_create_ocrc, mock_create_ocrc,
mock_create_tempest_deployer_input, mock_create_tempest_deployer_input,
mock_get_horizon_url, mock_get_horizon_url,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
workflow_client = clients.workflow_engine workflow_client = clients.workflow_engine
@ -979,6 +1008,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_create_tempest_deployer_input.assert_called_with() mock_create_tempest_deployer_input.assert_called_with()
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -1019,7 +1050,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_events, mock_tarball, mock_events, mock_tarball,
mock_get_horizon_url, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--rhel-reg', arglist = ['--templates', '--rhel-reg',
'--reg-sat-url', 'https://example.com', '--reg-sat-url', 'https://example.com',
@ -1230,6 +1263,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertFalse(mock_create_ocrc.called) self.assertFalse(mock_create_ocrc.called)
self.assertFalse(mock_create_tempest_deployer_input.called) self.assertFalse(mock_create_tempest_deployer_input.called)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -1256,7 +1291,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_create_tempest_deployer_input, mock_create_tempest_deployer_input,
mock_tarball, mock_get_horizon_url, mock_tarball, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
mock_list_plans.return_value = [] mock_list_plans.return_value = []
@ -1420,6 +1457,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd.take_action, self.cmd.take_action,
parsed_args) parsed_args)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch( @mock.patch(
'tripleoclient.workflows.plan_management.list_deployment_plans', 'tripleoclient.workflows.plan_management.list_deployment_plans',
@ -1464,7 +1503,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_deploy_post_config, mock_deploy_post_config,
mock_get_horizon_url, mock_get_horizon_url,
mock_list_plans, mock_list_plans,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--ceph-storage-scale', '3', arglist = ['--templates', '--ceph-storage-scale', '3',
'--control-scale', '3', '--ntp-server', 'ntp'] '--control-scale', '3', '--ntp-server', 'ntp']
@ -1616,6 +1657,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertRaises(exceptions.StackInProgress, self.assertRaises(exceptions.StackInProgress,
self.cmd.take_action, parsed_args) self.cmd.take_action, parsed_args)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch('tripleoclient.workflows.deployment.get_horizon_url', @mock.patch('tripleoclient.workflows.deployment.get_horizon_url',
autospec=True) autospec=True)
@ -1633,7 +1676,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_overcloud_endpoint, mock_overcloud_endpoint,
mock_create_tempest_deployer_input, mock_create_tempest_deployer_input,
mock_get_horizon_url, mock_get_horizon_url,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
orchestration_client = clients.orchestration orchestration_client = clients.orchestration
orchestration_client.stacks.get.return_value = mock.Mock() orchestration_client.stacks.get.return_value = mock.Mock()
@ -1648,6 +1693,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertNotCalled(self.cmd._predeploy_verify_capabilities) self.assertNotCalled(self.cmd._predeploy_verify_capabilities)
mock_create_tempest_deployer_input.assert_called_with() mock_create_tempest_deployer_input.assert_called_with()
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch('tripleoclient.workflows.deployment.get_horizon_url', @mock.patch('tripleoclient.workflows.deployment.get_horizon_url',
autospec=True) autospec=True)
@ -1665,7 +1712,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_overcloud_endpoint, mock_overcloud_endpoint,
mock_create_tempest_deployer_input, mock_create_tempest_deployer_input,
mock_get_horizon_url, mock_get_horizon_url,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
orchestration_client = clients.orchestration orchestration_client = clients.orchestration
orchestration_client.stacks.get.return_value = mock.Mock() orchestration_client.stacks.get.return_value = mock.Mock()
@ -1707,6 +1756,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.assertRaises(exceptions.InvalidConfiguration, self.assertRaises(exceptions.InvalidConfiguration,
self.cmd.take_action, parsed_args) self.cmd.take_action, parsed_args)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@mock.patch('tripleoclient.workflows.deployment.get_horizon_url', @mock.patch('tripleoclient.workflows.deployment.get_horizon_url',
autospec=True) autospec=True)
@ -1724,7 +1775,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_get_overcloud_endpoint, mock_get_overcloud_endpoint,
mock_provision, mock_tempest_deploy_input, mock_provision, mock_tempest_deploy_input,
mock_get_horizon_url, mock_get_horizon_url,
mock_config_download): mock_config_download,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
arglist = ['--templates', '--deployed-server', '--disable-validations'] arglist = ['--templates', '--deployed-server', '--disable-validations']
verifylist = [ verifylist = [
('templates', '/usr/share/openstack-tripleo-heat-templates/'), ('templates', '/usr/share/openstack-tripleo-heat-templates/'),
@ -1764,6 +1817,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
parsed_args) parsed_args)
self.assertFalse(mock_deploy_tmpdir.called) self.assertFalse(mock_deploy_tmpdir.called)
@mock.patch('tripleoclient.workflows.deployment.get_overcloud_hosts')
@mock.patch('tripleoclient.workflows.deployment.enable_ssh_admin')
@mock.patch('tripleoclient.workflows.deployment.get_horizon_url', @mock.patch('tripleoclient.workflows.deployment.get_horizon_url',
autospec=True) autospec=True)
@mock.patch('tripleoclient.workflows.deployment.config_download') @mock.patch('tripleoclient.workflows.deployment.config_download')
@ -1780,7 +1835,9 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
mock_overcloudrc, mock_write_overcloudrc, mock_overcloudrc, mock_write_overcloudrc,
mock_overcloud_endpoint, mock_overcloud_endpoint,
mock_create_tempest_deployer_input, mock_create_tempest_deployer_input,
mock_config_download, mock_get_horizon_url): mock_config_download, mock_get_horizon_url,
mock_enable_ssh_admin,
mock_get_overcloud_hosts):
clients = self.app.client_manager clients = self.app.client_manager
orchestration_client = clients.orchestration orchestration_client = clients.orchestration
orchestration_client.stacks.get.return_value = mock.Mock() orchestration_client.stacks.get.return_value = mock.Mock()
@ -1794,6 +1851,8 @@ class TestDeployOvercloud(fakes.TestDeployOvercloud):
self.cmd.take_action(parsed_args) self.cmd.take_action(parsed_args)
self.assertTrue(mock_deploy_tmpdir.called) self.assertTrue(mock_deploy_tmpdir.called)
self.assertTrue(mock_enable_ssh_admin.called)
self.assertTrue(mock_get_overcloud_hosts.called)
self.assertTrue(mock_config_download.called) self.assertTrue(mock_config_download.called)
def test_download_missing_files_from_plan(self): def test_download_missing_files_from_plan(self):

@ -0,0 +1,87 @@
# -*- 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.workflows import deployment
class TestDeploymentWorkflows(utils.TestCommand):
def setUp(self):
super(TestDeploymentWorkflows, self).setUp()
self.app.client_manager.workflow_engine = self.workflow = mock.Mock()
self.tripleoclient = mock.Mock()
self.websocket = mock.Mock()
self.websocket.__enter__ = lambda s: self.websocket
self.websocket.__exit__ = lambda s, *exc: None
self.tripleoclient.messaging_websocket.return_value = self.websocket
self.app.client_manager.tripleoclient = self.tripleoclient
self.message_success = iter([{
"execution": {"id": "IDID"},
"status": "SUCCESS",
"message": "Success.",
"registered_nodes": [],
}])
self.message_failed = iter([{
"execution": {"id": "IDID"},
"status": "FAIL",
"message": "Fail.",
}])
@mock.patch('tripleoclient.workflows.deployment.wait_for_ssh_port')
@mock.patch('tripleoclient.workflows.deployment.time.sleep')
@mock.patch('tripleoclient.workflows.deployment.shutil.rmtree')
@mock.patch('tripleoclient.workflows.deployment.open')
@mock.patch('tripleoclient.workflows.deployment.tempfile')
@mock.patch('tripleoclient.workflows.deployment.subprocess.check_call')
def test_enable_ssh_admin(self, mock_check_call, mock_tempfile,
mock_open, mock_rmtree, mock_sleep,
mock_wait_for_ssh_port):
log = mock.Mock()
hosts = 'a', 'b', 'c'
ssh_user = 'test-user'
ssh_key = 'test-key'
mock_tempfile.mkdtemp.return_value = '/foo'
mock_read = mock.Mock()
mock_read.read.return_value = 'key'
mock_open.return_value = mock_read
mock_state = mock.Mock()
mock_state.state = 'SUCCESS'
self.workflow.executions.get.return_value = mock_state
deployment.enable_ssh_admin(log, self.app.client_manager,
hosts, ssh_user, ssh_key)
# once for ssh-keygen, then twice per host
self.assertEqual(7, mock_check_call.call_count)
# execution ran
self.assertEqual(1, self.workflow.executions.create.call_count)
call_args = self.workflow.executions.create.call_args
self.assertEqual('tripleo.access.v1.enable_ssh_admin', call_args[0][0])
self.assertEqual(('a', 'b', 'c'),
call_args[1]['workflow_input']['ssh_servers'])
self.assertEqual('test-user',
call_args[1]['workflow_input']['ssh_user'])
self.assertEqual('key',
call_args[1]['workflow_input']['ssh_private_key'])
# tmpdir should be cleaned up
self.assertEqual(1, mock_rmtree.call_count)
self.assertEqual('/foo', mock_rmtree.call_args[0][0])

@ -625,6 +625,8 @@ class DeployOvercloud(command.Command):
) )
parser.add_argument( parser.add_argument(
'--overcloud-ssh-key', '--overcloud-ssh-key',
default=os.path.join(
os.path.expanduser('~'), '.ssh', 'id_rsa'),
help=_('Key path for ssh access to overcloud nodes.') help=_('Key path for ssh access to overcloud nodes.')
) )
parser.add_argument( parser.add_argument(
@ -900,9 +902,13 @@ class DeployOvercloud(command.Command):
if parsed_args.config_download: if parsed_args.config_download:
print("Deploying overcloud configuration") print("Deploying overcloud configuration")
hosts = deployment.get_overcloud_hosts(self.clients, stack)
deployment.enable_ssh_admin(self.log, self.clients,
hosts,
parsed_args.overcloud_ssh_user,
parsed_args.overcloud_ssh_key)
deployment.config_download(self.log, self.clients, stack, deployment.config_download(self.log, self.clients, stack,
parsed_args.templates, parsed_args.templates,
parsed_args.deployed_server,
parsed_args.overcloud_ssh_user, parsed_args.overcloud_ssh_user,
parsed_args.overcloud_ssh_key, parsed_args.overcloud_ssh_key,
parsed_args.output_dir, parsed_args.output_dir,

@ -14,12 +14,16 @@ from __future__ import print_function
import os import os
import pprint import pprint
import re import re
import shutil
import socket
import subprocess import subprocess
import tempfile
import time import time
from heatclient.common import event_utils from heatclient.common import event_utils
from openstackclient import shell from openstackclient import shell
from tripleoclient import constants
from tripleoclient import exceptions from tripleoclient import exceptions
from tripleoclient import utils from tripleoclient import utils
@ -104,47 +108,130 @@ def overcloudrc(workflow_client, **input_):
**input_) **input_)
def config_download(log, clients, stack, templates, deployed_server, def get_overcloud_hosts(clients, stack):
ssh_user, ssh_key, output_dir, verbosity=1):
role_net_hostname_map = utils.get_role_net_hostname_map(stack) role_net_hostname_map = utils.get_role_net_hostname_map(stack)
hostnames = [] hostnames = []
for role in role_net_hostname_map: for role in role_net_hostname_map:
hostnames.extend(role_net_hostname_map[role].get('ctlplane', [])) hostnames.extend(role_net_hostname_map[role].get('ctlplane', []))
ips = [] hosts = []
hosts_entry = utils.get_hosts_entry(stack) hosts_entry = utils.get_hosts_entry(stack)
for hostname in hostnames: for hostname in hostnames:
for line in hosts_entry.split('\n'): for line in hosts_entry.split('\n'):
match = re.search('\s*%s\s*' % hostname, line) match = re.search('\s*%s\s*' % hostname, line)
if match: if match:
ips.append(line.split(' ')[0]) hosts.append(line.split(' ')[0])
script_path = os.path.join(templates, return hosts
'deployed-server',
'scripts',
'enable-ssh-admin.sh')
env = os.environ.copy()
env.update(dict(OVERCLOUD_HOSTS=' '.join(ips),
OVERCLOUD_SSH_USER=ssh_user))
if ssh_key: def wait_for_ssh_port(host):
env['OVERCLOUD_SSH_KEY'] = ssh_key start = int(time.time())
while True:
now = int(time.time())
if (now - start) > constants.ENABLE_SSH_ADMIN_SSH_PORT_TIMEOUT:
raise exceptions.DeploymentError(
"Timed out waiting for port 22 from %s" % host)
proc = subprocess.Popen([script_path], env=env, shell=True, try:
stdout=subprocess.PIPE, socket.socket().connect((host, 22))
return
except socket.error:
pass
time.sleep(1)
def enable_ssh_admin(log, clients, hosts, ssh_user, ssh_key):
print("Enabling ssh admin (tripleo-admin) for hosts:")
print(" ".join(hosts))
print("Using ssh user %s for initial connection." % ssh_user)
print("Using ssh key at %s for initial connection." % ssh_key)
ssh_options = ("-o ConnectionAttempts=6 "
"-o ConnectTimeout=30 "
"-o StrictHostKeyChecking=no "
"-o UserKnownHostsFile=/dev/null")
tmp_key_dir = tempfile.mkdtemp()
tmp_key_private = os.path.join(tmp_key_dir, 'id_rsa')
tmp_key_public = os.path.join(tmp_key_dir, 'id_rsa.pub')
tmp_key_comment = "TripleO split stack short term key"
try:
tmp_key_command = ["ssh-keygen", "-N", "", "-t", "rsa", "-b", "4096",
"-f", tmp_key_private, "-C", tmp_key_comment]
subprocess.check_call(tmp_key_command, stderr=subprocess.STDOUT)
tmp_key_public_contents = open(tmp_key_public).read()
for host in hosts:
wait_for_ssh_port(host)
copy_tmp_key_command = ["ssh"] + ssh_options.split()
copy_tmp_key_command += \
["-o", "StrictHostKeyChecking=no",
"-i", ssh_key, "-l", ssh_user, host,
"echo -e '\n%s' >> $HOME/.ssh/authorized_keys" %
tmp_key_public_contents]
print("Inserting TripleO short term key for %s" % host)
subprocess.check_call(copy_tmp_key_command,
stderr=subprocess.STDOUT) stderr=subprocess.STDOUT)
while True: print("Starting ssh admin enablement workflow")
line = proc.stdout.readline().decode('utf-8')
if line:
log.info(line.rstrip())
if line == '' and proc.poll() is not None:
break
if proc.returncode != 0:
raise RuntimeError('%s failed.' % script_path)
workflow_client = clients.workflow_engine workflow_client = clients.workflow_engine
workflow_input = {
"ssh_user": ssh_user,
"ssh_servers": hosts,
"ssh_private_key": open(tmp_key_private).read(),
}
execution = base.start_workflow(
workflow_client,
'tripleo.access.v1.enable_ssh_admin',
workflow_input=workflow_input
)
start = int(time.time())
while True:
now = int(time.time())
if (now - start) > constants.ENABLE_SSH_ADMIN_TIMEOUT:
raise exceptions.DeploymentError(
"ssh admin enablement workflow - TIMED OUT.")
time.sleep(1)
execution = workflow_client.executions.get(execution.id)
state = execution.state
if state == 'RUNNING':
if (now - start) % constants.ENABLE_SSH_ADMIN_STATUS_INTERVAL\
== 0:
print("ssh admin enablement workflow - RUNNING.")
continue
elif state == 'SUCCESS':
print("ssh admin enablement workflow - COMPLETE.")
break
elif state == 'FAILED':
raise exceptions.DeploymentError(
"ssh admin enablement workflow - FAILED.")
for host in hosts:
rm_tmp_key_command = ["ssh"] + ssh_options.split()
rm_tmp_key_command += \
["-l", ssh_user, host,
"sed -i -e '/%s/d' $HOME/.ssh/authorized_keys" %
tmp_key_comment]
print("Removing TripleO short term key from %s" % host)
subprocess.check_call(rm_tmp_key_command, stderr=subprocess.STDOUT)
finally:
print("Removing short term keys locally")
shutil.rmtree(tmp_key_dir)
print("Enabling ssh admin - COMPLETE.")
def config_download(log, clients, stack, templates,
ssh_user, ssh_key, output_dir, verbosity=1):
workflow_client = clients.workflow_engine
tripleoclients = clients.tripleoclient tripleoclients = clients.tripleoclient
workflow_input = { workflow_input = {