summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloud-tests-requirements.txt28
-rw-r--r--doc/rtd/index.rst1
-rw-r--r--doc/rtd/topics/cloud_tests.rst764
-rw-r--r--tests/cloud_tests/__init__.py39
-rw-r--r--tests/cloud_tests/__main__.py71
-rw-r--r--tests/cloud_tests/args.py304
-rw-r--r--tests/cloud_tests/bddeb.py119
-rw-r--r--tests/cloud_tests/collect.py219
-rw-r--r--tests/cloud_tests/config.py165
-rw-r--r--tests/cloud_tests/manage.py74
-rw-r--r--tests/cloud_tests/platforms.yaml77
-rw-r--r--tests/cloud_tests/platforms/__init__.py43
-rw-r--r--tests/cloud_tests/platforms/azurecloud/__init__.py0
-rw-r--r--tests/cloud_tests/platforms/azurecloud/image.py116
-rw-r--r--tests/cloud_tests/platforms/azurecloud/instance.py247
-rw-r--r--tests/cloud_tests/platforms/azurecloud/platform.py240
-rw-r--r--tests/cloud_tests/platforms/azurecloud/regions.json42
-rw-r--r--tests/cloud_tests/platforms/azurecloud/snapshot.py58
-rw-r--r--tests/cloud_tests/platforms/ec2/__init__.py0
-rw-r--r--tests/cloud_tests/platforms/ec2/image.py100
-rw-r--r--tests/cloud_tests/platforms/ec2/instance.py132
-rw-r--r--tests/cloud_tests/platforms/ec2/platform.py263
-rw-r--r--tests/cloud_tests/platforms/ec2/snapshot.py66
-rw-r--r--tests/cloud_tests/platforms/images.py56
-rw-r--r--tests/cloud_tests/platforms/instances.py165
-rw-r--r--tests/cloud_tests/platforms/lxd/__init__.py0
-rw-r--r--tests/cloud_tests/platforms/lxd/image.py211
-rw-r--r--tests/cloud_tests/platforms/lxd/instance.py278
-rw-r--r--tests/cloud_tests/platforms/lxd/platform.py104
-rw-r--r--tests/cloud_tests/platforms/lxd/snapshot.py53
-rw-r--r--tests/cloud_tests/platforms/nocloudkvm/__init__.py0
-rw-r--r--tests/cloud_tests/platforms/nocloudkvm/image.py79
-rw-r--r--tests/cloud_tests/platforms/nocloudkvm/instance.py197
-rw-r--r--tests/cloud_tests/platforms/nocloudkvm/platform.py94
-rw-r--r--tests/cloud_tests/platforms/nocloudkvm/snapshot.py59
-rw-r--r--tests/cloud_tests/platforms/platforms.py109
-rw-r--r--tests/cloud_tests/platforms/snapshots.py44
-rw-r--r--tests/cloud_tests/releases.yaml381
-rw-r--r--tests/cloud_tests/run_funcs.py75
-rw-r--r--tests/cloud_tests/setup_image.py237
-rw-r--r--tests/cloud_tests/stage.py116
-rw-r--r--tests/cloud_tests/testcases.yaml50
-rw-r--r--tests/cloud_tests/testcases/__init__.py73
-rw-r--r--tests/cloud_tests/testcases/base.py385
-rw-r--r--tests/cloud_tests/testcases/bugs/README.md13
-rw-r--r--tests/cloud_tests/testcases/bugs/__init__.py8
-rw-r--r--tests/cloud_tests/testcases/bugs/lp1511485.py15
-rw-r--r--tests/cloud_tests/testcases/bugs/lp1511485.yaml11
-rw-r--r--tests/cloud_tests/testcases/bugs/lp1611074.yaml8
-rw-r--r--tests/cloud_tests/testcases/bugs/lp1628337.py23
-rw-r--r--tests/cloud_tests/testcases/bugs/lp1628337.yaml23
-rw-r--r--tests/cloud_tests/testcases/examples/README.md12
-rw-r--r--tests/cloud_tests/testcases/examples/TODO.md15
-rw-r--r--tests/cloud_tests/testcases/examples/__init__.py8
-rw-r--r--tests/cloud_tests/testcases/examples/add_apt_repositories.py20
-rw-r--r--tests/cloud_tests/testcases/examples/add_apt_repositories.yaml23
-rw-r--r--tests/cloud_tests/testcases/examples/alter_completion_message.py40
-rw-r--r--tests/cloud_tests/testcases/examples/alter_completion_message.yaml16
-rw-r--r--tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py27
-rw-r--r--tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.yaml41
-rw-r--r--tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py31
-rw-r--r--tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.yaml63
-rw-r--r--tests/cloud_tests/testcases/examples/including_user_groups.py49
-rw-r--r--tests/cloud_tests/testcases/examples/including_user_groups.yaml56
-rw-r--r--tests/cloud_tests/testcases/examples/install_arbitrary_packages.py20
-rw-r--r--tests/cloud_tests/testcases/examples/install_arbitrary_packages.yaml20
-rw-r--r--tests/cloud_tests/testcases/examples/install_run_chef_recipes.py17
-rw-r--r--tests/cloud_tests/testcases/examples/install_run_chef_recipes.yaml104
-rw-r--r--tests/cloud_tests/testcases/examples/run_apt_upgrade.py19
-rw-r--r--tests/cloud_tests/testcases/examples/run_apt_upgrade.yaml11
-rw-r--r--tests/cloud_tests/testcases/examples/run_commands.py15
-rw-r--r--tests/cloud_tests/testcases/examples/run_commands.yaml16
-rw-r--r--tests/cloud_tests/testcases/examples/run_commands_first_boot.py15
-rw-r--r--tests/cloud_tests/testcases/examples/run_commands_first_boot.yaml16
-rw-r--r--tests/cloud_tests/testcases/examples/setup_run_puppet.yaml55
-rw-r--r--tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py30
-rw-r--r--tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.yaml45
-rw-r--r--tests/cloud_tests/testcases/main/README.md11
-rw-r--r--tests/cloud_tests/testcases/main/__init__.py8
-rw-r--r--tests/cloud_tests/testcases/main/command_output_simple.py21
-rw-r--r--tests/cloud_tests/testcases/main/command_output_simple.yaml13
-rw-r--r--tests/cloud_tests/testcases/modules/README.md12
-rw-r--r--tests/cloud_tests/testcases/modules/TODO.md95
-rw-r--r--tests/cloud_tests/testcases/modules/__init__.py8
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_conf.py20
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_conf.yaml21
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py15
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_disable_suites.yaml20
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_primary.py24
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_primary.yaml19
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_proxy.py22
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_proxy.yaml18
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_security.py15
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_security.yaml18
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_key.py23
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_key.yaml50
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py23
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.yaml23
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_list.py31
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_list.yaml28
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py23
-rw-r--r--tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.yaml29
-rw-r--r--tests/cloud_tests/testcases/modules/apt_pipelining_disable.py15
-rw-r--r--tests/cloud_tests/testcases/modules/apt_pipelining_disable.yaml14
-rw-r--r--tests/cloud_tests/testcases/modules/apt_pipelining_os.py15
-rw-r--r--tests/cloud_tests/testcases/modules/apt_pipelining_os.yaml14
-rw-r--r--tests/cloud_tests/testcases/modules/bootcmd.py15
-rw-r--r--tests/cloud_tests/testcases/modules/bootcmd.yaml13
-rw-r--r--tests/cloud_tests/testcases/modules/byobu.py24
-rw-r--r--tests/cloud_tests/testcases/modules/byobu.yaml17
-rw-r--r--tests/cloud_tests/testcases/modules/ca_certs.py33
-rw-r--r--tests/cloud_tests/testcases/modules/ca_certs.yaml56
-rw-r--r--tests/cloud_tests/testcases/modules/debug_disable.py16
-rw-r--r--tests/cloud_tests/testcases/modules/debug_disable.yaml9
-rw-r--r--tests/cloud_tests/testcases/modules/debug_enable.py15
-rw-r--r--tests/cloud_tests/testcases/modules/debug_enable.yaml9
-rw-r--r--tests/cloud_tests/testcases/modules/final_message.py40
-rw-r--r--tests/cloud_tests/testcases/modules/final_message.yaml13
-rw-r--r--tests/cloud_tests/testcases/modules/keys_to_console.py22
-rw-r--r--tests/cloud_tests/testcases/modules/keys_to_console.yaml15
-rw-r--r--tests/cloud_tests/testcases/modules/landscape.yaml28
-rw-r--r--tests/cloud_tests/testcases/modules/locale.py30
-rw-r--r--tests/cloud_tests/testcases/modules/locale.yaml22
-rw-r--r--tests/cloud_tests/testcases/modules/lxd_bridge.py36
-rw-r--r--tests/cloud_tests/testcases/modules/lxd_bridge.yaml32
-rw-r--r--tests/cloud_tests/testcases/modules/lxd_dir.py30
-rw-r--r--tests/cloud_tests/testcases/modules/lxd_dir.yaml19
-rw-r--r--tests/cloud_tests/testcases/modules/ntp.py24
-rw-r--r--tests/cloud_tests/testcases/modules/ntp.yaml22
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_chrony.py26
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_chrony.yaml17
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_pools.py34
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_pools.yaml32
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_servers.py34
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_servers.yaml28
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_timesyncd.py15
-rw-r--r--tests/cloud_tests/testcases/modules/ntp_timesyncd.yaml15
-rw-r--r--tests/cloud_tests/testcases/modules/package_update_upgrade_install.py36
-rw-r--r--tests/cloud_tests/testcases/modules/package_update_upgrade_install.yaml30
-rw-r--r--tests/cloud_tests/testcases/modules/runcmd.py15
-rw-r--r--tests/cloud_tests/testcases/modules/runcmd.yaml13
-rw-r--r--tests/cloud_tests/testcases/modules/seed_random_command.yaml18
-rw-r--r--tests/cloud_tests/testcases/modules/seed_random_data.py15
-rw-r--r--tests/cloud_tests/testcases/modules/seed_random_data.yaml15
-rw-r--r--tests/cloud_tests/testcases/modules/set_hostname.py17
-rw-r--r--tests/cloud_tests/testcases/modules/set_hostname.yaml21
-rw-r--r--tests/cloud_tests/testcases/modules/set_hostname_fqdn.py31
-rw-r--r--tests/cloud_tests/testcases/modules/set_hostname_fqdn.yaml23
-rw-r--r--tests/cloud_tests/testcases/modules/set_password.py22
-rw-r--r--tests/cloud_tests/testcases/modules/set_password.yaml19
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_expire.py23
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_expire.yaml32
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_list.py12
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_list.yaml41
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_list_string.py12
-rw-r--r--tests/cloud_tests/testcases/modules/set_password_list_string.yaml41
-rw-r--r--tests/cloud_tests/testcases/modules/snap.py16
-rw-r--r--tests/cloud_tests/testcases/modules/snap.yaml21
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py16
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.yaml14
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py18
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.yaml21
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_import_id.py17
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_import_id.yaml17
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_keys_generate.py52
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_keys_generate.yaml38
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_keys_provided.py58
-rw-r--r--tests/cloud_tests/testcases/modules/ssh_keys_provided.yaml99
-rw-r--r--tests/cloud_tests/testcases/modules/timezone.py15
-rw-r--r--tests/cloud_tests/testcases/modules/timezone.yaml16
-rw-r--r--tests/cloud_tests/testcases/modules/user_groups.py49
-rw-r--r--tests/cloud_tests/testcases/modules/user_groups.yaml55
-rw-r--r--tests/cloud_tests/testcases/modules/write_files.py33
-rw-r--r--tests/cloud_tests/testcases/modules/write_files.yaml53
-rw-r--r--tests/cloud_tests/util.py532
-rw-r--r--tests/cloud_tests/verify.py149
-rw-r--r--tests/configs/sample1.yaml49
-rw-r--r--tests/unittests/test_handler/test_schema.py41
-rw-r--r--tox.ini11
179 files changed, 2 insertions, 10032 deletions
diff --git a/cloud-tests-requirements.txt b/cloud-tests-requirements.txt
deleted file mode 100644
index eecab63e..00000000
--- a/cloud-tests-requirements.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# PyPI requirements for cloud-init cloud tests
-# https://cloudinit.readthedocs.io/en/latest/topics/cloud_tests.html
-#
-# Note: Changes to this requirements may require updates to
-# the packages/pkg-deps.json file as well.
-#
-
-# ec2 backend
-boto3==1.14.53
-
-# ssh communication
-paramiko==2.7.2
-cryptography==3.2
-
-# lxd backend
-pylxd==2.2.11
-
-# finds latest image information
-git+https://git.launchpad.net/simplestreams
-
-# azure backend
-azure-storage==0.36.0
-msrestazure==0.6.1
-azure-common==1.1.23
-azure-mgmt-compute==7.0.0
-azure-mgmt-network==5.0.0
-azure-mgmt-resource==4.0.0
-azure-mgmt-storage==6.0.0
diff --git a/doc/rtd/index.rst b/doc/rtd/index.rst
index 67d6a9e3..69cf2068 100644
--- a/doc/rtd/index.rst
+++ b/doc/rtd/index.rst
@@ -78,6 +78,5 @@ Having trouble? We would like to help!
topics/docs.rst
topics/testing.rst
topics/integration_tests.rst
- topics/cloud_tests.rst
.. vi: textwidth=79
diff --git a/doc/rtd/topics/cloud_tests.rst b/doc/rtd/topics/cloud_tests.rst
deleted file mode 100644
index 0fbb1301..00000000
--- a/doc/rtd/topics/cloud_tests.rst
+++ /dev/null
@@ -1,764 +0,0 @@
-************************
-Cloud tests (Deprecated)
-************************
-
-Cloud tests are longer be maintained. For writing integration
-tests, see the :ref:`integration_tests` page.
-
-Overview
-========
-
-This page describes the execution, development, and architecture of the
-cloud-init integration tests:
-
-* Execution explains the options available and running of tests
-* Development shows how to write test cases
-* Architecture explains the internal processes
-
-Execution
-=========
-
-Overview
---------
-
-In order to avoid the need for dependencies and ease the setup and
-configuration users can run the integration tests via tox:
-
-.. code-block:: shell-session
-
- $ git clone https://github.com/canonical/cloud-init
- $ cd cloud-init
- $ tox -e citest -- -h
-
-Everything after the double dash will be passed to the integration tests.
-Executing tests has several options:
-
-* ``run`` an alias to run both ``collect`` and ``verify``. The ``tree_run``
- command does the same thing, except uses a deb built from the current
- working tree.
-
-* ``collect`` deploys on the specified platform and distro, patches with the
- requested deb or rpm, and finally collects output of the arbitrary
- commands. Similarly, ```tree_collect`` will collect output using a deb
- built from the current working tree.
-
-* ``verify`` given a directory of test data, run the Python unit tests on
- it to generate results.
-
-* ``bddeb`` will build a deb of the current working tree.
-
-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:: shell-session
-
- $ git clone https://github.com/canonical/cloud-init
- $ cd cloud-init
- $ tox -e citest -- run --verbose \
- --os-name stretch --os-name xenial \
- --deb cloud-init_0.7.8~my_patch_all.deb \
- --preserve-data --data-dir ~/collection \
- --preserve-instance
-
-The above command will do the following:
-
-* ``run`` both collect output and run tests the output
-
-* ``--verbose`` verbose output
-
-* ``--os-name stretch`` on the Debian Stretch release
-
-* ``--os-name 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
-
-* ``--preserve-data`` always preserve collected data, do not remove data
- after successful test run
-
-* ``--preserve-instance`` do not destroy the instance after test to allow
- for debugging the stopped instance during integration test development. By
- default, test instances are destroyed after the test completes.
-
-* ``--data-dir ~/collection`` write collected data into `~/collection`,
- rather than using a temporary directory
-
-For a more detailed explanation of each option see below.
-
-.. note::
- By default, data collected by the run command will be written into a
- temporary directory and deleted after a successful. If you would
- like to preserve this data, please use the option ``--preserve-data``.
-
-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:: shell-session
-
- $ tox -e citest -- collect -n xenial --data-dir /tmp/collection
-
-The above command will run the collection tests on xenial 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:: shell-session
-
- $ tox -e citest -- verify --data-dir /tmp/collection
-
-The above command will run the verify scripts on the data discovered in
-`/tmp/collection`.
-
-TreeRun and TreeCollect
------------------------
-
-If working on a cloud-init feature or resolving a bug, it may be useful to
-run the current copy of cloud-init in the integration testing environment.
-The integration testing suite can automatically build a deb based on the
-current working tree of cloud-init and run the test suite using this deb.
-
-The ``tree_run`` and ``tree_collect`` commands take the same arguments as
-the ``run`` and ``collect`` commands. These commands will build a deb and
-write it into a temporary file, then start the test suite and pass that deb
-in. To build a deb only, and not run the test suite, the ``bddeb`` command
-can be used.
-
-Note that code in the cloud-init working tree that has not been committed
-when the cloud-init deb is built will still be included. To build a
-cloud-init deb from or use the ``tree_run`` command using a copy of
-cloud-init located in a different directory, use the option ``--cloud-init
-/path/to/cloud-init``.
-
-.. code-block:: shell-session
-
- $ tox -e citest -- tree_run --verbose \
- --os-name xenial --os-name stretch \
- --test modules/final_message --test modules/write_files \
- --result /tmp/result.yaml
-
-Bddeb
------
-
-The ``bddeb`` command can be used to generate a deb file. This is used by the
-tree_run and tree_collect commands to build a deb of the current working tree
-using the packaging template contained in the ``packages/debian/`` directory.
-It can also be used to generate a deb for use in other situations and avoid
-needing to have all the build and test dependencies installed locally.
-
-* ``--bddeb-args``: arguments to pass through to bddeb
-* ``--build-os``: distribution to use as build system (default is xenial)
-* ``--build-platform``: platform to use for build system (default is lxd)
-* ``--cloud-init``: path to base of cloud-init tree (default is '.')
-* ``--deb``: path to write output deb to (default is '.')
-* ``--packaging-branch``: import the ``debian/`` packaging directory
- from the specified branch (default: ``ubuntu/devel``) instead of using
- the packaging template.
-
-Setup Image
------------
-
-By default an image that is used will remain unmodified, but certain
-scenarios may require image modification. For example, many images may use
-a much older cloud-init. As a result tests looking at newer functionality
-will fail because a newer version of cloud-init may be required. The
-following options can be used for further customization:
-
-* ``--deb``: install the specified deb into the image
-* ``--rpm``: install the specified rpm into the image
-* ``--repo``: enable a repository and upgrade cloud-init afterwards
-* ``--ppa``: enable a ppa and upgrade cloud-init afterwards
-* ``--upgrade``: upgrade cloud-init from repos
-* ``--upgrade-full``: run a full system upgrade
-* ``--script``: execute a script in the image. This can perform any setup
- required that is not covered by the other options
-
-Test Case Development
-=====================
-
-Overview
---------
-
-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
-
- #
- # Empty NTP config to setup using defaults
- #
- # NOTE: this should not require apt feature, use 'which' rather than 'dpkg -l'
- # NOTE: this should not require no_ntpdate feature, use 'which' to check for
- # installation rather than 'dpkg -l', as 'grep ntp' matches 'ntpdate'
- # NOTE: the verifier should check for any ntp server not 'ubuntu.pool.ntp.org'
- cloud_config: |
- #cloud-config
- ntp:
- servers:
- - pool.ntp.org
- required_features:
- - apt
- - no_ntpdate
- - ubuntu_ntp
- 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 several keys, 1 required and some 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. One 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.
-
-3. The optional ``enabled`` key enables or disables the test case. By
- default the test case will be enabled.
-
-4. The optional ``required_features`` key may be used to specify a list
- of features flags that an image must have to be able to run the test
- case. For example, if a test case relies on an image supporting apt,
- then the config for the test case should include ``required_features:
- [ apt ]``.
-
-
-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
-
- # This file is part of cloud-init. See LICENSE file for license information.
-
- """cloud-init Integration Test Verify Script"""
- from tests.cloud_tests.testcases import base
-
-
- class TestNtp(base.CloudTestCase):
- """Test ntp module"""
-
- def test_ntp_installed(self):
- """Test ntp installed"""
- out = self.get_data_file('ntp_installed_empty')
- 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_empty')
- self.assertEqual(1, int(out))
-
- def test_ntp_entires(self):
- """Test config entries"""
- out = self.get_data_file('ntp_conf_empty')
- self.assertIn('pool 0.ubuntu.pool.ntp.org iburst', out)
- self.assertIn('pool 1.ubuntu.pool.ntp.org iburst', out)
- self.assertIn('pool 2.ubuntu.pool.ntp.org iburst', out)
- self.assertIn('pool 3.ubuntu.pool.ntp.org iburst', out)
-
- # vi: ts=4 expandtab
-
-
-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``, either directly or via another test class.
-
-* There can be 1 to N number of functions with any name, however only
- functions starting with ``test_*`` will be executed.
-
-* There can be 1 to N number of classes in a test module, however only
- classes inheriting from ``base.CloudTestCase`` will be loaded.
-
-* Output from the commands can be accessed via
- ``self.get_data_file('key')`` where key is the sub-key of
- ``collect_scripts`` above.
-
-* The cloud config that the test ran with can be accessed via
- ``self.cloud_config``, or any entry from the cloud config can be accessed
- via ``self.get_config_entry('key')``.
-
-* See the base ``CloudTestCase`` for additional helper functions.
-
-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:: shell-session
-
- 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.
-
-Test Creation Helper
---------------------
-
-The integration testing suite has a built in helper to aid in test
-development. Help can be invoked via ``tox -e citest -- create --help``. It
-can create a template test case config file with user data passed in from
-the command line, as well as a template test case verifier module.
-
-The following would create a test case named ``example`` under the
-``modules`` category with the given description, and cloud config data read
-in from ``/tmp/user_data``.
-
-.. code-block:: shell-session
-
- $ tox -e citest -- create modules/example \
- -d "a simple example test case" -c "$(< /tmp/user_data)"
-
-
-Development Checklist
----------------------
-
-* Configuration File
- * Named 'your_test.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
- * Any image features required for the test are specified
-* Verification File
- * Named 'your_test.py'
- * Valid unit tests validating output collected
- * Passes pylint & pep8 checks
- * Placed in the appropriate sub-folder in the test cases directory
-* Tested by running the test:
-
- .. code-block:: shell-session
-
- $ tox -e citest -- run -verbose \
- --os-name <release target> \
- --test modules/your_test.yaml \
- [--deb <build of cloud-init>]
-
-
-Platforms
-=========
-
-EC2
----
-To run on the EC2 platform it is required that the user has an AWS credentials
-configuration file specifying his or her access keys and a default region.
-These configuration files are the standard that the AWS cli and other AWS
-tools utilize for interacting directly with AWS itself and are normally
-generated when running ``aws configure``:
-
-.. code-block:: shell-session
-
- $ cat $HOME/.aws/credentials
- [default]
- aws_access_key_id = <KEY HERE>
- aws_secret_access_key = <KEY HERE>
-
-.. code-block:: shell-session
-
- $ cat $HOME/.aws/config
- [default]
- region = us-west-2
-
-
-Azure Cloud
------------
-
-To run on Azure Cloud platform users login with Service Principal and export
-credentials file. Region is defaulted and can be set in
-``tests/cloud_tests/platforms.yaml``. The Service Principal credentials are
-the standard authentication for Azure SDK to interact with Azure Services:
-
-Create Service Principal account or login
-
-.. code-block:: shell-session
-
- $ az ad sp create-for-rbac --name "APP_ID" --password "STRONG-SECRET-PASSWORD"
-
-.. code-block:: shell-session
-
- $ az login --service-principal --username "APP_ID" --password "STRONG-SECRET-PASSWORD"
-
-Export credentials
-
-.. code-block:: shell-session
-
- $ az ad sp create-for-rbac --sdk-auth > $HOME/.azure/credentials.json
-
-.. code-block:: json
-
- {
- "clientId": "<Service principal ID>",
- "clientSecret": "<Service principal secret/password>",
- "subscriptionId": "<Subscription associated with the service principal>",
- "tenantId": "<The service principal's tenant>",
- "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
- "resourceManagerEndpointUrl": "https://management.azure.com/",
- "activeDirectoryGraphResourceId": "https://graph.windows.net/",
- "sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
- "galleryEndpointUrl": "https://gallery.azure.com/",
- "managementEndpointUrl": "https://management.core.windows.net/"
- }
-
-Set region in platforms.yaml
-
-.. code-block:: yaml
-
- azurecloud:
- enabled: true
- region: West US 2
- vm_size: Standard_DS1_v2
- storage_sku: standard_lrs
- tag: ci
-
-
-Architecture
-============
-
-The following section outlines the high-level architecture of the
-integration process.
-
-Overview
---------
-The process flow during a complete end-to-end LXD-backed test.
-
-1. Configuration
- * The back end and specific distro 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 request 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
- * Results can be dumped in yaml format to a specified file using the
- ``-r <result_file_name>.yaml`` option
-
-Configuring the Test Suite
---------------------------
-
-Most of the behavior of the test suite is configurable through several yaml
-files. These control the behavior of the test suite's platforms, images, and
-tests. The main config files for platforms, images and test cases are
-``platforms.yaml``, ``releases.yaml`` and ``testcases.yaml``.
-
-Config handling
-^^^^^^^^^^^^^^^
-
-All configurable parts of the test suite use a defaults + overrides system
-for managing config entries. All base config items are dictionaries.
-
-Merging is done on a key-by-key basis, with all keys in the default and
-override represented in the final result. If a key exists both in
-the defaults and the overrides, then the behavior depends on the type of data
-the key refers to. If it is atomic data or a list, then the overrides will
-replace the default. If the data is a dictionary then the value will be the
-result of merging that dictionary from the default config and that
-dictionary from the overrides.
-
-Merging is done using the function
-``tests.cloud_tests.config.merge_config``, which can be examined for more
-detail on config merging behavior.
-
-The following demonstrates merge behavior:
-
-.. code-block:: yaml
-
- defaults:
- list_item:
- - list_entry_1
- - list_entry_2
- int_item_1: 123
- int_item_2: 234
- dict_item:
- subkey_1: 1
- subkey_2: 2
- subkey_dict:
- subsubkey_1: a
- subsubkey_2: b
-
- overrides:
- list_item:
- - overridden_list_entry
- int_item_1: 0
- dict_item:
- subkey_2: false
- subkey_dict:
- subsubkey_2: 'new value'
-
- result:
- list_item:
- - overridden_list_entry
- int_item_1: 0
- int_item_2: 234
- dict_item:
- subkey_1: 1
- subkey_2: false
- subkey_dict:
- subsubkey_1: a
- subsubkey_2: 'new value'
-
-
-Image Config
-------------
-
-Image configuration is handled in ``releases.yaml``. The image configuration
-controls how platforms locate and acquire images, how the platforms should
-interact with the images, how platforms should detect when an image has
-fully booted, any options that are required to set the image up, and
-features that the image supports.
-
-Since settings for locating an image and interacting with it differ from
-platform to platform, there are 4 levels of settings available for images on
-top of the default image settings. The structure of the image config file
-is:
-
-.. code-block:: yaml
-
- default_release_config:
- default:
- ...
- <platform>:
- ...
- <platform>:
- ...
-
- releases:
- <release name>:
- <default>:
- ...
- <platform>:
- ...
- <platform>:
- ...
-
-
-The base config is created from the overall defaults and the overrides for
-the platform. The overrides are created from the default config for the
-image and the platform specific overrides for the image.
-
-System Boot
-^^^^^^^^^^^
-
-The test suite must be able to test if a system has fully booted and if
-cloud-init has finished running, so that running collect scripts does not
-race against the target image booting. This is done using the
-``system_ready_script`` and ``cloud_init_ready_script`` image config keys.
-
-Each of these keys accepts a small bash test statement as a string that must
-return 0 or 1. Since this test statement will be added into a larger bash
-statement it must be a single statement using the ``[`` test syntax.
-
-The default image config provides a system ready script that works for any
-systemd based image. If the image is not systemd based, then a different
-test statement must be provided. The default config also provides a test
-for whether or not cloud-init has finished which checks for the file
-``/run/cloud-init/result.json``. This should be sufficient for most systems
-as writing this file is one of the last things cloud-init does.
-
-The setting ``boot_timeout`` controls how long, in seconds, the platform
-should wait for an image to boot. If the system ready script has not
-indicated that the system is fully booted within this time an error will be
-raised.
-
-Feature Flags
-^^^^^^^^^^^^^
-
-Not all test cases can work on all images due to features the test case
-requires not being present on that image. If a test case requires features
-in an image that are not likely to be present across all distros and
-platforms that the test suite supports, then the test can be skipped
-everywhere it is not supported.
-
-Feature flags, which are names for features supported on some images, but
-not all that may be required by test cases. Configuration for feature flags
-is provided in ``releases.yaml`` under the ``features`` top level key. The
-features config includes a list of all currently defined feature flags,
-their meanings, and a list of feature groups.
-
-Feature groups are groups of features that many images have in common. For
-example, the ``Ubuntu_specific`` feature group includes features that
-should be present across most Ubuntu releases, but may or may not be for
-other distros. Feature groups are specified for an image as a list under
-the key ``feature_groups``.
-
-An image's feature flags are derived from the features groups that that
-image has and any feature overrides provided. Feature overrides can be
-specified under the ``features`` key which accepts a dictionary of
-``{<feature_name>: true/false}`` mappings. If a feature is omitted from an
-image's feature flags or set to false in the overrides then the test suite
-will skip any tests that require that feature when using that image.
-
-Feature flags may be overridden at run time using the ``--feature-override``
-command line argument. It accepts a feature flag and value to set in the
-format ``<feature name>=true/false``. Multiple ``--feature-override``
-flags can be used, and will all be applied to all feature flags for images
-used during a test.
-
-Setup Overrides
-^^^^^^^^^^^^^^^
-
-If an image requires some of the options for image setup to be used, then it
-may specify overrides for the command line arguments passed into setup
-image. These may be specified as a dictionary under the ``setup_overrides``
-key. When an image is set up, the arguments that control how it is set up
-will be the arguments from the command line, with any entries in
-``setup_overrides`` used to override these arguments.
-
-For example, images that do not come with cloud-init already installed
-should have ``setup_overrides: {upgrade: true}`` specified so that in the
-event that no additional setup options are given, cloud-init will be
-installed from the image's repos before running tests. Note that if other
-options such as ``--deb`` are passed in on the command line, these will
-still work as expected, since apt's policy for cloud-init would prefer the
-locally installed deb over an older version from the repos.
-
-Platform Specific Options
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-There are many platform specific options in image configuration that allow
-platforms to locate images and that control additional setup that the
-platform may have to do to make the image usable. For information on how
-these work, please consult the documentation for that platform in the
-integration testing suite and the ``releases.yaml`` file for examples.
-
-Error Handling
---------------
-
-The test suite makes an attempt to run as many tests as possible even in the
-event of some failing so that automated runs collect as much data as
-possible. In the event that something goes wrong while setting up for or
-running a test, the test suite will attempt to continue running any tests
-which have not been affected by the error.
-
-For example, if the test suite was told to run tests on one platform for two
-releases and an error occurred setting up the first image, all tests for
-that image would be skipped, and the test suite would continue to set up
-the second image and run tests on it. Or, if the system does not start
-properly for one test case out of many to run on that image, that test case
-will be skipped and the next one will be run.
-
-Note that if any errors occur, the test suite will record the failure and
-where it occurred in the result data and write it out to the specified
-result file.
-
-Results
--------
-
-The test suite generates result data that includes how long each stage of
-the test suite took and which parts were and were not successful. This data
-is dumped to the log after the collect and verify stages, and may also be
-written out in yaml format to a file. If part of the setup failed, the
-traceback for the failure and the error message will be included in the
-result file. If a test verifier finds a problem with the collected data
-from a test run, the class, test function and test will be recorded in the
-result data.
-
-Exit Codes
-^^^^^^^^^^
-
-The test suite counts how many errors occur throughout a run. The exit code
-after a run is the number of errors that occurred. If the exit code is
-non-zero then something is wrong either with the test suite, the
-configuration for an image, a test case, or cloud-init itself.
-
-Note that the exit code does not always directly correspond to the number
-of failed test cases, since in some cases, a single error during image setup
-can mean that several test cases are not run. If run is used, then the exit
-code will be the sum of the number of errors in the collect and verify
-stages.
-
-Data Dir
-^^^^^^^^
-
-When using run, the collected data is written into a temporary directory. In
-the event that all tests pass, this directory is deleted, but if a test
-fails or an error occurs, this data will be left in place, and a message
-will be written to the log giving the location of the data.
diff --git a/tests/cloud_tests/__init__.py b/tests/cloud_tests/__init__.py
deleted file mode 100644
index 6c632f99..00000000
--- a/tests/cloud_tests/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Main init."""
-
-import logging
-import os
-
-BASE_DIR = os.path.dirname(os.path.abspath(__file__))
-TESTCASES_DIR = os.path.join(BASE_DIR, 'testcases')
-TEST_CONF_DIR = os.path.join(BASE_DIR, 'testcases')
-TREE_BASE = os.sep.join(BASE_DIR.split(os.sep)[:-2])
-
-# This domain contains reverse lookups for hostnames that are used.
-# The primary reason is so sudo will return quickly when it attempts
-# to look up the hostname. i9n is just short for 'integration'.
-# see also bug 1730744 for why we had to do this.
-CI_DOMAIN = "i9n.cloud-init.io"
-
-
-def _initialize_logging():
- """Configure logging for cloud_tests."""
- logger = logging.getLogger(__name__)
- logger.setLevel(logging.DEBUG)
- formatter = logging.Formatter(
- '%(asctime)s - %(pathname)s:%(funcName)s:%(lineno)s '
- '[%(levelname)s]: %(message)s')
-
- console = logging.StreamHandler()
- console.setLevel(logging.DEBUG)
- console.setFormatter(formatter)
-
- logger.addHandler(console)
-
- return logger
-
-
-LOG = _initialize_logging()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/__main__.py b/tests/cloud_tests/__main__.py
deleted file mode 100644
index 7ee29cad..00000000
--- a/tests/cloud_tests/__main__.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Main entry point."""
-
-import argparse
-import logging
-import os
-import sys
-
-from tests.cloud_tests import args, bddeb, collect, manage, run_funcs, verify
-from tests.cloud_tests import LOG
-
-
-def configure_log(args):
- """Configure logging."""
- level = logging.INFO
- if args.verbose:
- level = logging.DEBUG
- elif args.quiet:
- level = logging.WARN
- LOG.setLevel(level)
-
-
-def main():
- """Entry point for cloud test suite."""
- # configure parser
- parser = argparse.ArgumentParser(prog='cloud_tests')
- subparsers = parser.add_subparsers(dest="subcmd")
- subparsers.required = True
-
- def add_subparser(name, description, arg_sets):
- """Add arguments to subparser."""
- subparser = subparsers.add_parser(name, help=description)
- for (_args, _kwargs) in (a for arg_set in arg_sets for a in arg_set):
- subparser.add_argument(*_args, **_kwargs)
-
- # configure subparsers
- for (name, (description, arg_sets)) in args.SUBCMDS.items():
- add_subparser(name, description,
- [args.ARG_SETS[arg_set] for arg_set in arg_sets])
-
- # parse arguments
- parsed = parser.parse_args()
-
- # process arguments
- configure_log(parsed)
- (_, arg_sets) = args.SUBCMDS[parsed.subcmd]
- for normalizer in [args.NORMALIZERS[arg_set] for arg_set in arg_sets]:
- parsed = normalizer(parsed)
- if not parsed:
- return -1
-
- # run handler
- LOG.debug('running with args: %s', parsed)
- return {
- 'bddeb': bddeb.bddeb,
- 'collect': collect.collect,
- 'create': manage.create,
- 'run': run_funcs.run,
- 'tree_collect': run_funcs.tree_collect,
- 'tree_run': run_funcs.tree_run,
- 'verify': verify.verify,
- }[parsed.subcmd](parsed)
-
-
-if __name__ == "__main__":
- if os.geteuid() == 0:
- sys.exit('Do not run as root')
- sys.exit(main())
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/args.py b/tests/cloud_tests/args.py
deleted file mode 100644
index ab345491..00000000
--- a/tests/cloud_tests/args.py
+++ /dev/null
@@ -1,304 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Argparse argument setup and sanitization."""
-
-import os
-
-from tests.cloud_tests import config, util
-from tests.cloud_tests import LOG, TREE_BASE
-
-ARG_SETS = {
- 'BDDEB': (
- (('--bddeb-args',),
- {'help': 'args to pass through to bddeb',
- 'action': 'store', 'default': None, 'required': False}),
- (('--build-os',),
- {'help': 'OS to use as build system (default is xenial)',
- 'action': 'store', 'choices': config.ENABLED_DISTROS,
- 'default': 'xenial', 'required': False}),
- (('--build-platform',),
- {'help': 'platform to use for build system (default is lxd)',
- 'action': 'store', 'choices': config.ENABLED_PLATFORMS,
- 'default': 'lxd', 'required': False}),
- (('--cloud-init',),
- {'help': 'path to base of cloud-init tree', 'metavar': 'DIR',
- 'action': 'store', 'required': False, 'default': TREE_BASE}),),
- 'COLLECT': (
- (('-p', '--platform'),
- {'help': 'platform(s) to run tests on', 'metavar': 'PLATFORM',
- 'action': 'append', 'choices': config.ENABLED_PLATFORMS,
- 'default': []}),
- (('-n', '--os-name'),
- {'help': 'the name(s) of the OS(s) to test', 'metavar': 'NAME',
- 'action': 'append', 'choices': config.ENABLED_DISTROS,
- 'default': []}),
- (('-t', '--test-config'),
- {'help': 'test config file(s) to use', 'metavar': 'FILE',
- 'action': 'append', 'default': []}),
- (('--feature-override',),
- {'help': 'feature flags override(s), <flagname>=<true/false>',
- 'action': 'append', 'default': [], 'required': False}),),
- 'CREATE': (
- (('-c', '--config'),
- {'help': 'cloud-config yaml for testcase', 'metavar': 'DATA',
- 'action': 'store', 'required': False, 'default': None}),
- (('-e', '--enable'),
- {'help': 'enable testcase', 'required': False, 'default': False,
- 'action': 'store_true'}),
- (('name',),
- {'help': 'testcase name, in format "<category>/<test>"',
- 'action': 'store'}),
- (('-d', '--description'),
- {'help': 'description of testcase', 'required': False}),
- (('-f', '--force'),
- {'help': 'overwrite already existing test', 'required': False,
- 'action': 'store_true', 'default': False}),),
- 'INTERFACE': (
- (('-v', '--verbose'),
- {'help': 'verbose output', 'action': 'store_true', 'default': False}),
- (('-q', '--quiet'),
- {'help': 'quiet output', 'action': 'store_true', 'default': False}),),
- 'OUTPUT': (
- (('-d', '--data-dir'),
- {'help': 'directory to store test data in',
- 'action': 'store', 'metavar': 'DIR', 'required': False}),
- (('--preserve-instance',),
- {'help': 'do not destroy the instance under test',
- 'action': 'store_true', 'default': False, 'required': False}),
- (('--preserve-data',),
- {'help': 'do not remove collected data after successful run',
- 'action': 'store_true', 'default': False, 'required': False}),),
- 'OUTPUT_DEB': (
- (('--deb',),
- {'help': 'path to write output deb to', 'metavar': 'FILE',
- 'action': 'store', 'required': False,
- 'default': 'cloud-init_all.deb'}),),
- 'RESULT': (
- (('-r', '--result'),
- {'help': 'file to write results to',
- 'action': 'store', 'metavar': 'FILE'}),),
- 'SETUP': (
- (('--deb',),
- {'help': 'install deb', 'metavar': 'FILE', 'action': 'store'}),
- (('--rpm',),
- {'help': 'install rpm', 'metavar': 'FILE', 'action': 'store'}),
- (('--script',),
- {'help': 'script to set up image', 'metavar': 'DATA',
- 'action': 'store'}),
- (('--repo',),
- {'help': 'repo to enable (implies -u)', 'metavar': 'NAME',
- 'action': 'store'}),
- (('--ppa',),
- {'help': 'ppa to enable (implies -u)', 'metavar': 'NAME',
- 'action': 'store'}),
- (('-u', '--upgrade'),
- {'help': 'upgrade or install cloud-init from repo',
- 'action': 'store_true', 'default': False}),
- (('--upgrade-full',),
- {'help': 'do full system upgrade from repo (implies -u)',
- 'action': 'store_true', 'default': False}),),
-
-}
-
-SUBCMDS = {
- 'bddeb': ('build cloud-init deb from tree',
- ('BDDEB', 'OUTPUT_DEB', 'INTERFACE')),
- 'collect': ('collect test data',
- ('COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT', 'SETUP')),
- 'create': ('create new test case', ('CREATE', 'INTERFACE')),
- 'run': ('run test suite',
- ('COLLECT', 'INTERFACE', 'RESULT', 'OUTPUT', 'SETUP')),
- 'tree_collect': ('collect using current working tree',
- ('BDDEB', 'COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT')),
- 'tree_run': ('run using current working tree',
- ('BDDEB', 'COLLECT', 'INTERFACE', 'OUTPUT', 'RESULT')),
- 'verify': ('verify test data', ('INTERFACE', 'OUTPUT', 'RESULT')),
-}
-
-
-def _empty_normalizer(args):
- """Do not normalize arguments."""
- return args
-
-
-def normalize_bddeb_args(args):
- """Normalize BDDEB arguments.
-
- @param args: parsed args
- @return_value: updated args, or None if errors encountered
- """
- # make sure cloud-init dir is accessible
- if not (args.cloud_init and os.path.isdir(args.cloud_init)):
- LOG.error('invalid cloud-init tree path')
- return None
-
- return args
-
-
-def normalize_create_args(args):
- """Normalize CREATE arguments.
-
- @param args: parsed args
- @return_value: updated args, or None if errors occurred
- """
- # ensure valid name for new test
- if len(args.name.split('/')) != 2:
- LOG.error('invalid test name: %s', args.name)
- return None
- if os.path.exists(config.name_to_path(args.name)):
- msg = 'test: {} already exists'.format(args.name)
- if args.force:
- LOG.warning('%s but ignoring due to --force', msg)
- else:
- LOG.error(msg)
- return None
-
- # ensure test config valid if specified
- if isinstance(args.config, str) and len(args.config) == 0:
- LOG.error('test config cannot be empty if specified')
- return None
-
- # ensure description valid if specified
- if (isinstance(args.description, str) and
- (len(args.description) > 70 or len(args.description) == 0)):
- LOG.error('test description must be between 1 and 70 characters')
- return None
-
- return args
-
-
-def normalize_collect_args(args):
- """Normalize COLLECT arguments.
-
- @param args: parsed args
- @return_value: updated args, or None if errors occurred
- """
- # platform should default to lxd
- if len(args.platform) == 0:
- args.platform = ['lxd']
- args.platform = util.sorted_unique(args.platform)
-
- # os name should default to all enabled
- # if os name is provided ensure that all provided are supported
- if len(args.os_name) == 0:
- args.os_name = config.ENABLED_DISTROS
- else:
- supported = config.ENABLED_DISTROS
- invalid = [os_name for os_name in args.os_name
- if os_name not in supported]
- if len(invalid) != 0:
- LOG.error('invalid os name(s): %s', invalid)
- return None
- args.os_name = util.sorted_unique(args.os_name)
-
- # test configs should default to all enabled
- # if test configs are provided, ensure that all provided are valid
- if len(args.test_config) == 0:
- args.test_config = config.list_test_configs()
- else:
- valid = []
- invalid = []
- for name in args.test_config:
- if os.path.exists(name):
- valid.append(name)
- elif os.path.exists(config.name_to_path(name)):
- valid.append(config.name_to_path(name))
- else:
- invalid.append(name)
- if len(invalid) != 0:
- LOG.error('invalid test config(s): %s', invalid)
- return None
- else:
- args.test_config = valid
- args.test_config = util.sorted_unique(args.test_config)
-
- # parse feature flag overrides and ensure all are valid
- if args.feature_override:
- overrides = args.feature_override
- args.feature_override = util.parse_conf_list(
- overrides, boolean=True, valid=config.list_feature_flags())
- if not args.feature_override:
- LOG.error('invalid feature flag override(s): %s', overrides)
- return None
- else:
- args.feature_override = {}
-
- return args
-
-
-def normalize_output_args(args):
- """Normalize OUTPUT arguments.
-
- @param args: parsed args
- @return_value: updated args, or None if errors occurred
- """
- if args.data_dir:
- args.data_dir = os.path.abspath(args.data_dir)
- if not os.path.exists(args.data_dir):
- os.mkdir(args.data_dir)
-
- if not args.data_dir:
- args.data_dir = None
-
- # ensure clean output dir if collect
- # ensure data exists if verify
- if args.subcmd == 'collect':
- if not util.is_clean_writable_dir(args.data_dir):
- LOG.error('data_dir must be empty/new and must be writable')
- return None
-
- return args
-
-
-def normalize_output_deb_args(args):
- """Normalize OUTPUT_DEB arguments.
-
- @param args: parsed args
- @return_value: updated args, or None if erros occurred
- """
- # make sure to use abspath for deb
- args.deb = os.path.abspath(args.deb)
-
- if not args.deb.endswith('.deb'):
- LOG.error('output filename does not end in ".deb"')
- return None
-
- return args
-
-
-def normalize_setup_args(args):
- """Normalize SETUP arguments.
-
- @param args: parsed args
- @return_value: updated_args, or None if errors occurred
- """
- # ensure deb or rpm valid if specified
- for pkg in (args.deb, args.rpm):
- if pkg is not None and not os.path.exists(pkg):
- LOG.error('cannot find package: %s', pkg)
- return None
-
- # if repo or ppa to be enabled run upgrade
- if args.repo or args.ppa:
- args.upgrade = True
-
- # if ppa is specified, remove leading 'ppa:' if any
- _ppa_header = 'ppa:'
- if args.ppa and args.ppa.startswith(_ppa_header):
- args.ppa = args.ppa[len(_ppa_header):]
-
- return args
-
-
-NORMALIZERS = {
- 'BDDEB': normalize_bddeb_args,
- 'COLLECT': normalize_collect_args,
- 'CREATE': normalize_create_args,
- 'INTERFACE': _empty_normalizer,
- 'OUTPUT': normalize_output_args,
- 'OUTPUT_DEB': normalize_output_deb_args,
- 'RESULT': _empty_normalizer,
- 'SETUP': normalize_setup_args,
-}
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/bddeb.py b/tests/cloud_tests/bddeb.py
deleted file mode 100644
index e45ad947..00000000
--- a/tests/cloud_tests/bddeb.py
+++ /dev/null
@@ -1,119 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Used to build a deb."""
-
-from functools import partial
-import os
-import tempfile
-
-from cloudinit import subp
-from tests.cloud_tests import (config, LOG)
-from tests.cloud_tests import platforms
-from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single)
-
-pre_reqs = ['devscripts', 'equivs', 'git', 'tar']
-
-
-def _out(cmd_res):
- """Get clean output from cmd result."""
- return cmd_res[0].decode("utf-8").strip()
-
-
-def build_deb(args, instance):
- """Build deb on system and copy out to location at args.deb.
-
- @param args: cmdline arguments
- @return_value: tuple of results and fail count
- """
- # update remote system package list and install build deps
- LOG.debug('installing pre-reqs')
- pkgs = ' '.join(pre_reqs)
- instance.execute('apt-get update && apt-get install --yes {}'.format(pkgs))
-
- # local tmpfile that must be deleted
- local_tarball = tempfile.NamedTemporaryFile().name
-
- # paths to use in remote system
- output_link = '/root/cloud-init_all.deb'
- remote_tarball = _out(instance.execute(['mktemp']))
- extract_dir = '/root'
- bddeb_path = os.path.join(extract_dir, 'packages', 'bddeb')
- git_env = {'GIT_DIR': os.path.join(extract_dir, '.git'),
- 'GIT_WORK_TREE': extract_dir}
-
- LOG.debug('creating tarball of cloud-init at: %s', local_tarball)
- subp.subp(['tar', 'cf', local_tarball, '--owner', 'root',
- '--group', 'root', '-C', args.cloud_init, '.'])
- LOG.debug('copying to remote system at: %s', remote_tarball)
- instance.push_file(local_tarball, remote_tarball)
-
- LOG.debug('extracting tarball in remote system at: %s', extract_dir)
- instance.execute(['tar', 'xf', remote_tarball, '-C', extract_dir])
- instance.execute(['git', 'commit', '-a', '-m', 'tmp', '--allow-empty'],
- env=git_env)
-
- LOG.debug('installing deps')
- deps_path = os.path.join(extract_dir, 'tools', 'read-dependencies')
- instance.execute([deps_path, '--install', '--test-distro',
- '--distro', 'ubuntu'])
-
- LOG.debug('building deb in remote system at: %s', output_link)
- bddeb_args = args.bddeb_args.split() if args.bddeb_args else []
- instance.execute([bddeb_path, '-d'] + bddeb_args, env=git_env)
-
- # copy the deb back to the host system
- LOG.debug('copying built deb to host at: %s', args.deb)
- instance.pull_file(output_link, args.deb)
-
-
-def setup_build(args):
- """Set build system up then run build.
-
- @param args: cmdline arguments
- @return_value: tuple of results and fail count
- """
- res = ({}, 1)
-
- # set up platform
- LOG.info('setting up platform: %s', args.build_platform)
- platform_config = config.load_platform_config(args.build_platform)
- platform_call = partial(platforms.get_platform, args.build_platform,
- platform_config)
- with PlatformComponent(platform_call) as platform:
-
- # set up image
- LOG.info('acquiring image for os: %s', args.build_os)
- img_conf = config.load_os_config(platform.platform_name, args.build_os)
- image_call = partial(platforms.get_image, platform, img_conf)
- with PlatformComponent(image_call) as image:
-
- # set up snapshot
- snapshot_call = partial(platforms.get_snapshot, image)
- with PlatformComponent(snapshot_call) as snapshot:
-
- # create instance with cloud-config to set it up
- LOG.info('creating instance to build deb in')
- empty_cloud_config = "#cloud-config\n{}"
- instance_call = partial(
- platforms.get_instance, snapshot, empty_cloud_config,
- use_desc='build cloud-init deb')
- with PlatformComponent(instance_call) as instance:
-
- # build the deb
- res = run_single('build deb on system',
- partial(build_deb, args, instance))
-
- return res
-
-
-def bddeb(args):
- """Entry point for build deb.
-
- @param args: cmdline arguments
- @return_value: fail count
- """
- LOG.info('preparing to build cloud-init deb')
- _res, failed = run_stage('build deb', [partial(setup_build, args)])
- return failed
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py
deleted file mode 100644
index 642745d8..00000000
--- a/tests/cloud_tests/collect.py
+++ /dev/null
@@ -1,219 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Used to collect data from platforms during tests."""
-
-from functools import partial
-import os
-
-from cloudinit import util as c_util
-from tests.cloud_tests import (config, LOG, setup_image, util)
-from tests.cloud_tests.stage import (PlatformComponent, run_stage, run_single)
-from tests.cloud_tests import platforms
-from tests.cloud_tests.testcases import base, get_test_class
-
-
-def collect_script(instance, base_dir, script, script_name):
- """Collect script data.
-
- @param instance: instance to run script on
- @param base_dir: base directory for output data
- @param script: script contents
- @param script_name: name of script to run
- @return_value: None, may raise errors
- """
- LOG.debug('running collect script: %s', script_name)
- (out, err, exit) = instance.run_script(
- script.encode(), rcs=False,
- description='collect: {}'.format(script_name))
- if err:
- LOG.debug("collect script %s exited '%s' and had stderr: %s",
- script_name, err, exit)
- if not isinstance(out, bytes):
- raise util.PlatformError(
- "Collection of '%s' returned type %s, expected bytes: %s" %
- (script_name, type(out), out))
-
- c_util.write_file(os.path.join(base_dir, script_name), out)
-
-
-def collect_console(instance, base_dir):
- """Collect instance console log.
-
- @param instance: instance to get console log for
- @param base_dir: directory to write console log to
- """
- logfile = os.path.join(base_dir, 'console.log')
- LOG.debug('getting console log for %s to %s', instance.name, logfile)
- try:
- data = instance.console_log()
- except NotImplementedError as e:
- # args[0] is hacky, but thats all I see to get at the message.
- data = b'NotImplementedError:' + e.args[0].encode()
- with open(logfile, "wb") as fp:
- fp.write(data)
-
-
-def collect_test_data(args, snapshot, os_name, test_name):
- """Collect data for test case.
-
- @param args: cmdline arguments
- @param snapshot: instantiated snapshot
- @param test_name: name or path of test to run
- @return_value: tuple of results and fail count
- """
- res = ({}, 1)
-
- # load test config
- test_name_in = test_name
- test_name = config.path_to_name(test_name)
- test_config = config.load_test_config(test_name)
- user_data = test_config['cloud_config']
- test_scripts = test_config['collect_scripts']
- test_output_dir = os.sep.join(
- (args.data_dir, snapshot.platform_name, os_name, test_name))
-
- # if test is not enabled, skip and return 0 failures
- if not test_config.get('enabled', False):
- LOG.warning('test config %s is not enabled, skipping', test_name)
- return ({}, 0)
-
- test_class = get_test_class(
- config.name_to_module(test_name_in),
- test_data={'platform': snapshot.platform_name, 'os_name': os_name},
- test_conf=test_config['cloud_config'])
- try:
- test_class.maybeSkipTest()
- except base.SkipTest as s:
- LOG.warning('skipping test config %s: %s', test_name, s)
- return ({}, 0)
-
- # if testcase requires a feature flag that the image does not support,
- # skip the testcase with a warning
- req_features = test_config.get('required_features', [])
- if any(feature not in snapshot.features for feature in req_features):
- LOG.warning('test config %s requires features not supported by image, '
- 'skipping.\nrequired features: %s\nsupported features: %s',
- test_name, req_features, snapshot.features)
- return ({}, 0)
-
- # if there are user data overrides required for this test case, apply them
- overrides = snapshot.config.get('user_data_overrides', {})
- if overrides:
- LOG.debug('updating user data for collect with: %s', overrides)
- user_data = util.update_user_data(user_data, overrides)
-
- # create test instance
- component = PlatformComponent(
- partial(platforms.get_instance, snapshot, user_data,
- block=True, start=False, use_desc=test_name),
- preserve_instance=args.preserve_instance)
-
- LOG.info('collecting test data for test: %s', test_name)
- with component as instance:
- start_call = partial(run_single, 'boot instance', partial(
- instance.start, wait=True, wait_for_cloud_init=True))
- collect_calls = [partial(run_single, 'script {}'.format(script_name),
- partial(collect_script, instance,
- test_output_dir, script, script_name))
- for script_name, script in test_scripts.items()]
-
- res = run_stage('collect for test: {}'.format(test_name),
- [start_call] + collect_calls)
-
- instance.shutdown()
- collect_console(instance, test_output_dir)
-
- return res
-
-
-def collect_snapshot(args, image, os_name):
- """Collect data for snapshot of image.
-
- @param args: cmdline arguments
- @param image: instantiated image with set up complete
- @return_value tuple of results and fail count
- """
- res = ({}, 1)
-
- component = PlatformComponent(partial(platforms.get_snapshot, image))
-
- LOG.debug('creating snapshot for %s', os_name)
- with component as snapshot:
- LOG.info('collecting test data for os: %s', os_name)
- res = run_stage(
- 'collect test data for {}'.format(os_name),
- [partial(collect_test_data, args, snapshot, os_name, test_name)
- for test_name in args.test_config])
-
- return res
-
-
-def collect_image(args, platform, os_name):
- """Collect data for image.
-
- @param args: cmdline arguments
- @param platform: instantiated platform
- @param os_name: name of distro to collect for
- @return_value: tuple of results and fail count
- """
- res = ({}, 1)
-
- os_config = config.load_os_config(
- platform.platform_name, os_name, require_enabled=True,
- feature_overrides=args.feature_override)
- LOG.debug('os config: %s', os_config)
- component = PlatformComponent(
- partial(platforms.get_image, platform, os_config))
-
- LOG.info('acquiring image for os: %s', os_name)
- with component as image:
- res = run_stage('set up and collect data for os: {}'.format(os_name),
- [partial(setup_image.setup_image, args, image)] +
- [partial(collect_snapshot, args, image, os_name)],
- continue_after_error=False)
-
- return res
-
-
-def collect_platform(args, platform_name):
- """Collect data for platform.
-
- @param args: cmdline arguments
- @param platform_name: platform to collect for
- @return_value: tuple of results and fail count
- """
- res = ({}, 1)
-
- platform_config = config.load_platform_config(
- platform_name, require_enabled=True)
- platform_config['data_dir'] = args.data_dir
- LOG.debug('platform config: %s', platform_config)
- component = PlatformComponent(
- partial(platforms.get_platform, platform_name, platform_config))
-
- LOG.info('setting up platform: %s', platform_name)
- with component as platform:
- res = run_stage('collect for platform: {}'.format(platform_name),
- [partial(collect_image, args, platform, os_name)
- for os_name in args.os_name])
-
- return res
-
-
-def collect(args):
- """Entry point for collection.
-
- @param args: cmdline arguments
- @return_value: fail count
- """
- (res, failed) = run_stage(
- 'collect data', [partial(collect_platform, args, platform_name)
- for platform_name in args.platform])
-
- LOG.debug('collect stages: %s', res)
- if args.result:
- util.merge_results({'collect_stages': res}, args.result)
-
- return failed
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/config.py b/tests/cloud_tests/config.py
deleted file mode 100644
index 06536edc..00000000
--- a/tests/cloud_tests/config.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Used to setup test configuration."""
-
-import glob
-import os
-
-from cloudinit import util as c_util
-from tests.cloud_tests import (BASE_DIR, TEST_CONF_DIR)
-
-# conf files
-CONF_EXT = '.yaml'
-VERIFY_EXT = '.py'
-PLATFORM_CONF = os.path.join(BASE_DIR, 'platforms.yaml')
-RELEASES_CONF = os.path.join(BASE_DIR, 'releases.yaml')
-TESTCASE_CONF = os.path.join(BASE_DIR, 'testcases.yaml')
-
-
-def get(base, key):
- """Get config entry 'key' from base, ensuring is dictionary."""
- return base[key] if key in base and base[key] is not None else {}
-
-
-def enabled(config):
- """Test if config item is enabled."""
- return isinstance(config, dict) and config.get('enabled', False)
-
-
-def path_to_name(path):
- """Convert abs or rel path to test config to path under 'sconfigs/'."""
- dir_path, file_name = os.path.split(os.path.normpath(path))
- name = os.path.splitext(file_name)[0]
- return os.sep.join((os.path.basename(dir_path), name))
-
-
-def name_to_path(name):
- """Convert test config path under configs/ to full config path."""
- name = os.path.normpath(name)
- if not name.endswith(CONF_EXT):
- name = name + CONF_EXT
- return name if os.path.isabs(name) else os.path.join(TEST_CONF_DIR, name)
-
-
-def name_sanitize(name):
- """Sanitize test name to be used as a module name."""
- return name.replace('-', '_')
-
-
-def name_to_module(name):
- """Convert test name to a loadable module name under 'testcases/'."""
- name = name_sanitize(path_to_name(name))
- return name.replace(os.path.sep, '.')
-
-
-def merge_config(base, override):
- """Merge config and base."""
- res = base.copy()
- res.update(override)
- res.update({k: merge_config(base.get(k, {}), v)
- for k, v in override.items() if isinstance(v, dict)})
- return res
-
-
-def merge_feature_groups(feature_conf, feature_groups, overrides):
- """Combine feature groups and overrides to construct a supported list.
-
- @param feature_conf: feature config from releases.yaml
- @param feature_groups: feature groups the release is a member of
- @param overrides: overrides specified by the release's config
- @return_value: dict of {feature: true/false} settings
- """
- res = dict().fromkeys(feature_conf['all'])
- for group in feature_groups:
- res.update(feature_conf['groups'][group])
- res.update(overrides)
- return res
-
-
-def load_platform_config(platform_name, require_enabled=False):
- """Load configuration for platform.
-
- @param platform_name: name of platform to retrieve config for
- @param require_enabled: if true, raise error if 'enabled' not True
- @return_value: config dict
- """
- main_conf = c_util.read_conf(PLATFORM_CONF)
- conf = merge_config(main_conf['default_platform_config'],
- main_conf['platforms'][platform_name])
- if require_enabled and not enabled(conf):
- raise ValueError('Platform is not enabled')
- return conf
-
-
-def load_os_config(platform_name, os_name, require_enabled=False,
- feature_overrides=None):
- """Load configuration for os.
-
- @param platform_name: platform name to load os config for
- @param os_name: name of os to retrieve config for
- @param require_enabled: if true, raise error if 'enabled' not True
- @param feature_overrides: feature flag overrides to merge with features
- @return_value: config dict
- """
- if feature_overrides is None:
- feature_overrides = {}
- main_conf = c_util.read_conf(RELEASES_CONF)
- default = main_conf['default_release_config']
- image = main_conf['releases'][os_name]
- conf = merge_config(merge_config(get(default, 'default'),
- get(default, platform_name)),
- merge_config(get(image, 'default'),
- get(image, platform_name)))
-
- feature_conf = main_conf['features']
- feature_groups = conf.get('feature_groups', [])
- overrides = merge_config(get(conf, 'features'), feature_overrides)
- conf['arch'] = c_util.get_dpkg_architecture()
- conf['features'] = merge_feature_groups(
- feature_conf, feature_groups, overrides)
-
- if require_enabled and not enabled(conf):
- raise ValueError('OS is not enabled')
- return conf
-
-
-def load_test_config(path):
- """Load a test config file by either abs path or rel path."""
- return merge_config(c_util.read_conf(TESTCASE_CONF)['base_test_data'],
- c_util.read_conf(name_to_path(path)))
-
-
-def list_feature_flags():
- """List all supported feature flags."""
- feature_conf = get(c_util.read_conf(RELEASES_CONF), 'features')
- return feature_conf.get('all', [])
-
-
-def list_enabled_platforms():
- """List all platforms enabled for testing."""
- platforms = get(c_util.read_conf(PLATFORM_CONF), 'platforms')
- return [k for k, v in platforms.items() if enabled(v)]
-
-
-def list_enabled_distros(platforms):
- """List all distros enabled for testing on specified platforms."""
- def platform_has_enabled(config):
- """List if platform is enabled."""
- return any(enabled(merge_config(get(config, 'default'),
- get(config, platform)))
- for platform in platforms)
-
- releases = get(c_util.read_conf(RELEASES_CONF), 'releases')
- return [k for k, v in releases.items() if platform_has_enabled(v)]
-
-
-def list_test_configs():
- """List all available test config files by abspath."""
- return [os.path.abspath(f) for f in
- glob.glob(os.sep.join((TEST_CONF_DIR, '*', '*.yaml')))]
-
-
-ENABLED_PLATFORMS = sorted(list_enabled_platforms())
-ENABLED_DISTROS = sorted(list_enabled_distros(ENABLED_PLATFORMS))
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/manage.py b/tests/cloud_tests/manage.py
deleted file mode 100644
index 5f0cfd23..00000000
--- a/tests/cloud_tests/manage.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Create test cases automatically given a user_data script."""
-
-import os
-import textwrap
-
-from cloudinit import util as c_util
-from tests.cloud_tests.config import VERIFY_EXT
-from tests.cloud_tests import (config, util)
-from tests.cloud_tests import TESTCASES_DIR
-
-
-_verifier_fmt = textwrap.dedent(
- """
- \"\"\"cloud-init Integration Test Verify Script\"\"\"
- from tests.cloud_tests.testcases import base
-
-
- class {test_class}(base.CloudTestCase):
- \"\"\"
- Name: {test_name}
- Category: {test_category}
- Description: {test_description}
- \"\"\"
- pass
- """
-).lstrip()
-_config_fmt = textwrap.dedent(
- """
- #
- # Name: {test_name}
- # Category: {test_category}
- # Description: {test_description}
- #
- {config}
- """
-).strip()
-
-
-def write_testcase_config(args, fmt_args, testcase_file):
- """Write the testcase config file."""
- testcase_config = {'enabled': args.enable, 'collect_scripts': {}}
- if args.config:
- testcase_config['cloud_config'] = args.config
- fmt_args['config'] = util.yaml_format(testcase_config)
- c_util.write_file(testcase_file, _config_fmt.format(**fmt_args), omode='w')
-
-
-def write_verifier(args, fmt_args, verifier_file):
- """Write the verifier script."""
- fmt_args['test_class'] = 'Test{}'.format(
- config.name_sanitize(fmt_args['test_name']).title())
- c_util.write_file(verifier_file,
- _verifier_fmt.format(**fmt_args), omode='w')
-
-
-def create(args):
- """Create a new testcase."""
- (test_category, test_name) = args.name.split('/')
- fmt_args = {'test_name': test_name, 'test_category': test_category,
- 'test_description': str(args.description)}
-
- testcase_file = config.name_to_path(args.name)
- verifier_file = os.path.join(
- TESTCASES_DIR, test_category,
- config.name_sanitize(test_name) + VERIFY_EXT)
-
- write_testcase_config(args, fmt_args, testcase_file)
- write_verifier(args, fmt_args, verifier_file)
-
- return 0
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms.yaml b/tests/cloud_tests/platforms.yaml
deleted file mode 100644
index eaaa0a71..00000000
--- a/tests/cloud_tests/platforms.yaml
+++ /dev/null
@@ -1,77 +0,0 @@
-# ============================= Platform Config ===============================
-default_platform_config:
- # all disabled by default
- enabled: false
- # maximum time to retrieve image
- get_image_timeout: 300
- # maximum time to create instance (before waiting for cloud-init)
- create_instance_timeout: 60
- private_key: cloud_init_rsa
- public_key: cloud_init_rsa.pub
-platforms:
- ec2:
- enabled: true
- instance-type: t2.micro
- tag: cii
- lxd:
- enabled: true
- # overrides for image templates
- template_overrides:
- /var/lib/cloud/seed/nocloud-net/meta-data:
- when:
- - create
- - copy
- template: cloud-init-meta.tpl
- /var/lib/cloud/seed/nocloud-net/network-config:
- when:
- - create
- - copy
- template: cloud-init-network.tpl
- /var/lib/cloud/seed/nocloud-net/user-data:
- when:
- - create
- - copy
- template: cloud-init-user.tpl
- properties:
- default: |
- #cloud-config
- {}
- /var/lib/cloud/seed/nocloud-net/vendor-data:
- when:
- - create
- - copy
- template: cloud-init-vendor.tpl
- properties:
- default: |
- #cloud-config
- {}
- # overrides image template files
- template_files:
- cloud-init-meta.tpl: |
- #cloud-config
- instance-id: {{ container.name }}
- local-hostname: {{ container.name }}
- {{ config_get("user.meta-data", "") }}
- cloud-init-network.tpl: |
- {% if config_get("user.network-config", "") == "" %}version: 1
- config:
- - type: physical
- name: eth0
- subnets:
- - type: {% if config_get("user.network_mode", "") == "link-local" %}manual{% else %}dhcp{% endif %}
- control: auto{% else %}{{ config_get("user.network-config", "") }}{% endif %}
- cloud-init-user.tpl: |
- {{ config_get("user.user-data", properties.default) }}
- cloud-init-vendor.tpl: |
- {{ config_get("user.vendor-data", properties.default) }}
- nocloud-kvm:
- enabled: true
- cache_mode: cache=none,aio=native
- azurecloud:
- enabled: true
- region: West US 2
- vm_size: Standard_DS1_v2
- storage_sku: standard_lrs
- tag: ci
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/__init__.py b/tests/cloud_tests/platforms/__init__.py
deleted file mode 100644
index e506baa0..00000000
--- a/tests/cloud_tests/platforms/__init__.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Main init."""
-
-from .ec2 import platform as ec2
-from .lxd import platform as lxd
-from .nocloudkvm import platform as nocloudkvm
-from .azurecloud import platform as azurecloud
-from ..util import emit_dots_on_travis
-
-PLATFORMS = {
- 'ec2': ec2.EC2Platform,
- 'nocloud-kvm': nocloudkvm.NoCloudKVMPlatform,
- 'lxd': lxd.LXDPlatform,
- 'azurecloud': azurecloud.AzureCloudPlatform,
-}
-
-
-def get_image(platform, config):
- """Get image from platform object using os_name."""
- with emit_dots_on_travis():
- return platform.get_image(config)
-
-
-def get_instance(snapshot, *args, **kwargs):
- """Get instance from snapshot."""
- return snapshot.launch(*args, **kwargs)
-
-
-def get_platform(platform_name, config):
- """Get the platform object for 'platform_name' and init."""
- platform_cls = PLATFORMS.get(platform_name)
- if not platform_cls:
- raise ValueError('invalid platform name: {}'.format(platform_name))
- return platform_cls(config)
-
-
-def get_snapshot(image):
- """Get snapshot from image."""
- return image.snapshot()
-
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/azurecloud/__init__.py b/tests/cloud_tests/platforms/azurecloud/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/tests/cloud_tests/platforms/azurecloud/__init__.py
+++ /dev/null
diff --git a/tests/cloud_tests/platforms/azurecloud/image.py b/tests/cloud_tests/platforms/azurecloud/image.py
deleted file mode 100644
index aad2bca1..00000000
--- a/tests/cloud_tests/platforms/azurecloud/image.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Azure Cloud image Base class."""
-
-from tests.cloud_tests import LOG
-
-from ..images import Image
-from .snapshot import AzureCloudSnapshot
-
-
-class AzureCloudImage(Image):
- """Azure Cloud backed image."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, config, image_id):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- @param image_id: image id used to boot instance
- """
- super(AzureCloudImage, self).__init__(platform, config)
- self._img_instance = None
- self.image_id = image_id
-
- @property
- def _instance(self):
- """Internal use only, returns a running instance"""
- if not self._img_instance:
- self._img_instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_id, user_data=None)
- self._img_instance.start(wait=True, wait_for_cloud_init=True)
- return self._img_instance
-
- def destroy(self):
- """Delete the instance used to create a custom image."""
- if self._img_instance:
- LOG.debug('Deleting backing instance %s',
- self._img_instance.vm_name)
- delete_vm = self.platform.compute_client.virtual_machines.delete(
- self.platform.resource_group.name, self._img_instance.vm_name)
- delete_vm.wait()
-
- super(AzureCloudImage, self).destroy()
-
- def _execute(self, *args, **kwargs):
- """Execute command in image, modifying image."""
- LOG.debug('executing commands on image')
- self._instance.start(wait=True)
- return self._instance._execute(*args, **kwargs)
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'."""
- LOG.debug('pushing file to image')
- return self._instance.push_file(local_path, remote_path)
-
- def run_script(self, *args, **kwargs):
- """Run script in image, modifying image.
-
- @return_value: script output
- """
- LOG.debug('running script on image')
- self._instance.start()
- return self._instance.run_script(*args, **kwargs)
-
- def snapshot(self):
- """ Create snapshot (image) of instance, wait until done.
-
- If no instance has been booted, base image is returned.
- Otherwise runs the clean script, deallocates, generalizes
- and creates custom image from instance.
- """
- LOG.debug('creating snapshot of image')
- if not self._img_instance:
- LOG.debug('No existing image, snapshotting base image')
- return AzureCloudSnapshot(self.platform, self.properties,
- self.config, self.features,
- self._instance.vm_name,
- delete_on_destroy=False)
-
- LOG.debug('creating snapshot from instance: %s', self._img_instance)
- if self.config.get('boot_clean_script'):
- self._img_instance.run_script(self.config.get('boot_clean_script'))
-
- LOG.debug('deallocating instance %s', self._instance.vm_name)
- deallocate = self.platform.compute_client.virtual_machines.deallocate(
- self.platform.resource_group.name, self._instance.vm_name)
- deallocate.wait()
-
- LOG.debug('generalizing instance %s', self._instance.vm_name)
- self.platform.compute_client.virtual_machines.generalize(
- self.platform.resource_group.name, self._instance.vm_name)
-
- image_params = {
- "location": self.platform.location,
- "properties": {
- "sourceVirtualMachine": {
- "id": self._img_instance.instance.id
- }
- }
- }
- LOG.debug('updating resource group image %s', self._instance.vm_name)
- self.platform.compute_client.images.create_or_update(
- self.platform.resource_group.name, self._instance.vm_name,
- image_params)
-
- LOG.debug('destroying self')
- self.destroy()
-
- LOG.debug('snapshot complete')
- return AzureCloudSnapshot(self.platform, self.properties, self.config,
- self.features, self._instance.vm_name)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/azurecloud/instance.py b/tests/cloud_tests/platforms/azurecloud/instance.py
deleted file mode 100644
index eedbaae8..00000000
--- a/tests/cloud_tests/platforms/azurecloud/instance.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud instance."""
-
-from datetime import datetime, timedelta
-from urllib.parse import urlparse
-from time import sleep
-import traceback
-import os
-
-
-# pylint: disable=no-name-in-module
-from azure.storage.blob import BlockBlobService, BlobPermissions
-from msrestazure.azure_exceptions import CloudError
-
-from tests.cloud_tests import LOG
-
-from ..instances import Instance
-
-
-class AzureCloudInstance(Instance):
- """Azure Cloud backed instance."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, properties, config,
- features, image_id, user_data=None):
- """Set up instance.
-
- @param platform: platform object
- @param properties: dictionary of properties
- @param config: dictionary of configuration values
- @param features: dictionary of supported feature flags
- @param image_id: image to find and/or use
- @param user_data: test user-data to pass to instance
- """
- super(AzureCloudInstance, self).__init__(
- platform, image_id, properties, config, features)
-
- self.ssh_port = 22
- self.ssh_ip = None
- self.instance = None
- self.image_id = image_id
- self.vm_name = 'ci-azure-i-%s' % self.platform.tag
- self.user_data = user_data
- self.ssh_key_file = os.path.join(
- platform.config['data_dir'], platform.config['private_key'])
- self.ssh_pubkey_file = os.path.join(
- platform.config['data_dir'], platform.config['public_key'])
- self.blob_client, self.container, self.blob = None, None, None
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance with the platforms NIC."""
- if self.instance:
- return
- data = self.image_id.split('-')
- release, support = data[2].replace('_', '.'), data[3]
- sku = '%s-%s' % (release, support) if support == 'LTS' else release
- image_resource_id = '/subscriptions/%s' \
- '/resourceGroups/%s' \
- '/providers/Microsoft.Compute/images/%s' % (
- self.platform.subscription_id,
- self.platform.resource_group.name,
- self.image_id)
- storage_uri = "http://%s.blob.core.windows.net" \
- % self.platform.storage.name
- with open(self.ssh_pubkey_file, 'r') as key:
- ssh_pub_keydata = key.read()
-
- image_exists = False
- try:
- LOG.debug('finding image in resource group using image_id')
- self.platform.compute_client.images.get(
- self.platform.resource_group.name,
- self.image_id
- )
- image_exists = True
- LOG.debug('image found, launching instance, image_id=%s',
- self.image_id)
- except CloudError:
- LOG.debug(('image not found, launching instance with base image, '
- 'image_id=%s'), self.image_id)
-
- vm_params = {
- 'name': self.vm_name,
- 'location': self.platform.location,
- 'os_profile': {
- 'computer_name': 'CI-%s' % self.platform.tag,
- 'admin_username': self.ssh_username,
- "customData": self.user_data,
- "linuxConfiguration": {
- "disable_password_authentication": True,
- "ssh": {
- "public_keys": [{
- "path": "/home/%s/.ssh/authorized_keys" %
- self.ssh_username,
- "keyData": ssh_pub_keydata
- }]
- }
- }
- },
- "diagnosticsProfile": {
- "bootDiagnostics": {
- "storageUri": storage_uri,
- "enabled": True
- }
- },
- 'hardware_profile': {
- 'vm_size': self.platform.vm_size
- },
- 'storage_profile': {
- 'image_reference': {
- 'id': image_resource_id
- } if image_exists else {
- 'publisher': 'Canonical',
- 'offer': 'UbuntuServer',
- 'sku': sku,
- 'version': 'latest'
- }
- },
- 'network_profile': {
- 'network_interfaces': [{
- 'id': self.platform.nic.id
- }]
- },
- 'tags': {
- 'Name': self.platform.tag,
- }
- }
-
- try:
- self.instance = self.platform.compute_client.virtual_machines.\
- create_or_update(self.platform.resource_group.name,
- self.vm_name, vm_params)
- LOG.debug('creating instance %s from image_id=%s', self.vm_name,
- self.image_id)
- except CloudError as e:
- raise RuntimeError(
- 'failed creating instance:\n{}'.format(traceback.format_exc())
- ) from e
-
- if wait:
- self.instance.wait()
- self.ssh_ip = self.platform.network_client.\
- public_ip_addresses.get(
- self.platform.resource_group.name,
- self.platform.public_ip.name
- ).ip_address
- self._wait_for_system(wait_for_cloud_init)
-
- self.instance = self.instance.result()
- self.blob_client, self.container, self.blob =\
- self._get_blob_client()
-
- def shutdown(self, wait=True):
- """Finds console log then stopping/deallocates VM"""
- LOG.debug('waiting on console log before stopping')
- attempts, exists = 5, False
- while not exists and attempts:
- try:
- attempts -= 1
- exists = self.blob_client.get_blob_to_bytes(
- self.container, self.blob)
- LOG.debug('found console log')
- except Exception as e:
- if attempts:
- LOG.debug('Unable to find console log, '
- '%s attempts remaining', attempts)
- sleep(15)
- else:
- LOG.warning('Could not find console log: %s', e)
-
- LOG.debug('stopping instance %s', self.image_id)
- vm_deallocate = \
- self.platform.compute_client.virtual_machines.deallocate(
- self.platform.resource_group.name, self.image_id)
- if wait:
- vm_deallocate.wait()
-
- def destroy(self):
- """Delete VM and close all connections"""
- if self.instance:
- LOG.debug('destroying instance: %s', self.image_id)
- vm_delete = self.platform.compute_client.virtual_machines.delete(
- self.platform.resource_group.name, self.image_id)
- vm_delete.wait()
-
- self._ssh_close()
-
- super(AzureCloudInstance, self).destroy()
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command on instance."""
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- return self._ssh(['sudo'] + env_args + list(command), stdin=stdin)
-
- def _get_blob_client(self):
- """
- Use VM details to retrieve container and blob name.
- Then Create blob service client for sas token to
- retrieve console log.
-
- :return: blob service, container name, blob name
- """
- LOG.debug('creating blob service for console log')
- storage = self.platform.storage_client.storage_accounts.get_properties(
- self.platform.resource_group.name, self.platform.storage.name)
-
- keys = self.platform.storage_client.storage_accounts.list_keys(
- self.platform.resource_group.name, self.platform.storage.name
- ).keys[0].value
-
- virtual_machine = self.platform.compute_client.virtual_machines.get(
- self.platform.resource_group.name, self.instance.name,
- expand='instanceView')
-
- blob_uri = virtual_machine.instance_view.boot_diagnostics.\
- serial_console_log_blob_uri
-
- container, blob = urlparse(blob_uri).path.split('/')[-2:]
-
- blob_client = BlockBlobService(
- account_name=storage.name,
- account_key=keys)
-
- sas = blob_client.generate_blob_shared_access_signature(
- container_name=container, blob_name=blob, protocol='https',
- expiry=datetime.utcnow() + timedelta(hours=1),
- permission=BlobPermissions.READ)
-
- blob_client = BlockBlobService(
- account_name=storage.name,
- sas_token=sas)
-
- return blob_client, container, blob
-
- def console_log(self):
- """Instance console.
-
- @return_value: bytes of this instance’s console
- """
- boot_diagnostics = self.blob_client.get_blob_to_bytes(
- self.container, self.blob)
- return boot_diagnostics.content
diff --git a/tests/cloud_tests/platforms/azurecloud/platform.py b/tests/cloud_tests/platforms/azurecloud/platform.py
deleted file mode 100644
index a664f612..00000000
--- a/tests/cloud_tests/platforms/azurecloud/platform.py
+++ /dev/null
@@ -1,240 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud class."""
-
-import os
-import base64
-import traceback
-from datetime import datetime
-from tests.cloud_tests import LOG
-
-# pylint: disable=no-name-in-module
-from azure.common.credentials import ServicePrincipalCredentials
-# pylint: disable=no-name-in-module
-from azure.mgmt.resource import ResourceManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.network import NetworkManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.compute import ComputeManagementClient
-# pylint: disable=no-name-in-module
-from azure.mgmt.storage import StorageManagementClient
-from msrestazure.azure_exceptions import CloudError
-
-from .image import AzureCloudImage
-from .instance import AzureCloudInstance
-from ..platforms import Platform
-
-from cloudinit import util as c_util
-
-
-class AzureCloudPlatform(Platform):
- """Azure Cloud test platforms."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, config):
- """Set up platform."""
- super(AzureCloudPlatform, self).__init__(config)
- self.tag = '%s-%s' % (
- config['tag'], datetime.now().strftime('%Y%m%d%H%M%S'))
- self.storage_sku = config['storage_sku']
- self.vm_size = config['vm_size']
- self.location = config['region']
-
- try:
- self.credentials, self.subscription_id = self._get_credentials()
-
- self.resource_client = ResourceManagementClient(
- self.credentials, self.subscription_id)
- self.compute_client = ComputeManagementClient(
- self.credentials, self.subscription_id)
- self.network_client = NetworkManagementClient(
- self.credentials, self.subscription_id)
- self.storage_client = StorageManagementClient(
- self.credentials, self.subscription_id)
-
- self.resource_group = self._create_resource_group()
- self.public_ip = self._create_public_ip_address()
- self.storage = self._create_storage_account(config)
- self.vnet = self._create_vnet()
- self.subnet = self._create_subnet()
- self.nic = self._create_nic()
- except CloudError as e:
- raise RuntimeError(
- 'failed creating a resource:\n{}'.format(
- traceback.format_exc()
- )
- ) from e
-
- def create_instance(self, properties, config, features,
- image_id, user_data=None):
- """Create an instance
-
- @param properties: image properties
- @param config: image configuration
- @param features: image features
- @param image_id: string of image id
- @param user_data: test user-data to pass to instance
- @return_value: cloud_tests.instances instance
- """
- if user_data is not None:
- user_data = str(base64.b64encode(
- user_data.encode('utf-8')), 'utf-8')
-
- return AzureCloudInstance(self, properties, config, features,
- image_id, user_data)
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- ss_region = self.azure_location_to_simplestreams_region()
-
- filters = [
- 'arch=%s' % 'amd64',
- 'endpoint=https://management.core.windows.net/',
- 'region=%s' % ss_region,
- 'release=%s' % img_conf['release']
- ]
-
- LOG.debug('finding image using streams')
- image = self._query_streams(img_conf, filters)
-
- try:
- image_id = image['id']
- LOG.debug('found image: %s', image_id)
- if image_id.find('__') > 0:
- image_id = image_id.split('__')[1]
- LOG.debug('image_id shortened to %s', image_id)
- except KeyError as e:
- raise RuntimeError(
- 'no images found for %s' % img_conf['release']
- ) from e
-
- return AzureCloudImage(self, img_conf, image_id)
-
- def destroy(self):
- """Delete all resources in resource group."""
- LOG.debug("Deleting resource group: %s", self.resource_group.name)
- delete = self.resource_client.resource_groups.delete(
- self.resource_group.name)
- delete.wait()
-
- def azure_location_to_simplestreams_region(self):
- """Convert location to simplestreams region"""
- location = self.location.lower().replace(' ', '')
- LOG.debug('finding location %s using simple streams', location)
- regions_file = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), 'regions.json')
- region_simplestreams_map = c_util.load_json(
- c_util.load_file(regions_file))
- return region_simplestreams_map.get(location, location)
-
- def _get_credentials(self):
- """Get credentials from environment"""
- LOG.debug('getting credentials from environment')
- cred_file = os.path.expanduser('~/.azure/credentials.json')
- try:
- azure_creds = c_util.load_json(
- c_util.load_file(cred_file))
- subscription_id = azure_creds['subscriptionId']
- credentials = ServicePrincipalCredentials(
- client_id=azure_creds['clientId'],
- secret=azure_creds['clientSecret'],
- tenant=azure_creds['tenantId'])
- return credentials, subscription_id
- except KeyError as e:
- raise RuntimeError(
- 'Please configure Azure service principal'
- ' credentials in %s' % cred_file
- ) from e
-
- def _create_resource_group(self):
- """Create resource group"""
- LOG.debug('creating resource group')
- resource_group_name = self.tag
- resource_group_params = {
- 'location': self.location
- }
- resource_group = self.resource_client.resource_groups.create_or_update(
- resource_group_name, resource_group_params)
- return resource_group
-
- def _create_storage_account(self, config):
- LOG.debug('creating storage account')
- storage_account_name = 'storage%s' % datetime.now().\
- strftime('%Y%m%d%H%M%S')
- storage_params = {
- 'sku': {
- 'name': config['storage_sku']
- },
- 'kind': "Storage",
- 'location': self.location
- }
- storage_account = self.storage_client.storage_accounts.create(
- self.resource_group.name, storage_account_name, storage_params)
- return storage_account.result()
-
- def _create_public_ip_address(self):
- """Create public ip address"""
- LOG.debug('creating public ip address')
- public_ip_name = '%s-ip' % self.resource_group.name
- public_ip_params = {
- 'location': self.location,
- 'public_ip_allocation_method': 'Dynamic'
- }
- ip = self.network_client.public_ip_addresses.create_or_update(
- self.resource_group.name, public_ip_name, public_ip_params)
- return ip.result()
-
- def _create_vnet(self):
- """create virtual network"""
- LOG.debug('creating vnet')
- vnet_name = '%s-vnet' % self.resource_group.name
- vnet_params = {
- 'location': self.location,
- 'address_space': {
- 'address_prefixes': ['10.0.0.0/16']
- }
- }
- vnet = self.network_client.virtual_networks.create_or_update(
- self.resource_group.name, vnet_name, vnet_params)
- return vnet.result()
-
- def _create_subnet(self):
- """create sub-network"""
- LOG.debug('creating subnet')
- subnet_name = '%s-subnet' % self.resource_group.name
- subnet_params = {
- 'address_prefix': '10.0.0.0/24'
- }
- subnet = self.network_client.subnets.create_or_update(
- self.resource_group.name, self.vnet.name,
- subnet_name, subnet_params)
- return subnet.result()
-
- def _create_nic(self):
- """Create network interface controller"""
- LOG.debug('creating nic')
- nic_name = '%s-nic' % self.resource_group.name
- nic_params = {
- 'location': self.location,
- 'ip_configurations': [{
- 'name': 'ipconfig',
- 'subnet': {
- 'id': self.subnet.id
- },
- 'publicIpAddress': {
- 'id': "/subscriptions/%s"
- "/resourceGroups/%s/providers/Microsoft.Network"
- "/publicIPAddresses/%s" % (
- self.subscription_id, self.resource_group.name,
- self.public_ip.name),
- }
- }]
- }
- nic = self.network_client.network_interfaces.create_or_update(
- self.resource_group.name, nic_name, nic_params)
- return nic.result()
diff --git a/tests/cloud_tests/platforms/azurecloud/regions.json b/tests/cloud_tests/platforms/azurecloud/regions.json
deleted file mode 100644
index c1b4da20..00000000
--- a/tests/cloud_tests/platforms/azurecloud/regions.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "eastasia": "East Asia",
- "southeastasia": "Southeast Asia",
- "centralus": "Central US",
- "eastus": "East US",
- "eastus2": "East US 2",
- "westus": "West US",
- "northcentralus": "North Central US",
- "southcentralus": "South Central US",
- "northeurope": "North Europe",
- "westeurope": "West Europe",
- "japanwest": "Japan West",
- "japaneast": "Japan East",
- "brazilsouth": "Brazil South",
- "australiaeast": "Australia East",
- "australiasoutheast": "Australia Southeast",
- "southindia": "South India",
- "centralindia": "Central India",
- "westindia": "West India",
- "canadacentral": "Canada Central",
- "canadaeast": "Canada East",
- "uksouth": "UK South",
- "ukwest": "UK West",
- "westcentralus": "West Central US",
- "westus2": "West US 2",
- "koreacentral": "Korea Central",
- "koreasouth": "Korea South",
- "francecentral": "France Central",
- "francesouth": "France South",
- "australiacentral": "Australia Central",
- "australiacentral2": "Australia Central 2",
- "uaecentral": "UAE Central",
- "uaenorth": "UAE North",
- "southafricanorth": "South Africa North",
- "southafricawest": "South Africa West",
- "switzerlandnorth": "Switzerland North",
- "switzerlandwest": "Switzerland West",
- "germanynorth": "Germany North",
- "germanywestcentral": "Germany West Central",
- "norwaywest": "Norway West",
- "norwayeast": "Norway East"
-}
diff --git a/tests/cloud_tests/platforms/azurecloud/snapshot.py b/tests/cloud_tests/platforms/azurecloud/snapshot.py
deleted file mode 100644
index 580cc596..00000000
--- a/tests/cloud_tests/platforms/azurecloud/snapshot.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base Azure Cloud snapshot."""
-
-from ..snapshots import Snapshot
-
-from tests.cloud_tests import LOG
-
-
-class AzureCloudSnapshot(Snapshot):
- """Azure Cloud image copy backed snapshot."""
-
- platform_name = 'azurecloud'
-
- def __init__(self, platform, properties, config, features, image_id,
- delete_on_destroy=True):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- super(AzureCloudSnapshot, self).__init__(
- platform, properties, config, features)
-
- self.image_id = image_id
- self.delete_on_destroy = delete_on_destroy
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param meta_data: meta_data for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: description of snapshot instance use
- @return_value: an Instance
- """
- if meta_data is not None:
- raise ValueError("metadata not supported on Azure Cloud tests")
-
- instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_id, user_data)
-
- return instance
-
- def destroy(self):
- """Clean up snapshot data."""
- LOG.debug('destroying image %s', self.image_id)
- if self.delete_on_destroy:
- self.platform.compute_client.images.delete(
- self.platform.resource_group.name,
- self.image_id)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/ec2/__init__.py b/tests/cloud_tests/platforms/ec2/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/tests/cloud_tests/platforms/ec2/__init__.py
+++ /dev/null
diff --git a/tests/cloud_tests/platforms/ec2/image.py b/tests/cloud_tests/platforms/ec2/image.py
deleted file mode 100644
index d7b2c908..00000000
--- a/tests/cloud_tests/platforms/ec2/image.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""EC2 Image Base Class."""
-
-from ..images import Image
-from .snapshot import EC2Snapshot
-
-from tests.cloud_tests import LOG
-
-
-class EC2Image(Image):
- """EC2 backed image."""
-
- platform_name = 'ec2'
-
- def __init__(self, platform, config, image_ami):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- @param image_ami: string of image ami ID
- """
- super(EC2Image, self).__init__(platform, config)
- self._img_instance = None
- self.image_ami = image_ami
-
- @property
- def _instance(self):
- """Internal use only, returns a running instance"""
- if not self._img_instance:
- self._img_instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_ami, user_data=None)
- self._img_instance.start(wait=True, wait_for_cloud_init=True)
- return self._img_instance
-
- def destroy(self):
- """Delete the instance used to create a custom image."""
- if self._img_instance:
- LOG.debug('terminating backing instance %s',
- self._img_instance.instance.instance_id)
- self._img_instance.instance.terminate()
- self._img_instance.instance.wait_until_terminated()
-
- super(EC2Image, self).destroy()
-
- def _execute(self, *args, **kwargs):
- """Execute command in image, modifying image."""
- self._instance.start(wait=True)
- return self._instance._execute(*args, **kwargs)
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'."""
- self._instance.start(wait=True)
- return self._instance.push_file(local_path, remote_path)
-
- def run_script(self, *args, **kwargs):
- """Run script in image, modifying image.
-
- @return_value: script output
- """
- self._instance.start(wait=True)
- return self._instance.run_script(*args, **kwargs)
-
- def snapshot(self):
- """Create snapshot of image, block until done.
-
- Will return base image_ami if no instance has been booted, otherwise
- will run the clean script, shutdown the instance, create a custom
- AMI, and use that AMI once available.
- """
- if not self._img_instance:
- return EC2Snapshot(self.platform, self.properties, self.config,
- self.features, self.image_ami,
- delete_on_destroy=False)
-
- if self.config.get('boot_clean_script'):
- self._img_instance.run_script(self.config.get('boot_clean_script'))
-
- self._img_instance.shutdown(wait=True)
-
- LOG.debug('creating custom ami from instance %s',
- self._img_instance.instance.instance_id)
- response = self.platform.ec2_client.create_image(
- Name='%s-%s' % (self.platform.tag, self.image_ami),
- InstanceId=self._img_instance.instance.instance_id
- )
- image_ami_edited = response['ImageId']
-
- # Create image and wait until it is in the 'available' state
- image = self.platform.ec2_resource.Image(image_ami_edited)
- image.wait_until_exists()
- waiter = self.platform.ec2_client.get_waiter('image_available')
- waiter.wait(ImageIds=[image.id])
- image.reload()
-
- return EC2Snapshot(self.platform, self.properties, self.config,
- self.features, image_ami_edited)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/ec2/instance.py b/tests/cloud_tests/platforms/ec2/instance.py
deleted file mode 100644
index d2e84047..00000000
--- a/tests/cloud_tests/platforms/ec2/instance.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base EC2 instance."""
-import os
-
-import botocore
-
-from ..instances import Instance
-from tests.cloud_tests import LOG, util
-
-
-class EC2Instance(Instance):
- """EC2 backed instance."""
-
- platform_name = "ec2"
- _ssh_client = None
-
- def __init__(self, platform, properties, config, features,
- image_ami, user_data=None):
- """Set up instance.
-
- @param platform: platform object
- @param properties: dictionary of properties
- @param config: dictionary of configuration values
- @param features: dictionary of supported feature flags
- @param image_ami: AWS AMI ID for image to use
- @param user_data: test user-data to pass to instance
- """
- super(EC2Instance, self).__init__(
- platform, image_ami, properties, config, features)
-
- self.image_ami = image_ami
- self.instance = None
- self.user_data = user_data
- self.ssh_ip = None
- self.ssh_port = 22
- self.ssh_key_file = os.path.join(
- platform.config['data_dir'], platform.config['private_key'])
- self.ssh_pubkey_file = os.path.join(
- platform.config['data_dir'], platform.config['public_key'])
-
- def console_log(self):
- """Collect console log from instance.
-
- The console log is buffered and not always present, therefore
- may return empty string.
- """
- try:
- # OutputBytes comes from platform._decode_console_output_as_bytes
- response = self.instance.console_output()
- return response['OutputBytes']
- except KeyError as e:
- if 'Output' in response:
- msg = ("'OutputBytes' did not exist in console_output() but "
- "'Output' did: %s..." % response['Output'][0:128])
- raise util.PlatformError('console_log', msg) from e
- return ('No Console Output [%s]' % self.instance).encode()
-
- def destroy(self):
- """Clean up instance."""
- if self.instance:
- LOG.debug('destroying instance %s', self.instance.id)
- self.instance.terminate()
- self.instance.wait_until_terminated()
-
- self._ssh_close()
-
- super(EC2Instance, self).destroy()
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command on instance."""
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- return self._ssh(['sudo'] + env_args + list(command), stdin=stdin)
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance on EC2 with the platfrom's VPC."""
- if self.instance:
- if self.instance.state['Name'] == 'running':
- return
-
- LOG.debug('starting instance %s', self.instance.id)
- self.instance.start()
- else:
- LOG.debug('launching instance')
-
- args = {
- 'ImageId': self.image_ami,
- 'InstanceType': self.platform.instance_type,
- 'KeyName': self.platform.key_name,
- 'MaxCount': 1,
- 'MinCount': 1,
- 'SecurityGroupIds': [self.platform.security_group.id],
- 'SubnetId': self.platform.subnet.id,
- 'TagSpecifications': [{
- 'ResourceType': 'instance',
- 'Tags': [{
- 'Key': 'Name', 'Value': self.platform.tag
- }]
- }],
- }
-
- if self.user_data:
- args['UserData'] = self.user_data
-
- try:
- instances = self.platform.ec2_resource.create_instances(**args)
- except botocore.exceptions.ClientError as error:
- error_msg = error.response['Error']['Message']
- raise util.PlatformError('start', error_msg)
-
- self.instance = instances[0]
-
- LOG.debug('instance id: %s', self.instance.id)
- if wait:
- self.instance.wait_until_running()
- self.instance.reload()
- self.ssh_ip = self.instance.public_ip_address
- self._wait_for_system(wait_for_cloud_init)
-
- def shutdown(self, wait=True):
- """Shutdown instance."""
- LOG.debug('stopping instance %s', self.instance.id)
- self.instance.stop()
-
- if wait:
- self.instance.wait_until_stopped()
- self.instance.reload()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/ec2/platform.py b/tests/cloud_tests/platforms/ec2/platform.py
deleted file mode 100644
index b61a2ffb..00000000
--- a/tests/cloud_tests/platforms/ec2/platform.py
+++ /dev/null
@@ -1,263 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base EC2 platform."""
-from datetime import datetime
-import os
-
-import boto3
-import botocore
-from botocore import session, handlers
-import base64
-
-from ..platforms import Platform
-from .image import EC2Image
-from .instance import EC2Instance
-from tests.cloud_tests import LOG
-
-
-class EC2Platform(Platform):
- """EC2 test platform."""
-
- platform_name = 'ec2'
- ipv4_cidr = '192.168.1.0/20'
-
- def __init__(self, config):
- """Set up platform."""
- super(EC2Platform, self).__init__(config)
- # Used for unique VPC, SSH key, and custom AMI generation naming
- self.tag = '%s-%s' % (
- config['tag'], datetime.now().strftime('%Y%m%d%H%M%S'))
- self.instance_type = config['instance-type']
-
- try:
- b3session = get_session()
- self.ec2_client = b3session.client('ec2')
- self.ec2_resource = b3session.resource('ec2')
- self.ec2_region = b3session.region_name
- self.key_name = self._upload_public_key(config)
- except botocore.exceptions.NoRegionError as e:
- raise RuntimeError(
- 'Please configure default region in $HOME/.aws/config'
- ) from e
- except botocore.exceptions.NoCredentialsError as e:
- raise RuntimeError(
- 'Please configure ec2 credentials in $HOME/.aws/credentials'
- ) from e
-
- self.vpc = self._create_vpc()
- self.internet_gateway = self._create_internet_gateway()
- self.subnet = self._create_subnet()
- self.routing_table = self._create_routing_table()
- self.security_group = self._create_security_group()
-
- def create_instance(self, properties, config, features,
- image_ami, user_data=None):
- """Create an instance
-
- @param src_img_path: image path to launch from
- @param properties: image properties
- @param config: image configuration
- @param features: image features
- @param image_ami: string of image ami ID
- @param user_data: test user-data to pass to instance
- @return_value: cloud_tests.instances instance
- """
- return EC2Instance(self, properties, config, features,
- image_ami, user_data)
-
- def destroy(self):
- """Delete SSH keys, terminate all instances, and delete VPC."""
- for instance in self.vpc.instances.all():
- LOG.debug('waiting for instance %s termination', instance.id)
- instance.terminate()
- instance.wait_until_terminated()
-
- if self.key_name:
- LOG.debug('deleting SSH key %s', self.key_name)
- self.ec2_client.delete_key_pair(KeyName=self.key_name)
-
- if self.security_group:
- LOG.debug('deleting security group %s', self.security_group.id)
- self.security_group.delete()
-
- if self.subnet:
- LOG.debug('deleting subnet %s', self.subnet.id)
- self.subnet.delete()
-
- if self.routing_table:
- LOG.debug('deleting routing table %s', self.routing_table.id)
- self.routing_table.delete()
-
- if self.internet_gateway:
- LOG.debug('deleting internet gateway %s', self.internet_gateway.id)
- self.internet_gateway.detach_from_vpc(VpcId=self.vpc.id)
- self.internet_gateway.delete()
-
- if self.vpc:
- LOG.debug('deleting vpc %s', self.vpc.id)
- self.vpc.delete()
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- Hard coded for 'amd64' based images.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- if img_conf['root-store'] == 'ebs':
- root_store = 'ssd'
- elif img_conf['root-store'] == 'instance-store':
- root_store = 'instance'
- else:
- raise RuntimeError('Unknown root-store type: %s' %
- (img_conf['root-store']))
-
- filters = [
- 'arch=%s' % 'amd64',
- 'endpoint=https://ec2.%s.amazonaws.com' % self.ec2_region,
- 'region=%s' % self.ec2_region,
- 'release=%s' % img_conf['release'],
- 'root_store=%s' % root_store,
- 'virt=hvm',
- ]
-
- LOG.debug('finding image using streams')
- image = self._query_streams(img_conf, filters)
-
- try:
- image_ami = image['id']
- except KeyError as e:
- raise RuntimeError(
- 'No images found for %s!' % img_conf['release']
- ) from e
-
- LOG.debug('found image: %s', image_ami)
- image = EC2Image(self, img_conf, image_ami)
- return image
-
- def _create_internet_gateway(self):
- """Create Internet Gateway and assign to VPC."""
- LOG.debug('creating internet gateway')
- # pylint: disable=no-member
- internet_gateway = self.ec2_resource.create_internet_gateway()
- internet_gateway.attach_to_vpc(VpcId=self.vpc.id)
- self._tag_resource(internet_gateway)
-
- return internet_gateway
-
- def _create_routing_table(self):
- """Update default routing table with internet gateway.
-
- This sets up internet access between the VPC via the internet gateway
- by configuring routing tables for IPv4 and IPv6.
- """
- LOG.debug('creating routing table')
- route_table = self.vpc.create_route_table()
- route_table.create_route(DestinationCidrBlock='0.0.0.0/0',
- GatewayId=self.internet_gateway.id)
- route_table.create_route(DestinationIpv6CidrBlock='::/0',
- GatewayId=self.internet_gateway.id)
- route_table.associate_with_subnet(SubnetId=self.subnet.id)
- self._tag_resource(route_table)
-
- return route_table
-
- def _create_security_group(self):
- """Enables ingress to default VPC security group."""
- LOG.debug('creating security group')
- security_group = self.vpc.create_security_group(
- GroupName=self.tag, Description='integration test security group')
- security_group.authorize_ingress(
- IpProtocol='-1', FromPort=-1, ToPort=-1, CidrIp='0.0.0.0/0')
- self._tag_resource(security_group)
-
- return security_group
-
- def _create_subnet(self):
- """Generate IPv4 and IPv6 subnets for use."""
- ipv6_cidr = self.vpc.ipv6_cidr_block_association_set[0][
- 'Ipv6CidrBlock'][:-2] + '64'
-
- LOG.debug('creating subnet with following ranges:')
- LOG.debug('ipv4: %s', self.ipv4_cidr)
- LOG.debug('ipv6: %s', ipv6_cidr)
- subnet = self.vpc.create_subnet(CidrBlock=self.ipv4_cidr,
- Ipv6CidrBlock=ipv6_cidr)
- modify_subnet = subnet.meta.client.modify_subnet_attribute
- modify_subnet(SubnetId=subnet.id,
- MapPublicIpOnLaunch={'Value': True})
- self._tag_resource(subnet)
-
- return subnet
-
- def _create_vpc(self):
- """Setup AWS EC2 VPC or return existing VPC."""
- LOG.debug('creating new vpc')
- try:
- vpc = self.ec2_resource.create_vpc( # pylint: disable=no-member
- CidrBlock=self.ipv4_cidr,
- AmazonProvidedIpv6CidrBlock=True)
- except botocore.exceptions.ClientError as e:
- raise RuntimeError(e) from e
-
- vpc.wait_until_available()
- self._tag_resource(vpc)
-
- return vpc
-
- def _tag_resource(self, resource):
- """Tag a resource with the specified tag.
-
- This makes finding and deleting resources specific to this testing
- much easier to find.
-
- @param resource: resource to tag
- """
- tag = {
- 'Key': 'Name',
- 'Value': self.tag
- }
- resource.create_tags(Tags=[tag])
-
- def _upload_public_key(self, config):
- """Generate random name and upload SSH key with that name.
-
- @param config: platform config
- @return: string of ssh key name
- """
- key_file = os.path.join(config['data_dir'], config['public_key'])
- with open(key_file, 'r') as file:
- public_key = file.read().strip('\n')
-
- LOG.debug('uploading SSH key %s', self.tag)
- self.ec2_client.import_key_pair(KeyName=self.tag,
- PublicKeyMaterial=public_key)
-
- return self.tag
-
-
-def _decode_console_output_as_bytes(parsed, **kwargs):
- """Provide console output as bytes in OutputBytes.
-
- For this to be useful, the session has to have had the
- decode_console_output handler unregistered already.
-
- https://github.com/boto/botocore/issues/1351 ."""
- if 'Output' not in parsed:
- return
- orig = parsed['Output']
- handlers.decode_console_output(parsed, **kwargs)
- parsed['OutputBytes'] = base64.b64decode(orig)
-
-
-def get_session():
- mysess = session.get_session()
- mysess.unregister('after-call.ec2.GetConsoleOutput',
- handlers.decode_console_output)
- mysess.register('after-call.ec2.GetConsoleOutput',
- _decode_console_output_as_bytes)
- return boto3.Session(botocore_session=mysess)
-
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/ec2/snapshot.py b/tests/cloud_tests/platforms/ec2/snapshot.py
deleted file mode 100644
index 2c48cb54..00000000
--- a/tests/cloud_tests/platforms/ec2/snapshot.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base EC2 snapshot."""
-
-from ..snapshots import Snapshot
-from tests.cloud_tests import LOG
-
-
-class EC2Snapshot(Snapshot):
- """EC2 image copy backed snapshot."""
-
- platform_name = 'ec2'
-
- def __init__(self, platform, properties, config, features, image_ami,
- delete_on_destroy=True):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- @param image_ami: string of image ami ID
- @param delete_on_destroy: boolean to delete on destroy
- """
- super(EC2Snapshot, self).__init__(
- platform, properties, config, features)
-
- self.image_ami = image_ami
- self.delete_on_destroy = delete_on_destroy
-
- def destroy(self):
- """Deregister the backing AMI."""
- if self.delete_on_destroy:
- image = self.platform.ec2_resource.Image(self.image_ami)
- snapshot_id = image.block_device_mappings[0]['Ebs']['SnapshotId']
-
- LOG.debug('removing custom ami %s', self.image_ami)
- self.platform.ec2_client.deregister_image(ImageId=self.image_ami)
-
- LOG.debug('removing custom snapshot %s', snapshot_id)
- self.platform.ec2_client.delete_snapshot(SnapshotId=snapshot_id)
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param meta_data: meta_data for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: string of test name
- @return_value: an Instance
- """
- if meta_data is not None:
- raise ValueError("metadata not supported on Ec2")
-
- instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self.image_ami, user_data)
-
- if start:
- instance.start()
-
- return instance
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/images.py b/tests/cloud_tests/platforms/images.py
deleted file mode 100644
index f047de2e..00000000
--- a/tests/cloud_tests/platforms/images.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base class for images."""
-
-from ..util import TargetBase
-
-
-class Image(TargetBase):
- """Base class for images."""
-
- platform_name = None
-
- def __init__(self, platform, config):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- """
- self.platform = platform
- self.config = config
-
- def __str__(self):
- """A brief description of the image."""
- return '-'.join((self.properties['os'], self.properties['release']))
-
- @property
- def properties(self):
- """{} containing: 'arch', 'os', 'version', 'release'."""
- return {k: self.config[k]
- for k in ('arch', 'os', 'release', 'version')}
-
- @property
- def features(self):
- """Feature flags supported by this image.
-
- @return_value: list of feature names
- """
- return [k for k, v in self.config.get('features', {}).items() if v]
-
- @property
- def setup_overrides(self):
- """Setup options that need to be overridden for the image.
-
- @return_value: dictionary to update args with
- """
- # NOTE: more sophisticated options may be requied at some point
- return self.config.get('setup_overrides', {})
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- raise NotImplementedError
-
- def destroy(self):
- """Clean up data associated with image."""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/instances.py b/tests/cloud_tests/platforms/instances.py
deleted file mode 100644
index efc35c7f..00000000
--- a/tests/cloud_tests/platforms/instances.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base instance."""
-import time
-
-import paramiko
-from paramiko.ssh_exception import (
- BadHostKeyException, AuthenticationException, SSHException)
-
-from ..util import TargetBase
-from tests.cloud_tests import LOG, util
-
-
-class Instance(TargetBase):
- """Base instance object."""
-
- platform_name = None
- _ssh_client = None
-
- def __init__(self, platform, name, properties, config, features):
- """Set up instance.
-
- @param platform: platform object
- @param name: hostname of instance
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- self.platform = platform
- self.name = name
- self.properties = properties
- self.config = config
- self.features = features
- self._tmp_count = 0
-
- self.ssh_ip = None
- self.ssh_port = None
- self.ssh_key_file = None
- self.ssh_username = 'ubuntu'
-
- def console_log(self):
- """Instance console.
-
- @return_value: bytes of this instance’s console
- """
- raise NotImplementedError
-
- def reboot(self, wait=True):
- """Reboot instance."""
- raise NotImplementedError
-
- def shutdown(self, wait=True):
- """Shutdown instance."""
- raise NotImplementedError
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance."""
- raise NotImplementedError
-
- def destroy(self):
- """Clean up instance."""
- self._ssh_close()
-
- def _ssh(self, command, stdin=None):
- """Run a command via SSH."""
- client = self._ssh_connect()
-
- cmd = util.shell_pack(command)
- fp_in, fp_out, fp_err = client.exec_command(cmd)
- channel = fp_in.channel
-
- if stdin is not None:
- fp_in.write(stdin)
- fp_in.close()
-
- channel.shutdown_write()
- rc = channel.recv_exit_status()
-
- return (fp_out.read(), fp_err.read(), rc)
-
- def _ssh_close(self):
- if self._ssh_client:
- try:
- self._ssh_client.close()
- except SSHException:
- LOG.warning('Failed to close SSH connection.')
- self._ssh_client = None
-
- def _ssh_connect(self):
- """Connect via SSH.
-
- Attempt to SSH to the client on the specific IP and port. If it
- fails in some manner, then retry 2 more times for a total of 3
- attempts; sleeping a few seconds between attempts.
- """
- if self._ssh_client:
- return self._ssh_client
-
- if not self.ssh_ip or not self.ssh_port:
- raise ValueError("Cannot ssh_connect, ssh_ip=%s ssh_port=%s" %
- (self.ssh_ip, self.ssh_port))
-
- client = paramiko.SSHClient()
- client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- private_key = paramiko.RSAKey.from_private_key_file(self.ssh_key_file)
-
- retries = 3
- while retries:
- try:
- client.connect(username=self.ssh_username,
- hostname=self.ssh_ip, port=self.ssh_port,
- pkey=private_key)
- self._ssh_client = client
- return client
- except (ConnectionRefusedError, AuthenticationException,
- BadHostKeyException, ConnectionResetError, SSHException,
- OSError):
- retries -= 1
- LOG.debug('Retrying ssh connection on connect failure')
- time.sleep(3)
-
- ssh_cmd = 'Failed ssh connection to %s@%s:%s after 3 retries' % (
- self.ssh_username, self.ssh_ip, self.ssh_port
- )
- raise util.InTargetExecuteError(b'', b'', 1, ssh_cmd, 'ssh')
-
- def _wait_for_system(self, wait_for_cloud_init):
- """Wait until system has fully booted and cloud-init has finished.
-
- @param wait_time: maximum time to wait
- @return_value: None, may raise OSError if wait_time exceeded
- """
- def clean_test(test):
- """Clean formatting for system ready test testcase."""
- return ' '.join(line for line in test.strip().splitlines()
- if not line.lstrip().startswith('#'))
-
- boot_timeout = self.config['boot_timeout']
- tests = [self.config['system_ready_script']]
- if wait_for_cloud_init:
- tests.append(self.config['cloud_init_ready_script'])
-
- formatted_tests = ' && '.join(clean_test(t) for t in tests)
- cmd = ('i=0; while [ $i -lt {time} ] && i=$(($i+1)); do {test} && '
- 'exit 0; sleep 1; done; exit 1').format(time=boot_timeout,
- test=formatted_tests)
-
- end_time = time.time() + boot_timeout
- while True:
- try:
- return_code = self.execute(
- cmd, rcs=(0, 1), description='wait for instance start'
- )[-1]
- if return_code == 0:
- break
- except util.InTargetExecuteError:
- LOG.warning("failed to connect via SSH")
-
- if time.time() < end_time:
- time.sleep(3)
- else:
- raise util.PlatformError('ssh', 'after %ss instance is not '
- 'reachable' % boot_timeout)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/lxd/__init__.py b/tests/cloud_tests/platforms/lxd/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/tests/cloud_tests/platforms/lxd/__init__.py
+++ /dev/null
diff --git a/tests/cloud_tests/platforms/lxd/image.py b/tests/cloud_tests/platforms/lxd/image.py
deleted file mode 100644
index a88b47f3..00000000
--- a/tests/cloud_tests/platforms/lxd/image.py
+++ /dev/null
@@ -1,211 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""LXD Image Base Class."""
-
-import os
-import shutil
-import tempfile
-
-from ..images import Image
-from .snapshot import LXDSnapshot
-from cloudinit import subp
-from cloudinit import util as c_util
-from tests.cloud_tests import util
-
-
-class LXDImage(Image):
- """LXD backed image."""
-
- platform_name = "lxd"
-
- def __init__(self, platform, config, pylxd_image):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- """
- self.modified = False
- self._img_instance = None
- self._pylxd_image = None
- self.pylxd_image = pylxd_image
- super(LXDImage, self).__init__(platform, config)
-
- @property
- def pylxd_image(self):
- """Property function."""
- if self._pylxd_image:
- self._pylxd_image.sync()
- return self._pylxd_image
-
- @pylxd_image.setter
- def pylxd_image(self, pylxd_image):
- if self._img_instance:
- self._instance.destroy()
- self._img_instance = None
- if (self._pylxd_image and
- (self._pylxd_image is not pylxd_image) and
- (not self.config.get('cache_base_image') or self.modified)):
- self._pylxd_image.delete(wait=True)
- self.modified = False
- self._pylxd_image = pylxd_image
-
- @property
- def _instance(self):
- """Internal use only, returns a instance
-
- This starts an lxc instance from the image, so it is "dirty".
- Better would be some way to modify this "at rest".
- lxc-pstart would be an option."""
- if not self._img_instance:
- self._img_instance = self.platform.launch_container(
- self.properties, self.config, self.features,
- use_desc='image-modification', image_desc=str(self),
- image=self.pylxd_image.fingerprint)
- self._img_instance.start()
- return self._img_instance
-
- @property
- def properties(self):
- """{} containing: 'arch', 'os', 'version', 'release'."""
- properties = self.pylxd_image.properties
- return {
- 'arch': properties.get('architecture'),
- 'os': properties.get('os'),
- 'version': properties.get('version'),
- 'release': properties.get('release'),
- }
-
- def export_image(self, output_dir):
- """Export image from lxd image store to disk.
-
- @param output_dir: dir to store the exported image in
- @return_value: tuple of path to metadata tarball and rootfs
-
- Only the "split" image format with separate rootfs and metadata
- files is supported, e.g:
-
- 71f171df[...]cd31.squashfs (could also be: .tar.xz or .tar.gz)
- meta-71f171df[...]cd31.tar.xz
-
- Combined images made by a single tarball are not supported.
- """
- # pylxd's image export feature doesn't do split exports, so use cmdline
- fp = self.pylxd_image.fingerprint
- subp.subp(['lxc', 'image', 'export', fp, output_dir], capture=True)
- image_files = [p for p in os.listdir(output_dir) if fp in p]
-
- if len(image_files) != 2:
- raise NotImplementedError(
- "Image %s has unsupported format. "
- "Expected 2 files, found %d: %s."
- % (fp, len(image_files), ', '.join(image_files)))
-
- metadata = os.path.join(
- output_dir,
- next(p for p in image_files if p.startswith('meta-')))
- rootfs = os.path.join(
- output_dir,
- next(p for p in image_files if not p.startswith('meta-')))
- return (metadata, rootfs)
-
- def import_image(self, metadata, rootfs):
- """Import image to lxd image store from (split) tarball on disk.
-
- Note, this will replace and delete the current pylxd_image
-
- @param metadata: metadata tarball
- @param rootfs: rootfs tarball
- @return_value: imported image fingerprint
- """
- alias = util.gen_instance_name(
- image_desc=str(self), use_desc='update-metadata')
- subp.subp(['lxc', 'image', 'import', metadata, rootfs,
- '--alias', alias], capture=True)
- self.pylxd_image = self.platform.query_image_by_alias(alias)
- return self.pylxd_image.fingerprint
-
- def update_templates(self, template_config, template_data):
- """Update the image's template configuration.
-
- Note, this will replace and delete the current pylxd_image
-
- @param template_config: config overrides for template metadata
- @param template_data: template data to place into templates/
- """
- # set up tmp files
- export_dir = tempfile.mkdtemp(prefix='cloud_test_util_')
- extract_dir = tempfile.mkdtemp(prefix='cloud_test_util_')
- new_metadata = os.path.join(export_dir, 'new-meta.tar.xz')
- metadata_yaml = os.path.join(extract_dir, 'metadata.yaml')
- template_dir = os.path.join(extract_dir, 'templates')
-
- try:
- # extract old data
- (metadata, rootfs) = self.export_image(export_dir)
- shutil.unpack_archive(metadata, extract_dir)
-
- # update metadata
- metadata = c_util.read_conf(metadata_yaml)
- templates = metadata.get('templates', {})
- templates.update(template_config)
- metadata['templates'] = templates
- util.yaml_dump(metadata, metadata_yaml)
-
- # write out template files
- for name, content in template_data.items():
- path = os.path.join(template_dir, name)
- c_util.write_file(path, content)
-
- # store new data, mark new image as modified
- util.flat_tar(new_metadata, extract_dir)
- self.import_image(new_metadata, rootfs)
- self.modified = True
-
- finally:
- # remove tmpfiles
- shutil.rmtree(export_dir)
- shutil.rmtree(extract_dir)
-
- def _execute(self, *args, **kwargs):
- """Execute command in image, modifying image."""
- return self._instance._execute(*args, **kwargs)
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'."""
- return self._instance.push_file(local_path, remote_path)
-
- def run_script(self, *args, **kwargs):
- """Run script in image, modifying image.
-
- @return_value: script output
- """
- return self._instance.run_script(*args, **kwargs)
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- # get empty user data to pass in to instance
- # if overrides for user data provided, use them
- empty_userdata = util.update_user_data(
- {}, self.config.get('user_data_overrides', {}))
- conf = {'user.user-data': empty_userdata}
- # clone current instance
- instance = self.platform.launch_container(
- self.properties, self.config, self.features,
- container=self._instance.name, image_desc=str(self),
- use_desc='snapshot', container_config=conf)
- # wait for cloud-init before boot_clean_script is run to ensure
- # /var/lib/cloud is removed cleanly
- instance.start(wait=True, wait_for_cloud_init=True)
- if self.config.get('boot_clean_script'):
- instance.run_script(self.config.get('boot_clean_script'))
- # freeze current instance and return snapshot
- instance.freeze()
- return LXDSnapshot(self.platform, self.properties, self.config,
- self.features, instance)
-
- def destroy(self):
- """Clean up data associated with image."""
- self.pylxd_image = None
- super(LXDImage, self).destroy()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/lxd/instance.py b/tests/cloud_tests/platforms/lxd/instance.py
deleted file mode 100644
index 2b973a08..00000000
--- a/tests/cloud_tests/platforms/lxd/instance.py
+++ /dev/null
@@ -1,278 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base LXD instance."""
-
-import os
-import shutil
-import time
-from tempfile import mkdtemp
-
-from cloudinit.subp import subp, ProcessExecutionError, which
-from cloudinit.util import load_yaml
-from tests.cloud_tests import LOG
-from tests.cloud_tests.util import PlatformError
-
-from ..instances import Instance
-
-from pylxd import exceptions as pylxd_exc
-
-
-class LXDInstance(Instance):
- """LXD container backed instance."""
-
- platform_name = "lxd"
- _console_log_method = None
- _console_log_file = None
-
- def __init__(self, platform, name, properties, config, features,
- pylxd_container):
- """Set up instance.
-
- @param platform: platform object
- @param name: hostname of instance
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- if not pylxd_container:
- raise ValueError("Invalid value pylxd_container: %s" %
- pylxd_container)
- self._pylxd_container = pylxd_container
- super(LXDInstance, self).__init__(
- platform, name, properties, config, features)
- self.tmpd = mkdtemp(prefix="%s-%s" % (type(self).__name__, name))
- self.name = name
- self._setup_console_log()
-
- @property
- def pylxd_container(self):
- """Property function."""
- if self._pylxd_container is None:
- raise RuntimeError(
- "%s: Attempted use of pylxd_container after deletion." % self)
- self._pylxd_container.sync()
- return self._pylxd_container
-
- def __str__(self):
- return (
- '%s(name=%s) status=%s' %
- (self.__class__.__name__, self.name,
- ("deleted" if self._pylxd_container is None else
- self.pylxd_container.status)))
-
- def _execute(self, command, stdin=None, env=None):
- if env is None:
- env = {}
-
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- # ensure instance is running and execute the command
- self.start()
-
- # Use cmdline client due to https://github.com/lxc/pylxd/issues/268
- exit_code = 0
- try:
- stdout, stderr = subp(
- ['lxc', 'exec', self.name, '--'] + env_args + list(command),
- data=stdin, decode=False)
- except ProcessExecutionError as e:
- exit_code = e.exit_code
- stdout = e.stdout
- stderr = e.stderr
-
- return stdout, stderr, exit_code
-
- def read_data(self, remote_path, decode=False):
- """Read data from instance filesystem.
-
- @param remote_path: path in instance
- @param decode: decode data before returning.
- @return_value: content of remote_path as bytes if 'decode' is False,
- and as string if 'decode' is True.
- """
- data = self.pylxd_container.files.get(remote_path)
- return data.decode() if decode else data
-
- def write_data(self, remote_path, data):
- """Write data to instance filesystem.
-
- @param remote_path: path in instance
- @param data: data to write in bytes
- """
- self.pylxd_container.files.put(remote_path, data)
-
- @property
- def console_log_method(self):
- if self._console_log_method is not None:
- return self._console_log_method
-
- client = which('lxc')
- if not client:
- raise PlatformError("No 'lxc' client.")
-
- elif _has_proper_console_support():
- self._console_log_method = 'show-log'
- elif client.startswith("/snap"):
- self._console_log_method = 'logfile-snap'
- else:
- self._console_log_method = 'logfile-tmp'
-
- LOG.debug("Set console log method to %s", self._console_log_method)
- return self._console_log_method
-
- def _setup_console_log(self):
- method = self.console_log_method
- if not method.startswith("logfile-"):
- return
-
- if method == "logfile-snap":
- log_dir = "/var/snap/lxd/common/consoles"
- if not os.path.exists(log_dir):
- raise PlatformError(
- "Unable to log with snap lxc. Please run:\n"
- " sudo mkdir --mode=1777 -p %s" % log_dir)
- elif method == "logfile-tmp":
- log_dir = "/tmp"
- else:
- raise PlatformError(
- "Unexpected value for console method: %s" % method)
-
- # doing this ensures we can read it. Otherwise it ends up root:root.
- log_file = os.path.join(log_dir, self.name)
- with open(log_file, "w") as fp:
- fp.write("# %s\n" % self.name)
-
- cfg = "lxc.console.logfile=%s" % log_file
- orig = self._pylxd_container.config.get('raw.lxc', "")
- if orig:
- orig += "\n"
- self._pylxd_container.config['raw.lxc'] = orig + cfg
- self._pylxd_container.save()
- self._console_log_file = log_file
-
- def console_log(self):
- """Console log.
-
- @return_value: bytes of this instance's console
- """
-
- if self._console_log_file:
- if not os.path.exists(self._console_log_file):
- raise NotImplementedError(
- "Console log '%s' does not exist. If this is a remote "
- "lxc, then this is really NotImplementedError. If it is "
- "A local lxc, then this is a RuntimeError."
- "https://github.com/lxc/lxd/issues/1129")
- with open(self._console_log_file, "rb") as fp:
- return fp.read()
-
- try:
- return subp(['lxc', 'console', '--show-log', self.name],
- decode=False)[0]
- except ProcessExecutionError as e:
- raise PlatformError(
- "console log",
- "Console log failed [%d]: stdout=%s stderr=%s" % (
- e.exit_code, e.stdout, e.stderr)
- ) from e
-
- def reboot(self, wait=True):
- """Reboot instance."""
- self.shutdown(wait=wait)
- self.start(wait=wait)
-
- def shutdown(self, wait=True, retry=1):
- """Shutdown instance."""
- if self.pylxd_container.status == 'Stopped':
- return
-
- try:
- LOG.debug("%s: shutting down (wait=%s)", self, wait)
- self.pylxd_container.stop(wait=wait)
- except (pylxd_exc.LXDAPIException, pylxd_exc.NotFound) as e:
- # An exception happens here sometimes (LP: #1783198)
- # LOG it, and try again.
- LOG.warning(
- ("%s: shutdown(retry=%d) caught %s in shutdown "
- "(response=%s): %s"),
- self, retry, e.__class__.__name__, e.response, e)
- if isinstance(e, pylxd_exc.NotFound):
- LOG.debug("container_exists(%s) == %s",
- self.name, self.platform.container_exists(self.name))
- if retry == 0:
- raise e
- return self.shutdown(wait=wait, retry=retry - 1)
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance."""
- if self.pylxd_container.status != 'Running':
- self.pylxd_container.start(wait=wait)
- if wait:
- self._wait_for_system(wait_for_cloud_init)
-
- def freeze(self):
- """Freeze instance."""
- if self.pylxd_container.status != 'Frozen':
- self.pylxd_container.freeze(wait=True)
-
- def unfreeze(self):
- """Unfreeze instance."""
- if self.pylxd_container.status == 'Frozen':
- self.pylxd_container.unfreeze(wait=True)
-
- def destroy(self):
- """Clean up instance."""
- LOG.debug("%s: deleting container.", self)
- self.unfreeze()
- self.shutdown()
- retries = [1] * 5
- for attempt, wait in enumerate(retries):
- try:
- self.pylxd_container.delete(wait=True)
- break
- except Exception:
- if attempt + 1 >= len(retries):
- raise
- LOG.debug('Failed to delete container %s (%s/%s) retrying...',
- self, attempt + 1, len(retries))
- time.sleep(wait)
-
- self._pylxd_container = None
-
- if self.platform.container_exists(self.name):
- raise OSError('%s: container was not properly removed' % self)
- if self._console_log_file and os.path.exists(self._console_log_file):
- os.unlink(self._console_log_file)
- shutil.rmtree(self.tmpd)
- super(LXDInstance, self).destroy()
-
-
-def _has_proper_console_support():
- stdout, _ = subp(['lxc', 'info'])
- info = load_yaml(stdout)
- reason = None
- if 'console' not in info.get('api_extensions', []):
- reason = "LXD server does not support console api extension"
- else:
- dver = str(info.get('environment', {}).get('driver_version', ""))
- if dver.startswith("2.") or dver.startswith("1."):
- reason = "LXD Driver version not 3.x+ (%s)" % dver
- else:
- try:
- stdout = subp(['lxc', 'console', '--help'], decode=False)[0]
- if not (b'console' in stdout and b'log' in stdout):
- reason = "no '--log' in lxc console --help"
- except ProcessExecutionError:
- reason = "no 'console' command in lxc client"
-
- if reason:
- LOG.debug("no console-support: %s", reason)
- return False
- else:
- LOG.debug("console-support looks good")
- return True
-
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/lxd/platform.py b/tests/cloud_tests/platforms/lxd/platform.py
deleted file mode 100644
index f7251a07..00000000
--- a/tests/cloud_tests/platforms/lxd/platform.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base LXD platform."""
-
-from pylxd import (Client, exceptions)
-
-from ..platforms import Platform
-from .image import LXDImage
-from .instance import LXDInstance
-from tests.cloud_tests import util
-
-DEFAULT_SSTREAMS_SERVER = "https://images.linuxcontainers.org:8443"
-
-
-class LXDPlatform(Platform):
- """LXD test platform."""
-
- platform_name = 'lxd'
-
- def __init__(self, config):
- """Set up platform."""
- super(LXDPlatform, self).__init__(config)
- # TODO: allow configuration of remote lxd host via env variables
- # set up lxd connection
- self.client = Client()
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- pylxd_image = self.client.images.create_from_simplestreams(
- img_conf.get('sstreams_server', DEFAULT_SSTREAMS_SERVER),
- img_conf['alias'])
- image = LXDImage(self, img_conf, pylxd_image)
- if img_conf.get('override_templates', False):
- image.update_templates(self.config.get('template_overrides', {}),
- self.config.get('template_files', {}))
- return image
-
- def launch_container(self, properties, config, features,
- image=None, container=None, ephemeral=False,
- container_config=None, block=True, image_desc=None,
- use_desc=None):
- """Launch a container.
-
- @param properties: image properties
- @param config: image configuration
- @param features: image features
- @param image: image fingerprint to launch from
- @param container: container to copy
- @param ephemeral: delete image after first shutdown
- @param container_config: config options for instance as dict
- @param block: wait until container created
- @param image_desc: description of image being launched
- @param use_desc: description of container's use
- @return_value: cloud_tests.instances instance
- """
- if not (image or container):
- raise ValueError("either image or container must be specified")
- container = self.client.containers.create({
- 'name': util.gen_instance_name(image_desc=image_desc,
- use_desc=use_desc,
- used_list=self.list_containers()),
- 'ephemeral': bool(ephemeral),
- 'config': (container_config
- if isinstance(container_config, dict) else {}),
- 'source': ({'type': 'image', 'fingerprint': image} if image else
- {'type': 'copy', 'source': container})
- }, wait=block)
- return LXDInstance(self, container.name, properties, config, features,
- container)
-
- def container_exists(self, container_name):
- """Check if container with name 'container_name' exists.
-
- @return_value: True if exists else False
- """
- res = True
- try:
- self.client.containers.get(container_name)
- except exceptions.LXDAPIException as e:
- res = False
- if e.response.status_code != 404:
- raise
- return res
-
- def list_containers(self):
- """List names of all containers.
-
- @return_value: list of names
- """
- return [container.name for container in self.client.containers.all()]
-
- def query_image_by_alias(self, alias):
- """Get image by alias in local image store.
-
- @param alias: alias of image
- @return_value: pylxd image (not cloud_tests.images instance)
- """
- return self.client.images.get_by_alias(alias)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/lxd/snapshot.py b/tests/cloud_tests/platforms/lxd/snapshot.py
deleted file mode 100644
index b524644f..00000000
--- a/tests/cloud_tests/platforms/lxd/snapshot.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base LXD snapshot."""
-
-from ..snapshots import Snapshot
-
-
-class LXDSnapshot(Snapshot):
- """LXD image copy backed snapshot."""
-
- platform_name = "lxd"
-
- def __init__(self, platform, properties, config, features,
- pylxd_frozen_instance):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- self.pylxd_frozen_instance = pylxd_frozen_instance
- super(LXDSnapshot, self).__init__(
- platform, properties, config, features)
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param instance_id: instance-id for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: description of snapshot instance use
- @return_value: an Instance
- """
- inst_config = {'user.user-data': user_data}
- if meta_data:
- inst_config['user.meta-data'] = meta_data
- instance = self.platform.launch_container(
- self.properties, self.config, self.features, block=block,
- image_desc=str(self), container=self.pylxd_frozen_instance.name,
- use_desc=use_desc, container_config=inst_config)
- if start:
- instance.start()
- return instance
-
- def destroy(self):
- """Clean up snapshot data."""
- self.pylxd_frozen_instance.destroy()
- super(LXDSnapshot, self).destroy()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/nocloudkvm/__init__.py b/tests/cloud_tests/platforms/nocloudkvm/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/tests/cloud_tests/platforms/nocloudkvm/__init__.py
+++ /dev/null
diff --git a/tests/cloud_tests/platforms/nocloudkvm/image.py b/tests/cloud_tests/platforms/nocloudkvm/image.py
deleted file mode 100644
index ff5b6ad7..00000000
--- a/tests/cloud_tests/platforms/nocloudkvm/image.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""NoCloud KVM Image Base Class."""
-
-from cloudinit import subp
-
-import os
-import shutil
-import tempfile
-
-from ..images import Image
-from .snapshot import NoCloudKVMSnapshot
-
-
-class NoCloudKVMImage(Image):
- """NoCloud KVM backed image."""
-
- platform_name = "nocloud-kvm"
-
- def __init__(self, platform, config, orig_img_path):
- """Set up image.
-
- @param platform: platform object
- @param config: image configuration
- @param img_path: path to the image
- """
- self.modified = False
- self._workd = tempfile.mkdtemp(prefix='NoCloudKVMImage')
- self._orig_img_path = orig_img_path
- self._img_path = os.path.join(self._workd,
- os.path.basename(self._orig_img_path))
-
- subp.subp(['qemu-img', 'create', '-f', 'qcow2',
- '-b', orig_img_path, self._img_path])
-
- super(NoCloudKVMImage, self).__init__(platform, config)
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command in image, modifying image."""
- return self.mount_image_callback(command, stdin=stdin, env=env)
-
- def mount_image_callback(self, command, stdin=None, env=None):
- """Run mount-image-callback."""
-
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- mic_chroot = ['sudo', 'mount-image-callback', '--system-mounts',
- '--system-resolvconf', self._img_path,
- '--', 'chroot', '_MOUNTPOINT_']
- try:
- out, err = subp.subp(mic_chroot + env_args + list(command),
- data=stdin, decode=False)
- return (out, err, 0)
- except subp.ProcessExecutionError as e:
- return (e.stdout, e.stderr, e.exit_code)
-
- def snapshot(self):
- """Create snapshot of image, block until done."""
- if not self._img_path:
- raise RuntimeError()
-
- return NoCloudKVMSnapshot(self.platform, self.properties, self.config,
- self.features, self._img_path)
-
- def destroy(self):
- """Unset path to signal image is no longer used.
-
- The removal of the images and all other items is handled by the
- framework. In some cases we want to keep the images, so let the
- framework decide whether to keep or destroy everything.
- """
- self._img_path = None
- shutil.rmtree(self._workd)
-
- super(NoCloudKVMImage, self).destroy()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/nocloudkvm/instance.py b/tests/cloud_tests/platforms/nocloudkvm/instance.py
deleted file mode 100644
index 5140a11c..00000000
--- a/tests/cloud_tests/platforms/nocloudkvm/instance.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base NoCloud KVM instance."""
-
-import copy
-import os
-import socket
-import subprocess
-import time
-import uuid
-
-from ..instances import Instance
-from cloudinit.atomic_helper import write_json
-from cloudinit import subp
-from tests.cloud_tests import LOG, util
-
-# This domain contains reverse lookups for hostnames that are used.
-# The primary reason is so sudo will return quickly when it attempts
-# to look up the hostname. i9n is just short for 'integration'.
-# see also bug 1730744 for why we had to do this.
-CI_DOMAIN = "i9n.cloud-init.io"
-
-
-class NoCloudKVMInstance(Instance):
- """NoCloud KVM backed instance."""
-
- platform_name = "nocloud-kvm"
-
- def __init__(self, platform, name, image_path, properties, config,
- features, user_data, meta_data):
- """Set up instance.
-
- @param platform: platform object
- @param name: image path
- @param image_path: path to disk image to boot.
- @param properties: dictionary of properties
- @param config: dictionary of configuration values
- @param features: dictionary of supported feature flags
- """
- super(NoCloudKVMInstance, self).__init__(
- platform, name, properties, config, features
- )
-
- self.user_data = user_data
- if meta_data:
- meta_data = copy.deepcopy(meta_data)
- else:
- meta_data = {}
-
- if 'instance-id' in meta_data:
- iid = meta_data['instance-id']
- else:
- iid = str(uuid.uuid1())
- meta_data['instance-id'] = iid
-
- self.instance_id = iid
- self.ssh_key_file = os.path.join(
- platform.config['data_dir'], platform.config['private_key'])
- self.ssh_pubkey_file = os.path.join(
- platform.config['data_dir'], platform.config['public_key'])
-
- self.ssh_pubkey = None
- if self.ssh_pubkey_file:
- with open(self.ssh_pubkey_file, "r") as fp:
- self.ssh_pubkey = fp.read().rstrip('\n')
-
- if not meta_data.get('public-keys'):
- meta_data['public-keys'] = []
- meta_data['public-keys'].append(self.ssh_pubkey)
-
- self.ssh_ip = '127.0.0.1'
- self.ssh_port = None
- self.pid = None
- self.pid_file = None
- self.console_file = None
- self.disk = image_path
- self.cache_mode = platform.config.get('cache_mode',
- 'cache=none,aio=native')
- self.meta_data = meta_data
-
- def shutdown(self, wait=True):
- """Shutdown instance."""
-
- if self.pid:
- # This relies on _execute which uses sudo over ssh. The ssh
- # connection would get killed before sudo exited, so ignore errors.
- cmd = ['shutdown', 'now']
- try:
- self._execute(cmd)
- except util.InTargetExecuteError:
- pass
- self._ssh_close()
-
- if wait:
- LOG.debug("Executed shutdown. waiting on pid %s to end",
- self.pid)
- time_for_shutdown = 120
- give_up_at = time.time() + time_for_shutdown
- pid_file_path = '/proc/%s' % self.pid
- msg = ("pid %s did not exit in %s seconds after shutdown." %
- (self.pid, time_for_shutdown))
- while True:
- if not os.path.exists(pid_file_path):
- break
- if time.time() > give_up_at:
- raise util.PlatformError("shutdown", msg)
- self.pid = None
-
- def destroy(self):
- """Clean up instance."""
- if self.pid:
- try:
- subp.subp(['kill', '-9', self.pid])
- except subp.ProcessExecutionError:
- pass
-
- if self.pid_file:
- try:
- os.remove(self.pid_file)
- except Exception:
- pass
-
- self.pid = None
- self._ssh_close()
-
- super(NoCloudKVMInstance, self).destroy()
-
- def _execute(self, command, stdin=None, env=None):
- env_args = []
- if env:
- env_args = ['env'] + ["%s=%s" for k, v in env.items()]
-
- return self._ssh(['sudo'] + env_args + list(command), stdin=stdin)
-
- def generate_seed(self, tmpdir):
- """Generate nocloud seed from user-data"""
- seed_file = os.path.join(tmpdir, '%s_seed.img' % self.name)
- user_data_file = os.path.join(tmpdir, '%s_user_data' % self.name)
- meta_data_file = os.path.join(tmpdir, '%s_meta_data' % self.name)
-
- with open(user_data_file, "w") as ud_file:
- ud_file.write(self.user_data)
-
- # meta-data can be yaml, but more easily pretty printed with json
- write_json(meta_data_file, self.meta_data)
- subp.subp(['cloud-localds', seed_file, user_data_file,
- meta_data_file])
-
- return seed_file
-
- def get_free_port(self):
- """Get a free port assigned by the kernel."""
- s = socket.socket()
- s.bind(('', 0))
- num = s.getsockname()[1]
- s.close()
- return num
-
- def start(self, wait=True, wait_for_cloud_init=False):
- """Start instance."""
- tmpdir = self.platform.config['data_dir']
- seed = self.generate_seed(tmpdir)
- self.pid_file = os.path.join(tmpdir, '%s.pid' % self.name)
- self.console_file = os.path.join(tmpdir, '%s-console.log' % self.name)
- self.ssh_port = self.get_free_port()
-
- cmd = ['./tools/xkvm',
- '--disk', '%s,%s' % (self.disk, self.cache_mode),
- '--disk', '%s' % seed,
- '--netdev', ','.join(['user',
- 'hostfwd=tcp::%s-:22' % self.ssh_port,
- 'dnssearch=%s' % CI_DOMAIN]),
- '--', '-pidfile', self.pid_file, '-vnc', 'none',
- '-m', '2G', '-smp', '2', '-nographic', '-name', self.name,
- '-serial', 'file:' + self.console_file]
- subprocess.Popen(cmd,
- close_fds=True,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
- while not os.path.exists(self.pid_file):
- time.sleep(1)
-
- with open(self.pid_file, 'r') as pid_f:
- self.pid = pid_f.readlines()[0].strip()
-
- if wait:
- self._wait_for_system(wait_for_cloud_init)
-
- def console_log(self):
- if not self.console_file:
- return b''
- with open(self.console_file, "rb") as fp:
- return fp.read()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/nocloudkvm/platform.py b/tests/cloud_tests/platforms/nocloudkvm/platform.py
deleted file mode 100644
index 53c8ebf2..00000000
--- a/tests/cloud_tests/platforms/nocloudkvm/platform.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base NoCloud KVM platform."""
-import glob
-import os
-
-from simplestreams import filters
-from simplestreams import mirrors
-from simplestreams import objectstores
-from simplestreams import util as s_util
-
-from ..platforms import Platform
-from .image import NoCloudKVMImage
-from .instance import NoCloudKVMInstance
-from cloudinit import subp
-from cloudinit import util as c_util
-from tests.cloud_tests import util
-
-
-class NoCloudKVMPlatform(Platform):
- """NoCloud KVM test platform."""
-
- platform_name = 'nocloud-kvm'
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- (url, path) = s_util.path_from_mirror_url(img_conf['mirror_url'], None)
-
- filter = filters.get_filters(
- [
- 'arch=%s' % c_util.get_dpkg_architecture(),
- 'release=%s' % img_conf['release'],
- 'ftype=disk1.img',
- ]
- )
- mirror_config = {'filters': filter,
- 'keep_items': False,
- 'max_items': 1,
- 'checksumming_reader': True,
- 'item_download': True
- }
-
- def policy(content, path):
- return s_util.read_signed(content, keyring=img_conf['keyring'])
-
- smirror = mirrors.UrlMirrorReader(url, policy=policy)
- tstore = objectstores.FileStore(img_conf['mirror_dir'])
- tmirror = mirrors.ObjectFilterMirror(config=mirror_config,
- objectstore=tstore)
- tmirror.sync(smirror, path)
-
- search_d = os.path.join(img_conf['mirror_dir'], '**',
- img_conf['release'], '**', '*.img')
-
- images = []
- for fname in glob.iglob(search_d, recursive=True):
- images.append(fname)
-
- if len(images) < 1:
- raise RuntimeError("No images found under '%s'" % search_d)
- if len(images) > 1:
- raise RuntimeError(
- "Multiple images found in '%s': %s" % (search_d,
- ' '.join(images)))
-
- image = NoCloudKVMImage(self, img_conf, images[0])
- return image
-
- def create_instance(self, properties, config, features,
- src_img_path, image_desc=None, use_desc=None,
- user_data=None, meta_data=None):
- """Create an instance
-
- @param src_img_path: image path to launch from
- @param properties: image properties
- @param config: image configuration
- @param features: image features
- @param image_desc: description of image being launched
- @param use_desc: description of container's use
- @return_value: cloud_tests.instances instance
- """
- name = util.gen_instance_name(image_desc=image_desc, use_desc=use_desc)
- img_path = os.path.join(self.config['data_dir'], name + '.qcow2')
- subp.subp(['qemu-img', 'create', '-f', 'qcow2',
- '-b', src_img_path, img_path])
-
- return NoCloudKVMInstance(self, name, img_path, properties, config,
- features, user_data, meta_data)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/nocloudkvm/snapshot.py b/tests/cloud_tests/platforms/nocloudkvm/snapshot.py
deleted file mode 100644
index 2dae3590..00000000
--- a/tests/cloud_tests/platforms/nocloudkvm/snapshot.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base NoCloud KVM snapshot."""
-import os
-import shutil
-import tempfile
-
-from ..snapshots import Snapshot
-
-
-class NoCloudKVMSnapshot(Snapshot):
- """NoCloud KVM image copy backed snapshot."""
-
- platform_name = "nocloud-kvm"
-
- def __init__(self, platform, properties, config, features, image_path):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- @param image_path: image file to snapshot.
- """
- self._workd = tempfile.mkdtemp(prefix='NoCloudKVMSnapshot')
- snapshot = os.path.join(self._workd, 'snapshot')
- shutil.copyfile(image_path, snapshot)
- self._image_path = snapshot
-
- super(NoCloudKVMSnapshot, self).__init__(
- platform, properties, config, features)
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param instance_id: instance-id for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: description of snapshot instance use
- @return_value: an Instance
- """
- instance = self.platform.create_instance(
- self.properties, self.config, self.features,
- self._image_path, image_desc=str(self), use_desc=use_desc,
- user_data=user_data, meta_data=meta_data)
-
- if start:
- instance.start()
-
- return instance
-
- def destroy(self):
- """Clean up snapshot data."""
- shutil.rmtree(self._workd)
- super(NoCloudKVMSnapshot, self).destroy()
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/platforms.py b/tests/cloud_tests/platforms/platforms.py
deleted file mode 100644
index ac3b6563..00000000
--- a/tests/cloud_tests/platforms/platforms.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base platform class."""
-import os
-import shutil
-
-from simplestreams import filters, mirrors
-from simplestreams import util as s_util
-
-from cloudinit import subp
-from cloudinit import util as c_util
-
-from tests.cloud_tests import util
-
-
-class Platform(object):
- """Base class for platforms."""
-
- platform_name = None
-
- def __init__(self, config):
- """Set up platform."""
- self.config = config
- self.tmpdir = util.mkdtemp()
- if 'data_dir' in config:
- self.data_dir = config['data_dir']
- else:
- self.data_dir = os.path.join(self.tmpdir, "data_dir")
- os.mkdir(self.data_dir)
-
- self._generate_ssh_keys(self.data_dir)
-
- def get_image(self, img_conf):
- """Get image using specified image configuration.
-
- @param img_conf: configuration for image
- @return_value: cloud_tests.images instance
- """
- raise NotImplementedError
-
- def destroy(self):
- """Clean up platform data."""
- shutil.rmtree(self.tmpdir)
-
- def _generate_ssh_keys(self, data_dir):
- """Generate SSH keys to be used with image."""
- filename = os.path.join(data_dir, self.config['private_key'])
-
- if os.path.exists(filename):
- c_util.del_file(filename)
-
- subp.subp(['ssh-keygen', '-m', 'PEM', '-t', 'rsa', '-b', '4096',
- '-f', filename, '-P', '',
- '-C', 'ubuntu@cloud_test'],
- capture=True)
-
- @staticmethod
- def _query_streams(img_conf, img_filter):
- """Query streams for latest image given a specific filter.
-
- @param img_conf: configuration for image
- @param filters: array of filters as strings format 'key=value'
- @return: dictionary with latest image information or empty
- """
- def policy(content, path):
- return s_util.read_signed(content, keyring=img_conf['keyring'])
-
- (url, path) = s_util.path_from_mirror_url(img_conf['mirror_url'], None)
- smirror = mirrors.UrlMirrorReader(url, policy=policy)
-
- config = {'max_items': 1, 'filters': filters.get_filters(img_filter)}
- tmirror = FilterMirror(config)
- tmirror.sync(smirror, path)
-
- try:
- return tmirror.json_entries[0]
- except IndexError as e:
- raise RuntimeError(
- 'no images found with filter: %s' % img_filter
- ) from e
-
-
-class FilterMirror(mirrors.BasicMirrorWriter):
- """Taken from sstream-query to return query result as json array."""
-
- def __init__(self, config=None):
- super(FilterMirror, self).__init__(config=config)
- if config is None:
- config = {}
- self.config = config
- self.filters = config.get('filters', [])
- self.json_entries = []
-
- def load_products(self, path=None, content_id=None):
- return {'content_id': content_id, 'products': {}}
-
- def filter_item(self, data, src, target, pedigree):
- return filters.filter_item(self.filters, data, src, pedigree)
-
- def insert_item(self, data, src, target, pedigree, contentsource):
- # src and target are top level products:1.0
- # data is src['products'][ped[0]]['versions'][ped[1]]['items'][ped[2]]
- # contentsource is a ContentSource if 'path' exists in data or None
- data = s_util.products_exdata(src, pedigree)
- if 'path' in data:
- data.update({'item_url': contentsource.url})
- self.json_entries.append(data)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/platforms/snapshots.py b/tests/cloud_tests/platforms/snapshots.py
deleted file mode 100644
index 0f5f8bb6..00000000
--- a/tests/cloud_tests/platforms/snapshots.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base snapshot."""
-
-
-class Snapshot(object):
- """Base class for snapshots."""
-
- platform_name = None
-
- def __init__(self, platform, properties, config, features):
- """Set up snapshot.
-
- @param platform: platform object
- @param properties: image properties
- @param config: image config
- @param features: supported feature flags
- """
- self.platform = platform
- self.properties = properties
- self.config = config
- self.features = features
-
- def __str__(self):
- """A brief description of the snapshot."""
- return '-'.join((self.properties['os'], self.properties['release']))
-
- def launch(self, user_data, meta_data=None, block=True, start=True,
- use_desc=None):
- """Launch instance.
-
- @param user_data: user-data for the instance
- @param instance_id: instance-id for the instance
- @param block: wait until instance is created
- @param start: start instance and wait until fully started
- @param use_desc: description of snapshot instance use
- @return_value: an Instance
- """
- raise NotImplementedError
-
- def destroy(self):
- """Clean up snapshot data."""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/releases.yaml b/tests/cloud_tests/releases.yaml
deleted file mode 100644
index c52b78f9..00000000
--- a/tests/cloud_tests/releases.yaml
+++ /dev/null
@@ -1,381 +0,0 @@
-# ============================= Release Config ================================
-default_release_config:
- # global default configuration options
- default:
- # all are disabled by default
- enabled: false
- # timeout for booting image and running cloud init
- boot_timeout: 120
- # a script to run after a boot that is used to modify an image, before
- # making a snapshot of the image. may be useful for removing data left
- # behind from cloud-init booting, such as logs, to ensure that data
- # from snapshot.launch() will not include a cloud-init.log from a boot
- # used to create the snapshot, if cloud-init has not run
- boot_clean_script: |
- #!/bin/bash
- rm -rf /var/log/cloud-init.log /var/log/cloud-init-output.log \
- /var/lib/cloud/ /run/cloud-init/ /var/log/syslog
- # test script to determine if system is booted fully
- system_ready_script: |
- # permit running or degraded state as both indicate complete boot
- [ $(systemctl is-system-running) = 'running' -o
- $(systemctl is-system-running) = 'degraded' ]
- # test script to determine if cloud-init has finished
- cloud_init_ready_script: |
- [ -f '/run/cloud-init/result.json' ]
- # currently used features and their uses are:
- # features groups and additional feature settings
- feature_groups: []
- features: {}
- mirror_url: https://cloud-images.ubuntu.com/daily
- mirror_dir: '/srv/citest/images'
- keyring: /usr/share/keyrings/ubuntu-cloudimage-keyring.gpg
- # The OS version formatted as Major.Minor is used to compare releases.
- # Each release needs to define this, for example "16.04". Quoting is
- # necessary to ensure the version is treated as a string.
- version: null
-
- ec2:
- # Choose from: [ebs, instance-store]
- root-store: ebs
- boot_timeout: 300
- nocloud-kvm:
- setup_overrides: null
- override_templates: false
- # lxd specific default configuration options
- lxd:
- # default sstreams server to use for lxd image retrieval
- sstreams_server: https://us.images.linuxcontainers.org:8443
- # keep base image, avoids downloading again next run
- cache_base_image: true
- # lxd images from linuxcontainers.org do not have the nocloud seed
- # templates in place, so the image metadata must be modified
- override_templates: true
- # arg overrides to set image up
- setup_overrides:
- # lxd images from linuxcontainers.org do not come with
- # cloud-init, so must pull cloud-init in from repo using
- # setup_image.upgrade
- upgrade: true
- azurecloud:
- boot_timeout: 300
-
-features:
- # all currently supported feature flags
- all:
- - apt # image supports apt package manager
- - byobu # byobu is available in repositories
- - landscape # landscape-client available in repos
- - lxd # lxd is available in the image
- - ppa # image supports ppas
- - rpm # image supports rpms
- - snap # supports snapd
- # NOTE: the following feature flags are to work around bugs in the
- # images, and can be removed when no longer needed
- - hostname # setting system hostname works
- # NOTE: the following feature flags are to work around issues in the
- # testcases, and can be removed when no longer needed
- - apt_src_cont # default contents and format of sources.list matches
- # ubuntu sources.list
- - apt_hist_fmt # apt command history entries use full paths to apt
- # executable rather than relative paths
- - daylight_time # timezones are daylight not standard time
- - apt_up_out # 'Calculating upgrade..' present in log output from
- # apt-get dist-upgrade output
- - engb_locale # locale en_GB.UTF-8 is available
- - locale_gen # the /etc/locale.gen file exists
- - no_ntpdate # 'ntpdate' is not installed by default
- - no_file_fmt_e # the 'file' utility does not have a formatting error
- - ppa_file_name # the name of the source file added to sources.list.d has
- # the expected format for newer ubuntu releases
- - sshd # requires ssh server to be installed by default
- - ssh_key_fmt # ssh auth keys printed to console have expected format
- - syslog # test case requires syslog to be written by default
- - ubuntu_ntp # expect ubuntu.pool.ntp.org to be used as ntp server
- - ubuntu_repos # test case requres ubuntu repositories to be used
- - ubuntu_user # test case needs user with the name 'ubuntu' to exist
- # NOTE: the following feature flags are to work around issues that may
- # be considered bugs in cloud-init
- - lsb_release # image has lsb_release installed, maybe should install
- # if missing by default
- - sudo # image has sudo installed, should not be required
- # feature flag groups
- groups:
- base:
- hostname: true
- no_file_fmt_e: true
- ubuntu_specific:
- apt_src_cont: true
- apt_hist_fmt: true
- byobu: true
- daylight_time: true
- engb_locale: true
- landscape: true
- locale_gen: true
- lsb_release: true
- lxd: true
- ppa: true
- ppa_file_name: true
- snap: true
- sshd: true
- ssh_key_fmt: true
- sudo: true
- syslog: true
- ubuntu_ntp: true
- ubuntu_repos: true
- ubuntu_user: true
- debian_base:
- apt: true
- apt_up_out: true
- no_ntpdate: true
- rhel_base:
- rpm: true
-
-releases:
- # UBUNTU =================================================================
- impish:
- # EOL: July 2022
- default:
- enabled: true
- release: impish
- version: "21.10"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: impish
- setup_overrides: null
- override_templates: false
-
- hirsute:
- # EOL: Jan 2022
- default:
- enabled: true
- release: hirsute
- version: "21.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: hirsute
- setup_overrides: null
- override_templates: false
- groovy:
- # EOL: Jul 2021
- default:
- enabled: true
- release: groovy
- version: "20.10"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: groovy
- setup_overrides: null
- override_templates: false
- focal:
- # EOL: Apr 2025
- default:
- enabled: true
- release: focal
- version: "20.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: focal
- setup_overrides: null
- override_templates: false
- eoan:
- # EOL: Jul 2020
- default:
- enabled: true
- release: eoan
- version: "19.10"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: eoan
- setup_overrides: null
- override_templates: false
- disco:
- # EOL: Jan 2020
- default:
- enabled: true
- release: disco
- version: "19.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: disco
- setup_overrides: null
- override_templates: false
- cosmic:
- # EOL: Jul 2019
- default:
- enabled: true
- release: cosmic
- version: "18.10"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: cosmic
- setup_overrides: null
- override_templates: false
- bionic:
- # EOL: Apr 2023
- default:
- enabled: true
- release: bionic
- version: "18.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: bionic
- setup_overrides: null
- override_templates: false
- artful:
- # EOL: Jul 2018
- default:
- enabled: true
- release: artful
- version: "17.10"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: artful
- setup_overrides: null
- override_templates: false
- xenial:
- # EOL: Apr 2021
- default:
- enabled: true
- release: xenial
- version: "16.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: xenial
- setup_overrides: null
- override_templates: false
- trusty:
- # EOL: Apr 2019
- default:
- enabled: true
- release: trusty
- version: "14.04"
- os: ubuntu
- feature_groups:
- - base
- - debian_base
- - ubuntu_specific
- features:
- apt_up_out: false
- locale_gen: false
- lxd: false
- ppa_file_name: false
- snap: false
- ssh_key_fmt: false
- no_ntpdate: false
- no_file_fmt_e: false
- system_ready_script: |
- #!/bin/bash
- # upstart based, so use old style runlevels
- [ $(runlevel | awk '{print $2}') = '2' ]
- lxd:
- sstreams_server: https://cloud-images.ubuntu.com/daily
- alias: trusty
- setup_overrides: null
- override_templates: false
- # DEBIAN =================================================================
- stretch:
- # EOL: Not yet released
- default:
- enabled: true
- feature_groups:
- - base
- - debian_base
- lxd:
- alias: debian/stretch/default
- jessie:
- # EOL: Jun 2020
- # NOTE: the cloud-init version shipped with jessie is out of date
- # tests work if an up to date deb is used
- default:
- enabled: true
- feature_groups:
- - base
- - debian_base
- lxd:
- alias: debian/jessie/default
- # CENTOS =================================================================
- centos70:
- # EOL: Jun 2024 (2020 - end of full updates)
- default:
- enabled: true
- feature_groups:
- - base
- - rhel_base
- user_data_overrides:
- preserve_hostname: true
- lxd:
- features:
- # NOTE: (LP: #1575779)
- hostname: false
- alias: centos/7/default
- centos66:
- # EOL: Nov 2020
- default:
- enabled: true
- feature_groups:
- - base
- - rhel_base
- # still supported, but only bugfixes after may 2017
- system_ready_script: |
- #!/bin/bash
- [ $(runlevel | awk '{print $2}') = '3' ]
- user_data_overrides:
- preserve_hostname: true
- lxd:
- features:
- # NOTE: (LP: #1575779)
- hostname: false
- alias: centos/6/default
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/run_funcs.py b/tests/cloud_tests/run_funcs.py
deleted file mode 100644
index 8ae91120..00000000
--- a/tests/cloud_tests/run_funcs.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Run functions."""
-
-import os
-
-from tests.cloud_tests import bddeb, collect, util, verify
-
-
-def tree_collect(args):
- """Collect data using deb build from current tree.
-
- @param args: cmdline args
- @return_value: fail count
- """
- failed = 0
- tmpdir = util.TempDir(tmpdir=args.data_dir, preserve=args.preserve_data)
-
- with tmpdir as data_dir:
- args.data_dir = data_dir
- args.deb = os.path.join(tmpdir.tmpdir, 'cloud-init_all.deb')
- try:
- failed += bddeb.bddeb(args)
- failed += collect.collect(args)
- except Exception:
- failed += 1
- raise
-
- return failed
-
-
-def tree_run(args):
- """Run test suite using deb build from current tree.
-
- @param args: cmdline args
- @return_value: fail count
- """
- failed = 0
- tmpdir = util.TempDir(tmpdir=args.data_dir, preserve=args.preserve_data)
-
- with tmpdir as data_dir:
- args.data_dir = data_dir
- args.deb = os.path.join(tmpdir.tmpdir, 'cloud-init_all.deb')
- try:
- failed += bddeb.bddeb(args)
- failed += collect.collect(args)
- failed += verify.verify(args)
- except Exception:
- failed += 1
- raise
-
- return failed
-
-
-def run(args):
- """Run test suite.
-
- @param args: cmdline args
- @return_value: fail count
- """
- failed = 0
- tmpdir = util.TempDir(tmpdir=args.data_dir, preserve=args.preserve_data)
-
- with tmpdir as data_dir:
- args.data_dir = data_dir
- try:
- failed += collect.collect(args)
- failed += verify.verify(args)
- except Exception:
- failed += 1
- raise
-
- return failed
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/setup_image.py b/tests/cloud_tests/setup_image.py
deleted file mode 100644
index 69e66e3f..00000000
--- a/tests/cloud_tests/setup_image.py
+++ /dev/null
@@ -1,237 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Setup image for testing."""
-
-from functools import partial
-import os
-import yaml
-
-from tests.cloud_tests import LOG
-from tests.cloud_tests import stage, util
-
-
-def installed_package_version(image, package, ensure_installed=True):
- """Get installed version of package.
-
- @param image: cloud_tests.images instance to operate on
- @param package: name of package
- @param ensure_installed: raise error if not installed
- @return_value: cloud-init version string
- """
- os_family = util.get_os_family(image.properties['os'])
- if os_family == 'debian':
- cmd = ['dpkg-query', '-W', "--showformat=${Version}", package]
- elif os_family == 'redhat':
- cmd = ['rpm', '-q', '--queryformat', "'%{VERSION}'", package]
- else:
- raise NotImplementedError
-
- return image.execute(
- cmd, description='query version for package: {}'.format(package),
- rcs=(0,) if ensure_installed else range(0, 256))[0].strip()
-
-
-def install_deb(args, image):
- """Install deb into image.
-
- @param args: cmdline arguments, must contain --deb
- @param image: cloud_tests.images instance to operate on
- @return_value: None, may raise errors
- """
- # ensure system is compatible with package format
- os_family = util.get_os_family(image.properties['os'])
- if os_family != 'debian':
- raise NotImplementedError('install deb: {} not supported on os '
- 'family: {}'.format(args.deb, os_family))
-
- # install deb
- msg = 'install deb: "{}" into target'.format(args.deb)
- LOG.debug(msg)
- remote_path = os.path.join('/tmp', os.path.basename(args.deb))
- image.push_file(args.deb, remote_path)
- image.execute(
- ['apt-get', 'install', '--allow-downgrades', '--assume-yes',
- remote_path], description=msg)
- # check installed deb version matches package
- fmt = ['-W', "--showformat=${Version}"]
- out = image.execute(['dpkg-deb'] + fmt + [remote_path])[0]
- expected_version = out.strip()
- found_version = installed_package_version(image, 'cloud-init')
- if expected_version != found_version:
- raise OSError('install deb version "{}" does not match expected "{}"'
- .format(found_version, expected_version))
-
- LOG.debug('successfully installed: %s, version: %s', args.deb,
- found_version)
-
-
-def install_rpm(args, image):
- """Install rpm into image.
-
- @param args: cmdline arguments, must contain --rpm
- @param image: cloud_tests.images instance to operate on
- @return_value: None, may raise errors
- """
- os_family = util.get_os_family(image.properties['os'])
- if os_family != 'redhat':
- raise NotImplementedError('install rpm: {} not supported on os '
- 'family: {}'.format(args.rpm, os_family))
-
- # install rpm
- msg = 'install rpm: "{}" into target'.format(args.rpm)
- LOG.debug(msg)
- remote_path = os.path.join('/tmp', os.path.basename(args.rpm))
- image.push_file(args.rpm, remote_path)
- image.execute(['rpm', '-U', remote_path], description=msg)
-
- fmt = ['--queryformat', '"%{VERSION}"']
- (out, _err, _exit) = image.execute(['rpm', '-q'] + fmt + [remote_path])
- expected_version = out.strip()
- found_version = installed_package_version(image, 'cloud-init')
- if expected_version != found_version:
- raise OSError('install rpm version "{}" does not match expected "{}"'
- .format(found_version, expected_version))
-
- LOG.debug('successfully installed: %s, version %s', args.rpm,
- found_version)
-
-
-def upgrade(args, image):
- """Upgrade or install cloud-init from repo.
-
- @param args: cmdline arguments
- @param image: cloud_tests.images instance to operate on
- @return_value: None, may raise errors
- """
- os_family = util.get_os_family(image.properties['os'])
- if os_family == 'debian':
- cmd = 'apt-get update && apt-get install cloud-init --yes'
- elif os_family == 'redhat':
- cmd = 'sleep 10 && yum install cloud-init --assumeyes'
- else:
- raise NotImplementedError
-
- msg = 'upgrading cloud-init'
- LOG.debug(msg)
- image.execute(cmd, description=msg)
-
-
-def upgrade_full(args, image):
- """Run the system's full upgrade command.
-
- @param args: cmdline arguments
- @param image: cloud_tests.images instance to operate on
- @return_value: None, may raise errors
- """
- os_family = util.get_os_family(image.properties['os'])
- if os_family == 'debian':
- cmd = 'apt-get update && apt-get upgrade --yes'
- elif os_family == 'redhat':
- cmd = 'yum upgrade --assumeyes'
- else:
- raise NotImplementedError('upgrade command not configured for distro '
- 'from family: {}'.format(os_family))
-
- msg = 'full system upgrade'
- LOG.debug(msg)
- image.execute(cmd, description=msg)
-
-
-def run_script(args, image):
- """Run a script in the target image.
-
- @param args: cmdline arguments, must contain --script
- @param image: cloud_tests.images instance to operate on
- @return_value: None, may raise errors
- """
- msg = 'run setup image script in target image'
- LOG.debug(msg)
- image.run_script(args.script, description=msg)
-
-
-def enable_ppa(args, image):
- """Enable a ppa in the target image.
-
- @param args: cmdline arguments, must contain --ppa
- @param image: cloud_tests.image instance to operate on
- @return_value: None, may raise errors
- """
- # ppa only supported on ubuntu (maybe debian?)
- if image.properties['os'].lower() != 'ubuntu':
- raise NotImplementedError('enabling a ppa is only available on ubuntu')
-
- # add ppa with add-apt-repository and update
- ppa = 'ppa:{}'.format(args.ppa)
- msg = 'enable ppa: "{}" in target'.format(ppa)
- LOG.debug(msg)
- cmd = 'add-apt-repository --yes {} && apt-get update'.format(ppa)
- image.execute(cmd, description=msg)
-
-
-def enable_repo(args, image):
- """Enable a repository in the target image.
-
- @param args: cmdline arguments, must contain --repo
- @param image: cloud_tests.image instance to operate on
- @return_value: None, may raise errors
- """
- # find enable repo command for the distro
- os_family = util.get_os_family(image.properties['os'])
- if os_family == 'debian':
- cmd = ('echo "{}" >> "/etc/apt/sources.list" '.format(args.repo) +
- '&& apt-get update')
- elif os_family == 'centos':
- cmd = 'yum-config-manager --add-repo="{}"'.format(args.repo)
- else:
- raise NotImplementedError('enable repo command not configured for '
- 'distro from family: {}'.format(os_family))
-
- msg = 'enable repo: "{}" in target'.format(args.repo)
- LOG.debug(msg)
- image.execute(cmd, description=msg)
-
-
-def setup_image(args, image):
- """Set up image as specified in args.
-
- @param args: cmdline arguments
- @param image: cloud_tests.image instance to operate on
- @return_value: tuple of results and fail count
- """
- # update the args if necessary for this image
- overrides = image.setup_overrides
- LOG.debug('updating args for setup with: %s', overrides)
- args = util.update_args(args, overrides, preserve_old=True)
-
- # mapping of setup cmdline arg name to setup function
- # represented as a tuple rather than a dict or odict as lookup by name not
- # needed, and order is important as --script and --upgrade go at the end
- handlers = (
- # arg handler description
- ('deb', install_deb, 'setup func for --deb, install deb'),
- ('rpm', install_rpm, 'setup func for --rpm, install rpm'),
- ('repo', enable_repo, 'setup func for --repo, enable repo'),
- ('ppa', enable_ppa, 'setup func for --ppa, enable ppa'),
- ('script', run_script, 'setup func for --script, run script'),
- ('upgrade', upgrade, 'setup func for --upgrade, upgrade cloud-init'),
- ('upgrade-full', upgrade_full, 'setup func for --upgrade-full'),
- )
-
- # determine which setup functions needed
- calls = [partial(stage.run_single, desc, partial(func, args, image))
- for name, func, desc in handlers if getattr(args, name, None)]
-
- try:
- data = yaml.safe_load(
- image.read_data("/etc/cloud/build.info", decode=True))
- info = ' '.join(["%s=%s" % (k, data.get(k))
- for k in ("build_name", "serial") if k in data])
- except Exception as e:
- info = "N/A (%s)" % e
-
- LOG.info('setting up image %s (info %s)', image, info)
- res = stage.run_stage(
- 'set up for {}'.format(image), calls, continue_after_error=False)
- return res
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/stage.py b/tests/cloud_tests/stage.py
deleted file mode 100644
index d64a1dcc..00000000
--- a/tests/cloud_tests/stage.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Stage a run."""
-
-import sys
-import time
-import traceback
-
-from tests.cloud_tests import LOG
-
-
-class PlatformComponent(object):
- """Context manager to safely handle platform components."""
-
- def __init__(self, get_func, preserve_instance=False):
- """Store get_<platform component> function as partial with no args.
-
- @param get_func: Callable returning an instance from the platform.
- @param preserve_instance: Boolean, when True, do not destroy instance
- after test. Used for test development.
- """
- self.get_func = get_func
- self.preserve_instance = preserve_instance
-
- def __enter__(self):
- """Create instance of platform component."""
- self.instance = self.get_func()
- return self.instance
-
- def __exit__(self, etype, value, trace):
- """Destroy instance."""
- if self.instance is not None:
- if self.preserve_instance:
- LOG.info('Preserving test instance %s', self.instance.name)
- else:
- self.instance.destroy()
-
-
-def run_single(name, call):
- """Run a single function, keeping track of results and time.
-
- @param name: name of part
- @param call: call to make
- @return_value: a tuple of result and fail count
- """
- res = {
- 'name': name,
- 'time': 0,
- 'errors': [],
- 'success': False
- }
- failed = 0
- start_time = time.time()
-
- try:
- call()
- except Exception as e:
- failed += 1
- res['errors'].append(str(e))
- LOG.error('stage part: %s encountered error: %s', name, str(e))
- trace = traceback.extract_tb(sys.exc_info()[-1])
- LOG.error('traceback:\n%s', ''.join(traceback.format_list(trace)))
-
- res['time'] = time.time() - start_time
- if failed == 0:
- res['success'] = True
-
- return res, failed
-
-
-def run_stage(parent_name, calls, continue_after_error=True):
- """Run a stage of collection, keeping track of results and failures.
-
- @param parent_name: name of stage calls are under
- @param calls: list of function call taking no params. must return a tuple
- of results and failures. may raise exceptions
- @param continue_after_error: whether or not to proceed to the next call
- after catching an exception or recording a
- failure
- @return_value: a tuple of results and failures, with result containing
- results from the function call under 'stages', and a list
- of errors (if any on this level), and elapsed time
- running stage, and the name
- """
- res = {
- 'name': parent_name,
- 'time': 0,
- 'errors': [],
- 'stages': [],
- 'success': False,
- }
- failed = 0
- start_time = time.time()
-
- for call in calls:
- try:
- (call_res, call_failed) = call()
- res['stages'].append(call_res)
- except Exception as e:
- call_failed = 1
- res['errors'].append(str(e))
- LOG.error('stage: %s encountered error: %s', parent_name, str(e))
- trace = traceback.extract_tb(sys.exc_info()[-1])
- LOG.error('traceback:\n%s', ''.join(traceback.format_list(trace)))
-
- failed += call_failed
- if call_failed and not continue_after_error:
- break
-
- res['time'] = time.time() - start_time
- if not failed:
- res['success'] = True
-
- return (res, failed)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases.yaml b/tests/cloud_tests/testcases.yaml
deleted file mode 100644
index fb9a5d27..00000000
--- a/tests/cloud_tests/testcases.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-# ============================= Base Test Config ==============================
-base_test_data:
- script_timeout: 20
- enabled: True
- required_features: []
- cloud_config: |
- #cloud-config
- collect_scripts:
- cloud-init.log: |
- #!/bin/sh
- cat /var/log/cloud-init.log
- cloud-init-output.log: |
- #!/bin/sh
- cat /var/log/cloud-init-output.log
- instance-id: |
- #!/bin/sh
- cat /run/cloud-init/.instance-id
- instance-data.json: |
- #!/bin/sh
- cat /run/cloud-init/instance-data.json
- result.json: |
- #!/bin/sh
- cat /run/cloud-init/result.json
- status.json: |
- #!/bin/sh
- cat /run/cloud-init/status.json
- package-versions: |
- #!/bin/sh
- dpkg-query --show
- build.info: |
- #!/bin/sh
- binfo=/etc/cloud/build.info
- [ -f "$binfo" ] && cat "$binfo" || echo "N/A"
- system.journal.gz: |
- #!/bin/sh
- [ -d /run/systemd ] || { echo "not systemd."; exit 0; }
- fail() { echo "ERROR:" "$@" 1>&2; exit 1; }
- journal=""
- for d in /run/log/journal /var/log/journal; do
- for f in $d/*/system.journal; do
- [ -f "$f" ] || continue
- [ -z "$journal" ] ||
- fail "multiple journal found: $f $journal."
- journal="$f"
- done
- done
- [ -f "$journal" ] || fail "no journal file found."
- gzip --to-stdout "$journal"
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/__init__.py b/tests/cloud_tests/testcases/__init__.py
deleted file mode 100644
index bb9785d3..00000000
--- a/tests/cloud_tests/testcases/__init__.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Main init."""
-
-import importlib
-import inspect
-import unittest
-
-from cloudinit.util import read_conf
-
-from tests.cloud_tests import config
-from tests.cloud_tests.testcases.base import CloudTestCase as base_test
-
-
-def discover_test(test_name):
- """Discover tests in test file for 'testname'.
-
- @return_value: list of test classes
- """
- testmod_name = 'tests.cloud_tests.testcases.{}'.format(
- config.name_sanitize(test_name))
- try:
- testmod = importlib.import_module(testmod_name)
- except NameError as e:
- raise ValueError(
- 'no test verifier found at: {}'.format(testmod_name)
- ) from e
-
- found = [mod for name, mod in inspect.getmembers(testmod)
- if (inspect.isclass(mod)
- and base_test in inspect.getmro(mod)
- and getattr(mod, '__test__', True))]
- if len(found) != 1:
- raise RuntimeError(
- "Unexpected situation, multiple tests for %s: %s" % (
- test_name, found))
-
- return found
-
-
-def get_test_class(test_name, test_data, test_conf):
- test_class = discover_test(test_name)[0]
-
- class DynamicTestSubclass(test_class):
-
- _realclass = test_class
- data = test_data
- conf = test_conf
- release_conf = read_conf(config.RELEASES_CONF)['releases']
-
- def __str__(self):
- return "%s (%s)" % (self._testMethodName,
- unittest.util.strclass(self._realclass))
-
- @classmethod
- def setUpClass(cls):
- cls.maybeSkipTest()
-
- return DynamicTestSubclass
-
-
-def get_suite(test_name, data, conf):
- """Get test suite with all tests for 'testname'.
-
- @return_value: a test suite
- """
- suite = unittest.TestSuite()
- suite.addTest(
- unittest.defaultTestLoader.loadTestsFromTestCase(
- get_test_class(test_name, data, conf)))
- return suite
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/base.py b/tests/cloud_tests/testcases/base.py
deleted file mode 100644
index 4448e0b5..00000000
--- a/tests/cloud_tests/testcases/base.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Base test case module."""
-
-import crypt
-import json
-import re
-import unittest
-
-
-from cloudinit import util as c_util
-
-SkipTest = unittest.SkipTest
-
-
-class CloudTestCase(unittest.TestCase):
- """Base test class for verifiers."""
-
- # data gets populated in get_suite.setUpClass
- data = {}
- conf = None
- _cloud_config = None
- release_conf = {} # The platform's os release configuration
-
- expected_warnings = () # Subclasses set to ignore expected WARN logs
-
- @property
- def os_cfg(self):
- return self.release_conf[self.os_name]['default']
-
- def is_distro(self, distro_name):
- return self.os_cfg['os'] == distro_name
-
- @classmethod
- def maybeSkipTest(cls):
- """Present to allow subclasses to override and raise a skipTest."""
-
- def assertPackageInstalled(self, name, version=None):
- """Check dpkg-query --show output for matching package name.
-
- @param name: package base name
- @param version: string representing a package version or part of a
- version.
- """
- pkg_out = self.get_data_file('package-versions')
- pkg_match = re.search(
- '^%s\t(?P<version>.*)$' % name, pkg_out, re.MULTILINE)
- if pkg_match:
- installed_version = pkg_match.group('version')
- if not version:
- return # Success
- if installed_version.startswith(version):
- return # Success
- raise AssertionError(
- 'Expected package version %s-%s not found. Found %s' %
- name, version, installed_version)
- raise AssertionError('Package not installed: %s' % name)
-
- def os_version_cmp(self, cmp_version):
- """Compare the version of the test to comparison_version.
-
- @param: cmp_version: Either a float or a string representing
- a release os from releases.yaml (e.g. centos66)
-
- @return: -1 when version < cmp_version, 0 when version=cmp_version and
- 1 when version > cmp_version.
- """
- version = self.release_conf[self.os_name]['default']['version']
- if isinstance(cmp_version, str):
- cmp_version = self.release_conf[cmp_version]['default']['version']
- if version < cmp_version:
- return -1
- elif version == cmp_version:
- return 0
- else:
- return 1
-
- @property
- def os_name(self):
- return self.data.get('os_name', 'UNKNOWN')
-
- @property
- def platform(self):
- return self.data.get('platform', 'UNKNOWN')
-
- @property
- def cloud_config(self):
- """Get the cloud-config used by the test."""
- if not self._cloud_config:
- self._cloud_config = c_util.load_yaml(self.conf)
- return self._cloud_config
-
- def get_config_entry(self, name):
- """Get a config entry from cloud-config ensuring that it is present."""
- if name not in self.cloud_config:
- raise AssertionError('Key "{}" not in cloud config'.format(name))
- return self.cloud_config[name]
-
- def get_data_file(self, name, decode=True):
- """Get data file failing test if it is not present."""
- if name not in self.data:
- raise AssertionError('File "{}" missing from collect data'
- .format(name))
- if not decode:
- return self.data[name]
- return self.data[name].decode('utf-8')
-
- def get_instance_id(self):
- """Get recorded instance id."""
- return self.get_data_file('instance-id').strip()
-
- def get_status_data(self, data, version=None):
- """Parse result.json and status.json like data files.
-
- @param data: data to load
- @param version: cloud-init output version, defaults to 'v1'
- @return_value: dict of data or None if missing
- """
- if not version:
- version = 'v1'
- data = json.loads(data)
- return data.get(version)
-
- def get_datasource(self):
- """Get datasource name."""
- data = self.get_status_data(self.get_data_file('result.json'))
- return data.get('datasource')
-
- def test_no_stages_errors(self):
- """Ensure that there were no errors in any stage."""
- status = self.get_status_data(self.get_data_file('status.json'))
- for stage in ('init', 'init-local', 'modules-config', 'modules-final'):
- self.assertIn(stage, status)
- self.assertEqual(len(status[stage]['errors']), 0,
- 'errors {} were encountered in stage {}'
- .format(status[stage]['errors'], stage))
- result = self.get_status_data(self.get_data_file('result.json'))
- self.assertEqual(len(result['errors']), 0)
-
- def test_no_warnings_in_log(self):
- """Unexpected warnings should not be found in the log."""
- warnings = [
- line for line in self.get_data_file('cloud-init.log').splitlines()
- if 'WARN' in line]
- joined_warnings = '\n'.join(warnings)
- for expected_warning in self.expected_warnings:
- self.assertIn(
- expected_warning, joined_warnings,
- msg="Did not find %s in cloud-init.log" % expected_warning)
- # Prune expected from discovered warnings
- warnings = [w for w in warnings if expected_warning not in w]
- self.assertEqual(
- [], warnings, msg="'WARN' found inside cloud-init.log")
-
- def test_instance_data_json_ec2(self):
- """Validate instance-data.json content by ec2 platform.
-
- This content is sourced by snapd when determining snapstore endpoints.
- We validate expected values per cloud type to ensure we don't break
- snapd.
- """
- if self.platform != 'ec2':
- raise SkipTest(
- 'Skipping ec2 instance-data.json on %s' % self.platform)
- out = self.get_data_file('instance-data.json')
- if not out:
- if self.is_distro('ubuntu') and self.os_version_cmp('bionic') >= 0:
- raise AssertionError(
- 'No instance-data.json found on %s' % self.os_name)
- raise SkipTest(
- 'Skipping instance-data.json test.'
- ' OS: %s not bionic or newer' % self.os_name)
- instance_data = json.loads(out)
- self.assertCountEqual(['merged_cfg'], instance_data['sensitive_keys'])
- ds = instance_data.get('ds', {})
- v1_data = instance_data.get('v1', {})
- metadata = ds.get('meta-data', {})
- macs = metadata.get(
- 'network', {}).get('interfaces', {}).get('macs', {})
- if not macs:
- raise AssertionError('No network data from EC2 meta-data')
- # Check meta-data items we depend on
- expected_net_keys = [
- 'public-ipv4s', 'ipv4-associations', 'local-hostname',
- 'public-hostname']
- for mac_data in macs.values():
- for key in expected_net_keys:
- self.assertIn(key, mac_data)
- self.assertIsNotNone(
- metadata.get('placement', {}).get('availability-zone'),
- 'Could not determine EC2 Availability zone placement')
- self.assertIsNotNone(
- v1_data['availability_zone'], 'expected ec2 availability_zone')
- self.assertEqual('aws', v1_data['cloud_name'])
- self.assertEqual('ec2', v1_data['platform'])
- self.assertEqual(
- 'metadata (http://169.254.169.254)', v1_data['subplatform'])
- self.assertIn('i-', v1_data['instance_id'])
- self.assertIn('ip-', v1_data['local_hostname'])
- self.assertIsNotNone(v1_data['region'], 'expected ec2 region')
- self.assertIsNotNone(
- re.match(r'\d\.\d+\.\d+-\d+-aws', v1_data['kernel_release']))
- self.assertEqual(
- 'redacted for non-root user', instance_data['merged_cfg'])
- self.assertEqual(self.os_cfg['os'], v1_data['variant'])
- self.assertEqual(self.os_cfg['os'], v1_data['distro'])
- self.assertEqual(
- self.os_cfg['os'], instance_data["sys_info"]['dist'][0],
- "Unexpected sys_info dist value")
- self.assertEqual(self.os_name, v1_data['distro_release'])
- self.assertEqual(
- str(self.os_cfg['version']), v1_data['distro_version'])
- self.assertEqual('x86_64', v1_data['machine'])
- self.assertIsNotNone(
- re.match(r'3.\d\.\d', v1_data['python_version']),
- "unexpected python version: {ver}".format(
- ver=v1_data["python_version"]))
-
- def test_instance_data_json_lxd(self):
- """Validate instance-data.json content by lxd platform.
-
- This content is sourced by snapd when determining snapstore endpoints.
- We validate expected values per cloud type to ensure we don't break
- snapd.
- """
- if self.platform != 'lxd':
- raise SkipTest(
- 'Skipping lxd instance-data.json on %s' % self.platform)
- out = self.get_data_file('instance-data.json')
- if not out:
- if self.is_distro('ubuntu') and self.os_version_cmp('bionic') >= 0:
- raise AssertionError(
- 'No instance-data.json found on %s' % self.os_name)
- raise SkipTest(
- 'Skipping instance-data.json test.'
- ' OS: %s not bionic or newer' % self.os_name)
- instance_data = json.loads(out)
- v1_data = instance_data.get('v1', {})
- self.assertCountEqual([], sorted(instance_data['base64_encoded_keys']))
- self.assertEqual('unknown', v1_data['cloud_name'])
- self.assertEqual('lxd', v1_data['platform'])
- self.assertEqual(
- 'seed-dir (/var/lib/cloud/seed/nocloud-net)',
- v1_data['subplatform'])
- self.assertIsNone(
- v1_data['availability_zone'],
- 'found unexpected lxd availability_zone %s' %
- v1_data['availability_zone'])
- self.assertIn('cloud-test', v1_data['instance_id'])
- self.assertIn('cloud-test', v1_data['local_hostname'])
- self.assertIsNone(
- v1_data['region'],
- 'found unexpected lxd region %s' % v1_data['region'])
- self.assertIsNotNone(
- re.match(r'\d\.\d+\.\d+-\d+', v1_data['kernel_release']))
- self.assertEqual(
- 'redacted for non-root user', instance_data['merged_cfg'])
- self.assertEqual(self.os_cfg['os'], v1_data['variant'])
- self.assertEqual(self.os_cfg['os'], v1_data['distro'])
- self.assertEqual(
- self.os_cfg['os'], instance_data["sys_info"]['dist'][0],
- "Unexpected sys_info dist value")
- self.assertEqual(self.os_name, v1_data['distro_release'])
- self.assertEqual(
- str(self.os_cfg['version']), v1_data['distro_version'])
- self.assertEqual('x86_64', v1_data['machine'])
- self.assertIsNotNone(
- re.match(r'3.\d\.\d', v1_data['python_version']),
- "unexpected python version: {ver}".format(
- ver=v1_data["python_version"]))
-
- def test_instance_data_json_kvm(self):
- """Validate instance-data.json content by nocloud-kvm platform.
-
- This content is sourced by snapd when determining snapstore endpoints.
- We validate expected values per cloud type to ensure we don't break
- snapd.
- """
- if self.platform != 'nocloud-kvm':
- raise SkipTest(
- 'Skipping nocloud-kvm instance-data.json on %s' %
- self.platform)
- out = self.get_data_file('instance-data.json')
- if not out:
- if self.is_distro('ubuntu') and self.os_version_cmp('bionic') >= 0:
- raise AssertionError(
- 'No instance-data.json found on %s' % self.os_name)
- raise SkipTest(
- 'Skipping instance-data.json test.'
- ' OS: %s not bionic or newer' % self.os_name)
- instance_data = json.loads(out)
- v1_data = instance_data.get('v1', {})
- self.assertCountEqual([], instance_data['base64_encoded_keys'])
- self.assertEqual('unknown', v1_data['cloud_name'])
- self.assertEqual('nocloud', v1_data['platform'])
- subplatform = v1_data['subplatform']
- self.assertIsNotNone(
- re.match(r'config-disk \(\/dev\/[a-z]{3}\)', subplatform),
- 'kvm subplatform "%s" != "config-disk (/dev/...)"' % subplatform)
- self.assertIsNone(
- v1_data['availability_zone'],
- 'found unexpected kvm availability_zone %s' %
- v1_data['availability_zone'])
- self.assertIsNotNone(
- re.match(r'[\da-f]{8}(-[\da-f]{4}){3}-[\da-f]{12}',
- v1_data['instance_id']),
- 'kvm instance_id is not a UUID: %s' % v1_data['instance_id'])
- self.assertIn('ubuntu', v1_data['local_hostname'])
- self.assertIsNone(
- v1_data['region'],
- 'found unexpected lxd region %s' % v1_data['region'])
- self.assertIsNotNone(
- re.match(r'\d\.\d+\.\d+-\d+', v1_data['kernel_release']))
- self.assertEqual(
- 'redacted for non-root user', instance_data['merged_cfg'])
- self.assertEqual(self.os_cfg['os'], v1_data['variant'])
- self.assertEqual(self.os_cfg['os'], v1_data['distro'])
- self.assertEqual(
- self.os_cfg['os'], instance_data["sys_info"]['dist'][0],
- "Unexpected sys_info dist value")
- self.assertEqual(self.os_name, v1_data['distro_release'])
- self.assertEqual(
- str(self.os_cfg['version']), v1_data['distro_version'])
- self.assertEqual('x86_64', v1_data['machine'])
- self.assertIsNotNone(
- re.match(r'3.\d\.\d', v1_data['python_version']),
- "unexpected python version: {ver}".format(
- ver=v1_data["python_version"]))
-
-
-class PasswordListTest(CloudTestCase):
- """Base password test case class."""
-
- def test_shadow_passwords(self):
- """Test shadow passwords."""
- shadow = self.get_data_file('shadow')
- users = {}
- dupes = []
- for line in shadow.splitlines():
- user, encpw = line.split(":")[0:2]
- if user in users:
- dupes.append(user)
- users[user] = encpw
-
- jane_enc = "$5$iW$XsxmWCdpwIW8Yhv.Jn/R3uk6A4UaicfW5Xp7C9p9pg."
- self.assertEqual([], dupes)
- self.assertEqual(jane_enc, users['jane'])
-
- mikey_enc = "$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89"
- self.assertEqual(mikey_enc, users['mikey'])
-
- # shadow entry is $N$salt$, so we encrypt with the same format
- # and salt and expect the result.
- tom = "mypassword123!"
- fmtsalt = users['tom'][0:users['tom'].rfind("$") + 1]
- tom_enc = crypt.crypt(tom, fmtsalt)
- self.assertEqual(tom_enc, users['tom'])
-
- harry_enc = ("$6$LF$9Z2p6rWK6TNC1DC6393ec0As.18KRAvKDbfsG"
- "JEdWN3sRQRwpdfoh37EQ3yUh69tP4GSrGW5XKHxMLiKowJgm/")
- dick_enc = "$1$ssisyfpf$YqvuJLfrrW6Cg/l53Pi1n1"
-
- # these should have been changed to random values.
- self.assertNotEqual(harry_enc, users['harry'])
- self.assertTrue(users['harry'].startswith("$"))
- self.assertNotEqual(dick_enc, users['dick'])
- self.assertTrue(users['dick'].startswith("$"))
-
- self.assertNotEqual(users['harry'], users['dick'])
-
- def test_shadow_expected_users(self):
- """Test every tom, dick, and harry user in shadow."""
- out = self.get_data_file('shadow')
- self.assertIn('tom:', out)
- self.assertIn('dick:', out)
- self.assertIn('harry:', out)
- self.assertIn('jane:', out)
- self.assertIn('mikey:', out)
-
- def test_sshd_config(self):
- """Test sshd config allows passwords."""
- out = self.get_data_file('sshd_config')
- self.assertIn('PasswordAuthentication yes', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/README.md b/tests/cloud_tests/testcases/bugs/README.md
deleted file mode 100644
index 09ce0765..00000000
--- a/tests/cloud_tests/testcases/bugs/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Bug Test Configs
-
-## purpose
-Configs that reproduce bugs filed against cloud-init. Having test configs for
-cloud-init bugs ensures that the fixes do not break in the future, and makes it
-easy to see how many systems and platforms are effected by a new bug.
-
-## structure
-Should have one test config for most bugs filed. The name of the test should
-contain ``lp`` followed by the bug number. It may also be useful to add a
-comment to each bug config with a summary copied from the bug report.
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/__init__.py b/tests/cloud_tests/testcases/bugs/__init__.py
deleted file mode 100644
index c6452f9c..00000000
--- a/tests/cloud_tests/testcases/bugs/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Test verifiers for cloud-init bugs.
-
-See configs/bugs/README.md for more information
-"""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/lp1511485.py b/tests/cloud_tests/testcases/bugs/lp1511485.py
deleted file mode 100644
index 670d3aff..00000000
--- a/tests/cloud_tests/testcases/bugs/lp1511485.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestLP1511485(base.CloudTestCase):
- """Test LP# 1511485."""
-
- def test_final_message(self):
- """Test final message exists."""
- out = self.get_data_file('cloud-init-output.log')
- self.assertIn('Final message from cloud-config', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/lp1511485.yaml b/tests/cloud_tests/testcases/bugs/lp1511485.yaml
deleted file mode 100644
index ebf9763f..00000000
--- a/tests/cloud_tests/testcases/bugs/lp1511485.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# LP Bug 1511485: final_message is silent on ubuntu-12.04.5 / cloud-init 0.6.3
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- final_message: "Final message from cloud-config"
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/lp1611074.yaml b/tests/cloud_tests/testcases/bugs/lp1611074.yaml
deleted file mode 100644
index 960679d5..00000000
--- a/tests/cloud_tests/testcases/bugs/lp1611074.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# LP Bug 1611074: Reformatting of ephemeral drive fails on resize of Azure VM
-#
-# 2016-11-18: Disabled until test written
-#
-enabled: False
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/lp1628337.py b/tests/cloud_tests/testcases/bugs/lp1628337.py
deleted file mode 100644
index a2c90481..00000000
--- a/tests/cloud_tests/testcases/bugs/lp1628337.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestLP1628337(base.CloudTestCase):
- """Test LP# 1511485."""
-
- def test_fetch_indices(self):
- """Verify no apt errors."""
- out = self.get_data_file('cloud-init-output.log')
- self.assertNotIn('W: Failed to fetch', out)
- self.assertNotIn('W: Some index files failed to download. '
- 'They have been ignored, or old ones used instead.',
- out)
-
- def test_ntp(self):
- """Verify can find ntp and install it."""
- out = self.get_data_file('cloud-init-output.log')
- self.assertNotIn('E: Unable to locate package ntp', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/bugs/lp1628337.yaml b/tests/cloud_tests/testcases/bugs/lp1628337.yaml
deleted file mode 100644
index e39b3cd8..00000000
--- a/tests/cloud_tests/testcases/bugs/lp1628337.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# LP Bug 1628337: cloud-init tries to install NTP before even configuring the archives
-#
-required_features:
- - apt
- - lsb_release
-cloud_config: |
- #cloud-config
- ntp:
- servers: ['ntp.ubuntu.com']
- apt:
- primary:
- - arches: [default]
- uri: http://us.archive.ubuntu.com/ubuntu/
-collect_sciprts:
- ntp.conf: |
- #!/bin/bash
- cat /etc/ntp.conf
- sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/README.md b/tests/cloud_tests/testcases/examples/README.md
deleted file mode 100644
index 110a223b..00000000
--- a/tests/cloud_tests/testcases/examples/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Example Test Configs
-
-## Purpose
-This folder contains example cloud configs found on
-[cloudinit.readthedocs.io](https://cloudinit.readthedocs.io/en/latest/topics/examples.html).
-Examples covered by other tests, like modules, are excluded from tests here
-to prevent duplication and reduce test time.
-
-## Structure
-One test per example test config on cloudinit.readthedocs.io
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/TODO.md b/tests/cloud_tests/testcases/examples/TODO.md
deleted file mode 100644
index cde699a7..00000000
--- a/tests/cloud_tests/testcases/examples/TODO.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Missing Examples
-
-Below lists each of the issing examples and why it is not currently added.
-
- - Chef (takes > 60 seconds to run)
- - Puppet (takes > 60 seconds to run)
- - Manage resolve.conf (lxd backend overrides changes)
- - Adding a yum repository (need centos system)
- - Register Red Hat Subscription (need centos system + subscription)
- - Adjust mount points mounted (need multiple disks)
- - Call a url when finished (need end point)
- - Reboot/poweroff when finished (how to test)
- - Disk setup (need multiple disks)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/__init__.py b/tests/cloud_tests/testcases/examples/__init__.py
deleted file mode 100644
index 39af88c2..00000000
--- a/tests/cloud_tests/testcases/examples/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Test verifiers for cloud-init examples.
-
-See configs/examples/README.md for more information
-"""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/add_apt_repositories.py b/tests/cloud_tests/testcases/examples/add_apt_repositories.py
deleted file mode 100644
index 71eede97..00000000
--- a/tests/cloud_tests/testcases/examples/add_apt_repositories.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigurePrimary(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_ubuntu_sources(self):
- """Test no default Ubuntu entries exist."""
- out = self.get_data_file('ubuntu.sources.list')
- self.assertEqual(0, int(out))
-
- def test_gatech_sources(self):
- """Test GaTech entires exist."""
- out = self.get_data_file('gatech.sources.list')
- self.assertEqual(20, int(out))
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/add_apt_repositories.yaml b/tests/cloud_tests/testcases/examples/add_apt_repositories.yaml
deleted file mode 100644
index 4b8575f7..00000000
--- a/tests/cloud_tests/testcases/examples/add_apt_repositories.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-required_features:
- - apt
-cloud_config: |
- #cloud-config
- apt:
- primary:
- - arches: [default]
- uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/"
-collect_scripts:
- ubuntu.sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep archive.ubuntu.com | wc -l
- gatech.sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list | grep -v '^#' | sed '/^\s*$/d' | grep gtlib.gatech.edu | wc -l
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/alter_completion_message.py b/tests/cloud_tests/testcases/examples/alter_completion_message.py
deleted file mode 100644
index b7b5d5e0..00000000
--- a/tests/cloud_tests/testcases/examples/alter_completion_message.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestFinalMessage(base.CloudTestCase):
- """Test cloud init module `cc_final_message`."""
-
- subs_char = '$'
-
- def get_final_message_config(self):
- """Get config for final message."""
- self.assertIn('final_message', self.cloud_config)
- return self.cloud_config['final_message']
-
- def get_final_message(self):
- """Get final message from log."""
- out = self.get_data_file('cloud-init-output.log')
- lines = len(self.get_final_message_config().splitlines())
- return '\n'.join(out.splitlines()[-1 * lines:])
-
- def test_final_message_string(self):
- """Ensure final handles regular strings."""
- for actual, config in zip(
- self.get_final_message().splitlines(),
- self.get_final_message_config().splitlines()):
- if self.subs_char not in config:
- self.assertEqual(actual, config)
-
- def test_final_message_subs(self):
- """Test variable substitution in final message."""
- # TODO: add verification of other substitutions
- patterns = {'$datasource': self.get_datasource()}
- for key, expected in patterns.items():
- index = self.get_final_message_config().splitlines().index(key)
- actual = self.get_final_message().splitlines()[index]
- self.assertEqual(actual, expected)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/alter_completion_message.yaml b/tests/cloud_tests/testcases/examples/alter_completion_message.yaml
deleted file mode 100644
index 9e154f80..00000000
--- a/tests/cloud_tests/testcases/examples/alter_completion_message.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- final_message: |
- This is my final message!
- $version
- $timestamp
- $datasource
- $uptime
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py b/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py
deleted file mode 100644
index 38540eb8..00000000
--- a/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestTrustedCA(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_cert_count_ca(self):
- """Test correct count of CAs in .crt."""
- out = self.get_data_file('cert_count_ca')
- self.assertIn('7 /etc/ssl/certs/ca-certificates.crt', out)
-
- def test_cert_count_cloudinit(self):
- """Test correct count of CAs in .pem."""
- out = self.get_data_file('cert_count_cloudinit')
- self.assertIn('7 /etc/ssl/certs/cloud-init-ca-certs.pem', out)
-
- def test_cloudinit_certs(self):
- """Test text of cert."""
- out = self.get_data_file('cloudinit_certs')
- self.assertIn('-----BEGIN CERTIFICATE-----', out)
- self.assertIn('YOUR-ORGS-TRUSTED-CA-CERT-HERE', out)
- self.assertIn('-----END CERTIFICATE-----', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.yaml b/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.yaml
deleted file mode 100644
index ad32b088..00000000
--- a/tests/cloud_tests/testcases/examples/configure_instance_trusted_ca_certificates.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- ca-certs:
- # If present and set to True, the 'remove-defaults' parameter will remove
- # all the default trusted CA certificates that are normally shipped with
- # Ubuntu.
- # This is mainly for paranoid admins - most users will not need this
- # functionality.
- remove-defaults: true
-
- # If present, the 'trusted' parameter should contain a certificate (or list
- # of certificates) to add to the system as trusted CA certificates.
- # Pay close attention to the YAML multiline list syntax. The example shown
- # here is for a list of multiline certificates.
- trusted:
- - |
- -----BEGIN CERTIFICATE-----
- YOUR-ORGS-TRUSTED-CA-CERT-HERE
- -----END CERTIFICATE-----
- - |
- -----BEGIN CERTIFICATE-----
- YOUR-ORGS-TRUSTED-CA-CERT-HERE
- -----END CERTIFICATE-----
-collect_scripts:
- cloudinit_certs: |
- #!/bin/bash
- cat /etc/ssl/certs/cloud-init-ca-certs.pem
- cert_count_ca: |
- #!/bin/bash
- wc -l /etc/ssl/certs/ca-certificates.crt
- cert_count_cloudinit: |
- #!/bin/bash
- wc -l /etc/ssl/certs/cloud-init-ca-certs.pem
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py b/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py
deleted file mode 100644
index 691a316b..00000000
--- a/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSSHKeys(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_cert_count(self):
- """Test cert count."""
- out = self.get_data_file('cert_count')
- self.assertEqual(20, int(out))
-
- def test_dsa_public(self):
- """Test DSA key has ending."""
- out = self.get_data_file('dsa_public')
- self.assertIn('ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost', out)
-
- def test_rsa_public(self):
- """Test RSA key has specific ending."""
- out = self.get_data_file('rsa_public')
- self.assertIn('PemAWthxHO18QJvWPocKJtlsDNi3 smoser@localhost', out)
-
- def test_auth_keys(self):
- """Test authorized keys has specific ending."""
- out = self.get_data_file('auth_keys')
- self.assertIn('QPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host', out)
- self.assertIn('Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.yaml b/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.yaml
deleted file mode 100644
index f3eaf3ce..00000000
--- a/tests/cloud_tests/testcases/examples/configure_instances_ssh_keys.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- ssh_authorized_keys:
- - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEA3FSyQwBI6Z+nCSjUUk8EEAnnkhXlukKoUPND/RRClWz2s5TCzIkd3Ou5+Cyz71X0XmazM3l5WgeErvtIwQMyT1KjNoMhoJMrJnWqQPOt5Q8zWd9qG7PBl9+eiH5qV7NZ mykey@host
- - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3I7VUf2l5gSn5uavROsc5HRDpZdQueUq5ozemNSj8T7enqKHOEaFoU2VoPgGEWC9RyzSQVeyD6s7APMcE82EtmW4skVEgEGSbDc1pvxzxtchBj78hJP6Cf5TCMFSXw+Fz5rF1dR23QDbN1mkHs7adr8GW4kSWqU7Q7NDwfIrJJtO7Hi42GyXtvEONHbiRPOe8stqUly7MvUoN+5kfjBM8Qqpfl2+FNhTYWpMfYdPUnE7u536WqzFmsaqJctz3gBxH9Ex7dFtrxR4qiqEr9Qtlu3xGn7Bw07/+i1D+ey3ONkZLN+LQ714cgj8fRS4Hj29SCmXp5Kt5/82cD/VN3NtHw== smoser@brickies
-
- # Send pre-generated ssh private keys to the server
- # If these are present, they will be written to /etc/ssh and
- # new random keys will not be generated
- # in addition to 'rsa' and 'dsa' as shown below, 'ecdsa' is also supported
- ssh_keys:
- rsa_private: |
- -----BEGIN RSA PRIVATE KEY-----
- MIIBxwIBAAJhAKD0YSHy73nUgysO13XsJmd4fHiFyQ+00R7VVu2iV9Qcon2LZS/x
- 1cydPZ4pQpfjEha6WxZ6o8ci/Ea/w0n+0HGPwaxlEG2Z9inNtj3pgFrYcRztfECb
- 1j6HCibZbAzYtwIBIwJgO8h72WjcmvcpZ8OvHSvTwAguO2TkR6mPgHsgSaKy6GJo
- PUJnaZRWuba/HX0KGyhz19nPzLpzG5f0fYahlMJAyc13FV7K6kMBPXTRR6FxgHEg
- L0MPC7cdqAwOVNcPY6A7AjEA1bNaIjOzFN2sfZX0j7OMhQuc4zP7r80zaGc5oy6W
- p58hRAncFKEvnEq2CeL3vtuZAjEAwNBHpbNsBYTRPCHM7rZuG/iBtwp8Rxhc9I5w
- ixvzMgi+HpGLWzUIBS+P/XhekIjPAjA285rVmEP+DR255Ls65QbgYhJmTzIXQ2T9
- luLvcmFBC6l35Uc4gTgg4ALsmXLn71MCMGMpSWspEvuGInayTCL+vEjmNBT+FAdO
- W7D4zCpI43jRS9U06JVOeSc9CDk2lwiA3wIwCTB/6uc8Cq85D9YqpM10FuHjKpnP
- REPPOyrAspdeOAV+6VKRavstea7+2DZmSUgE
- -----END RSA PRIVATE KEY-----
-
- rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEAoPRhIfLvedSDKw7XdewmZ3h8eIXJD7TRHtVW7aJX1ByifYtlL/HVzJ09nilCl+MSFrpbFnqjxyL8Rr/DSf7QcY/BrGUQbZn2Kc22PemAWthxHO18QJvWPocKJtlsDNi3 smoser@localhost
-
- dsa_private: |
- -----BEGIN DSA PRIVATE KEY-----
- MIIBuwIBAAKBgQDP2HLu7pTExL89USyM0264RCyWX/CMLmukxX0Jdbm29ax8FBJT
- pLrO8TIXVY5rPAJm1dTHnpuyJhOvU9G7M8tPUABtzSJh4GVSHlwaCfycwcpLv9TX
- DgWIpSj+6EiHCyaRlB1/CBp9RiaB+10QcFbm+lapuET+/Au6vSDp9IRtlQIVAIMR
- 8KucvUYbOEI+yv+5LW9u3z/BAoGBAI0q6JP+JvJmwZFaeCMMVxXUbqiSko/P1lsa
- LNNBHZ5/8MOUIm8rB2FC6ziidfueJpqTMqeQmSAlEBCwnwreUnGfRrKoJpyPNENY
- d15MG6N5J+z81sEcHFeprryZ+D3Ge9VjPq3Tf3NhKKwCDQ0240aPezbnjPeFm4mH
- bYxxcZ9GAoGAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI3
- 8UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC
- /QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQCFEIsKKWv
- 99iziAH0KBMVbxy03Trz
- -----END DSA PRIVATE KEY-----
-
- dsa_public: ssh-dsa AAAAB3NzaC1kc3MAAACBAM/Ycu7ulMTEvz1RLIzTbrhELJZf8Iwua6TFfQl1ubb1rHwUElOkus7xMhdVjms8AmbV1Meem7ImE69T0bszy09QAG3NImHgZVIeXBoJ/JzByku/1NcOBYilKP7oSIcLJpGUHX8IGn1GJoH7XRBwVub6Vqm4RP78C7q9IOn0hG2VAAAAFQCDEfCrnL1GGzhCPsr/uS1vbt8/wQAAAIEAjSrok/4m8mbBkVp4IwxXFdRuqJKSj8/WWxos00Ednn/ww5QibysHYULrOKJ1+54mmpMyp5CZICUQELCfCt5ScZ9GsqgmnI80Q1h3Xkwbo3kn7PzWwRwcV6muvJn4PcZ71WM+rdN/c2EorAINDTbjRo97NueM94WbiYdtjHFxn0YAAACAXmLIFSQgiAPu459rCKxT46tHJtM0QfnNiEnQLbFluefZ/yiI4DI38UzTCOXLhUA7ybmZha+D/csj15Y9/BNFuO7unzVhikCQV9DTeXX46pG4s1o23JKC/QaYWNMZ7kTRv+wWow9MhGiVdML4ZN4XnifuO5krqAybngIy66PMEoQ= smoser@localhost
-collect_scripts:
- cert_count: |
- #!/bin/bash
- ls | wc -l
- dsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_dsa_key.pub
- rsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_rsa_key.pub
- auth_keys: |
- #!/bin/bash
- cat /home/ubuntu/.ssh/authorized_keys
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/including_user_groups.py b/tests/cloud_tests/testcases/examples/including_user_groups.py
deleted file mode 100644
index 4067348d..00000000
--- a/tests/cloud_tests/testcases/examples/including_user_groups.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestUserGroups(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_group_ubuntu(self):
- """Test ubuntu group exists."""
- out = self.get_data_file('group_ubuntu')
- self.assertRegex(out, r'ubuntu:x:[0-9]{4}:')
-
- def test_group_cloud_users(self):
- """Test cloud users group exists."""
- out = self.get_data_file('group_cloud_users')
- self.assertRegex(out, r'cloud-users:x:[0-9]{4}:barfoo')
-
- def test_user_ubuntu(self):
- """Test ubuntu user exists."""
- out = self.get_data_file('user_ubuntu')
- self.assertRegex(
- out, r'ubuntu:x:[0-9]{4}:[0-9]{4}:Ubuntu:/home/ubuntu:/bin/bash')
-
- def test_user_foobar(self):
- """Test foobar user exists."""
- out = self.get_data_file('user_foobar')
- self.assertRegex(
- out, r'foobar:x:[0-9]{4}:[0-9]{4}:Foo B. Bar:/home/foobar:')
-
- def test_user_barfoo(self):
- """Test barfoo user exists."""
- out = self.get_data_file('user_barfoo')
- self.assertRegex(
- out, r'barfoo:x:[0-9]{4}:[0-9]{4}:Bar B. Foo:/home/barfoo:')
-
- def test_user_cloudy(self):
- """Test cloudy user exists."""
- out = self.get_data_file('user_cloudy')
- self.assertRegex(out, r'cloudy:x:[0-9]{3,4}:')
-
- def test_user_root_in_secret(self):
- """Test root user is in 'secret' group."""
- _user, _, groups = self.get_data_file('root_groups').partition(":")
- self.assertIn("secret", groups.split(),
- msg="User root is not in group 'secret'")
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/including_user_groups.yaml b/tests/cloud_tests/testcases/examples/including_user_groups.yaml
deleted file mode 100644
index 86e392dd..00000000
--- a/tests/cloud_tests/testcases/examples/including_user_groups.yaml
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- # Add groups to the system
- groups:
- - secret: [root]
- - cloud-users
-
- # Add users to the system. Users are added after groups are added.
- users:
- - default
- - name: foobar
- gecos: Foo B. Bar
- primary_group: foobar
- groups: users
- expiredate: '2038-01-19'
- lock_passwd: false
- passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
- - name: barfoo
- gecos: Bar B. Foo
- sudo: ALL=(ALL) NOPASSWD:ALL
- groups: [cloud-users, secret]
- lock_passwd: true
- - name: cloudy
- gecos: Magic Cloud App Daemon User
- inactive: '5'
- system: true
-collect_scripts:
- group_ubuntu: |
- #!/bin/bash
- getent group ubuntu
- group_cloud_users: |
- #!/bin/bash
- getent group cloud-users
- user_ubuntu: |
- #!/bin/bash
- getent passwd ubuntu
- user_foobar: |
- #!/bin/bash
- getent passwd foobar
- user_barfoo: |
- #!/bin/bash
- getent passwd barfoo
- user_cloudy: |
- #!/bin/bash
- getent passwd cloudy
- root_groups: |
- #!/bin/bash
- groups root
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py b/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py
deleted file mode 100644
index df133844..00000000
--- a/tests/cloud_tests/testcases/examples/install_arbitrary_packages.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestInstall(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_htop(self):
- """Verify htop installed."""
- out = self.get_data_file('htop')
- self.assertEqual(1, int(out))
-
- def test_tree(self):
- """Verify tree installed."""
- out = self.get_data_file('treeutils')
- self.assertEqual(1, int(out))
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/install_arbitrary_packages.yaml b/tests/cloud_tests/testcases/examples/install_arbitrary_packages.yaml
deleted file mode 100644
index d3980228..00000000
--- a/tests/cloud_tests/testcases/examples/install_arbitrary_packages.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- packages:
- - htop
- - tree
-collect_scripts:
- htop: |
- #!/bin/bash
- dpkg -l | grep htop | wc -l
- tree: |
- #!/bin/bash
- dpkg -l | grep tree | wc -l
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/install_run_chef_recipes.py b/tests/cloud_tests/testcases/examples/install_run_chef_recipes.py
deleted file mode 100644
index 4ec26b8f..00000000
--- a/tests/cloud_tests/testcases/examples/install_run_chef_recipes.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestChefExample(base.CloudTestCase):
- """Test chef module."""
-
- def test_chef_basic(self):
- """Test chef installed."""
- out = self.get_data_file('chef_installed')
- self.assertIn('install ok', out)
-
- # FIXME: Add more tests, and/or replace with comprehensive module tests
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/install_run_chef_recipes.yaml b/tests/cloud_tests/testcases/examples/install_run_chef_recipes.yaml
deleted file mode 100644
index 68ca95b5..00000000
--- a/tests/cloud_tests/testcases/examples/install_run_chef_recipes.yaml
+++ /dev/null
@@ -1,104 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2017-03-31: Disabled as depends on third party apt repository
-#
-enabled: False
-cloud_config: |
- #cloud-config
- # Key from https://packages.chef.io/chef.asc
- apt:
- sources:
- source1:
- source: "deb http://packages.chef.io/repos/apt/stable $RELEASE main"
- key: |
- -----BEGIN PGP PUBLIC KEY BLOCK-----
- Version: GnuPG v1.4.12 (Darwin)
- Comment: GPGTools - http://gpgtools.org
-
- mQGiBEppC7QRBADfsOkZU6KZK+YmKw4wev5mjKJEkVGlus+NxW8wItX5sGa6kdUu
- twAyj7Yr92rF+ICFEP3gGU6+lGo0Nve7KxkN/1W7/m3G4zuk+ccIKmjp8KS3qn99
- dxy64vcji9jIllVa+XXOGIp0G8GEaj7mbkixL/bMeGfdMlv8Gf2XPpp9vwCgn/GC
- JKacfnw7MpLKUHOYSlb//JsEAJqao3ViNfav83jJKEkD8cf59Y8xKia5OpZqTK5W
- ShVnNWS3U5IVQk10ZDH97Qn/YrK387H4CyhLE9mxPXs/ul18ioiaars/q2MEKU2I
- XKfV21eMLO9LYd6Ny/Kqj8o5WQK2J6+NAhSwvthZcIEphcFignIuobP+B5wNFQpe
- DbKfA/0WvN2OwFeWRcmmd3Hz7nHTpcnSF+4QX6yHRF/5BgxkG6IqBIACQbzPn6Hm
- sMtm/SVf11izmDqSsQptCrOZILfLX/mE+YOl+CwWSHhl+YsFts1WOuh1EhQD26aO
- Z84HuHV5HFRWjDLw9LriltBVQcXbpfSrRP5bdr7Wh8vhqJTPjrQnT3BzY29kZSBQ
- YWNrYWdlcyA8cGFja2FnZXNAb3BzY29kZS5jb20+iGAEExECACAFAkppC7QCGwMG
- CwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRApQKupg++Caj8sAKCOXmdG36gWji/K
- +o+XtBfvdMnFYQCfTCEWxRy2BnzLoBBFCjDSK6sJqCu0IENIRUYgUGFja2FnZXMg
- PHBhY2thZ2VzQGNoZWYuaW8+iGIEExECACIFAlQwYFECGwMGCwkIBwMCBhUIAgkK
- CwQWAgMBAh4BAheAAAoJEClAq6mD74JqX94An26z99XOHWpLN8ahzm7cp13t4Xid
- AJ9wVcgoUBzvgg91lKfv/34cmemZn7kCDQRKaQu0EAgAg7ZLCVGVTmLqBM6njZEd
- Zbv+mZbvwLBSomdiqddE6u3eH0X3GuwaQfQWHUVG2yedyDMiG+EMtCdEeeRebTCz
- SNXQ8Xvi22hRPoEsBSwWLZI8/XNg0n0f1+GEr+mOKO0BxDB2DG7DA0nnEISxwFkK
- OFJFebR3fRsrWjj0KjDxkhse2ddU/jVz1BY7Nf8toZmwpBmdozETMOTx3LJy1HZ/
- Te9FJXJMUaB2lRyluv15MVWCKQJro4MQG/7QGcIfrIZNfAGJ32DDSjV7/YO+IpRY
- IL4CUBQ65suY4gYUG4jhRH6u7H1p99sdwsg5OIpBe/v2Vbc/tbwAB+eJJAp89Zeu
- twADBQf/ZcGoPhTGFuzbkcNRSIz+boaeWPoSxK2DyfScyCAuG41CY9+g0HIw9Sq8
- DuxQvJ+vrEJjNvNE3EAEdKl/zkXMZDb1EXjGwDi845TxEMhhD1dDw2qpHqnJ2mtE
- WpZ7juGwA3sGhi6FapO04tIGacCfNNHmlRGipyq5ZiKIRq9mLEndlECr8cwaKgkS
- 0wWu+xmMZe7N5/t/TK19HXNh4tVacv0F3fYK54GUjt2FjCQV75USnmNY4KPTYLXA
- dzC364hEMlXpN21siIFgB04w+TXn5UF3B4FfAy5hevvr4DtV4MvMiGLu0oWjpaLC
- MpmrR3Ny2wkmO0h+vgri9uIP06ODWIhJBBgRAgAJBQJKaQu0AhsMAAoJEClAq6mD
- 74Jq4hIAoJ5KrYS8kCwj26SAGzglwggpvt3CAJ0bekyky56vNqoegB+y4PQVDv4K
- zA==
- =IxPr
- -----END PGP PUBLIC KEY BLOCK-----
-
- chef:
-
- # Valid values are 'gems' and 'packages' and 'omnibus'
- install_type: "packages"
-
- # Boolean: run 'install_type' code even if chef-client
- # appears already installed.
- force_install: false
-
- # Chef settings
- server_url: "https://chef.yourorg.com:4000"
-
- # Node Name
- # Defaults to the instance-id if not present
- node_name: "your-node-name"
-
- # Environment
- # Defaults to '_default' if not present
- environment: "production"
-
- # Default validation name is chef-validator
- validation_name: "yourorg-validator"
- # if validation_cert's value is "system" then it is expected
- # that the file already exists on the system.
- validation_cert: |
- -----BEGIN RSA PRIVATE KEY-----
- YOUR-ORGS-VALIDATION-KEY-HERE
- -----END RSA PRIVATE KEY-----
-
- # A run list for a first boot json
- run_list:
- - "recipe[apache2]"
- - "role[db]"
-
- # Specify a list of initial attributes used by the cookbooks
- initial_attributes:
- apache:
- prefork:
- maxclients: 100
- keepalive: "off"
-
- # if install_type is 'omnibus', change the url to download
- omnibus_url: "https://www.opscode.com/chef/install.sh"
-
-
- # Capture all subprocess output into a logfile
- # Useful for troubleshooting cloud-init issues
- output: {all: '| tee -a /var/log/cloud-init-output.log'}
-
-collect_scripts:
- chef_installed: |
- #!/bin/sh
- dpkg-query -W -f '${Status}\n' chef
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_apt_upgrade.py b/tests/cloud_tests/testcases/examples/run_apt_upgrade.py
deleted file mode 100644
index 744e49cb..00000000
--- a/tests/cloud_tests/testcases/examples/run_apt_upgrade.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestUpgrade(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_upgrade(self):
- """Test upgrade exists in apt history."""
- out = self.get_data_file('cloud-init.log')
- self.assertIn(
- '[CLOUDINIT] util.py[DEBUG]: apt-upgrade '
- '[eatmydata apt-get --option=Dpkg::Options::=--force-confold '
- '--option=Dpkg::options::=--force-unsafe-io --assume-yes --quiet '
- 'dist-upgrade] took', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_apt_upgrade.yaml b/tests/cloud_tests/testcases/examples/run_apt_upgrade.yaml
deleted file mode 100644
index 2b7eae4c..00000000
--- a/tests/cloud_tests/testcases/examples/run_apt_upgrade.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- package_upgrade: true
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_commands.py b/tests/cloud_tests/testcases/examples/run_commands.py
deleted file mode 100644
index 01d5d4fc..00000000
--- a/tests/cloud_tests/testcases/examples/run_commands.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestRunCmd(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_run_cmd(self):
- """Test run command worked."""
- out = self.get_data_file('run_cmd')
- self.assertIn('cloud-init run cmd test', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_commands.yaml b/tests/cloud_tests/testcases/examples/run_commands.yaml
deleted file mode 100644
index f80eb8ce..00000000
--- a/tests/cloud_tests/testcases/examples/run_commands.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- runcmd:
- - echo cloud-init run cmd test > /var/tmp/run_cmd
-collect_scripts:
- run_cmd: |
- #!/bin/bash
- cat /var/tmp/run_cmd
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_commands_first_boot.py b/tests/cloud_tests/testcases/examples/run_commands_first_boot.py
deleted file mode 100644
index 3f3d8f84..00000000
--- a/tests/cloud_tests/testcases/examples/run_commands_first_boot.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestBootCmd(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_bootcmd_host(self):
- """Test boot command worked."""
- out = self.get_data_file('hosts')
- self.assertIn('192.168.1.130 us.archive.ubuntu.com', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/run_commands_first_boot.yaml b/tests/cloud_tests/testcases/examples/run_commands_first_boot.yaml
deleted file mode 100644
index 7bd803db..00000000
--- a/tests/cloud_tests/testcases/examples/run_commands_first_boot.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- bootcmd:
- - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts
-collect_scripts:
- hosts: |
- #!/bin/bash
- cat /etc/hosts
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/setup_run_puppet.yaml b/tests/cloud_tests/testcases/examples/setup_run_puppet.yaml
deleted file mode 100644
index cdb1c28d..00000000
--- a/tests/cloud_tests/testcases/examples/setup_run_puppet.yaml
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as test suite fails this long running test currently
-#
-enabled: False
-cloud_config: |
- #cloud-config
- puppet:
- # Every key present in the conf object will be added to puppet.conf:
- # [name]
- # subkey=value
- #
- # For example the configuration below will have the following section
- # added to puppet.conf:
- # [puppetd]
- # server=puppetserver.example.org
- # certname=i-0123456.ip-X-Y-Z.cloud.internal
- #
- # The puppmaster ca certificate will be available in
- # /var/lib/puppet/ssl/certs/ca.pem
- conf:
- agent:
- server: "puppetserver.example.org"
- # certname supports substitutions at runtime:
- # %i: instanceid
- # Example: i-0123456
- # %f: fqdn of the machine
- # Example: ip-X-Y-Z.cloud.internal
- #
- # NB: the certname will automatically be lowercased as required by puppet
- certname: "%i.%f"
- # ca_cert is a special case. It won't be added to puppet.conf.
- # It holds the puppetserver certificate in pem format.
- # It should be a multi-line string (using the | yaml notation for
- # multi-line strings).
- # The puppetserver certificate is located in
- # /var/lib/puppet/ssl/ca/ca_crt.pem on the puppetserver host.
- #
- ca_cert: |
- -----BEGIN CERTIFICATE-----
- MIICCTCCAXKgAwIBAgIBATANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDDAJjYTAe
- Fw0xMDAyMTUxNzI5MjFaFw0xNTAyMTQxNzI5MjFaMA0xCzAJBgNVBAMMAmNhMIGf
- MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu7Q40sm47/E1Pf+r8AYb/V/FWGPgc
- b014OmNoX7dgCxTDvps/h8Vw555PdAFsW5+QhsGr31IJNI3kSYprFQcYf7A8tNWu
- 1MASW2CfaEiOEi9F1R3R4Qlz4ix+iNoHiUDTjazw/tZwEdxaQXQVLwgTGRwVa+aA
- qbutJKi93MILLwIDAQABo3kwdzA4BglghkgBhvhCAQ0EKxYpUHVwcGV0IFJ1Ynkv
- T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwDwYDVR0TAQH/BAUwAwEB/zAd
- BgNVHQ4EFgQUu4+jHB+GYE5Vxo+ol1OAhevspjAwCwYDVR0PBAQDAgEGMA0GCSqG
- SIb3DQEBBQUAA4GBAH/rxlUIjwNb3n7TXJcDJ6MMHUlwjr03BDJXKb34Ulndkpaf
- +GAlzPXWa7bO908M9I8RnPfvtKnteLbvgTK+h+zX1XCty+S2EQWk29i2AdoqOTxb
- hppiGMp0tT5Havu4aceCXiy2crVcudj3NFciy8X66SoECemW9UYDCb9T5D0d
- -----END CERTIFICATE-----
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py b/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py
deleted file mode 100644
index 7bd520f6..00000000
--- a/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestWriteFiles(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_b64(self):
- """Test b64 encoded file reads as ascii."""
- out = self.get_data_file('file_b64')
- self.assertIn('ASCII text', out)
-
- def test_binary(self):
- """Test binary file reads as executable."""
- out = self.get_data_file('file_binary')
- self.assertIn('ELF 64-bit LSB executable, x86-64, version 1', out)
-
- def test_gzip(self):
- """Test gzip file shows up as a shell script."""
- out = self.get_data_file('file_gzip')
- self.assertIn('POSIX shell script, ASCII text executable', out)
-
- def test_text(self):
- """Test text shows up as ASCII text."""
- out = self.get_data_file('file_text')
- self.assertIn('ASCII text', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.yaml b/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.yaml
deleted file mode 100644
index 6f78f994..00000000
--- a/tests/cloud_tests/testcases/examples/writing_out_arbitrary_files.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# From cloud config examples on cloudinit.readthedocs.io
-#
-# 2016-11-17: Disabled as covered by module based tests
-#
-enabled: False
-cloud_config: |
- #cloud-config
- write_files:
- - encoding: b64
- content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4
- owner: root:root
- path: /root/file_b64
- permissions: '0644'
- - content: |
- # My new /root/file_text
-
- SMBDOPTIONS="-D"
- path: /root/file_text
- - content: !!binary |
- f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAwARAAAAAAABAAAAAAAAAAJAVAAAAAAAAAAAAAEAAOAAI
- AEAAHgAdAAYAAAAFAAAAQAAAAAAAAABAAEAAAAAAAEAAQAAAAAAAwAEAAAAAAADAAQAAAAAAAAgA
- AAAAAAAAAwAAAAQAAAAAAgAAAAAAAAACQAAAAAAAAAJAAAAAAAAcAAAAAAAAABwAAAAAAAAAAQAA
- path: /root/file_binary
- permissions: '0555'
- - encoding: gzip
- content: !!binary |
- H4sIAIDb/U8C/1NW1E/KzNMvzuBKTc7IV8hIzcnJVyjPL8pJ4QIA6N+MVxsAAAA=
- path: /root/file_gzip
- permissions: '0755'
-collect_scripts:
- file_b64: |
- #!/bin/bash
- file /root/file_b64
- file_text: |
- #!/bin/bash
- file /root/file_text
- file_binary: |
- #!/bin/bash
- file /root/file_binary
- file_gzip: |
- #!/bin/bash
- file /root/file_gzip
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/main/README.md b/tests/cloud_tests/testcases/main/README.md
deleted file mode 100644
index 60346063..00000000
--- a/tests/cloud_tests/testcases/main/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Main Functionality Test Configs
-
-## purpose
-Test main features and config options of cloud-init such as logging, output
-redirection, early init and integration with init system
-
-## structure
-Should have one or more test configs for all main cloud-init output and logging
-options, and basic functionality test cases
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/main/__init__.py b/tests/cloud_tests/testcases/main/__init__.py
deleted file mode 100644
index 0a592637..00000000
--- a/tests/cloud_tests/testcases/main/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Test verifiers for cloud-init main features.
-
-See configs/main/README.md for more information
-"""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/main/command_output_simple.py b/tests/cloud_tests/testcases/main/command_output_simple.py
deleted file mode 100644
index 80a2c8d7..00000000
--- a/tests/cloud_tests/testcases/main/command_output_simple.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestCommandOutputSimple(base.CloudTestCase):
- """Test functionality of simple output redirection."""
-
- expected_warnings = ('Stdout, stderr changing to',)
-
- def test_output_file(self):
- """Ensure that the output file is not empty and has all stages."""
- data = self.get_data_file('cloud-init-test-output')
- self.assertNotEqual(len(data), 0, "specified log empty")
- self.assertEqual(self.get_config_entry('final_message'),
- data.splitlines()[-1].strip())
- # TODO: need to test that all stages redirected here
-
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/main/command_output_simple.yaml b/tests/cloud_tests/testcases/main/command_output_simple.yaml
deleted file mode 100644
index 08ca8940..00000000
--- a/tests/cloud_tests/testcases/main/command_output_simple.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Test functionality of simple output redirection
-#
-cloud_config: |
- #cloud-config
- output: { all: "| tee -a /var/log/cloud-init-test-output" }
- final_message: "should be last line in cloud-init-test-output file"
-collect_scripts:
- cloud-init-test-output: |
- #!/bin/bash
- cat /var/log/cloud-init-test-output
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/README.md b/tests/cloud_tests/testcases/modules/README.md
deleted file mode 100644
index d66101f2..00000000
--- a/tests/cloud_tests/testcases/modules/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Module Test Configs
-
-## Purpose
-Test functionality of cloud config modules. See
-[here](https://cloudinit.readthedocs.io/en/latest/topics/modules.html) for
-a full list.
-
-## Structure
-Should have one or more test configs for each module in cloudinit/config/. The
-name of the test should indicate which module the config is verifying.
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/TODO.md b/tests/cloud_tests/testcases/modules/TODO.md
deleted file mode 100644
index 9513cb2d..00000000
--- a/tests/cloud_tests/testcases/modules/TODO.md
+++ /dev/null
@@ -1,95 +0,0 @@
-# TODO
-
-The following lists complete or partially misisng modules. If a module is
-listed with nothing below it indicates that no work is completed on that
-module. If there is a list below the module name that is the remainig
-identified work.
-
-## apt_configure
-
- * apt_get_wrapper
- * What does this do? How to use it?
- * apt_get_command
- * To specify a different 'apt-get' command, set 'apt_get_command'.
- This must be a list, and the subcommand (update, upgrade) is appended to it.
- * Modify default and verify the options got passed correctly.
- * preserve sources
- * TBD
-
-## chef
-2016-11-17: Tests took > 60 seconds and test framework times out currently.
-
-## disable EC2 metadata
-
-## disk setup
-
-## emit upstart
-
-## fan
-
-## growpart
-
-## grub dpkg
-
-## landscape
-2016-11-17: Module is not working
-
-## lxd
-2016-11-17: Need a zfs backed test written
-
-## mcollective
-
-## migrator
-
-## mounts
-
-## phone home
-
-## power state change
-
-## puppet
-2016-11-17: Tests took > 60 seconds and test framework times out currently.
-
-## resizefs
-
-## resolv conf
-2016-11-17: Issues with changing resolv.conf and lxc backend.
-
-## redhat subscription
-2016-11-17: Need RH support in test framework.
-
-## rightscale userdata
-2016-11-17: Specific to RightScale cloud enviornment.
-
-## rsyslog
-
-## scripts per boot
-Not applicable to write a test for this as it specifies when something should be run.
-
-## scripts per instance
-Not applicable to write a test for this as it specifies when something should be run.
-
-## scripts per once
-Not applicable to write a test for this as it specifies when something should be run.
-
-## scripts user
-Not applicable to write a test for this as it specifies when something should be run.
-
-## scripts vendor
-Not applicable to write a test for this as it specifies when something should be run.
-
-## snap
-2019-12-19: Need to investigate
-
-## spacewalk
-
-## ssh authkey fingerprints
-The authkey_hash key does not appear to work. In fact the default claims to be md5, however syslog only shows sha256
-
-## update etc hosts
-2016-11-17: Issues with changing /etc/hosts and lxc backend.
-
-## yum add repo
-2016-11-17: Need RH support in test framework.
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/__init__.py b/tests/cloud_tests/testcases/modules/__init__.py
deleted file mode 100644
index 6ab8114d..00000000
--- a/tests/cloud_tests/testcases/modules/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Test verifiers for cloud-init cc modules.
-
-See configs/modules/README.md for more information
-"""
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_conf.py b/tests/cloud_tests/testcases/modules/apt_configure_conf.py
deleted file mode 100644
index 3bf93447..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_conf.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureConf(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_apt_conf_assumeyes(self):
- """Test config assumes true."""
- out = self.get_data_file('94cloud-init-config')
- self.assertIn('Assume-Yes "true";', out)
-
- def test_apt_conf_fixbroken(self):
- """Test config fixes broken."""
- out = self.get_data_file('94cloud-init-config')
- self.assertIn('Fix-Broken "true";', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_conf.yaml b/tests/cloud_tests/testcases/modules/apt_configure_conf.yaml
deleted file mode 100644
index de453000..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_conf.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Provide a configuration for APT
-#
-required_features:
- - apt
-cloud_config: |
- #cloud-config
- apt:
- conf: |
- APT {
- Get {
- Assume-Yes "true";
- Fix-Broken "true";
- }
- }
-collect_scripts:
- 94cloud-init-config: |
- #!/bin/bash
- cat /etc/apt/apt.conf.d/94cloud-init-config
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py b/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py
deleted file mode 100644
index eabe4607..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureDisableSuites(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_empty_sourcelist(self):
- """Test source list is empty."""
- out = self.get_data_file('sources.list')
- self.assertEqual('', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.yaml b/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.yaml
deleted file mode 100644
index 98800673..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_disable_suites.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# Disables everything in sources.list
-#
-required_features:
- - apt
- - lsb_release
-cloud_config: |
- #cloud-config
- apt:
- disable_suites:
- - $RELEASE
- - $RELEASE-updates
- - $RELEASE-backports
- - $RELEASE-security
-collect_scripts:
- sources.list: |
- #!/bin/bash
- grep -v '^#' /etc/apt/sources.list | sed '/^\s*$/d'
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_primary.py b/tests/cloud_tests/testcases/modules/apt_configure_primary.py
deleted file mode 100644
index 4950a2ef..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_primary.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigurePrimary(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_ubuntu_sources(self):
- """Test no default Ubuntu entries exist."""
- out = self.get_data_file('sources.list')
- ubuntu_source_count = len(
- [line for line in out.split('\n') if 'archive.ubuntu.com' in line])
- self.assertEqual(0, ubuntu_source_count)
-
- def test_gatech_sources(self):
- """Test GaTech entries exist."""
- out = self.get_data_file('sources.list')
- gatech_source_count = len(
- [line for line in out.split('\n') if 'gtlib.gatech.edu' in line])
- self.assertGreater(gatech_source_count, 0)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_primary.yaml b/tests/cloud_tests/testcases/modules/apt_configure_primary.yaml
deleted file mode 100644
index cc067d4f..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_primary.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Setup a custome primary sources.list
-#
-required_features:
- - apt
- - apt_src_cont
-cloud_config: |
- #cloud-config
- apt:
- primary:
- - arches:
- - default
- uri: "http://www.gtlib.gatech.edu/pub/ubuntu-releases/"
-collect_scripts:
- sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_proxy.py b/tests/cloud_tests/testcases/modules/apt_configure_proxy.py
deleted file mode 100644
index 0c61b6cc..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_proxy.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureProxy(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_proxy_config(self):
- """Test proxy options added to apt config."""
- out = self.get_data_file('90cloud-init-aptproxy')
- self.assertIn(
- 'Acquire::http::Proxy "http://squid.internal:3128";', out)
- self.assertIn(
- 'Acquire::http::Proxy "http://squid.internal:3128";', out)
- self.assertIn(
- 'Acquire::ftp::Proxy "ftp://squid.internal:3128";', out)
- self.assertIn(
- 'Acquire::https::Proxy "https://squid.internal:3128";', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_proxy.yaml b/tests/cloud_tests/testcases/modules/apt_configure_proxy.yaml
deleted file mode 100644
index be6c6f81..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_proxy.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Set apt proxy
-#
-required_features:
- - apt
-cloud_config: |
- #cloud-config
- apt:
- proxy: "http://squid.internal:3128"
- http_proxy: "http://squid.internal:3128"
- ftp_proxy: "ftp://squid.internal:3128"
- https_proxy: "https://squid.internal:3128"
-collect_scripts:
- 90cloud-init-aptproxy: |
- #!/bin/bash
- cat /etc/apt/apt.conf.d/90cloud-init-aptproxy
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_security.py b/tests/cloud_tests/testcases/modules/apt_configure_security.py
deleted file mode 100644
index 7d7e2585..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_security.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureSecurity(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_security_mirror(self):
- """Test security lines added and uncommented in source.list."""
- out = self.get_data_file('sources.list')
- self.assertEqual(6, int(out))
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_security.yaml b/tests/cloud_tests/testcases/modules/apt_configure_security.yaml
deleted file mode 100644
index 83dd51df..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_security.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Add security to sources.list
-#
-required_features:
- - apt
- - ubuntu_repos
-cloud_config: |
- #cloud-config
- apt:
- security:
- - arches:
- - default
-collect_scripts:
- sources.list: |
- #!/bin/bash
- grep -c security.ubuntu.com /etc/apt/sources.list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py
deleted file mode 100644
index d9061f3c..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_key.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureSourcesKey(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_apt_key_list(self):
- """Test key list updated."""
- out = self.get_data_file('apt_key_list')
- self.assertIn(
- '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out)
- self.assertIn('Launchpad PPA for cloud init development team', out)
-
- def test_source_list(self):
- """Test source.list updated."""
- out = self.get_data_file('sources.list')
- self.assertIn(
- 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_key.yaml b/tests/cloud_tests/testcases/modules/apt_configure_sources_key.yaml
deleted file mode 100644
index bde9398a..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_key.yaml
+++ /dev/null
@@ -1,50 +0,0 @@
-#
-# Add a sources.list entry with a given key (Debian Jessie)
-#
-required_features:
- - apt
- - lsb_release
-cloud_config: |
- #cloud-config
- apt:
- sources:
- source1:
- source: "deb http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu $RELEASE main"
- key: |
- -----BEGIN PGP PUBLIC KEY BLOCK-----
- Version: SKS 1.1.6
- Comment: Hostname: keyserver.ubuntu.com
-
- mQINBFbZRUIBEAC+A0PIKYBP9kLC4hQtRrffRS11uLo8/BdtmOdrlW0hpPHzCfKnjR3tvSEI
- lqPHG1QrrjAXKZDnZMRz+h/px7lUztvytGzHPSJd5ARUzAyjyRezUhoJ3VSCxrPqx62avuWf
- RfoJaIeHfDehL5/dTVkyiWxfVZ369ZX6JN2AgLsQTeybTQ75+2z0xPrrhnGmgh6g0qTYcAaq
- M5ONOGiqeSBX/Smjh6ALy5XkhUiFGLsI7Yluf6XSICY/x7gd6RAfgSIQrUTNMoS1sqhT4aot
- +xvOfQy8ySkfAK4NddXql6E/+ZqTmBY/Lr0YklFBy8jGT+UysfiIznPMIwbmgq5Li7BtDDtX
- b8Uyi4edPpjtextezfXYn4NVIpPL5dPZS/FXh4HpzyH0pYCfrH4QDGA7i52AGmhpiOFjJMo6
- N33sdjZHOH/2Vyp+QZaQnsdUAi1N4M6c33tQbpIScn1SY+El8z5JDA4PBzkw8HpLCi1gGoa6
- V4kfbWqXXbGAJFkLkP/vc4+pY9axOlmCkJg7xCPwhI75y1cONgovhz+BEXOzolh5KZuGbGbj
- xe0wva5DLBeIg7EQFf+99pOS7Syby3Xpm6ZbswEFV0cllK4jf/QMjtfInxobuMoI0GV0bE5l
- WlRtPCK5FnbHwxi0wPNzB/5fwzJ77r6HgPrR0OkT0lWmbUyoOQARAQABtC1MYXVuY2hwYWQg
- UFBBIGZvciBjbG91ZCBpbml0IGRldmVsb3BtZW50IHRlYW2JAjgEEwECACIFAlbZRUICGwMG
- CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEAg9Bvvk0wTfHfcP/REK5N2s1JYc69qEa9ZN
- o6oi+A7l6AYw+ZY88O5TJe7F9otv5VXCIKSUT0Vsepjgf0mtXAgf/sb2lsJn/jp7tzgov3YH
- vSrkTkRydz8xcA87gwQKePuvTLxQpftF4flrBxgSueIn5O/tPrBOxLz7EVYBc78SKg9aj9L2
- yUp+YuNevlwfZCTYeBb9r3FHaab2HcgkwqYch66+nKYfwiLuQ9NzXXm0Wn0JcEQ6pWvJscbj
- C9BdawWovfvMK5/YLfI6Btm7F4mIpQBdhSOUp/YXKmdvHpmwxMCN2QhqYK49SM7qE9aUDbJL
- arppSEBtlCLWhRBZYLTUna+BkuQ1bHz4St++XTR49Qd7vDERALpApDjB2dxPfMiBzCMwQQyq
- uy13exU8o2ETLg+dZSLfDTzrBNsBFmXlw8WW17nTISYdKeGKL+QdlUjpzdwUMMzHhAO8SmMH
- zjeSlDSRMXBJFAFSbCl7EwmMKa3yVX0zInT91fNllZ3iatAmtVdqVH/BFQfTIMH2ET7A8WzJ
- ZzVSuMRhqoKdr5AMcHuJGPUoVkVJHQA+NNvEiXSysF3faL7jmKapmUwrhpYYX2H8pf+VMu2e
- cLflKTI28dl+ZQ4Pl/aVsxrti/pzhdYy05Sn5ddtySyIkvo8L1cU5MWpbvSlFPkTstBUDLBf
- pb0uBy+g0oxJQg15
- =uy53
- -----END PGP PUBLIC KEY BLOCK-----
-collect_scripts:
- sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list.d/source1.list
- apt_key_list: |
- #!/bin/bash
- apt-key finger
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py
deleted file mode 100644
index ddc86174..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureSourcesKeyserver(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_apt_key_list(self):
- """Test specific key added."""
- out = self.get_data_file('apt_key_list')
- self.assertIn(
- '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out)
- self.assertIn('Launchpad PPA for cloud init development team', out)
-
- def test_source_list(self):
- """Test source.list updated."""
- out = self.get_data_file('sources.list')
- self.assertIn(
- 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.yaml b/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.yaml
deleted file mode 100644
index 25088135..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_keyserver.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Add a sources.list entry with a key from a keyserver
-#
-required_features:
- - apt
- - lsb_release
-cloud_config: |
- #cloud-config
- apt:
- sources:
- source1:
- keyid: 1FF0D8535EF7E719E5C81B9C083D06FBE4D304DF
- keyserver: keyserver.ubuntu.com
- source: "deb http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu $RELEASE main"
-collect_scripts:
- sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list.d/source1.list
- apt_key_list: |
- #!/bin/bash
- apt-key finger
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py
deleted file mode 100644
index cf84e056..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_list.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureSourcesList(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_sources_list(self):
- """Test sources.list includes sources."""
- out = self.get_data_file('sources.list')
-
- # Verify we have 6 entires
- self.assertEqual(6, len(out.rstrip().split('\n')))
-
- # Verify the keys generated the list correctly
- self.assertRegex(out, r'deb http:\/\/archive.ubuntu.com\/ubuntu '
- '[a-z].* main restricted')
- self.assertRegex(out, r'deb-src http:\/\/archive.ubuntu.com\/ubuntu '
- '[a-z].* main restricted')
- self.assertRegex(out, r'deb http:\/\/archive.ubuntu.com\/ubuntu '
- '[a-z].* universe restricted')
- self.assertRegex(out, r'deb-src http:\/\/archive.ubuntu.com\/ubuntu '
- '[a-z].* universe restricted')
- self.assertRegex(out, r'deb http:\/\/security.ubuntu.com\/ubuntu '
- '[a-z].*security multiverse')
- self.assertRegex(out, r'deb-src http:\/\/security.ubuntu.com\/ubuntu '
- '[a-z].*security multiverse')
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_list.yaml b/tests/cloud_tests/testcases/modules/apt_configure_sources_list.yaml
deleted file mode 100644
index 87e470c1..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_list.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Generate a sources.list
-#
-required_features:
- - apt
- - lsb_release
-cloud_config: |
- #cloud-config
- apt:
- primary:
- - arches: [default]
- uri: http://archive.ubuntu.com/ubuntu
- security:
- - arches: [default]
- uri: http://security.ubuntu.com/ubuntu
- sources_list: |
- deb $MIRROR $RELEASE main restricted
- deb-src $MIRROR $RELEASE main restricted
- deb $PRIMARY $RELEASE universe restricted
- deb-src $PRIMARY $RELEASE universe restricted
- deb $SECURITY $RELEASE-security multiverse
- deb-src $SECURITY $RELEASE-security multiverse
-collect_scripts:
- sources.list: |
- #/bin/bash
- cat /etc/apt/sources.list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py b/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py
deleted file mode 100644
index dfbdeadf..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptconfigureSourcesPPA(base.CloudTestCase):
- """Test apt-configure module."""
-
- def test_ppa(self):
- """Test specific ppa added."""
- out = self.get_data_file('sources.list')
- self.assertIn(
- 'http://ppa.launchpad.net/cloud-init-dev/test-archive/ubuntu', out)
-
- def test_ppa_key(self):
- """Test ppa key added."""
- out = self.get_data_file('apt-key')
- self.assertIn(
- '1FF0 D853 5EF7 E719 E5C8 1B9C 083D 06FB E4D3 04DF', out)
- self.assertIn('Launchpad PPA for cloud init development team', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.yaml b/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.yaml
deleted file mode 100644
index b997bcfb..00000000
--- a/tests/cloud_tests/testcases/modules/apt_configure_sources_ppa.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-#
-# Add a PPA to source.list
-#
-# NOTE: on older ubuntu releases the sources file added is named
-# 'cloud-init-dev-test-archive-trusty', without 'ubuntu' in the middle
-required_features:
- - apt
- - ppa
- - ppa_file_name
-cloud_config: |
- #cloud-config
- apt:
- sources:
- source1:
- keyid: 0165013E
- keyserver: keyserver.ubuntu.com
- source: "ppa:cloud-init-dev/test-archive"
-collect_scripts:
- sources.list: |
- #!/bin/bash
- cat /etc/apt/sources.list.d/cloud-init-dev-ubuntu-test-archive-*.list
- apt-key: |
- #!/bin/bash
- apt-key finger
- sources_full: |
- #!/bin/bash
- cat /etc/apt/sources.list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py b/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py
deleted file mode 100644
index c98eedef..00000000
--- a/tests/cloud_tests/testcases/modules/apt_pipelining_disable.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptPipeliningDisable(base.CloudTestCase):
- """Test apt-pipelining module."""
-
- def test_disable_pipelining(self):
- """Test pipelining disabled."""
- out = self.get_data_file('90cloud-init-pipelining')
- self.assertIn('Acquire::http::Pipeline-Depth "0";', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_disable.yaml b/tests/cloud_tests/testcases/modules/apt_pipelining_disable.yaml
deleted file mode 100644
index 22a31dc4..00000000
--- a/tests/cloud_tests/testcases/modules/apt_pipelining_disable.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Disable apt pipelining value
-#
-required_features:
- - apt
-cloud_config: |
- #cloud-config
- apt_pipelining: false
-collect_scripts:
- 90cloud-init-pipelining: |
- #!/bin/bash
- cat /etc/apt/apt.conf.d/90cloud-init-pipelining
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_os.py b/tests/cloud_tests/testcases/modules/apt_pipelining_os.py
deleted file mode 100644
index 2b940a66..00000000
--- a/tests/cloud_tests/testcases/modules/apt_pipelining_os.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestAptPipeliningOS(base.CloudTestCase):
- """Test apt-pipelining module."""
-
- def test_os_pipelining(self):
- """test 'os' settings does not write apt config file."""
- out = self.get_data_file('90cloud-init-pipelining_not_written')
- self.assertEqual(0, int(out))
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/apt_pipelining_os.yaml b/tests/cloud_tests/testcases/modules/apt_pipelining_os.yaml
deleted file mode 100644
index 86d5220b..00000000
--- a/tests/cloud_tests/testcases/modules/apt_pipelining_os.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Set apt pipelining value to OS, no conf written
-#
-required_features:
- - apt
-cloud_config: |
- #cloud-config
- apt_pipelining: os
-collect_scripts:
- 90cloud-init-pipelining_not_written: |
- #!/bin/bash
- ls /etc/apt/apt.conf.d/90cloud-init-pipelining | wc -l
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/bootcmd.py b/tests/cloud_tests/testcases/modules/bootcmd.py
deleted file mode 100644
index f5b86b03..00000000
--- a/tests/cloud_tests/testcases/modules/bootcmd.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestBootCmd(base.CloudTestCase):
- """Test bootcmd module."""
-
- def test_bootcmd_host(self):
- """Test boot cmd worked."""
- out = self.get_data_file('hosts')
- self.assertIn('192.168.1.130 us.archive.ubuntu.com', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/bootcmd.yaml b/tests/cloud_tests/testcases/modules/bootcmd.yaml
deleted file mode 100644
index 3a73994e..00000000
--- a/tests/cloud_tests/testcases/modules/bootcmd.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Early boot command
-#
-cloud_config: |
- #cloud-config
- bootcmd:
- - echo 192.168.1.130 us.archive.ubuntu.com > /etc/hosts
-collect_scripts:
- hosts: |
- #!/bin/bash
- cat /etc/hosts
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/byobu.py b/tests/cloud_tests/testcases/modules/byobu.py
deleted file mode 100644
index 74d0529a..00000000
--- a/tests/cloud_tests/testcases/modules/byobu.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestByobu(base.CloudTestCase):
- """Test Byobu module."""
-
- def test_byobu_installed(self):
- """Test byobu installed."""
- self.assertPackageInstalled('byobu')
-
- def test_byobu_profile_enabled(self):
- """Test byobu profile.d file exists."""
- out = self.get_data_file('byobu_profile_enabled')
- self.assertIn('/etc/profile.d/Z97-byobu.sh', out)
-
- def test_byobu_launch_exists(self):
- """Test byobu-launch exists."""
- out = self.get_data_file('byobu_launch_exists')
- self.assertIn('/usr/bin/byobu-launch', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/byobu.yaml b/tests/cloud_tests/testcases/modules/byobu.yaml
deleted file mode 100644
index d002a611..00000000
--- a/tests/cloud_tests/testcases/modules/byobu.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Install and enable byobu system wide and default user
-#
-required_features:
- - byobu
-cloud_config: |
- #cloud-config
- byobu_by_default: enable
-collect_scripts:
- byobu_profile_enabled: |
- #!/bin/bash
- ls /etc/profile.d/Z97-byobu.sh
- byobu_launch_exists: |
- #!/bin/bash
- which /usr/bin/byobu-launch
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ca_certs.py b/tests/cloud_tests/testcases/modules/ca_certs.py
deleted file mode 100644
index 6b56f639..00000000
--- a/tests/cloud_tests/testcases/modules/ca_certs.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestCaCerts(base.CloudTestCase):
- """Test ca certs module."""
-
- def test_certs_updated(self):
- """Test certs have been updated in /etc/ssl/certs."""
- out = self.get_data_file('cert_links')
- # Bionic update-ca-certificates creates less links debian #895075
- unlinked_files = []
- links = {}
- for cert_line in out.splitlines():
- if '->' in cert_line:
- fname, _sep, link = cert_line.split()
- links[fname] = link
- else:
- unlinked_files.append(cert_line)
- self.assertEqual(['ca-certificates.crt'], unlinked_files)
- self.assertEqual('cloud-init-ca-certs.pem', links['a535c1f3.0'])
- self.assertEqual(
- '/usr/share/ca-certificates/cloud-init-ca-certs.crt',
- links['cloud-init-ca-certs.pem'])
-
- def test_cert_installed(self):
- """Test line from our cert exists."""
- out = self.get_data_file('cert')
- self.assertIn('a36c744454555024e7f82edc420fd2c8', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ca_certs.yaml b/tests/cloud_tests/testcases/modules/ca_certs.yaml
deleted file mode 100644
index 2cd91551..00000000
--- a/tests/cloud_tests/testcases/modules/ca_certs.yaml
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Remove existing ca_certs and install custom ca-cert
-#
-cloud_config: |
- #cloud-config
- ca-certs:
- remove-defaults: true
- trusted:
- - |
- -----BEGIN CERTIFICATE-----
- MIIGJzCCBA+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBsjELMAkGA1UEBhMCRlIx
- DzANBgNVBAgMBkFsc2FjZTETMBEGA1UEBwwKU3RyYXNib3VyZzEYMBYGA1UECgwP
- d3d3LmZyZWVsYW4ub3JnMRAwDgYDVQQLDAdmcmVlbGFuMS0wKwYDVQQDDCRGcmVl
- bGFuIFNhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxIjAgBgkqhkiG9w0BCQEW
- E2NvbnRhY3RAZnJlZWxhbi5vcmcwHhcNMTIwNDI3MTAzMTE4WhcNMjIwNDI1MTAz
- MTE4WjB+MQswCQYDVQQGEwJGUjEPMA0GA1UECAwGQWxzYWNlMRgwFgYDVQQKDA93
- d3cuZnJlZWxhbi5vcmcxEDAOBgNVBAsMB2ZyZWVsYW4xDjAMBgNVBAMMBWFsaWNl
- MSIwIAYJKoZIhvcNAQkBFhNjb250YWN0QGZyZWVsYW4ub3JnMIICIjANBgkqhkiG
- 9w0BAQEFAAOCAg8AMIICCgKCAgEA3W29+ID6194bH6ejLrIC4hb2Ugo8v6ZC+Mrc
- k2dNYMNPjcOKABvxxEtBamnSaeU/IY7FC/giN622LEtV/3oDcrua0+yWuVafyxmZ
- yTKUb4/GUgafRQPf/eiX9urWurtIK7XgNGFNUjYPq4dSJQPPhwCHE/LKAykWnZBX
- RrX0Dq4XyApNku0IpjIjEXH+8ixE12wH8wt7DEvdO7T3N3CfUbaITl1qBX+Nm2Z6
- q4Ag/u5rl8NJfXg71ZmXA3XOj7zFvpyapRIZcPmkvZYn7SMCp8dXyXHPdpSiIWL2
- uB3KiO4JrUYvt2GzLBUThp+lNSZaZ/Q3yOaAAUkOx+1h08285Pi+P8lO+H2Xic4S
- vMq1xtLg2bNoPC5KnbRfuFPuUD2/3dSiiragJ6uYDLOyWJDivKGt/72OVTEPAL9o
- 6T2pGZrwbQuiFGrGTMZOvWMSpQtNl+tCCXlT4mWqJDRwuMGrI4DnnGzt3IKqNwS4
- Qyo9KqjMIPwnXZAmWPm3FOKe4sFwc5fpawKO01JZewDsYTDxVj+cwXwFxbE2yBiF
- z2FAHwfopwaH35p3C6lkcgP2k/zgAlnBluzACUI+MKJ/G0gv/uAhj1OHJQ3L6kn1
- SpvQ41/ueBjlunExqQSYD7GtZ1Kg8uOcq2r+WISE3Qc9MpQFFkUVllmgWGwYDuN3
- Zsez95kCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNT
- TCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFFlfyRO6G8y5qEFKikl5
- ajb2fT7XMB8GA1UdIwQYMBaAFCNsLT0+KV14uGw+quK7Lh5sh/JTMA0GCSqGSIb3
- DQEBBQUAA4ICAQAT5wJFPqervbja5+90iKxi1d0QVtVGB+z6aoAMuWK+qgi0vgvr
- mu9ot2lvTSCSnRhjeiP0SIdqFMORmBtOCFk/kYDp9M/91b+vS+S9eAlxrNCB5VOf
- PqxEPp/wv1rBcE4GBO/c6HcFon3F+oBYCsUQbZDKSSZxhDm3mj7pb67FNbZbJIzJ
- 70HDsRe2O04oiTx+h6g6pW3cOQMgIAvFgKN5Ex727K4230B0NIdGkzuj4KSML0NM
- slSAcXZ41OoSKNjy44BVEZv0ZdxTDrRM4EwJtNyggFzmtTuV02nkUj1bYYYC5f0L
- ADr6s0XMyaNk8twlWYlYDZ5uKDpVRVBfiGcq0uJIzIvemhuTrofh8pBQQNkPRDFT
- Rq1iTo1Ihhl3/Fl1kXk1WR3jTjNb4jHX7lIoXwpwp767HAPKGhjQ9cFbnHMEtkro
- RlJYdtRq5mccDtwT0GFyoJLLBZdHHMHJz0F9H7FNk2tTQQMhK5MVYwg+LIaee586
- CQVqfbscp7evlgjLW98H+5zylRHAgoH2G79aHljNKMp9BOuq6SnEglEsiWGVtu2l
- hnx8SB3sVJZHeer8f/UQQwqbAO+Kdy70NmbSaqaVtp8jOxLiidWkwSyRTsuU6D8i
- DiH5uEqBXExjrj0FslxcVKdVj5glVcSmkLwZKbEU1OKwleT/iXFhvooWhQ==
- -----END CERTIFICATE-----
-collect_scripts:
- cert_links: |
- #!/bin/bash
- # links printed <filename> -> <link target>
- # non-links printed <filename>
- for file in `ls /etc/ssl/certs`; do
- [ -h /etc/ssl/certs/$file ] && echo -n $file ' -> ' && readlink /etc/ssl/certs/$file || echo $file;
- done
- cert: |
- #!/bin/bash
- md5sum /etc/ssl/certs/ca-certificates.crt
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/debug_disable.py b/tests/cloud_tests/testcases/modules/debug_disable.py
deleted file mode 100644
index e40e4b89..00000000
--- a/tests/cloud_tests/testcases/modules/debug_disable.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestDebugDisable(base.CloudTestCase):
- """Disable debug messages."""
-
- def test_debug_disable(self):
- """Test verbose output missing from logs."""
- out = self.get_data_file('cloud-init.log')
- self.assertNotIn(
- out, r'Skipping module named [a-z].* verbose printing disabled')
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/debug_disable.yaml b/tests/cloud_tests/testcases/modules/debug_disable.yaml
deleted file mode 100644
index 63218b18..00000000
--- a/tests/cloud_tests/testcases/modules/debug_disable.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Do not run in debug mode
-#
-cloud_config: |
- #cloud-config
- debug:
- verbose: False
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/debug_enable.py b/tests/cloud_tests/testcases/modules/debug_enable.py
deleted file mode 100644
index 28d26062..00000000
--- a/tests/cloud_tests/testcases/modules/debug_enable.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestDebugEnable(base.CloudTestCase):
- """Test debug messages."""
-
- def test_debug_enable(self):
- """Test debug messages in cloud-init log."""
- out = self.get_data_file('cloud-init.log')
- self.assertIn('[DEBUG]', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/debug_enable.yaml b/tests/cloud_tests/testcases/modules/debug_enable.yaml
deleted file mode 100644
index d44147db..00000000
--- a/tests/cloud_tests/testcases/modules/debug_enable.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Run in debug mode
-#
-cloud_config: |
- #cloud-config
- debug:
- verbose: True
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/final_message.py b/tests/cloud_tests/testcases/modules/final_message.py
deleted file mode 100644
index b7b5d5e0..00000000
--- a/tests/cloud_tests/testcases/modules/final_message.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestFinalMessage(base.CloudTestCase):
- """Test cloud init module `cc_final_message`."""
-
- subs_char = '$'
-
- def get_final_message_config(self):
- """Get config for final message."""
- self.assertIn('final_message', self.cloud_config)
- return self.cloud_config['final_message']
-
- def get_final_message(self):
- """Get final message from log."""
- out = self.get_data_file('cloud-init-output.log')
- lines = len(self.get_final_message_config().splitlines())
- return '\n'.join(out.splitlines()[-1 * lines:])
-
- def test_final_message_string(self):
- """Ensure final handles regular strings."""
- for actual, config in zip(
- self.get_final_message().splitlines(),
- self.get_final_message_config().splitlines()):
- if self.subs_char not in config:
- self.assertEqual(actual, config)
-
- def test_final_message_subs(self):
- """Test variable substitution in final message."""
- # TODO: add verification of other substitutions
- patterns = {'$datasource': self.get_datasource()}
- for key, expected in patterns.items():
- index = self.get_final_message_config().splitlines().index(key)
- actual = self.get_final_message().splitlines()[index]
- self.assertEqual(actual, expected)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/final_message.yaml b/tests/cloud_tests/testcases/modules/final_message.yaml
deleted file mode 100644
index c9ed6118..00000000
--- a/tests/cloud_tests/testcases/modules/final_message.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Print a final message with various predefined variables
-#
-cloud_config: |
- #cloud-config
- final_message: |
- This is my final message!
- $version
- $timestamp
- $datasource
- $uptime
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/keys_to_console.py b/tests/cloud_tests/testcases/modules/keys_to_console.py
deleted file mode 100644
index 07f38112..00000000
--- a/tests/cloud_tests/testcases/modules/keys_to_console.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestKeysToConsole(base.CloudTestCase):
- """Test proper keys are included and excluded to console."""
-
- def test_excluded_keys(self):
- """Test excluded keys missing."""
- out = self.get_data_file('syslog')
- self.assertNotIn('(DSA)', out)
- self.assertNotIn('(ECDSA)', out)
-
- def test_expected_keys(self):
- """Test expected keys exist."""
- out = self.get_data_file('syslog')
- self.assertIn('(ED25519)', out)
- self.assertIn('(RSA)', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/keys_to_console.yaml b/tests/cloud_tests/testcases/modules/keys_to_console.yaml
deleted file mode 100644
index 5d86e739..00000000
--- a/tests/cloud_tests/testcases/modules/keys_to_console.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Hide printing of ssh key and fingerprints for specific keys
-#
-required_features:
- - syslog
-cloud_config: |
- #cloud-config
- ssh_fp_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256]
- ssh_key_console_blacklist: [ssh-dss, ssh-dsa, ecdsa-sha2-nistp256]
-collect_scripts:
- syslog: |
- #!/bin/bash
- cat /var/log/syslog
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/landscape.yaml b/tests/cloud_tests/testcases/modules/landscape.yaml
deleted file mode 100644
index ed2c37c4..00000000
--- a/tests/cloud_tests/testcases/modules/landscape.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Setup landscape client settings
-#
-# 2016-11-17: Disabled due to this not working
-#
-enabled: false
-required_features:
- - landscape
-cloud_config: |
- #cloud-conifg
- landscape:
- client:
- log_level: "info"
- url: "https://landscape.canonical.com/message-system"
- ping_url: "http://landscape.canonical.com/ping"
- data_path: "/var/lib/landscape/client"
- http_proxy: "http://my.proxy.com/foobar"
- https_proxy: "https://my.proxy.com/foobar"
- tags: "server,cloud"
- computer_title: "footitle"
- registration_key: "fookey"
- account_name: "fooaccount"
-collect_scripts:
- client.conf: |
- #!/bin/bash
- cat /etc/landscape/client.conf
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/locale.py b/tests/cloud_tests/testcases/modules/locale.py
deleted file mode 100644
index cb9e1dce..00000000
--- a/tests/cloud_tests/testcases/modules/locale.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-from cloudinit import util
-
-
-class TestLocale(base.CloudTestCase):
- """Test locale is set properly."""
-
- def test_locale(self):
- """Test locale is set properly."""
- data = util.load_shell_content(self.get_data_file('locale_default'))
- self.assertIn("LANG", data)
- self.assertEqual('en_GB.UTF-8', data['LANG'])
-
- def test_locale_a(self):
- """Test locale -a has both options."""
- out = self.get_data_file('locale_a')
- self.assertIn('en_GB.utf8', out)
- self.assertIn('en_US.utf8', out)
-
- def test_locale_gen(self):
- """Test local.gen file has all entries."""
- out = self.get_data_file('locale_gen')
- self.assertIn('en_GB.UTF-8', out)
- self.assertIn('en_US.UTF-8', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/locale.yaml b/tests/cloud_tests/testcases/modules/locale.yaml
deleted file mode 100644
index e01518a1..00000000
--- a/tests/cloud_tests/testcases/modules/locale.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Set locale to non-default option and verify
-#
-required_features:
- - engb_locale
- - locale_gen
-cloud_config: |
- #cloud-config
- locale: en_GB.UTF-8
- locale_configfile: /etc/default/locale
-collect_scripts:
- locale_default: |
- #!/bin/bash
- cat /etc/default/locale
- locale_a: |
- #!/bin/bash
- locale -a
- locale_gen: |
- #!/bin/bash
- cat /etc/locale.gen | grep -v '^#' | uniq
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/lxd_bridge.py b/tests/cloud_tests/testcases/modules/lxd_bridge.py
deleted file mode 100644
index ea545e0a..00000000
--- a/tests/cloud_tests/testcases/modules/lxd_bridge.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestLxdBridge(base.CloudTestCase):
- """Test LXD module."""
-
- @classmethod
- def maybeSkipTest(cls):
- """Skip on cosmic for two reasons:
- a.) LP: #1795036 - 'lxd init' fails on cosmic kernel.
- b.) apt install lxd installs via snap which can be slow
- as that will download core snap and lxd."""
- os_name = cls.data.get('os_name', 'UNKNOWN')
- if os_name == "cosmic":
- raise base.SkipTest('Skipping test on cosmic (LP: #1795036).')
-
- def test_lxd(self):
- """Test lxd installed."""
- out = self.get_data_file('lxd')
- self.assertIn('/lxd', out)
-
- def test_lxc(self):
- """Test lxc installed."""
- out = self.get_data_file('lxc')
- self.assertIn('/lxc', out)
-
- def test_bridge(self):
- """Test bridge config."""
- out = self.get_data_file('lxc-bridge')
- self.assertIn('lxdbr0', out)
- self.assertIn('10.100.100.1/24', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/lxd_bridge.yaml b/tests/cloud_tests/testcases/modules/lxd_bridge.yaml
deleted file mode 100644
index e6b7e76a..00000000
--- a/tests/cloud_tests/testcases/modules/lxd_bridge.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# LXD configured with directory backend and IPv4 bridge
-#
-required_features:
- - lxd
-cloud_config: |
- #cloud-config
- lxd:
- init:
- storage_backend: dir
- bridge:
- mode: new
- name: lxdbr0
- ipv4_address: 10.100.100.1
- ipv4_netmask: 24
- ipv4_dhcp_first: 10.100.100.100
- ipv4_dhcp_last: 10.100.100.200
- ipv4_nat: true
- domain: lxd
-collect_scripts:
- lxc: |
- #!/bin/bash
- which lxc
- lxd: |
- #!/bin/bash
- which lxd
- lxc-bridge: |
- #!/bin/bash
- ip addr show lxdbr0
- cat /etc/default/lxd-bridge 2>/dev/null | grep -v ^# | sort -u
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/lxd_dir.py b/tests/cloud_tests/testcases/modules/lxd_dir.py
deleted file mode 100644
index 797bafed..00000000
--- a/tests/cloud_tests/testcases/modules/lxd_dir.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestLxdDir(base.CloudTestCase):
- """Test LXD module."""
-
- @classmethod
- def maybeSkipTest(cls):
- """Skip on cosmic for two reasons:
- a.) LP: #1795036 - 'lxd init' fails on cosmic kernel.
- b.) apt install lxd installs via snap which can be slow
- as that will download core snap and lxd."""
- os_name = cls.data.get('os_name', 'UNKNOWN')
- if os_name == "cosmic":
- raise base.SkipTest('Skipping test on cosmic (LP: #1795036).')
-
- def test_lxd(self):
- """Test lxd installed."""
- out = self.get_data_file('lxd')
- self.assertIn('/lxd', out)
-
- def test_lxc(self):
- """Test lxc installed."""
- out = self.get_data_file('lxc')
- self.assertIn('/lxc', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/lxd_dir.yaml b/tests/cloud_tests/testcases/modules/lxd_dir.yaml
deleted file mode 100644
index f93a3fa7..00000000
--- a/tests/cloud_tests/testcases/modules/lxd_dir.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# LXD configured with directory backend
-#
-required_features:
- - lxd
-cloud_config: |
- #cloud-config
- lxd:
- init:
- storage_backend: dir
-collect_scripts:
- lxc: |
- #!/bin/bash
- which lxc
- lxd: |
- #!/bin/bash
- which lxd
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp.py b/tests/cloud_tests/testcases/modules/ntp.py
deleted file mode 100644
index c63cc15e..00000000
--- a/tests/cloud_tests/testcases/modules/ntp.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestNtp(base.CloudTestCase):
- """Test ntp module"""
-
- def test_ntp_installed(self):
- """Test ntp installed"""
- self.assertPackageInstalled('ntp')
-
- def test_ntp_dist_entries(self):
- """Test dist config file is empty"""
- out = self.get_data_file('ntp_conf_dist_empty')
- self.assertEqual(0, int(out))
-
- def test_ntp_entries(self):
- """Test config entries"""
- out = self.get_data_file('ntp_conf_pool_list')
- self.assertIn('pool.ntp.org iburst', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp.yaml b/tests/cloud_tests/testcases/modules/ntp.yaml
deleted file mode 100644
index 7ea0707d..00000000
--- a/tests/cloud_tests/testcases/modules/ntp.yaml
+++ /dev/null
@@ -1,22 +0,0 @@
-#
-# Emtpy NTP config to setup using defaults
-#
-cloud_config: |
- #cloud-config
- ntp:
- ntp_client: ntp
- pools: []
- servers: []
-collect_scripts:
- ntp_installed: |
- #!/bin/bash
- ntpd --version > /dev/null 2>&1
- echo $?
- ntp_conf_dist_empty: |
- #!/bin/bash
- ls /etc/ntp.conf.dist | wc -l
- ntp_conf_pool_list: |
- #!/bin/bash
- grep 'pool.ntp.org' /etc/ntp.conf | grep -v ^#
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_chrony.py b/tests/cloud_tests/testcases/modules/ntp_chrony.py
deleted file mode 100644
index 7d341773..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_chrony.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-import unittest
-
-from tests.cloud_tests.testcases import base
-
-
-class TestNtpChrony(base.CloudTestCase):
- """Test ntp module with chrony client"""
-
- def setUp(self):
- """Skip this suite of tests on lxd and artful or older."""
- if self.platform == 'lxd':
- if self.is_distro('ubuntu') and self.os_version_cmp('artful') <= 0:
- raise unittest.SkipTest(
- 'No support for chrony on containers <= artful.'
- ' LP: #1589780')
- return super(TestNtpChrony, self).setUp()
-
- def test_chrony_entries(self):
- """Test chrony config entries"""
- out = self.get_data_file('chrony_conf')
- self.assertIn('.pool.ntp.org', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_chrony.yaml b/tests/cloud_tests/testcases/modules/ntp_chrony.yaml
deleted file mode 100644
index 120735e2..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_chrony.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# ntp enabled, chrony selected, check conf file
-# as chrony won't start in a container
-#
-cloud_config: |
- #cloud-config
- ntp:
- enabled: true
- ntp_client: chrony
-collect_scripts:
- chrony_conf: |
- #!/bin/sh
- set -- /etc/chrony.conf /etc/chrony/chrony.conf
- for p in "$@"; do
- [ -e "$p" ] && { cat "$p"; exit; }
- done
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_pools.py b/tests/cloud_tests/testcases/modules/ntp_pools.py
deleted file mode 100644
index 152fd3f1..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_pools.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestNtpPools(base.CloudTestCase):
- """Test ntp module."""
-
- def test_ntp_installed(self):
- """Test ntp installed"""
- out = self.get_data_file('ntp_installed_pools')
- self.assertEqual(0, int(out))
-
- def test_ntp_dist_entries(self):
- """Test dist config file is empty"""
- out = self.get_data_file('ntp_conf_dist_pools')
- self.assertEqual(0, int(out))
-
- def test_ntp_entires(self):
- """Test config entries"""
- out = self.get_data_file('ntp_conf_pools')
- pools = self.cloud_config.get('ntp').get('pools')
- for pool in pools:
- self.assertIn('pool %s iburst' % pool, out)
-
- def test_ntpq_servers(self):
- """Test ntpq output has configured servers"""
- out = self.get_data_file('ntpq_servers')
- pools = self.cloud_config.get('ntp').get('pools')
- for pool in pools:
- self.assertIn(pool, out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_pools.yaml b/tests/cloud_tests/testcases/modules/ntp_pools.yaml
deleted file mode 100644
index 60fa0fd1..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_pools.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# NTP config using specific pools
-#
-# NOTE: lsb_release listed here because with recent cloud-init deb with
-# (LP: 1628337) resolved, cloud-init will attempt to configure archives.
-# this fails without lsb_release as UNAVAILABLE is used for $RELEASE
-required_features:
- - lsb_release
-cloud_config: |
- #cloud-config
- ntp:
- ntp_client: ntp
- pools:
- - 0.cloud-init.mypool
- - 1.cloud-init.mypool
- - 172.16.15.14
-collect_scripts:
- ntp_installed_pools: |
- #!/bin/bash
- ntpd --version > /dev/null 2>&1
- echo $?
- ntp_conf_dist_pools: |
- #!/bin/bash
- ls /etc/ntp.conf.dist | wc -l
- ntp_conf_pools: |
- #!/bin/bash
- grep '^pool' /etc/ntp.conf
- ntpq_servers: |
- #!/bin/sh
- ntpq -p -w -n
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_servers.py b/tests/cloud_tests/testcases/modules/ntp_servers.py
deleted file mode 100644
index 8d2a68b3..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_servers.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script"""
-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(0, int(out))
-
- def test_ntp_dist_entries(self):
- """Test dist config file is empty"""
- out = self.get_data_file('ntp_conf_dist_servers')
- self.assertEqual(0, int(out))
-
- def test_ntp_entries(self):
- """Test config server entries"""
- out = self.get_data_file('ntp_conf_servers')
- servers = self.cloud_config.get('ntp').get('servers')
- for server in servers:
- self.assertIn('server %s iburst' % server, out)
-
- def test_ntpq_servers(self):
- """Test ntpq output has configured servers"""
- out = self.get_data_file('ntpq_servers')
- servers = self.cloud_config.get('ntp').get('servers')
- for server in servers:
- self.assertIn(server, out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_servers.yaml b/tests/cloud_tests/testcases/modules/ntp_servers.yaml
deleted file mode 100644
index ee636679..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_servers.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# NTP config using specific servers
-#
-required_features:
- - lsb_release
-cloud_config: |
- #cloud-config
- ntp:
- ntp_client: ntp
- servers:
- - 172.16.15.14
- - 172.16.17.18
-collect_scripts:
- ntp_installed_servers: |
- #!/bin/sh
- ntpd --version > /dev/null 2>&1
- echo $?
- ntp_conf_dist_servers: |
- #!/bin/sh
- cat /etc/ntp.conf.dist | wc -l
- ntp_conf_servers: |
- #!/bin/sh
- grep '^server' /etc/ntp.conf
- ntpq_servers: |
- #!/bin/sh
- ntpq -p -w -n
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_timesyncd.py b/tests/cloud_tests/testcases/modules/ntp_timesyncd.py
deleted file mode 100644
index eca750bc..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_timesyncd.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestNtpTimesyncd(base.CloudTestCase):
- """Test ntp module with systemd-timesyncd client"""
-
- def test_timesyncd_entries(self):
- """Test timesyncd config entries"""
- out = self.get_data_file('timesyncd_conf')
- self.assertIn('.pool.ntp.org', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ntp_timesyncd.yaml b/tests/cloud_tests/testcases/modules/ntp_timesyncd.yaml
deleted file mode 100644
index ee47a741..00000000
--- a/tests/cloud_tests/testcases/modules/ntp_timesyncd.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# ntp enabled, systemd-timesyncd selected, check conf file
-# as systemd-timesyncd won't start in a container
-#
-cloud_config: |
- #cloud-config
- ntp:
- enabled: true
- ntp_client: systemd-timesyncd
-collect_scripts:
- timesyncd_conf: |
- #!/bin/sh
- cat /etc/systemd/timesyncd.conf.d/cloud-init.conf
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py b/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py
deleted file mode 100644
index fecad768..00000000
--- a/tests/cloud_tests/testcases/modules/package_update_upgrade_install.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestPackageInstallUpdateUpgrade(base.CloudTestCase):
- """Test package install update upgrade module."""
-
- def test_installed_sl(self):
- """Test sl got installed."""
- self.assertPackageInstalled('sl')
-
- def test_installed_tree(self):
- """Test tree got installed."""
- self.assertPackageInstalled('tree')
-
- def test_apt_history(self):
- """Test apt history for update command."""
- out = self.get_data_file('apt_history_cmdline')
- self.assertIn(
- 'Commandline: /usr/bin/apt-get --option=Dpkg::Options'
- '::=--force-confold --option=Dpkg::options::=--force-unsafe-io '
- '--assume-yes --quiet install sl tree', out)
-
- def test_cloud_init_output(self):
- """Test cloud-init-output for install & upgrade stuff."""
- out = self.get_data_file('cloud-init-output.log')
- self.assertIn('Setting up tree (', out)
- self.assertIn('Setting up sl (', out)
- self.assertIn('Reading package lists...', out)
- self.assertIn('Building dependency tree...', out)
- self.assertIn('Reading state information...', out)
- self.assertIn('Calculating upgrade...', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/package_update_upgrade_install.yaml b/tests/cloud_tests/testcases/modules/package_update_upgrade_install.yaml
deleted file mode 100644
index dd79e438..00000000
--- a/tests/cloud_tests/testcases/modules/package_update_upgrade_install.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Update/upgrade via apt and then install a pair of packages
-#
-# NOTE: this should not require apt feature, use 'which' rather than 'dpkg -l'
-# NOTE: the testcase for this looks for the command in history.log as
-# /usr/bin/apt-get..., which is not how it always appears. it should
-# instead look for just apt-get...
-# NOTE: this testcase should not require 'apt_up_out', and should look for a
-# call to 'apt-get upgrade' or 'apt-get dist-upgrade' in cloud-init.log
-# rather than 'Calculating upgrade...' in output
-required_features:
- - apt
- - apt_hist_fmt
- - apt_up_out
-cloud_config: |
- #cloud-config
- packages:
- - sl
- - tree
- package_update: true
- package_upgrade: true
-collect_scripts:
- apt_history_cmdline: |
- #!/bin/bash
- grep ^Commandline: /var/log/apt/history.log
- dpkg_show: |
- #!/bin/bash
- dpkg-query --show
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/runcmd.py b/tests/cloud_tests/testcases/modules/runcmd.py
deleted file mode 100644
index 9fce3062..00000000
--- a/tests/cloud_tests/testcases/modules/runcmd.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestRunCmd(base.CloudTestCase):
- """Test runcmd module."""
-
- def test_run_cmd(self):
- """Test run command worked."""
- out = self.get_data_file('run_cmd')
- self.assertIn('cloud-init run cmd test', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/runcmd.yaml b/tests/cloud_tests/testcases/modules/runcmd.yaml
deleted file mode 100644
index 8309a883..00000000
--- a/tests/cloud_tests/testcases/modules/runcmd.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Run a simple command
-#
-cloud_config: |
- #cloud-config
- runcmd:
- - echo cloud-init run cmd test > /var/tmp/run_cmd
-collect_scripts:
- run_cmd: |
- #!/bin/bash
- cat /var/tmp/run_cmd
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/seed_random_command.yaml b/tests/cloud_tests/testcases/modules/seed_random_command.yaml
deleted file mode 100644
index 6a9157eb..00000000
--- a/tests/cloud_tests/testcases/modules/seed_random_command.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Use uuid to create a random string
-#
-# 2016-11-15 Disabled as this is not working currently
-#
-enabled: False
-cloud_config: |
- #cloud-config
- random_seed:
- command: ["cat", "/proc/sys/kernel/random/uuid"]
- command_required: true
- file: /root/seed
-collect_scripts:
- seed_data: |
- #!/bin/bash
- cat /root/seed
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/seed_random_data.py b/tests/cloud_tests/testcases/modules/seed_random_data.py
deleted file mode 100644
index db433d26..00000000
--- a/tests/cloud_tests/testcases/modules/seed_random_data.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSeedRandom(base.CloudTestCase):
- """Test seed random module."""
-
- def test_random_seed_data(self):
- """Test random data passed in exists."""
- out = self.get_data_file('seed_data')
- self.assertIn('MYUb34023nD:LFDK10913jk;dfnk:Df', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/seed_random_data.yaml b/tests/cloud_tests/testcases/modules/seed_random_data.yaml
deleted file mode 100644
index a9b2c885..00000000
--- a/tests/cloud_tests/testcases/modules/seed_random_data.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Push in random raw string to set as seed
-#
-cloud_config: |
- #cloud-config
- random_seed:
- data: 'MYUb34023nD:LFDK10913jk;dfnk:Df'
- encoding: raw
- file: /root/seed
-collect_scripts:
- seed_data: |
- #!/bin/bash
- cat /root/seed
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_hostname.py b/tests/cloud_tests/testcases/modules/set_hostname.py
deleted file mode 100644
index 1dbe64c2..00000000
--- a/tests/cloud_tests/testcases/modules/set_hostname.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestHostname(base.CloudTestCase):
- """Test hostname module."""
-
- ex_hostname = "cloudinit2"
-
- def test_hostname(self):
- """Test hostname command shows correct output."""
- out = self.get_data_file('hostname')
- self.assertIn(self.ex_hostname, out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_hostname.yaml b/tests/cloud_tests/testcases/modules/set_hostname.yaml
deleted file mode 100644
index 071fb220..00000000
--- a/tests/cloud_tests/testcases/modules/set_hostname.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Set the hostname and update /etc/hosts
-#
-required_features:
- - hostname
-cloud_config: |
- #cloud-config
- hostname: cloudinit2
-
-collect_scripts:
- hosts: |
- #!/bin/bash
- grep ^127 /etc/hosts
- hostname: |
- #!/bin/bash
- hostname
- fqdn: |
- #!/bin/bash
- hostname --fqdn
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py
deleted file mode 100644
index a405b30b..00000000
--- a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests import CI_DOMAIN
-from tests.cloud_tests.testcases import base
-
-
-class TestHostnameFqdn(base.CloudTestCase):
- """Test Hostname module."""
-
- ex_hostname = "cloudinit1"
- ex_fqdn = "cloudinit2." + CI_DOMAIN
-
- def test_hostname(self):
- """Test hostname output."""
- out = self.get_data_file('hostname')
- self.assertIn(self.ex_hostname, out)
-
- def test_hostname_fqdn(self):
- """Test hostname fqdn output."""
- out = self.get_data_file('fqdn')
- self.assertIn(self.ex_fqdn, out)
-
- def test_hosts(self):
- """Test /etc/hosts file."""
- out = self.get_data_file('hosts')
- self.assertIn('127.0.1.1 %s %s' % (self.ex_fqdn, self.ex_hostname),
- out)
- self.assertIn('127.0.0.1 localhost', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.yaml b/tests/cloud_tests/testcases/modules/set_hostname_fqdn.yaml
deleted file mode 100644
index a85ee79e..00000000
--- a/tests/cloud_tests/testcases/modules/set_hostname_fqdn.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Set the hostname and update /etc/hosts
-#
-required_features:
- - hostname
-cloud_config: |
- #cloud-config
- manage_etc_hosts: true
- hostname: cloudinit1
- # this needs changing if CI_DOMAIN were updated.
- fqdn: cloudinit2.i9n.cloud-init.io
-collect_scripts:
- hosts: |
- #!/bin/bash
- grep ^127 /etc/hosts
- hostname: |
- #!/bin/bash
- hostname
- fqdn: |
- #!/bin/bash
- hostname --fqdn
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password.py b/tests/cloud_tests/testcases/modules/set_password.py
deleted file mode 100644
index a29b2261..00000000
--- a/tests/cloud_tests/testcases/modules/set_password.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestPassword(base.CloudTestCase):
- """Test password module."""
-
- # TODO add test to make sure password is actually "password"
-
- def test_shadow(self):
- """Test ubuntu user in shadow."""
- out = self.get_data_file('shadow')
- self.assertIn('ubuntu:', out)
-
- def test_sshd_config(self):
- """Test sshd config allows passwords."""
- out = self.get_data_file('sshd_config')
- self.assertIn('PasswordAuthentication yes', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password.yaml b/tests/cloud_tests/testcases/modules/set_password.yaml
deleted file mode 100644
index 04d7c58a..00000000
--- a/tests/cloud_tests/testcases/modules/set_password.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Set password of default user
-#
-required_features:
- - ubuntu_user
-cloud_config: |
- #cloud-config
- password: password
- chpasswd: { expire: False }
- ssh_pwauth: True
-collect_scripts:
- shadow: |
- #!/bin/bash
- cat /etc/shadow
- sshd_config: |
- #!/bin/bash
- grep '^PasswordAuth' /etc/ssh/sshd_config
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_expire.py b/tests/cloud_tests/testcases/modules/set_password_expire.py
deleted file mode 100644
index 967aca7b..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_expire.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestPasswordExpire(base.CloudTestCase):
- """Test password module."""
-
- def test_shadow(self):
- """Test user frozen in shadow."""
- out = self.get_data_file('shadow')
- self.assertIn('harry:!:', out)
- self.assertIn('dick:!:', out)
- self.assertIn('tom:!:', out)
- self.assertIn('harry:!:', out)
-
- def test_sshd_config(self):
- """Test sshd config allows passwords."""
- out = self.get_data_file('sshd_config')
- self.assertIn('PasswordAuthentication yes', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_expire.yaml b/tests/cloud_tests/testcases/modules/set_password_expire.yaml
deleted file mode 100644
index ba6344b9..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_expire.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# Expire password for all users
-#
-required_features:
- - sshd
-cloud_config: |
- #cloud-config
- chpasswd: { expire: True }
- ssh_pwauth: yes
- users:
- - default
- - name: tom
- password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE.
- lock_passwd: false
- - name: dick
- password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE.
- lock_passwd: false
- - name: harry
- password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE.
- lock_passwd: false
- - name: jane
- password: $1$xyz$sPMsLNmf66Ohl.ol6JvzE.
- lock_passwd: false
-collect_scripts:
- shadow: |
- #!/bin/bash
- cat /etc/shadow
- sshd_config: |
- #!/bin/bash
- grep '^PasswordAuth' /etc/ssh/sshd_config
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_list.py b/tests/cloud_tests/testcases/modules/set_password_list.py
deleted file mode 100644
index 375cd27d..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_list.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestPasswordList(base.PasswordListTest, base.CloudTestCase):
- """Test password setting via list in chpasswd/list."""
-
- __test__ = True
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_list.yaml b/tests/cloud_tests/testcases/modules/set_password_list.yaml
deleted file mode 100644
index fd3e1e44..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_list.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Set password of list of users
-#
-cloud_config: |
- #cloud-config
- ssh_pwauth: yes
- users:
- - default
- - name: tom
- # md5 gotomgo
- passwd: "$1$S7$tT1BEDIYrczeryDQJfdPe0"
- lock_passwd: false
- - name: dick
- # md5 gocubsgo
- passwd: "$1$ssisyfpf$YqvuJLfrrW6Cg/l53Pi1n1"
- lock_passwd: false
- - name: harry
- # sha512 goharrygo
- passwd: "$6$LF$9Z2p6rWK6TNC1DC6393ec0As.18KRAvKDbfsGJEdWN3sRQRwpdfoh37EQ3yUh69tP4GSrGW5XKHxMLiKowJgm/"
- lock_passwd: false
- - name: jane
- # sha256 gojanego
- passwd: "$5$iW$XsxmWCdpwIW8Yhv.Jn/R3uk6A4UaicfW5Xp7C9p9pg."
- lock_passwd: false
- - name: "mikey"
- lock_passwd: false
- chpasswd:
- list:
- - tom:mypassword123!
- - dick:RANDOM
- - harry:RANDOM
- - mikey:$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89
-collect_scripts:
- shadow: |
- #!/bin/bash
- cat /etc/shadow
- sshd_config: |
- #!/bin/bash
- grep '^PasswordAuth' /etc/ssh/sshd_config
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_list_string.py b/tests/cloud_tests/testcases/modules/set_password_list_string.py
deleted file mode 100644
index 8c2634c5..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_list_string.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestPasswordListString(base.PasswordListTest, base.CloudTestCase):
- """Test password setting via string in chpasswd/list."""
-
- __test__ = True
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/set_password_list_string.yaml b/tests/cloud_tests/testcases/modules/set_password_list_string.yaml
deleted file mode 100644
index e9fe54b0..00000000
--- a/tests/cloud_tests/testcases/modules/set_password_list_string.yaml
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Set password of list of users as a string
-#
-cloud_config: |
- #cloud-config
- ssh_pwauth: yes
- users:
- - default
- - name: tom
- # md5 gotomgo
- passwd: "$1$S7$tT1BEDIYrczeryDQJfdPe0"
- lock_passwd: false
- - name: dick
- # md5 gocubsgo
- passwd: "$1$ssisyfpf$YqvuJLfrrW6Cg/l53Pi1n1"
- lock_passwd: false
- - name: harry
- # sha512 goharrygo
- passwd: "$6$LF$9Z2p6rWK6TNC1DC6393ec0As.18KRAvKDbfsGJEdWN3sRQRwpdfoh37EQ3yUh69tP4GSrGW5XKHxMLiKowJgm/"
- lock_passwd: false
- - name: jane
- # sha256 gojanego
- passwd: "$5$iW$XsxmWCdpwIW8Yhv.Jn/R3uk6A4UaicfW5Xp7C9p9pg."
- lock_passwd: false
- - name: "mikey"
- lock_passwd: false
- chpasswd:
- list: |
- tom:mypassword123!
- dick:RANDOM
- harry:RANDOM
- mikey:$5$xZ$B2YGGEx2AOf4PeW48KC6.QyT1W2B4rZ9Qbltudtha89
-collect_scripts:
- shadow: |
- #!/bin/bash
- cat /etc/shadow
- sshd_config: |
- #!/bin/bash
- grep '^PasswordAuth' /etc/ssh/sshd_config
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/snap.py b/tests/cloud_tests/testcases/modules/snap.py
deleted file mode 100644
index ff68abbe..00000000
--- a/tests/cloud_tests/testcases/modules/snap.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script"""
-from tests.cloud_tests.testcases import base
-
-
-class TestSnap(base.CloudTestCase):
- """Test snap module"""
-
- def test_snappy_version(self):
- """Expect hello-world and core snaps are installed."""
- out = self.get_data_file('snaplist')
- self.assertIn('core', out)
- self.assertIn('hello-world', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/snap.yaml b/tests/cloud_tests/testcases/modules/snap.yaml
deleted file mode 100644
index 322199c3..00000000
--- a/tests/cloud_tests/testcases/modules/snap.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Install snappy
-#
-# Aug 23, 2018: Disabled due to requiring a proxy for testing
-# tests do not handle the proxy well at this time.
-enabled: False
-required_features:
- - snap
-cloud_config: |
- #cloud-config
- package_update: true
- snap:
- squashfuse_in_container: true
- commands:
- - snap install hello-world
-collect_scripts:
- snaplist: |
- #!/bin/bash
- snap list
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py
deleted file mode 100644
index 02935447..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSshKeyFingerprintsDisable(base.CloudTestCase):
- """Test ssh key fingerprints module."""
-
- def test_cloud_init_log(self):
- """Verify disabled."""
- out = self.get_data_file('cloud-init.log')
- self.assertIn('Skipping module named ssh-authkey-fingerprints, '
- 'logging of SSH fingerprints disabled', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.yaml b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.yaml
deleted file mode 100644
index d93893e2..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_disable.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Disable fingerprint printing
-#
-required_features:
- - syslog
-cloud_config: |
- #cloud-config
- no_ssh_fingerprints: true
-collect_scripts:
- syslog: |
- #!/bin/bash
- cat /var/log/syslog
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py
deleted file mode 100644
index 3510e75a..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSshKeyFingerprintsEnable(base.CloudTestCase):
- """Test ssh key fingerprints module."""
-
- def test_syslog(self):
- """Verify output of syslog."""
- out = self.get_data_file('syslog')
- self.assertRegex(out, r'256 SHA256:.*(ECDSA)')
- self.assertRegex(out, r'256 SHA256:.*(ED25519)')
- self.assertNotRegex(out, r'1024 SHA256:.*(DSA)')
- self.assertNotRegex(out, r'2048 SHA256:.*(RSA)')
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.yaml b/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.yaml
deleted file mode 100644
index 9f5dc34a..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_auth_key_fingerprints_enable.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-#
-# Print auth keys with different hash than md5
-#
-# NOTE: testcase checks for '256 SHA256:.*(ECDSA)' on output line on trusty
-# this fails as line in output reads '256:.*(ECDSA)'
-required_features:
- - syslog
- - ssh_key_fmt
-cloud_config: |
- #cloud-config
- ssh_genkeytypes:
- - ecdsa
- - ed25519
- ssh_authorized_keys:
- - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXW9Gg5H7ehjdSc6qDzwNtgCy94XYHhEYlXZMO2+FJrH3wfHGiMfCwOHxcOMt2QiXItULthdeQWS9QjBSSjVRXf6731igFrqPFyS9qBlOQ5D29C4HBXFnQggGVpBNJ82IRJv7szbbe/vpgLBP4kttUza9Dr4e1YM1ln4PRnjfXea6T0m+m1ixNb5432pTXlqYOnNOxSIm1gHgMLxPuDrJvQERDKrSiKSjIdyC9Jd8t2e1tkNLY0stmckVRbhShmcJvlyofHWbc2Ca1mmtP7MlS1VQnfLkvU1IrFwkmaQmaggX6WR6coRJ6XFXdWcq/AI2K6GjSnl1dnnCxE8VCEXBlXgFzad+PMSG4yiL5j8Oo1ZVpkTdgBnw4okGqTYCXyZg6X00As9IBNQfZMFlQXlIo4FiWgj3CO5QHQOyOX6FuEumaU13GnERrSSdp9tCs1Qm3/DG2RSCQBWTfcgMcStIvKqvJ3IjFn0vGLvI3Ampnq9q1SHwmmzAPSdzcMA76HyMUA5VWaBvWHlUxzIM6unxZASnwvuCzpywSEB5J2OF+p6H+cStJwQ32XwmOG8pLp1srlVWpqZI58Du/lzrkPqONphoZx0LDV86w7RUz1ksDzAdcm0tvmNRFMN1a0frDs506oA3aWK0oDk4Nmvk8sXGTYYw3iQSkOvDUUlIsqdaO+w==
-collect_scripts:
- syslog: |
- #!/bin/bash
- cat /var/log/syslog
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_import_id.py b/tests/cloud_tests/testcases/modules/ssh_import_id.py
deleted file mode 100644
index ef156f47..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_import_id.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSshImportId(base.CloudTestCase):
- """Test ssh import id module."""
-
- def test_authorized_keys(self):
- """Test that ssh keys were imported."""
- out = self.get_data_file('auth_keys_ubuntu')
-
- self.assertIn('# ssh-import-id gh:powersj', out)
- self.assertIn('# ssh-import-id lp:smoser', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_import_id.yaml b/tests/cloud_tests/testcases/modules/ssh_import_id.yaml
deleted file mode 100644
index b62d3f69..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_import_id.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Import a user's ssh key via gh or lp
-#
-required_features:
- - ubuntu_user
- - sudo
-cloud_config: |
- #cloud-config
- ssh_import_id:
- - gh:powersj
- - lp:smoser
-collect_scripts:
- auth_keys_ubuntu: |
- #!/bin/bash
- cat /home/ubuntu/.ssh/authorized_keys
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_generate.py b/tests/cloud_tests/testcases/modules/ssh_keys_generate.py
deleted file mode 100644
index b68f5565..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_keys_generate.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSshKeysGenerate(base.CloudTestCase):
- """Test ssh keys module."""
-
- # TODO: Check cloud-init-output for the correct keys being generated
-
- def test_dsa_public(self):
- """Test dsa public key not generated."""
- out = self.get_data_file('dsa_public')
- self.assertEqual('', out)
-
- def test_dsa_private(self):
- """Test dsa private key not generated."""
- out = self.get_data_file('dsa_private')
- self.assertEqual('', out)
-
- def test_rsa_public(self):
- """Test rsa public key not generated."""
- out = self.get_data_file('rsa_public')
- self.assertEqual('', out)
-
- def test_rsa_private(self):
- """Test rsa public key not generated."""
- out = self.get_data_file('rsa_private')
- self.assertEqual('', out)
-
- def test_ecdsa_public(self):
- """Test ecdsa public key generated."""
- out = self.get_data_file('ecdsa_public')
- self.assertIsNotNone(out)
-
- def test_ecdsa_private(self):
- """Test ecdsa public key generated."""
- out = self.get_data_file('ecdsa_private')
- self.assertIsNotNone(out)
-
- def test_ed25519_public(self):
- """Test ed25519 public key generated."""
- out = self.get_data_file('ed25519_public')
- self.assertIsNotNone(out)
-
- def test_ed25519_private(self):
- """Test ed25519 public key generated."""
- out = self.get_data_file('ed25519_private')
- self.assertIsNotNone(out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_generate.yaml b/tests/cloud_tests/testcases/modules/ssh_keys_generate.yaml
deleted file mode 100644
index 0a7adf62..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_keys_generate.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# SSH keys generated using cloud-init
-#
-required_features:
- - ubuntu_user
-cloud_config: |
- #cloud-config
- ssh_genkeytypes:
- - ecdsa
- - ed25519
- authkey_hash: sha512
-collect_scripts:
- dsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_dsa_key.pub
- dsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_dsa_key
- rsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_rsa_key.pub
- rsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_rsa_key
- ecdsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ecdsa_key.pub
- ecdsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ecdsa_key
- ed25519_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ed25519_key.pub
- ed25519_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ed25519_key
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_provided.py b/tests/cloud_tests/testcases/modules/ssh_keys_provided.py
deleted file mode 100644
index add3f469..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_keys_provided.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestSshKeysProvided(base.CloudTestCase):
- """Test ssh keys module."""
-
- def test_dsa_public(self):
- """Test dsa public key passed in."""
- out = self.get_data_file('dsa_public')
- self.assertIn('AAAAB3NzaC1kc3MAAACBAPkWy1zbchVIN7qTgM0/yyY8q4RZS8c'
- 'NM4ZpeuE5UB/Nnr6OSU/nmbO8LuM', out)
-
- def test_dsa_private(self):
- """Test dsa private key passed in."""
- out = self.get_data_file('dsa_private')
- self.assertIn('MIIBuwIBAAKBgQD5Fstc23IVSDe6k4DNP8smPKuEWUvHDTOGaXr'
- 'hOVAfzZ6+jklP', out)
-
- def test_rsa_public(self):
- """Test rsa public key passed in."""
- out = self.get_data_file('rsa_public')
- self.assertIn('AAAAB3NzaC1yc2EAAAADAQABAAABAQC0/Ho+o3eJISydO2JvIgT'
- 'LnZOtrxPl+fSvJfKDjoOLY0HB2eOjy2s2/2N6d9X9SGZ4', out)
-
- def test_rsa_private(self):
- """Test rsa public key passed in."""
- out = self.get_data_file('rsa_private')
- self.assertIn('4DOkqNiUGl80Zp1RgZNohHUXlJMtAbrIlAVEk+mTmg7vjfyp2un'
- 'RQvLZpMRdywBm', out)
-
- def test_ecdsa_public(self):
- """Test ecdsa public key passed in."""
- out = self.get_data_file('ecdsa_public')
- self.assertIn('AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAAB'
- 'BBFsS5Tvky/IC/dXhE/afxxU', out)
-
- def test_ecdsa_private(self):
- """Test ecdsa public key passed in."""
- out = self.get_data_file('ecdsa_private')
- self.assertIn('AwEHoUQDQgAEWxLlO+TL8gL91eET9p/HFQbqR1A691AkJgZk3jY'
- '5mpZqxgX4vcgb', out)
-
- def test_ed25519_public(self):
- """Test ed25519 public key passed in."""
- out = self.get_data_file('ed25519_public')
- self.assertIn('AAAAC3NzaC1lZDI1NTE5AAAAINudAZSu4vjZpVWzId5pXmZg1M6'
- 'G15dqjQ2XkNVOEnb5', out)
-
- def test_ed25519_private(self):
- """Test ed25519 public key passed in."""
- out = self.get_data_file('ed25519_private')
- self.assertIn('XAAAAAtzc2gtZWQyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNT'
- 'OhteXao0Nl5DVThJ2+Q', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/ssh_keys_provided.yaml b/tests/cloud_tests/testcases/modules/ssh_keys_provided.yaml
deleted file mode 100644
index 41f63550..00000000
--- a/tests/cloud_tests/testcases/modules/ssh_keys_provided.yaml
+++ /dev/null
@@ -1,99 +0,0 @@
-#
-# SSH keys provided via cloud config
-#
-enabled: False
-required_features:
- - ubuntu_user
- - sudo
-cloud_config: |
- #cloud-config
- disable_root: false
- ssh_authorized_keys:
- - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDXW9Gg5H7ehjdSc6qDzwNtgCy94XYHhEYlXZMO2+FJrH3wfHGiMfCwOHxcOMt2QiXItULthdeQWS9QjBSSjVRXf6731igFrqPFyS9qBlOQ5D29C4HBXFnQggGVpBNJ82IRJv7szbbe/vpgLBP4kttUza9Dr4e1YM1ln4PRnjfXea6T0m+m1ixNb5432pTXlqYOnNOxSIm1gHgMLxPuDrJvQERDKrSiKSjIdyC9Jd8t2e1tkNLY0stmckVRbhShmcJvlyofHWbc2Ca1mmtP7MlS1VQnfLkvU1IrFwkmaQmaggX6WR6coRJ6XFXdWcq/AI2K6GjSnl1dnnCxE8VCEXBlXgFzad+PMSG4yiL5j8Oo1ZVpkTdgBnw4okGqTYCXyZg6X00As9IBNQfZMFlQXlIo4FiWgj3CO5QHQOyOX6FuEumaU13GnERrSSdp9tCs1Qm3/DG2RSCQBWTfcgMcStIvKqvJ3IjFn0vGLvI3Ampnq9q1SHwmmzAPSdzcMA76HyMUA5VWaBvWHlUxzIM6unxZASnwvuCzpywSEB5J2OF+p6H+cStJwQ32XwmOG8pLp1srlVWpqZI58Du/lzrkPqONphoZx0LDV86w7RUz1ksDzAdcm0tvmNRFMN1a0frDs506oA3aWK0oDk4Nmvk8sXGTYYw3iQSkOvDUUlIsqdaO+w==
- ssh_keys:
- rsa_private: |
- -----BEGIN RSA PRIVATE KEY-----
- MIIEowIBAAKCAQEAtPx6PqN3iSEsnTtibyIEy52Tra8T5fn0ryXyg46Di2NBwdnj
- o8trNv9jenfV/UhmePl58lXjT43wV8OCMl6KsYXyBdegM35NNtono4I4mLLKFMR9
- 9TOtDn6iYcaNenVhF3ZCj9Z2nNOlTrdc0uchHqKMrxLjCRCUrL91Uf+xioTF901Y
- RM+ZqC5lT92yAL76F4qPF+Lq1QtUfNfUIwwvOp5ccDZLPxij0YvyBzubYye9hJHu
- yjbJv78R4JHV+L2WhzSoX3W/6WrxVzeXqFGqH894ccOaC/7tnqSP6V8lIQ6fE2+c
- DurJcpM3CJRgkndGHjtU55Y71YkcdLksSMvezQIDAQABAoIBAQCrU4IJP8dNeaj5
- IpkY6NQvR/jfZqfogYi+MKb1IHin/4rlDfUvPcY9pt8ttLlObjYK+OcWn3Vx/sRw
- 4DOkqNiUGl80Zp1RgZNohHUXlJMtAbrIlAVEk+mTmg7vjfyp2unRQvLZpMRdywBm
- lq95OrCghnG03aUsFJUZPpi5ydnwbA12ma+KHkG0EzaVlhA7X9N6z0K6U+zue2gl
- goMLt/MH0rsYawkHrwiwXaIFQeyV4MJP0vmrZLbFk1bycu9X/xPtTYotWyWo4eKA
- cb05uu04qwexkKHDM0KXtT0JecbTo2rOefFo8Uuab6uJY+fEHNocZ+v1vLA4aOxJ
- ovp1JuXlAoGBAOWYNgKrlTfy5n0sKsNk+1RuL2jHJZJ3HMd0EIt7/fFQN3Fi08Hu
- jtntqD30Wj+DJK8b8Lrt66FruxyEJm5VhVmwkukrLR5ige2f6ftZnoFCmdyy+0zP
- dnPZSUe2H5ZPHa+qthJgHLn+al2P04tGh+1fGHC2PbP+e0Co+/ZRIOxrAoGBAMnN
- IEen9/FRsqvnDd36I8XnJGskVRTZNjylxBmbKcuMWm+gNhOI7gsCAcqzD4BYZjjW
- pLhrt/u9p+l4MOJy6OUUdM/okg12SnJEGryysOcVBcXyrvOfklWnANG4EAH5jt1N
- ftTb1XTxzvWVuR/WJK0B5MZNYM71cumBdUDtPi+nAoGAYmoIXMSnxb+8xNL10aOr
- h9ljQQp8NHgSQfyiSufvRk0YNuYh1vMnEIsqnsPrG2Zfhx/25GmvoxXGssaCorDN
- 5FAn6QK06F1ZTD5L0Y3sv4OI6G1gAuC66ZWuL6sFhyyKkQ4f1WiVZ7SCa3CHQSAO
- i9VDaKz1bf4bXvAQcNj9v9kCgYACSOZCqW4vN0OUmqsXhkt9ZB6Pb/veno70pNPR
- jmYsvcwQU3oJQpWfXkhy6RAV3epaXmPDCsUsfns2M3wqNC7a2R5xdCqjKGGzZX4A
- AO3rz9se4J6Gd5oKijeCKFlWDGNHsibrdgm2pz42nZlY+O21X74dWKbt8O16I1MW
- hxkbJQKBgAXfuen/srVkJgPuqywUYag90VWCpHsuxdn+fZJa50SyZADr+RbiDfH2
- vek8Uo8ap8AEsv4Rfs9opUcUZevLp3g2741eOaidHVLm0l4iLIVl03otGOqvSzs+
- A3tFPEOxauXpzCt8f8eXsz0WQXAgIKW2h8zu5QHjomioU3i27mtE
- -----END RSA PRIVATE KEY-----
- rsa_public: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0/Ho+o3eJISydO2JvIgTLnZOtrxPl+fSvJfKDjoOLY0HB2eOjy2s2/2N6d9X9SGZ4+XnyVeNPjfBXw4IyXoqxhfIF16Azfk022iejgjiYssoUxH31M60OfqJhxo16dWEXdkKP1nac06VOt1zS5yEeooyvEuMJEJSsv3VR/7GKhMX3TVhEz5moLmVP3bIAvvoXio8X4urVC1R819QjDC86nlxwNks/GKPRi/IHO5tjJ72Eke7KNsm/vxHgkdX4vZaHNKhfdb/pavFXN5eoUaofz3hxw5oL/u2epI/pXyUhDp8Tb5wO6slykzcIlGCSd0YeO1TnljvViRx0uSxIy97N root@xenial-lxd
- dsa_private: |
- -----BEGIN DSA PRIVATE KEY-----
- MIIBuwIBAAKBgQD5Fstc23IVSDe6k4DNP8smPKuEWUvHDTOGaXrhOVAfzZ6+jklP
- 55mzvC7jO53PWWC31hq10xBoWdev0WtcNF9Tv+4bAa1263y51Rqo4GI7xx+xic1d
- mLqqfYijBT9k48J/1tV0cs1Wjs6FP/IJTD/kYVC930JjYQMi722lBnUxsQIVAL7i
- z3fTGKTvSzvW0wQlwnYpS2QFAoGANp+KdyS9V93HgxGQEN1rlj/TSv/a3EVdCKtE
- nQf55aPHxDAVDVw5JtRh4pZbbRV4oGRPc9KOdjo5BU28vSM3Lmhkb+UaaDXwHkgI
- nK193o74DKjADWZxuLyyiKHiMOhxozoxDfjWxs8nz6uqvSW0pr521EwIY6RajbED
- nZ2a3GkCgYEAyoUomNRB6bmpsIfzt8zdtqLP5umIj2uhr9MVPL8/QdbxmJ72Z7pf
- Q2z1B7QAdIBGOlqJXtlau7ABhWK29Efe+99ObyTSSdDc6RCDeAwUmBAiPRQhDH2E
- wExw3doDSCUb28L1B50wBzQ8mC3KXp6C7IkBXWspb16DLHUHFSI8bkICFA5kVUcW
- nCPOXEQsayANi8+Cb7BH
- -----END DSA PRIVATE KEY-----
- dsa_public: ssh-dss AAAAB3NzaC1kc3MAAACBAPkWy1zbchVIN7qTgM0/yyY8q4RZS8cNM4ZpeuE5UB/Nnr6OSU/nmbO8LuM7nc9ZYLfWGrXTEGhZ16/Ra1w0X1O/7hsBrXbrfLnVGqjgYjvHH7GJzV2Yuqp9iKMFP2Tjwn/W1XRyzVaOzoU/8glMP+RhUL3fQmNhAyLvbaUGdTGxAAAAFQC+4s930xik70s71tMEJcJ2KUtkBQAAAIA2n4p3JL1X3ceDEZAQ3WuWP9NK/9rcRV0Iq0SdB/nlo8fEMBUNXDkm1GHillttFXigZE9z0o52OjkFTby9IzcuaGRv5RpoNfAeSAicrX3ejvgMqMANZnG4vLKIoeIw6HGjOjEN+NbGzyfPq6q9JbSmvnbUTAhjpFqNsQOdnZrcaQAAAIEAyoUomNRB6bmpsIfzt8zdtqLP5umIj2uhr9MVPL8/QdbxmJ72Z7pfQ2z1B7QAdIBGOlqJXtlau7ABhWK29Efe+99ObyTSSdDc6RCDeAwUmBAiPRQhDH2EwExw3doDSCUb28L1B50wBzQ8mC3KXp6C7IkBXWspb16DLHUHFSI8bkI= root@xenial-lxd
- ed25519_private: |
- -----BEGIN OPENSSH PRIVATE KEY-----
- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
- QyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNTOhteXao0Nl5DVThJ2+QAAAJgwt+lcMLfp
- XAAAAAtzc2gtZWQyNTUxOQAAACDbnQGUruL42aVVsyHeaV5mYNTOhteXao0Nl5DVThJ2+Q
- AAAEDQlFZpz9q8+/YJHS9+jPAqy2ZT6cGEv8HTB6RZtTjd/dudAZSu4vjZpVWzId5pXmZg
- 1M6G15dqjQ2XkNVOEnb5AAAAD3Jvb3RAeGVuaWFsLWx4ZAECAwQFBg==
- -----END OPENSSH PRIVATE KEY-----
- ed25519_public: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINudAZSu4vjZpVWzId5pXmZg1M6G15dqjQ2XkNVOEnb5 root@xenial-lxd
- ecdsa_private: |
- -----BEGIN EC PRIVATE KEY-----
- MHcCAQEEIDuK+QFc1wmyJY8uDqQVa1qHte30Rk/fdLxGIBkwJAyOoAoGCCqGSM49
- AwEHoUQDQgAEWxLlO+TL8gL91eET9p/HFQbqR1A691AkJgZk3jY5mpZqxgX4vcgb
- 7f/CtXuM6s2svcDJqAeXr6Wk8OJJcMxylA==
- -----END EC PRIVATE KEY-----
- ecdsa_public: ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFsS5Tvky/IC/dXhE/afxxUG6kdQOvdQJCYGZN42OZqWasYF+L3IG+3/wrV7jOrNrL3AyagHl6+lpPDiSXDMcpQ= root@xenial-lxd
-collect_scripts:
- dsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_dsa_key.pub
- dsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_dsa_key
- rsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_rsa_key.pub
- rsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_rsa_key
- ecdsa_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ecdsa_key.pub
- ecdsa_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ecdsa_key
- ed25519_public: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ed25519_key.pub
- ed25519_private: |
- #!/bin/bash
- cat /etc/ssh/ssh_host_ed25519_key
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/timezone.py b/tests/cloud_tests/testcases/modules/timezone.py
deleted file mode 100644
index 654fa53d..00000000
--- a/tests/cloud_tests/testcases/modules/timezone.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestTimezone(base.CloudTestCase):
- """Test timezone module."""
-
- def test_timezone(self):
- """Test date prints correct timezone."""
- out = self.get_data_file('timezone')
- self.assertEqual('HDT', out.rstrip())
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/timezone.yaml b/tests/cloud_tests/testcases/modules/timezone.yaml
deleted file mode 100644
index 5112aa9f..00000000
--- a/tests/cloud_tests/testcases/modules/timezone.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Set system timezone
-#
-required_features:
- - daylight_time
-cloud_config: |
- #cloud-config
- timezone: US/Aleutian
-collect_scripts:
- timezone: |
- #!/bin/bash
- # date will convert this to system's configured time zone.
- # use a static date to avoid dealing with daylight savings.
- date "+%Z" --date="Thu, 03 Nov 2016 00:47:00 -0400"
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/user_groups.py b/tests/cloud_tests/testcases/modules/user_groups.py
deleted file mode 100644
index 4067348d..00000000
--- a/tests/cloud_tests/testcases/modules/user_groups.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestUserGroups(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_group_ubuntu(self):
- """Test ubuntu group exists."""
- out = self.get_data_file('group_ubuntu')
- self.assertRegex(out, r'ubuntu:x:[0-9]{4}:')
-
- def test_group_cloud_users(self):
- """Test cloud users group exists."""
- out = self.get_data_file('group_cloud_users')
- self.assertRegex(out, r'cloud-users:x:[0-9]{4}:barfoo')
-
- def test_user_ubuntu(self):
- """Test ubuntu user exists."""
- out = self.get_data_file('user_ubuntu')
- self.assertRegex(
- out, r'ubuntu:x:[0-9]{4}:[0-9]{4}:Ubuntu:/home/ubuntu:/bin/bash')
-
- def test_user_foobar(self):
- """Test foobar user exists."""
- out = self.get_data_file('user_foobar')
- self.assertRegex(
- out, r'foobar:x:[0-9]{4}:[0-9]{4}:Foo B. Bar:/home/foobar:')
-
- def test_user_barfoo(self):
- """Test barfoo user exists."""
- out = self.get_data_file('user_barfoo')
- self.assertRegex(
- out, r'barfoo:x:[0-9]{4}:[0-9]{4}:Bar B. Foo:/home/barfoo:')
-
- def test_user_cloudy(self):
- """Test cloudy user exists."""
- out = self.get_data_file('user_cloudy')
- self.assertRegex(out, r'cloudy:x:[0-9]{3,4}:')
-
- def test_user_root_in_secret(self):
- """Test root user is in 'secret' group."""
- _user, _, groups = self.get_data_file('root_groups').partition(":")
- self.assertIn("secret", groups.split(),
- msg="User root is not in group 'secret'")
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/user_groups.yaml b/tests/cloud_tests/testcases/modules/user_groups.yaml
deleted file mode 100644
index 91b0e281..00000000
--- a/tests/cloud_tests/testcases/modules/user_groups.yaml
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Create groups and users with various options
-#
-required_features:
- - ubuntu_user
-cloud_config: |
- #cloud-config
- # Add groups to the system
- groups:
- - secret: [root]
- - cloud-users
-
- # Add users to the system. Users are added after groups are added.
- users:
- - default
- - name: foobar
- gecos: Foo B. Bar
- primary_group: foobar
- groups: users
- expiredate: '2038-01-19'
- lock_passwd: false
- passwd: $6$j212wezy$7H/1LT4f9/N3wpgNunhsIqtMj62OKiS3nyNwuizouQc3u7MbYCarYeAHWYPYb2FT.lbioDm2RrkJPb9BZMN1O/
- - name: barfoo
- gecos: Bar B. Foo
- sudo: ALL=(ALL) NOPASSWD:ALL
- groups: [cloud-users, secret]
- lock_passwd: true
- - name: cloudy
- gecos: Magic Cloud App Daemon User
- inactive: '5'
- system: true
-collect_scripts:
- group_ubuntu: |
- #!/bin/bash
- getent group ubuntu
- group_cloud_users: |
- #!/bin/bash
- getent group cloud-users
- user_ubuntu: |
- #!/bin/bash
- getent passwd ubuntu
- user_foobar: |
- #!/bin/bash
- getent passwd foobar
- user_barfoo: |
- #!/bin/bash
- getent passwd barfoo
- user_cloudy: |
- #!/bin/bash
- getent passwd cloudy
- root_groups: |
- #!/bin/bash
- groups root
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/write_files.py b/tests/cloud_tests/testcases/modules/write_files.py
deleted file mode 100644
index 526a2ebd..00000000
--- a/tests/cloud_tests/testcases/modules/write_files.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""cloud-init Integration Test Verify Script."""
-from tests.cloud_tests.testcases import base
-
-
-class TestWriteFiles(base.CloudTestCase):
- """Example cloud-config test."""
-
- def test_b64(self):
- """Test b64 encoded file reads as ascii."""
- out = self.get_data_file('file_b64')
- self.assertIn('ASCII text', out)
-
- def test_binary(self):
- """Test binary file reads as executable."""
- out = self.get_data_file('file_binary').strip()
- md5 = "3801184b97bb8c6e63fa0e1eae2920d7"
- sha256 = ("2c791c4037ea5bd7e928d6a87380f8ba7a803cd83d"
- "5e4f269e28f5090f0f2c9a")
- self.assertIn(out, (md5 + " -", sha256 + " -"))
-
- def test_gzip(self):
- """Test gzip file shows up as a shell script."""
- out = self.get_data_file('file_gzip')
- self.assertIn('POSIX shell script, ASCII text executable', out)
-
- def test_text(self):
- """Test text shows up as ASCII text."""
- out = self.get_data_file('file_text')
- self.assertIn('ASCII text', out)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/testcases/modules/write_files.yaml b/tests/cloud_tests/testcases/modules/write_files.yaml
deleted file mode 100644
index cc7ea4bd..00000000
--- a/tests/cloud_tests/testcases/modules/write_files.yaml
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# Write various file types
-#
-# NOTE: on trusty 'file' has an output formatting error for binary files and
-# has 2 spaces in 'LSB executable', which causes a failure here
-#
-# NOTE: the binary data can be any binary data, not only executables
-# and can be generated via the base 64 command as such:
-# $ base64 < hello > hello.txt
-# the opposite is running:
-# $ base64 -d < hello.txt > hello
-#
-required_features:
- - no_file_fmt_e
-cloud_config: |
- #cloud-config
- write_files:
- - encoding: b64
- content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4
- owner: root:root
- path: /root/file_b64
- permissions: '0644'
- - content: |
- # My new /root/file_text
-
- SMBDOPTIONS="-D"
- path: /root/file_text
- - content: !!binary |
- /Z/xrHR4WINT0UNoKPQKbuovp6+Js+JK
- path: /root/file_binary
- permissions: '0555'
- - encoding: gzip
- content: !!binary |
- H4sIAIDb/U8C/1NW1E/KzNMvzuBKTc7IV8hIzcnJVyjPL8pJ4QIA6N+MVxsAAAA=
- path: /root/file_gzip
- permissions: '0755'
-collect_scripts:
- file_b64: |
- #!/bin/bash
- file /root/file_b64
- file_text: |
- #!/bin/bash
- file /root/file_text
- file_binary: |
- #!/bin/bash
- for hasher in md5sum sha256sum; do
- $hasher </root/file_binary && break
- done
- file_gzip: |
- #!/bin/bash
- file /root/file_gzip
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/util.py b/tests/cloud_tests/util.py
deleted file mode 100644
index 49baadb0..00000000
--- a/tests/cloud_tests/util.py
+++ /dev/null
@@ -1,532 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Utilities for re-use across integration tests."""
-
-import base64
-import copy
-import glob
-import multiprocessing
-import os
-import random
-import shlex
-import shutil
-import string
-import subprocess
-import tempfile
-import time
-import yaml
-from contextlib import contextmanager
-
-from cloudinit import subp
-from cloudinit import util as c_util
-from tests.cloud_tests import LOG
-
-OS_FAMILY_MAPPING = {
- 'debian': ['debian', 'ubuntu'],
- 'redhat': ['centos', 'photon', 'rhel', 'fedora'],
- 'gentoo': ['gentoo'],
- 'freebsd': ['freebsd'],
- 'suse': ['sles'],
- 'arch': ['arch'],
-}
-
-
-def list_test_data(data_dir):
- """Find all tests with test data available in data_dir.
-
- @param data_dir: should contain <platforms>/<os_name>/<testnames>/<data>
- @return_value: {<platform>: {<os_name>: [<testname>]}}
- """
- if not os.path.isdir(data_dir):
- raise ValueError("bad data dir")
-
- res = {}
- for platform in os.listdir(data_dir):
- if not os.path.isdir(os.path.join(data_dir, platform)):
- continue
-
- res[platform] = {}
- for os_name in os.listdir(os.path.join(data_dir, platform)):
- res[platform][os_name] = [
- os.path.sep.join(f.split(os.path.sep)[-2:]) for f in
- glob.glob(os.sep.join((data_dir, platform, os_name, '*/*')))]
-
- LOG.debug('found test data: %s\n', res)
- return res
-
-
-def gen_instance_name(prefix='cloud-test', image_desc=None, use_desc=None,
- max_len=63, delim='-', max_tries=16, used_list=None,
- valid=string.ascii_lowercase + string.digits):
- """Generate an unique name for a test instance.
-
- @param prefix: name prefix, defaults to cloud-test, default should be left
- @param image_desc: short string (len <= 16) with image desc
- @param use_desc: short string (len <= 30) with usage desc
- @param max_len: maximum name length, defaults to 64 chars
- @param delim: delimiter to use between tokens
- @param max_tries: maximum tries to find a unique name before giving up
- @param used_list: already used names, or none to not check
- @param valid: string of valid characters for name
- @return_value: valid, unused name, may raise StopIteration
- """
- unknown = 'unknown'
-
- def join(*args):
- """Join args with delim."""
- return delim.join(args)
-
- def fill(*args):
- """Join name elems and fill rest with random data."""
- name = join(*args)
- num = max_len - len(name) - len(delim)
- return join(name, ''.join(random.choice(valid) for _ in range(num)))
-
- def clean(elem, max_len):
- """Filter bad characters out of elem and trim to length."""
- elem = elem.lower()[:max_len] if elem else unknown
- return ''.join(c if c in valid else delim for c in elem)
-
- return next(name for name in
- (fill(prefix, clean(image_desc, 16), clean(use_desc, 30))
- for _ in range(max_tries))
- if not used_list or name not in used_list)
-
-
-def sorted_unique(iterable, key=None, reverse=False):
- """Create unique sorted list.
-
- @param iterable: the data structure to sort
- @param key: if you have a specific key
- @param reverse: to reverse or not
- @return_value: a sorted list of unique items in iterable
- """
- return sorted(set(iterable), key=key, reverse=reverse)
-
-
-def get_os_family(os_name):
- """Get os family type for os_name.
-
- @param os_name: name of os
- @return_value: family name for os_name
- """
- return next((k for k, v in OS_FAMILY_MAPPING.items()
- if os_name.lower() in v), None)
-
-
-def current_verbosity():
- """Get verbosity currently in effect from log level.
-
- @return_value: verbosity, 0-2, 2=verbose, 0=quiet
- """
- return max(min(3 - int(LOG.level / 10), 2), 0)
-
-
-@contextmanager
-def emit_dots_on_travis():
- """
- A context manager that emits a dot every 10 seconds if running on Travis.
-
- Travis will kill jobs that don't emit output for a certain amount of time.
- This context manager spins up a background process which will emit a dot to
- stdout every 10 seconds to avoid being killed.
-
- It should be wrapped selectively around operations that are known to take a
- long time.
- """
- if os.environ.get('TRAVIS') != "true":
- # If we aren't on Travis, don't do anything.
- yield
- return
-
- def emit_dots():
- while True:
- print(".")
- time.sleep(10)
-
- dot_process = multiprocessing.Process(target=emit_dots)
- dot_process.start()
- try:
- yield
- finally:
- dot_process.terminate()
-
-
-def is_writable_dir(path):
- """Make sure dir is writable.
-
- @param path: path to determine if writable
- @return_value: boolean with result
- """
- try:
- c_util.ensure_dir(path)
- os.remove(tempfile.mkstemp(dir=os.path.abspath(path))[1])
- except (IOError, OSError):
- return False
- return True
-
-
-def is_clean_writable_dir(path):
- """Make sure dir is empty and writable, creating it if it does not exist.
-
- @param path: path to check
- @return_value: True/False if successful
- """
- path = os.path.abspath(path)
- if not (is_writable_dir(path) and len(os.listdir(path)) == 0):
- return False
- return True
-
-
-def configure_yaml():
- """Clean yaml."""
- yaml.add_representer(str, (lambda dumper, data: dumper.represent_scalar(
- 'tag:yaml.org,2002:str', data, style='|' if '\n' in data else '')))
-
-
-def yaml_format(data, content_type=None):
- """Format data as yaml.
-
- @param data: data to dump
- @param header: if specified, add a header to the dumped data
- @return_value: yaml string
- """
- configure_yaml()
- content_type = (
- '#{}\n'.format(content_type.strip('#\n')) if content_type else '')
- return content_type + yaml.dump(data, indent=2, default_flow_style=False)
-
-
-def yaml_dump(data, path):
- """Dump data to path in yaml format."""
- c_util.write_file(os.path.abspath(path), yaml_format(data), omode='w')
-
-
-def merge_results(data, path):
- """Handle merging results from collect phase and verify phase."""
- current = {}
- if os.path.exists(path):
- with open(path, 'r') as fp:
- current = c_util.load_yaml(fp.read())
- current.update(data)
- yaml_dump(current, path)
-
-
-def rel_files(basedir):
- """List of files under directory by relative path, not including dirs.
-
- @param basedir: directory to search
- @return_value: list or relative paths
- """
- basedir = os.path.normpath(basedir)
- return [path[len(basedir) + 1:] for path in
- glob.glob(os.path.join(basedir, '**'), recursive=True)
- if not os.path.isdir(path)]
-
-
-def flat_tar(output, basedir, owner='root', group='root'):
- """Create a flat tar archive (no leading ./) from basedir.
-
- @param output: output tar file to write
- @param basedir: base directory for archive
- @param owner: owner of archive files
- @param group: group archive files belong to
- @return_value: none
- """
- subp.subp(['tar', 'cf', output, '--owner', owner, '--group', group,
- '-C', basedir] + rel_files(basedir), capture=True)
-
-
-def parse_conf_list(entries, valid=None, boolean=False):
- """Parse config in a list of strings in key=value format.
-
- @param entries: list of key=value strings
- @param valid: list of valid keys in result, return None if invalid input
- @param boolean: if true, then interpret all values as booleans
- @return_value: dict of configuration or None if invalid
- """
- res = {key: value.lower() == 'true' if boolean else value
- for key, value in (i.split('=') for i in entries)}
- return res if not valid or all(k in valid for k in res.keys()) else None
-
-
-def update_args(args, updates, preserve_old=True):
- """Update cmdline arguments from a dictionary.
-
- @param args: cmdline arguments
- @param updates: dictionary of {arg_name: new_value} mappings
- @param preserve_old: if true, create a deep copy of args before updating
- @return_value: updated cmdline arguments
- """
- args = copy.deepcopy(args) if preserve_old else args
- if updates:
- vars(args).update(updates)
- return args
-
-
-def update_user_data(user_data, updates, dump_to_yaml=True):
- """Update user_data from dictionary.
-
- @param user_data: user data as yaml string or dict
- @param updates: dictionary to merge with user data
- @param dump_to_yaml: return as yaml dumped string if true
- @return_value: updated user data, as yaml string if dump_to_yaml is true
- """
- user_data = (c_util.load_yaml(user_data)
- if isinstance(user_data, str) else copy.deepcopy(user_data))
- user_data.update(updates)
- return (yaml_format(user_data, content_type='cloud-config')
- if dump_to_yaml else user_data)
-
-
-def shell_safe(cmd):
- """Produce string safe shell string.
-
- Create a string that can be passed to:
- set -- <string>
- to produce the same array that cmd represents.
-
- Internally we utilize 'getopt's ability/knowledge on how to quote
- strings to be safe for shell. This implementation could be changed
- to be pure python. It is just a matter of correctly escaping
- or quoting characters like: ' " ^ & $ ; ( ) ...
-
- @param cmd: command as a list
- """
- out = subprocess.check_output(
- ["getopt", "--shell", "sh", "--options", "", "--", "--"] + list(cmd))
- # out contains ' -- <data>\n'. drop the ' -- ' and the '\n'
- return out.decode()[4:-1]
-
-
-def shell_pack(cmd):
- """Return a string that can shuffled through 'sh' and execute cmd.
-
- In Python subprocess terms:
- check_output(cmd) == check_output(shell_pack(cmd), shell=True)
-
- @param cmd: list or string of command to pack up
- """
-
- if isinstance(cmd, str):
- cmd = [cmd]
- else:
- cmd = list(cmd)
-
- stuffed = shell_safe(cmd)
- # for whatever reason b64encode returns bytes when it is clearly
- # representable as a string by nature of being base64 encoded.
- b64 = base64.b64encode(stuffed.encode()).decode()
- return 'eval set -- "$(echo %s | base64 --decode)" && exec "$@"' % b64
-
-
-def shell_quote(cmd):
- if isinstance(cmd, (tuple, list)):
- return ' '.join([shlex.quote(x) for x in cmd])
- return shlex.quote(cmd)
-
-
-class TargetBase(object):
- _tmp_count = 0
-
- def execute(self, command, stdin=None, env=None,
- rcs=None, description=None):
- """Execute command in instance, recording output, error and exit code.
-
- Assumes functional networking and execution as root with the
- target filesystem being available at /.
-
- @param command: the command to execute as root inside the image
- if command is a string, then it will be executed as:
- ['sh', '-c', command]
- @param stdin: bytes content for standard in
- @param env: environment variables
- @param rcs: return codes.
- None (default): non-zero exit code will raise exception.
- False: any is allowed (No execption raised).
- list of int: any rc not in the list will raise exception.
- @param description: purpose of command
- @return_value: tuple containing stdout data, stderr data, exit code
- """
- if isinstance(command, str):
- command = ['sh', '-c', command]
-
- if rcs is None:
- rcs = (0,)
-
- if description:
- LOG.debug('executing "%s"', description)
- else:
- LOG.debug("executing command: %s", shell_quote(command))
-
- out, err, rc = self._execute(command=command, stdin=stdin, env=env)
-
- # False means accept anything.
- if (rcs is False or rc in rcs):
- return out, err, rc
-
- raise InTargetExecuteError(out, err, rc, command, description)
-
- def _execute(self, command, stdin=None, env=None):
- """Execute command in inside, return stdout, stderr and exit code.
-
- Assumes functional networking and execution as root with the
- target filesystem being available at /.
-
- @param stdin: bytes content for standard in
- @param env: environment variables
- @return_value: tuple containing stdout data, stderr data, exit code
-
- This is intended to be implemented by the Image or Instance.
- Many callers will use the higher level 'execute'."""
- raise NotImplementedError("_execute must be implemented by subclass.")
-
- def read_data(self, remote_path, decode=False):
- """Read data from instance filesystem.
-
- @param remote_path: path in instance
- @param decode: decode data before returning.
- @return_value: content of remote_path as bytes if 'decode' is False,
- and as string if 'decode' is True.
- """
- # when sh is invoked with '-c', then the first argument is "$0"
- # which is commonly understood as the "program name".
- # 'read_data' is the program name, and 'remote_path' is '$1'
- stdout, _stderr, rc = self._execute(
- ["sh", "-c", 'exec cat "$1"', 'read_data', remote_path])
- if rc != 0:
- raise RuntimeError("Failed to read file '%s'" % remote_path)
-
- if decode:
- return stdout.decode()
- return stdout
-
- def write_data(self, remote_path, data):
- """Write data to instance filesystem.
-
- @param remote_path: path in instance
- @param data: data to write in bytes
- """
- # when sh is invoked with '-c', then the first argument is "$0"
- # which is commonly understood as the "program name".
- # 'write_data' is the program name, and 'remote_path' is '$1'
- _, _, rc = self._execute(
- ["sh", "-c", 'exec cat >"$1"', 'write_data', remote_path],
- stdin=data)
-
- if rc != 0:
- raise RuntimeError("Failed to write to '%s'" % remote_path)
- return
-
- def pull_file(self, remote_path, local_path):
- """Copy file at 'remote_path', from instance to 'local_path'.
-
- @param remote_path: path on remote instance
- @param local_path: path on local instance
- """
- with open(local_path, 'wb') as fp:
- fp.write(self.read_data(remote_path))
-
- def push_file(self, local_path, remote_path):
- """Copy file at 'local_path' to instance at 'remote_path'.
-
- @param local_path: path on local instance
- @param remote_path: path on remote instance"""
- with open(local_path, "rb") as fp:
- self.write_data(remote_path, data=fp.read())
-
- def run_script(self, script, rcs=None, description=None):
- """Run script in target and return stdout.
-
- @param script: script contents
- @param rcs: allowed return codes from script
- @param description: purpose of script
- @return_value: stdout from script
- """
- # Just write to a file, add execute, run it, then remove it.
- shblob = '; '.join((
- 'set -e',
- 's="$1"',
- 'shift',
- 'cat > "$s"',
- 'trap "rm -f $s" EXIT',
- 'chmod +x "$s"',
- '"$s" "$@"'))
- return self.execute(
- ['sh', '-c', shblob, 'runscript', self.tmpfile()],
- stdin=script, description=description, rcs=rcs)
-
- def tmpfile(self):
- """Get a tmp file in the target.
-
- @return_value: path to new file in target
- """
- path = "/tmp/%s-%04d" % (type(self).__name__, self._tmp_count)
- self._tmp_count += 1
- return path
-
-
-class InTargetExecuteError(subp.ProcessExecutionError):
- """Error type for in target commands that fail."""
-
- default_desc = 'Unexpected error while running command.'
-
- def __init__(self, stdout, stderr, exit_code, cmd, description=None,
- reason=None):
- """Init error and parent error class."""
- super(InTargetExecuteError, self).__init__(
- stdout=stdout, stderr=stderr, exit_code=exit_code,
- cmd=shell_quote(cmd),
- description=description if description else self.default_desc,
- reason=reason)
-
-
-class PlatformError(IOError):
- """Error type for platform errors."""
-
- default_desc = 'unexpected error in platform.'
-
- def __init__(self, operation, description=None):
- """Init error and parent error class."""
- description = description if description else self.default_desc
-
- message = '%s: %s' % (operation, description)
- IOError.__init__(self, message)
-
-
-def mkdtemp(prefix='cloud_test_data'):
- return tempfile.mkdtemp(prefix=prefix)
-
-
-class TempDir(object):
- """Configurable temporary directory like tempfile.TemporaryDirectory."""
-
- def __init__(self, tmpdir=None, preserve=False, prefix='cloud_test_data_'):
- """Initialize.
-
- @param tmpdir: directory to use as tempdir
- @param preserve: if true, always preserve data on exit
- @param prefix: prefix to use for tempfile name
- """
- self.tmpdir = tmpdir
- self.preserve = preserve
- self.prefix = prefix
-
- def __enter__(self):
- """Create tempdir.
-
- @return_value: tempdir path
- """
- if not self.tmpdir:
- self.tmpdir = mkdtemp(prefix=self.prefix)
- LOG.debug('using tmpdir: %s', self.tmpdir)
- return self.tmpdir
-
- def __exit__(self, etype, value, trace):
- """Destroy tempdir if no errors occurred."""
- if etype or self.preserve:
- LOG.info('leaving data in %s', self.tmpdir)
- else:
- shutil.rmtree(self.tmpdir)
-
-# vi: ts=4 expandtab
diff --git a/tests/cloud_tests/verify.py b/tests/cloud_tests/verify.py
deleted file mode 100644
index 0295af40..00000000
--- a/tests/cloud_tests/verify.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# This file is part of cloud-init. See LICENSE file for license information.
-
-"""Verify test results."""
-
-import os
-import unittest
-
-from tests.cloud_tests import (config, LOG, util, testcases)
-
-
-def verify_data(data_dir, platform, os_name, tests):
- """Verify test data is correct.
-
- @param data_dir: top level directory for all tests
- @param platform: The platform name we for this test data (e.g. lxd)
- @param os_name: The operating system under test (xenial, artful, etc.).
- @param tests: list of test names
- @return_value: {<test_name>: {passed: True/False, failures: []}}
- """
- base_dir = os.sep.join((data_dir, platform, os_name))
- runner = unittest.TextTestRunner(verbosity=util.current_verbosity())
- res = {}
- for test_name in tests:
- LOG.debug('verifying test data for %s', test_name)
-
- # get cloudconfig for test
- test_conf = config.load_test_config(test_name)
- test_module = config.name_to_module(test_name)
- cloud_conf = test_conf['cloud_config']
-
- # load script outputs
- data = {'platform': platform, 'os_name': os_name}
- test_dir = os.path.join(base_dir, test_name)
- for script_name in os.listdir(test_dir):
- with open(os.path.join(test_dir, script_name), 'rb') as fp:
- data[script_name] = fp.read()
-
- # get test suite and launch tests
- suite = testcases.get_suite(test_module, data, cloud_conf)
- suite_results = runner.run(suite)
- res[test_name] = {
- 'passed': suite_results.wasSuccessful(),
- 'failures': [{'module': type(test_class).__base__.__module__,
- 'class': type(test_class).__base__.__name__,
- 'function': str(test_class).split()[0],
- 'error': trace.splitlines()[-1],
- 'traceback': trace, }
- for test_class, trace in suite_results.failures]
- }
-
- for failure in res[test_name]['failures']:
- LOG.warning('test case: %s failed %s.%s with: %s',
- test_name, failure['class'], failure['function'],
- failure['error'])
-
- return res
-
-
-def format_test_failures(test_result):
- """Return a human-readable printable format of test failures."""
- if not test_result['failures']:
- return ''
- failure_hdr = ' test failures:'
- failure_fmt = ' * {module}.{class}.{function}\n '
- output = []
- for failure in test_result['failures']:
- if not output:
- output = [failure_hdr]
- msg = failure_fmt.format(**failure)
- if failure.get('error'):
- msg += failure['error']
- else:
- msg += failure.get('traceback', '')
- output.append(msg)
- return '\n'.join(output)
-
-
-def format_results(res):
- """Return human-readable results as a string"""
- platform_hdr = 'Platform: {platform}'
- distro_hdr = ' Distro: {distro}'
- distro_summary_fmt = (
- ' test modules passed:{passed} tests failed:{failed}')
- output = ['']
- counts = {}
- for platform, platform_data in res.items():
- output.append(platform_hdr.format(platform=platform))
- counts[platform] = {}
- for distro, distro_data in platform_data.items():
- distro_failure_output = []
- output.append(distro_hdr.format(distro=distro))
- counts[platform][distro] = {'passed': 0, 'failed': 0}
- for _, test_result in distro_data.items():
- if test_result['passed']:
- counts[platform][distro]['passed'] += 1
- else:
- counts[platform][distro]['failed'] += len(
- test_result['failures'])
- failure_output = format_test_failures(test_result)
- if failure_output:
- distro_failure_output.append(failure_output)
- output.append(
- distro_summary_fmt.format(**counts[platform][distro]))
- if distro_failure_output:
- output.extend(distro_failure_output)
- return '\n'.join(output)
-
-
-def verify(args):
- """Verify test data.
-
- @param args: directory of test data
- @return_value: 0 for success, or number of failed tests
- """
- failed = 0
- res = {}
-
- # find test data
- tests = util.list_test_data(args.data_dir)
-
- for platform in tests.keys():
- res[platform] = {}
- for os_name in tests[platform].keys():
- test_name = "platform='{}', os='{}'".format(platform, os_name)
- LOG.info('test: %s verifying test data', test_name)
-
- # run test
- res[platform][os_name] = verify_data(
- args.data_dir, platform, os_name,
- tests[platform][os_name])
-
- # handle results
- fail_list = [k for k, v in res[platform][os_name].items()
- if not v.get('passed')]
- if len(fail_list) == 0:
- LOG.info('test: %s passed all tests', test_name)
- else:
- LOG.warning('test: %s failed %s tests', test_name,
- len(fail_list))
- failed += len(fail_list)
-
- # dump results
- LOG.debug('\n---- Verify summarized results:\n%s', format_results(res))
- if args.result:
- util.merge_results({'verify': res}, args.result)
-
- return failed
-
-# vi: ts=4 expandtab
diff --git a/tests/configs/sample1.yaml b/tests/configs/sample1.yaml
deleted file mode 100644
index ae935cc0..00000000
--- a/tests/configs/sample1.yaml
+++ /dev/null
@@ -1,49 +0,0 @@
-#cloud-config
-#apt_update: false
-#apt_upgrade: true
-packages: [ bzr, pastebinit, ubuntu-dev-tools, ccache, bzr-builddeb, vim-nox, git-core, lftp ]
-
-#disable_root: False
-
-# mounts:
-# - [ ephemeral0, /mnt ]
-# - [ swap, none, swap, sw, 0, 0 ]
-
-ssh_import_id: [smoser ]
-
-#!/bin/sh
-
-output: {all: '| tee -a /var/log/cloud-init-output.log'}
-
-sm_misc:
- - &user_setup |
- set -x; exec > ~/user_setup.log 2>&1
- echo "starting at $(date -R)"
- echo "set -o vi" >> ~/.bashrc
- cat >> ~/.profile <<"EOF"
- export EDITOR=vi
- export DEB_BUILD_OPTIONS=parallel=4
- export PATH=/usr/lib/ccache:$PATH
- EOF
-
- mkdir ~/bin
- chmod 755 ~/bin
- cat > ~/bin/mdebuild <<"EOF"
- #!/bin/sh
- exec debuild --prepend-path /usr/lib/ccache "$@"
- EOF
- chmod 755 ~/bin/*
-
- #byobu-launcher-install
- byobu-ctrl-a screen 2>&1 || :
-
- echo "pinging 8.8.8.8"
- ping -c 4 8.8.8.8
-
-runcmd:
- - [ sudo, -Hu, ubuntu, sh, -c, '[ -e /var/log/cloud-init.log ] || exit 0; grep "cloud-init.*running" /var/log/cloud-init.log > ~/runcmd.log' ]
- - [ sudo, -Hu, ubuntu, sh, -c, 'read up sleep < /proc/uptime; echo $(date): runcmd up at $up | tee -a ~/runcmd.log' ]
- - [ sudo, -Hu, ubuntu, sh, -c, *user_setup ]
-
-
-byobu_by_default: user
diff --git a/tests/unittests/test_handler/test_schema.py b/tests/unittests/test_handler/test_schema.py
index 15aa77bb..6b0b1f74 100644
--- a/tests/unittests/test_handler/test_schema.py
+++ b/tests/unittests/test_handler/test_schema.py
@@ -10,7 +10,6 @@ from cloudinit.tests.helpers import CiTestCase, mock, skipUnlessJsonSchema
from copy import copy
import itertools
-import os
import pytest
from pathlib import Path
from textwrap import dedent
@@ -493,46 +492,6 @@ class TestMain:
assert expected == err
-class CloudTestsIntegrationTest(CiTestCase):
- """Validate all cloud-config yaml schema provided in integration tests.
-
- It is less expensive to have unittests validate schema of all cloud-config
- yaml provided to integration tests, than to run an integration test which
- raises Warnings or errors on invalid cloud-config schema.
- """
-
- @skipUnlessJsonSchema()
- def test_all_integration_test_cloud_config_schema(self):
- """Validate schema of cloud_tests yaml files looking for warnings."""
- schema = get_schema()
- testsdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
- integration_testdir = os.path.sep.join(
- [testsdir, 'cloud_tests', 'testcases'])
- errors = []
-
- yaml_files = []
- for root, _dirnames, filenames in os.walk(integration_testdir):
- yaml_files.extend([os.path.join(root, f)
- for f in filenames if f.endswith(".yaml")])
- self.assertTrue(len(yaml_files) > 0)
-
- for filename in yaml_files:
- test_cfg = safe_load(open(filename))
- cloud_config = test_cfg.get('cloud_config')
- if cloud_config:
- cloud_config = safe_load(
- cloud_config.replace("#cloud-config\n", ""))
- try:
- validate_cloudconfig_schema(
- cloud_config, schema, strict=True)
- except SchemaValidationError as e:
- errors.append(
- '{0}: {1}'.format(
- filename, e))
- if errors:
- raise AssertionError(', '.join(errors))
-
-
def _get_schema_doc_examples():
examples_dir = Path(
cloudinit.__file__).parent.parent / 'doc' / 'examples'
diff --git a/tox.ini b/tox.ini
index 45ccadce..214fb623 100644
--- a/tox.ini
+++ b/tox.ini
@@ -27,7 +27,7 @@ deps =
# test-requirements because unit tests are now present in cloudinit tree
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/integration-requirements.txt
-commands = {envpython} -m pylint {posargs:cloudinit tests --ignore=cloud_tests tools}
+commands = {envpython} -m pylint {posargs:cloudinit tests tools}
[testenv:py3]
@@ -123,7 +123,7 @@ commands = {envpython} -m flake8 {posargs:cloudinit/ tests/ tools/ setup.py}
deps = flake8
[testenv:tip-pylint]
-commands = {envpython} -m pylint {posargs:cloudinit tests --ignore=cloud_tests tools}
+commands = {envpython} -m pylint {posargs:cloudinit tests tools}
deps =
# requirements
pylint
@@ -131,13 +131,6 @@ deps =
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/integration-requirements.txt
-[testenv:citest]
-basepython = python3
-commands = {envpython} -m tests.cloud_tests {posargs}
-passenv = HOME TRAVIS
-deps =
- -r{toxinidir}/cloud-tests-requirements.txt
-
# Until Xenial tox support is dropped or bumps to tox:2.3.2, reflect changes to
# deps into testenv:integration-tests-ci: commands, passenv and deps.
# This is due to (https://github.com/tox-dev/tox/issues/208) which means that