Add commands to run command on hosts

Change-Id: I019fc3f5c59c383215febb958f9c4cf8c8b8e4a6
Story: 2003312
Task: 24270
This commit is contained in:
Kevin Tibi 2018-08-06 12:32:23 +02:00 committed by Will Szumski
parent 7cb684a253
commit b8305b1799
9 changed files with 201 additions and 0 deletions

View File

@ -0,0 +1,6 @@
---
- name: Run a command
hosts: seed-hypervisor:seed:overcloud
tasks:
- name: Run a command
shell: "{{ host_command_to_run }}"

View File

@ -21,6 +21,20 @@ To only install updates that have been marked security related::
Note that these commands do not affect packages installed in containers, only Note that these commands do not affect packages installed in containers, only
those installed on the host. those installed on the host.
Running Commands
================
It is possible to run a command on the overcloud hosts::
(kayobe) $ kayobe overcloud host command run --command "<command>"
For example::
(kayobe) $ kayobe overcloud host command run --command "service docker restart"
To execute the command with root privileges, add the ``--become`` argument.
Adding the ``--verbose`` argument allows the output of the command to be seen.
Reconfiguring Containerised Services Reconfiguring Containerised Services
==================================== ====================================

View File

@ -122,3 +122,21 @@ Finally, start the Ironic and Ironic Inspector services again::
docker exec -it bifrost_deploy \ docker exec -it bifrost_deploy \
systemctl start ironic-api ironic-conductor ironic-inspector systemctl start ironic-api ironic-conductor ironic-inspector
Running Commands
================
It is possible to run a command on the seed host::
(kayobe) $ kayobe seed host command run --command "<command>"
For example::
(kayobe) $ kayobe seed host command run --command "service docker restart"
Commands can also be run on the seed hypervisor host, if one is in use::
(kayobe) $ kayobe seed hypervisor host command run --command "<command>"
To execute the command with root privileges, add the ``--become`` argument.
Adding the ``--verbose`` argument allows the output of the command to be seen.

View File

@ -326,6 +326,27 @@ class SeedHypervisorHostConfigure(KollaAnsibleMixin, KayobeAnsibleMixin,
limit="seed-hypervisor") limit="seed-hypervisor")
class SeedHypervisorHostCommandRun(KayobeAnsibleMixin, VaultMixin, Command):
"""Run command on the seed hypervisor host."""
def get_parser(self, prog_name):
parser = super(SeedHypervisorHostCommandRun, self).get_parser(
prog_name)
group = parser.add_argument_group("Host Command Run")
group.add_argument("--command", required=True,
help="Command to run (required).")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Run command on seed hypervisor host")
extra_vars = {
"host_command_to_run": utils.escape_jinja(parsed_args.command)}
playbooks = _build_playbook_list("host-command-run")
self.run_kayobe_playbooks(parsed_args, playbooks,
limit="seed-hypervisor",
extra_vars=extra_vars)
class SeedHypervisorHostUpgrade(KayobeAnsibleMixin, VaultMixin, Command): class SeedHypervisorHostUpgrade(KayobeAnsibleMixin, VaultMixin, Command):
"""Upgrade the seed hypervisor host services. """Upgrade the seed hypervisor host services.
@ -503,6 +524,25 @@ class SeedHostPackageUpdate(KayobeAnsibleMixin, VaultMixin, Command):
extra_vars=extra_vars) extra_vars=extra_vars)
class SeedHostCommandRun(KayobeAnsibleMixin, VaultMixin, Command):
"""Run command on the seed host."""
def get_parser(self, prog_name):
parser = super(SeedHostCommandRun, self).get_parser(prog_name)
group = parser.add_argument_group("Host Command Run")
group.add_argument("--command", required=True,
help="Command to run (required).")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Run command on seed host")
extra_vars = {
"host_command_to_run": utils.escape_jinja(parsed_args.command)}
playbooks = _build_playbook_list("host-command-run")
self.run_kayobe_playbooks(parsed_args, playbooks, limit="seed",
extra_vars=extra_vars)
class SeedHostUpgrade(KollaAnsibleMixin, KayobeAnsibleMixin, VaultMixin, class SeedHostUpgrade(KollaAnsibleMixin, KayobeAnsibleMixin, VaultMixin,
Command): Command):
"""Upgrade the seed host services. """Upgrade the seed host services.
@ -877,6 +917,25 @@ class OvercloudHostPackageUpdate(KayobeAnsibleMixin, VaultMixin, Command):
extra_vars=extra_vars) extra_vars=extra_vars)
class OvercloudHostCommandRun(KayobeAnsibleMixin, VaultMixin, Command):
"""Run command on the overcloud host."""
def get_parser(self, prog_name):
parser = super(OvercloudHostCommandRun, self).get_parser(prog_name)
group = parser.add_argument_group("Host Command Run")
group.add_argument("--command", required=True,
help="Command to run (required).")
return parser
def take_action(self, parsed_args):
self.app.LOG.debug("Run command on overcloud host")
extra_vars = {
"host_command_to_run": utils.escape_jinja(parsed_args.command)}
playbooks = _build_playbook_list("host-command-run")
self.run_kayobe_playbooks(parsed_args, playbooks, limit="overcloud",
extra_vars=extra_vars)
class OvercloudHostUpgrade(KayobeAnsibleMixin, VaultMixin, Command): class OvercloudHostUpgrade(KayobeAnsibleMixin, VaultMixin, Command):
"""Upgrade the overcloud host services. """Upgrade the overcloud host services.

View File

@ -273,6 +273,30 @@ class TestCase(unittest.TestCase):
] ]
self.assertEqual(expected_calls, mock_run.call_args_list) self.assertEqual(expected_calls, mock_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks")
def test_seed_hypervisor_host_command_run(self, mock_run):
command = commands.SeedHypervisorHostCommandRun(TestApp(), [])
parser = command.get_parser("test")
parsed_args = parser.parse_args(["--command", "ls -a"])
result = command.run(parsed_args)
self.assertEqual(0, result)
expected_calls = [
mock.call(
mock.ANY,
[
utils.get_data_files_path("ansible",
"host-command-run.yml"),
],
limit="seed-hypervisor",
extra_vars={
"host_command_to_run": utils.escape_jinja("ls -a")},
),
]
self.assertEqual(expected_calls, mock_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin, @mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks") "run_kayobe_playbooks")
def test_seed_hypervisor_host_upgrade(self, mock_run): def test_seed_hypervisor_host_upgrade(self, mock_run):
@ -485,6 +509,30 @@ class TestCase(unittest.TestCase):
] ]
self.assertEqual(expected_calls, mock_kolla_run.call_args_list) self.assertEqual(expected_calls, mock_kolla_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks")
def test_seed_host_command_run(self, mock_run):
command = commands.SeedHostCommandRun(TestApp(), [])
parser = command.get_parser("test")
parsed_args = parser.parse_args(["--command", "ls -a"])
result = command.run(parsed_args)
self.assertEqual(0, result)
expected_calls = [
mock.call(
mock.ANY,
[
utils.get_data_files_path("ansible",
"host-command-run.yml"),
],
limit="seed",
extra_vars={
"host_command_to_run": utils.escape_jinja("ls -a")},
),
]
self.assertEqual(expected_calls, mock_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin, @mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks") "run_kayobe_playbooks")
def test_seed_host_package_update_all(self, mock_run): def test_seed_host_package_update_all(self, mock_run):
@ -1059,6 +1107,30 @@ class TestCase(unittest.TestCase):
] ]
self.assertEqual(expected_calls, mock_kolla_run.call_args_list) self.assertEqual(expected_calls, mock_kolla_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks")
def test_overcloud_host_command_run(self, mock_run):
command = commands.OvercloudHostCommandRun(TestApp(), [])
parser = command.get_parser("test")
parsed_args = parser.parse_args(["--command", "ls -a"])
result = command.run(parsed_args)
self.assertEqual(0, result)
expected_calls = [
mock.call(
mock.ANY,
[
utils.get_data_files_path("ansible",
"host-command-run.yml"),
],
limit="overcloud",
extra_vars={
"host_command_to_run": utils.escape_jinja("ls -a")},
),
]
self.assertEqual(expected_calls, mock_run.call_args_list)
@mock.patch.object(commands.KayobeAnsibleMixin, @mock.patch.object(commands.KayobeAnsibleMixin,
"run_kayobe_playbooks") "run_kayobe_playbooks")
def test_overcloud_host_package_update_all(self, mock_run): def test_overcloud_host_package_update_all(self, mock_run):

View File

@ -123,3 +123,8 @@ key2: value2
def test_quote_and_escape_non_string(self): def test_quote_and_escape_non_string(self):
self.assertEqual(True, utils.quote_and_escape(True)) self.assertEqual(True, utils.quote_and_escape(True))
def test_escape_jinja(self):
value = "string to escape"
expected = "{{'c3RyaW5nIHRvIGVzY2FwZQ==' | b64decode }}"
self.assertEqual(expected, utils.escape_jinja(value))

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import base64
import glob import glob
import logging import logging
import os import os
@ -165,3 +166,18 @@ def quote_and_escape(value):
if not isinstance(value, six.string_types): if not isinstance(value, six.string_types):
return value return value
return "'" + value.replace("'", "'\\''") + "'" return "'" + value.replace("'", "'\\''") + "'"
def escape_jinja(string):
"""Escapes a string so that jinja template variables are not expanded
:param string: the string to escape
:return: the escaped string
"""
# We base64 encode the string to avoid the need to escape characters.
# This is because ansible has some parsing quirks that makes it fairly
# hard to escape stuff in generic way.
# See: https://github.com/ansible/ansible/issues/10464
b64_value = base64.b64encode(string.encode())
return ''.join(('{{', "'", b64_value.decode(), "' | b64decode ", '}}'))

View File

@ -0,0 +1,8 @@
---
features:
- |
Add commands to run commands on seed hypervisor, seed and overcloud hosts:
``kayobe seed hypervisor host command run --command <command>``
``kayobe seed host command run --command <command>``
``kayobe overcloud host command run --command <command>``

View File

@ -58,6 +58,7 @@ kayobe.cli=
overcloud_hardware_inspect = kayobe.cli.commands:OvercloudHardwareInspect overcloud_hardware_inspect = kayobe.cli.commands:OvercloudHardwareInspect
overcloud_host_configure = kayobe.cli.commands:OvercloudHostConfigure overcloud_host_configure = kayobe.cli.commands:OvercloudHostConfigure
overcloud_host_package_update = kayobe.cli.commands:OvercloudHostPackageUpdate overcloud_host_package_update = kayobe.cli.commands:OvercloudHostPackageUpdate
overcloud_host_command_run = kayobe.cli.commands:OvercloudHostCommandRun
overcloud_host_upgrade = kayobe.cli.commands:OvercloudHostUpgrade overcloud_host_upgrade = kayobe.cli.commands:OvercloudHostUpgrade
overcloud_introspection_data_save = kayobe.cli.commands:OvercloudIntrospectionDataSave overcloud_introspection_data_save = kayobe.cli.commands:OvercloudIntrospectionDataSave
overcloud_inventory_discover = kayobe.cli.commands:OvercloudInventoryDiscover overcloud_inventory_discover = kayobe.cli.commands:OvercloudInventoryDiscover
@ -75,8 +76,10 @@ kayobe.cli=
seed_deployment_image_build = kayobe.cli.commands:SeedDeploymentImageBuild seed_deployment_image_build = kayobe.cli.commands:SeedDeploymentImageBuild
seed_host_configure = kayobe.cli.commands:SeedHostConfigure seed_host_configure = kayobe.cli.commands:SeedHostConfigure
seed_host_package_update = kayobe.cli.commands:SeedHostPackageUpdate seed_host_package_update = kayobe.cli.commands:SeedHostPackageUpdate
seed_host_command_run = kayobe.cli.commands:SeedHostCommandRun
seed_host_upgrade = kayobe.cli.commands:SeedHostUpgrade seed_host_upgrade = kayobe.cli.commands:SeedHostUpgrade
seed_hypervisor_host_configure = kayobe.cli.commands:SeedHypervisorHostConfigure seed_hypervisor_host_configure = kayobe.cli.commands:SeedHypervisorHostConfigure
seed_hypervisor_host_command_run = kayobe.cli.commands:SeedHypervisorHostCommandRun
seed_hypervisor_host_upgrade = kayobe.cli.commands:SeedHypervisorHostUpgrade seed_hypervisor_host_upgrade = kayobe.cli.commands:SeedHypervisorHostUpgrade
seed_service_deploy = kayobe.cli.commands:SeedServiceDeploy seed_service_deploy = kayobe.cli.commands:SeedServiceDeploy
seed_service_upgrade = kayobe.cli.commands:SeedServiceUpgrade seed_service_upgrade = kayobe.cli.commands:SeedServiceUpgrade