def test_ansible_module_call(self): """ Test Ansible module call from ansible gate module :return: """ class Module(object): """ An ansible module mock. """ __name__ = "one.two.three" __file__ = "foofile" def main(): # pylint: disable=no-method-argument pass ANSIBLE_MODULE_ARGS = '{"ANSIBLE_MODULE_ARGS": ["arg_1", {"kwarg1": "foobar"}]}' proc = MagicMock(side_effect=[ MockTimedProc(stdout=ANSIBLE_MODULE_ARGS.encode(), stderr=None), MockTimedProc(stdout='{"completed": true}'.encode(), stderr=None), ]) with patch.object(ansible, "_resolver", self.resolver), patch.object( ansible._resolver, "load_module", MagicMock(return_value=Module())): _ansible_module_caller = ansible.AnsibleModuleCaller( ansible._resolver) with patch("salt.utils.timed_subprocess.TimedProc", proc): ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar") proc.assert_any_call( [sys.executable, "foofile"], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200, ) try: proc.assert_any_call( [ "echo", '{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}', ], stdout=-1, timeout=1200, ) except AssertionError: proc.assert_any_call( [ "echo", '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}', ], stdout=-1, timeout=1200, ) assert ret == {"completed": True, "timeout": 1200}
def test_ansible_module_call(self): ''' Test Ansible module call from ansible gate module :return: ''' class Module(object): ''' An ansible module mock. ''' __name__ = 'one.two.three' __file__ = 'foofile' def main(): pass ANSIBLE_MODULE_ARGS = '{"ANSIBLE_MODULE_ARGS": ["arg_1", {"kwarg1": "foobar"}]}' proc = MagicMock(side_effect=[ MockTimedProc(stdout=ANSIBLE_MODULE_ARGS.encode(), stderr=None), MockTimedProc(stdout='{"completed": true}'.encode(), stderr=None) ]) with patch.object(ansible, '_resolver', self.resolver), \ patch.object(ansible._resolver, 'load_module', MagicMock(return_value=Module())): _ansible_module_caller = ansible.AnsibleModuleCaller( ansible._resolver) with patch('salt.utils.timed_subprocess.TimedProc', proc): ret = _ansible_module_caller.call("one.two.three", "arg_1", kwarg1="foobar") if six.PY3: proc.assert_any_call(['python3', 'foofile'], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200) else: proc.assert_any_call(['python', 'foofile'], stdin=ANSIBLE_MODULE_ARGS, stdout=-1, timeout=1200) try: proc.assert_any_call([ 'echo', '{"ANSIBLE_MODULE_ARGS": {"kwarg1": "foobar", "_raw_params": "arg_1"}}' ], stdout=-1, timeout=1200) except AssertionError: proc.assert_any_call([ 'echo', '{"ANSIBLE_MODULE_ARGS": {"_raw_params": "arg_1", "kwarg1": "foobar"}}' ], stdout=-1, timeout=1200) assert ret == {"completed": True, "timeout": 1200}
def test_cve_2021_25284(caplog): proc = MagicMock( return_value=MockTimedProc(stdout=b"foo", stderr=b"wtf", returncode=2)) with patch("salt.utils.timed_subprocess.TimedProc", proc): with caplog.at_level(logging.DEBUG, logger="salt.modules.cmdmod"): cmdmod.run("testcmd -p ImAPassword", output_loglevel="error") assert "ImAPassword" not in caplog.text
def test_run_all_binary_replace(self): ''' Test for failed decoding of binary data, for instance when doing something silly like using dd to read from /dev/urandom and write to /dev/stdout. ''' # Since we're using unicode_literals, read the random bytes from a file rand_bytes_file = os.path.join(FILES, 'file', 'base', 'random_bytes') with salt.utils.files.fopen(rand_bytes_file, 'rb') as fp_: stdout_bytes = fp_.read() # kitchen-salt uses unix2dos on all the files before copying them over # to the vm that will be running the tests. It skips binary files though # The file specified in `rand_bytes_file` is detected as binary so the # Unix-style line ending remains. This should account for that. stdout_bytes = stdout_bytes.rstrip() + os.linesep.encode() # stdout with the non-decodable bits replaced with the unicode # replacement character U+FFFD. stdout_unicode = '\ufffd\x1b\ufffd\ufffd' + os.linesep stderr_bytes = os.linesep.encode().join([ b'1+0 records in', b'1+0 records out', b'4 bytes copied, 9.1522e-05 s, 43.7 kB/s' ]) + os.linesep.encode() stderr_unicode = stderr_bytes.decode() proc = MagicMock(return_value=MockTimedProc(stdout=stdout_bytes, stderr=stderr_bytes)) with patch('salt.utils.timed_subprocess.TimedProc', proc): ret = cmdmod.run_all( 'dd if=/dev/urandom of=/dev/stdout bs=4 count=1', rstrip=False) self.assertEqual(ret['stdout'], stdout_unicode) self.assertEqual(ret['stderr'], stderr_unicode)
def test_run_all_binary_replace(): """ Test for failed decoding of binary data, for instance when doing something silly like using dd to read from /dev/urandom and write to /dev/stdout. """ # Since we're using unicode_literals, read the random bytes from a file rand_bytes_file = os.path.join(RUNTIME_VARS.BASE_FILES, "random_bytes") with salt.utils.files.fopen(rand_bytes_file, "rb") as fp_: stdout_bytes = fp_.read() # kitchen-salt uses unix2dos on all the files before copying them over # to the vm that will be running the tests. It skips binary files though # The file specified in `rand_bytes_file` is detected as binary so the # Unix-style line ending remains. This should account for that. stdout_bytes = stdout_bytes.rstrip() + os.linesep.encode() # stdout with the non-decodable bits replaced with the unicode # replacement character U+FFFD. stdout_unicode = "\ufffd\x1b\ufffd\ufffd" + os.linesep stderr_bytes = (os.linesep.encode().join([ b"1+0 records in", b"1+0 records out", b"4 bytes copied, 9.1522e-05 s, 43.7 kB/s", ]) + os.linesep.encode()) stderr_unicode = stderr_bytes.decode() proc = MagicMock( return_value=MockTimedProc(stdout=stdout_bytes, stderr=stderr_bytes)) with patch("salt.utils.timed_subprocess.TimedProc", proc): ret = cmdmod.run_all("dd if=/dev/urandom of=/dev/stdout bs=4 count=1", rstrip=False) assert ret["stdout"] == stdout_unicode assert ret["stderr"] == stderr_unicode
def test_run_all_none(): """ Tests cases when proc.stdout or proc.stderr are None. These should be caught and replaced with empty strings. """ proc = MagicMock(return_value=MockTimedProc(stdout=None, stderr=None)) with patch("salt.utils.timed_subprocess.TimedProc", proc): ret = cmdmod.run_all("some command", rstrip=False) assert ret["stdout"] == "" assert ret["stderr"] == ""
def test_run_all_none(self): ''' Tests cases when proc.stdout or proc.stderr are None. These should be caught and replaced with empty strings. ''' proc = MagicMock(return_value=MockTimedProc(stdout=None, stderr=None)) with patch('salt.utils.timed_subprocess.TimedProc', proc): ret = cmdmod.run_all('some command', rstrip=False) self.assertEqual(ret['stdout'], '') self.assertEqual(ret['stderr'], '')
def test_bootout_retcode_36_success(self): """ Make sure that if we run a `launchctl bootout` cmd and it returns 36 that we treat it as a success. """ proc = MagicMock(return_value=MockTimedProc( stdout=None, stderr=None, returncode=36)) with patch("salt.utils.timed_subprocess.TimedProc", proc): with patch("salt.utils.mac_utils.__salt__", {"cmd.run_all": cmd._run_all_quiet}): ret = mac_utils.launchctl("bootout", "org.salt.minion") self.assertEqual(ret, True)
def test_run_all_output_encoding(self): ''' Test that specifying the output encoding works as expected ''' stdout = 'Æ' stdout_latin1_enc = stdout.encode('latin1') proc = MagicMock(return_value=MockTimedProc(stdout=stdout_latin1_enc)) with patch('salt.utils.timed_subprocess.TimedProc', proc), \ patch.object(builtins, '__salt_system_encoding__', 'utf-8'): ret = cmdmod.run_all('some command', output_encoding='latin1') self.assertEqual(ret['stdout'], stdout)
def test_run_all_output_loglevel_debug(caplog): """ Test that specifying debug for loglevel does log the command. """ stdout = b"test" proc = MagicMock(return_value=MockTimedProc(stdout=stdout)) msg = "Executing command 'some' in directory" with patch("salt.utils.timed_subprocess.TimedProc", proc): with caplog.at_level(logging.DEBUG, logger="salt.modules.cmdmod"): ret = cmdmod.run_all("some command", output_loglevel="debug") assert msg in caplog.text assert ret["stdout"] == salt.utils.stringutils.to_unicode(stdout)
def test_run_all_output_encoding(): """ Test that specifying the output encoding works as expected """ stdout = "Æ" stdout_latin1_enc = stdout.encode("latin1") proc = MagicMock(return_value=MockTimedProc(stdout=stdout_latin1_enc)) with patch("salt.utils.timed_subprocess.TimedProc", proc), patch.object(builtins, "__salt_system_encoding__", "utf-8"): ret = cmdmod.run_all("some command", output_encoding="latin1") assert ret["stdout"] == stdout
def test_run_all_output_loglevel_debug(self): """ Test that specifying debug for loglevel does log the command. """ stdout = b"test" proc = MagicMock(return_value=MockTimedProc(stdout=stdout)) msg = "INFO:Executing command 'some command' in directory" with patch("salt.utils.timed_subprocess.TimedProc", proc): with TstSuiteLoggingHandler() as log_handler: ret = cmdmod.run_all("some command", output_loglevel="debug") assert [x for x in log_handler.messages if msg in x] self.assertEqual(ret["stdout"], salt.utils.stringutils.to_unicode(stdout))
def test_run_all_output_loglevel_quiet(self): ''' Test that specifying quiet for loglevel does not log the command. ''' stdout = b'test' proc = MagicMock(return_value=MockTimedProc(stdout=stdout)) msg = "INFO:Executing command 'some command' in directory" with patch('salt.utils.timed_subprocess.TimedProc', proc): with TstSuiteLoggingHandler() as log_handler: ret = cmdmod.run_all('some command', output_loglevel='quiet') assert not [x for x in log_handler.messages if msg in x] self.assertEqual(ret['stdout'], salt.utils.stringutils.to_unicode(stdout))
def test_run_all_unicode(self): ''' Ensure that unicode stdout and stderr are decoded properly ''' stdout_unicode = 'Here is some unicode: спам' stderr_unicode = 'Here is some unicode: яйца' stdout_bytes = stdout_unicode.encode('utf-8') stderr_bytes = stderr_unicode.encode('utf-8') proc = MagicMock(return_value=MockTimedProc(stdout=stdout_bytes, stderr=stderr_bytes)) with patch('salt.utils.timed_subprocess.TimedProc', proc), \ patch.object(builtins, '__salt_system_encoding__', 'utf-8'): ret = cmdmod.run_all('some command', rstrip=False) self.assertEqual(ret['stdout'], stdout_unicode) self.assertEqual(ret['stderr'], stderr_unicode)
def test_bootout_retcode_99_fail(self): """ Make sure that if we run a `launchctl bootout` cmd and it returns something other than 0 or 36 that we treat it as a fail. """ error = ("Failed to bootout service:\n" "stdout: failure\n" "stderr: test failure\n" "retcode: 99") proc = MagicMock(return_value=MockTimedProc( stdout=b"failure", stderr=b"test failure", returncode=99)) with patch("salt.utils.timed_subprocess.TimedProc", proc): with patch("salt.utils.mac_utils.__salt__", {"cmd.run_all": cmd._run_all_quiet}): try: mac_utils.launchctl("bootout", "org.salt.minion") except CommandExecutionError as exc: self.assertEqual(exc.message, error)
def test_not_bootout_retcode_36_fail(self): """ Make sure that if we get a retcode 36 on non bootout cmds that we still get a failure. """ error = ("Failed to bootstrap service:\n" "stdout: failure\n" "stderr: test failure\n" "retcode: 36") proc = MagicMock(return_value=MockTimedProc( stdout=b"failure", stderr=b"test failure", returncode=36)) with patch("salt.utils.timed_subprocess.TimedProc", proc): with patch("salt.utils.mac_utils.__salt__", {"cmd.run_all": cmd._run_all_quiet}): try: mac_utils.launchctl("bootstrap", "org.salt.minion") except CommandExecutionError as exc: self.assertEqual(exc.message, error)
def test_run_all_unicode(): """ Ensure that unicode stdout and stderr are decoded properly """ stdout_unicode = "Here is some unicode: спам" stderr_unicode = "Here is some unicode: яйца" stdout_bytes = stdout_unicode.encode("utf-8") stderr_bytes = stderr_unicode.encode("utf-8") proc = MagicMock( return_value=MockTimedProc(stdout=stdout_bytes, stderr=stderr_bytes)) with patch("salt.utils.timed_subprocess.TimedProc", proc), patch.object(builtins, "__salt_system_encoding__", "utf-8"): ret = cmdmod.run_all("some command", rstrip=False) assert ret["stdout"] == stdout_unicode assert ret["stderr"] == stderr_unicode
def mock_proc(__cmd__, **kwargs): cmd_handler.cmd = " ".join(__cmd__) return MagicMock(return_value=MockTimedProc(stdout=None, stderr=None))