diff --git a/kolla_cli/api/control_plane.py b/kolla_cli/api/control_plane.py index 29365fc..77dc2e3 100644 --- a/kolla_cli/api/control_plane.py +++ b/kolla_cli/api/control_plane.py @@ -60,6 +60,36 @@ class ControlPlaneApi(object): ansible_job = action.deploy(hostnames, serial_flag, servicenames) return Job(ansible_job) + @staticmethod + def prechecks(verbose_level=1, hostnames=[], servicenames=[]): + # type: (int, List[str], List[str]) -> Job + """Check pre-deployment configuration of hosts. + + Check if host is ready for a new deployment. This will fail if + any of the hosts are not configured correctly or if they have + already been deployed to. + :param hostnames: host names + :type hostnames: list + :param verbose_level: the higher the number, the more verbose + :type verbose_level: integer + :param servicenames: services to prechecks. + :type servicenames: list of strings + :return: Job object + :rtype: Job + """ + check_arg(hostnames, u._('Host names'), list, + empty_ok=True, none_ok=True) + check_arg(verbose_level, u._('Verbose level'), int) + check_arg(servicenames, u._('Service names'), list, + empty_ok=True, none_ok=True) + + hostnames = safe_decode(hostnames) + servicenames = safe_decode(servicenames) + action = KollaAction(verbose_level=verbose_level, + playbook_name='site.yml') + ansible_job = action.precheck(hostnames, servicenames) + return Job(ansible_job) + @staticmethod def pull(verbose_level=1, hostnames=[], servicenames=[]): """Pull. diff --git a/kolla_cli/api/host.py b/kolla_cli/api/host.py index 8fe2a75..1b9e338 100644 --- a/kolla_cli/api/host.py +++ b/kolla_cli/api/host.py @@ -190,32 +190,6 @@ class HostApi(object): include_data, remove_images) return Job(ansible_job) - @staticmethod - def host_precheck(hostnames, verbose_level=1): - # type: (List[str], int) -> Job - """Check pre-deployment configuration of hosts. - - Check if host is ready for a new deployment. This will fail if - any of the hosts are not configured correctly or if they have - already been deployed to. - :param hostnames: host names - :type hostnames: list - :param verbose_level: the higher the number, the more verbose - :type verbose_level: integer - :return: Job object - :rtype: Job - """ - check_arg(hostnames, u._('Host names'), list) - check_arg(verbose_level, u._('Verbose level'), int) - hostnames = safe_decode(hostnames) - inventory = Inventory.load() - inventory.validate_hostnames(hostnames) - - action = KollaAction(verbose_level=verbose_level, - playbook_name='site.yml') - ansible_job = action.precheck(hostnames) - return Job(ansible_job) - @staticmethod def host_stop(hostnames, verbose_level=1): # type: (List[str], int) -> Job diff --git a/kolla_cli/commands/host.py b/kolla_cli/commands/host.py index 2de89c1..4b859dc 100644 --- a/kolla_cli/commands/host.py +++ b/kolla_cli/commands/host.py @@ -185,45 +185,37 @@ class HostList(Lister): class HostCheck(Command): - """Check configuration of host(s).""" + """Check an ssh check of host(s).""" def get_parser(self, prog_name): parser = super(HostCheck, self).get_parser(prog_name) parser.add_argument('hostname', metavar='', help=u._('Host name or "all"')) - parser.add_argument('--predeploy', action='store_true', - help=u._('Run pre-deploy host checks.')) return parser def take_action(self, parsed_args): try: hostname = parsed_args.hostname.strip() - hostnames = [hostname] if hostname == 'all': hostnames = _get_all_hostnames() - - if parsed_args.predeploy: - # run pre-deploy checks - verbose_level = self.app.options.verbose_level - job = CLIENT.host_precheck(hostnames, verbose_level) - status = job.wait() - handers_action_result(job, status, verbose_level) else: - # just do an ssh check - summary = CLIENT.host_ssh_check(hostnames) - all_ok = True - for hostname, info in summary.items(): - status = u._('success') - msg = '' - if not info['success']: - status = u._('failed-') - msg = info['msg'] - all_ok = False - LOG.info(u._('Host {host}: {sts} {msg}') - .format(host=hostname, sts=status, msg=msg)) + hostnames = [hostname] - if not all_ok: - raise CommandError(u._('Host check failed.')) + # just do an ssh check + summary = CLIENT.host_ssh_check(hostnames) + all_ok = True + for hostname, info in summary.items(): + status = u._('success') + msg = '' + if not info['success']: + status = u._('failed-') + msg = info['msg'] + all_ok = False + LOG.info(u._('Host {host}: {sts} {msg}') + .format(host=hostname, sts=status, msg=msg)) + + if not all_ok: + raise CommandError(u._('Host check failed.')) except ClientException as e: raise CommandError(str(e)) except Exception as e: diff --git a/kolla_cli/commands/kolla_action.py b/kolla_cli/commands/kolla_action.py index f0908e7..4f0f993 100644 --- a/kolla_cli/commands/kolla_action.py +++ b/kolla_cli/commands/kolla_action.py @@ -99,6 +99,37 @@ class Deploy(Command): raise Exception(traceback.format_exc()) +class Prechecks(Command): + """Do pre-deployment checks for hosts.""" + def get_parser(self, prog_name): + parser = super(Prechecks, self).get_parser(prog_name) + parser.add_argument('--hosts', nargs='?', + metavar='', + help=u._('Pull host list')) + parser.add_argument('--services', nargs='?', + metavar='', + help=u._('Pull service list')) + return parser + + def take_action(self, parsed_args): + hosts = [] + services = [] + try: + verbose_level = self.app.options.verbose_level + + if parsed_args.hosts: + host_list = parsed_args.hosts.strip() + hosts = host_list.split(',') + if parsed_args.services: + service_list = parsed_args.services.strip() + services = service_list.split(',') + job = CLIENT.prechecks(verbose_level, hosts, services) + status = job.wait() + handers_action_result(job, status, verbose_level) + except Exception: + raise Exception(traceback.format_exc()) + + class Pull(Command): """Pull all images for containers (only pulls, no running container).""" def get_parser(self, prog_name): diff --git a/kolla_cli/common/ansible/actions.py b/kolla_cli/common/ansible/actions.py index b63bcfc..dad7fe3 100644 --- a/kolla_cli/common/ansible/actions.py +++ b/kolla_cli/common/ansible/actions.py @@ -118,7 +118,7 @@ class KollaAction(object): job = self.playbook.run() return job - def precheck(self, hostnames): + def precheck(self, hostnames=[], servicenames=[]): '''run check playbooks on a set of hosts''' # check that password file has no empty password values @@ -135,7 +135,8 @@ class KollaAction(object): # define 'hosts' to be all, but inventory filtering will subset # that down to the hosts in playbook.hosts. self.playbook.hosts = hostnames - self.playbook.extra_vars = 'kolla_action=precheck hosts=all' + self.playbook.services = servicenames + self.playbook.extra_vars = 'kolla_action=precheck' self.playbook.print_output = True job = self.playbook.run() return job diff --git a/kolla_cli/tests/functional/test_host.py b/kolla_cli/tests/functional/test_host.py index 73ba7ae..3d93200 100644 --- a/kolla_cli/tests/functional/test_host.py +++ b/kolla_cli/tests/functional/test_host.py @@ -122,7 +122,6 @@ class TestFunctional(KollaCliTest): self.check_types(CLIENT.host_setup, [dict]) self.check_types(CLIENT.host_ssh_check, [list]) self.check_types(CLIENT.host_destroy, [list, str, int, bool]) - self.check_types(CLIENT.host_precheck, [list, int]) def test_host_list_nonascii(self): hostname = 'host_test1' diff --git a/kolla_cli/tests/unit/test_host_cmd.py b/kolla_cli/tests/unit/test_host_cmd.py index 0389aae..226bb50 100644 --- a/kolla_cli/tests/unit/test_host_cmd.py +++ b/kolla_cli/tests/unit/test_host_cmd.py @@ -135,30 +135,6 @@ class TestUnit(KollaCliUnitTest): mock_ssh_check.assert_called_once_with([hostname]) mock_log.assert_called_once_with('Host %s: failed- FAILED' % hostname) - @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') - @mock.patch('kolla_cli.commands.host.ClientApi.host_precheck') - @mock.patch('kolla_cli.api.client.ClientApi.host_get_all') - @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', - return_value=True) - def test_host_precheck(self, _, mock_get_all, mock_precheck, - mock_get_status): - hostname = 'foo' - mock_get_all.return_value = [self.get_fake_host(hostname)] - - # host check hostname --predeploy (success) - mock_precheck.return_value = self.get_fake_job() - mock_get_status.return_value = 0 - ret = self.run_cli_command('host check %s --predeploy' % hostname) - self.assertEqual(ret, 0) - mock_precheck.assert_called_once_with([hostname], 1) - - # host check hostname --predeploy (fail) - mock_precheck.reset_mock() - mock_get_status.return_value = 1 - ret = self.run_cli_command('host check %s --predeploy' % hostname) - self.assertEqual(ret, 1) - mock_precheck.assert_called_once_with([hostname], 1) - @mock.patch('kolla_cli.commands.host.HostSetup._get_yml_data') @mock.patch('getpass.getpass') @mock.patch('kolla_cli.commands.host.ClientApi.host_ssh_check') diff --git a/kolla_cli/tests/unit/test_prechecks_cmd.py b/kolla_cli/tests/unit/test_prechecks_cmd.py new file mode 100644 index 0000000..3ba39f3 --- /dev/null +++ b/kolla_cli/tests/unit/test_prechecks_cmd.py @@ -0,0 +1,74 @@ +# Copyright (c) 2018 OpenStack Foundation +# +# 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 kolla_cli.tests.unit.common import KollaCliUnitTest + + +class TestUnit(KollaCliUnitTest): + @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') + @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') + @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', + return_value=True) + def test_prechecks(self, _, mock_get_status, mock_prechecks): + mock_get_status.return_value = 0 + mock_prechecks.return_value = self.get_fake_job() + ret = self.run_cli_command('action prechecks') + self.assertEqual(ret, 0) + mock_prechecks.assert_called_once_with(1, [], []) + + @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') + @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') + @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', + return_value=True) + def test_prechecks_with_hosts(self, _, mock_get_status, mock_prechecks): + mock_get_status.return_value = 0 + mock_prechecks.return_value = self.get_fake_job() + hostnames = ['host1', 'host2'] + ret = self.run_cli_command( + 'action prechecks --hosts {hosts}'.format( + hosts=','.join(hostnames))) + self.assertEqual(ret, 0) + mock_prechecks.assert_called_once_with(1, hostnames, []) + + @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') + @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') + @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', + return_value=True) + def test_prechecks_with_services(self, _, mock_get_status, mock_prechecks): + mock_get_status.return_value = 0 + mock_prechecks.return_value = self.get_fake_job() + services = ['service1', 'service2'] + ret = self.run_cli_command( + 'action prechecks --service {services}'.format( + services=','.join(services))) + self.assertEqual(ret, 0) + mock_prechecks.assert_called_once_with(1, [], services) + + @mock.patch('kolla_cli.api.control_plane.ControlPlaneApi.prechecks') + @mock.patch('kolla_cli.common.ansible.job.AnsibleJob.get_status') + @mock.patch('kolla_cli.shell.KollaCli._is_inventory_present', + return_value=True) + def test_prechecks_with_hosts_and_services(self, _, mock_get_status, + mock_prechecks): + mock_get_status.return_value = 0 + mock_prechecks.return_value = self.get_fake_job() + hostnames = ['host1', 'host2'] + services = ['service1', 'service2'] + ret = self.run_cli_command( + 'action prechecks --hosts {hosts} --service {services}'.format( + hosts=','.join(hostnames), services=','.join(services))) + self.assertEqual(ret, 0) + mock_prechecks.assert_called_once_with(1, hostnames, services) diff --git a/setup.cfg b/setup.cfg index be87d20..9d1e6a4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -32,6 +32,7 @@ kolla.cli = action_check = kolla_cli.commands.kolla_action:Check action_deploy = kolla_cli.commands.kolla_action:Deploy action_genconfig = kolla_cli.commands.kolla_action:Genconfig + action_prechecks = kolla_cli.commands.kolla_action:Prechecks action_postdeploy = kolla_cli.commands.kolla_action:PostDeploy action_pull = kolla_cli.commands.kolla_action:Pull action_reconfigure = kolla_cli.commands.kolla_action:Reconfigure