Example #1
0
    def test_action_base_sudo_only_if_user_differs(self):
        fake_loader = MagicMock()
        fake_loader.get_basedir.return_value = os.getcwd()
        play_context = PlayContext()
        action_base = DerivedActionBase(None, None, play_context, fake_loader, None, None)
        action_base._connection = MagicMock(exec_command=MagicMock(return_value=(0, '', '')))
        action_base._connection._shell = MagicMock(append_command=MagicMock(return_value=('JOINED CMD')))

        play_context.become = True
        play_context.become_user = play_context.remote_user = '******'
        play_context.make_become_cmd = MagicMock(return_value='CMD')

        action_base._low_level_execute_command('ECHO', sudoable=True)
        play_context.make_become_cmd.assert_not_called()

        play_context.remote_user = '******'
        action_base._low_level_execute_command('ECHO', sudoable=True, executable='/bin/csh')
        play_context.make_become_cmd.assert_called_once_with("ECHO", executable='/bin/csh')

        play_context.make_become_cmd.reset_mock()

        become_allow_same_user = C.BECOME_ALLOW_SAME_USER
        C.BECOME_ALLOW_SAME_USER = True
        try:
            play_context.remote_user = '******'
            action_base._low_level_execute_command('ECHO SAME', sudoable=True)
            play_context.make_become_cmd.assert_called_once_with("ECHO SAME", executable=None)
        finally:
            C.BECOME_ALLOW_SAME_USER = become_allow_same_user
    def test_sudo_only_if_user_differs(self):
        play_context = PlayContext()
        action_base = ActionBase(None, None, play_context, None, None, None)
        action_base._connection = Mock(exec_command=Mock(return_value=(0, '', '')))

        play_context.become = True
        play_context.become_user = play_context.remote_user = '******'
        play_context.make_become_cmd = Mock(return_value='CMD')

        action_base._low_level_execute_command('ECHO', sudoable=True)
        play_context.make_become_cmd.assert_not_called()

        play_context.remote_user = '******'
        action_base._low_level_execute_command('ECHO', sudoable=True)
        play_context.make_become_cmd.assert_called_once_with('ECHO', executable=None)

        play_context.make_become_cmd.reset_mock()

        become_allow_same_user = C.BECOME_ALLOW_SAME_USER
        C.BECOME_ALLOW_SAME_USER = True
        try:
            play_context.remote_user = '******'
            action_base._low_level_execute_command('ECHO SAME', sudoable=True)
            play_context.make_become_cmd.assert_called_once_with('ECHO SAME', executable=None)
        finally:
            C.BECOME_ALLOW_SAME_USER = become_allow_same_user
Example #3
0
    def test_action_base__make_tmp_path(self):
        # create our fake task
        mock_task = MagicMock()

        def get_shell_opt(opt):

            ret = None
            if opt == 'admin_users':
                ret = ['root', 'toor', 'Administrator']
            elif opt == 'remote_tmp':
                ret = '~/.ansible/tmp'

            return ret

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()
        mock_connection.transport = 'ssh'
        mock_connection._shell.mkdtemp.return_value = 'mkdir command'
        mock_connection._shell.join_path.side_effect = os.path.join
        mock_connection._shell.get_option = get_shell_opt
        mock_connection._shell.HOMES_RE = re.compile(r'(\'|\")?(~|\$HOME)(.*)')

        # we're using a real play context here
        play_context = PlayContext()
        play_context.become = True
        play_context.become_user = '******'

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        action_base._low_level_execute_command = MagicMock()
        action_base._low_level_execute_command.return_value = dict(rc=0, stdout='/some/path')
        self.assertEqual(action_base._make_tmp_path('root'), '/some/path/')

        # empty path fails
        action_base._low_level_execute_command.return_value = dict(rc=0, stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # authentication failure
        action_base._low_level_execute_command.return_value = dict(rc=5, stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # ssh error
        action_base._low_level_execute_command.return_value = dict(rc=255, stdout='', stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        play_context.verbosity = 5
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # general error
        action_base._low_level_execute_command.return_value = dict(rc=1, stdout='some stuff here', stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        action_base._low_level_execute_command.return_value = dict(rc=1, stdout='some stuff here', stderr='No space left on device')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
    def test_play_context(self):
        (options, args) = self._parser.parse_args(['-vv', '--check'])
        play_context = PlayContext(options=options)
        self.assertEqual(play_context.connection, 'smart')
        self.assertEqual(play_context.remote_addr, None)
        self.assertEqual(play_context.remote_user, pwd.getpwuid(os.geteuid())[0])
        self.assertEqual(play_context.password, '')
        self.assertEqual(play_context.port, None)
        self.assertEqual(play_context.private_key_file, C.DEFAULT_PRIVATE_KEY_FILE)
        self.assertEqual(play_context.timeout, C.DEFAULT_TIMEOUT)
        self.assertEqual(play_context.shell, None)
        self.assertEqual(play_context.verbosity, 2)
        self.assertEqual(play_context.check_mode, True)
        self.assertEqual(play_context.no_log, None)

        mock_play = MagicMock()
        mock_play.connection    = 'mock'
        mock_play.remote_user   = '******'
        mock_play.port          = 1234
        mock_play.become        = True
        mock_play.become_method = 'mock'
        mock_play.become_user   = '******'
        mock_play.no_log        = True

        play_context = PlayContext(play=mock_play, options=options)
        self.assertEqual(play_context.connection, 'mock')
        self.assertEqual(play_context.remote_user, 'mock')
        self.assertEqual(play_context.password, '')
        self.assertEqual(play_context.port, 1234)
        self.assertEqual(play_context.no_log, True)
        self.assertEqual(play_context.become, True)
        self.assertEqual(play_context.become_method, "mock")
        self.assertEqual(play_context.become_user, "mockroot")

        mock_task = MagicMock()
        mock_task.connection    = 'mocktask'
        mock_task.remote_user   = '******'
        mock_task.become        = True
        mock_task.become_method = 'mocktask'
        mock_task.become_user   = '******'
        mock_task.become_pass   = '******'
        mock_task.no_log        = False

        all_vars = dict(
            ansible_connection = 'mock_inventory',
            ansible_ssh_port = 4321,
        )

        play_context = PlayContext(play=mock_play, options=options)
        play_context = play_context.set_task_and_variable_override(task=mock_task, variables=all_vars)
        self.assertEqual(play_context.connection, 'mock_inventory')
        self.assertEqual(play_context.remote_user, 'mocktask')
        self.assertEqual(play_context.port, 4321)
        self.assertEqual(play_context.no_log, False)
        self.assertEqual(play_context.become, True)
        self.assertEqual(play_context.become_method, "mocktask")
        self.assertEqual(play_context.become_user, "mocktaskroot")
        self.assertEqual(play_context.become_pass, "mocktaskpass")
Example #5
0
    def test_network_cli__invalid_os(self, mocked_super):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = network_cli.Connection(pc, new_stdin)
        conn.ssh = MagicMock()
        conn.receive = MagicMock()
        conn._terminal = MagicMock()
        pc.network_os = None
        self.assertRaises(AnsibleConnectionFailure, conn._connect)
Example #6
0
    def test_action_base__make_tmp_path(self):
        # create our fake task
        mock_task = MagicMock()

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()
        mock_connection.transport = 'ssh'
        mock_connection._shell.mkdtemp.return_value = 'mkdir command'
        mock_connection._shell.join_path.side_effect = os.path.join

        # we're using a real play context here
        play_context = PlayContext()
        play_context.become = True
        play_context.become_user = '******'

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        action_base._low_level_execute_command = MagicMock()
        action_base._low_level_execute_command.return_value = dict(rc=0, stdout='/some/path')
        self.assertEqual(action_base._make_tmp_path('root'), '/some/path/')

        # empty path fails
        action_base._low_level_execute_command.return_value = dict(rc=0, stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # authentication failure
        action_base._low_level_execute_command.return_value = dict(rc=5, stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # ssh error
        action_base._low_level_execute_command.return_value = dict(rc=255, stdout='', stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        play_context.verbosity = 5
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # general error
        action_base._low_level_execute_command.return_value = dict(rc=1, stdout='some stuff here', stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        action_base._low_level_execute_command.return_value = dict(rc=1, stdout='some stuff here', stderr='No space left on device')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
Example #7
0
    def update_play_context(self, pc_data):
        """Updates the play context information for the connection"""
        pc_data = to_bytes(pc_data)
        if PY3:
            pc_data = cPickle.loads(pc_data, encoding='bytes')
        else:
            pc_data = cPickle.loads(pc_data)
        play_context = PlayContext()
        play_context.deserialize(pc_data)

        messages = ['updating play_context for connection']
        if self._play_context.become is False and play_context.become is True:
            auth_pass = play_context.become_pass
            self._terminal.on_become(passwd=auth_pass)
            messages.append('authorizing connection')

        elif self._play_context.become is True and not play_context.become:
            self._terminal.on_unbecome()
            messages.append('deauthorizing connection')

        self._play_context = play_context
        return messages
Example #8
0
    def test_network_cli__connect(self, mocked_super, mocked_terminal_loader):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = network_cli.Connection(pc, new_stdin)
        conn.ssh = None

        self.assertRaises(AnsibleConnectionFailure, conn._connect)
        mocked_terminal_loader.all.assert_called_with(class_only=True)

        mocked_terminal_loader.reset_mock()
        mocked_terminal_loader.get.return_value = None

        pc.network_os = 'invalid'
        self.assertRaises(AnsibleConnectionFailure, conn._connect)
        self.assertFalse(mocked_terminal_loader.all.called)

        mocked_terminal_loader.reset_mock()
        mocked_terminal_loader.get.return_value = 'valid'

        conn._connect()
        self.assertEqual(conn._terminal, 'valid')
Example #9
0
    def test_network_cli__connect(self, mocked_super, mocked_terminal_loader):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = network_cli.Connection(pc, new_stdin)
        pc.network_os = 'ios'

        conn.ssh = MagicMock()
        conn.receive = MagicMock()
        conn._terminal = MagicMock()

        conn._connect()
        self.assertTrue(conn._terminal.on_open_shell.called)
        self.assertFalse(conn._terminal.on_become.called)

        conn._play_context.become = True
        conn._play_context.become_method = 'enable'
        conn._play_context.become_pass = '******'
        conn._connected = False

        conn._connect()
        conn._terminal.on_become.assert_called_with(passwd='password')
Example #10
0
    def test_plugins_connection_ssh__examine_output(self):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = ssh.Connection(pc, new_stdin)

        conn.check_password_prompt    = MagicMock()
        conn.check_become_success     = MagicMock()
        conn.check_incorrect_password = MagicMock()
        conn.check_missing_password   = MagicMock()

        def _check_password_prompt(line):
            if b'foo' in line:
                return True
            return False

        def _check_become_success(line):
            if b'BECOME-SUCCESS-abcdefghijklmnopqrstuvxyz' in line:
                return True
            return False

        def _check_incorrect_password(line):
            if b'incorrect password' in line:
                return True
            return False

        def _check_missing_password(line):
            if b'bad password' in line:
                return True
            return False

        conn.check_password_prompt.side_effect    = _check_password_prompt
        conn.check_become_success.side_effect     = _check_become_success
        conn.check_incorrect_password.side_effect = _check_incorrect_password
        conn.check_missing_password.side_effect   = _check_missing_password

        # test examining output for prompt
        conn._flags = dict(
            become_prompt = False,
            become_success = False,
            become_error = False,
            become_nopasswd_error = False,
        )

        pc.prompt = True
        output, unprocessed = conn._examine_output(u'source', u'state', b'line 1\nline 2\nfoo\nline 3\nthis should be the remainder', False)
        self.assertEqual(output, b'line 1\nline 2\nline 3\n')
        self.assertEqual(unprocessed, b'this should be the remainder')
        self.assertTrue(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for become prompt
        conn._flags = dict(
            become_prompt = False,
            become_success = False,
            become_error = False,
            become_nopasswd_error = False,
        )

        pc.prompt = False
        pc.success_key = u'BECOME-SUCCESS-abcdefghijklmnopqrstuvxyz'
        output, unprocessed = conn._examine_output(u'source', u'state', b'line 1\nline 2\nBECOME-SUCCESS-abcdefghijklmnopqrstuvxyz\nline 3\n', False)
        self.assertEqual(output, b'line 1\nline 2\nline 3\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertTrue(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for become failure
        conn._flags = dict(
            become_prompt = False,
            become_success = False,
            become_error = False,
            become_nopasswd_error = False,
        )

        pc.prompt = False
        pc.success_key = None
        output, unprocessed = conn._examine_output(u'source', u'state', b'line 1\nline 2\nincorrect password\n', True)
        self.assertEqual(output, b'line 1\nline 2\nincorrect password\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertTrue(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for missing password
        conn._flags = dict(
            become_prompt = False,
            become_success = False,
            become_error = False,
            become_nopasswd_error = False,
        )

        pc.prompt = False
        pc.success_key = None
        output, unprocessed = conn._examine_output(u'source', u'state', b'line 1\nbad password\n', True)
        self.assertEqual(output, b'line 1\nbad password\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertTrue(conn._flags['become_nopasswd_error'])
Example #11
0
    def test_action_base__execute_module(self):
        # create our fake task
        mock_task = MagicMock()
        mock_task.action = 'copy'
        mock_task.args = dict(a=1, b=2, c=3)

        # create a mock connection, so we don't actually try and connect to things
        def build_module_command(env_string,
                                 shebang,
                                 cmd,
                                 arg_path=None,
                                 rm_tmp=None):
            to_run = [env_string, cmd]
            if arg_path:
                to_run.append(arg_path)
            if rm_tmp:
                to_run.append(rm_tmp)
            return " ".join(to_run)

        mock_connection = MagicMock()
        mock_connection.build_module_command.side_effect = build_module_command
        mock_connection._shell.join_path.side_effect = os.path.join

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        # fake a lot of methods as we test those elsewhere
        action_base._configure_module = MagicMock()
        action_base._supports_check_mode = MagicMock()
        action_base._late_needs_tmp_path = MagicMock()
        action_base._make_tmp_path = MagicMock()
        action_base._transfer_data = MagicMock()
        action_base._compute_environment_string = MagicMock()
        action_base._low_level_execute_command = MagicMock()
        action_base._fixup_perms = MagicMock()

        action_base._configure_module.return_value = (
            'new', '#!/usr/bin/python', 'this is the module data', 'path')
        action_base._late_needs_tmp_path.return_value = False
        action_base._compute_environment_string.return_value = ''
        action_base._connection.has_pipelining = True
        action_base._low_level_execute_command.return_value = dict(
            stdout='{"rc": 0, "stdout": "ok"}')
        self.assertEqual(
            action_base._execute_module(module_name=None, module_args=None),
            dict(rc=0, stdout="ok", stdout_lines=['ok']))
        self.assertEqual(
            action_base._execute_module(module_name='foo',
                                        module_args=dict(z=9, y=8, x=7),
                                        task_vars=dict(a=1)),
            dict(rc=0, stdout="ok", stdout_lines=['ok']))

        # test with needing/removing a remote tmp path
        action_base._configure_module.return_value = (
            'old', '#!/usr/bin/python', 'this is the module data', 'path')
        action_base._late_needs_tmp_path.return_value = True
        action_base._make_tmp_path.return_value = '/the/tmp/path'
        self.assertEqual(action_base._execute_module(),
                         dict(rc=0, stdout="ok", stdout_lines=['ok']))

        action_base._configure_module.return_value = (
            'non_native_want_json', '#!/usr/bin/python',
            'this is the module data', 'path')
        self.assertEqual(action_base._execute_module(),
                         dict(rc=0, stdout="ok", stdout_lines=['ok']))

        play_context.become = True
        play_context.become_user = '******'
        self.assertEqual(action_base._execute_module(),
                         dict(rc=0, stdout="ok", stdout_lines=['ok']))

        # test an invalid shebang return
        action_base._configure_module.return_value = (
            'new', '', 'this is the module data', 'path')
        action_base._late_needs_tmp_path.return_value = False
        self.assertRaises(AnsibleError, action_base._execute_module)

        # test with check mode enabled, once with support for check
        # mode and once with support disabled to raise an error
        play_context.check_mode = True
        action_base._configure_module.return_value = (
            'new', '#!/usr/bin/python', 'this is the module data', 'path')
        self.assertEqual(action_base._execute_module(),
                         dict(rc=0, stdout="ok", stdout_lines=['ok']))
        action_base._supports_check_mode = False
        self.assertRaises(AnsibleError, action_base._execute_module)
Example #12
0
    def test_action_base__configure_module(self):
        fake_loader = DictDataLoader({})

        # create our fake task
        mock_task = MagicMock()
        mock_task.action = "copy"

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()

        # create a mock shared loader object
        def mock_find_plugin(name, options):
            if name == 'badmodule':
                return None
            elif '.ps1' in options:
                return '/fake/path/to/%s.ps1' % name
            else:
                return '/fake/path/to/%s' % name

        mock_module_loader = MagicMock()
        mock_module_loader.find_plugin.side_effect = mock_find_plugin
        mock_shared_obj_loader = MagicMock()
        mock_shared_obj_loader.module_loader = mock_module_loader

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=fake_loader,
            templar=None,
            shared_loader_obj=mock_shared_obj_loader,
        )

        # test python module formatting
        with patch.object(
                builtins, 'open',
                mock_open(read_data=to_bytes(python_module_replacers.strip(),
                                             encoding='utf-8'))) as m:
            with patch.object(os, 'rename') as m:
                mock_task.args = dict(a=1, foo='fö〩')
                mock_connection.module_implementation_preferences = ('', )
                (style, shebang, data,
                 path) = action_base._configure_module(mock_task.action,
                                                       mock_task.args)
                self.assertEqual(style, "new")
                self.assertEqual(shebang, b"#!/usr/bin/python")

                # test module not found
                self.assertRaises(AnsibleError, action_base._configure_module,
                                  'badmodule', mock_task.args)

        # test powershell module formatting
        with patch.object(
                builtins, 'open',
                mock_open(
                    read_data=to_bytes(powershell_module_replacers.strip(),
                                       encoding='utf-8'))) as m:
            mock_task.action = 'win_copy'
            mock_task.args = dict(b=2)
            mock_connection.module_implementation_preferences = ('.ps1', )
            (style, shebang, data,
             path) = action_base._configure_module('stat', mock_task.args)
            self.assertEqual(style, "new")
            self.assertEqual(shebang, None)

            # test module not found
            self.assertRaises(AnsibleError, action_base._configure_module,
                              'badmodule', mock_task.args)
Example #13
0
def main():
    """ Called to initiate the connect to the remote device
    """
    rc = 0
    result = {}
    messages = list()
    socket_path = None

    # Need stdin as a byte stream
    if PY3:
        stdin = sys.stdin.buffer
    else:
        stdin = sys.stdin

    # Note: update the below log capture code after Display.display() is refactored.
    saved_stdout = sys.stdout
    sys.stdout = StringIO()

    try:
        # read the play context data via stdin, which means depickling it
        vars_data = read_stream(stdin)
        init_data = read_stream(stdin)

        if PY3:
            pc_data = cPickle.loads(init_data, encoding='bytes')
            variables = cPickle.loads(vars_data, encoding='bytes')
        else:
            pc_data = cPickle.loads(init_data)
            variables = cPickle.loads(vars_data)

        play_context = PlayContext()
        play_context.deserialize(pc_data)
        display.verbosity = play_context.verbosity

    except Exception as e:
        rc = 1
        result.update({
            'error': to_text(e),
            'exception': traceback.format_exc()
        })

    if rc == 0:
        ssh = connection_loader.get('ssh', class_only=True)
        ansible_playbook_pid = sys.argv[1]
        task_uuid = sys.argv[2]
        cp = ssh._create_control_path(play_context.remote_addr,
                                      play_context.port,
                                      play_context.remote_user,
                                      play_context.connection,
                                      ansible_playbook_pid)
        # create the persistent connection dir if need be and create the paths
        # which we will be using later
        tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR)
        makedirs_safe(tmp_path)

        socket_path = unfrackpath(cp % dict(directory=tmp_path))
        lock_path = unfrackpath("%s/.ansible_pc_lock_%s" %
                                os.path.split(socket_path))

        with file_lock(lock_path):
            if not os.path.exists(socket_path):
                messages.append(
                    ('vvvv',
                     'local domain socket does not exist, starting it'))
                original_path = os.getcwd()
                r, w = os.pipe()
                pid = fork_process()

                if pid == 0:
                    try:
                        os.close(r)
                        wfd = os.fdopen(w, 'w')
                        process = ConnectionProcess(wfd, play_context,
                                                    socket_path, original_path,
                                                    task_uuid,
                                                    ansible_playbook_pid)
                        process.start(variables)
                    except Exception:
                        messages.append(('error', traceback.format_exc()))
                        rc = 1

                    if rc == 0:
                        process.run()
                    else:
                        process.shutdown()

                    sys.exit(rc)

                else:
                    os.close(w)
                    rfd = os.fdopen(r, 'r')
                    data = json.loads(rfd.read(), cls=AnsibleJSONDecoder)
                    messages.extend(data.pop('messages'))
                    result.update(data)

            else:
                messages.append(
                    ('vvvv', 'found existing local domain socket, using it!'))
                conn = Connection(socket_path)
                conn.set_options(var_options=variables)
                pc_data = to_text(init_data)
                try:
                    conn.update_play_context(pc_data)
                    conn.set_check_prompt(task_uuid)
                except Exception as exc:
                    # Only network_cli has update_play context and set_check_prompt, so missing this is
                    # not fatal e.g. netconf
                    if isinstance(exc, ConnectionError) and getattr(
                            exc, 'code', None) == -32601:
                        pass
                    else:
                        result.update({
                            'error': to_text(exc),
                            'exception': traceback.format_exc()
                        })

    if os.path.exists(socket_path):
        messages.extend(Connection(socket_path).pop_messages())
    messages.append(('vvvv', sys.stdout.getvalue()))
    result.update({'messages': messages, 'socket_path': socket_path})

    sys.stdout = saved_stdout
    if 'exception' in result:
        rc = 1
        sys.stderr.write(json.dumps(result, cls=AnsibleJSONEncoder))
    else:
        rc = 0
        sys.stdout.write(json.dumps(result, cls=AnsibleJSONEncoder))

    sys.exit(rc)
Example #14
0
    def test_network_cli__no_os(self):
        pc = PlayContext()
        pc.network_os = None

        self.assertRaises(AnsibleConnectionFailure, connection_loader.get, 'network_cli', pc, '/dev/null')
Example #15
0
    def test_play_context(self):
        (options, args) = self._parser.parse_args(['-vv', '--check'])
        play_context = PlayContext(options=options)
        self.assertEqual(play_context.connection, 'smart')
        self.assertEqual(play_context.remote_addr, None)
        self.assertEqual(play_context.remote_user, None)
        self.assertEqual(play_context.password, '')
        self.assertEqual(play_context.port, None)
        self.assertEqual(play_context.private_key_file,
                         C.DEFAULT_PRIVATE_KEY_FILE)
        self.assertEqual(play_context.timeout, C.DEFAULT_TIMEOUT)
        self.assertEqual(play_context.shell, None)
        self.assertEqual(play_context.verbosity, 2)
        self.assertEqual(play_context.check_mode, True)
        self.assertEqual(play_context.no_log, None)

        mock_play = MagicMock()
        mock_play.connection = 'mock'
        mock_play.remote_user = '******'
        mock_play.port = 1234
        mock_play.become = True
        mock_play.become_method = 'mock'
        mock_play.become_user = '******'
        mock_play.no_log = True

        play_context = PlayContext(play=mock_play, options=options)
        self.assertEqual(play_context.connection, 'mock')
        self.assertEqual(play_context.remote_user, 'mock')
        self.assertEqual(play_context.password, '')
        self.assertEqual(play_context.port, 1234)
        self.assertEqual(play_context.become, True)
        self.assertEqual(play_context.become_method, "mock")
        self.assertEqual(play_context.become_user, "mockroot")

        mock_task = MagicMock()
        mock_task.connection = 'mocktask'
        mock_task.remote_user = '******'
        mock_task.no_log = mock_play.no_log
        mock_task.become = True
        mock_task.become_method = 'mocktask'
        mock_task.become_user = '******'
        mock_task.become_pass = '******'
        mock_task._local_action = False
        mock_task.delegate_to = None

        all_vars = dict(
            ansible_connection='mock_inventory',
            ansible_ssh_port=4321,
        )

        mock_templar = MagicMock()

        play_context = PlayContext(play=mock_play, options=options)
        play_context = play_context.set_task_and_variable_override(
            task=mock_task, variables=all_vars, templar=mock_templar)
        self.assertEqual(play_context.connection, 'mock_inventory')
        self.assertEqual(play_context.remote_user, 'mocktask')
        self.assertEqual(play_context.port, 4321)
        self.assertEqual(play_context.no_log, True)
        self.assertEqual(play_context.become, True)
        self.assertEqual(play_context.become_method, "mocktask")
        self.assertEqual(play_context.become_user, "mocktaskroot")
        self.assertEqual(play_context.become_pass, "mocktaskpass")

        mock_task.no_log = False
        play_context = play_context.set_task_and_variable_override(
            task=mock_task, variables=all_vars, templar=mock_templar)
        self.assertEqual(play_context.no_log, False)
Example #16
0
    def test_action_base__execute_module(self):
        # create our fake task
        mock_task = MagicMock()
        mock_task.action = 'copy'
        mock_task.args = dict(a=1, b=2, c=3)

        # create a mock connection, so we don't actually try and connect to things
        def build_module_command(env_string, shebang, cmd, arg_path=None, rm_tmp=None):
            to_run = [env_string, cmd]
            if arg_path:
                to_run.append(arg_path)
            if rm_tmp:
                to_run.append(rm_tmp)
            return " ".join(to_run)

        mock_connection = MagicMock()
        mock_connection.build_module_command.side_effect = build_module_command
        mock_connection._shell.get_remote_filename.return_value = 'copy.py'
        mock_connection._shell.join_path.side_effect = os.path.join

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        # fake a lot of methods as we test those elsewhere
        action_base._configure_module = MagicMock()
        action_base._supports_check_mode = MagicMock()
        action_base._is_pipelining_enabled = MagicMock()
        action_base._make_tmp_path = MagicMock()
        action_base._transfer_data = MagicMock()
        action_base._compute_environment_string = MagicMock()
        action_base._low_level_execute_command = MagicMock()
        action_base._fixup_perms2 = MagicMock()

        action_base._configure_module.return_value = ('new', '#!/usr/bin/python', 'this is the module data', 'path')
        action_base._is_pipelining_enabled.return_value = False
        action_base._compute_environment_string.return_value = ''
        action_base._connection.has_pipelining = False
        action_base._make_tmp_path.return_value = '/the/tmp/path'
        action_base._low_level_execute_command.return_value = dict(stdout='{"rc": 0, "stdout": "ok"}')
        self.assertEqual(action_base._execute_module(module_name=None, module_args=None), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))
        self.assertEqual(
            action_base._execute_module(
                module_name='foo',
                module_args=dict(z=9, y=8, x=7),
                task_vars=dict(a=1)
            ),
            dict(
                _ansible_parsed=True,
                rc=0,
                stdout="ok",
                stdout_lines=['ok'],
            )
        )

        # test with needing/removing a remote tmp path
        action_base._configure_module.return_value = ('old', '#!/usr/bin/python', 'this is the module data', 'path')
        action_base._is_pipelining_enabled.return_value = False
        action_base._make_tmp_path.return_value = '/the/tmp/path'
        self.assertEqual(action_base._execute_module(), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))

        action_base._configure_module.return_value = ('non_native_want_json', '#!/usr/bin/python', 'this is the module data', 'path')
        self.assertEqual(action_base._execute_module(), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))

        play_context.become = True
        play_context.become_user = '******'
        self.assertEqual(action_base._execute_module(), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))

        # test an invalid shebang return
        action_base._configure_module.return_value = ('new', '', 'this is the module data', 'path')
        action_base._is_pipelining_enabled.return_value = False
        action_base._make_tmp_path.return_value = '/the/tmp/path'
        self.assertRaises(AnsibleError, action_base._execute_module)

        # test with check mode enabled, once with support for check
        # mode and once with support disabled to raise an error
        play_context.check_mode = True
        action_base._configure_module.return_value = ('new', '#!/usr/bin/python', 'this is the module data', 'path')
        self.assertEqual(action_base._execute_module(), dict(_ansible_parsed=True, rc=0, stdout="ok", stdout_lines=['ok']))
        action_base._supports_check_mode = False
        self.assertRaises(AnsibleError, action_base._execute_module)
Example #17
0
    def test_play_iterator(self):
        #import epdb; epdb.st()
        fake_loader = DictDataLoader({
            "test_play.yml":
            """
            - hosts: all
              gather_facts: false
              roles:
              - test_role
              pre_tasks:
              - debug: msg="this is a pre_task"
              tasks:
              - debug: msg="this is a regular task"
              - block:
                - debug: msg="this is a block task"
                - block:
                  - debug: msg="this is a sub-block in a block"
                rescue:
                - debug: msg="this is a rescue task"
                - block:
                  - debug: msg="this is a sub-block in a rescue"
                always:
                - debug: msg="this is an always task"
                - block:
                  - debug: msg="this is a sub-block in an always"
              post_tasks:
              - debug: msg="this is a post_task"
            """,
            '/etc/ansible/roles/test_role/tasks/main.yml':
            """
            - debug: msg="this is a role task"
            """,
        })

        mock_var_manager = MagicMock()
        mock_var_manager._fact_cache = dict()
        mock_var_manager.get_vars.return_value = dict()

        p = Playbook.load('test_play.yml',
                          loader=fake_loader,
                          variable_manager=mock_var_manager)

        hosts = []
        for i in range(0, 10):
            host = MagicMock()
            host.name = host.get_name.return_value = 'host%02d' % i
            hosts.append(host)

        mock_var_manager._fact_cache['host00'] = dict()

        inventory = MagicMock()
        inventory.get_hosts.return_value = hosts
        inventory.filter_hosts.return_value = hosts

        play_context = PlayContext(play=p._entries[0])

        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        # lookup up an original task
        target_task = p._entries[0].tasks[0].block[0]
        task_copy = target_task.copy(exclude_block=True)
        found_task = itr.get_original_task(hosts[0], task_copy)
        self.assertEqual(target_task, found_task)

        bad_task = Task()
        found_task = itr.get_original_task(hosts[0], bad_task)
        self.assertIsNone(found_task)

        # pre task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # role task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertIsNotNone(task._role)
        # regular play task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertIsNone(task._role)
        # block task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg="this is a block task"))
        # sub-block task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg="this is a sub-block in a block"))
        # mark the host failed
        itr.mark_host_failed(hosts[0])
        # block rescue task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg="this is a rescue task"))
        # sub-block rescue task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args,
                         dict(msg="this is a sub-block in a rescue"))
        # block always task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg="this is an always task"))
        # sub-block always task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args,
                         dict(msg="this is a sub-block in an always"))
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # post task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # end of iteration
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNone(task)

        # host 0 shouldn't be in the failed hosts, as the error
        # was handled by a rescue block
        failed_hosts = itr.get_failed_hosts()
        self.assertNotIn(hosts[0], failed_hosts)
Example #18
0
    def test_play_iterator_add_tasks(self):
        fake_loader = DictDataLoader({
            'test_play.yml':
            """
            - hosts: all
              gather_facts: no
              tasks:
              - debug: msg="dummy task"
            """,
        })

        mock_var_manager = MagicMock()
        mock_var_manager._fact_cache = dict()
        mock_var_manager.get_vars.return_value = dict()

        p = Playbook.load('test_play.yml',
                          loader=fake_loader,
                          variable_manager=mock_var_manager)

        hosts = []
        for i in range(0, 10):
            host = MagicMock()
            host.name = host.get_name.return_value = 'host%02d' % i
            hosts.append(host)

        inventory = MagicMock()
        inventory.get_hosts.return_value = hosts
        inventory.filter_hosts.return_value = hosts

        play_context = PlayContext(play=p._entries[0])

        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        # test the high-level add_tasks() method
        s = HostState(blocks=[0, 1, 2])
        itr._insert_tasks_into_state = MagicMock(return_value=s)
        itr.add_tasks(hosts[0], [3, 4, 5])
        self.assertEqual(itr._host_states[hosts[0].name], s)

        # now actually test the lower-level method that does the work
        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        # iterate past first task
        _, task = itr.get_next_task_for_host(hosts[0])
        while (task and task.action != 'debug'):
            _, task = itr.get_next_task_for_host(hosts[0])

        if task is None:
            raise Exception(
                "iterated past end of play while looking for place to insert tasks"
            )

        # get the current host state and copy it so we can mutate it
        s = itr.get_host_state(hosts[0])
        s_copy = s.copy()

        # assert with an empty task list, or if we're in a failed state, we simply return the state as-is
        res_state = itr._insert_tasks_into_state(s_copy, task_list=[])
        self.assertEqual(res_state, s_copy)

        s_copy.fail_state = itr.FAILED_TASKS
        res_state = itr._insert_tasks_into_state(s_copy,
                                                 task_list=[MagicMock()])
        self.assertEqual(res_state, s_copy)

        # but if we've failed with a rescue/always block
        mock_task = MagicMock()
        s_copy.run_state = itr.ITERATING_RESCUE
        res_state = itr._insert_tasks_into_state(s_copy, task_list=[mock_task])
        self.assertEqual(res_state, s_copy)
        self.assertIn(mock_task, res_state._blocks[res_state.cur_block].rescue)
        itr._host_states[hosts[0].name] = res_state
        (next_state, next_task) = itr.get_next_task_for_host(hosts[0],
                                                             peek=True)
        self.assertEqual(next_task, mock_task)
        itr._host_states[hosts[0].name] = s

        # test a regular insertion
        s_copy = s.copy()
        res_state = itr._insert_tasks_into_state(s_copy,
                                                 task_list=[MagicMock()])
Example #19
0
    def test_play_iterator_nested_blocks(self):
        fake_loader = DictDataLoader({
            "test_play.yml":
            """
            - hosts: all
              gather_facts: false
              tasks:
              - block:
                - block:
                  - block:
                    - block:
                      - block:
                        - debug: msg="this is the first task"
                        - ping:
                      rescue:
                      - block:
                        - block:
                          - block:
                            - block:
                              - debug: msg="this is the rescue task"
                  always:
                  - block:
                    - block:
                      - block:
                        - block:
                          - debug: msg="this is the always task"
            """,
        })

        mock_var_manager = MagicMock()
        mock_var_manager._fact_cache = dict()
        mock_var_manager.get_vars.return_value = dict()

        p = Playbook.load('test_play.yml',
                          loader=fake_loader,
                          variable_manager=mock_var_manager)

        hosts = []
        for i in range(0, 10):
            host = MagicMock()
            host.name = host.get_name.return_value = 'host%02d' % i
            hosts.append(host)

        inventory = MagicMock()
        inventory.get_hosts.return_value = hosts
        inventory.filter_hosts.return_value = hosts

        play_context = PlayContext(play=p._entries[0])

        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        self.assertEqual(task.args, dict(_raw_params='flush_handlers'))
        # get the first task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg='this is the first task'))
        # fail the host
        itr.mark_host_failed(hosts[0])
        # get the resuce task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg='this is the rescue task'))
        # get the always task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertEqual(task.args, dict(msg='this is the always task'))
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        self.assertEqual(task.args, dict(_raw_params='flush_handlers'))
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        self.assertEqual(task.args, dict(_raw_params='flush_handlers'))
        # end of iteration
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNone(task)
    def run(self, tmp=None, task_vars=None):

        if task_vars is None:
            task_vars = dict()

        results = super(ActionModule, self).run(tmp, task_vars)

        args = self._task.args.copy()

        dest = args.pop('dest',None)
        mode = args.pop('mode',None)
        force = args.pop('force',True)
        become = self._play_context.become
        become_method = self._play_context.become_method


        old_connection = self._connection
        self._connection = self._shared_loader_obj.connection_loader.get('local',PlayContext(),old_connection._new_stdin)
        self._play_context.become = False
        self._play_context.become_method = None

        results = merge_hash(
            results,
            # executes hashivault_read module on localhost
            self._execute_module(module_name='hashivault_read', tmp=tmp, task_vars=task_vars, module_args=args)
        )

        if 'failed' in results and results['failed'] == True:
            return results

        content = results.pop('value',None)

        if content == None:
            results['failed'] = True
            results['msg'] = 'Could not find file `%s` in secret `%s`'%(args['key'],args['secret'])
            return(results)


        #write to temp file on ansible host to copy to remote host
        local_tmp = tempfile.NamedTemporaryFile(delete=False)
        local_tmp.write(content.decode('base64'))
        local_tmp.close()

        new_module_args = {
            'dest':dest,
            'src':local_tmp.name,
            'force':force,
            'mode':mode
        }

        self._update_module_args('copy',new_module_args,task_vars)

        # `copy` module uses an action plugin, so we have to execute
        # the plugin instead of directly executing the module
        copy_action = self._get_copy_action_plugin(old_connection)
        copy_action._task.args = new_module_args
        copy_action._play_context.become = become
        copy_action._play_context.become_method = become_method

        results = merge_hash(
            results,
            # executes copy action plugin/module on remote host
            copy_action.run(task_vars=task_vars)
        )

        #remove temp file
        os.unlink(local_tmp.name)

        if force == False and results['changed'] == False:
            results['failed'] = True
            results['msg'] = 'File %s already exists. Use `force: true` to overwrite'%dest

        return(results)
Example #21
0
    def test_plugins_connection_ssh_put_file(self, mock_ospe):
        pc = PlayContext()
        new_stdin = StringIO()
        conn = ssh.Connection(pc, new_stdin)
        conn._build_command = MagicMock()
        conn._run = MagicMock()

        mock_ospe.return_value = True
        conn._build_command.return_value = 'some command to run'
        conn._run.return_value = (0, '', '')
        conn.host = "some_host"

        # Test with C.DEFAULT_SCP_IF_SSH set to smart
        # Test when SFTP works
        C.DEFAULT_SCP_IF_SSH = 'smart'
        expected_in_data = b' '.join(
            (b'put', to_bytes(shlex_quote('/path/to/in/file')),
             to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n'
        conn.put_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run',
                                     expected_in_data,
                                     checkrc=False)

        # Test when SFTP doesn't work but SCP does
        conn._run.side_effect = [(1, 'stdout', 'some errors'), (0, '', '')]
        conn.put_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run',
                                     None,
                                     checkrc=False)
        conn._run.side_effect = None

        # test with C.DEFAULT_SCP_IF_SSH enabled
        C.DEFAULT_SCP_IF_SSH = True
        conn.put_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run',
                                     None,
                                     checkrc=False)

        conn.put_file(u'/path/to/in/file/with/unicode-fö〩',
                      u'/path/to/dest/file/with/unicode-fö〩')
        conn._run.assert_called_with('some command to run',
                                     None,
                                     checkrc=False)

        # test with C.DEFAULT_SCP_IF_SSH disabled
        C.DEFAULT_SCP_IF_SSH = False
        expected_in_data = b' '.join(
            (b'put', to_bytes(shlex_quote('/path/to/in/file')),
             to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n'
        conn.put_file('/path/to/in/file', '/path/to/dest/file')
        conn._run.assert_called_with('some command to run',
                                     expected_in_data,
                                     checkrc=False)

        expected_in_data = b' '.join(
            (b'put', to_bytes(
                shlex_quote('/path/to/in/file/with/unicode-fö〩')),
             to_bytes(
                 shlex_quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
        conn.put_file(u'/path/to/in/file/with/unicode-fö〩',
                      u'/path/to/dest/file/with/unicode-fö〩')
        conn._run.assert_called_with('some command to run',
                                     expected_in_data,
                                     checkrc=False)

        # test that a non-zero rc raises an error
        conn._run.return_value = (1, 'stdout', 'some errors')
        self.assertRaises(AnsibleError, conn.put_file, '/path/to/bad/file',
                          '/remote/path/to/file')

        # test that a not-found path raises an error
        mock_ospe.return_value = False
        conn._run.return_value = (0, 'stdout', '')
        self.assertRaises(AnsibleFileNotFound, conn.put_file,
                          '/path/to/bad/file', '/remote/path/to/file')
Example #22
0
    def run(self, play):
        '''
        Iterates over the roles/tasks in a play, using the given (or default)
        strategy for queueing tasks. The default is the linear strategy, which
        operates like classic Ansible by keeping all hosts in lock-step with
        a given task (meaning no hosts move on to the next task until all hosts
        are done with the current task).
        '''

        if not self._callbacks_loaded:
            self.load_callbacks()

        all_vars = self._variable_manager.get_vars(play=play)
        templar = Templar(loader=self._loader, variables=all_vars)
        warn_if_reserved(all_vars, templar.environment.globals.keys())

        new_play = play.copy()
        new_play.post_validate(templar)
        new_play.handlers = new_play.compile_roles_handlers() + new_play.handlers

        self.hostvars = HostVars(
            inventory=self._inventory,
            variable_manager=self._variable_manager,
            loader=self._loader,
        )

        play_context = PlayContext(new_play, self.passwords, self._connection_lockfile.fileno())
        if (self._stdout_callback and
                hasattr(self._stdout_callback, 'set_play_context')):
            self._stdout_callback.set_play_context(play_context)

        for callback_plugin in self._callback_plugins:
            if hasattr(callback_plugin, 'set_play_context'):
                callback_plugin.set_play_context(play_context)

        self.send_callback('v2_playbook_on_play_start', new_play)

        # build the iterator
        iterator = PlayIterator(
            inventory=self._inventory,
            play=new_play,
            play_context=play_context,
            variable_manager=self._variable_manager,
            all_vars=all_vars,
            start_at_done=self._start_at_done,
        )

        # adjust to # of workers to configured forks or size of batch, whatever is lower
        self._initialize_processes(min(self._forks, iterator.batch_size))

        # load the specified strategy (or the default linear one)
        strategy = strategy_loader.get(new_play.strategy, self)
        if strategy is None:
            raise AnsibleError("Invalid play strategy specified: %s" % new_play.strategy, obj=play._ds)

        # Because the TQM may survive multiple play runs, we start by marking
        # any hosts as failed in the iterator here which may have been marked
        # as failed in previous runs. Then we clear the internal list of failed
        # hosts so we know what failed this round.
        for host_name in self._failed_hosts.keys():
            host = self._inventory.get_host(host_name)
            iterator.mark_host_failed(host)
        for host_name in self._unreachable_hosts.keys():
            iterator._play._removed_hosts.append(host_name)

        self.clear_failed_hosts()

        # during initialization, the PlayContext will clear the start_at_task
        # field to signal that a matching task was found, so check that here
        # and remember it so we don't try to skip tasks on future plays
        if context.CLIARGS.get('start_at_task') is not None and play_context.start_at_task is None:
            self._start_at_done = True

        # and run the play using the strategy and cleanup on way out
        try:
            play_return = strategy.run(iterator, play_context)
        finally:
            strategy.cleanup()
            self._cleanup_processes()

        # now re-save the hosts that failed from the iterator to our internal list
        for host_name in iterator.get_failed_hosts():
            self._failed_hosts[host_name] = True

        if iterator.end_play:
            raise AnsibleEndPlay(play_return)

        return play_return
    def test_action_base__make_tmp_path(self):
        # create our fake task
        mock_task = MagicMock()

        def get_shell_opt(opt):

            ret = None
            if opt == 'admin_users':
                ret = ['root', 'toor', 'Administrator']
            elif opt == 'remote_tmp':
                ret = '~/.ansible/tmp'

            return ret

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()
        mock_connection.transport = 'ssh'
        mock_connection._shell.mkdtemp.return_value = 'mkdir command'
        mock_connection._shell.join_path.side_effect = os.path.join
        mock_connection._shell.get_option = get_shell_opt
        mock_connection._shell.HOMES_RE = re.compile(r'(\'|\")?(~|\$HOME)(.*)')

        # we're using a real play context here
        play_context = PlayContext()
        play_context.become = True
        play_context.become_user = '******'

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        action_base._low_level_execute_command = MagicMock()
        action_base._low_level_execute_command.return_value = dict(
            rc=0, stdout='/some/path')
        self.assertEqual(action_base._make_tmp_path('root'), '/some/path/')

        # empty path fails
        action_base._low_level_execute_command.return_value = dict(rc=0,
                                                                   stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # authentication failure
        action_base._low_level_execute_command.return_value = dict(rc=5,
                                                                   stdout='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # ssh error
        action_base._low_level_execute_command.return_value = dict(rc=255,
                                                                   stdout='',
                                                                   stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        play_context.verbosity = 5
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')

        # general error
        action_base._low_level_execute_command.return_value = dict(
            rc=1, stdout='some stuff here', stderr='')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
        action_base._low_level_execute_command.return_value = dict(
            rc=1, stdout='some stuff here', stderr='No space left on device')
        self.assertRaises(AnsibleError, action_base._make_tmp_path, 'root')
Example #24
0
    def test_action_base__late_needs_tmp_path(self):
        # create our fake task
        mock_task = MagicMock()

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        # assert no temp path is required because tmp is set
        self.assertFalse(action_base._late_needs_tmp_path("/tmp/foo", "new"))

        # assert no temp path is required when using a new-style module
        # with pipelining supported and enabled with no become method
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = None
        self.assertFalse(action_base._late_needs_tmp_path(None, "new"))

        # assert a temp path is required for each of the following:
        # the module style is not 'new'
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "old"))
        # connection plugin does not support pipelining
        mock_connection.has_pipelining = False
        play_context.pipelining = True
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
        # pipelining is disabled via the play context settings
        mock_connection.has_pipelining = True
        play_context.pipelining = False
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
        # keep remote files is enabled
        # FIXME: implement
        # the become method is 'su'
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = 'su'
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
Example #25
0
def plugin():
    task = FakeTask('openshift_health_check', {'checks': ['fake_check']})
    plugin = ActionModule(task, None, PlayContext(), None, None, None)
    return plugin
Example #26
0
def test_play_context_make_become_cmd(parser):
    (options, args) = parser.parse_args([])
    play_context = PlayContext(options=options)

    default_cmd = "/bin/foo"
    default_exe = "/bin/bash"
    sudo_exe = C.DEFAULT_SUDO_EXE or 'sudo'
    sudo_flags = C.DEFAULT_SUDO_FLAGS
    su_exe = C.DEFAULT_SU_EXE or 'su'
    su_flags = C.DEFAULT_SU_FLAGS or ''
    pbrun_exe = 'pbrun'
    pbrun_flags = ''
    pfexec_exe = 'pfexec'
    pfexec_flags = ''
    doas_exe = 'doas'
    doas_flags = ' -n  -u foo '
    ksu_exe = 'ksu'
    ksu_flags = ''
    dzdo_exe = 'dzdo'

    cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
    assert cmd == default_cmd

    play_context.become = True
    play_context.become_user = '******'

    play_context.become_method = 'sudo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s -u %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags, play_context.become_user,
                                                            default_exe, play_context.success_key, default_cmd))

    play_context.become_pass = '******'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
    assert (cmd == """%s %s -p "%s" -u %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags.replace('-n', ''),
                                                                    play_context.prompt, play_context.become_user, default_exe,
                                                                    play_context.success_key, default_cmd))

    play_context.become_pass = None
    play_context.become_method = 'su'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s  %s -c '%s -c '"'"'echo %s; %s'"'"''""" % (su_exe, play_context.become_user, default_exe,
                                                                    play_context.success_key, default_cmd))

    play_context.become_method = 'pbrun'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == """%s %s -u %s 'echo %s; %s'""" % (pbrun_exe, pbrun_flags, play_context.become_user, play_context.success_key, default_cmd)

    play_context.become_method = 'pfexec'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == '''%s %s "'echo %s; %s'"''' % (pfexec_exe, pfexec_flags, play_context.success_key, default_cmd)

    play_context.become_method = 'doas'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s echo %s && %s %s env ANSIBLE=true %s""" % (doas_exe, doas_flags, play_context.
                                                                       success_key, doas_exe, doas_flags, default_cmd))

    play_context.become_method = 'ksu'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s %s -e %s -c 'echo %s; %s'""" % (ksu_exe, play_context.become_user, ksu_flags,
                                                            default_exe, play_context.success_key, default_cmd))

    play_context.become_method = 'bad'
    with pytest.raises(AnsibleError):
        play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")

    play_context.become_method = 'dzdo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == """%s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, play_context.become_user, default_exe, play_context.success_key, default_cmd)

    play_context.become_pass = '******'
    play_context.become_method = 'dzdo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s -p %s -u %s %s -c 'echo %s; %s'""" % (dzdo_exe, shlex_quote(play_context.prompt),
                                                               play_context.become_user, default_exe,
                                                               play_context.success_key, default_cmd))
Example #27
0
    def test_plugins_connection_ssh_fetch_file(self, mock_sleep):
        pc = PlayContext()
        new_stdin = StringIO()
        conn = connection_loader.get('ssh', pc, new_stdin)
        conn._build_command = MagicMock()
        conn._bare_run = MagicMock()
        conn._load_name = 'ssh'

        conn._build_command.return_value = 'some command to run'
        conn._bare_run.return_value = (0, '', '')
        conn.host = "some_host"

        C.ANSIBLE_SSH_RETRIES = 9

        # Test with C.DEFAULT_SCP_IF_SSH set to smart
        # Test when SFTP works
        C.DEFAULT_SCP_IF_SSH = 'smart'
        expected_in_data = b' '.join(
            (b'get', to_bytes(shlex_quote('/path/to/in/file')),
             to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n'
        conn.set_options({})
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._bare_run.assert_called_with('some command to run',
                                          expected_in_data,
                                          checkrc=False)

        # Test when SFTP doesn't work but SCP does
        conn._bare_run.side_effect = [(1, 'stdout', 'some errors'),
                                      (0, '', '')]
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._bare_run.assert_called_with('some command to run',
                                          None,
                                          checkrc=False)
        conn._bare_run.side_effect = None

        # test with C.DEFAULT_SCP_IF_SSH enabled
        C.DEFAULT_SCP_IF_SSH = True
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._bare_run.assert_called_with('some command to run',
                                          None,
                                          checkrc=False)

        conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩',
                        u'/path/to/dest/file/with/unicode-fö〩')
        conn._bare_run.assert_called_with('some command to run',
                                          None,
                                          checkrc=False)

        # test with C.DEFAULT_SCP_IF_SSH disabled
        C.DEFAULT_SCP_IF_SSH = False
        expected_in_data = b' '.join(
            (b'get', to_bytes(shlex_quote('/path/to/in/file')),
             to_bytes(shlex_quote('/path/to/dest/file')))) + b'\n'
        conn.fetch_file('/path/to/in/file', '/path/to/dest/file')
        conn._bare_run.assert_called_with('some command to run',
                                          expected_in_data,
                                          checkrc=False)

        expected_in_data = b' '.join(
            (b'get', to_bytes(
                shlex_quote('/path/to/in/file/with/unicode-fö〩')),
             to_bytes(
                 shlex_quote('/path/to/dest/file/with/unicode-fö〩')))) + b'\n'
        conn.fetch_file(u'/path/to/in/file/with/unicode-fö〩',
                        u'/path/to/dest/file/with/unicode-fö〩')
        conn._bare_run.assert_called_with('some command to run',
                                          expected_in_data,
                                          checkrc=False)

        # test that a non-zero rc raises an error
        conn._bare_run.return_value = (1, 'stdout', 'some errors')
        self.assertRaises(AnsibleError, conn.fetch_file, '/path/to/bad/file',
                          '/remote/path/to/file')
Example #28
0
    def test_network_cli__invalid_os(self):
        pc = PlayContext()
        pc.network_os = 'does not exist'

        self.assertRaises(AnsibleConnectionFailure, connection_loader.get, 'network_cli', pc, '/dev/null')
Example #29
0
 def test_plugins_connection_ssh__build_command(self):
     pc = PlayContext()
     new_stdin = StringIO()
     conn = connection_loader.get('ssh', pc, new_stdin)
     conn._build_command('ssh')
Example #30
0
      time.sleep(0.01)


debug("starting")
cur_worker      = 0
pending_results = 0


var_manager = VariableManager()

debug("loading inventory")
inventory = Inventory(host_list='/tmp/med_inventory', loader=loader, variable_manager=var_manager)
hosts = inventory.get_hosts()[:]
debug("done loading inventory")

play_context = PlayContext()
play_context.connection = 'local'

for i in range(NUM_TASKS):
   #for j in range(NUM_HOSTS):
   for h in hosts:
      debug("queuing %s %d" % (h, i))
      #h = Host(name="host%06d" % j)
      t = Task().load(dict(name="task %d" % (i,), debug="msg='hello from %s, %d'" % (h,i)))
      #t = Task().load(dict(name="task %d" % (i,), ping=""))
      #task_vars = var_manager.get_vars(loader=loader, host=h, task=t)
      task_vars = dict()
      new_t = t.copy()
      new_t.post_validate(task_vars)
      send_data((h, t, task_vars, play_context))
      debug("done queuing %s %d" % (h, i))
Example #31
0
    def test_plugins_connection_ssh__examine_output(self):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = connection_loader.get('ssh', pc, new_stdin)
        conn.set_become_plugin(become_loader.get('sudo'))

        conn.check_password_prompt = MagicMock()
        conn.check_become_success = MagicMock()
        conn.check_incorrect_password = MagicMock()
        conn.check_missing_password = MagicMock()

        def _check_password_prompt(line):
            if b'foo' in line:
                return True
            return False

        def _check_become_success(line):
            if b'BECOME-SUCCESS-abcdefghijklmnopqrstuvxyz' in line:
                return True
            return False

        def _check_incorrect_password(line):
            if b'incorrect password' in line:
                return True
            return False

        def _check_missing_password(line):
            if b'bad password' in line:
                return True
            return False

        conn.become.check_password_prompt = MagicMock(
            side_effect=_check_password_prompt)
        conn.become.check_become_success = MagicMock(
            side_effect=_check_become_success)
        conn.become.check_incorrect_password = MagicMock(
            side_effect=_check_incorrect_password)
        conn.become.check_missing_password = MagicMock(
            side_effect=_check_missing_password)

        # test examining output for prompt
        conn._flags = dict(
            become_prompt=False,
            become_success=False,
            become_error=False,
            become_nopasswd_error=False,
        )

        pc.prompt = True
        conn.become.prompt = True

        def get_option(option):
            if option == 'become_pass':
                return 'password'
            return None

        conn.become.get_option = get_option
        output, unprocessed = conn._examine_output(
            u'source', u'state',
            b'line 1\nline 2\nfoo\nline 3\nthis should be the remainder',
            False)
        self.assertEqual(output, b'line 1\nline 2\nline 3\n')
        self.assertEqual(unprocessed, b'this should be the remainder')
        self.assertTrue(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for become prompt
        conn._flags = dict(
            become_prompt=False,
            become_success=False,
            become_error=False,
            become_nopasswd_error=False,
        )

        pc.prompt = False
        conn.become.prompt = False
        pc.success_key = u'BECOME-SUCCESS-abcdefghijklmnopqrstuvxyz'
        conn.become.success = u'BECOME-SUCCESS-abcdefghijklmnopqrstuvxyz'
        output, unprocessed = conn._examine_output(
            u'source', u'state',
            b'line 1\nline 2\nBECOME-SUCCESS-abcdefghijklmnopqrstuvxyz\nline 3\n',
            False)
        self.assertEqual(output, b'line 1\nline 2\nline 3\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertTrue(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for become failure
        conn._flags = dict(
            become_prompt=False,
            become_success=False,
            become_error=False,
            become_nopasswd_error=False,
        )

        pc.prompt = False
        conn.become.prompt = False
        pc.success_key = None
        output, unprocessed = conn._examine_output(
            u'source', u'state', b'line 1\nline 2\nincorrect password\n', True)
        self.assertEqual(output, b'line 1\nline 2\nincorrect password\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertTrue(conn._flags['become_error'])
        self.assertFalse(conn._flags['become_nopasswd_error'])

        # test examining output for missing password
        conn._flags = dict(
            become_prompt=False,
            become_success=False,
            become_error=False,
            become_nopasswd_error=False,
        )

        pc.prompt = False
        conn.become.prompt = False
        pc.success_key = None
        output, unprocessed = conn._examine_output(u'source', u'state',
                                                   b'line 1\nbad password\n',
                                                   True)
        self.assertEqual(output, b'line 1\nbad password\n')
        self.assertEqual(unprocessed, b'')
        self.assertFalse(conn._flags['become_prompt'])
        self.assertFalse(conn._flags['become_success'])
        self.assertFalse(conn._flags['become_error'])
        self.assertTrue(conn._flags['become_nopasswd_error'])
Example #32
0
    def test_noop(self):
        fake_loader = DictDataLoader({
            "test_play.yml":
            """
            - hosts: all
              gather_facts: no
              tasks:
                - block:
                   - block:
                     - name: task1
                       debug: msg='task1'
                       failed_when: inventory_hostname == 'host01'

                     - name: task2
                       debug: msg='task2'

                     rescue:
                       - name: rescue1
                         debug: msg='rescue1'

                       - name: rescue2
                         debug: msg='rescue2'
            """,
        })

        mock_var_manager = MagicMock()
        mock_var_manager._fact_cache = dict()
        mock_var_manager.get_vars.return_value = dict()

        p = Playbook.load('test_play.yml',
                          loader=fake_loader,
                          variable_manager=mock_var_manager)

        inventory = MagicMock()
        inventory.hosts = {}
        hosts = []
        for i in range(0, 2):
            host = MagicMock()
            host.name = host.get_name.return_value = 'host%02d' % i
            hosts.append(host)
            inventory.hosts[host.name] = host
        inventory.get_hosts.return_value = hosts
        inventory.filter_hosts.return_value = hosts

        mock_var_manager._fact_cache['host00'] = dict()

        play_context = PlayContext(play=p._entries[0])

        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=mock_var_manager,
            loader=fake_loader,
            passwords=None,
            forks=5,
        )
        tqm._initialize_processes(3)
        strategy = StrategyModule(tqm)
        strategy._hosts_cache = [h.name for h in hosts]
        strategy._hosts_cache_all = [h.name for h in hosts]

        # implicit meta: flush_handlers
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'meta')
        self.assertEqual(host2_task.action, 'meta')

        # debug: task1, debug: task1
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'debug')
        self.assertEqual(host2_task.action, 'debug')
        self.assertEqual(host1_task.name, 'task1')
        self.assertEqual(host2_task.name, 'task1')

        # mark the second host failed
        itr.mark_host_failed(hosts[1])

        # debug: task2, meta: noop
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'debug')
        self.assertEqual(host2_task.action, 'meta')
        self.assertEqual(host1_task.name, 'task2')
        self.assertEqual(host2_task.name, '')

        # meta: noop, debug: rescue1
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'meta')
        self.assertEqual(host2_task.action, 'debug')
        self.assertEqual(host1_task.name, '')
        self.assertEqual(host2_task.name, 'rescue1')

        # meta: noop, debug: rescue2
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'meta')
        self.assertEqual(host2_task.action, 'debug')
        self.assertEqual(host1_task.name, '')
        self.assertEqual(host2_task.name, 'rescue2')

        # implicit meta: flush_handlers
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'meta')
        self.assertEqual(host2_task.action, 'meta')

        # implicit meta: flush_handlers
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNotNone(host1_task)
        self.assertIsNotNone(host2_task)
        self.assertEqual(host1_task.action, 'meta')
        self.assertEqual(host2_task.action, 'meta')

        # end of iteration
        hosts_left = strategy.get_hosts_left(itr)
        hosts_tasks = strategy._get_next_task_lockstep(hosts_left, itr)
        host1_task = hosts_tasks[0][1]
        host2_task = hosts_tasks[1][1]
        self.assertIsNone(host1_task)
        self.assertIsNone(host2_task)
def test_play_context_make_become_cmd(parser):
    (options, args) = parser.parse_args([])
    play_context = PlayContext(options=options)

    default_cmd = "/bin/foo"
    default_exe = "/bin/bash"
    sudo_exe = C.DEFAULT_SUDO_EXE or 'sudo'
    sudo_flags = C.DEFAULT_SUDO_FLAGS
    su_exe = C.DEFAULT_SU_EXE or 'su'
    su_flags = C.DEFAULT_SU_FLAGS or ''
    pbrun_exe = 'pbrun'
    pbrun_flags = ''
    pfexec_exe = 'pfexec'
    pfexec_flags = ''
    doas_exe = 'doas'
    doas_flags = ' -n  -u foo '
    ksu_exe = 'ksu'
    ksu_flags = ''
    dzdo_exe = 'dzdo'
    dzdo_flags = ''

    cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
    assert cmd == default_cmd

    play_context.become = True
    play_context.become_user = '******'

    play_context.become_method = 'sudo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s -u %s %s -c 'echo %s; %s'""" %
            (sudo_exe, sudo_flags, play_context.become_user, default_exe,
             play_context.success_key, default_cmd))

    play_context.become_pass = '******'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
    assert (cmd == """%s %s -p "%s" -u %s %s -c 'echo %s; %s'""" %
            (sudo_exe, sudo_flags.replace(
                '-n', ''), play_context.prompt, play_context.become_user,
             default_exe, play_context.success_key, default_cmd))

    play_context.become_pass = None
    play_context.become_method = 'su'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s  %s -c '%s -c '"'"'echo %s; %s'"'"''""" %
            (su_exe, play_context.become_user, default_exe,
             play_context.success_key, default_cmd))

    play_context.become_method = 'pbrun'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == """%s %s -u %s 'echo %s; %s'""" % (
        pbrun_exe, pbrun_flags, play_context.become_user,
        play_context.success_key, default_cmd)

    play_context.become_method = 'pfexec'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == '''%s %s "'echo %s; %s'"''' % (
        pfexec_exe, pfexec_flags, play_context.success_key, default_cmd)

    play_context.become_method = 'doas'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s %s -c 'echo %s; %s'""" %
            (doas_exe, doas_flags, default_exe, play_context.success_key,
             default_cmd))

    play_context.become_method = 'ksu'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s %s -e %s -c 'echo %s; %s'""" %
            (ksu_exe, play_context.become_user, ksu_flags, default_exe,
             play_context.success_key, default_cmd))

    play_context.become_method = 'bad'
    with pytest.raises(AnsibleError):
        play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")

    play_context.become_method = 'dzdo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert cmd == """%s %s -u %s %s -c 'echo %s; %s'""" % (
        dzdo_exe, dzdo_flags, play_context.become_user, default_exe,
        play_context.success_key, default_cmd)

    play_context.become_pass = '******'
    play_context.become_method = 'dzdo'
    cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
    assert (cmd == """%s %s -p %s -u %s %s -c 'echo %s; %s'""" %
            (dzdo_exe, dzdo_flags, shlex_quote(
                play_context.prompt), play_context.become_user, default_exe,
             play_context.success_key, default_cmd))
Example #34
0
    def test_action_base__late_needs_tmp_path(self):
        # create our fake task
        mock_task = MagicMock()

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )

        # assert no temp path is required because tmp is set
        self.assertFalse(action_base._late_needs_tmp_path("/tmp/foo", "new"))

        # assert no temp path is required when using a new-style module
        # with pipelining supported and enabled with no become method
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = None
        self.assertFalse(action_base._late_needs_tmp_path(None, "new"))

        # assert a temp path is required for each of the following:
        # the module style is not 'new'
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "old"))
        # connection plugin does not support pipelining
        mock_connection.has_pipelining = False
        play_context.pipelining = True
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
        # pipelining is disabled via the play context settings
        mock_connection.has_pipelining = True
        play_context.pipelining = False
        play_context.become_method = None
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
        # keep remote files is enabled
        # FIXME: implement
        # the become method is 'su'
        mock_connection.has_pipelining = True
        play_context.pipelining = True
        play_context.become_method = 'su'
        self.assertTrue(action_base._late_needs_tmp_path(None, "new"))
def test_play_context(mocker, parser):
    (options, args) = parser.parse_args(['-vv', '--check'])
    play_context = PlayContext(options=options)

    assert play_context._attributes['connection'] == C.DEFAULT_TRANSPORT
    assert play_context.remote_addr is None
    assert play_context.remote_user is None
    assert play_context.password == ''
    assert play_context.port is None
    assert play_context.private_key_file == C.DEFAULT_PRIVATE_KEY_FILE
    assert play_context.timeout == C.DEFAULT_TIMEOUT
    assert play_context.shell is None
    assert play_context.verbosity == 2
    assert play_context.check_mode is True
    assert play_context.no_log is None

    mock_play = mocker.MagicMock()
    mock_play.connection = 'mock'
    mock_play.remote_user = '******'
    mock_play.port = 1234
    mock_play.become = True
    mock_play.become_method = 'mock'
    mock_play.become_user = '******'
    mock_play.no_log = True

    play_context = PlayContext(play=mock_play, options=options)
    assert play_context.connection == 'mock'
    assert play_context.remote_user == 'mock'
    assert play_context.password == ''
    assert play_context.port == 1234
    assert play_context.become is True
    assert play_context.become_method == "mock"
    assert play_context.become_user == "mockroot"

    mock_task = mocker.MagicMock()
    mock_task.connection = 'mocktask'
    mock_task.remote_user = '******'
    mock_task.no_log = mock_play.no_log
    mock_task.become = True
    mock_task.become_method = 'mocktask'
    mock_task.become_user = '******'
    mock_task.become_pass = '******'
    mock_task._local_action = False
    mock_task.delegate_to = None

    all_vars = dict(
        ansible_connection='mock_inventory',
        ansible_ssh_port=4321,
    )

    mock_templar = mocker.MagicMock()

    play_context = PlayContext(play=mock_play, options=options)
    play_context = play_context.set_task_and_variable_override(
        task=mock_task, variables=all_vars, templar=mock_templar)

    assert play_context.connection == 'mock_inventory'
    assert play_context.remote_user == 'mocktask'
    assert play_context.port == 4321
    assert play_context.no_log is True
    assert play_context.become is True
    assert play_context.become_method == "mocktask"
    assert play_context.become_user == "mocktaskroot"
    assert play_context.become_pass == "mocktaskpass"

    mock_task.no_log = False
    play_context = play_context.set_task_and_variable_override(
        task=mock_task, variables=all_vars, templar=mock_templar)
    assert play_context.no_log is False
    def test_action_base__fixup_perms2(self):
        mock_task = MagicMock()
        mock_connection = MagicMock()
        play_context = PlayContext()
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=None,
            templar=None,
            shared_loader_obj=None,
        )
        action_base._low_level_execute_command = MagicMock()
        remote_paths = ['/tmp/foo/bar.txt', '/tmp/baz.txt']
        remote_user = '******'

        # Used for skipping down to common group dir.
        CHMOD_ACL_FLAGS = ('+a', 'A+user:remoteuser2:r:allow')

        def runWithNoExpectation(execute=False):
            return action_base._fixup_perms2(remote_paths,
                                             remote_user=remote_user,
                                             execute=execute)

        def assertSuccess(execute=False):
            self.assertEqual(runWithNoExpectation(execute), remote_paths)

        def assertThrowRegex(regex, execute=False):
            self.assertRaisesRegexp(AnsibleError,
                                    regex,
                                    action_base._fixup_perms2,
                                    remote_paths,
                                    remote_user=remote_user,
                                    execute=execute)

        def get_shell_option_for_arg(args_kv, default):
            '''A helper for get_shell_option. Returns a function that, if
            called with ``option`` that exists in args_kv, will return the
            value, else will return ``default`` for every other given arg'''
            def _helper(option, *args, **kwargs):
                return args_kv.get(option, default)

            return _helper

        action_base.get_become_option = MagicMock()
        action_base.get_become_option.return_value = 'remoteuser2'

        # Step 1: On windows, we just return remote_paths
        action_base._connection._shell._IS_WINDOWS = True
        assertSuccess(execute=False)
        assertSuccess(execute=True)

        # But if we're not on windows....we have more work to do.
        action_base._connection._shell._IS_WINDOWS = False

        # Step 2: We're /not/ becoming an unprivileged user
        action_base._remote_chmod = MagicMock()
        action_base._is_become_unprivileged = MagicMock()
        action_base._is_become_unprivileged.return_value = False
        # Two subcases:
        #   - _remote_chmod rc is 0
        #   - _remote-chmod rc is not 0, something failed
        action_base._remote_chmod.return_value = {
            'rc': 0,
            'stdout': 'some stuff here',
            'stderr': '',
        }
        assertSuccess(execute=True)

        # When execute=False, we just get the list back. But add it here for
        # completion. chmod is never called.
        assertSuccess()

        action_base._remote_chmod.return_value = {
            'rc': 1,
            'stdout': 'some stuff here',
            'stderr': 'and here',
        }
        assertThrowRegex('Failed to set execute bit on remote files',
                         execute=True)

        # Step 3: we are becoming unprivileged
        action_base._is_become_unprivileged.return_value = True

        # Step 3a: setfacl
        action_base._remote_set_user_facl = MagicMock()
        action_base._remote_set_user_facl.return_value = {
            'rc': 0,
            'stdout': '',
            'stderr': '',
        }
        assertSuccess()

        # Step 3b: chmod +x if we need to
        # To get here, setfacl failed, so mock it as such.
        action_base._remote_set_user_facl.return_value = {
            'rc': 1,
            'stdout': '',
            'stderr': '',
        }
        action_base._remote_chmod.return_value = {
            'rc': 1,
            'stdout': 'some stuff here',
            'stderr': '',
        }
        assertThrowRegex('Failed to set file mode on remote temporary file',
                         execute=True)
        action_base._remote_chmod.return_value = {
            'rc': 0,
            'stdout': 'some stuff here',
            'stderr': '',
        }
        assertSuccess(execute=True)

        # Step 3c: chown
        action_base._remote_chown = MagicMock()
        action_base._remote_chown.return_value = {
            'rc': 0,
            'stdout': '',
            'stderr': '',
        }
        assertSuccess()
        action_base._remote_chown.return_value = {
            'rc': 1,
            'stdout': '',
            'stderr': '',
        }
        remote_user = '******'
        action_base._get_admin_users = MagicMock()
        action_base._get_admin_users.return_value = ['root']
        assertThrowRegex('user would be unable to read the file.')
        remote_user = '******'

        # Step 3d: chmod +a on osx
        assertSuccess()
        action_base._remote_chmod.assert_called_with(
            ['remoteuser2 allow read'] + remote_paths, '+a')

        # This case can cause Solaris chmod to return 5 which the ssh plugin
        # treats as failure. To prevent a regression and ensure we still try the
        # rest of the cases below, we mock the thrown exception here.
        # This function ensures that only the macOS case (+a) throws this.
        def raise_if_plus_a(definitely_not_underscore, mode):
            if mode == '+a':
                raise AnsibleAuthenticationFailure()
            return {'rc': 0, 'stdout': '', 'stderr': ''}

        action_base._remote_chmod.side_effect = raise_if_plus_a
        assertSuccess()

        # Step 3e: chmod A+ on Solaris
        # We threw AnsibleAuthenticationFailure above, try Solaris fallback.
        # Based on our lambda above, it should be successful.
        action_base._remote_chmod.assert_called_with(
            remote_paths, 'A+user:remoteuser2:r:allow')
        assertSuccess()

        # Step 3f: Common group
        def rc_1_if_chmod_acl(definitely_not_underscore, mode):
            rc = 0
            if mode in CHMOD_ACL_FLAGS:
                rc = 1
            return {'rc': rc, 'stdout': '', 'stderr': ''}

        action_base._remote_chmod = MagicMock()
        action_base._remote_chmod.side_effect = rc_1_if_chmod_acl

        get_shell_option = action_base.get_shell_option
        action_base.get_shell_option = MagicMock()
        action_base.get_shell_option.side_effect = get_shell_option_for_arg(
            {
                'common_remote_group': 'commongroup',
            }, None)
        action_base._remote_chgrp = MagicMock()
        action_base._remote_chgrp.return_value = {
            'rc': 0,
            'stdout': '',
            'stderr': '',
        }
        # TODO: Add test to assert warning is shown if
        # ALLOW_WORLD_READABLE_TMPFILES is set in this case.
        assertSuccess()
        action_base._remote_chgrp.assert_called_once_with(
            remote_paths, 'commongroup')

        # Step 4: world-readable tmpdir
        action_base.get_shell_option.side_effect = get_shell_option_for_arg(
            {
                'world_readable_temp': True,
                'common_remote_group': None,
            }, None)
        action_base._remote_chmod.return_value = {
            'rc': 0,
            'stdout': 'some stuff here',
            'stderr': '',
        }
        assertSuccess()
        action_base._remote_chmod = MagicMock()
        action_base._remote_chmod.return_value = {
            'rc': 1,
            'stdout': 'some stuff here',
            'stderr': '',
        }
        assertThrowRegex('Failed to set file mode on remote files')

        # Otherwise if we make it here in this state, we hit the catch-all
        action_base.get_shell_option.side_effect = get_shell_option_for_arg(
            {}, None)
        assertThrowRegex('on the temporary files Ansible needs to create')
Example #37
0
    def run(self):

        # Note: slightly wrong, this is written so that implicit localhost
        # Manage passwords
        sshpass = None
        becomepass = None
        b_vault_pass = None
        passwords = {}

        # initial error check, to make sure all specified playbooks are accessible
        # before we start running anything through the playbook executor
        for playbook in self.playbooks:
            if not os.path.exists(playbook):
                raise AnsibleError("the playbook: %s could not be found" %
                                   playbook)
            if not (os.path.isfile(playbook)
                    or stat.S_ISFIFO(os.stat(playbook).st_mode)):
                raise AnsibleError(
                    "the playbook: %s does not appear to be a file" % playbook)

        # don't deal with privilege escalation or passwords when we don't need to
        if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax:
            self.normalize_become_options()
            (sshpass, becomepass) = self.ask_passwords()
            passwords = {'conn_pass': sshpass, 'become_pass': becomepass}

        loader = DataLoader()

        if self.options.vault_password_file:
            # read vault_pass from a file
            b_vault_pass = CLI.read_vault_password_file(
                self.options.vault_password_file, loader=loader)
            loader.set_vault_password(b_vault_pass)
        elif self.options.ask_vault_pass:
            b_vault_pass = self.ask_vault_passwords()
            loader.set_vault_password(b_vault_pass)
        elif 'VAULT_PASS' in os.environ:
            loader.set_vault_password(os.environ['VAULT_PASS'])

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager()

        # Subspace injection
        option_extra_vars = load_extra_vars(loader=loader,
                                            options=self.options)
        option_extra_vars.update(self.extra_vars)
        variable_manager.extra_vars = option_extra_vars
        # End Subspace injection

        variable_manager.options_vars = load_options_vars(self.options)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = Inventory(loader=loader,
                              variable_manager=variable_manager,
                              host_list=self.options.inventory)
        variable_manager.set_inventory(inventory)

        # (which is not returned in list_hosts()) is taken into account for
        # warning if inventory is empty.  But it can't be taken into account for
        # checking if limit doesn't match any hosts.  Instead we don't worry about
        # limit if only implicit localhost was in inventory to start with.
        #
        # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts())
        no_hosts = False
        if len(inventory.list_hosts()) == 0:
            # Empty inventory
            display.warning(
                "provided hosts list is empty, only localhost is available")
            no_hosts = True
        inventory.subset(self.options.subset)
        if len(inventory.list_hosts()) == 0 and no_hosts is False:
            # Invalid limit
            raise AnsibleError("Specified --limit does not match any hosts")

        # flush fact cache if requested
        if self.options.flush_cache:
            self._flush_cache(inventory, variable_manager)

        hosts = inventory.get_hosts()
        if self.options.subset and not hosts:
            raise NoValidHosts(
                "The limit <%s> is not included in the inventory: %s" %
                (self.options.subset, inventory.host_list))

    # create the playbook executor, which manages running the plays via a task queue manager
    # Subspace injection
        pbex = PlaybookExecutor(playbooks=self.playbooks,
                                inventory=inventory,
                                variable_manager=variable_manager,
                                loader=loader,
                                options=self.options,
                                passwords=passwords)
        playbook_map = self._get_playbook_map()
        pbex._tqm._stats = SubspaceAggregateStats(playbook_map)
        pbex._tqm.load_callbacks()
        pbex._tqm.send_callback(
            'start_logging',
            logger=self.options.logger,
            username=self.extra_vars.get('ATMOUSERNAME', "No-User"),
        )
        for host in inventory._subset:
            variables = inventory.get_vars(host)
            self.options.logger.info("Vars found for hostname %s: %s" %
                                     (host, variables))
        # End Subspace injection

        results = pbex.run()
        # Subspace injection
        stats = pbex._tqm._stats
        self.stats = stats
        # Nonpersistent fact cache stores 'register' variables. We would like
        # to get access to stdout/stderr for specific commands and relay
        # some of that information back to the end user.
        self.results = dict(pbex._variable_manager._nonpersistent_fact_cache)
        # End Subspace injection

        if isinstance(results, list):
            for p in results:

                display.display('\nplaybook: %s' % p['playbook'])
                for idx, play in enumerate(p['plays']):
                    if play._included_path is not None:
                        loader.set_basedir(play._included_path)
                    else:
                        pb_dir = os.path.realpath(
                            os.path.dirname(p['playbook']))
                        loader.set_basedir(pb_dir)

                    msg = "\n  play #%d (%s): %s" % (idx + 1, ','.join(
                        play.hosts), play.name)
                    mytags = set(play.tags)
                    msg += '\tTAGS: [%s]' % (','.join(mytags))

                    if self.options.listhosts:
                        playhosts = set(inventory.get_hosts(play.hosts))
                        msg += "\n    pattern: %s\n    hosts (%d):" % (
                            play.hosts, len(playhosts))
                        for host in playhosts:
                            msg += "\n      %s" % host

                    display.display(msg)

                    all_tags = set()
                    if self.options.listtags or self.options.listtasks:
                        taskmsg = ''
                        if self.options.listtasks:
                            taskmsg = '    tasks:\n'

                        def _process_block(b):
                            taskmsg = ''
                            for task in b.block:
                                if isinstance(task, Block):
                                    taskmsg += _process_block(task)
                                else:
                                    if task.action == 'meta':
                                        continue

                                    all_tags.update(task.tags)
                                    if self.options.listtasks:
                                        cur_tags = list(
                                            mytags.union(set(task.tags)))
                                        cur_tags.sort()
                                        if task.name:
                                            taskmsg += "      %s" % task.get_name(
                                            )
                                        else:
                                            taskmsg += "      %s" % task.action
                                        taskmsg += "\tTAGS: [%s]\n" % ', '.join(
                                            cur_tags)

                            return taskmsg

                        all_vars = variable_manager.get_vars(loader=loader,
                                                             play=play)
                        play_context = PlayContext(play=play,
                                                   options=self.options)
                        for block in play.compile():
                            block = block.filter_tagged_tasks(
                                play_context, all_vars)
                            if not block.has_tasks():
                                continue
                            taskmsg += _process_block(block)

                        if self.options.listtags:
                            cur_tags = list(mytags.union(all_tags))
                            cur_tags.sort()
                            taskmsg += "      TASK TAGS: [%s]\n" % ', '.join(
                                cur_tags)

                        display.display(taskmsg)

            return 0
        else:
            return results
Example #38
0
    def test_plugins_connection_ssh__run(self, mock_Popen, mock_openpty, mock_osclose, mock_oswrite, mock_fcntl, mock_select):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = ssh.Connection(pc, new_stdin)
        conn._send_initial_data = MagicMock()
        conn._examine_output = MagicMock()
        conn._terminate_process = MagicMock()
        conn.sshpass_pipe = [MagicMock(), MagicMock()]

        mock_popen_res = MagicMock()
        mock_popen_res.poll   = MagicMock()
        mock_popen_res.wait   = MagicMock()
        mock_popen_res.stdin  = MagicMock()
        mock_popen_res.stdin.fileno.return_value = 1000
        mock_popen_res.stdout = MagicMock()
        mock_popen_res.stdout.fileno.return_value = 1001
        mock_popen_res.stderr = MagicMock()
        mock_popen_res.stderr.fileno.return_value = 1002
        mock_popen_res.return_code = 0
        mock_Popen.return_value = mock_popen_res

        def _mock_select(rlist, wlist, elist, timeout=None):
            rvals = []
            if mock_popen_res.stdin in rlist:
                rvals.append(mock_popen_res.stdin)
            if mock_popen_res.stderr in rlist:
                rvals.append(mock_popen_res.stderr)
            return (rvals, [], [])

        mock_select.side_effect = _mock_select

        mock_popen_res.stdout.read.side_effect = [b"some data", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # test with a password set to trigger the sshpass write
        pc.password = '******'
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run(["ssh", "is", "a", "cmd"], "this is more data")

        # test with password prompting enabled
        pc.password = None
        pc.prompt = True
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # test with some become settings
        pc.prompt = False
        pc.become = True
        pc.success_key = 'BECOME-SUCCESS-abcdefg'
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # simulate no data input
        mock_openpty.return_value = (98, 99)
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "")

        # simulate no data input but Popen using new pty's fails
        mock_Popen.return_value = None
        mock_Popen.side_effect = [OSError(), mock_popen_res]
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "")
Example #39
0
    def test_plugins_connection_ssh__run(self, mock_Popen, mock_openpty,
                                         mock_osclose, mock_oswrite,
                                         mock_fcntl, mock_select):
        pc = PlayContext()
        new_stdin = StringIO()

        conn = ssh.Connection(pc, new_stdin)
        conn._send_initial_data = MagicMock()
        conn._examine_output = MagicMock()
        conn._terminate_process = MagicMock()
        conn.sshpass_pipe = [MagicMock(), MagicMock()]

        mock_popen_res = MagicMock()
        mock_popen_res.poll = MagicMock()
        mock_popen_res.wait = MagicMock()
        mock_popen_res.stdin = MagicMock()
        mock_popen_res.stdin.fileno.return_value = 1000
        mock_popen_res.stdout = MagicMock()
        mock_popen_res.stdout.fileno.return_value = 1001
        mock_popen_res.stderr = MagicMock()
        mock_popen_res.stderr.fileno.return_value = 1002
        mock_popen_res.return_code = 0
        mock_Popen.return_value = mock_popen_res

        def _mock_select(rlist, wlist, elist, timeout=None):
            rvals = []
            if mock_popen_res.stdin in rlist:
                rvals.append(mock_popen_res.stdin)
            if mock_popen_res.stderr in rlist:
                rvals.append(mock_popen_res.stderr)
            return (rvals, [], [])

        mock_select.side_effect = _mock_select

        mock_popen_res.stdout.read.side_effect = [b"some data", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # test with a password set to trigger the sshpass write
        pc.password = '******'
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run(["ssh", "is", "a", "cmd"], "this is more data")

        # test with password prompting enabled
        pc.password = None
        pc.prompt = True
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # test with some become settings
        pc.prompt = False
        pc.become = True
        pc.success_key = 'BECOME-SUCCESS-abcdefg'
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "this is input data")

        # simulate no data input
        mock_openpty.return_value = (98, 99)
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "")

        # simulate no data input but Popen using new pty's fails
        mock_Popen.return_value = None
        mock_Popen.side_effect = [OSError(), mock_popen_res]
        mock_popen_res.stdout.read.side_effect = [b"some data", b"", b""]
        mock_popen_res.stderr.read.side_effect = [b""]
        conn._run("ssh", "")
Example #40
0
    def test_play_iterator(self):
        fake_loader = DictDataLoader({
            "test_play.yml": """
            - hosts: all
              gather_facts: false
              roles:
              - test_role
              pre_tasks:
              - debug: msg="this is a pre_task"
              tasks:
              - debug: msg="this is a regular task"
              post_tasks:
              - debug: msg="this is a post_task"
            """,
            '/etc/ansible/roles/test_role/tasks/main.yml': """
            - debug: msg="this is a role task"
            """,
        })

        p = Playbook.load('test_play.yml', loader=fake_loader)

        hosts = []
        for i in range(0, 10):
            host  = MagicMock()
            host.get_name.return_value = 'host%02d' % i
            hosts.append(host)

        inventory = MagicMock()
        inventory.get_hosts.return_value = hosts
        inventory.filter_hosts.return_value = hosts

        mock_var_manager = MagicMock()
        mock_var_manager._fact_cache = dict()

        play_context = PlayContext(play=p._entries[0])

        itr = PlayIterator(
            inventory=inventory,
            play=p._entries[0],
            play_context=play_context,
            variable_manager=mock_var_manager,
            all_vars=dict(),
        )

        # pre task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # role task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertIsNotNone(task._role)
        # regular play task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        self.assertIsNone(task._role)
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # post task
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'debug')
        # implicit meta: flush_handlers
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNotNone(task)
        self.assertEqual(task.action, 'meta')
        # end of iteration
        (host_state, task) = itr.get_next_task_for_host(hosts[0])
        self.assertIsNone(task)
    def test_play_context_make_become_cmd(self):
        (options, args) = self._parser.parse_args([])
        play_context = PlayContext(options=options)

        default_cmd = "/bin/foo"
        default_exe = "/bin/bash"
        sudo_exe    = C.DEFAULT_SUDO_EXE or 'sudo'
        sudo_flags  = C.DEFAULT_SUDO_FLAGS
        su_exe      = C.DEFAULT_SU_EXE or 'su'
        su_flags    = C.DEFAULT_SU_FLAGS or ''
        pbrun_exe   = 'pbrun'
        pbrun_flags = ''
        pfexec_exe   = 'pfexec'
        pfexec_flags = ''
        doas_exe    = 'doas'
        doas_flags  = ' -n  -u foo '

        cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
        self.assertEqual(cmd, default_cmd)

        play_context.become = True
        play_context.become_user = '******'

        play_context.become_method = 'sudo'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
        self.assertEqual(cmd, """%s %s -u %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags, play_context.become_user, default_exe, play_context.success_key, default_cmd))
        play_context.become_pass = '******'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable=default_exe)
        self.assertEqual(cmd, """%s %s -p "%s" -u %s %s -c 'echo %s; %s'""" % (sudo_exe, sudo_flags.replace('-n',''), play_context.prompt, play_context.become_user, default_exe, play_context.success_key, default_cmd))

        play_context.become_pass = None

        play_context.become_method = 'su'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
        self.assertEqual(cmd, """%s  %s -c '%s -c '"'"'echo %s; %s'"'"''""" % (su_exe, play_context.become_user, default_exe, play_context.success_key, default_cmd))

        play_context.become_method = 'pbrun'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
        self.assertEqual(cmd, """%s -b %s -u %s 'echo %s; %s'""" % (pbrun_exe, pbrun_flags, play_context.become_user, play_context.success_key, default_cmd))

        play_context.become_method = 'pfexec'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
        self.assertEqual(cmd, '''%s %s "'echo %s; %s'"''' % (pfexec_exe, pfexec_flags, play_context.success_key, default_cmd))

        play_context.become_method = 'doas'
        cmd = play_context.make_become_cmd(cmd=default_cmd, executable="/bin/bash")
        self.assertEqual(cmd, """%s %s echo %s && %s %s env ANSIBLE=true %s""" % (doas_exe, doas_flags, play_context.success_key, doas_exe, doas_flags, default_cmd))

        play_context.become_method = 'bad'
        self.assertRaises(AnsibleError, play_context.make_become_cmd, cmd=default_cmd, executable="/bin/bash")
    def test_action_base__configure_module(self):
        fake_loader = DictDataLoader({})

        # create our fake task
        mock_task = MagicMock()
        mock_task.action = "copy"
        mock_task.async_val = 0
        mock_task.delegate_to = None

        # create a mock connection, so we don't actually try and connect to things
        mock_connection = MagicMock()

        # create a mock shared loader object
        def mock_find_plugin_with_context(name, options, collection_list=None):
            mockctx = MagicMock()
            if name == 'badmodule':
                mockctx.resolved = False
                mockctx.plugin_resolved_path = None
            elif '.ps1' in options:
                mockctx.resolved = True
                mockctx.plugin_resolved_path = '/fake/path/to/%s.ps1' % name
            else:
                mockctx.resolved = True
                mockctx.plugin_resolved_path = '/fake/path/to/%s' % name
            return mockctx

        mock_module_loader = MagicMock()
        mock_module_loader.find_plugin_with_context.side_effect = mock_find_plugin_with_context
        mock_shared_obj_loader = MagicMock()
        mock_shared_obj_loader.module_loader = mock_module_loader

        # we're using a real play context here
        play_context = PlayContext()

        # our test class
        action_base = DerivedActionBase(
            task=mock_task,
            connection=mock_connection,
            play_context=play_context,
            loader=fake_loader,
            templar=Templar(loader=fake_loader),
            shared_loader_obj=mock_shared_obj_loader,
        )

        # test python module formatting
        with patch.object(
                builtins, 'open',
                mock_open(read_data=to_bytes(python_module_replacers.strip(),
                                             encoding='utf-8'))):
            with patch.object(os, 'rename'):
                mock_task.args = dict(a=1, foo='fö〩')
                mock_connection.module_implementation_preferences = ('', )
                (style, shebang, data, path) = action_base._configure_module(
                    mock_task.action,
                    mock_task.args,
                    task_vars=dict(
                        ansible_python_interpreter='/usr/bin/python',
                        ansible_playbook_python='/usr/bin/python'))
                self.assertEqual(style, "new")
                self.assertEqual(shebang, u"#!/usr/bin/python")

                # test module not found
                self.assertRaises(AnsibleError, action_base._configure_module,
                                  'badmodule', mock_task.args, {})

        # test powershell module formatting
        with patch.object(
                builtins, 'open',
                mock_open(read_data=to_bytes(
                    powershell_module_replacers.strip(), encoding='utf-8'))):
            mock_task.action = 'win_copy'
            mock_task.args = dict(b=2)
            mock_connection.module_implementation_preferences = ('.ps1', )
            (style, shebang, data,
             path) = action_base._configure_module('stat', mock_task.args, {})
            self.assertEqual(style, "new")
            self.assertEqual(shebang, u'#!powershell')

            # test module not found
            self.assertRaises(AnsibleError, action_base._configure_module,
                              'badmodule', mock_task.args, {})
Example #43
0
    def run(self):

        super(PlaybookCLI, self).run()

        # Note: slightly wrong, this is written so that implicit localhost
        # Manage passwords
        sshpass    = None
        becomepass    = None
        vault_pass = None
        passwords = {}

        # don't deal with privilege escalation or passwords when we don't need to
        if not self.options.listhosts and not self.options.listtasks and not self.options.listtags and not self.options.syntax:
            self.normalize_become_options()
            (sshpass, becomepass) = self.ask_passwords()
            passwords = { 'conn_pass': sshpass, 'become_pass': becomepass }

        loader = DataLoader()

        if self.options.vault_password_file:
            # read vault_pass from a file
            vault_pass = CLI.read_vault_password_file(self.options.vault_password_file, loader=loader)
            loader.set_vault_password(vault_pass)
        elif self.options.ask_vault_pass:
            vault_pass = self.ask_vault_passwords()[0]
            loader.set_vault_password(vault_pass)

        # initial error check, to make sure all specified playbooks are accessible
        # before we start running anything through the playbook executor
        for playbook in self.args:
            if not os.path.exists(playbook):
                raise AnsibleError("the playbook: %s could not be found" % playbook)
            if not (os.path.isfile(playbook) or stat.S_ISFIFO(os.stat(playbook).st_mode)):
                raise AnsibleError("the playbook: %s does not appear to be a file" % playbook)

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager()
        variable_manager.extra_vars = load_extra_vars(loader=loader, options=self.options)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=self.options.inventory)
        variable_manager.set_inventory(inventory)

        # (which is not returned in list_hosts()) is taken into account for
        # warning if inventory is empty.  But it can't be taken into account for
        # checking if limit doesn't match any hosts.  Instead we don't worry about
        # limit if only implicit localhost was in inventory to start with.
        #
        # Fix this when we rewrite inventory by making localhost a real host (and thus show up in list_hosts())
        no_hosts = False
        if len(inventory.list_hosts()) == 0:
            # Empty inventory
            display.warning("provided hosts list is empty, only localhost is available")
            no_hosts = True
        inventory.subset(self.options.subset)
        if len(inventory.list_hosts()) == 0 and no_hosts is False:
            # Invalid limit
            raise AnsibleError("Specified --limit does not match any hosts")

        # create the playbook executor, which manages running the plays via a task queue manager
        pbex = PlaybookExecutor(playbooks=self.args, inventory=inventory, variable_manager=variable_manager, loader=loader, options=self.options, passwords=passwords)

        results = pbex.run()

        if isinstance(results, list):
            for p in results:

                display.display('\nplaybook: %s' % p['playbook'])
                for idx, play in enumerate(p['plays']):
                    msg = "\n  play #%d (%s): %s" % (idx + 1, ','.join(play.hosts), play.name)
                    mytags = set(play.tags)
                    msg += '\tTAGS: [%s]' % (','.join(mytags))

                    if self.options.listhosts:
                        playhosts = set(inventory.get_hosts(play.hosts))
                        msg += "\n    pattern: %s\n    hosts (%d):" % (play.hosts, len(playhosts))
                        for host in playhosts:
                            msg += "\n      %s" % host

                    display.display(msg)

                    all_tags = set()
                    if self.options.listtags or self.options.listtasks:
                        taskmsg = ''
                        if self.options.listtasks:
                            taskmsg = '    tasks:\n'

                        def _process_block(b):
                            taskmsg = ''
                            for task in b.block:
                                if isinstance(task, Block):
                                    taskmsg += _process_block(task)
                                else:
                                    if task.action == 'meta':
                                        continue

                                    all_tags.update(task.tags)
                                    if self.options.listtasks:
                                        cur_tags = list(mytags.union(set(task.tags)))
                                        cur_tags.sort()
                                        if task.name:
                                            taskmsg += "      %s" % task.get_name()
                                        else:
                                            taskmsg += "      %s" % task.action
                                        taskmsg += "\tTAGS: [%s]\n" % ', '.join(cur_tags)

                            return taskmsg

                        all_vars = variable_manager.get_vars(loader=loader, play=play)
                        play_context = PlayContext(play=play, options=self.options)
                        for block in play.compile():
                            block = block.filter_tagged_tasks(play_context, all_vars)
                            if not block.has_tasks():
                                continue
                            taskmsg += _process_block(block)

                        if self.options.listtags:
                            cur_tags = list(mytags.union(all_tags))
                            cur_tags.sort()
                            taskmsg += "      TASK TAGS: [%s]\n" % ', '.join(cur_tags)

                        display.display(taskmsg)

            return 0
        else:
            return results
Example #44
0
 def setUp(self):
     self.play_context = PlayContext()
     self.play_context.prompt = (
         '[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: '
     )
     self.in_stream = StringIO()
Example #45
0
    def run(self, play):
        '''
        Iterates over the roles/tasks in a play, using the given (or default)
        strategy for queueing tasks. The default is the linear strategy, which
        operates like classic Ansible by keeping all hosts in lock-step with
        a given task (meaning no hosts move on to the next task until all hosts
        are done with the current task).
        '''

        if not self._callbacks_loaded:
            self.load_callbacks()

        all_vars = self._variable_manager.get_vars(loader=self._loader,
                                                   play=play)
        templar = Templar(loader=self._loader, variables=all_vars)

        new_play = play.copy()
        new_play.post_validate(templar)
        new_play.handlers = new_play.compile_roles_handlers(
        ) + new_play.handlers

        self.hostvars = HostVars(
            inventory=self._inventory,
            variable_manager=self._variable_manager,
            loader=self._loader,
        )

        # Fork # of forks, # of hosts or serial, whichever is lowest
        num_hosts = len(
            self._inventory.get_hosts(new_play.hosts,
                                      ignore_restrictions=True))

        max_serial = 0
        if new_play.serial:
            # the play has not been post_validated here, so we may need
            # to convert the scalar value to a list at this point
            serial_items = new_play.serial
            if not isinstance(serial_items, list):
                serial_items = [serial_items]
            max_serial = max([pct_to_int(x, num_hosts) for x in serial_items])

        contenders = [self._options.forks, max_serial, num_hosts]
        contenders = [v for v in contenders if v is not None and v > 0]
        self._initialize_processes(min(contenders))

        play_context = PlayContext(new_play, self._options, self.passwords,
                                   self._connection_lockfile.fileno())
        for callback_plugin in self._callback_plugins:
            if hasattr(callback_plugin, 'set_play_context'):
                callback_plugin.set_play_context(play_context)

        self.send_callback('v2_playbook_on_play_start', new_play)

        # initialize the shared dictionary containing the notified handlers
        self._initialize_notified_handlers(new_play)

        # load the specified strategy (or the default linear one)
        strategy = strategy_loader.get(new_play.strategy, self)
        if strategy is None:
            raise AnsibleError("Invalid play strategy specified: %s" %
                               new_play.strategy,
                               obj=play._ds)

        # build the iterator
        iterator = PlayIterator(
            inventory=self._inventory,
            play=new_play,
            play_context=play_context,
            variable_manager=self._variable_manager,
            all_vars=all_vars,
            start_at_done=self._start_at_done,
        )

        # Because the TQM may survive multiple play runs, we start by marking
        # any hosts as failed in the iterator here which may have been marked
        # as failed in previous runs. Then we clear the internal list of failed
        # hosts so we know what failed this round.
        for host_name in self._failed_hosts.keys():
            host = self._inventory.get_host(host_name)
            iterator.mark_host_failed(host)

        self.clear_failed_hosts()

        # during initialization, the PlayContext will clear the start_at_task
        # field to signal that a matching task was found, so check that here
        # and remember it so we don't try to skip tasks on future plays
        if getattr(self._options, 'start_at_task',
                   None) is not None and play_context.start_at_task is None:
            self._start_at_done = True

        # and run the play using the strategy and cleanup on way out
        play_return = strategy.run(iterator, play_context)

        # now re-save the hosts that failed from the iterator to our internal list
        for host_name in iterator.get_failed_hosts():
            self._failed_hosts[host_name] = True

        strategy.cleanup()
        self._cleanup_processes()
        return play_return
Example #46
0
def test_play_context(mocker, parser):
    (options, args) = parser.parse_args(['-vv', '--check'])
    play_context = PlayContext(options=options)

    assert play_context._attributes['connection'] == C.DEFAULT_TRANSPORT
    assert play_context.remote_addr is None
    assert play_context.remote_user is None
    assert play_context.password == ''
    assert play_context.port is None
    assert play_context.private_key_file == C.DEFAULT_PRIVATE_KEY_FILE
    assert play_context.timeout == C.DEFAULT_TIMEOUT
    assert play_context.shell is None
    assert play_context.verbosity == 2
    assert play_context.check_mode is True
    assert play_context.no_log is None

    mock_play = mocker.MagicMock()
    mock_play.connection = 'mock'
    mock_play.remote_user = '******'
    mock_play.port = 1234
    mock_play.become = True
    mock_play.become_method = 'mock'
    mock_play.become_user = '******'
    mock_play.no_log = True

    play_context = PlayContext(play=mock_play, options=options)
    assert play_context.connection == 'mock'
    assert play_context.remote_user == 'mock'
    assert play_context.password == ''
    assert play_context.port == 1234
    assert play_context.become is True
    assert play_context.become_method == "mock"
    assert play_context.become_user == "mockroot"

    mock_task = mocker.MagicMock()
    mock_task.connection = 'mocktask'
    mock_task.remote_user = '******'
    mock_task.no_log = mock_play.no_log
    mock_task.become = True
    mock_task.become_method = 'mocktask'
    mock_task.become_user = '******'
    mock_task.become_pass = '******'
    mock_task._local_action = False
    mock_task.delegate_to = None

    all_vars = dict(
        ansible_connection='mock_inventory',
        ansible_ssh_port=4321,
    )

    mock_templar = mocker.MagicMock()

    play_context = PlayContext(play=mock_play, options=options)
    play_context = play_context.set_task_and_variable_override(task=mock_task, variables=all_vars, templar=mock_templar)

    assert play_context.connection == 'mock_inventory'
    assert play_context.remote_user == 'mocktask'
    assert play_context.port == 4321
    assert play_context.no_log is True
    assert play_context.become is True
    assert play_context.become_method == "mocktask"
    assert play_context.become_user == "mocktaskroot"
    assert play_context.become_pass == "mocktaskpass"

    mock_task.no_log = False
    play_context = play_context.set_task_and_variable_override(task=mock_task, variables=all_vars, templar=mock_templar)
    assert play_context.no_log is False
Example #47
0
    def test_play_context_make_become_cmd(self):
        (options, args) = self._parser.parse_args([])
        play_context = PlayContext(options=options)

        default_cmd = "/bin/foo"
        default_exe = "/bin/bash"
        sudo_exe = C.DEFAULT_SUDO_EXE or 'sudo'
        sudo_flags = C.DEFAULT_SUDO_FLAGS
        su_exe = C.DEFAULT_SU_EXE or 'su'
        su_flags = C.DEFAULT_SU_FLAGS or ''
        pbrun_exe = 'pbrun'
        pbrun_flags = ''
        pfexec_exe = 'pfexec'
        pfexec_flags = ''
        doas_exe = 'doas'
        doas_flags = ' -n  -u foo '

        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable=default_exe)
        self.assertEqual(cmd, default_cmd)

        play_context.become = True
        play_context.become_user = '******'

        play_context.become_method = 'sudo'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable="/bin/bash")
        self.assertEqual(
            cmd, """%s %s -u %s %s -c 'echo %s; %s'""" %
            (sudo_exe, sudo_flags, play_context.become_user, default_exe,
             play_context.success_key, default_cmd))
        play_context.become_pass = '******'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable=default_exe)
        self.assertEqual(
            cmd, """%s %s -p "%s" -u %s %s -c 'echo %s; %s'""" %
            (sudo_exe, sudo_flags.replace(
                '-n', ''), play_context.prompt, play_context.become_user,
             default_exe, play_context.success_key, default_cmd))

        play_context.become_pass = None

        play_context.become_method = 'su'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable="/bin/bash")
        self.assertEqual(
            cmd, """%s  %s -c '%s -c '"'"'echo %s; %s'"'"''""" %
            (su_exe, play_context.become_user, default_exe,
             play_context.success_key, default_cmd))

        play_context.become_method = 'pbrun'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable="/bin/bash")
        self.assertEqual(
            cmd, """%s -b %s -u %s 'echo %s; %s'""" %
            (pbrun_exe, pbrun_flags, play_context.become_user,
             play_context.success_key, default_cmd))

        play_context.become_method = 'pfexec'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable="/bin/bash")
        self.assertEqual(
            cmd, '''%s %s "'echo %s; %s'"''' %
            (pfexec_exe, pfexec_flags, play_context.success_key, default_cmd))

        play_context.become_method = 'doas'
        cmd = play_context.make_become_cmd(cmd=default_cmd,
                                           executable="/bin/bash")
        self.assertEqual(
            cmd, """%s %s echo %s && %s %s env ANSIBLE=true %s""" %
            (doas_exe, doas_flags, play_context.success_key, doas_exe,
             doas_flags, default_cmd))

        play_context.become_method = 'bad'
        self.assertRaises(AnsibleError,
                          play_context.make_become_cmd,
                          cmd=default_cmd,
                          executable="/bin/bash")