summaryrefslogtreecommitdiff
path: root/doc/rtd/topics/module_creation.rst
blob: 69a6a8aeb6b7c3910296ae7e9c2e1df8a95e14ac (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
134
135
.. _module_creation:

Module Creation
***************

Much of cloud-init functionality is provided by :ref:`modules<modules>`.
All modules follow a similar layout in order to provide consistent execution
and documentation. Use the example provided here to create a new module.

Example
=======
.. code-block:: python

    # This file is part of cloud-init. See LICENSE file for license information.
    """Example Module: Shows how to create a module"""

    from logging import Logger

    from cloudinit.cloud import Cloud
    from cloudinit.config import Config
    from cloudinit.config.schema import MetaSchema, get_meta_doc
    from cloudinit.distros import ALL_DISTROS
    from cloudinit.settings import PER_INSTANCE

    MODULE_DESCRIPTION = """\
    Description that will be used in module documentation.

    This will likely take multiple lines.
    """

    meta: MetaSchema = {
        "id": "cc_example",
        "name": "Example Module",
        "title": "Shows how to create a module",
        "description": MODULE_DESCRIPTION,
        "distros": [ALL_DISTROS],
        "frequency": PER_INSTANCE,
        "activate_by_schema_keys": ["example_key, example_other_key"],
        "examples": [
            "example_key: example_value",
            "example_other_key: ['value', 2]",
        ],
    }

    __doc__ = get_meta_doc(meta)


    def handle(
        name: str, cfg: Config, cloud: Cloud, log: Logger, args: list
    ) -> None:
        log.debug(f"Hi from module {name}")


Guidelines
==========

* Create a new module in the ``cloudinit/config`` directory with a `cc_`
  prefix.
* Your module must include a ``handle`` function. The arguments are:

  * ``name``: The module name specified in the configuration
  * ``cfg``: A configuration object that is the result of the merging of
    cloud-config configuration with any datasource provided configuration.
  * ``cloud``: A cloud object that can be used to access various datasource
    and paths for the given distro and data provided by the various datasource
    instance types.
  * ``log``: A logger object that can be used to log messages.
  * ``args``: An argument list. This is usually empty and is only populated
    if the module is called independently from the command line or if the
    module definition in ``/etc/cloud/cloud.cfg[.d]`` has been modified
    to pass arguments to this module.

* Your module name must be included in `schema-cloud-config.json`_
  under ``$defs.all_modules``, in order to be accepted as a module key in
  the :ref:`base config<base_config_reference>`.

* Add the new module to `Module Reference`_.

* If your module introduces any new cloud-config keys, you must provide a
  schema definition in `schema-cloud-config.json`_.
* The ``meta`` variable must exist and be of type `MetaSchema`_.

  * ``id``: The module id. In most cases this will be the filename without
    the `.py` extension.
  * ``distros``: Defines the list of supported distros. It can contain
    any of the values (not keys) defined in the `OSFAMILIES`_ map or
    ``[ALL_DISTROS]`` if there is no distro restriction.
  * ``frequency``: Defines how often module runs. It must be one of:

    * ``PER_ALWAYS``: Runs on every boot.
    * ``ONCE``: Runs only on first boot.
    * ``PER_INSTANCE``: Runs once per instance. When exactly this happens
      is dependent on the datasource but may triggered anytime there
      would be a significant change to the instance metadata. An example
      could be an instance being moved to a different subnet.

  * ``activate_by_schema_keys``: (Optional) List of cloud-config keys that will
    activate this module. When this list not empty, the config module will be
    skipped unless one of the ``activate_by_schema_keys`` are present in merged
    cloud-config instance-data.
  * ``examples``: Lists examples of any cloud-config keys this module reacts
    to. These examples will be rendered in the module reference documentation
    and will automatically be tested against the defined schema
    during testing.

* ``__doc__ = get_meta_doc(meta)`` is necessary to provide proper module
  documentation.

Module Execution
================

In order for a module to be run, it must be defined in a module run section in
``/etc/cloud/cloud.cfg`` or ``/etc/cloud/cloud.cfg.d`` on the launched
instance. The three module sections are
`cloud_init_modules`_, `cloud_config_modules`_, and `cloud_final_modules`_,
corresponding to the :ref:`topics/boot:Network`, :ref:`topics/boot:Config`,
and :ref:`topics/boot:Final` boot stages respectively.

Add your module to `cloud.cfg.tmpl`_ under the appropriate module section.
Each module gets run in the order listed, so ensure your module is defined
in the correct location based on dependencies. If your module has no particular
dependencies or is not necessary for a later boot stage, it should be placed
in the ``cloud_final_modules`` section before the ``final-message`` module.



.. _MetaSchema: https://github.com/canonical/cloud-init/blob/3bcffacb216d683241cf955e4f7f3e89431c1491/cloudinit/config/schema.py#L58
.. _OSFAMILIES: https://github.com/canonical/cloud-init/blob/3bcffacb216d683241cf955e4f7f3e89431c1491/cloudinit/distros/__init__.py#L35
.. _settings.py: https://github.com/canonical/cloud-init/blob/3bcffacb216d683241cf955e4f7f3e89431c1491/cloudinit/settings.py#L66
.. _schema-cloud-config.json: https://github.com/canonical/cloud-init/blob/main/cloudinit/config/schemas/schema-cloud-config-v1.json
.. _cloud.cfg.tmpl: https://github.com/canonical/cloud-init/blob/main/config/cloud.cfg.tmpl
.. _cloud_init_modules: https://github.com/canonical/cloud-init/blob/b4746b6aed7660510071395e70b2d6233fbdc3ab/config/cloud.cfg.tmpl#L70
.. _cloud_config_modules: https://github.com/canonical/cloud-init/blob/b4746b6aed7660510071395e70b2d6233fbdc3ab/config/cloud.cfg.tmpl#L101
.. _cloud_final_modules: https://github.com/canonical/cloud-init/blob/b4746b6aed7660510071395e70b2d6233fbdc3ab/config/cloud.cfg.tmpl#L144
.. _Module Reference: https://github.com/canonical/cloud-init/blob/main/doc/rtd/topics/modules.rst