def handle(name, cfg, cloud, log, _args):
    if "drivers" not in cfg:
        log.debug("Skipping module named %s, no 'drivers' key in config", name)
        return

    validate_cloudconfig_schema(cfg, schema)
    install_drivers(cfg['drivers'], cloud.distro.install_packages)
 def test_warn_schema_requires_token(self, _cfg, _):
     """Warn if ubuntu_advantage configuration lacks token."""
     validate_cloudconfig_schema(
         {'ubuntu_advantage': {'enable': ['esm']}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nubuntu_advantage:"
         " 'token' is a required property\n", self.logs.getvalue())
Beispiel #3
0
 def test_schema_warns_on_snap_not_as_dict(self):
     """If the snap configuration is not a dict, emit a warning."""
     validate_cloudconfig_schema({'snap': 'wrong type'}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap: 'wrong type' is not of type"
         " 'object'\n",
         self.logs.getvalue())
 def test_schema_warns_on_ubuntu_advantage_not_dict(self, _cfg, _):
     """If ubuntu_advantage configuration is not a dict, emit a warning."""
     validate_cloudconfig_schema({'ubuntu_advantage': 'wrong type'}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nubuntu_advantage: 'wrong type' is not"
         " of type 'object'\n",
         self.logs.getvalue())
Beispiel #5
0
 def test_schema_warns_on_snap_not_as_dict(self):
     """If the snap configuration is not a dict, emit a warning."""
     validate_cloudconfig_schema({'snap': 'wrong type'}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap: 'wrong type' is not of type"
         " 'object'\n",
         self.logs.getvalue())
Beispiel #6
0
def handle(name, cfg, cloud, log, _args):
    """Enable and configure ntp."""
    if 'ntp' not in cfg:
        LOG.debug("Skipping module named %s, not present or disabled by cfg",
                  name)
        return
    ntp_cfg = cfg.get('ntp', {})

    # TODO drop this when validate_cloudconfig_schema is strict=True
    if not isinstance(ntp_cfg, (dict)):
        raise RuntimeError(("'ntp' key existed in config,"
                            " but not a dictionary type,"
                            " is a %s %instead"), type_utils.obj_name(ntp_cfg))

    validate_cloudconfig_schema(cfg, schema)
    rename_ntp_conf()
    # ensure when ntp is installed it has a configuration file
    # to use instead of starting up with packaged defaults
    write_ntp_config_template(ntp_cfg, cloud)
    install_ntp(cloud.distro.install_packages,
                packages=['ntp'],
                check_exe="ntpd")
    # if ntp was already installed, it may not have started
    try:
        reload_ntp(systemd=cloud.distro.uses_systemd())
    except util.ProcessExecutionError as e:
        LOG.exception("Failed to reload/start ntp service: %s", e)
        raise
Beispiel #7
0
 def test_schema_when_assertions_are_list_or_dict(self, _):
     """No warnings when snap:assertions are a list or dict."""
     validate_cloudconfig_schema(
         {'snap': {'assertions': ['valid']}}, schema)
     validate_cloudconfig_schema(
         {'snap': {'assertions': {'01': 'also valid'}}}, schema)
     self.assertEqual('', self.logs.getvalue())
 def test_schema_validation(self, config, error_msg):
     schema = get_schema()
     if error_msg is None:
         validate_cloudconfig_schema(config, schema, strict=True)
     else:
         with pytest.raises(SchemaValidationError, match=error_msg):
             validate_cloudconfig_schema(config, schema, strict=True)
Beispiel #9
0
def handle(name, cfg, cloud, log, _args):

    if "bootcmd" not in cfg:
        log.debug(("Skipping module named %s,"
                   " no 'bootcmd' key in configuration"), name)
        return

    validate_cloudconfig_schema(cfg, schema)
    with temp_utils.ExtendedTemporaryFile(suffix=".sh") as tmpf:
        try:
            content = util.shellify(cfg["bootcmd"])
            tmpf.write(util.encode_text(content))
            tmpf.flush()
        except Exception as e:
            util.logexc(log, "Failed to shellify bootcmd: %s", str(e))
            raise

        try:
            env = os.environ.copy()
            iid = cloud.get_instance_id()
            if iid:
                env['INSTANCE_ID'] = str(iid)
            cmd = ['/bin/sh', tmpf.name]
            util.subp(cmd, env=env, capture=False)
        except Exception:
            util.logexc(log, "Failed to run bootcmd module %s", name)
            raise
Beispiel #10
0
 def test_validateconfig_schema_non_strict_emits_warnings(self):
     """When strict is False validate_cloudconfig_schema emits warnings."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     validate_cloudconfig_schema({'p1': -1}, schema, strict=False)
     self.assertIn(
         "Invalid config:\np1: -1 is not of type 'string'\n",
         self.logs.getvalue())
Beispiel #11
0
 def test_validateconfig_schema_of_example(self, schema_id, example):
     """For a given example in a config module we test if it is valid
     according to the unified schema of all config modules
     """
     schema = get_schema()
     config_load = load(example)
     # cloud-init-schema-v1 is permissive of additionalProperties at the
     # top-level.
     # To validate specific schemas against known documented examples
     # we need to only define the specific module schema and supply
     # strict=True.
     # TODO(Drop to pop/update once full schema is strict)
     schema.pop("allOf")
     schema.update(schema["$defs"][schema_id])
     schema["additionalProperties"] = False
     # Some module examples reference keys defined in multiple schemas
     supplemental_schemas = {
         "cc_ubuntu_advantage": ["cc_power_state_change"],
         "cc_update_hostname": ["cc_set_hostname"],
         "cc_users_groups": ["cc_ssh_import_id"],
         "cc_disk_setup": ["cc_mounts"],
     }
     for supplement_id in supplemental_schemas.get(schema_id, []):
         supplemental_props = dict([(key, value)
                                    for key, value in schema["$defs"]
                                    [supplement_id]["properties"].items()])
         schema["properties"].update(supplemental_props)
     validate_cloudconfig_schema(config_load, schema, strict=True)
Beispiel #12
0
    def test_all_integration_test_cloud_config_schema(self):
        """Validate schema of cloud_tests yaml files looking for warnings."""
        schema = get_schema()
        testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        integration_testdir = os.path.sep.join(
            [testsdir, 'cloud_tests', 'testcases'])
        errors = []

        yaml_files = []
        for root, _dirnames, filenames in os.walk(integration_testdir):
            yaml_files.extend([os.path.join(root, f)
                               for f in filenames if f.endswith(".yaml")])
        self.assertTrue(len(yaml_files) > 0)

        for filename in yaml_files:
            test_cfg = safe_load(open(filename))
            cloud_config = test_cfg.get('cloud_config')
            if cloud_config:
                cloud_config = safe_load(
                    cloud_config.replace("#cloud-config\n", ""))
                try:
                    validate_cloudconfig_schema(
                        cloud_config, schema, strict=True)
                except SchemaValidationError as e:
                    errors.append(
                        '{0}: {1}'.format(
                            filename, e))
        if errors:
            raise AssertionError(', '.join(errors))
Beispiel #13
0
 def test_validateconfig_schema_honors_formats(self):
     """With strict True, validate_cloudconfig_schema errors on format."""
     schema = {"properties": {"p1": {"type": "string", "format": "email"}}}
     with pytest.raises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({"p1": "-1"}, schema, strict=True)
     assert "Cloud config schema errors: p1: '-1' is not a 'email'" == (str(
         context_mgr.value))
Beispiel #14
0
 def test_validateconfig_schema_non_strict_emits_warnings(self):
     """When strict is False validate_cloudconfig_schema emits warnings."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     validate_cloudconfig_schema({'p1': -1}, schema, strict=False)
     self.assertIn(
         "Invalid config:\np1: -1 is not of type 'string'\n",
         self.logs.getvalue())
Beispiel #15
0
    def test_all_integration_test_cloud_config_schema(self):
        """Validate schema of cloud_tests yaml files looking for warnings."""
        schema = get_schema()
        testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        integration_testdir = os.path.sep.join(
            [testsdir, 'cloud_tests', 'testcases'])
        errors = []

        yaml_files = []
        for root, _dirnames, filenames in os.walk(integration_testdir):
            yaml_files.extend([
                os.path.join(root, f) for f in filenames if f.endswith(".yaml")
            ])
        self.assertTrue(len(yaml_files) > 0)

        for filename in yaml_files:
            test_cfg = safe_load(open(filename))
            cloud_config = test_cfg.get('cloud_config')
            if cloud_config:
                cloud_config = safe_load(
                    cloud_config.replace("#cloud-config\n", ""))
                try:
                    validate_cloudconfig_schema(cloud_config,
                                                schema,
                                                strict=True)
                except SchemaValidationError as e:
                    errors.append('{0}: {1}'.format(filename, e))
        if errors:
            raise AssertionError(', '.join(errors))
Beispiel #16
0
 def test_schema_when_commands_are_list_or_dict(self, _):
     """No warnings when snap:commands are either a list or dict."""
     validate_cloudconfig_schema({"snap": {"commands": ["valid"]}}, schema)
     validate_cloudconfig_schema(
         {"snap": {"commands": {"01": "also valid"}}}, schema
     )
     self.assertEqual("", self.logs.getvalue())
 def test_validateconfig_schema_of_example(self, schema_id, example):
     """For a given example in a config module we test if it is valid
     according to the unified schema of all config modules
     """
     schema = get_schema()
     config_load = safe_load(example)
     validate_cloudconfig_schema(config_load, schema, strict=True)
Beispiel #18
0
def handle(name, cfg, cloud, log, _args):

    if "bootcmd" not in cfg:
        log.debug(("Skipping module named %s,"
                   " no 'bootcmd' key in configuration"), name)
        return

    validate_cloudconfig_schema(cfg, schema)
    with temp_utils.ExtendedTemporaryFile(suffix=".sh") as tmpf:
        try:
            content = util.shellify(cfg["bootcmd"])
            tmpf.write(util.encode_text(content))
            tmpf.flush()
        except Exception as e:
            util.logexc(log, "Failed to shellify bootcmd: %s", str(e))
            raise

        try:
            env = os.environ.copy()
            iid = cloud.get_instance_id()
            if iid:
                env['INSTANCE_ID'] = str(iid)
            cmd = ['/bin/sh', tmpf.name]
            util.subp(cmd, env=env, capture=False)
        except Exception:
            util.logexc(log, "Failed to run bootcmd module %s", name)
            raise
Beispiel #19
0
 def test_schema_when_assertions_are_list_or_dict(self, _):
     """No warnings when snap:assertions are a list or dict."""
     validate_cloudconfig_schema(
         {'snap': {'assertions': ['valid']}}, schema)
     validate_cloudconfig_schema(
         {'snap': {'assertions': {'01': 'also valid'}}}, schema)
     self.assertEqual('', self.logs.getvalue())
Beispiel #20
0
def handle(name, cfg, cloud, log, args):
    ua_section = None
    if "ubuntu-advantage" in cfg:
        LOG.warning(
            'Deprecated configuration key "ubuntu-advantage" provided.'
            ' Expected underscore delimited "ubuntu_advantage"; will'
            " attempt to continue."
        )
        ua_section = cfg["ubuntu-advantage"]
    if "ubuntu_advantage" in cfg:
        ua_section = cfg["ubuntu_advantage"]
    if ua_section is None:
        LOG.debug(
            "Skipping module named %s,"
            " no 'ubuntu_advantage' configuration found",
            name,
        )
        return
    validate_cloudconfig_schema(cfg, schema)
    if "commands" in ua_section:
        msg = (
            'Deprecated configuration "ubuntu-advantage: commands" provided.'
            ' Expected "token"'
        )
        LOG.error(msg)
        raise RuntimeError(msg)

    maybe_install_ua_tools(cloud)
    configure_ua(
        token=ua_section.get("token"), enable=ua_section.get("enable")
    )
Beispiel #21
0
 def test_warn_schema_requires_either_commands_or_assertions(self):
     """Warn when snap configuration lacks both commands and assertions."""
     validate_cloudconfig_schema(
         {'snap': {}}, schema)
     self.assertIn(
         'WARNING: Invalid config:\nsnap: {} does not have enough'
         ' properties',
         self.logs.getvalue())
Beispiel #22
0
 def test_validateconfig_schema_honors_formats(self):
     """With strict True, validate_cloudconfig_schema errors on format."""
     schema = {'properties': {'p1': {'type': 'string', 'format': 'email'}}}
     with self.assertRaises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({'p1': '-1'}, schema, strict=True)
     self.assertEqual(
         "Cloud config schema errors: p1: '-1' is not a 'email'",
         str(context_mgr.exception))
Beispiel #23
0
 def test_duplicates_are_fine_array_array(self):
     """Duplicated commands array/array entries are allowed."""
     byebye = ["echo", "bye"]
     try:
         cfg = {'snap': {'commands': [byebye, byebye]}}
         validate_cloudconfig_schema(cfg, schema, strict=True)
     except schema.SchemaValidationError as e:
         self.fail("command entries can be duplicate.")
Beispiel #24
0
def handle(name, cfg, _cloud, log, _args):
    files = cfg.get('write_files')
    if not files:
        log.debug(("Skipping module named %s,"
                   " no/empty 'write_files' key in configuration"), name)
        return
    validate_cloudconfig_schema(cfg, schema)
    write_files(name, files)
Beispiel #25
0
 def test_validateconfig_schema_emits_warning_on_missing_jsonschema(self):
     """Warning from validate_cloudconfig_schema when missing jsonschema."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     with mock.patch.dict('sys.modules', **{'jsonschema': ImportError()}):
         validate_cloudconfig_schema({'p1': -1}, schema, strict=True)
     self.assertIn(
         'Ignoring schema validation. python-jsonschema is not present',
         self.logs.getvalue())
Beispiel #26
0
 def test_duplicates_are_fine_dict_string(self):
     """Duplicated commands dict/string entries are allowed."""
     byebye = "echo bye"
     try:
         cfg = {'snap': {'commands': {'00': byebye, '01': byebye}}}
         validate_cloudconfig_schema(cfg, schema, strict=True)
     except schema.SchemaValidationError as e:
         self.fail("command entries can be duplicate.")
Beispiel #27
0
 def test_warn_schema_assertions_is_not_list_or_dict(self, _):
     """Warn when snap:assertions config is not a list or dict."""
     validate_cloudconfig_schema(
         {'snap': {'assertions': 'broken'}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap.assertions: 'broken' is not of"
         " type 'object', 'array'\n",
         self.logs.getvalue())
Beispiel #28
0
 def test_warn_schema_commands_is_not_list_or_dict(self, _):
     """Warn when snap:commands config is not a list or dict."""
     validate_cloudconfig_schema({"snap": {"commands": "broken"}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap.commands: 'broken' is not of type"
         " 'object', 'array'\n",
         self.logs.getvalue(),
     )
 def test_schema_warns_on_ubuntu_advantage_not_dict(self, _cfg, _):
     """If ubuntu_advantage configuration is not a dict, emit a warning."""
     validate_cloudconfig_schema({"ubuntu_advantage": "wrong type"}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nubuntu_advantage: 'wrong type' is not"
         " of type 'object'\n",
         self.logs.getvalue(),
     )
Beispiel #30
0
 def test_warn_schema_assertions_is_not_list_or_dict(self, _):
     """Warn when snap:assertions config is not a list or dict."""
     validate_cloudconfig_schema({"snap": {"assertions": "broken"}}, schema)
     self.assertEqual(
         "WARNING: Invalid cloud-config provided:\nsnap.assertions:"
         " 'broken' is not of type 'object', 'array'\n",
         self.logs.getvalue(),
     )
Beispiel #31
0
 def test_schema_disallows_unknown_keys(self, _):
     """Unknown keys in the snap configuration emit warnings."""
     validate_cloudconfig_schema(
         {'snap': {'commands': ['ls'], 'invalid-key': ''}}, schema)
     self.assertIn(
         'WARNING: Invalid config:\nsnap: Additional properties are not'
         " allowed ('invalid-key' was unexpected)",
         self.logs.getvalue())
Beispiel #32
0
 def test_validateconfig_schema_strict_raises_errors(self):
     """When strict is True validate_cloudconfig_schema raises errors."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     with self.assertRaises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({'p1': -1}, schema, strict=True)
     self.assertEqual(
         "Cloud config schema errors: p1: -1 is not of type 'string'",
         str(context_mgr.exception))
Beispiel #33
0
 def test_warn_schema_when_assertions_is_empty(self, _):
     """Emit warnings when snap:assertions is an empty list or dict."""
     validate_cloudconfig_schema({'snap': {'assertions': []}}, schema)
     validate_cloudconfig_schema({'snap': {'assertions': {}}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap.assertions: [] is too short\n"
         "WARNING: Invalid config:\nsnap.assertions: {} does not have"
         " enough properties\n", self.logs.getvalue())
Beispiel #34
0
 def test_validateconfig_schema_strict_raises_errors(self):
     """When strict is True validate_cloudconfig_schema raises errors."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     with self.assertRaises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({'p1': -1}, schema, strict=True)
     self.assertEqual(
         "Cloud config schema errors: p1: -1 is not of type 'string'",
         str(context_mgr.exception))
Beispiel #35
0
 def test_schema_disallows_unknown_keys(self, _):
     """Unknown keys in the snap configuration emit warnings."""
     validate_cloudconfig_schema(
         {'snap': {'commands': ['ls'], 'invalid-key': ''}}, schema)
     self.assertIn(
         'WARNING: Invalid config:\nsnap: Additional properties are not'
         " allowed ('invalid-key' was unexpected)",
         self.logs.getvalue())
Beispiel #36
0
 def test_validateconfig_schema_emits_warning_on_missing_jsonschema(self):
     """Warning from validate_cloudconfig_schema when missing jsonschema."""
     schema = {'properties': {'p1': {'type': 'string'}}}
     with mock.patch.dict('sys.modules', **{'jsonschema': ImportError()}):
         validate_cloudconfig_schema({'p1': -1}, schema, strict=True)
     self.assertIn(
         'Ignoring schema validation. python-jsonschema is not present',
         self.logs.getvalue())
Beispiel #37
0
 def test_validateconfig_schema_emits_warning_on_missing_jsonschema(
         self, caplog):
     """Warning from validate_cloudconfig_schema when missing jsonschema."""
     schema = {"properties": {"p1": {"type": "string"}}}
     with mock.patch.dict("sys.modules", **{"jsonschema": ImportError()}):
         validate_cloudconfig_schema({"p1": -1}, schema, strict=True)
     assert "Ignoring schema validation. jsonschema is not present" in (
         caplog.text)
Beispiel #38
0
 def test_validateconfig_schema_strict_raises_errors(self):
     """When strict is True validate_cloudconfig_schema raises errors."""
     schema = {"properties": {"p1": {"type": "string"}}}
     with pytest.raises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({"p1": -1}, schema, strict=True)
     assert (
         "Cloud config schema errors: p1: -1 is not of type 'string'" == (
             str(context_mgr.value)))
Beispiel #39
0
 def test_warn_schema_requires_either_commands_or_assertions(self):
     """Warn when snap configuration lacks both commands and assertions."""
     validate_cloudconfig_schema(
         {'snap': {}}, schema)
     self.assertIn(
         'WARNING: Invalid config:\nsnap: {} does not have enough'
         ' properties',
         self.logs.getvalue())
 def test_schema_validation(self, config, error_msg):
     """Assert expected schema validation and error messages."""
     schema = get_schema()
     if error_msg is None:
         validate_cloudconfig_schema(config, schema, strict=True)
     else:
         with pytest.raises(SchemaValidationError, match=error_msg):
             validate_cloudconfig_schema(config, schema, strict=True)
Beispiel #41
0
 def test_warn_schema_requires_token(self, _cfg, _):
     """Warn if ubuntu_advantage configuration lacks token."""
     validate_cloudconfig_schema({'ubuntu_advantage': {
         'enable': ['esm']
     }}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nubuntu_advantage:"
         " 'token' is a required property\n", self.logs.getvalue())
Beispiel #42
0
 def test_warn_schema_assertions_is_not_list_or_dict(self, _):
     """Warn when snap:assertions config is not a list or dict."""
     validate_cloudconfig_schema(
         {'snap': {'assertions': 'broken'}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap.assertions: 'broken' is not of"
         " type 'object', 'array'\n",
         self.logs.getvalue())
 def test_warn_schema_services_is_not_list_or_dict(self, _cfg, _):
     """Warn when ubuntu_advantage:enable config is not a list."""
     validate_cloudconfig_schema(
         {'ubuntu_advantage': {'enable': 'needslist'}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nubuntu_advantage: 'token' is a"
         " required property\nubuntu_advantage.enable: 'needslist'"
         " is not of type 'array'\n",
         self.logs.getvalue())
Beispiel #44
0
 def test_validateconfig_schema_honors_formats(self):
     """With strict True, validate_cloudconfig_schema errors on format."""
     schema = {
         'properties': {'p1': {'type': 'string', 'format': 'hostname'}}}
     with self.assertRaises(SchemaValidationError) as context_mgr:
         validate_cloudconfig_schema({'p1': '-1'}, schema, strict=True)
     self.assertEqual(
         "Cloud config schema errors: p1: '-1' is not a 'hostname'",
         str(context_mgr.exception))
 def test_schema_disallows_unknown_keys(self, _cfg, _):
     """Unknown keys in ubuntu_advantage configuration emit warnings."""
     validate_cloudconfig_schema(
         {'ubuntu_advantage': {'token': 'winner', 'invalid-key': ''}},
         schema)
     self.assertIn(
         'WARNING: Invalid config:\nubuntu_advantage: Additional properties'
         " are not allowed ('invalid-key' was unexpected)",
         self.logs.getvalue())
Beispiel #46
0
 def test_warn_schema_when_assertions_is_empty(self, _):
     """Emit warnings when snap:assertions is an empty list or dict."""
     validate_cloudconfig_schema(
         {'snap': {'assertions': []}}, schema)
     validate_cloudconfig_schema(
         {'snap': {'assertions': {}}}, schema)
     self.assertEqual(
         "WARNING: Invalid config:\nsnap.assertions: [] is too short\n"
         "WARNING: Invalid config:\nsnap.assertions: {} does not have"
         " enough properties\n",
         self.logs.getvalue())
Beispiel #47
0
def handle(name, cfg, cloud, log, args):
    cfgin = cfg.get('snap', {})
    if not cfgin:
        LOG.debug(("Skipping module named %s,"
                   " no 'snap' key in configuration"), name)
        return

    validate_cloudconfig_schema(cfg, schema)
    if util.is_true(cfgin.get('squashfuse_in_container', False)):
        maybe_install_squashfuse(cloud)
    add_assertions(cfgin.get('assertions', []))
    run_commands(cfgin.get('commands', []))
Beispiel #48
0
    def assertSchemaValid(self, cfg, msg="Valid Schema failed validation."):
        """Assert the config is valid per self.schema.

        If there is only one top level key in the schema properties, then
        the cfg will be put under that key."""
        props = list(self.schema.get('properties'))
        # put cfg under top level key if there is only one in the schema
        if len(props) == 1:
            cfg = {props[0]: cfg}
        try:
            validate_cloudconfig_schema(cfg, self.schema, strict=True)
        except SchemaValidationError:
            self.fail(msg)
Beispiel #49
0
def handle(name, cfg, cloud, log, _args):
    if "runcmd" not in cfg:
        log.debug(("Skipping module named %s,"
                   " no 'runcmd' key in configuration"), name)
        return

    validate_cloudconfig_schema(cfg, schema)
    out_fn = os.path.join(cloud.get_ipath('scripts'), "runcmd")
    cmd = cfg["runcmd"]
    try:
        content = util.shellify(cmd)
        util.write_file(out_fn, content, 0o700)
    except Exception:
        util.logexc(log, "Failed to shellify %s into file %s", cmd, out_fn)
def handle(name, cfg, cloud, log, args):
    ua_section = None
    if 'ubuntu-advantage' in cfg:
        LOG.warning('Deprecated configuration key "ubuntu-advantage" provided.'
                    ' Expected underscore delimited "ubuntu_advantage"; will'
                    ' attempt to continue.')
        ua_section = cfg['ubuntu-advantage']
    if 'ubuntu_advantage' in cfg:
        ua_section = cfg['ubuntu_advantage']
    if ua_section is None:
        LOG.debug("Skipping module named %s,"
                  " no 'ubuntu_advantage' configuration found", name)
        return
    validate_cloudconfig_schema(cfg, schema)
    if 'commands' in ua_section:
        msg = (
            'Deprecated configuration "ubuntu-advantage: commands" provided.'
            ' Expected "token"')
        LOG.error(msg)
        raise RuntimeError(msg)

    maybe_install_ua_tools(cloud)
    configure_ua(token=ua_section.get('token'),
                 enable=ua_section.get('enable'))
Beispiel #51
0
def handle(name, cfg, _cloud, log, args):
    if len(args) != 0:
        resize_root = args[0]
    else:
        resize_root = util.get_cfg_option_str(cfg, "resize_rootfs", True)
    validate_cloudconfig_schema(cfg, schema)
    if not util.translate_bool(resize_root, addons=[NOBLOCK]):
        log.debug("Skipping module named %s, resizing disabled", name)
        return

    # TODO(harlowja): allow what is to be resized to be configurable??
    resize_what = "/"
    result = util.get_mount_info(resize_what, log)
    if not result:
        log.warn("Could not determine filesystem type of %s", resize_what)
        return

    (devpth, fs_type, mount_point) = result

    # if we have a zfs then our device path at this point
    # is the zfs label. For example: vmzroot/ROOT/freebsd
    # we will have to get the zpool name out of this
    # and set the resize_what variable to the zpool
    # so the _resize_zfs function gets the right attribute.
    if fs_type == 'zfs':
        zpool = devpth.split('/')[0]
        devpth = util.get_device_info_from_zpool(zpool)
        if not devpth:
            return  # could not find device from zpool
        resize_what = zpool

    info = "dev=%s mnt_point=%s path=%s" % (devpth, mount_point, resize_what)
    log.debug("resize_info: %s" % info)

    devpth = maybe_get_writable_device_path(devpth, info, log)
    if not devpth:
        return  # devpath was not a writable block device

    resizer = None
    if can_skip_resize(fs_type, resize_what, devpth):
        log.debug("Skip resize filesystem type %s for %s",
                  fs_type, resize_what)
        return

    fstype_lc = fs_type.lower()
    for (pfix, root_cmd) in RESIZE_FS_PREFIXES_CMDS:
        if fstype_lc.startswith(pfix):
            resizer = root_cmd
            break

    if not resizer:
        log.warn("Not resizing unknown filesystem type %s for %s",
                 fs_type, resize_what)
        return

    resize_cmd = resizer(resize_what, devpth)
    log.debug("Resizing %s (%s) using %s", resize_what, fs_type,
              ' '.join(resize_cmd))

    if resize_root == NOBLOCK:
        # Fork to a child that will run
        # the resize command
        util.fork_cb(
            util.log_time, logfunc=log.debug, msg="backgrounded Resizing",
            func=do_resize, args=(resize_cmd, log))
    else:
        util.log_time(logfunc=log.debug, msg="Resizing",
                      func=do_resize, args=(resize_cmd, log))

    action = 'Resized'
    if resize_root == NOBLOCK:
        action = 'Resizing (via forking)'
    log.debug("%s root filesystem (type=%s, val=%s)", action, fs_type,
              resize_root)
 def test_schema_requires_boolean_for_license_accepted(self):
     with self.assertRaisesRegex(
             SchemaValidationError, ".*license-accepted.*TRUE.*boolean"):
         validate_cloudconfig_schema(
             {'drivers': {'nvidia': {'license-accepted': "TRUE"}}},
             schema=drivers.schema, strict=True)
Beispiel #53
0
def handle(name, cfg, cloud, log, _args):
    """Enable and configure ntp."""
    if 'ntp' not in cfg:
        LOG.debug(
            "Skipping module named %s, not present or disabled by cfg", name)
        return
    ntp_cfg = cfg['ntp']
    if ntp_cfg is None:
        ntp_cfg = {}  # Allow empty config which will install the package

    # TODO drop this when validate_cloudconfig_schema is strict=True
    if not isinstance(ntp_cfg, (dict)):
        raise RuntimeError(
            "'ntp' key existed in config, but not a dictionary type,"
            " is a {_type} instead".format(_type=type_utils.obj_name(ntp_cfg)))

    validate_cloudconfig_schema(cfg, schema)

    # Allow users to explicitly enable/disable
    enabled = ntp_cfg.get('enabled', True)
    if util.is_false(enabled):
        LOG.debug("Skipping module named %s, disabled by cfg", name)
        return

    # Select which client is going to be used and get the configuration
    ntp_client_config = select_ntp_client(ntp_cfg.get('ntp_client'),
                                          cloud.distro)

    # Allow user ntp config to override distro configurations
    ntp_client_config = util.mergemanydict(
        [ntp_client_config, ntp_cfg.get('config', {})], reverse=True)

    supplemental_schema_validation(ntp_client_config)
    rename_ntp_conf(confpath=ntp_client_config.get('confpath'))

    template_fn = None
    if not ntp_client_config.get('template'):
        template_name = (
            ntp_client_config.get('template_name').replace('{distro}',
                                                           cloud.distro.name))
        template_fn = cloud.get_template_filename(template_name)
        if not template_fn:
            msg = ('No template found, not rendering %s' %
                   ntp_client_config.get('template_name'))
            raise RuntimeError(msg)

    write_ntp_config_template(cloud.distro.name,
                              servers=ntp_cfg.get('servers', []),
                              pools=ntp_cfg.get('pools', []),
                              path=ntp_client_config.get('confpath'),
                              template_fn=template_fn,
                              template=ntp_client_config.get('template'))

    install_ntp_client(cloud.distro.install_packages,
                       packages=ntp_client_config['packages'],
                       check_exe=ntp_client_config['check_exe'])
    try:
        reload_ntp(ntp_client_config['service_name'],
                   systemd=cloud.distro.uses_systemd())
    except util.ProcessExecutionError as e:
        LOG.exception("Failed to reload/start ntp service: %s", e)
        raise