Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Molecule testing #197

Merged
merged 25 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
31b0b0c
Add molecule testing for cloudera.exe.rdbms_server to collection, inc…
wmudge Sep 12, 2024
6518fe1
Add deprecation warning to nested rol
wmudge Sep 12, 2024
8e2f16b
Update local TLS paths
wmudge Sep 12, 2024
01c0931
Update platforms
wmudge Sep 12, 2024
f4e52d5
Update to ensure psycopg2 library and postgres user
wmudge Sep 12, 2024
c9d9772
Supress 'crypt' deprecation warning
wmudge Sep 12, 2024
9ceaf2f
Add development libraries
wmudge Sep 12, 2024
bde6c1e
Remove testing libraries
wmudge Sep 12, 2024
5971d5f
Add skeleton tox-ansible configuration
wmudge Sep 12, 2024
4e0e7fd
Update testing instructions for pytest-ansible and Molecule usage
wmudge Sep 12, 2024
fd346c1
Fix linting errors
wmudge Sep 12, 2024
3c581b2
Add default Molecule scenario
wmudge Sep 13, 2024
0d912a7
Add fully qualifed RHEL UBI images
wmudge Sep 13, 2024
25799f1
Update psycopg2 build prerequisites for RHEL8
wmudge Sep 13, 2024
4bc8a5a
Update collection dependencies to reflect upstream requirements
wmudge Sep 13, 2024
8ee6d5b
Add missing SQL file
wmudge Sep 13, 2024
e1c094f
Update dependeny requirement file locations
wmudge Sep 16, 2024
8aebe07
Update SQL template location
wmudge Sep 16, 2024
50f118c
Update Molecule dependency file locations
wmudge Sep 16, 2024
5cfaaf7
Update TESTING documentation
wmudge Sep 16, 2024
81fed34
Fix documentation error
wmudge Sep 16, 2024
5de9bbe
Update PostgreSQL repositories to handle arm64 architectures
wmudge Sep 25, 2024
b3b9d66
Fix variable substitution
wmudge Sep 26, 2024
519de1b
Remove explicit architecture reference in apt repository
wmudge Sep 26, 2024
1e5c171
Expand conditional to include AARCH64 and AMD64
wmudge Sep 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .config/molecule/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

provisioner:
name: ansible
config_options:
defaults:
collections_path: ${ANSIBLE_COLLECTIONS_PATH}
196 changes: 183 additions & 13 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,195 @@
# Testing cloudera.exe

The collection uses `ansible-test` for unit and integration testing.
The collection is migrating from `ansible-test` to `pytest` and `molecule` for unit and integration testing. In addition, we use `pre-commit` to handle linting and formatting both for `git` commits and for various Github Action workflows in the repository.

## Setup

To set up a development and test environment for the collection, you need to:

1. Set up the Ansible Collection and Role paths
1. Install Ansible and the Python dependencies
1. Install the collection and its dependencies
1. Configure the PYTHONPATH to use the correct location of the collections code
1. Install the Molecule driver dependencies

### Ansible Collection and Role Paths

You have to install your Ansible collections, both the collection under test and its dependencies, into the `ansible_collections/<namespace>/<name>` folder structure. For the collection under test, run the following _in the parent directory of your choosing_:

```bash
git clone https://github.com/cloudera-labs/cloudera.exe.git ansible_collections/cloudera/exe
```

Then create the `roles` directory in the _parent directory_:

```bash
mkdir roles
```

Lastly, set the Ansible [COLLECTION](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#envvar-ANSIBLE_COLLECTIONS_PATH) and [ROLE](https://docs.ansible.com/ansible/latest/reference_appendices/config.html#envvar-ANSIBLE_ROLES_PATH) configurations for these two locations:

```bash
export ANSIBLE_COLLECTIONS_PATH=$(pwd)
export ANSIBLE_ROLES_PATH="$(pwd)/roles"
```

### Set the PYTHONPATH

Include the `ANSIBLE_COLLECTIONS_PATH` variable to the `PYTHONPATH` to allow module imports.

```bash
export PYTHONPATH="${ANSIBLE_COLLECTIONS_PATH}":"${PYTHONPATH}"
```

### Ansible

Set up a development `virtualenv` and install `ansible-core~=2.16.0` and `ansible-navigator`.

```bash
pip install ansible-core~=2.16.0 ansible-navigator
```

> [!warning]
> Installing `>=2.17` will require that the target hosts run Python 3.7. This requirement extends to RHEL 8.x and its `platform-python`, which means that `2.17` will not work on these platforms.

### Python Dependencies

Install the development and collection Python requirements from the `requirements-dev.txt` and `requirements.txt` files respectively in the project root.

```bash
pip install -r ansible_collections/cloudera/exe/requirements.txt
pip install -r ansible_collections/cloudera/exe/requirements-dev.txt
```

### Collection Dependencies

You also need to install the collection's dependencies and install them into the `ANSIBLE_COLLECTIONS_PATH`:

```bash
ansible-galaxy collection install -r ansible_collections/cloudera/exe/requirements.yml -p "${ANSIBLE_COLLECTIONS_PATH}"
```

And install any role dependencies as well into the `ANSIBLE_ROLES_PATH`:

```bash
ansible-galaxy role install -r ansible_collections/cloudera/exe/requirements.yml -p "${ANSIBLE_ROLES_PATH}"
```

If the collection has any system requirements, run `bindep` on its requirements file:

```bash
# Sanity tests
ansible-test sanity --docker --python 3.9
bindep -f ansible_collections/cloudera/exe/bindep.txt
```

### Molecule

Running the `molecule` tests requires `podman` as the container engine, so you will need to install that service on your test machine. Read more about [Podman](https://podman.io/) or [Podman Desktop](https://podman-desktop.io/).

## Testing

You can either run standalone `molecule`, for roles and more advanced integration testing, or `pytest`. The latter is set up to run any and all tests, including `molecule` scenarios.

### Running standalone `molecule` tests

Currently, `molecule` scenarios are located in the `extensions/molecule` directory of the collection. To run a scenario, change to `extensions` as your current working directory and then run `molecule`. For example:

| Command | Description |
| --- | --- |
| `molecule test -s rdbms_server_postgresql_14_tls` | Execute the full test lifecyle for the PostgreSQL 14 server role with TLS |
| `molecule create -s rdbms_server_postgresql_14_tls` | Create the `platforms`, i.e. the inventory, that are the target hosts of the role testing |
| `molecule prepare -s rdbms_server_postgresql_14_tls` | Prep the target hosts for testing the roles |
| `molecule converge -s rdbms_server_postgresql_14_tls` | Run the testing playbook, i.e. converge the test code, on the target hosts |
| `molecule side-effect -s rdbms_server_postgresql_14_tls` | Prep the target hosts, post-`converge`, for any additional setup prior to verification or idempotency testing |
| `molecule verify -s rdbms_server_postgresql_14_tls` | Verify the target hosts |
| `molecule cleanup -s rdbms_server_postgresql_14_tls` | Clean up any resources, for example, temporary files created on the controller |
| `molecule destroy -s rdbms_server_postgresql_14_tls` | Destroy the `platform` hosts |

You can limit testing to a `platform` within a scenario by using the `-p/--platform-name` parameter (or via the `MOLECULE_PLATFORM_NAME` environment variable):

```bash
molecule test -s rdbms_server_postgresql_14_tls -p rhel9.4
```

To stop tests from destroying the platforms after encountering an error (or at all, even on a successful test), pass the `--destroy=never` parameter:

```bash
molecule test -s rdbms_server_postgresql_14_tls -p rhel9.4 --destroy=never
```

You can log into a running platform via the `login` subcommand and the `-h/--host` parameter:

```bash
molecule login -s rdbms_server_postgresql_14_tls -h rhel9.4
```

As well as pass extra parameters to the underlying playbook (`converge` command only!):

# Unit tests
ansible-test units --docker --python 3.9
```bash
molecule converge -s rdbms_server_postgresql_14_tls -- -vvv -t tls_config
```

### Running `pytest` tests

We use the `ansible-pytest` plugin to run unit and integration tests for the collection.

To see what tests (unit and integration) are available, run the following from the `ANSIBLE_COLLECTIONS_PATH` directory:

```bash
pytest ansible_collections/cloudera/exe --collect-only
```

You should see something like:

```
platform darwin -- Python 3.12.4, pytest-8.3.3, pluggy-1.5.0
ansible: 2.16.11
rootdir: /Users/wmudge/Devel/ansible_collections/cloudera/exe
configfile: pyproject.toml
testpaths: tests
plugins: ansible-24.9.0, xdist-3.6.1
collected 8 items

# Integration tests
ansible-test integration --docker
<Dir exe>
<Dir tests>
<Dir integration>
<Module test_molecule_integration.py>
<Function test_integration[extensions-rdbms_server_postgresql_14_tls]>
<Function test_integration[extensions-rdbms_server_postgresql_default]>
<Function test_integration[extensions-rdbms_server_postgresql_14]>
<Function test_integration[platform-default]>
<Function test_integration[platform-level0]>
<Function test_integration[runtime-default]>
<Function test_integration[runtime-level0]>
<Package unit>
<Package plugins>
<Package filter>
<Module test_core_exe.py>
<UnitTestCase TestFilterModule>
<TestCaseFunction test_combine_onto>
```

To run the _integration_ tests, you first need to have a running virtual environment configured with Ansible (`core`) and the required collections. When you run `ansible-test`, the program will bootstrap the [requirements|tests/integration/requirements.txt] in the Docker container and mount the `ANSIBLE_COLLECTION_PATHS`.
To run a selected test, execute with a regex:

```bash
# In your favorite VENV...
pip3 install ansible-core
ansible-galaxy collection install -p collections -r galaxy.yml
export ANSIBLE_COLLECTION_PATHS="$(pwd)/collections"
pytest ansible_collections/cloudera/exe -k "postgresql_14_tls"
```

You also need to provide AWS credentials and test configuration in the `integration_config.yml` file. This file is *not* included in the project, as it will contain sensitive data, but there is a template -- `integration_config.yml.template` -- that you can copy and update as needed.
To run a Molecule scenario on a selected platform, i.e. target host, set the platform via the environment variable:

```bash
MOLECULE_PLATFORM_NAME="rhel9.4" pytest ansible_collections/cloudera/exe -k "postgresql_14_tls"
```

> [!warning]
> If you run `pytest` in the root of the collection, `pytest` will copies the current collection into the required Ansible collection path structure within the working directory. That is, running `pytest` at the root of the **collection** creates a `collection/ansible_collections/<namespace>/<name>` **within** the collection.
> Thus, our recommendation is that you can run `pytest` in at the root of the **Ansible collections path**. That is, run `pytest ansible_collections/<namespace>/<name> ...` so that `pytest` doesn't have to bootstrap the collections path.

## Linting and Commits

The `pre-commit` Python application is used to manage linting and other housekeeping functions. The application is installed as a `git` hook and as a Github workflow check.

Commits and pull requests will fail if your contributions do not pass the `pre-commit` checks. You can check your work-in-progress code by running the following:

```bash
pre-commit run -a
```
40 changes: 40 additions & 0 deletions extensions/molecule/default/Dockerfile-rhel.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Derived from molecule-plugins[podman]

{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}

{% if item.env is defined %}
{% for var, value in item.env.items() %}
{% if value %}
ENV {{ var }} {{ value }}
{% endif %}
{% endfor %}
{% endif %}

RUN dnf makecache && dnf --assumeyes install \
python3 \
python3-devel \
python3-dnf \
sudo \
bash \
iproute \
&& dnf clean all

CMD ["/sbin/init"]
50 changes: 50 additions & 0 deletions extensions/molecule/default/Dockerfile-ubuntu.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Derived from molecule-plugins[podman]

{% if item.registry is defined %}
FROM {{ item.registry.url }}/{{ item.image }}
{% else %}
FROM {{ item.image }}
{% endif %}

{% if item.env is defined %}
{% for var, value in item.env.items() %}
{% if value %}
ENV {{ var }} {{ value }}
{% endif %}
{% endfor %}
{% endif %}

ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
python3-pip \
python3-apt \
python3-dev \
sudo \
bash \
gpgv2 \
systemd \
systemd-cron \
xmlsec1 \
libxmlsec1-openssl \
libpq-dev \
&& apt-get clean \
&& rm -Rf /usr/share/doc && rm -Rf /usr/share/man \
&& rm -rf /var/lib/apt/lists/*

CMD ["/lib/systemd/systemd"]
20 changes: 20 additions & 0 deletions extensions/molecule/default/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

- name: Default test
hosts: all
gather_facts: yes
tasks:
- name: Heartbeat
ansible.builtin.ping:
38 changes: 38 additions & 0 deletions extensions/molecule/default/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

driver:
name: podman
dependency:
name: galaxy
options:
requirements-file: "${MOLECULE_SCENARIO_DIRECTORY}/requirements.yml"
role-file: "${MOLECULE_SCENARIO_DIRECTORY}/requirements.yml"
platforms:
- name: rhel9.4
image: registry.access.redhat.com/ubi9/ubi:9.4
dockerfile: Dockerfile-rhel.j2
command: /sbin/init
- name: rhel8.10
image: registry.access.redhat.com/ubi8/ubi:8.10
dockerfile: Dockerfile-rhel.j2
command: /sbin/init
- name: ubuntu22.04
image: ubuntu:22.04
dockerfile: Dockerfile-ubuntu.j2
command: /lib/systemd/systemd
- name: ubuntu20.04
image: ubuntu:20.04
dockerfile: Dockerfile-ubuntu.j2
command: /lib/systemd/systemd
17 changes: 17 additions & 0 deletions extensions/molecule/default/requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 Cloudera, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

collections:
- containers.podman
- ansible.posix
Loading
Loading