def test_handle_warns_on_undiscoverable_root_path_in_commandline(self): """handle noops when the root path is not found on the commandline.""" cfg = {'resize_rootfs': True} exists_mock_path = 'cloudinit.config.cc_resizefs.os.path.exists' def fake_mount_info(path, log): self.assertEqual('/', path) self.assertEqual(LOG, log) return ('/dev/root', 'ext4', '/') with mock.patch(exists_mock_path) as m_exists: m_exists.return_value = False wrap_and_call('cloudinit.config.cc_resizefs.util', { 'is_container': { 'return_value': False }, 'get_mount_info': { 'side_effect': fake_mount_info }, 'get_cmdline': { 'return_value': 'BOOT_IMAGE=/vmlinuz.efi' } }, handle, 'cc_resizefs', cfg, _cloud=None, log=LOG, args=[]) logs = self.logs.getvalue() self.assertIn("WARNING: Unable to find device '/dev/root'", logs)
def test_status_main(self): """status.main can be run as a standalone script.""" write_json(self.status_file, {"v1": { "init": { "start": 1, "finished": None } }}) with self.assertRaises(SystemExit) as context_manager: with mock.patch("sys.stdout", new_callable=StringIO) as m_stdout: wrap_and_call( "cloudinit.cmd.status", { "sys.argv": { "new": ["status"] }, "_is_cloudinit_disabled": (False, ""), "Init": { "side_effect": self.init_class }, }, status.main, ) self.assertEqual(0, context_manager.exception.code) self.assertEqual("status: running\n", m_stdout.getvalue())
def test_get_data_cloudinit_metadata_not_found(self): """Test metadata file can't be found. """ paths = Paths({'cloud_dir': self.tdir}) ds = self.datasource(sys_cfg={'disable_vmware_customization': True}, distro={}, paths=paths) # Prepare the conf file conf_file = self.tmp_path('test-cust', self.tdir) conf_content = dedent("""\ [CLOUDINIT] METADATA = test-meta """) util.write_file(conf_file, conf_content) # Don't prepare the meta data file with mock.patch(MPATH + 'set_customization_status', return_value=('msg', b'')): with self.assertRaises(FileNotFoundError) as context: wrap_and_call( 'cloudinit.sources.DataSourceOVF', { 'dmi.read_dmi_data': 'vmware', 'util.del_dir': True, 'search_file': self.tdir, 'wait_for_imc_cfg_file': conf_file, 'get_nics_to_enable': '' }, ds.get_data) self.assertIn('is not found', str(context.exception))
def test_handler_writes_merged_provided_cloudconfig_with_defaults(self): """Merge and write options from cloud-config options with defaults.""" # Write empty sparse client.conf file util.write_file(self.conf, "") mycloud = get_cloud("ubuntu") cfg = {"landscape": {"client": {"computer_title": "My PC"}}} expected = { "client": { "log_level": "info", "url": "https://landscape.canonical.com/message-system", "ping_url": "http://landscape.canonical.com/ping", "data_path": "/var/lib/landscape/client", "computer_title": "My PC", } } wrap_and_call( "cloudinit.config.cc_landscape", {"LSC_CLIENT_CFG_FILE": { "new": self.conf }}, cc_landscape.handle, "notimportant", cfg, mycloud, LOG, None, ) self.assertEqual(expected, dict(ConfigObj(self.conf))) self.assertIn( "Wrote landscape config file to {0}".format(self.conf), self.logs.getvalue(), )
def test_handler_installs_client_and_creates_config_file(self): """Write landscape client.conf and install landscape-client.""" mycloud = get_cloud('ubuntu') cfg = {'landscape': {'client': {}}} expected = { 'client': { 'log_level': 'info', 'url': 'https://landscape.canonical.com/message-system', 'ping_url': 'http://landscape.canonical.com/ping', 'data_path': '/var/lib/landscape/client' } } mycloud.distro = mock.MagicMock() wrap_and_call( 'cloudinit.config.cc_landscape', { 'LSC_CLIENT_CFG_FILE': { 'new': self.conf }, 'LS_DEFAULT_FILE': { 'new': self.default_file } }, cc_landscape.handle, 'notimportant', cfg, mycloud, LOG, None) self.assertEqual([mock.call('landscape-client')], mycloud.distro.install_packages.call_args) self.assertEqual(expected, dict(ConfigObj(self.conf))) self.assertIn('Wrote landscape config file to {0}'.format(self.conf), self.logs.getvalue()) default_content = util.load_file(self.default_file) self.assertEqual('RUN=1\n', default_content)
def test_get_data_vmware_customization_enabled(self): """When cloud-init workflow for vmware is enabled via sys_cfg log a message. """ paths = Paths({'cloud_dir': self.tdir}) ds = self.datasource(sys_cfg={'disable_vmware_customization': False}, distro={}, paths=paths) conf_file = self.tmp_path('test-cust', self.tdir) conf_content = dedent("""\ [CUSTOM-SCRIPT] SCRIPT-NAME = test-script [MISC] MARKER-ID = 12345345 """) util.write_file(conf_file, conf_content) with mock.patch(MPATH + 'get_tools_config', return_value='true'): with self.assertRaises(CustomScriptNotFound) as context: wrap_and_call( 'cloudinit.sources.DataSourceOVF', { 'dmi.read_dmi_data': 'vmware', 'util.del_dir': True, 'search_file': self.tdir, 'wait_for_imc_cfg_file': conf_file, 'get_nics_to_enable': '' }, ds.get_data) customscript = self.tmp_path('test-script', self.tdir) self.assertIn('Script %s not found!!' % customscript, str(context.exception))
def test_get_data_cust_script_disabled(self): """If custom script is disabled by VMware tools configuration, raise a RuntimeError. """ paths = Paths({'cloud_dir': self.tdir}) ds = self.datasource(sys_cfg={'disable_vmware_customization': False}, distro={}, paths=paths) # Prepare the conf file conf_file = self.tmp_path('test-cust', self.tdir) conf_content = dedent("""\ [CUSTOM-SCRIPT] SCRIPT-NAME = test-script [MISC] MARKER-ID = 12345346 """) util.write_file(conf_file, conf_content) # Prepare the custom sript customscript = self.tmp_path('test-script', self.tdir) util.write_file(customscript, "This is the post cust script") with mock.patch(MPATH + 'get_tools_config', return_value='invalid'): with mock.patch(MPATH + 'set_customization_status', return_value=('msg', b'')): with self.assertRaises(RuntimeError) as context: wrap_and_call( 'cloudinit.sources.DataSourceOVF', { 'dmi.read_dmi_data': 'vmware', 'util.del_dir': True, 'search_file': self.tdir, 'wait_for_imc_cfg_file': conf_file, 'get_nics_to_enable': '' }, ds.get_data) self.assertIn('Custom script is disabled by VM Administrator', str(context.exception))
def test_status_main(self, m_read_cfg_paths, config: Config): """status.main can be run as a standalone script.""" m_read_cfg_paths.return_value = config.paths write_json( config.status_file, {"v1": { "init": { "start": 1, "finished": None } }}, ) with pytest.raises(SystemExit) as e: with mock.patch("sys.stdout", new_callable=StringIO) as m_stdout: wrap_and_call( M_NAME, { "sys.argv": { "new": ["status"] }, "_is_cloudinit_disabled": (False, ""), }, status.main, ) assert e.value.code == 0 assert m_stdout.getvalue() == "status: running\n"
def test_handle_warns_on_undiscoverable_root_path_in_commandline(self): """handle noops when the root path is not found on the commandline.""" cfg = {"resize_rootfs": True} exists_mock_path = "cloudinit.config.cc_resizefs.os.path.exists" def fake_mount_info(path, log): self.assertEqual("/", path) self.assertEqual(LOG, log) return ("/dev/root", "ext4", "/") with mock.patch(exists_mock_path) as m_exists: m_exists.return_value = False wrap_and_call( "cloudinit.config.cc_resizefs.util", { "is_container": { "return_value": False }, "get_mount_info": { "side_effect": fake_mount_info }, "get_cmdline": { "return_value": "BOOT_IMAGE=/vmlinuz.efi" }, }, handle, "cc_resizefs", cfg, _cloud=None, log=LOG, args=[], ) logs = self.logs.getvalue() self.assertIn("WARNING: Unable to find device '/dev/root'", logs)
def test_add_assertions_adds_assertions_as_list(self, m_subp): """When provided with a list, add_assertions adds all assertions.""" self.assertEqual( ASSERTIONS_FILE, "/var/lib/cloud/instance/snapd.assertions" ) assert_file = self.tmp_path("snapd.assertions", dir=self.tmp) assertions = [SYSTEM_USER_ASSERTION, ACCOUNT_ASSERTION] wrap_and_call( "cloudinit.config.cc_snap", {"ASSERTIONS_FILE": {"new": assert_file}}, add_assertions, assertions, ) self.assertIn( "Importing user-provided snap assertions", self.logs.getvalue() ) self.assertIn("sertions", self.logs.getvalue()) self.assertEqual( [mock.call(["snap", "ack", assert_file], capture=True)], m_subp.call_args_list, ) compare_file = self.tmp_path("comparison", dir=self.tmp) util.write_file(compare_file, "\n".join(assertions).encode("utf-8")) self.assertEqual( util.load_file(compare_file), util.load_file(assert_file) )
def test_add_assertions_adds_assertions_as_dict(self, m_subp): """When provided with a dict, add_assertions adds all assertions.""" self.assertEqual( ASSERTIONS_FILE, "/var/lib/cloud/instance/snapd.assertions" ) assert_file = self.tmp_path("snapd.assertions", dir=self.tmp) assertions = {"00": SYSTEM_USER_ASSERTION, "01": ACCOUNT_ASSERTION} wrap_and_call( "cloudinit.config.cc_snap", {"ASSERTIONS_FILE": {"new": assert_file}}, add_assertions, assertions, ) self.assertIn( "Importing user-provided snap assertions", self.logs.getvalue() ) self.assertIn( "DEBUG: Snap acking: ['type: system-user', 'authority-id: Lqv", self.logs.getvalue(), ) self.assertIn( "DEBUG: Snap acking: ['type: account-key', 'authority-id: canonic", self.logs.getvalue(), ) self.assertEqual( [mock.call(["snap", "ack", assert_file], capture=True)], m_subp.call_args_list, ) compare_file = self.tmp_path("comparison", dir=self.tmp) combined = "\n".join(assertions.values()) util.write_file(compare_file, combined.encode("utf-8")) self.assertEqual( util.load_file(compare_file), util.load_file(assert_file) )
def test_add_assertions_adds_assertions_as_dict(self, m_subp): """When provided with a dict, add_assertions adds all assertions.""" self.assertEqual(ASSERTIONS_FILE, '/var/lib/cloud/instance/snapd.assertions') assert_file = self.tmp_path('snapd.assertions', dir=self.tmp) assertions = {'00': SYSTEM_USER_ASSERTION, '01': ACCOUNT_ASSERTION} wrap_and_call('cloudinit.config.cc_snap', {'ASSERTIONS_FILE': { 'new': assert_file }}, add_assertions, assertions) self.assertIn('Importing user-provided snap assertions', self.logs.getvalue()) self.assertIn( "DEBUG: Snap acking: ['type: system-user', 'authority-id: Lqv", self.logs.getvalue()) self.assertIn( "DEBUG: Snap acking: ['type: account-key', 'authority-id: canonic", self.logs.getvalue()) self.assertEqual( [mock.call(['snap', 'ack', assert_file], capture=True)], m_subp.call_args_list) compare_file = self.tmp_path('comparison', dir=self.tmp) combined = '\n'.join(assertions.values()) util.write_file(compare_file, combined.encode('utf-8')) self.assertEqual(util.load_file(compare_file), util.load_file(assert_file))
def test_handle_adds_assertions(self, m_subp): """Any configured snap assertions are provided to add_assertions.""" assert_file = self.tmp_path("snapd.assertions", dir=self.tmp) compare_file = self.tmp_path("comparison", dir=self.tmp) cfg = { "snap": { "assertions": [SYSTEM_USER_ASSERTION, ACCOUNT_ASSERTION] } } wrap_and_call( "cloudinit.config.cc_snap", {"ASSERTIONS_FILE": { "new": assert_file }}, handle, "snap", cfg=cfg, cloud=None, log=self.logger, args=None, ) content = "\n".join(cfg["snap"]["assertions"]) util.write_file(compare_file, content.encode("utf-8")) self.assertEqual(util.load_file(compare_file), util.load_file(assert_file))
def test_collect_logs_includes_optional_userdata(self, m_getuid): """collect-logs include userdata when --include-userdata is set.""" m_getuid.return_value = 0 log1 = self.tmp_path('cloud-init.log', self.new_root) write_file(log1, 'cloud-init-log') log2 = self.tmp_path('cloud-init-output.log', self.new_root) write_file(log2, 'cloud-init-output-log') userdata = self.tmp_path('user-data.txt', self.new_root) write_file(userdata, 'user-data') ensure_dir(self.run_dir) write_file(self.tmp_path('results.json', self.run_dir), 'results') write_file(self.tmp_path(INSTANCE_JSON_SENSITIVE_FILE, self.run_dir), 'sensitive') output_tarfile = self.tmp_path('logs.tgz') date = datetime.utcnow().date().strftime('%Y-%m-%d') date_logdir = 'cloud-init-logs-{0}'.format(date) version_out = '/usr/bin/cloud-init 18.2fake\n' expected_subp = { ('dpkg-query', '--show', "-f=${Version}\n", 'cloud-init'): '0.7fake', ('cloud-init', '--version'): version_out, ('dmesg',): 'dmesg-out\n', ('journalctl', '--boot=0', '-o', 'short-precise'): 'journal-out\n', ('tar', 'czvf', output_tarfile, date_logdir): '' } def fake_subp(cmd): cmd_tuple = tuple(cmd) if cmd_tuple not in expected_subp: raise AssertionError( 'Unexpected command provided to subp: {0}'.format(cmd)) if cmd == ['tar', 'czvf', output_tarfile, date_logdir]: subp(cmd) # Pass through tar cmd so we can check output return expected_subp[cmd_tuple], '' fake_stderr = mock.MagicMock() wrap_and_call( 'cloudinit.cmd.devel.logs', {'subp': {'side_effect': fake_subp}, 'sys.stderr': {'new': fake_stderr}, 'CLOUDINIT_LOGS': {'new': [log1, log2]}, 'CLOUDINIT_RUN_DIR': {'new': self.run_dir}, 'USER_DATA_FILE': {'new': userdata}}, logs.collect_logs, output_tarfile, include_userdata=True) # unpack the tarfile and check file contents subp(['tar', 'zxvf', output_tarfile, '-C', self.new_root]) out_logdir = self.tmp_path(date_logdir, self.new_root) self.assertEqual( 'user-data', load_file(os.path.join(out_logdir, 'user-data.txt'))) self.assertEqual( 'sensitive', load_file(os.path.join(out_logdir, 'run', 'cloud-init', INSTANCE_JSON_SENSITIVE_FILE))) fake_stderr.write.assert_any_call('Wrote %s\n' % output_tarfile)
def test_get_data_cloudinit_userdata_not_found(self): """Test userdata file can't be found.""" paths = Paths({"cloud_dir": self.tdir}) ds = self.datasource( sys_cfg={"disable_vmware_customization": True}, distro={}, paths=paths, ) # Prepare the conf file conf_file = self.tmp_path("test-cust", self.tdir) conf_content = dedent( """\ [CLOUDINIT] METADATA = test-meta USERDATA = test-user """ ) util.write_file(conf_file, conf_content) # Prepare the meta data file metadata_file = self.tmp_path("test-meta", self.tdir) metadata_content = dedent( """\ instance-id: cloud-vm local-hostname: my-host.domain.com network: version: 2 ethernets: nics: match: name: ens* dhcp4: yes """ ) util.write_file(metadata_file, metadata_content) # Don't prepare the user data file with mock.patch( MPATH + "set_customization_status", return_value=("msg", b"") ): with self.assertRaises(FileNotFoundError) as context: wrap_and_call( "cloudinit.sources.DataSourceOVF", { "dmi.read_dmi_data": "vmware", "util.del_dir": True, "search_file": self.tdir, "wait_for_imc_cfg_file": conf_file, "get_nics_to_enable": "", }, ds.get_data, ) self.assertIn("is not found", str(context.exception))
def test_get_data_force_run_post_script_is_yes(self): """If DEFAULT-RUN-POST-CUST-SCRIPT is yes, custom script could run if enable-custom-scripts is not defined in VM Tools configuration """ paths = Paths({"cloud_dir": self.tdir}) ds = self.datasource( sys_cfg={"disable_vmware_customization": False}, distro={}, paths=paths, ) # Prepare the conf file conf_file = self.tmp_path("test-cust", self.tdir) # set DEFAULT-RUN-POST-CUST-SCRIPT = yes so that enable-custom-scripts # default value is TRUE conf_content = dedent( """\ [CUSTOM-SCRIPT] SCRIPT-NAME = test-script [MISC] MARKER-ID = 12345346 DEFAULT-RUN-POST-CUST-SCRIPT = yes """ ) util.write_file(conf_file, conf_content) # Mock get_tools_config(section, key, defaultVal) to return # defaultVal def my_get_tools_config(*args, **kwargs): return args[2] with mock.patch( MPATH + "get_tools_config", side_effect=my_get_tools_config ): with mock.patch( MPATH + "set_customization_status", return_value=("msg", b"") ): with self.assertRaises(CustomScriptNotFound) as context: wrap_and_call( "cloudinit.sources.DataSourceOVF", { "dmi.read_dmi_data": "vmware", "util.del_dir": True, "search_file": self.tdir, "wait_for_imc_cfg_file": conf_file, "get_nics_to_enable": "", }, ds.get_data, ) # Verify custom script still runs although it is # disabled by VMware Tools customscript = self.tmp_path("test-script", self.tdir) self.assertIn( "Script %s not found!!" % customscript, str(context.exception) )
def test_handler_restarts_landscape_client(self, m_subp): """handler restarts lansdscape-client after install.""" mycloud = get_cloud('ubuntu') cfg = {'landscape': {'client': {}}} wrap_and_call('cloudinit.config.cc_landscape', {'LSC_CLIENT_CFG_FILE': { 'new': self.conf }}, cc_landscape.handle, 'notimportant', cfg, mycloud, LOG, None) self.assertEqual( [mock.call(['service', 'landscape-client', 'restart'])], m_subp.subp.call_args_list)
def test_get_data_cloudinit_metadata_not_valid(self): """Test metadata is not JSON or YAML format.""" paths = Paths({"cloud_dir": self.tdir}) ds = self.datasource( sys_cfg={"disable_vmware_customization": True}, distro={}, paths=paths, ) # Prepare the conf file conf_file = self.tmp_path("test-cust", self.tdir) conf_content = dedent( """\ [CLOUDINIT] METADATA = test-meta """ ) util.write_file(conf_file, conf_content) # Prepare the meta data file metadata_file = self.tmp_path("test-meta", self.tdir) metadata_content = "[This is not json or yaml format]a=b" util.write_file(metadata_file, metadata_content) with mock.patch( MPATH + "set_customization_status", return_value=("msg", b"") ): with self.assertRaises(YAMLError) as context: wrap_and_call( "cloudinit.sources.DataSourceOVF", { "dmi.read_dmi_data": "vmware", "util.del_dir": True, "search_file": self.tdir, "wait_for_imc_cfg_file": conf_file, "collect_imc_file_paths": [ self.tdir + "/test-meta", "", "", ], "get_nics_to_enable": "", }, ds.get_data, ) self.assertIn( "expected '<document start>', but found '<scalar>'", str(context.exception), )
def test_remove_artifacts_removes_artifacts_skipping_seed(self): """remove_artifacts cleans artifacts dir with exception of seed dir.""" dirs = [ self.artifact_dir, os.path.join(self.artifact_dir, "seed"), os.path.join(self.artifact_dir, "dir1"), os.path.join(self.artifact_dir, "dir2"), ] for _dir in dirs: ensure_dir(_dir) retcode = wrap_and_call( "cloudinit.cmd.clean", {"Init": { "side_effect": self.init_class }}, clean.remove_artifacts, remove_logs=False, ) self.assertEqual(0, retcode) for expected_dir in dirs[:2]: self.assertTrue( os.path.exists(expected_dir), "Missing {0} dir".format(expected_dir), ) for deleted_dir in dirs[2:]: self.assertFalse( os.path.exists(deleted_dir), "Unexpected {0} dir".format(deleted_dir), )
def test__is_cloudinit_disabled( self, ensured_file: Optional[Callable], uses_systemd: bool, get_cmdline: str, expected_is_disabled: bool, is_disabled_msg: str, expected_reason: Union[str, Callable], config: Config, ): if ensured_file is not None: ensure_file(ensured_file(config)) (is_disabled, reason) = wrap_and_call( M_NAME, { "uses_systemd": uses_systemd, "get_cmdline": get_cmdline, }, status._is_cloudinit_disabled, config.disable_file, config.paths, ) assert is_disabled == expected_is_disabled, is_disabled_msg if isinstance(expected_reason, str): assert reason == expected_reason else: assert reason == expected_reason(config)
def test_status_output( self, m_read_cfg_paths, ensured_file: Optional[Callable], status_content: Dict, assert_file, cmdargs: MyArgs, expected_retcode: int, expected_status: str, config: Config, ): m_read_cfg_paths.return_value = config.paths if ensured_file: ensure_file(ensured_file(config)) write_json( config.status_file, status_content, ) if assert_file: assert not os.path.exists( config.result_file), f"Unexpected {config.result_file} found" with mock.patch("sys.stdout", new_callable=StringIO) as m_stdout: retcode = wrap_and_call( M_NAME, {"_is_cloudinit_disabled": (False, "")}, status.handle_status_args, "ignored", cmdargs, ) assert retcode == expected_retcode assert m_stdout.getvalue() == expected_status
def test_status_wait_blocks_until_error(self, m_read_cfg_paths, config: Config): """Specifying wait will poll every 1/4 second until error state.""" m_read_cfg_paths.return_value = config.paths running_json = { "v1": { "stage": "init", "init": { "start": 124.456, "finished": None }, "init-local": { "start": 123.45, "finished": 123.46 }, } } error_json = { "v1": { "stage": None, "init": { "errors": ["error1"], "start": 124.456, "finished": 125.678, }, "init-local": { "start": 123.45, "finished": 123.46 }, } } sleep_calls = 0 def fake_sleep(interval): nonlocal sleep_calls assert interval == 0.25 sleep_calls += 1 if sleep_calls == 2: write_json(config.status_file, running_json) elif sleep_calls == 3: write_json(config.status_file, error_json) cmdargs = MyArgs(long=False, wait=True) with mock.patch("sys.stdout", new_callable=StringIO) as m_stdout: retcode = wrap_and_call( M_NAME, { "sleep": { "side_effect": fake_sleep }, "_is_cloudinit_disabled": (False, ""), }, status.handle_status_args, "ignored", cmdargs, ) assert retcode == 1 assert sleep_calls == 4 assert m_stdout.getvalue() == "....\nstatus: error\n"
def test_maybe_get_writable_device_path_returns_cmdline_root(self): """When root device is UUID in kernel commandline, update devpath.""" # XXX Long-term we want to use FilesystemMocking test to avoid # touching os.stat. FakeStat = namedtuple( "FakeStat", ["st_mode", "st_size", "st_mtime"]) # minimal def. info = "dev=/dev/root mnt_point=/ path=/does/not/matter" devpath = wrap_and_call( "cloudinit.config.cc_resizefs", { "util.get_cmdline": { "return_value": "asdf root=UUID=my-uuid" }, "util.is_container": False, "os.path.exists": False, # /dev/root doesn't exist "os.stat": { "return_value": FakeStat(25008, 0, 1) }, # char block device }, maybe_get_writable_device_path, "/dev/root", info, LOG, ) self.assertEqual("/dev/disk/by-uuid/my-uuid", devpath) self.assertIn( "DEBUG: Converted /dev/root to '/dev/disk/by-uuid/my-uuid'" " per kernel cmdline", self.logs.getvalue(), )
def test_get_data_vmware_customization_sys_cfg_disabled(self): """When vmware customization is disabled via sys_cfg and no meta data is found, log a message. """ paths = Paths({'cloud_dir': self.tdir}) ds = self.datasource(sys_cfg={ 'disable_vmware_customization': True, 'datasource': { 'OVF': { 'allow_raw_data': True } } }, distro={}, paths=paths) conf_file = self.tmp_path('test-cust', self.tdir) conf_content = dedent("""\ [MISC] MARKER-ID = 12345345 """) util.write_file(conf_file, conf_content) retcode = wrap_and_call( 'cloudinit.sources.DataSourceOVF', { 'dmi.read_dmi_data': 'vmware', 'transport_iso9660': NOT_FOUND, 'transport_vmware_guestinfo': NOT_FOUND, 'util.del_dir': True, 'search_file': self.tdir, 'wait_for_imc_cfg_file': conf_file }, ds.get_data) self.assertFalse(retcode, 'Expected False return from ds.get_data') self.assertIn('DEBUG: Customization using VMware config is disabled.', self.logs.getvalue())
def test_maybe_get_writable_device_path_warns_missing_cmdline_root(self): """When root does not exist isn't in the cmdline, log warning.""" info = "does not matter" def fake_mount_info(path, log): self.assertEqual("/", path) self.assertEqual(LOG, log) return ("/dev/root", "ext4", "/") exists_mock_path = "cloudinit.config.cc_resizefs.os.path.exists" with mock.patch(exists_mock_path) as m_exists: m_exists.return_value = False devpath = wrap_and_call( "cloudinit.config.cc_resizefs.util", { "is_container": { "return_value": False }, "get_mount_info": { "side_effect": fake_mount_info }, "get_cmdline": { "return_value": "BOOT_IMAGE=/vmlinuz.efi" }, }, maybe_get_writable_device_path, "/dev/root", info, LOG, ) self.assertIsNone(devpath) logs = self.logs.getvalue() self.assertIn("WARNING: Unable to find device '/dev/root'", logs)
def test_order_precedence_is_builtin_system_runtime_cmdline(self): builtin = {'key1': 'builtin0', 'key3': 'builtin3'} conf_d = {'key1': 'confd1', 'key2': 'confd2', 'keyconfd1': 'kconfd1'} runtime = {'key1': 'runtime1', 'key2': 'runtime2'} cmdline = {'key1': 'cmdline1'} ret = helpers.wrap_and_call( 'cloudinit.stages', { 'util.read_conf_with_confd': { 'return_value': conf_d }, 'util.get_builtin_cfg': { 'return_value': builtin }, 'util.read_conf_from_cmdline': { 'return_value': cmdline }, 'read_runtime_config': { 'return_value': runtime }, }, stages.fetch_base_config) self.assertEqual( ret, { 'key1': 'cmdline1', 'key2': 'runtime2', 'key3': 'builtin3', 'keyconfd1': 'kconfd1' })
def test_cmdline_overrides_confd_runtime_and_defaults(self): builtin = {'key1': 'value0', 'key3': 'other2'} conf_d = {'key1': 'value1', 'key2': 'other1'} cmdline = {'key3': 'other3', 'key2': 'other2'} runtime = {'key3': 'runtime3'} ret = helpers.wrap_and_call( 'cloudinit.stages', { 'util.read_conf_with_confd': { 'return_value': conf_d }, 'util.get_builtin_cfg': { 'return_value': builtin }, 'read_runtime_config': { 'return_value': runtime }, 'util.read_conf_from_cmdline': { 'return_value': cmdline } }, stages.fetch_base_config) self.assertEqual(ret, { 'key1': 'value1', 'key2': 'other2', 'key3': 'other3' })
def test_main_init_run_net_runs_modules(self): """Modules like write_files are run in 'net' mode.""" cmdargs = myargs( debug=False, files=None, force=False, local=False, reporter=None, subcommand='init') (_item1, item2) = wrap_and_call( 'cloudinit.cmd.main', {'util.close_stdin': True, 'netinfo.debug_info': 'my net debug info', 'util.fixup_output': ('outfmt', 'errfmt')}, main.main_init, 'init', cmdargs) self.assertEqual([], item2) # Instancify is called instance_id_path = 'var/lib/cloud/data/instance-id' self.assertEqual( 'iid-datasource-none\n', os.path.join(load_file( os.path.join(self.new_root, instance_id_path)))) # modules are run (including write_files) self.assertEqual( 'blah', load_file(os.path.join(self.new_root, 'etc/blah.ini'))) expected_logs = [ 'network config is disabled by fallback', # apply_network_config 'my net debug info', # netinfo.debug_info 'no previous run detected' ] for log in expected_logs: self.assertIn(log, self.stderr.getvalue())
def test_main_init_run_net_stops_on_file_no_net(self): """When no-net file is present, main_init does not process modules.""" stop_file = os.path.join(self.cloud_dir, 'data', 'no-net') # stop file write_file(stop_file, '') cmdargs = myargs( debug=False, files=None, force=False, local=False, reporter=None, subcommand='init') (_item1, item2) = wrap_and_call( 'cloudinit.cmd.main', {'util.close_stdin': True, 'netinfo.debug_info': 'my net debug info', 'util.fixup_output': ('outfmt', 'errfmt')}, main.main_init, 'init', cmdargs) # We should not run write_files module self.assertFalse( os.path.exists(os.path.join(self.new_root, 'etc/blah.ini')), 'Unexpected run of write_files module produced blah.ini') self.assertEqual([], item2) # Instancify is called instance_id_path = 'var/lib/cloud/data/instance-id' self.assertFalse( os.path.exists(os.path.join(self.new_root, instance_id_path)), 'Unexpected call to datasource.instancify produced instance-id') expected_logs = [ "Exiting. stop file ['{stop_file}'] existed\n".format( stop_file=stop_file), 'my net debug info' # netinfo.debug_info ] for log in expected_logs: self.assertIn(log, self.stderr.getvalue())
def test_mkdtemp_default_non_root_needs_exe(self): """mkdtemp creates a dir under /var/tmp/cloud-init when needs_exe.""" calls = [] def fake_mkdtemp(*args, **kwargs): calls.append(kwargs) return "/fake/return/path" retval = wrap_and_call( "cloudinit.temp_utils", { "os.getuid": 1000, "tempfile.mkdtemp": { "side_effect": fake_mkdtemp }, "_TMPDIR": { "new": None }, "os.path.isdir": True, }, mkdtemp, needs_exe=True, ) self.assertEqual("/fake/return/path", retval) self.assertEqual([{"dir": "/var/tmp/cloud-init"}], calls)