mirror of https://github.com/ansible/ansible.git
Co-authored-by: Matt Clay <matt@mystile.com>
(cherry picked from commit b6ebb9d41a)
pull/81285/head
parent
c8b5d96ee0
commit
d03bf6430c
@ -1,22 +0,0 @@
|
|||||||
- import_tasks: get_boot_time.yml
|
|
||||||
- name: Reboot with custom reboot_command using unqualified path
|
|
||||||
reboot:
|
|
||||||
reboot_command: reboot
|
|
||||||
register: reboot_result
|
|
||||||
- import_tasks: check_reboot.yml
|
|
||||||
|
|
||||||
|
|
||||||
- import_tasks: get_boot_time.yml
|
|
||||||
- name: Reboot with custom reboot_command using absolute path
|
|
||||||
reboot:
|
|
||||||
reboot_command: /sbin/reboot
|
|
||||||
register: reboot_result
|
|
||||||
- import_tasks: check_reboot.yml
|
|
||||||
|
|
||||||
|
|
||||||
- import_tasks: get_boot_time.yml
|
|
||||||
- name: Reboot with custom reboot_command with parameters
|
|
||||||
reboot:
|
|
||||||
reboot_command: shutdown -r now
|
|
||||||
register: reboot_result
|
|
||||||
- import_tasks: check_reboot.yml
|
|
||||||
@ -0,0 +1,214 @@
|
|||||||
|
# Copyright (c) 2022 Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
"""Tests for the reboot action plugin."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from ansible.errors import AnsibleConnectionFailure
|
||||||
|
from ansible.playbook.task import Task
|
||||||
|
from ansible.plugins.action.reboot import ActionModule as RebootAction
|
||||||
|
from ansible.plugins.loader import connection_loader
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def task_args(request):
|
||||||
|
"""Return playbook task args."""
|
||||||
|
return getattr(request, 'param', {})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def module_task(mocker, task_args):
|
||||||
|
"""Construct a task object."""
|
||||||
|
task = mocker.MagicMock(Task)
|
||||||
|
task.action = 'reboot'
|
||||||
|
task.args = task_args
|
||||||
|
task.async_val = False
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def play_context(mocker):
|
||||||
|
"""Construct a play context."""
|
||||||
|
ctx = mocker.MagicMock()
|
||||||
|
ctx.check_mode = False
|
||||||
|
ctx.shell = 'sh'
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def action_plugin(play_context, module_task):
|
||||||
|
"""Initialize an action plugin."""
|
||||||
|
connection = connection_loader.get('local', play_context, os.devnull)
|
||||||
|
loader = None
|
||||||
|
templar = None
|
||||||
|
shared_loader_obj = None
|
||||||
|
|
||||||
|
return RebootAction(
|
||||||
|
module_task,
|
||||||
|
connection,
|
||||||
|
play_context,
|
||||||
|
loader,
|
||||||
|
templar,
|
||||||
|
shared_loader_obj,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_SENTINEL_REBOOT_COMMAND = '/reboot-command-mock --arg'
|
||||||
|
_SENTINEL_SHORT_REBOOT_COMMAND = '/reboot-command-mock'
|
||||||
|
_SENTINEL_TEST_COMMAND = 'cmd-stub'
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'task_args',
|
||||||
|
(
|
||||||
|
{
|
||||||
|
'reboot_timeout': 5,
|
||||||
|
'reboot_command': _SENTINEL_REBOOT_COMMAND,
|
||||||
|
'test_command': _SENTINEL_TEST_COMMAND,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'reboot_timeout': 5,
|
||||||
|
'reboot_command': _SENTINEL_SHORT_REBOOT_COMMAND,
|
||||||
|
'test_command': _SENTINEL_TEST_COMMAND,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ids=('reboot command with spaces', 'reboot command without spaces'),
|
||||||
|
indirect=('task_args', ),
|
||||||
|
)
|
||||||
|
def test_reboot_command(action_plugin, mocker, monkeypatch, task_args):
|
||||||
|
"""Check that the reboot command gets called and reboot verified."""
|
||||||
|
def _patched_low_level_execute_command(cmd, *args, **kwargs):
|
||||||
|
return {
|
||||||
|
_SENTINEL_TEST_COMMAND: {
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<test command stub-stderr>',
|
||||||
|
'stdout': '<test command stub-stdout>',
|
||||||
|
},
|
||||||
|
_SENTINEL_REBOOT_COMMAND: {
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<reboot command stub-stderr>',
|
||||||
|
'stdout': '<reboot command stub-stdout>',
|
||||||
|
},
|
||||||
|
f'{_SENTINEL_SHORT_REBOOT_COMMAND} ': { # no args is concatenated
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<short reboot command stub-stderr>',
|
||||||
|
'stdout': '<short reboot command stub-stdout>',
|
||||||
|
},
|
||||||
|
}[cmd]
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
action_plugin,
|
||||||
|
'_low_level_execute_command',
|
||||||
|
_patched_low_level_execute_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
action_plugin._connection = mocker.Mock()
|
||||||
|
|
||||||
|
monkeypatch.setattr(action_plugin, 'check_boot_time', lambda *_a, **_kw: 5)
|
||||||
|
monkeypatch.setattr(action_plugin, 'get_distribution', mocker.MagicMock())
|
||||||
|
monkeypatch.setattr(action_plugin, 'get_system_boot_time', lambda d: 0)
|
||||||
|
|
||||||
|
low_level_cmd_spy = mocker.spy(action_plugin, '_low_level_execute_command')
|
||||||
|
|
||||||
|
action_result = action_plugin.run()
|
||||||
|
|
||||||
|
assert low_level_cmd_spy.called
|
||||||
|
|
||||||
|
expected_reboot_command = (
|
||||||
|
task_args['reboot_command'] if ' ' in task_args['reboot_command']
|
||||||
|
else f'{task_args["reboot_command"] !s} '
|
||||||
|
)
|
||||||
|
low_level_cmd_spy.assert_any_call(expected_reboot_command, sudoable=True)
|
||||||
|
low_level_cmd_spy.assert_any_call(task_args['test_command'], sudoable=True)
|
||||||
|
|
||||||
|
assert low_level_cmd_spy.call_count == 2
|
||||||
|
assert low_level_cmd_spy.spy_return == {
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<test command stub-stderr>',
|
||||||
|
'stdout': '<test command stub-stdout>',
|
||||||
|
}
|
||||||
|
assert low_level_cmd_spy.spy_exception is None
|
||||||
|
|
||||||
|
assert 'failed' not in action_result
|
||||||
|
assert action_result == {'rebooted': True, 'changed': True, 'elapsed': 0}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'task_args',
|
||||||
|
(
|
||||||
|
{
|
||||||
|
'reboot_timeout': 5,
|
||||||
|
'reboot_command': _SENTINEL_REBOOT_COMMAND,
|
||||||
|
'test_command': _SENTINEL_TEST_COMMAND,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ids=('reboot command with spaces', ),
|
||||||
|
indirect=('task_args', ),
|
||||||
|
)
|
||||||
|
def test_reboot_command_connection_fail(action_plugin, mocker, monkeypatch, task_args):
|
||||||
|
"""Check that the reboot command gets called and reboot verified."""
|
||||||
|
def _patched_low_level_execute_command(cmd, *args, **kwargs):
|
||||||
|
if cmd == _SENTINEL_REBOOT_COMMAND:
|
||||||
|
raise AnsibleConnectionFailure('Fake connection drop')
|
||||||
|
return {
|
||||||
|
_SENTINEL_TEST_COMMAND: {
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<test command stub-stderr>',
|
||||||
|
'stdout': '<test command stub-stdout>',
|
||||||
|
},
|
||||||
|
}[cmd]
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
action_plugin,
|
||||||
|
'_low_level_execute_command',
|
||||||
|
_patched_low_level_execute_command,
|
||||||
|
)
|
||||||
|
|
||||||
|
action_plugin._connection = mocker.Mock()
|
||||||
|
|
||||||
|
monkeypatch.setattr(action_plugin, 'check_boot_time', lambda *_a, **_kw: 5)
|
||||||
|
monkeypatch.setattr(action_plugin, 'get_distribution', mocker.MagicMock())
|
||||||
|
monkeypatch.setattr(action_plugin, 'get_system_boot_time', lambda d: 0)
|
||||||
|
|
||||||
|
low_level_cmd_spy = mocker.spy(action_plugin, '_low_level_execute_command')
|
||||||
|
|
||||||
|
action_result = action_plugin.run()
|
||||||
|
|
||||||
|
assert low_level_cmd_spy.called
|
||||||
|
|
||||||
|
low_level_cmd_spy.assert_any_call(
|
||||||
|
task_args['reboot_command'], sudoable=True,
|
||||||
|
)
|
||||||
|
low_level_cmd_spy.assert_any_call(task_args['test_command'], sudoable=True)
|
||||||
|
|
||||||
|
assert low_level_cmd_spy.call_count == 2
|
||||||
|
assert low_level_cmd_spy.spy_return == {
|
||||||
|
'rc': 0,
|
||||||
|
'stderr': '<test command stub-stderr>',
|
||||||
|
'stdout': '<test command stub-stdout>',
|
||||||
|
}
|
||||||
|
|
||||||
|
assert 'failed' not in action_result
|
||||||
|
assert action_result == {'rebooted': True, 'changed': True, 'elapsed': 0}
|
||||||
|
|
||||||
|
|
||||||
|
def test_reboot_connection_local(action_plugin, module_task):
|
||||||
|
"""Verify that using local connection doesn't let reboot happen."""
|
||||||
|
expected_message = ' '.join(
|
||||||
|
(
|
||||||
|
'Running', module_task.action,
|
||||||
|
'with local connection would reboot the control node.',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
expected_action_result = {
|
||||||
|
'changed': False,
|
||||||
|
'elapsed': 0,
|
||||||
|
'failed': True,
|
||||||
|
'msg': expected_message,
|
||||||
|
'rebooted': False,
|
||||||
|
}
|
||||||
|
|
||||||
|
action_result = action_plugin.run()
|
||||||
|
|
||||||
|
assert action_result == expected_action_result
|
||||||
Loading…
Reference in New Issue