800 lines
26 KiB
ReStructuredText
800 lines
26 KiB
ReStructuredText
Developer's Guide
|
|
=================
|
|
|
|
Writing Validations
|
|
-------------------
|
|
|
|
All validations are written in standard Ansible with a couple of extra
|
|
meta-data to provide information to the validation framework.
|
|
|
|
For people not familiar with Ansible, get started with their `excellent
|
|
documentation <https://docs.ansible.com/ansible/>`_.
|
|
|
|
After the generic explanation on writing validations is a couple of concrete
|
|
examples.
|
|
|
|
Directory Structure
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
All validations consist of an Ansible role located in the ``roles`` directory
|
|
and a playbook located in the ``playbooks`` directory.
|
|
|
|
- the ``playbooks`` one contains all the validations playbooks you can run;
|
|
- the ``lookup_plugins`` one is for custom Ansible look up plugins available
|
|
to the validations;
|
|
- the ``library`` one is for custom Ansible modules available to the
|
|
validations;
|
|
- the ``roles`` one contains all the necessary Ansible roles to validate your
|
|
TripleO deployment;
|
|
|
|
Here is what the tree looks like::
|
|
|
|
playbooks/
|
|
├── first_validation.yaml
|
|
├── second_validation.yaml
|
|
├── third_validation.yaml
|
|
└── etc...
|
|
library/
|
|
├── another_module.py
|
|
├── some_module.py
|
|
└── etc...
|
|
lookup_plugins/
|
|
├── one_lookup_plugin.py
|
|
├── another_lookup_plugin.py
|
|
└── etc...
|
|
roles
|
|
├── first_role
|
|
├── second_role
|
|
└── etc...
|
|
|
|
|
|
Sample Validation
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Each validation is an Ansible playbook located in the ``playbooks`` directory
|
|
calling his own Ansible role located in the ``roles`` directory. Each playbook
|
|
have some metadata. Here is what a minimal validation would look like:
|
|
|
|
.. code-block:: yaml
|
|
|
|
---
|
|
- hosts: undercloud
|
|
vars:
|
|
metadata:
|
|
name: Hello World
|
|
description: This validation prints Hello World!
|
|
roles:
|
|
- hello-world
|
|
|
|
It should be saved as ``playbooks/hello_world.yaml``.
|
|
|
|
As shown here, the validation playbook requires three top-level directives:
|
|
``hosts``, ``vars -> metadata`` and ``roles``.
|
|
|
|
``hosts`` specify which nodes to run the validation on. Based on the
|
|
``hosts.sample`` structure, the options can be ``all`` (run on all nodes),
|
|
``undercloud``, ``allovercloud`` (all overcloud nodes), ``controller`` and
|
|
``compute``.
|
|
|
|
The ``vars`` section serves for storing variables that are going to be
|
|
available to the Ansible playbook. The validations API uses the ``metadata``
|
|
section to read each validation's name and description. These values are then
|
|
reported by the API.
|
|
|
|
The validations can be grouped together by specifying a ``groups`` metadata.
|
|
Groups function similar to tags and a validation can thus be part of many
|
|
groups. Here is, for example, how to have a validation be part of the
|
|
`pre-deployment` and `hardware` groups:
|
|
|
|
.. code-block:: yaml
|
|
|
|
metadata:
|
|
groups:
|
|
- pre-deployment
|
|
- hardware
|
|
|
|
The validations can be categorized by technical domain and can belong to one or
|
|
multiple categories. The categorization is depending on what the validation is
|
|
checking on the hosts. For example, if a validation checks some networking
|
|
related configuration and needs to get configuration items from the
|
|
undercloud.conf file, you will have to put `networking` and `undercloud-config` in
|
|
the ``categories`` metadata key:
|
|
|
|
.. code-block:: yaml
|
|
|
|
metadata:
|
|
groups:
|
|
- pre-deployment
|
|
- hardware
|
|
categories:
|
|
- networking
|
|
- undercloud-config
|
|
|
|
.. note::
|
|
|
|
The ``categories`` are not restricted to a list as for the ``groups``
|
|
present in the ``groups.yaml`` file, but it could be for example:
|
|
|
|
* ``networking``
|
|
* ``compute``
|
|
* ``baremetal``
|
|
* ``provisioning``
|
|
* ``database``
|
|
* ``os``
|
|
* ``system``
|
|
* ``packaging``
|
|
* ``kernel``
|
|
* ``security``
|
|
* ``tls-everywhere``
|
|
* ``dns``
|
|
* ``dhcp``
|
|
* ``dnsmasq``
|
|
* ``webserver``
|
|
* ``storage``
|
|
* ``ha``
|
|
* ``clustering``
|
|
* ``undercloud-config``
|
|
* etc ...
|
|
|
|
The validations should be linked to a product. Every validations hosted in
|
|
``tripleo-validations`` should get at least ``tripleo`` in the ``products``
|
|
metadata key:
|
|
|
|
.. code-block:: yaml
|
|
|
|
metadata:
|
|
groups:
|
|
- pre-deployment
|
|
- hardware
|
|
categories:
|
|
- networking
|
|
- undercloud-config
|
|
products:
|
|
- tripleo
|
|
|
|
``roles`` include the Ansible role, which contains all the tasks to run,
|
|
associated to this validation. Each task is a YAML dictionary that must at
|
|
minimum contain a name and a module to use. Module can be any module that ships
|
|
with Ansible or any of the custom ones in the ``library`` directory.
|
|
|
|
The `Ansible documentation on playbooks
|
|
<https://docs.ansible.com/ansible/playbooks.html>`__ provides more detailed
|
|
information.
|
|
|
|
Ansible Inventory
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
Dynamic inventory
|
|
+++++++++++++++++
|
|
|
|
Tripleo-validations ships with a `dynamic inventory
|
|
<https://docs.ansible.com/ansible/intro_dynamic_inventory.html>`__, which
|
|
contacts the various OpenStack services to provide the addresses of the
|
|
deployed nodes as well as the undercloud.
|
|
|
|
Just pass ``-i /usr/bin/tripleo-ansible-inventory`` to ``ansible-playbook``
|
|
command.
|
|
|
|
As the playbooks are located in their own directory and not at the same level as
|
|
the ``roles``, ``callback_plugins``, ``library`` and ``lookup_plugins``
|
|
directories, you will have to export some Ansible variables first:
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd tripleo-validations/
|
|
$ export ANSIBLE_CALLBACK_PLUGINS="${PWD}/callback_plugins"
|
|
$ export ANSIBLE_ROLES_PATH="${PWD}/roles"
|
|
$ export ANSIBLE_LOOKUP_PLUGINS="${PWD}/lookup_plugins"
|
|
$ export ANSIBLE_LIBRARY="${PWD}/library"
|
|
|
|
$ ansible-playbook -i /usr/bin/tripleo-ansible-inventory playbooks/hello_world.yaml
|
|
|
|
Hosts file
|
|
++++++++++
|
|
|
|
When more flexibility than what the current dynamic inventory provides is
|
|
needed or when running validations against a host that hasn't been deployed via
|
|
heat (such as the ``prep`` validations), it is possible to write a custom hosts
|
|
inventory file. It should look something like this:
|
|
|
|
.. code-block:: INI
|
|
|
|
[undercloud]
|
|
undercloud.example.com
|
|
|
|
[allovercloud:children]
|
|
controller
|
|
compute
|
|
|
|
[controller]
|
|
controller.example.com
|
|
|
|
[compute]
|
|
compute-1.example.com
|
|
compute-2.example.com
|
|
|
|
[all:vars]
|
|
ansible_ssh_user=stack
|
|
ansible_sudo=true
|
|
|
|
It will have a ``[group]`` section for each role (``undercloud``,
|
|
``controller``, ``compute``) listing all the nodes belonging to that group. It
|
|
is also possible to create a group from other groups as done with
|
|
``[allovercloud:children]`` in the above example. If a validation specifies
|
|
``hosts: overcloud``, it will be run on any node that belongs to the
|
|
``compute`` or ``controller`` groups. If a node happens to belong to both, the
|
|
validation will only be run once.
|
|
|
|
Lastly, there is an ``[all:vars]`` section where to configure certain
|
|
Ansible-specific options.
|
|
|
|
``ansible_ssh_user`` will specify the user Ansible should SSH as. If that user
|
|
does not have root privileges, it is possible to instruct it to use ``sudo`` by
|
|
setting ``ansible_sudo`` to ``true``.
|
|
|
|
Learn more at the `Ansible documentation page for the Inventory
|
|
<https://docs.ansible.com/ansible/intro_inventory.html>`__
|
|
|
|
Custom Modules
|
|
~~~~~~~~~~~~~~
|
|
|
|
In case the `available Ansible modules
|
|
<https://docs.ansible.com/ansible/modules_by_category.html>`__ don't cover your
|
|
needs, it is possible to write your own. Modules belong to the
|
|
``library`` directory.
|
|
|
|
Here is a sample module that will always fail
|
|
|
|
.. code-block:: python
|
|
|
|
#!/usr/bin/env python
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
|
|
if __name__ == '__main__':
|
|
module = AnsibleModule(argument_spec={})
|
|
module.fail_json(msg="This module always fails.")
|
|
|
|
Save it as ``library/my_module.py`` and use it in a validation like
|
|
so:
|
|
|
|
.. code-block:: yaml
|
|
|
|
tasks:
|
|
... # some tasks
|
|
- name: Running my custom module
|
|
my_module:
|
|
... # some other tasks
|
|
|
|
The name of the module in the validation ``my_module`` must match the file name
|
|
(without extension): ``my_module.py``.
|
|
|
|
The custom modules can accept parameters and do more complex reporting. Please
|
|
refer to the guide on writing modules in the Ansible documentation.
|
|
|
|
.. Warning::
|
|
|
|
Each custom module must be accompanied by the most complete unit tests
|
|
possible.
|
|
|
|
Learn more at the `Ansible documentation page about writing custom modules
|
|
<https://docs.ansible.com/ansible/developing_modules.html>`__.
|
|
|
|
Running a validation
|
|
--------------------
|
|
|
|
Running the validations require ansible and a set of nodes to run them against.
|
|
These nodes need to be reachable from the operator's machine and need to have
|
|
an account it can ssh to and perform passwordless sudo.
|
|
|
|
The nodes need to be present in the static inventory file or available from the
|
|
dynamic inventory script depending on which one the operator chooses to use.
|
|
Check which nodes are available with:
|
|
|
|
.. code-block:: console
|
|
|
|
$ source stackrc
|
|
$ tripleo-ansible-inventory --list
|
|
|
|
In general, Ansible and the validations will be located on the *undercloud*,
|
|
because it should have connectivity to all the *overcloud* nodes is already set
|
|
up to SSH to them.
|
|
|
|
.. code-block:: console
|
|
|
|
$ source ~/stackrc
|
|
$ tripleo-validation.py
|
|
usage: tripleo-validation.py [-h] [--inventory INVENTORY]
|
|
[--extra-vars EXTRA_VARS [EXTRA_VARS ...]]
|
|
[--validation <validation_id>[,<validation_id>,...]]
|
|
[--group <group>[,<group>,...]] [--quiet]
|
|
[--validation-dir VALIDATION_DIR]
|
|
[--ansible-base-dir ANSIBLE_BASE_DIR]
|
|
[--output-log OUTPUT_LOG]
|
|
{run,list,show}
|
|
|
|
$ tripleo-validation.py run --validation <validation_name>
|
|
|
|
|
|
Example: Verify Undercloud RAM requirements
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The Undercloud has a requirement of 16GB RAM. Let's write a validation
|
|
that verifies this is indeed the case before deploying anything.
|
|
|
|
Let's create ``playbooks/undercloud-ram.yaml`` and put some metadata
|
|
in there:
|
|
|
|
.. code-block:: yaml
|
|
|
|
---
|
|
- hosts: undercloud
|
|
vars:
|
|
metadata:
|
|
name: Minimum RAM required on the undercloud
|
|
description: >
|
|
Make sure the undercloud has enough RAM.
|
|
groups:
|
|
- prep
|
|
- pre-introspection
|
|
categories:
|
|
- os
|
|
- system
|
|
- ram
|
|
products:
|
|
- tripleo
|
|
|
|
|
|
The ``hosts`` key will tell which server should the validation run on. The
|
|
common values are ``undercloud``, ``overcloud`` (i.e. all overcloud nodes),
|
|
``controller`` and ``compute`` (i.e. just the controller or the compute nodes).
|
|
|
|
The ``name`` and ``description`` metadata will show up in the API and the
|
|
TripleO UI so make sure to put something meaningful there. The ``groups``
|
|
metadata applies a tag to the validation and allows to group them together in
|
|
order to perform group operations, such are running them all in one call.
|
|
|
|
Now let's include the Ansible role associated to this validation. Add this under
|
|
the same indentation as ``hosts`` and ``vars``:
|
|
|
|
.. code-block:: yaml
|
|
|
|
roles:
|
|
- undercloud-ram
|
|
|
|
Now let's create the ``undercloud-ram`` Ansible role which will contain the
|
|
necessary task(s) for checking if the Undercloud has the mininum amount of RAM
|
|
required:
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd tripleo-validations
|
|
$ ansible-galaxy init --init-path=roles/ undercloud-ram
|
|
- undercloud-ram was created successfully
|
|
|
|
The tree of the new created role should look like::
|
|
|
|
undercloud-ram/
|
|
├── defaults
|
|
│ └── main.yml
|
|
├── meta
|
|
│ └── main.yml
|
|
├── tasks
|
|
│ └── main.yml
|
|
└── vars
|
|
└── main.yml
|
|
|
|
Now let's add an Ansible task to test that it's all set up properly:
|
|
|
|
.. code-block:: yaml
|
|
|
|
$ cat <<EOF >> roles/undercloud-ram/tasks/main.yml
|
|
- name: Test Output
|
|
debug:
|
|
msg: "Hello World!"
|
|
EOF
|
|
|
|
When running it, it should output something like this:
|
|
|
|
.. code-block:: console
|
|
|
|
$ /bin/run-validations.sh --validation-name undercloud-ram.yaml --ansible-default-callback
|
|
|
|
PLAY [undercloud] *********************************************************
|
|
|
|
TASK [Gathering Facts] ****************************************************
|
|
ok: [undercloud]
|
|
|
|
TASK [undercloud-ram : Test Output] ***************************************
|
|
ok: [undercloud] => {
|
|
"msg": "Hello World!"
|
|
}
|
|
|
|
PLAY RECAP ****************************************************************
|
|
undercloud : ok=2 changed=0 unreachable=0 failed=0
|
|
|
|
|
|
If you run into an issue where the validation isn't found, it may be because the
|
|
run-validations.sh script is searching for it in the path where the packaging
|
|
installs validations. For development, export an environment variable named
|
|
VALIDATIONS_BASEDIR with the value of base path of your git repo:
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd /path/to/git/repo
|
|
$ export VALIDATIONS_BASEDIR=$(pwd)
|
|
|
|
Writing the full validation code is quite easy in this case because Ansible has
|
|
done all the hard work for us already. We can use the ``ansible_memtotal_mb``
|
|
fact to get the amount of RAM (in megabytes) the tested server currently has.
|
|
For other useful values, run ``ansible -i /usr/bin/tripleo-ansible-inventory
|
|
undercloud -m setup``.
|
|
|
|
So, let's replace the hello world task with a real one:
|
|
|
|
.. code-block:: yaml
|
|
|
|
tasks:
|
|
- name: Verify the RAM requirements
|
|
fail: msg="The RAM on the undercloud node is {{ ansible_memtotal_mb }} MB, the minimal recommended value is 16 GB."
|
|
failed_when: "({{ ansible_memtotal_mb }}) < 16000"
|
|
|
|
Running this, we see:
|
|
|
|
.. code-block:: console
|
|
|
|
TASK: [Verify the RAM requirements] *******************************************
|
|
failed: [localhost] => {"failed": true, "failed_when_result": true}
|
|
msg: The RAM on the undercloud node is 8778 MB, the minimal recommended value is 16 GB.
|
|
|
|
|
|
Because our Undercloud node really does not have enough RAM. Your mileage may
|
|
vary.
|
|
|
|
Either way, the validation works and reports the lack of RAM properly!
|
|
|
|
``failed_when`` is the real hero here: it evaluates an Ansible expression (e.g.
|
|
does the node have more than 16 GB of RAM) and fails when it's evaluated as
|
|
true.
|
|
|
|
The ``fail`` line right above it lets us print a custom error in case of
|
|
a failure. If the task succeeds (because we do have enough RAM), nothing will
|
|
be printed out.
|
|
|
|
Now, we're almost done, but there are a few things we can do to make this nicer
|
|
on everybody.
|
|
|
|
First, let's hoist the minimum RAM requirement into a variable. That way we'll
|
|
have one place where to change it if we need to and we'll be able to test the
|
|
validation better as well!
|
|
|
|
So, let's call the variable ``minimum_ram_gb`` and set it to ``16``. Do this in
|
|
the ``vars`` section:
|
|
|
|
.. code-block:: yaml
|
|
|
|
vars:
|
|
metadata:
|
|
name: ...
|
|
description: ...
|
|
groups: ...
|
|
categories: ...
|
|
products: ...
|
|
minimum_ram_gb: 16
|
|
|
|
Make sure it's on the same indentation level as ``metadata``.
|
|
|
|
Then, update ``failed_when`` like this:
|
|
|
|
.. code-block:: yaml
|
|
|
|
failed_when: "({{ ansible_memtotal_mb }}) < {{ minimum_ram_gb|int * 1024 }}"
|
|
|
|
And ``fail`` like so:
|
|
|
|
.. code-block:: yaml
|
|
|
|
fail: msg="The RAM on the undercloud node is {{ ansible_memtotal_mb }} MB, the minimal recommended value is {{ minimum_ram_gb|int * 1024 }} MB."
|
|
|
|
And re-run it again to be sure it's still working.
|
|
|
|
One benefit of using a variable instead of a hardcoded value is that we can now
|
|
change the value without editing the yaml file!
|
|
|
|
Let's do that to test both success and failure cases.
|
|
|
|
This should succeed but saying the RAM requirement is 1 GB::
|
|
|
|
.. code-block:: console
|
|
|
|
ansible-playbook -i /usr/bin/tripleo-ansible-inventory playbooks/undercloud-ram.yaml -e minimum_ram_gb=1
|
|
|
|
And this should fail by requiring much more RAM than is necessary::
|
|
|
|
.. code-block:: console
|
|
|
|
ansible-playbook -i /usr/bin/tripleo-ansible-inventory playbooks/undercloud-ram.yaml -e minimum_ram_gb=128
|
|
|
|
(the actual values may be different in your configuration -- just make sure one
|
|
is low enough and the other too high)
|
|
|
|
And that's it! The validation is now finished and you can start using it in
|
|
earnest.
|
|
|
|
Create a new role with automation
|
|
---------------------------------
|
|
|
|
The role addition process is also automated using ansible. If ansible is
|
|
available on the development workstation change directory to the root of
|
|
the `tripleo-validations` repository and run the the following command which
|
|
will perform the basic tasks noted above.
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd tripleo-validations/
|
|
$ export ANSIBLE_ROLES_PATH="${PWD}/roles"
|
|
$ ansible-playbook -i localhost, role-addition.yml -e validation_init_role_name=${NEWROLENAME}
|
|
|
|
The new role will be created in `tripleo-validations/roles/` from a skeleton and one playbook
|
|
will be added in `tripleo-validations/playbooks/`.
|
|
|
|
It will also add a new **job** entry into the `zuul.d/molecule.yaml`.
|
|
|
|
.. code-block:: yaml
|
|
|
|
- job:
|
|
files:
|
|
- ^roles/${NEWROLENAME}/.*
|
|
- ^tests/prepare-test-host.yml
|
|
- ^ci/playbooks/pre.yml
|
|
- ^ci/playbooks/run.yml
|
|
- ^molecule-requirements.txt
|
|
name: tripleo-validations-centos-8-molecule-${NEWROLENAME}
|
|
parent: tripleo-validations-centos-8-base
|
|
vars:
|
|
tripleo_validations_role_name: ${NEWROLENAME}
|
|
|
|
|
|
And the **job** name will be added into the check and gate section at the top
|
|
of the `molecule.yaml` file.
|
|
|
|
.. code-block:: yaml
|
|
|
|
- project:
|
|
check:
|
|
jobs:
|
|
- tripleo-validations-centos-8-molecule-${NEWROLENAME}
|
|
gate:
|
|
jobs:
|
|
- tripleo-validations-centos-8-molecule-${NEWROLENAME}
|
|
|
|
|
|
Finally it will add a role documentation file at
|
|
`doc/source/roles/role-${NEWROLENAME}.rst`. This file will need to contain
|
|
a title, a literal include of the defaults yaml and a literal include of
|
|
the molecule playbook, or playbooks, used to test the role, which is noted
|
|
as an "example" playbook.
|
|
|
|
You will now be able to develop your new validation!
|
|
|
|
Developing your own molecule test(s)
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The role addition process will create a default Molecule scenario from the
|
|
skeleton. By using Molecule, you will be able to test it locally and of course
|
|
it will be executed during the CI checks.
|
|
|
|
In your role directory, you will notice a `molecule` folder which contains a
|
|
single `Scenario` called `default`. Scenarios are the starting point for a lot
|
|
of powerful functionality that Molecule offers. A scenario is a kind of a test
|
|
suite for your newly created role.
|
|
|
|
The Scenario layout
|
|
+++++++++++++++++++
|
|
|
|
Within the `molecule/default` folder, you will find those files:
|
|
|
|
.. code-block:: console
|
|
|
|
$ ls
|
|
molecule.yml converge.yml prepare.yml verify.yml
|
|
|
|
* ``molecule.yml`` is the central configuration entrypoint for `Molecule`. With this
|
|
file, you can configure each tool that `Molecule` will employ when testing
|
|
your role.
|
|
|
|
.. note::
|
|
|
|
`Tripleo-validations` uses a global configuration file for `Molecule`.
|
|
This file is located at the repository level (``tripleo-validations/.config/molecule/.config.yml``).
|
|
and defines all the default values for all the ``molecule.yml``. By default,
|
|
the role addition process will produce an empty ``molecule.yml`` inheriting
|
|
this ``config.yml`` file. Any key defined in the role ``molecule.yml`` file
|
|
will override values from the ``config.yml`` file.
|
|
|
|
But, if you want to override the default values set in the ``config.yml``
|
|
file, you will have to redefine them completely in your ``molecule.yml``
|
|
file. `Molecule` won't merge both configuration files and that's why you
|
|
will have to redefine them completely.
|
|
|
|
* ``prepare.yml`` is the playbook file that contains everything you need to
|
|
include before your test. It could include packages installation, file
|
|
creation, whatever your need on the instance created by the driver.
|
|
|
|
* ``converge.yml`` is the playbook file that contains the call for you
|
|
role. `Molecule` will invoke this playbook with ``ansible-playbook`` and run
|
|
it against and instance created by the driver.
|
|
|
|
* ``verify.yml`` is the Ansible file used for testing as Ansible is the default
|
|
``Verifier``. This allows you to write specific tests against the state of the
|
|
container after your role has finished executing.
|
|
|
|
Inspecting the Global Molecule Configuration file
|
|
+++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
As mentioned above, ``tripleo-validations`` uses a global configuration for
|
|
Molecule.
|
|
|
|
.. literalinclude:: ../../../.config/molecule/config.yml
|
|
:language: yaml
|
|
|
|
* The ``Driver`` provider: ``podman`` is the default. Molecule will use the
|
|
driver to delegate the task of creating instances.
|
|
* The ``Platforms`` definitions: Molecule relies on this to know which instances
|
|
to create, name and to which group each instance
|
|
belongs. ``Tripleo-validations`` uses ``CentOS 8 Stream image``.
|
|
* The ``Provisioner``: Molecule only provides an Ansible provisioner. Ansible
|
|
manages the life cycle of the instance based on this configuration.
|
|
* The ``Scenario`` definition: Molecule relies on this configuration to control
|
|
the scenario sequence order.
|
|
* The ``Verifier`` framework. Molecule uses Ansible by default to provide a way
|
|
to write specific stat checking tests (such as deployment smoke tests) on the
|
|
target instance.
|
|
|
|
Local testing of new roles
|
|
--------------------------
|
|
|
|
Local testing of new roles can be done in two ways:
|
|
|
|
* Via the script `scripts/run-local-test`,
|
|
* or manually by following the procedure described below.
|
|
|
|
Running molecule tests with the script run-local-test
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
This script will setup the local work environment to execute tests mimicking
|
|
what Zuul does on a *CentOS 8* machine.
|
|
|
|
.. warning::
|
|
|
|
This script makes the assumption the executing user has the
|
|
ability to escalate privileges and will modify the local system.
|
|
|
|
To use this script execute the following command.
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd tripleo-validations
|
|
$ ./scripts/run-local-test ${NEWROLENAME}
|
|
|
|
When using the `run-local-test` script, the TRIPLEO_JOB_ANSIBLE_ARGS
|
|
environment variable can be used to pass arbitrary Ansible arguments.
|
|
For example, the following shows how to use `--skip-tags` when testing
|
|
a role with tags.
|
|
|
|
.. code-block:: console
|
|
|
|
$ export TRIPLEO_JOB_ANSIBLE_ARGS="--skip-tags tag_one,tag_two"
|
|
$ ./scripts/run-local-test ${ROLENAME}
|
|
|
|
|
|
Running molecule tests manually
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Role based testing with `molecule`_ can be executed directly from within
|
|
the role directory.
|
|
|
|
.. note::
|
|
|
|
All tests require `Podman`_ for container based testing. If `Podman`_ is not
|
|
available on the local workstation it will need to be installed prior to
|
|
executing most molecule based tests.
|
|
|
|
|
|
.. note::
|
|
|
|
The script `bindep-install`, in the **scripts** path, is available and will
|
|
install all system dependencies.
|
|
|
|
|
|
.. note::
|
|
|
|
Each molecule tests are configured to bind mount a read-only volume on the
|
|
container where the tests are running:
|
|
|
|
.. code-block:: yaml
|
|
|
|
volumes:
|
|
- /etc/ci/mirror_info.sh:/etc/ci/mirror_info.sh:ro
|
|
|
|
It is an OpenStack Zuul requirement for detecting if we are on a CI node. Of
|
|
course, when running your `molecule`_ test on your workstation, it is going
|
|
to fail because you don't have the empty `mirror_info.sh` script in the
|
|
`/etc/ci/` directory. You can workaround this by creating it in your
|
|
workstation or removing the volume key in the global configuration file for
|
|
molecule.
|
|
|
|
.. code-block:: console
|
|
|
|
$ sudo mkdir -p /etc/ci
|
|
$ sudo touch /etc/ci/mirror_info.sh
|
|
|
|
|
|
Before running basic `molecule`_ tests, it is recommended to install all
|
|
of the python dependencies in a virtual environment.
|
|
|
|
.. code-block:: console
|
|
|
|
$ sudo dnf install python3 python3-virtualenv
|
|
$ python3 -m virtualenv --system-site-packages "${HOME}/test-python"
|
|
$ source "${HOME}/test-python/bin/activate"
|
|
(test-python) $ python3 -m pip install "pip>=19.1.1" setuptools bindep --upgrade
|
|
(test-python) $ scripts/./bindep-install
|
|
(test-python) $ python3 -m pip install -r requirements.txt \
|
|
-r test-requirements.txt \
|
|
-r molecule-requirements.txt
|
|
(test-python) $ ansible-galaxy install -fr ansible-collections-requirements.txt
|
|
|
|
|
|
Now, it is important to install `validations-common` and `tripleo-ansible` as
|
|
dependencies.
|
|
|
|
.. note::
|
|
|
|
`validation-common` contains Ansible Custom modules needed by
|
|
`tripleo-validations` roles. That's the reason why we will need to clone it
|
|
beforehand.
|
|
|
|
Cloning `tripleo-ansible` project is only necessary in order to
|
|
run the `molecule` test(s) for the `image_serve` role. Otherwise, you won't
|
|
probably need it.
|
|
|
|
|
|
.. code-block:: console
|
|
|
|
$ cd tripleo-validations/
|
|
$ for REPO in validations-common tripleo-ansible; do git clone https://opendev.org/openstack/${REPO} roles/roles.galaxy/${REPO}; done
|
|
|
|
|
|
To run a basic `molecule`_ test, simply source the `ansible-test-env.rc`
|
|
file from the project root, and then execute the following commands.
|
|
|
|
.. code-block:: console
|
|
|
|
(test-python) $ source ansible-test-env.rc
|
|
(test-python) $ cd roles/${NEWROLENAME}/
|
|
(test-python) $ molecule test --all
|
|
|
|
|
|
If a role has more than one scenario, a specific scenario can be
|
|
specified on the command line. Running specific scenarios will
|
|
help provide developer feedback faster. To pass-in a scenario use
|
|
the `--scenario-name` flag with the name of the desired scenario.
|
|
|
|
.. code-block:: console
|
|
|
|
(test-python) $ cd roles/${NEWROLENAME}/
|
|
(test-python) $ molecule test --scenario-name ${EXTRA_SCENARIO_NAME}
|
|
|
|
|
|
When debugging `molecule`_ tests its sometimes useful to use the
|
|
`--debug` flag. This flag will provide extra verbose output about
|
|
test being executed and running the environment.
|
|
|
|
.. code-block:: console
|
|
|
|
(test-python) $ molecule --debug test
|
|
|
|
.. _molecule: https://github.com/ansible-community/molecule
|
|
.. _podman: https://podman.io/
|