diff options
| -rw-r--r-- | cloudinit/config/cc_apt_configure.py | 4 | ||||
| -rw-r--r-- | cloudinit/config/cc_emit_upstart.py | 28 | ||||
| -rw-r--r-- | cloudinit/config/cc_grub_dpkg.py | 21 | ||||
| -rw-r--r-- | cloudinit/config/cc_locale.py | 6 | ||||
| -rw-r--r-- | cloudinit/config/cc_snappy.py | 133 | ||||
| -rw-r--r-- | cloudinit/settings.py | 2 | ||||
| -rw-r--r-- | cloudinit/stages.py | 21 | ||||
| -rw-r--r-- | config/cloud.cfg | 1 | ||||
| -rw-r--r-- | doc/examples/cloud-config.txt | 2 | 
9 files changed, 197 insertions, 21 deletions
| diff --git a/cloudinit/config/cc_apt_configure.py b/cloudinit/config/cc_apt_configure.py index de72903f..2c51d116 100644 --- a/cloudinit/config/cc_apt_configure.py +++ b/cloudinit/config/cc_apt_configure.py @@ -51,6 +51,10 @@ EXPORT_GPG_KEYID = """  def handle(name, cfg, cloud, log, _args): +    if util.is_false(cfg.get('apt_configure_enabled', True)): +        log.debug("Skipping module named %s, disabled by config.", name) +        return +      release = get_release()      mirrors = find_apt_mirror_info(cloud, cfg)      if not mirrors or "primary" not in mirrors: diff --git a/cloudinit/config/cc_emit_upstart.py b/cloudinit/config/cc_emit_upstart.py index 6d376184..e1b9a4c2 100644 --- a/cloudinit/config/cc_emit_upstart.py +++ b/cloudinit/config/cc_emit_upstart.py @@ -21,11 +21,32 @@  import os  from cloudinit.settings import PER_ALWAYS +from cloudinit import log as logging  from cloudinit import util  frequency = PER_ALWAYS  distros = ['ubuntu', 'debian'] +LOG = logging.getLogger(__name__) + + +def is_upstart_system(): +    if not os.path.isfile("/sbin/initctl"): +        LOG.debug(("Skipping module named %s," +                   " no /sbin/initctl located"), name) +        return False + +    myenv = os.environ.copy() +    if 'UPSTART_SESSION' in myenv: +        del myenv['UPSTART_SESSION'] +    check_cmd = ['initctl', 'version'] +    try: +        (out, err) = util.subp(check_cmd, env=myenv) +        return 'upstart' in out +    except util.ProcessExecutionError as e: +        LOG.debug("'%s' returned '%s', not using upstart", +                  ' '.join(check_cmd), e.exit_code) +    return False  def handle(name, _cfg, cloud, log, args): @@ -34,10 +55,11 @@ def handle(name, _cfg, cloud, log, args):          # Default to the 'cloud-config'          # event for backwards compat.          event_names = ['cloud-config'] -    if not os.path.isfile("/sbin/initctl"): -        log.debug(("Skipping module named %s," -                   " no /sbin/initctl located"), name) + +    if not is_upstart_system(): +        log.debug("not upstart system, '%s' disabled")          return +      cfgpath = cloud.paths.get_ipath_cur("cloud_config")      for n in event_names:          cmd = ['initctl', 'emit', str(n), 'CLOUD_CFG=%s' % cfgpath] diff --git a/cloudinit/config/cc_grub_dpkg.py b/cloudinit/config/cc_grub_dpkg.py index e3219e81..456597af 100644 --- a/cloudinit/config/cc_grub_dpkg.py +++ b/cloudinit/config/cc_grub_dpkg.py @@ -25,15 +25,20 @@ from cloudinit import util  distros = ['ubuntu', 'debian'] -def handle(_name, cfg, _cloud, log, _args): -    idevs = None -    idevs_empty = None +def handle(name, cfg, _cloud, log, _args): -    if "grub-dpkg" in cfg: -        idevs = util.get_cfg_option_str(cfg["grub-dpkg"], -            "grub-pc/install_devices", None) -        idevs_empty = util.get_cfg_option_str(cfg["grub-dpkg"], -            "grub-pc/install_devices_empty", None) +    mycfg = cfg.get("grub_dpkg", cfg.get("grub-dpkg", {})) +    if not mycfg: +        mycfg = {} + +    enabled = mycfg.get('enabled', True) +    if util.is_false(enabled): +        log.debug("%s disabled by config grub_dpkg/enabled=%s", name, enabled) +        return + +    idevs = util.get_cfg_option_str(mycfg, "grub-pc/install_devices", None) +    idevs_empty = util.get_cfg_option_str(mycfg, +        "grub-pc/install_devices_empty", None)      if ((os.path.exists("/dev/sda1") and not os.path.exists("/dev/sda")) or              (os.path.exists("/dev/xvda1") diff --git a/cloudinit/config/cc_locale.py b/cloudinit/config/cc_locale.py index 6feaae9d..bbe5fcae 100644 --- a/cloudinit/config/cc_locale.py +++ b/cloudinit/config/cc_locale.py @@ -27,9 +27,9 @@ def handle(name, cfg, cloud, log, args):      else:          locale = util.get_cfg_option_str(cfg, "locale", cloud.get_locale()) -    if not locale: -        log.debug(("Skipping module named %s, " -                   "no 'locale' configuration found"), name) +    if util.is_false(locale): +        log.debug("Skipping module named %s, disabled by config: %s", +                  name, locale)          return      log.debug("Setting locale to %s", locale) diff --git a/cloudinit/config/cc_snappy.py b/cloudinit/config/cc_snappy.py new file mode 100644 index 00000000..1588443f --- /dev/null +++ b/cloudinit/config/cc_snappy.py @@ -0,0 +1,133 @@ +# vi: ts=4 expandtab +# + +from cloudinit import log as logging +from cloudinit import templater +from cloudinit import util +from cloudinit.settings import PER_INSTANCE + +import glob +import os + +LOG = logging.getLogger(__name__) + +frequency = PER_INSTANCE +SNAPPY_ENV_PATH = "/writable/system-data/etc/snappy.env" + +CI_SNAPPY_CFG = { +    'env_file_path': SNAPPY_ENV_PATH, +    'packages': [], +    'packages_dir': '/writable/user-data/cloud-init/click_packages', +    'ssh_enabled': False +} + +""" +snappy: +  ssh_enabled: True +  packages: +    - etcd +    - {'name': 'pkg1', 'config': "wark"} +""" + + +def flatten(data, fill=None, tok="_", prefix='', recurse=True): +    if fill is None: +        fill = {} +    for key, val in data.items(): +        key = key.replace("-", "_") +        if isinstance(val, dict) and recurse: +            flatten(val, fill, tok=tok, prefix=prefix + key + tok, +                    recurse=recurse) +        elif isinstance(key, str): +            fill[prefix + key] = val +    return fill + + +def render2env(data, tok="_", prefix=''): +    flat = flatten(data, tok=tok, prefix=prefix) +    ret = ["%s='%s'" % (key, val) for key, val in flat.items()] +    return '\n'.join(ret) + '\n' + + +def install_package(pkg_name, config=None): +    cmd = ["snappy", "install"] +    if config: +        if os.path.isfile(config): +            cmd.append("--config-file=" + config) +        else: +            cmd.append("--config=" + config) +    cmd.append(pkg_name) +    util.subp(cmd) + + +def install_packages(package_dir, packages): +    local_pkgs = glob.glob(os.path.sep.join([package_dir, '*.click'])) +    LOG.debug("installing local packages %s" % local_pkgs) +    if local_pkgs: +        for pkg in local_pkgs: +            cfg = pkg.replace(".click", ".config") +            if not os.path.isfile(cfg): +                cfg = None +            install_package(pkg, config=cfg) + +    LOG.debug("installing click packages") +    if packages: +        for pkg in packages: +            if not pkg: +                continue +            if isinstance(pkg, str): +                name = pkg +                config = None +            elif pkg: +                name = pkg.get('name', pkg) +                config = pkg.get('config') +            install_package(pkg_name=name, config=config) + + +def disable_enable_ssh(enabled): +    LOG.debug("setting enablement of ssh to: %s", enabled) +    # do something here that would enable or disable +    not_to_be_run = "/etc/ssh/sshd_not_to_be_run" +    if enabled: +        util.del_file(not_to_be_run) +        # this is an indempotent operation +        util.subp(["systemctl", "start", "ssh"]) +    else: +        # this is an indempotent operation +        util.subp(["systemctl", "stop", "ssh"]) +        util.write_file(not_to_be_run, "cloud-init\n") + + +def handle(name, cfg, cloud, log, args): +    mycfg = cfg.get('snappy', {'ssh_enabled': False}) + +    if not mycfg: +        LOG.debug("%s: no top level found", name) +        return + +    # take out of 'cfg' the cfg keys that cloud-init uses, so +    # mycfg has only content external to cloud-init. +    ci_cfg = CI_SNAPPY_CFG.copy() +    for i in ci_cfg: +        if i in mycfg: +            ci_cfg[i] = mycfg[i] +            del mycfg[i] + +    # render the flattened environment variable style file to a path +    # this was useful for systemd config environment files.  given: +    # snappy: +    #   foo: +    #     bar: wark +    #     cfg1: +    #       key1: value +    # you get the following in env_file_path. +    #   foo_bar=wark +    #   foo_cfg1_key1=value +    contents = render2env(mycfg) +    header = '# for internal use only, not a guaranteed interface\n' +    util.write_file(ci_cfg['env_file_path'], header + render2env(mycfg)) + +    install_packages(ci_cfg['packages_dir'], +                     ci_cfg['packages']) + +    disable_enable_ssh(ci_cfg.get('ssh_enabled', False)) diff --git a/cloudinit/settings.py b/cloudinit/settings.py index 5efcb0b0..b61e5613 100644 --- a/cloudinit/settings.py +++ b/cloudinit/settings.py @@ -47,7 +47,7 @@ CFG_BUILTIN = {      ],      'def_log_file': '/var/log/cloud-init.log',      'log_cfgs': [], -    'syslog_fix_perms': 'syslog:adm', +    'syslog_fix_perms': ['syslog:adm', 'root:adm'],      'system_info': {          'paths': {              'cloud_dir': '/var/lib/cloud', diff --git a/cloudinit/stages.py b/cloudinit/stages.py index 45d64823..d28e765b 100644 --- a/cloudinit/stages.py +++ b/cloudinit/stages.py @@ -148,16 +148,25 @@ class Init(object):      def _initialize_filesystem(self):          util.ensure_dirs(self._initial_subdirs())          log_file = util.get_cfg_option_str(self.cfg, 'def_log_file') -        perms = util.get_cfg_option_str(self.cfg, 'syslog_fix_perms')          if log_file:              util.ensure_file(log_file) -            if perms: -                u, g = util.extract_usergroup(perms) +            perms = self.cfg.get('syslog_fix_perms') +            if not perms: +                perms = {} +            if not isinstance(perms, list): +                perms = [perms] + +            error = None +            for perm in perms: +                u, g = util.extract_usergroup(perm)                  try:                      util.chownbyname(log_file, u, g) -                except OSError: -                    util.logexc(LOG, "Unable to change the ownership of %s to " -                                "user %s, group %s", log_file, u, g) +                    return +                except OSError as e: +                    error = e + +            LOG.warn("Failed changing perms on '%s'. tried: %s. %s", +                     log_file, ','.join(perms), error)      def read_cfg(self, extra_fns=None):          # None check so that we don't keep on re-loading if empty diff --git a/config/cloud.cfg b/config/cloud.cfg index 200050d3..e96e1781 100644 --- a/config/cloud.cfg +++ b/config/cloud.cfg @@ -48,6 +48,7 @@ cloud_config_modules:   - ssh-import-id   - locale   - set-passwords + - snappy   - grub-dpkg   - apt-pipelining   - apt-configure diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt index 1c59c2cf..1236796c 100644 --- a/doc/examples/cloud-config.txt +++ b/doc/examples/cloud-config.txt @@ -536,6 +536,8 @@ timezone: US/Eastern  #   # to remedy this situation, 'def_log_file' can be set to a filename  # and syslog_fix_perms to a string containing "<user>:<group>" +# if syslog_fix_perms is a list, it will iterate through and use the +# first pair that does not raise error.  #  # the default values are '/var/log/cloud-init.log' and 'syslog:adm'  # the value of 'def_log_file' should match what is configured in logging | 
