summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/examples/cloud-config-apt.txt4
-rw-r--r--doc/examples/cloud-config-boot-cmds.txt2
-rw-r--r--doc/examples/cloud-config-gluster.txt4
-rw-r--r--doc/examples/cloud-config-mount-points.txt8
-rw-r--r--doc/examples/cloud-config.txt6
-rw-r--r--doc/rtd/index.rst1
-rw-r--r--doc/rtd/topics/boot.rst4
-rw-r--r--doc/rtd/topics/format.rst2
-rw-r--r--doc/rtd/topics/logging.rst2
-rw-r--r--doc/rtd/topics/tests.rst275
10 files changed, 292 insertions, 16 deletions
diff --git a/doc/examples/cloud-config-apt.txt b/doc/examples/cloud-config-apt.txt
index 1a0fc6f2..ff8206f6 100644
--- a/doc/examples/cloud-config-apt.txt
+++ b/doc/examples/cloud-config-apt.txt
@@ -70,7 +70,7 @@ apt:
# modifications have been made.
# Suites are even disabled if no other modification was made,
# but not if is preserve_sources_list is active.
- # There is a special alias “$RELEASE” as in the sources that will be replace
+ # There is a special alias "$RELEASE" as in the sources that will be replace
# by the matching release.
#
# To ease configuration and improve readability the following common ubuntu
@@ -84,7 +84,7 @@ apt:
# There is no harm in specifying a suite to be disabled that is not found in
# the source.list file (just a no-op then)
#
- # Note: Lines don’t get deleted, but disabled by being converted to a comment.
+ # Note: Lines don't get deleted, but disabled by being converted to a comment.
# The following example disables all usual defaults except $RELEASE-security.
# On top it disables a custom suite called "mysuite"
disable_suites: [$RELEASE-updates, backports, $RELEASE, mysuite]
diff --git a/doc/examples/cloud-config-boot-cmds.txt b/doc/examples/cloud-config-boot-cmds.txt
index 5c05bef7..84e487a5 100644
--- a/doc/examples/cloud-config-boot-cmds.txt
+++ b/doc/examples/cloud-config-boot-cmds.txt
@@ -9,7 +9,7 @@
# boothook, but possibly with more friendly.
# - bootcmd will run on every boot
# - the INSTANCE_ID variable will be set to the current instance id.
-# - you can use 'cloud-init-boot-per' command to help only run once
+# - you can use 'cloud-init-per' command to help only run once
bootcmd:
- echo 192.168.1.130 us.archive.ubuntu.com >> /etc/hosts
- [ cloud-init-per, once, mymkfs, mkfs, /dev/vdb ]
diff --git a/doc/examples/cloud-config-gluster.txt b/doc/examples/cloud-config-gluster.txt
index f8183e77..cb979123 100644
--- a/doc/examples/cloud-config-gluster.txt
+++ b/doc/examples/cloud-config-gluster.txt
@@ -1,6 +1,6 @@
#cloud-config
# vim: syntax=yaml
-# Mounts volfile exported by glusterfsd running on
+# Mounts volfile exported by glusterfsd running on
# "volfile-server-hostname" onto the local mount point '/mnt/data'
#
# In reality, replace 'volfile-server-hostname' with one of your nodes
@@ -10,7 +10,7 @@ packages:
- glusterfs-client
mounts:
- - [ 'volfile-server-hostname:6996', /mnt/data, glusterfs, "defaults,nobootwait", "0", "2" ]
+ - [ 'volfile-server-hostname:6996', /mnt/data, glusterfs, "defaults,nofail", "0", "2" ]
runcmd:
- [ modprobe, fuse ]
diff --git a/doc/examples/cloud-config-mount-points.txt b/doc/examples/cloud-config-mount-points.txt
index aa676c24..5a6c24f5 100644
--- a/doc/examples/cloud-config-mount-points.txt
+++ b/doc/examples/cloud-config-mount-points.txt
@@ -23,19 +23,19 @@
# - if an entry does not have all 6 fields, they will be filled in
# with values from 'mount_default_fields' below.
#
-# Note, that you should set 'nobootwait' (see man fstab) for volumes that may
-# not be attached at instance boot (or reboot)
+# Note, that you should set 'nofail' (see man fstab) for volumes that may not
+# be attached at instance boot (or reboot).
#
mounts:
- [ ephemeral0, /mnt, auto, "defaults,noexec" ]
- [ sdc, /opt/data ]
- - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ]
+ - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ]
- [ dd, /dev/zero ]
# mount_default_fields
# These values are used to fill in any entries in 'mounts' that are not
# complete. This must be an array, and must have 7 fields.
-mount_default_fields: [ None, None, "auto", "defaults,nobootwait", "0", "2" ]
+mount_default_fields: [ None, None, "auto", "defaults,nofail", "0", "2" ]
# swap can also be set up by the 'mounts' module
diff --git a/doc/examples/cloud-config.txt b/doc/examples/cloud-config.txt
index 190029e4..c5f84b13 100644
--- a/doc/examples/cloud-config.txt
+++ b/doc/examples/cloud-config.txt
@@ -46,19 +46,19 @@ packages:
# - if an entry does not have all 6 fields, they will be filled in
# with values from 'mount_default_fields' below.
#
-# Note, that you should set 'nobootwait' (see man fstab) for volumes that may
+# Note, that you should set 'nofail' (see man fstab) for volumes that may
# not be attached at instance boot (or reboot)
#
mounts:
- [ ephemeral0, /mnt, auto, "defaults,noexec" ]
- [ sdc, /opt/data ]
- - [ xvdh, /opt/data, "auto", "defaults,nobootwait", "0", "0" ]
+ - [ xvdh, /opt/data, "auto", "defaults,nofail", "0", "0" ]
- [ dd, /dev/zero ]
# mount_default_fields
# These values are used to fill in any entries in 'mounts' that are not
# complete. This must be an array, and must have 7 fields.
-mount_default_fields: [ None, None, "auto", "defaults,nobootwait", "0", "2" ]
+mount_default_fields: [ None, None, "auto", "defaults,nofail", "0", "2" ]
# add each entry to ~/.ssh/authorized_keys for the configured user or the
# first user defined in the user definition directive.
diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst
index 3caf33f3..8f163b6a 100644
--- a/doc/rtd/index.rst
+++ b/doc/rtd/index.rst
@@ -41,6 +41,7 @@ initialization of a cloud instance.
topics/vendordata.rst
topics/moreinfo.rst
topics/hacking.rst
+ topics/tests.rst
.. _Cloud-init: https://launchpad.net/cloud-init
.. vi: textwidth=78
diff --git a/doc/rtd/topics/boot.rst b/doc/rtd/topics/boot.rst
index 9d42336c..859409a6 100644
--- a/doc/rtd/topics/boot.rst
+++ b/doc/rtd/topics/boot.rst
@@ -21,7 +21,7 @@ boot goals. By default, this generator will enable cloud-init. It will
not enable cloud-init if either:
* A file exists: ``/etc/cloud/cloud-init.disabled``
- * The kernel command line as fond in /proc/cmdline contains ``cloud-init=disabled``.
+ * The kernel command line as found in /proc/cmdline contains ``cloud-init=disabled``.
When running in a container, the kernel command line is not honored, but
cloud-init will read an environment variable named ``KERNEL_CMDLINE`` in
its place.
@@ -56,7 +56,7 @@ is rendered. This includes clearing of all previous (stale) configuration
including persistent device naming with old mac addresses.
This stage must block network bring-up or any stale configuration might
-already have been applied. That could have negative effects such as DCHP
+already have been applied. That could have negative effects such as DHCP
hooks or broadcast of an old hostname. It would also put the system in
an odd state to recover from as it may then have to restart network
devices.
diff --git a/doc/rtd/topics/format.rst b/doc/rtd/topics/format.rst
index 5898d17a..ed87d3ed 100644
--- a/doc/rtd/topics/format.rst
+++ b/doc/rtd/topics/format.rst
@@ -9,7 +9,7 @@ Gzip Compressed Content
Content found to be gzip compressed will be uncompressed.
The uncompressed data will then be used as if it were not compressed.
-This is typically is useful because user-data is limited to ~16384 [#]_ bytes.
+This is typically useful because user-data is limited to ~16384 [#]_ bytes.
Mime Multi Part Archive
=======================
diff --git a/doc/rtd/topics/logging.rst b/doc/rtd/topics/logging.rst
index c6afca16..4fd7e28e 100644
--- a/doc/rtd/topics/logging.rst
+++ b/doc/rtd/topics/logging.rst
@@ -22,7 +22,7 @@ output to ``tee``, or ``logger``. If only a filename is provided, cloud-init
will append its output to the file as though ``>>`` was specified.
By default, cloud-init loads its output configuration from
-``/etc/cloud/coud.cfg.d/05_logging.cfg``. The default config directs both
+``/etc/cloud/cloud.cfg.d/05_logging.cfg``. The default config directs both
stdout and stderr from all cloud-init stages to
``/var/log/cloud-init-output.log``. The default config is given as ::
diff --git a/doc/rtd/topics/tests.rst b/doc/rtd/topics/tests.rst
new file mode 100644
index 00000000..00c63c63
--- /dev/null
+++ b/doc/rtd/topics/tests.rst
@@ -0,0 +1,275 @@
+****************
+Test Development
+****************
+
+
+Overview
+========
+
+The purpose of this page is to describe how to write integration tests for
+cloud-init. As a test writer you need to develop a test configuration and
+a verification file:
+
+ * The test configuration specifies a specific cloud-config to be used by
+ cloud-init and a list of arbitrary commands to capture the output of
+ (e.g my_test.yaml)
+
+ * The verification file runs tests on the collected output to determine
+ the result of the test (e.g. my_test.py)
+
+The names must match, however the extensions will of course be different,
+yaml vs py.
+
+Configuration
+=============
+
+The test configuration is a YAML file such as *ntp_server.yaml* below:
+
+.. code-block:: yaml
+
+ #
+ # NTP config using specific servers (ntp_server.yaml)
+ #
+ cloud_config: |
+ #cloud-config
+ ntp:
+ servers:
+ - pool.ntp.org
+ collect_scripts:
+ ntp_installed_servers: |
+ #!/bin/bash
+ dpkg -l | grep ntp | wc -l
+ ntp_conf_dist_servers: |
+ #!/bin/bash
+ ls /etc/ntp.conf.dist | wc -l
+ ntp_conf_servers: |
+ #!/bin/bash
+ cat /etc/ntp.conf | grep '^server'
+
+
+There are two keys, 1 required and 1 optional, in the YAML file:
+
+1. The required key is ``cloud_config``. This should be a string of valid
+ YAML that is exactly what would normally be placed in a cloud-config file,
+ including the cloud-config header. This essentially sets up the scenario
+ under test.
+
+2. The optional key is ``collect_scripts``. This key has one or more
+ sub-keys containing strings of arbitrary commands to execute (e.g.
+ ```cat /var/log/cloud-config-output.log```). In the example above the
+ output of dpkg is captured, grep for ntp, and the number of lines
+ reported. The name of the sub-key is important. The sub-key is used by
+ the verification script to recall the output of the commands ran.
+
+Default Collect Scripts
+-----------------------
+
+By default the following files will be collected for every test. There is
+no need to specify these items:
+
+* ``/var/log/cloud-init.log``
+* ``/var/log/cloud-init-output.log``
+* ``/run/cloud-init/.instance-id``
+* ``/run/cloud-init/result.json``
+* ``/run/cloud-init/status.json``
+* ```dpkg-query -W -f='${Version}' cloud-init```
+
+Verification
+============
+
+The verification script is a Python file with unit tests like the one,
+`ntp_server.py`, below:
+
+.. code-block:: python
+
+ """cloud-init Integration Test Verify Script (ntp_server.yaml)"""
+ from tests.cloud_tests.testcases import base
+
+
+ class TestNtpServers(base.CloudTestCase):
+ """Test ntp module"""
+
+ def test_ntp_installed(self):
+ """Test ntp installed"""
+ out = self.get_data_file('ntp_installed_servers')
+ self.assertEqual(1, int(out))
+
+ def test_ntp_dist_entries(self):
+ """Test dist config file has one entry"""
+ out = self.get_data_file('ntp_conf_dist_servers')
+ self.assertEqual(1, int(out))
+
+ def test_ntp_entires(self):
+ """Test config entries"""
+ out = self.get_data_file('ntp_conf_servers')
+ self.assertIn('server pool.ntp.org iburst', out)
+
+
+Here is a breakdown of the unit test file:
+
+* The import statement allows access to the output files.
+
+* The class can be named anything, but must import the ``base.CloudTestCase``
+
+* There can be 1 to N number of functions with any name, however only
+ tests starting with ``test_*`` will be executed.
+
+* Output from the commands can be accessed via
+ ``self.get_data_file('key')`` where key is the sub-key of
+ ``collect_scripts`` above.
+
+Layout
+======
+
+Integration tests are located under the `tests/cloud_tests` directory.
+Test configurations are placed under `configs` and the test verification
+scripts under `testcases`:
+
+.. code-block:: bash
+
+ cloud-init$ tree -d tests/cloud_tests/
+ tests/cloud_tests/
+ ├── configs
+ │   ├── bugs
+ │   ├── examples
+ │   ├── main
+ │   └── modules
+ └── testcases
+ ├── bugs
+ ├── examples
+ ├── main
+ └── modules
+
+The sub-folders of bugs, examples, main, and modules help organize the
+tests. View the README.md in each to understand in more detail each
+directory.
+
+
+Development Checklist
+=====================
+
+* Configuration File
+ * Named 'your_test_here.yaml'
+ * Contains at least a valid cloud-config
+ * Optionally, commands to capture additional output
+ * Valid YAML
+ * Placed in the appropriate sub-folder in the configs directory
+* Verification File
+ * Named 'your_test_here.py'
+ * Valid unit tests validating output collected
+ * Passes pylint & pep8 checks
+ * Placed in the appropriate sub-folder in the testcsaes directory
+* Tested by running the test:
+
+ .. code-block:: bash
+
+ $ python3 -m tests.cloud_tests run -v -n <release of choice> \
+ --deb <build of cloud-init> \
+ -t tests/cloud_tests/configs/<dir>/your_test_here.yaml
+
+
+Execution
+=========
+
+Executing tests has three options:
+
+* ``run`` an alias to run both ``collect`` and ``verify``
+
+* ``collect`` deploys on the specified platform and os, patches with the
+ requested deb or rpm, and finally collects output of the arbitrary
+ commands.
+
+* ``verify`` given a directory of test data, run the Python unit tests on
+ it to generate results.
+
+Run
+---
+The first example will provide a complete end-to-end run of data
+collection and verification. There are additional examples below
+explaining how to run one or the other independently.
+
+.. code-block:: bash
+
+ $ git clone https://git.launchpad.net/cloud-init
+ $ cd cloud-init
+ $ python3 -m tests.cloud_tests run -v -n trusty -n xenial \
+ --deb cloud-init_0.7.8~my_patch_all.deb
+
+The above command will do the following:
+
+* ``-v`` verbose output
+
+* ``run`` both collect output and run tests the output
+
+* ``-n trusty`` on the Ubuntu Trusty release
+
+* ``-n xenial`` on the Ubuntu Xenial release
+
+* ``--deb cloud-init_0.7.8~patch_all.deb`` use this deb as the version of
+ cloud-init to run with
+
+For a more detailed explanation of each option see below.
+
+Collect
+-------
+
+If developing tests it may be necessary to see if cloud-config works as
+expected and the correct files are pulled down. In this case only a
+collect can be ran by running:
+
+.. code-block:: bash
+
+ $ python3 -m tests.cloud_tests collect -n xenial -d /tmp/collection \
+ --deb cloud-init_0.7.8~my_patch_all.deb
+
+The above command will run the collection tests on xenial with the
+provided deb and place all results into `/tmp/collection`.
+
+Verify
+------
+
+When developing tests it is much easier to simply rerun the verify scripts
+without the more lengthy collect process. This can be done by running:
+
+.. code-block:: bash
+
+ $ python3 -m tests.cloud_tests verify -d /tmp/collection
+
+The above command will run the verify scripts on the data discovered in
+`/tmp/collection`.
+
+
+Architecture
+============
+
+The following outlines the process flow during a complete end-to-end LXD-backed test.
+
+1. Configuration
+ * The back end and specific OS releases are verified as supported
+ * The test or tests that need to be run are determined either by directory or by individual yaml
+
+2. Image Creation
+ * Acquire the daily LXD image
+ * Install the specified cloud-init package
+ * Clean the image so that it does not appear to have been booted
+ * A snapshot of the image is created and reused by all tests
+
+3. Configuration
+ * For each test, the cloud-config is injected into a copy of the
+ snapshot and booted
+ * The framework waits for ``/var/lib/cloud/instance/boot-finished``
+ (up to 120 seconds)
+ * All default commands are ran and output collected
+ * Any commands the user specified are executed and output collected
+
+4. Verification
+ * The default commands are checked for any failures, errors, and
+ warnings to validate basic functionality of cloud-init completed
+ successfully
+ * The user generated unit tests are then ran validating against the
+ collected output
+
+5. Results
+ * If any failures were detected the test suite returns a failure
+
+