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
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")
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)
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')
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
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')
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')
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'])
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)
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)
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)
def test_network_cli__no_os(self): pc = PlayContext() pc.network_os = None self.assertRaises(AnsibleConnectionFailure, connection_loader.get, 'network_cli', pc, '/dev/null')
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)
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)
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)
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()])
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)
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')
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')
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 plugin(): task = FakeTask('openshift_health_check', {'checks': ['fake_check']}) plugin = ActionModule(task, None, PlayContext(), None, None, None) return plugin
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))
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')
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')
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')
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))
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'])
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))
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')
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
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", "")
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, {})
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
def setUp(self): self.play_context = PlayContext() self.play_context.prompt = ( '[sudo via ansible, key=ouzmdnewuhucvuaabtjmweasarviygqq] password: ' ) self.in_stream = StringIO()
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
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_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")