summaryrefslogtreecommitdiff
path: root/cloudinit/config/cc_snappy.py
blob: 1588443f87d22a4906e171fdcf43ffe283fc6881 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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))