summaryrefslogtreecommitdiff
path: root/doc/rtd
diff options
context:
space:
mode:
Diffstat (limited to 'doc/rtd')
-rw-r--r--doc/rtd/index.rst1
-rw-r--r--doc/rtd/topics/datasources/aliyun.rst15
-rw-r--r--doc/rtd/topics/datasources/cloudstack.rst2
-rw-r--r--doc/rtd/topics/datasources/ovf.rst9
-rw-r--r--doc/rtd/topics/debugging.rst6
-rw-r--r--doc/rtd/topics/examples.rst4
-rw-r--r--doc/rtd/topics/format.rst14
-rw-r--r--doc/rtd/topics/integration_tests.rst32
-rw-r--r--doc/rtd/topics/network-config-format-v1.rst16
-rw-r--r--doc/rtd/topics/network-config-format-v2.rst33
-rw-r--r--doc/rtd/topics/testing.rst173
11 files changed, 280 insertions, 25 deletions
diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst
index ddcb0b31..10e8228f 100644
--- a/doc/rtd/index.rst
+++ b/doc/rtd/index.rst
@@ -75,6 +75,7 @@ Having trouble? We would like to help!
topics/dir_layout.rst
topics/analyze.rst
topics/docs.rst
+ topics/testing.rst
topics/integration_tests.rst
topics/cloud_tests.rst
diff --git a/doc/rtd/topics/datasources/aliyun.rst b/doc/rtd/topics/datasources/aliyun.rst
index 3f4f40ca..587bd4f4 100644
--- a/doc/rtd/topics/datasources/aliyun.rst
+++ b/doc/rtd/topics/datasources/aliyun.rst
@@ -12,6 +12,21 @@ The Alibaba Cloud metadata service is available at the well known url
Alibaba Cloud ECS on `metadata
<https://www.alibabacloud.com/help/zh/faq-detail/49122.htm>`__.
+Configuration
+-------------
+The following configuration can be set for the datasource in system
+configuration (in ``/etc/cloud/cloud.cfg`` or ``/etc/cloud/cloud.cfg.d/``).
+
+An example configuration with the default values is provided below:
+
+.. sourcecode:: yaml
+
+ datasource:
+ AliYun:
+ metadata_urls: ["http://100.100.100.200"]
+ timeout: 50
+ max_wait: 120
+
Versions
^^^^^^^^
Like the EC2 metadata service, Alibaba Cloud's metadata service provides
diff --git a/doc/rtd/topics/datasources/cloudstack.rst b/doc/rtd/topics/datasources/cloudstack.rst
index a24de34f..325aeeaf 100644
--- a/doc/rtd/topics/datasources/cloudstack.rst
+++ b/doc/rtd/topics/datasources/cloudstack.rst
@@ -46,8 +46,6 @@ An example configuration with the default values is provided below:
CloudStack:
max_wait: 120
timeout: 50
- datasource_list:
- - CloudStack
.. _Apache CloudStack: http://cloudstack.apache.org/
diff --git a/doc/rtd/topics/datasources/ovf.rst b/doc/rtd/topics/datasources/ovf.rst
index 6256e624..85b0c377 100644
--- a/doc/rtd/topics/datasources/ovf.rst
+++ b/doc/rtd/topics/datasources/ovf.rst
@@ -13,6 +13,15 @@ source code tree in doc/sources/ovf
Configuration
-------------
+The following configuration can be set for the datasource in system
+configuration (in `/etc/cloud/cloud.cfg` or `/etc/cloud/cloud.cfg.d/`).
+
+The settings that may be configured are:
+
+ * vmware_cust_file_max_wait: the maximum amount of clock time in seconds that
+ should be spent waiting for vmware customization files. (default: 15)
+
+
On VMware platforms, VMTools use is required for OVF datasource configuration
settings as well as vCloud and vSphere admin configuration. User could change
the VMTools configuration options with command::
diff --git a/doc/rtd/topics/debugging.rst b/doc/rtd/topics/debugging.rst
index 0d416f32..fb3006fe 100644
--- a/doc/rtd/topics/debugging.rst
+++ b/doc/rtd/topics/debugging.rst
@@ -1,6 +1,6 @@
-********************************
-Testing and debugging cloud-init
-********************************
+********************
+Debugging cloud-init
+********************
Overview
========
diff --git a/doc/rtd/topics/examples.rst b/doc/rtd/topics/examples.rst
index 81860f85..97fd616d 100644
--- a/doc/rtd/topics/examples.rst
+++ b/doc/rtd/topics/examples.rst
@@ -149,8 +149,8 @@ Disk setup
:language: yaml
:linenos:
-Register RedHat Subscription
-============================
+Register Red Hat Subscription
+=============================
.. literalinclude:: ../../examples/cloud-config-rh_subscription.txt
:language: yaml
diff --git a/doc/rtd/topics/format.rst b/doc/rtd/topics/format.rst
index d03e4caf..fa8aa925 100644
--- a/doc/rtd/topics/format.rst
+++ b/doc/rtd/topics/format.rst
@@ -23,9 +23,11 @@ Using a mime-multi part file, the user can specify more than one type of data.
For example, both a user data script and a cloud-config type could be
specified.
-Supported content-types are listed from the cloud-init subcommand make-mime::
+Supported content-types are listed from the cloud-init subcommand make-mime:
- % cloud-init devel make-mime --list-types
+.. code-block:: shell-session
+
+ $ cloud-init devel make-mime --list-types
cloud-boothook
cloud-config
cloud-config-archive
@@ -47,9 +49,11 @@ The cloud-init subcommand can generate MIME multi-part files: `make-mime`_.
separated by a colon (e.g. ``config.yaml:cloud-config``) and emits a MIME
multipart message to stdout. An example invocation, assuming you have your
cloud config in ``config.yaml`` and a shell script in ``script.sh`` and want
-to store the multipart message in ``user-data``::
+to store the multipart message in ``user-data``:
+
+.. code-block:: shell-session
- % cloud-init devel make-mime -a config.yaml:cloud-config -a script.sh:x-shellscript > user-data
+ $ cloud-init devel make-mime -a config.yaml:cloud-config -a script.sh:x-shellscript > user-data
.. _make-mime: https://github.com/canonical/cloud-init/blob/master/cloudinit/cmd/devel/make_mime.py
@@ -70,7 +74,7 @@ archive.
Example
-------
-::
+.. code-block:: shell-session
$ cat myscript.sh
diff --git a/doc/rtd/topics/integration_tests.rst b/doc/rtd/topics/integration_tests.rst
index aeda326c..6c124ad9 100644
--- a/doc/rtd/topics/integration_tests.rst
+++ b/doc/rtd/topics/integration_tests.rst
@@ -9,11 +9,41 @@ Overview
Integration tests are written using pytest and are located at
``tests/integration_tests``. General design principles
-laid out in :ref:`unit_testing` should be followed for integration tests.
+laid out in :ref:`testing` should be followed for integration tests.
Setup is accomplished via a set of fixtures located in
``tests/integration_tests/conftest.py``.
+Image Selection
+===============
+
+Each integration testing run uses a single image as its basis. This
+image is configured using the ``OS_IMAGE`` variable; see
+:ref:`Configuration` for details of how configuration works.
+
+``OS_IMAGE`` can take two types of value: an Ubuntu series name (e.g.
+"focal"), or an image specification. If an Ubuntu series name is
+given, then the most recent image for that series on the target cloud
+will be used. For other use cases, an image specification is used.
+
+In its simplest form, an image specification can simply be a cloud's
+image ID (e.g. "ami-deadbeef", "ubuntu:focal"). In this case, the
+image so-identified will be used as the basis for this testing run.
+
+This has a drawback, however: as we do not know what OS or release is
+within the image, the integration testing framework will run *all*
+tests against the image in question. If it's a RHEL8 image, then we
+would expect Ubuntu-specific tests to fail (and vice versa).
+
+To address this, a full image specification can be given. This is of
+the form: ``<image_id>[::<os>[::<release]]`` where ``image_id`` is a
+cloud's image ID, ``os`` is the OS name, and ``release`` is the OS
+release name. So, for example, Ubuntu 18.04 (Bionic Beaver) on LXD is
+``ubuntu:bionic::ubuntu::bionic`` or RHEL 8 on Amazon is
+``ami-justanexample::rhel::8``. When a full specification is given,
+only tests which are intended for use on that OS and release will be
+executed.
+
Image Setup
===========
diff --git a/doc/rtd/topics/network-config-format-v1.rst b/doc/rtd/topics/network-config-format-v1.rst
index 92e81897..17732c2a 100644
--- a/doc/rtd/topics/network-config-format-v1.rst
+++ b/doc/rtd/topics/network-config-format-v1.rst
@@ -414,9 +414,19 @@ Subnet types are one of the following:
- ``dhcp6``: Configure this interface with IPv6 dhcp.
- ``static``: Configure this interface with a static IPv4.
- ``static6``: Configure this interface with a static IPv6 .
+- ``ipv6_dhcpv6-stateful``: Configure this interface with ``dhcp6``
+- ``ipv6_dhcpv6-stateless``: Configure this interface with SLAAC and DHCP
+- ``ipv6_slaac``: Configure address with SLAAC
-When making use of ``dhcp`` types, no additional configuration is needed in
-the subnet dictionary.
+When making use of ``dhcp`` or either of the ``ipv6_dhcpv6`` types,
+no additional configuration is needed in the subnet dictionary.
+
+Using ``ipv6_dhcpv6-stateless`` or ``ipv6_slaac`` allows the IPv6 address to be
+automatically configured with StateLess Address AutoConfiguration (`SLAAC`_).
+SLAAC requires support from the network, so verify that your cloud or network
+offering has support before trying it out. With ``ipv6_dhcpv6-stateless``,
+DHCPv6 is still used to fetch other subnet details such as gateway or DNS
+servers. If you only want to discover the address, use ``ipv6_slaac``.
**Subnet DHCP Example**::
@@ -603,4 +613,6 @@ Some more examples to explore the various options available.
- dellstack
type: nameserver
+.. _SLAAC: https://tools.ietf.org/html/rfc4862
+
.. vi: textwidth=78
diff --git a/doc/rtd/topics/network-config-format-v2.rst b/doc/rtd/topics/network-config-format-v2.rst
index aa17bef5..af65a4ce 100644
--- a/doc/rtd/topics/network-config-format-v2.rst
+++ b/doc/rtd/topics/network-config-format-v2.rst
@@ -8,9 +8,25 @@ version 2 format defined for the `netplan`_ tool. Cloud-init supports
both reading and writing of Version 2; the latter support requires a
distro with `netplan`_ present.
+Netplan Passthrough
+-------------------
+
+On a system with netplan present, cloud-init will pass Version 2 configuration
+through to netplan without modification. On such systems, you do not need to
+limit yourself to the below subset of netplan's configuration format.
+
+.. warning::
+ If you are writing or generating network configuration that may be used on
+ non-netplan systems, you **must** limit yourself to the subset described in
+ this document, or you will see network configuration failures on
+ non-netplan systems.
+
+Version 2 Configuration Format
+------------------------------
+
The ``network`` key has at least two required elements. First
it must include ``version: 2`` and one or more of possible device
-``types``..
+``types``.
Cloud-init will read this format from system config.
For example the following could be present in
@@ -34,9 +50,6 @@ Each type block contains device definitions as a map where the keys (called
"configuration IDs"). Each entry under the ``types`` may include IP and/or
device configuration.
-Cloud-init does not current support ``wifis`` type that is present in native
-`netplan`_.
-
Device configuration IDs
------------------------
@@ -478,6 +491,11 @@ This is a complex example which shows most available features: ::
nameservers:
search: [foo.local, bar.local]
addresses: [8.8.8.8]
+ # static routes
+ routes:
+ - to: 192.0.2.0/24
+ via: 11.0.0.1
+ metric: 3
lom:
match:
driver: ixgbe
@@ -506,11 +524,6 @@ This is a complex example which shows most available features: ::
id: 1
link: id0
dhcp4: yes
- # static routes
- routes:
- - to: 0.0.0.0/0
- via: 11.0.0.1
- metric: 3
-.. _netplan: https://launchpad.net/netplan
+.. _netplan: https://netplan.io
.. vi: textwidth=78
diff --git a/doc/rtd/topics/testing.rst b/doc/rtd/topics/testing.rst
new file mode 100644
index 00000000..5b702bd2
--- /dev/null
+++ b/doc/rtd/topics/testing.rst
@@ -0,0 +1,173 @@
+*******
+Testing
+*******
+
+cloud-init has both unit tests and integration tests. Unit tests can
+be found in-tree alongside the source code, as well as
+at ``tests/unittests``. Integration tests can be found at
+``tests/integration_tests``. Documentation specifically for integration
+tests can be found on the :ref:`integration_tests` page, but
+the guidelines specified below apply to both types of tests.
+
+cloud-init uses `pytest`_ to run its tests, and has tests written both
+as ``unittest.TestCase`` sub-classes and as un-subclassed pytest tests.
+
+Guidelines
+==========
+
+The following guidelines should be followed.
+
+Test Layout
+-----------
+
+* For ease of organisation and greater accessibility for developers not
+ familiar with pytest, all cloud-init unit tests must be contained
+ within test classes
+
+ * Put another way, module-level test functions should not be used
+
+* As all tests are contained within classes, it is acceptable to mix
+ ``TestCase`` test classes and pytest test classes within the same
+ test file
+
+ * These can be easily distinguished by their definition: pytest
+ classes will not use inheritance at all (e.g.
+ `TestGetPackageMirrorInfo`_), whereas ``TestCase`` classes will
+ subclass (indirectly) from ``TestCase`` (e.g.
+ `TestPrependBaseCommands`_)
+
+``pytest`` Tests
+----------------
+
+* pytest test classes should use `pytest fixtures`_ to share
+ functionality instead of inheritance
+
+* pytest tests should use bare ``assert`` statements, to take advantage
+ of pytest's `assertion introspection`_
+
+ * For ``==`` and other commutative assertions, the expected value
+ should be placed before the value under test:
+ ``assert expected_value == function_under_test()``
+
+
+``pytest`` Version Gotchas
+--------------------------
+
+As we still support Ubuntu 16.04 (Xenial Xerus), we can only use pytest
+features that are available in v2.8.7. This is an inexhaustive list of
+ways in which this may catch you out:
+
+* Support for using ``yield`` in ``pytest.fixture`` functions was only
+ introduced in `pytest 3.0`_. Such functions must instead use the
+ ``pytest.yield_fixture`` decorator.
+
+* Only the following built-in fixtures are available [#fixture-list]_:
+
+ * ``cache``
+ * ``capfd``
+ * ``caplog`` (provided by ``python3-pytest-catchlog`` on xenial)
+ * ``capsys``
+ * ``monkeypatch``
+ * ``pytestconfig``
+ * ``record_xml_property``
+ * ``recwarn``
+ * ``tmpdir_factory``
+ * ``tmpdir``
+
+* On xenial, the objects returned by the ``tmpdir`` fixture cannot be
+ used where paths are required; they are rejected as invalid paths.
+ You must instead use their ``.strpath`` attribute.
+
+ * For example, instead of ``util.write_file(tmpdir.join("some_file"),
+ ...)``, you should write
+ ``util.write_file(tmpdir.join("some_file").strpath, ...)``.
+
+* The `pytest.param`_ function cannot be used. It was introduced in
+ pytest 3.1, which means it is not available on xenial. The more
+ limited mechanism it replaced was removed in pytest 4.0, so is not
+ available in focal or later. The only available alternatives are to
+ write mark-requiring test instances as completely separate tests,
+ without utilising parameterisation, or to apply the mark to the
+ entire parameterized test (and therefore every test instance).
+
+Mocking and Assertions
+----------------------
+
+* Variables/parameter names for ``Mock`` or ``MagicMock`` instances
+ should start with ``m_`` to clearly distinguish them from non-mock
+ variables
+
+ * For example, ``m_readurl`` (which would be a mock for ``readurl``)
+
+* The ``assert_*`` methods that are available on ``Mock`` and
+ ``MagicMock`` objects should be avoided, as typos in these method
+ names may not raise ``AttributeError`` (and so can cause tests to
+ silently pass). An important exception: if a ``Mock`` is
+ `autospecced`_ then misspelled assertion methods *will* raise an
+ ``AttributeError``, so these assertion methods may be used on
+ autospecced ``Mock`` objects.
+
+ For non-autospecced ``Mock`` s, these substitutions can be used
+ (``m`` is assumed to be a ``Mock``):
+
+ * ``m.assert_any_call(*args, **kwargs)`` => ``assert
+ mock.call(*args, **kwargs) in m.call_args_list``
+ * ``m.assert_called()`` => ``assert 0 != m.call_count``
+ * ``m.assert_called_once()`` => ``assert 1 == m.call_count``
+ * ``m.assert_called_once_with(*args, **kwargs)`` => ``assert
+ [mock.call(*args, **kwargs)] == m.call_args_list``
+ * ``m.assert_called_with(*args, **kwargs)`` => ``assert
+ mock.call(*args, **kwargs) == m.call_args_list[-1]``
+ * ``m.assert_has_calls(call_list, any_order=True)`` => ``for call in
+ call_list: assert call in m.call_args_list``
+
+ * ``m.assert_has_calls(...)`` and ``m.assert_has_calls(...,
+ any_order=False)`` are not easily replicated in a single
+ statement, so their use when appropriate is acceptable.
+
+ * ``m.assert_not_called()`` => ``assert 0 == m.call_count``
+
+* When there are multiple patch calls in a test file for the module it
+ is testing, it may be desirable to capture the shared string prefix
+ for these patch calls in a module-level variable. If used, such
+ variables should be named ``M_PATH`` or, for datasource tests,
+ ``DS_PATH``.
+
+Test Argument Ordering
+----------------------
+
+* Test arguments should be ordered as follows:
+
+ * ``mock.patch`` arguments. When used as a decorator, ``mock.patch``
+ partially applies its generated ``Mock`` object as the first
+ argument, so these arguments must go first.
+ * ``pytest.mark.parametrize`` arguments, in the order specified to
+ the ``parametrize`` decorator. These arguments are also provided
+ by a decorator, so it's natural that they sit next to the
+ ``mock.patch`` arguments.
+ * Fixture arguments, alphabetically. These are not provided by a
+ decorator, so they are last, and their order has no defined
+ meaning, so we default to alphabetical.
+
+* It follows from this ordering of test arguments (so that we retain
+ the property that arguments left-to-right correspond to decorators
+ bottom-to-top) that test decorators should be ordered as follows:
+
+ * ``pytest.mark.parametrize``
+ * ``mock.patch``
+
+.. [#fixture-list] This list of fixtures (with markup) can be
+ reproduced by running::
+
+ py.test-3 --fixtures -q | grep "^[^ -]" | grep -v '\(no\|capturelog\)' | sort | sed 's/.*/* ``\0``/'
+
+ in a xenial lxd container with python3-pytest-catchlog installed.
+
+.. _pytest: https://docs.pytest.org/
+.. _pytest fixtures: https://docs.pytest.org/en/latest/fixture.html
+.. _TestGetPackageMirrorInfo: https://github.com/canonical/cloud-init/blob/42f69f410ab8850c02b1f53dd67c132aa8ef64f5/cloudinit/distros/tests/test_init.py\#L15
+.. _TestPrependBaseCommands: https://github.com/canonical/cloud-init/blob/master/cloudinit/tests/test_subp.py#L9
+.. _assertion introspection: https://docs.pytest.org/en/latest/assert.html
+.. _pytest 3.0: https://docs.pytest.org/en/latest/changelog.html#id1093
+.. _pytest.param: https://docs.pytest.org/en/latest/reference.html#pytest-param
+.. _autospecced: https://docs.python.org/3.8/library/unittest.mock.html#autospeccing