summaryrefslogtreecommitdiff
path: root/cloudinit/config/cc_fan.py
blob: ae211f310ad8d1abf2187a985befc875eeaa1d7c (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
# Copyright (C) 2015 Canonical Ltd.
#
# Author: Scott Moser <scott.moser@canonical.com>
#
# This file is part of cloud-init. See LICENSE file for license information.
"""Fan: Configure ubuntu fan networking"""

from logging import Logger
from textwrap import dedent

from cloudinit import log as logging
from cloudinit import subp, util
from cloudinit.cloud import Cloud
from cloudinit.config import Config
from cloudinit.config.schema import MetaSchema, get_meta_doc
from cloudinit.settings import PER_INSTANCE

MODULE_DESCRIPTION = """\
This module installs, configures and starts the ubuntu fan network system. For
more information about Ubuntu Fan, see:
``https://wiki.ubuntu.com/FanNetworking``.

If cloud-init sees a ``fan`` entry in cloud-config it will:

    - write ``config_path`` with the contents of the ``config`` key
    - install the package ``ubuntu-fan`` if it is not installed
    - ensure the service is started (or restarted if was previously running)

Additionally, the ``ubuntu-fan`` package will be automatically installed
if not present.
"""

distros = ["ubuntu"]
meta: MetaSchema = {
    "id": "cc_fan",
    "name": "Fan",
    "title": "Configure ubuntu fan networking",
    "description": MODULE_DESCRIPTION,
    "distros": distros,
    "frequency": PER_INSTANCE,
    "examples": [
        dedent(
            """\
            fan:
              config: |
                # fan 240
                10.0.0.0/8 eth0/16 dhcp
                10.0.0.0/8 eth1/16 dhcp off
                # fan 241
                241.0.0.0/8 eth0/16 dhcp
              config_path: /etc/network/fan
            """
        )
    ],
    "activate_by_schema_keys": ["fan"],
}

__doc__ = get_meta_doc(meta)

LOG = logging.getLogger(__name__)

BUILTIN_CFG = {
    "config": None,
    "config_path": "/etc/network/fan",
}


def stop_update_start(distro, service, config_file, content):
    try:
        distro.manage_service("stop", service)
        stop_failed = False
    except subp.ProcessExecutionError as e:
        stop_failed = True
        LOG.warning("failed to stop %s: %s", service, e)

    if not content.endswith("\n"):
        content += "\n"
    util.write_file(config_file, content, omode="w")

    try:
        distro.manage_service("start", service)
        if stop_failed:
            LOG.warning("success: %s started", service)
    except subp.ProcessExecutionError as e:
        LOG.warning("failed to start %s: %s", service, e)

    distro.manage_service("enable", service)


def handle(
    name: str, cfg: Config, cloud: Cloud, log: Logger, args: list
) -> None:
    cfgin = cfg.get("fan")
    if not cfgin:
        cfgin = {}
    mycfg = util.mergemanydict([cfgin, BUILTIN_CFG])

    if not mycfg.get("config"):
        LOG.debug("%s: no 'fan' config entry. disabling", name)
        return

    util.write_file(mycfg.get("config_path"), mycfg.get("config"), omode="w")
    distro = cloud.distro
    if not subp.which("fanctl"):
        distro.install_packages(["ubuntu-fan"])

    stop_update_start(
        distro,
        service="ubuntu-fan",
        config_file=mycfg.get("config_path"),
        content=mycfg.get("config"),
    )


# vi: ts=4 expandtab