def test_udevadm_fails(self): '''Test user_data_rhevm() where udevadm fails.''' self.m_udevadm_settle.side_effect = subp.ProcessExecutionError( "Failed settle.") dsrc = dsac.DataSourceAltCloud({}, None, self.paths) self.assertEqual(False, dsrc.user_data_rhevm())
def test_lock_exception_wait(self, m_sleep, m_apt_avail, m_subp, m_which): exception = subp.ProcessExecutionError( exit_code=100, stderr="Could not get apt lock" ) m_subp.side_effect = [exception, exception, "return_thing"] ret = self.distro._wait_for_apt_command("stub", {"args": "stub2"}) assert ret == "return_thing"
def test_no_retries_on_none(self, m_subp, m_sleep): """retry should not be done if retries is None.""" m_subp.side_effect = subp.ProcessExecutionError( stdout='', stderr='', exit_code=2, cmd=['mycmd']) with self.assertRaises(ValueError): gpg.recv_key("ABCD", "keyserver.example.com", retries=None) m_sleep.assert_not_called()
def test_no_modprobe_cmd(self): '''Test user_data_rhevm() with no modprobe command.''' self.m_modprobe_floppy.side_effect = subp.ProcessExecutionError( "No such file or dir") dsrc = dsac.DataSourceAltCloud({}, None, self.paths) self.assertEqual(False, dsrc.user_data_rhevm())
def test_get_device_info_from_zpool_handles_no_zpool(self, m_sub, m_os): """Handle case where there is no zpool command""" # mock /dev/zfs exists m_os.path.exists.return_value = True m_sub.side_effect = subp.ProcessExecutionError("No zpool cmd") ret = util.get_device_info_from_zpool('vmzroot') self.assertIsNone(ret)
def test_modprobe_fails(self): '''Test user_data_rhevm() where modprobe fails.''' self.m_modprobe_floppy.side_effect = subp.ProcessExecutionError( "Failed modprobe") dsrc = dsac.DataSourceAltCloud({}, None, self.paths) self.assertEqual(False, dsrc.user_data_rhevm())
def fake_subp(cmd, capture=None): fail_cmds = [["ua", "enable", "--assume-yes", svc] for svc in ["esm", "cc"]] if cmd in fail_cmds and capture: svc = cmd[-1] raise subp.ProcessExecutionError( "Invalid {} credentials".format(svc.upper()))
def test_notfound_and_warns_on_unexpected_exit_code(self, m_subp, m_which): """If vmware-rpctool exits non zero or 1, warnings should be logged.""" m_which.return_value = self.rpctool_path m_subp.side_effect = subp.ProcessExecutionError( stdout=None, stderr="No value found", exit_code=2, cmd=["unused"]) self.assertEqual(NOT_FOUND, dsovf.transport_vmware_guestinfo()) self.assertEqual(1, m_subp.call_count) self.assertIn("WARNING", self.logs.getvalue(), "exit code of 2 by rpctool should log WARNING.")
def test_pexec_error_empty_msgs(self): error = subp.ProcessExecutionError() self.assertTrue(all(attr == self.empty_attr for attr in (error.stderr, error.stdout, error.reason))) self.assertEqual(error.description, self.empty_description) self.assertEqual(str(error), self.template.format( description=self.empty_description, exit_code=self.empty_attr, reason=self.empty_attr, stdout=self.empty_attr, stderr=self.empty_attr, cmd=self.empty_attr))
def test_pexec_error_indent_text(self): error = subp.ProcessExecutionError() msg = 'abc\ndef' formatted = 'abc\n{0}def'.format(' ' * 4) self.assertEqual(error._indent_text(msg, indent_level=4), formatted) self.assertEqual(error._indent_text(msg.encode(), indent_level=4), formatted.encode()) self.assertIsInstance(error._indent_text(msg.encode()), type(msg.encode()))
def test_retries_on_subp_exc(self, m_subp, m_sleep): """retry should be done on gpg receive keys failure.""" retries = (1, 2, 4) my_exc = subp.ProcessExecutionError( stdout='', stderr='', exit_code=2, cmd=['mycmd']) m_subp.side_effect = (my_exc, my_exc, ('', '')) gpg.recv_key("ABCD", "keyserver.example.com", retries=retries) self.assertEqual( [mock.call(1), mock.call(2)], m_sleep.call_args_list)
def test_notfound_on_exit_code_1(self, m_subp, m_which): """If vmware-rpctool exits 1, then must return not found.""" m_which.return_value = self.rpctool_path m_subp.side_effect = subp.ProcessExecutionError( stdout="", stderr="No value found", exit_code=1, cmd=["unused"]) self.assertEqual(NOT_FOUND, dsovf.transport_vmware_guestinfo()) self.assertEqual(1, m_subp.call_count) self.assertNotIn( "WARNING", self.logs.getvalue(), "exit code of 1 by rpctool should not cause warning.")
def test_lock_exception_timeout( self, m_time, m_sleep, m_apt_avail, m_subp, m_which ): m_subp.side_effect = subp.ProcessExecutionError( exit_code=100, stderr="Could not get apt lock" ) with pytest.raises(TimeoutError): self.distro._wait_for_apt_command( "stub", {"args": "stub2"}, timeout=5 )
def test_pexec_error_single_line_msgs(self): stdout_msg = 'out out' stderr_msg = 'error error' cmd = 'test command' exit_code = 3 error = subp.ProcessExecutionError( stdout=stdout_msg, stderr=stderr_msg, exit_code=3, cmd=cmd) self.assertEqual(str(error), self.template.format( description=self.empty_description, stdout=stdout_msg, stderr=stderr_msg, exit_code=str(exit_code), reason=self.empty_attr, cmd=cmd))
def test_configure_ua_attach_error(self, m_subp): """Errors from ua attach command are raised.""" m_subp.side_effect = subp.ProcessExecutionError( 'Invalid token SomeToken') with self.assertRaises(RuntimeError) as context_manager: configure_ua(token='SomeToken') self.assertEqual( 'Failure attaching Ubuntu Advantage:\nUnexpected error while' ' running command.\nCommand: -\nExit code: -\nReason: -\n' 'Stdout: Invalid token SomeToken\nStderr: -', str(context_manager.exception))
def test_raises_error_after_retries(self, m_subp, m_sleep): """If the final run fails, error should be raised.""" naplen = 1 keyid, keyserver = ("ABCD", "keyserver.example.com") m_subp.side_effect = subp.ProcessExecutionError( stdout='', stderr='', exit_code=2, cmd=['mycmd']) with self.assertRaises(ValueError) as rcm: gpg.recv_key(keyid, keyserver, retries=(naplen,)) self.assertIn(keyid, str(rcm.exception)) self.assertIn(keyserver, str(rcm.exception)) m_sleep.assert_called_with(naplen)
def test_get_tools_config_internal_exception(self): """ This test is designed to verify the behavior if internal exception is raised. """ with mock.patch.object(subp, 'which', return_value='/dummy/path'): with mock.patch.object(subp, 'subp', return_value=('key=value', b''), side_effect=subp.ProcessExecutionError( "subp failed", exit_code=99)): # verify return value is 'defaultVal', not 'value'. self.assertEqual( get_tools_config('section', 'key', 'defaultVal'), 'defaultVal')
def test_get_tools_config_internal_exception(self): """ This test is designed to verify the behavior if internal exception is raised. """ with mock.patch.object(subp, "which", return_value="/dummy/path"): with mock.patch.object( subp, "subp", return_value=SubpResult("key=value", b""), side_effect=subp.ProcessExecutionError("subp failed", exit_code=99), ): # verify return value is 'defaultVal', not 'value'. self.assertEqual( get_tools_config("section", "key", "defaultVal"), "defaultVal", )
def test_pexec_error_multi_line_msgs(self): # make sure bytes is converted handled properly when formatting stdout_msg = 'multi\nline\noutput message'.encode() stderr_msg = 'multi\nline\nerror message\n\n\n' error = subp.ProcessExecutionError(stdout=stdout_msg, stderr=stderr_msg) self.assertEqual( str(error), '\n'.join(( '{description}', 'Command: {empty_attr}', 'Exit code: {empty_attr}', 'Reason: {empty_attr}', 'Stdout: multi', ' line', ' output message', 'Stderr: multi', ' line', ' error message', )).format(description=self.empty_description, empty_attr=self.empty_attr))
def test_pexec_error_type(self): self.assertIsInstance(subp.ProcessExecutionError(), IOError)
def fake_subp(cmd, capture=None): fail_cmds = [['ua', 'enable', svc] for svc in ['esm', 'cc']] if cmd in fail_cmds and capture: svc = cmd[-1] raise subp.ProcessExecutionError( 'Invalid {} credentials'.format(svc.upper()))
class TestRbxDataSource(CiTestCase): parsed_user = None allowed_subp = ['bash'] def _fetch_distro(self, kind): cls = distros.fetch(kind) paths = helpers.Paths({}) return cls(kind, {}, paths) def setUp(self): super(TestRbxDataSource, self).setUp() self.tmp = self.tmp_dir() self.paths = helpers.Paths({ 'cloud_dir': self.tmp, 'run_dir': self.tmp }) # defaults for few tests self.ds = ds.DataSourceRbxCloud self.seed_dir = self.paths.seed_dir self.sys_cfg = {'datasource': {'RbxCloud': {'dsmode': 'local'}}} def test_seed_read_user_data_callback_empty_file(self): populate_user_metadata(self.seed_dir, '') populate_cloud_metadata(self.seed_dir, {}) results = ds.read_user_data_callback(self.seed_dir) self.assertIsNone(results) def test_seed_read_user_data_callback_valid_disk(self): populate_user_metadata(self.seed_dir, '') populate_cloud_metadata(self.seed_dir, CLOUD_METADATA) results = ds.read_user_data_callback(self.seed_dir) self.assertNotEqual(results, None) self.assertTrue('userdata' in results) self.assertTrue('metadata' in results) self.assertTrue('cfg' in results) def test_seed_read_user_data_callback_userdata(self): userdata = "#!/bin/sh\nexit 1" populate_user_metadata(self.seed_dir, userdata) populate_cloud_metadata(self.seed_dir, CLOUD_METADATA) results = ds.read_user_data_callback(self.seed_dir) self.assertNotEqual(results, None) self.assertTrue('userdata' in results) self.assertEqual(results['userdata'], userdata) def test_generate_network_config(self): expected = { 'version': 1, 'config': [{ 'subnets': [{ 'control': 'auto', 'dns_nameservers': ['8.8.8.8', '8.8.4.4'], 'netmask': '255.255.248.0', 'address': '62.181.8.174', 'type': 'static', 'gateway': '62.181.8.1' }], 'type': 'physical', 'name': 'eth0', 'mac_address': '00:15:5d:ff:0f:03' }, { 'subnets': [{ 'control': 'auto', 'dns_nameservers': ['9.9.9.9', '8.8.8.8'], 'netmask': '255.255.255.0', 'address': '10.209.78.11', 'type': 'static', 'gateway': '10.209.78.1' }], 'type': 'physical', 'name': 'eth1', 'mac_address': '00:15:5d:ff:0f:24' }] } self.assertTrue(ds.generate_network_config(CLOUD_METADATA['netadp']), expected) @mock.patch(DS_PATH + '.subp.subp') def test_gratuitous_arp_run_standard_arping(self, m_subp): """Test handle run arping & parameters.""" items = [ { 'destination': '172.17.0.2', 'source': '172.16.6.104' }, { 'destination': '172.17.0.2', 'source': '172.16.6.104', }, ] ds.gratuitous_arp(items, self._fetch_distro('ubuntu')) self.assertEqual([ mock.call( ['arping', '-c', '2', '-S', '172.16.6.104', '172.17.0.2']), mock.call( ['arping', '-c', '2', '-S', '172.16.6.104', '172.17.0.2']) ], m_subp.call_args_list) @mock.patch(DS_PATH + '.subp.subp') def test_handle_rhel_like_arping(self, m_subp): """Test handle on RHEL-like distros.""" items = [{ 'source': '172.16.6.104', 'destination': '172.17.0.2', }] ds.gratuitous_arp(items, self._fetch_distro('fedora')) self.assertEqual([ mock.call( ['arping', '-c', '2', '-s', '172.16.6.104', '172.17.0.2']) ], m_subp.call_args_list) @mock.patch(DS_PATH + '.subp.subp', side_effect=subp.ProcessExecutionError()) def test_continue_on_arping_error(self, m_subp): """Continue when command error""" items = [ { 'destination': '172.17.0.2', 'source': '172.16.6.104' }, { 'destination': '172.17.0.2', 'source': '172.16.6.104', }, ] ds.gratuitous_arp(items, self._fetch_distro('ubuntu')) self.assertEqual([ mock.call( ['arping', '-c', '2', '-S', '172.16.6.104', '172.17.0.2']), mock.call( ['arping', '-c', '2', '-S', '172.16.6.104', '172.17.0.2']) ], m_subp.call_args_list)
class TestRbxDataSource(CiTestCase): parsed_user = None allowed_subp = ["bash"] def _fetch_distro(self, kind): cls = distros.fetch(kind) paths = helpers.Paths({}) return cls(kind, {}, paths) def setUp(self): super(TestRbxDataSource, self).setUp() self.tmp = self.tmp_dir() self.paths = helpers.Paths({ "cloud_dir": self.tmp, "run_dir": self.tmp }) # defaults for few tests self.ds = ds.DataSourceRbxCloud self.seed_dir = self.paths.seed_dir self.sys_cfg = {"datasource": {"RbxCloud": {"dsmode": "local"}}} def test_seed_read_user_data_callback_empty_file(self): populate_user_metadata(self.seed_dir, "") populate_cloud_metadata(self.seed_dir, {}) results = ds.read_user_data_callback(self.seed_dir) self.assertIsNone(results) def test_seed_read_user_data_callback_valid_disk(self): populate_user_metadata(self.seed_dir, "") populate_cloud_metadata(self.seed_dir, CLOUD_METADATA) results = ds.read_user_data_callback(self.seed_dir) self.assertNotEqual(results, None) self.assertTrue("userdata" in results) self.assertTrue("metadata" in results) self.assertTrue("cfg" in results) def test_seed_read_user_data_callback_userdata(self): userdata = "#!/bin/sh\nexit 1" populate_user_metadata(self.seed_dir, userdata) populate_cloud_metadata(self.seed_dir, CLOUD_METADATA) results = ds.read_user_data_callback(self.seed_dir) self.assertNotEqual(results, None) self.assertTrue("userdata" in results) self.assertEqual(results["userdata"], userdata) def test_generate_network_config(self): expected = { "version": 1, "config": [ { "subnets": [{ "control": "auto", "dns_nameservers": ["8.8.8.8", "8.8.4.4"], "netmask": "255.255.248.0", "address": "62.181.8.174", "type": "static", "gateway": "62.181.8.1", }], "type": "physical", "name": "eth0", "mac_address": "00:15:5d:ff:0f:03", }, { "subnets": [{ "control": "auto", "dns_nameservers": ["9.9.9.9", "8.8.8.8"], "netmask": "255.255.255.0", "address": "10.209.78.11", "type": "static", "gateway": "10.209.78.1", }], "type": "physical", "name": "eth1", "mac_address": "00:15:5d:ff:0f:24", }, ], } self.assertTrue(ds.generate_network_config(CLOUD_METADATA["netadp"]), expected) @mock.patch(DS_PATH + ".subp.subp") def test_gratuitous_arp_run_standard_arping(self, m_subp): """Test handle run arping & parameters.""" items = [ { "destination": "172.17.0.2", "source": "172.16.6.104" }, { "destination": "172.17.0.2", "source": "172.16.6.104", }, ] ds.gratuitous_arp(items, self._fetch_distro("ubuntu")) self.assertEqual( [ mock.call( ["arping", "-c", "2", "-S", "172.16.6.104", "172.17.0.2"]), mock.call( ["arping", "-c", "2", "-S", "172.16.6.104", "172.17.0.2"]), ], m_subp.call_args_list, ) @mock.patch(DS_PATH + ".subp.subp") def test_handle_rhel_like_arping(self, m_subp): """Test handle on RHEL-like distros.""" items = [{ "source": "172.16.6.104", "destination": "172.17.0.2", }] ds.gratuitous_arp(items, self._fetch_distro("fedora")) self.assertEqual( [ mock.call( ["arping", "-c", "2", "-s", "172.16.6.104", "172.17.0.2"]) ], m_subp.call_args_list, ) @mock.patch(DS_PATH + ".subp.subp", side_effect=subp.ProcessExecutionError()) def test_continue_on_arping_error(self, m_subp): """Continue when command error""" items = [ { "destination": "172.17.0.2", "source": "172.16.6.104" }, { "destination": "172.17.0.2", "source": "172.16.6.104", }, ] ds.gratuitous_arp(items, self._fetch_distro("ubuntu")) self.assertEqual( [ mock.call( ["arping", "-c", "2", "-S", "172.16.6.104", "172.17.0.2"]), mock.call( ["arping", "-c", "2", "-S", "172.16.6.104", "172.17.0.2"]), ], m_subp.call_args_list, )
def _subp_side_effect(value, **kwargs): if value[0] == "dmsetup": raise subp.ProcessExecutionError()
def _subp_side_effect(value, **kwargs): if value[0] == "dmsetup": return ("1 dependencies : (vdx1)", ) elif value[0] == "cryptsetup" and "resize" in value: raise subp.ProcessExecutionError() return mock.Mock()
def _dmidecode_subp(cmd): if cmd[-1] != key: raise subp.ProcessExecutionError() return (content, error)
def _kenv_subp(cmd): if cmd[-1] != dmi.DMIDECODE_TO_KERNEL[key].freebsd: raise subp.ProcessExecutionError() return (content, error)
class TestHandleSSHPwauth: @pytest.mark.parametrize( "uses_systemd,cmd", ( (True, ["systemctl", "status", "ssh"]), (False, ["service", "ssh", "status"]), ), ) @mock.patch("cloudinit.distros.subp.subp") def test_unknown_value_logs_warning( self, m_subp, uses_systemd, cmd, caplog ): cloud = get_cloud("ubuntu") with mock.patch.object( cloud.distro, "uses_systemd", return_value=uses_systemd ): setpass.handle_ssh_pwauth("floo", cloud.distro) assert "Unrecognized value: ssh_pwauth=floo" in caplog.text assert [mock.call(cmd, capture=True)] == m_subp.call_args_list @pytest.mark.parametrize( "uses_systemd,ssh_updated,cmd,expected_log", ( ( True, True, ["systemctl", "restart", "ssh"], "Restarted the SSH daemon.", ), ( True, False, ["systemctl", "status", "ssh"], "No need to restart SSH", ), ( False, True, ["service", "ssh", "restart"], "Restarted the SSH daemon.", ), ( False, False, ["service", "ssh", "status"], "No need to restart SSH", ), ), ) @mock.patch(MODPATH + "update_ssh_config") @mock.patch("cloudinit.distros.subp.subp") def test_restart_ssh_only_when_changes_made_and_ssh_installed( self, m_subp, update_ssh_config, uses_systemd, ssh_updated, cmd, expected_log, caplog, ): update_ssh_config.return_value = ssh_updated cloud = get_cloud("ubuntu") with mock.patch.object( cloud.distro, "uses_systemd", return_value=uses_systemd ): setpass.handle_ssh_pwauth(True, cloud.distro) if ssh_updated: m_subp.assert_called_with(cmd, capture=True) else: assert [mock.call(cmd, capture=True)] == m_subp.call_args_list assert expected_log in "\n".join( r.msg for r in caplog.records if r.levelname == "DEBUG" ) @mock.patch(MODPATH + "update_ssh_config", return_value=True) @mock.patch("cloudinit.distros.subp.subp") def test_unchanged_value_does_nothing( self, m_subp, update_ssh_config, mock_uses_systemd ): """If 'unchanged', then no updates to config and no restart.""" update_ssh_config.assert_not_called() cloud = get_cloud("ubuntu") setpass.handle_ssh_pwauth("unchanged", cloud.distro) assert [ mock.call(["systemctl", "status", "ssh"], capture=True) ] == m_subp.call_args_list @pytest.mark.allow_subp_for("systemctl") @mock.patch("cloudinit.distros.subp.subp") def test_valid_value_changes_updates_ssh(self, m_subp, mock_uses_systemd): """If value is a valid changed value, then update will be called.""" cloud = get_cloud("ubuntu") upname = MODPATH + "update_ssh_config" optname = "PasswordAuthentication" for n, value in enumerate(util.FALSE_STRINGS + util.TRUE_STRINGS, 1): optval = "yes" if value in util.TRUE_STRINGS else "no" with mock.patch(upname, return_value=False) as m_update: setpass.handle_ssh_pwauth(value, cloud.distro) assert ( mock.call({optname: optval}) == m_update.call_args_list[-1] ) assert m_subp.call_count == n @pytest.mark.parametrize( [ "uses_systemd", "raised_error", "warning_log", "debug_logs", "update_ssh_call_count", ], ( ( True, subp.ProcessExecutionError( stderr="Service is not running.", exit_code=3 ), None, [ "Writing config 'ssh_pwauth: True'. SSH service" " 'ssh' will not be restarted because it is stopped.", "Not restarting SSH service: service is stopped.", ], 1, ), ( True, subp.ProcessExecutionError( stderr="Service is not installed.", exit_code=4 ), "Ignoring config 'ssh_pwauth: True'. SSH service 'ssh' is" " not installed.", [], 0, ), ( True, subp.ProcessExecutionError( stderr="Service is not available.", exit_code=2 ), "Ignoring config 'ssh_pwauth: True'. SSH service 'ssh'" " is not available. Error: ", [], 0, ), ( False, subp.ProcessExecutionError( stderr="Service is not available.", exit_code=25 ), None, [ "Writing config 'ssh_pwauth: True'. SSH service" " 'ssh' will not be restarted because it is not running" " or not available.", "Not restarting SSH service: service is stopped.", ], 1, ), ( False, subp.ProcessExecutionError( stderr="Service is not available.", exit_code=3 ), None, [ "Writing config 'ssh_pwauth: True'. SSH service" " 'ssh' will not be restarted because it is not running" " or not available.", "Not restarting SSH service: service is stopped.", ], 1, ), ( False, subp.ProcessExecutionError( stderr="Service is not available.", exit_code=4 ), None, [ "Writing config 'ssh_pwauth: True'. SSH service" " 'ssh' will not be restarted because it is not running" " or not available.", "Not restarting SSH service: service is stopped.", ], 1, ), ), ) @mock.patch(MODPATH + "update_ssh_config", return_value=True) @mock.patch("cloudinit.distros.subp.subp") def test_no_restart_when_service_is_not_running( self, m_subp, m_update_ssh_config, uses_systemd, raised_error, warning_log, debug_logs, update_ssh_call_count, caplog, ): """Write config but don't restart SSH service when not running.""" cloud = get_cloud("ubuntu") cloud.distro.manage_service = mock.Mock(side_effect=raised_error) cloud.distro.uses_systemd = mock.Mock(return_value=uses_systemd) setpass.handle_ssh_pwauth(True, cloud.distro) logs_by_level = {logging.WARNING: [], logging.DEBUG: []} for _, level, msg in caplog.record_tuples: logs_by_level[level].append(msg) if warning_log: assert warning_log in "\n".join( logs_by_level[logging.WARNING] ), logs_by_level for debug_log in debug_logs: assert debug_log in logs_by_level[logging.DEBUG] assert [ mock.call("status", "ssh") ] == cloud.distro.manage_service.call_args_list assert m_update_ssh_config.call_count == update_ssh_call_count assert m_subp.call_count == 0 assert cloud.distro.uses_systemd.call_count == 1
def test_subp_exception_raises_to_caller(self, m_subp): m_subp.side_effect = subp.ProcessExecutionError("BOOM") self.assertRaises(subp.ProcessExecutionError, util.udevadm_settle)
def test_not_is_registered(self, mock_subp): mock_subp.side_effect = subp.ProcessExecutionError(exit_code=1) self.assertFalse(cc_spacewalk.is_registered())