Example #1
0
    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)
Example #2
0
 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())
Example #3
0
    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))
Example #4
0
 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(),
     )
Example #5
0
 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)
Example #6
0
 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))
Example #7
0
    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))
Example #8
0
 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"
Example #9
0
    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)
Example #10
0
 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)
     )
Example #11
0
 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)
     )
Example #12
0
 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))
Example #13
0
 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))
Example #14
0
    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)
Example #15
0
    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))
Example #16
0
    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)
        )
Example #17
0
 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)
Example #18
0
    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),
            )
Example #20
0
 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)
Example #21
0
 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
Example #22
0
    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"
Example #23
0
 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(),
     )
Example #24
0
 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())
Example #25
0
    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)
Example #26
0
 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'
         })
Example #27
0
 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'
     })
Example #28
0
 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())
Example #29
0
 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())
Example #30
0
    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)