From 880705cf2fcb3ac64f3610d4a4ad1f0e00f4efe2 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Wed, 27 Apr 2022 16:28:42 -0500 Subject: [PATCH 1/5] docs: Add docs for module creation Additionally remove the cc_foo module as any relevant documentation there has been moved to the official documentation. --- cloudinit/config/cc_foo.py | 70 ---------------------- doc/rtd/index.rst | 1 + doc/rtd/topics/module_creation.rst | 94 ++++++++++++++++++++++++++++++ doc/rtd/topics/modules.rst | 5 +- 4 files changed, 97 insertions(+), 73 deletions(-) delete mode 100644 cloudinit/config/cc_foo.py create mode 100644 doc/rtd/topics/module_creation.rst diff --git a/cloudinit/config/cc_foo.py b/cloudinit/config/cc_foo.py deleted file mode 100644 index 3d881209b2a..00000000000 --- a/cloudinit/config/cc_foo.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (C) 2009-2010 Canonical Ltd. -# Copyright (C) 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Scott Moser -# Author: Juerg Haefliger -# -# This file is part of cloud-init. See LICENSE file for license information. -"""Foo: Example module""" - -from typing import List - -from cloudinit.config.schema import MetaSchema, get_meta_doc -from cloudinit.settings import PER_ONCE - -MODULE_DESCRIPTION = """\ -Example to show module structure. Does not do anything. - -**Internal name:** ``cc_foo`` - -**Module frequency:** per instance - -**Supported distros:** all -""" - -distros: List[str] = [] -frequency = PER_ONCE -meta: MetaSchema = { - "id": "cc_foo", - "name": "Foo", - "title": "Example module", - "description": MODULE_DESCRIPTION, - "distros": distros, - "frequency": frequency, - "examples": [], -} - -__doc__ = get_meta_doc(meta) - - -# Modules are expected to have the following attributes. -# 1. A required 'handle' method which takes the following params. -# a) The name will not be this files name, but instead -# the name specified in configuration (which is the name -# which will be used to find this module). -# b) A configuration object that is the result of the merging -# of cloud configs configuration with legacy configuration -# as well as any datasource provided configuration -# c) 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. -# d) A argument list that may or may not be empty to this module. -# Typically those are from module configuration where the module -# is defined with some extra configuration that will eventually -# be translated from yaml into arguments to this module. -# 2. A optional 'frequency' that defines how often this module should be run. -# Typically one of PER_INSTANCE, PER_ALWAYS, PER_ONCE. If not -# provided PER_INSTANCE will be assumed. -# See settings.py for these constants. -# 3. A optional 'distros' array/set/tuple that defines the known distros -# this module will work with (if not all of them). This is used to write -# a warning out if a module is being ran on a untested distribution for -# informational purposes. If non existent all distros are assumed and -# no warning occurs. - - -def handle(name, _cfg, _cloud, log, _args): - log.debug("Hi from module %s", name) - - -# vi: ts=4 expandtab diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst index 8bdff4a516e..1516a5cb0bd 100644 --- a/doc/rtd/index.rst +++ b/doc/rtd/index.rst @@ -65,6 +65,7 @@ Having trouble? We would like to help! :caption: Development topics/contributing.rst + topics/module_creation.rst topics/code_review.rst topics/security.rst topics/debugging.rst diff --git a/doc/rtd/topics/module_creation.rst b/doc/rtd/topics/module_creation.rst new file mode 100644 index 00000000000..fb842b633a3 --- /dev/null +++ b/doc/rtd/topics/module_creation.rst @@ -0,0 +1,94 @@ +.. _module_creation: + +Module Creation +*************** + +Much of cloud-init functionality is provided by :ref:`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.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, + "examples": [ + "cc_example: example1", + "cc_example: ['example', 2]", + ], + } + + __doc__ = get_meta_doc(meta) + + + def handle(name: str, cfg: dict, cloud: Cloud, log: Logger, args: list): + 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. + +* If your module introduces any new cloud-config keys, you must provide a + schema definition in `cloud-init-schema.json`_. +* The ``meta`` variable must exist and be of type `MetaSchema`_. + + * ``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. + + * ``examples``: Lists examples to be shown in the documentation. + These examples will automatically be tested against the defined schema + during testing. + +* ``__doc__ = get_meta_doc(meta)`` is necessary to provide proper module + documentation. + + +.. _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 +.. _cloud-init-schema.json: https://github.com/canonical/cloud-init/blob/main/cloudinit/config/cloud-init-schema.json diff --git a/doc/rtd/topics/modules.rst b/doc/rtd/topics/modules.rst index 80a136bedc7..47789ddba0b 100644 --- a/doc/rtd/topics/modules.rst +++ b/doc/rtd/topics/modules.rst @@ -1,9 +1,8 @@ .. _modules: -******* -Modules -******* +Module Reference +**************** .. contents:: Table of Contents .. automodule:: cloudinit.config.cc_apk_configure From 4faafe36173c1e70c89f9a87aacaaad06fcd2dd8 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Mon, 2 May 2022 10:41:21 -0500 Subject: [PATCH 2/5] Remove cc_foo from documentation --- doc/rtd/topics/modules.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/rtd/topics/modules.rst b/doc/rtd/topics/modules.rst index 47789ddba0b..4bfb27cf4af 100644 --- a/doc/rtd/topics/modules.rst +++ b/doc/rtd/topics/modules.rst @@ -17,7 +17,6 @@ Module Reference .. automodule:: cloudinit.config.cc_disk_setup .. automodule:: cloudinit.config.cc_fan .. automodule:: cloudinit.config.cc_final_message -.. automodule:: cloudinit.config.cc_foo .. automodule:: cloudinit.config.cc_growpart .. automodule:: cloudinit.config.cc_grub_dpkg .. automodule:: cloudinit.config.cc_install_hotplug From c1e7bc9a09ee865ab050933b35612a1d2c0df79b Mon Sep 17 00:00:00 2001 From: James Falcon Date: Mon, 2 May 2022 10:39:13 -0500 Subject: [PATCH 3/5] review comments --- doc/rtd/topics/module_creation.rst | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/doc/rtd/topics/module_creation.rst b/doc/rtd/topics/module_creation.rst index fb842b633a3..07108511e88 100644 --- a/doc/rtd/topics/module_creation.rst +++ b/doc/rtd/topics/module_creation.rst @@ -35,8 +35,8 @@ Example "distros": [ALL_DISTROS], "frequency": PER_INSTANCE, "examples": [ - "cc_example: example1", - "cc_example: ['example', 2]", + "example_key: example_value", + "example_other_key: ['value', 2]", ], } @@ -68,6 +68,8 @@ Guidelines schema definition in `cloud-init-schema.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. @@ -80,15 +82,31 @@ Guidelines would be a significant change to the instance metadata. An example could be an instance being moved to a different subnet. - * ``examples``: Lists examples to be shown in the documentation. - These examples will automatically be tested against the defined schema + * ``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 ``/etc/cloud`` on the +launched instance. To do so, add your module to `cloud.cfg.tmpl`_ under +the appropriate module section. The three module sections are +`cloud_init_modules`_, `cloud_config_modules`_, and `cloud_final_modules`_. +Each section corresponds to the :ref:`topics/boot:Network`, +:ref:`topics/boot:Config`, and :ref:`topics/boot:Final` boot stages +respectively. + .. _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 .. _cloud-init-schema.json: https://github.com/canonical/cloud-init/blob/main/cloudinit/config/cloud-init-schema.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 From 2f7f9fd02d1f49b6c93314fa05bacb77a0fb1368 Mon Sep 17 00:00:00 2001 From: James Falcon Date: Mon, 2 May 2022 11:05:53 -0500 Subject: [PATCH 4/5] some additional wordsmithing --- doc/rtd/topics/module_creation.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/doc/rtd/topics/module_creation.rst b/doc/rtd/topics/module_creation.rst index 07108511e88..65794c998e8 100644 --- a/doc/rtd/topics/module_creation.rst +++ b/doc/rtd/topics/module_creation.rst @@ -94,12 +94,17 @@ Module Execution ================ In order for a module to be run, it must be defined in ``/etc/cloud`` on the -launched instance. To do so, add your module to `cloud.cfg.tmpl`_ under -the appropriate module section. The three module sections are -`cloud_init_modules`_, `cloud_config_modules`_, and `cloud_final_modules`_. -Each section corresponds to the :ref:`topics/boot:Network`, -:ref:`topics/boot:Config`, and :ref:`topics/boot:Final` boot stages -respectively. +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 From d2bbe429a7d27ea25008101dcf8cbb93b28b2b0c Mon Sep 17 00:00:00 2001 From: James Falcon Date: Tue, 3 May 2022 09:02:17 -0500 Subject: [PATCH 5/5] comments --- doc/rtd/topics/module_creation.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/rtd/topics/module_creation.rst b/doc/rtd/topics/module_creation.rst index 65794c998e8..b09cd2cc3f8 100644 --- a/doc/rtd/topics/module_creation.rst +++ b/doc/rtd/topics/module_creation.rst @@ -93,8 +93,9 @@ Guidelines Module Execution ================ -In order for a module to be run, it must be defined in ``/etc/cloud`` on the -launched instance. The three module sections are +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.