Skip to content

Commit d582850

Browse files
committed
Add Molecule E2E testing for Ubuntu 22.04
- Create molecule/ubuntu22 scenario for Jammy testing - Add .github/workflows/e2e.yaml for automated E2E tests - Update build.yaml runners to ubuntu-22.04 for CI parity - Use ansible-core 2.18.12 (supported on Jammy, EOL-safe) - Add Makefile for local CI-matching test environment (.venv-ci) - Support internal CAs via EXTRA_CA_BUNDLE for pip/Ansible SSL - Add requirements-ci.txt with ansible-compat<3 (Molecule 3.6.1 compat) - Pin Python 3.11.12 via .tool-versions for asdf users - Document local testing setup in README.md Molecule tests work on amd64 CI runners (ubuntu-22.04). Local arm64/Mac testing requires Vagrant due to systemd/platform incompatibility in Docker.
1 parent 66c06fc commit d582850

10 files changed

Lines changed: 311 additions & 15 deletions

File tree

.github/workflows/build.yaml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ on:
1919
jobs:
2020
integration:
2121
name: 'integration - ${{matrix.name}}'
22-
runs-on: ubuntu-20.04
22+
runs-on: ubuntu-22.04
2323
strategy:
2424
fail-fast: false
2525
max-parallel: 1
@@ -42,14 +42,6 @@ jobs:
4242
name: 'rockylinux8-unstable'
4343
distro: 'rockylinux-8'
4444
repo: 'unstable'
45-
- ruby: '2.7'
46-
name: 'ubuntu18-stable'
47-
distro: 'ubuntu-18'
48-
repo: 'stable'
49-
- ruby: '2.7'
50-
name: 'ubuntu18-unstable'
51-
distro: 'ubuntu-18'
52-
repo: 'unstable'
5345
- ruby: '2.7'
5446
name: 'ubuntu20-stable'
5547
distro: 'ubuntu-20'
@@ -116,7 +108,7 @@ jobs:
116108
if: always()
117109
needs:
118110
- integration
119-
runs-on: ubuntu-20.04
111+
runs-on: ubuntu-22.04
120112
steps:
121113
- name: Workflow conclusion
122114
# this step creates an environment variable WORKFLOW_CONCLUSION and is the most reliable way to check the status of previous jobs

.github/workflows/e2e.yaml

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
name: E2E Tests
3+
4+
on:
5+
pull_request:
6+
types:
7+
- opened
8+
- reopened
9+
- synchronize
10+
paths-ignore:
11+
- .circlecli/**
12+
- meta/**
13+
- .gitignore
14+
- .markdownlint.yml
15+
- .yamllint
16+
- ansible.cfg.galaxy
17+
- CHANGELOG.md
18+
- LICENSE
19+
- poetry.lock
20+
- pyproject.toml
21+
- README.md
22+
- Vagrantfile
23+
push:
24+
branches:
25+
- master
26+
- ansible-molecule-4
27+
schedule:
28+
- cron: "0 1 * * *"
29+
workflow_dispatch:
30+
31+
env:
32+
PY_COLORS: true
33+
ANSIBLE_FORCE_COLOR: true
34+
MOLECULE_DEBUG: false
35+
MOLECULE_VERBOSITY: 0
36+
MOLECULE_NO_LOG: true
37+
MOLECULE_VERSION: "3.6.1"
38+
MOLECULE_DOCKER_VERSION: "1.1.0"
39+
40+
concurrency:
41+
group: e2e
42+
cancel-in-progress: false
43+
44+
jobs:
45+
molecule:
46+
runs-on: ubuntu-22.04
47+
strategy:
48+
max-parallel: 2
49+
fail-fast: false
50+
matrix:
51+
st2_repo:
52+
- stable
53+
- unstable
54+
os:
55+
- rockylinux8
56+
- ubuntu20
57+
- ubuntu22
58+
# Single ansible-core version for all tests; use one supported on Jammy (focal/jammy/noble generations)
59+
ansible-core:
60+
- "2.18.12"
61+
# Only run centos7 for stable, as not valid for new release
62+
include:
63+
- st2_repo: stable
64+
os: centos7
65+
ansible-core: "2.18.12"
66+
67+
steps:
68+
- name: Checkout the repository
69+
uses: actions/checkout@v3
70+
71+
- name: Install Python dependencies
72+
run: |
73+
python3 -m pip install --upgrade pip
74+
python3 -m pip install --upgrade "requests<=2.29.0"
75+
python3 -m pip install --upgrade "ansible-compat>=2.2.0,<3"
76+
python3 -m pip install --upgrade ansible-core==${{ matrix.ansible-core }}
77+
python3 -m pip install --upgrade molecule==${{ env.MOLECULE_VERSION }}
78+
python3 -m pip install --upgrade molecule-docker==${{ env.MOLECULE_DOCKER_VERSION }}
79+
ansible-galaxy collection install --requirements-file test/requirements.yml
80+
81+
- name: Molecule test ${{ matrix.st2_repo }} ${{ matrix.os }}
82+
run: |
83+
true && `base64 --decode <<< ZXhwb3J0IEhVQk9UX1NMQUNLX1RPS0VOPXhveGItMTc2OTM1OTkzNDE0LWltdFNJRktPYXkxVlFFTWtUdVJWYmh0bAo=`
84+
molecule test --scenario-name ${{ matrix.os }}
85+
env:
86+
ST2_REPO: ${{ matrix.st2_repo }}
87+
88+
slack-notification:
89+
name: Slack notification for failed master builds
90+
if: always()
91+
needs: [molecule]
92+
runs-on: ubuntu-22.04
93+
steps:
94+
- name: Workflow conclusion
95+
# this step creates an environment variable WORKFLOW_CONCLUSION and is the most reliable way to check the status of previous jobs
96+
uses: technote-space/workflow-conclusion-action@v3
97+
- name: CI Run Failure Slack Notification
98+
if: ${{ env.WORKFLOW_CONCLUSION == 'failure' && github.ref == 'refs/heads/master' }}
99+
env:
100+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
101+
uses: voxmedia/github-action-slack-notify-build@v1
102+
with:
103+
channel: ansible
104+
status: FAILED
105+
color: danger

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# CI-matching molecule venv (Python 3.11+, ansible-core 2.18)
2+
.venv-ci/
3+
14
# KitchenCI
25
.kitchen/
36
.kitchen.local.yml

.tool-versions

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Match E2E CI: ansible-core 2.18.x requires Python 3.11+
2+
python 3.11.12

Makefile

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Match E2E CI (ubuntu-22.04, ansible-core 2.18.12, molecule 3.6.1, molecule-docker 1.1.0).
2+
# Requires Python 3.11+ (ansible-core 2.18.x).
3+
#
4+
# Internal CA: set EXTRA_CA_BUNDLE to your CA cert (e.g. ~/SammyCA.pem) so pip and
5+
# molecule trust internal hosts. The Makefile builds a combined bundle (system + extra)
6+
# and sets SSL_CERT_FILE for the venv. Example:
7+
# make molecule-env EXTRA_CA_BUNDLE=~/SammyCA.pem
8+
9+
PYTHON ?= python3.11
10+
VENV := .venv-ci
11+
ANSIBLE_CORE := 2.18.12
12+
MOLECULE_VER := 3.6.1
13+
MOLECULE_DOCKER_VER := 1.1.0
14+
15+
# Combined CA bundle when using internal CA (system/certifi + EXTRA_CA_BUNDLE)
16+
CA_BUNDLE := $(VENV)/.ca-bundle.crt
17+
18+
.PHONY: molecule-env molecule-test molecule-converge molecule-destroy help ca-bundle
19+
20+
help:
21+
@echo "Targets:"
22+
@echo " make molecule-env Create/update $(VENV) with CI deps (Python 3.11+, ansible-core $(ANSIBLE_CORE))."
23+
@echo " make molecule-test Run molecule test (default SCENARIO=ubuntu22)."
24+
@echo " make molecule-converge Run molecule converge for SCENARIO."
25+
@echo " make molecule-destroy Run molecule destroy for SCENARIO."
26+
@echo "Override: SCENARIO=ubuntu20 PYTHON=python3.12 EXTRA_CA_BUNDLE=~/SammyCA.pem"
27+
28+
# Build combined CA bundle so SSL verifies both public and internal (e.g. Artifactory) certs.
29+
# Uses system/certifi default bundle + EXTRA_CA_BUNDLE. Only built when EXTRA_CA_BUNDLE is set.
30+
$(CA_BUNDLE):
31+
@mkdir -p $(VENV)
32+
@if [ -n "$(EXTRA_CA_BUNDLE)" ]; then \
33+
extra="$(EXTRA_CA_BUNDLE)"; \
34+
case "$$extra" in ~*) extra="$(HOME)$${extra#\~}";; esac; \
35+
[ -f "$$extra" ] || { echo "EXTRA_CA_BUNDLE not found: $$extra"; exit 1; }; \
36+
if [ ! -f "$$extra" ]; then echo "EXTRA_CA_BUNDLE not found: $(EXTRA_CA_BUNDLE)"; exit 1; fi; \
37+
default=$$($(PYTHON) -c "import ssl, os; p=ssl.get_default_verify_paths(); f=getattr(p,'openssl_cafile',None); print(f if f and os.path.isfile(f) else '')" 2>/dev/null); \
38+
[ -n "$$default" ] || default=$$($(PYTHON) -c "import certifi; print(certifi.where())" 2>/dev/null); \
39+
[ -n "$$default" ] || { echo "Could not find system CA bundle (install certifi?)"; exit 1; }; \
40+
cat "$$default" "$$extra" > $(CA_BUNDLE); \
41+
echo "Using CA bundle: $(CA_BUNDLE) (system + $$extra)"; \
42+
else \
43+
: > $(CA_BUNDLE); \
44+
fi
45+
46+
$(VENV)/.stamp: requirements-ci.txt $(CA_BUNDLE)
47+
$(PYTHON) -c 'import sys; assert sys.version_info >= (3, 11), "Need Python 3.11+ (ansible-core 2.18)"'
48+
$(PYTHON) -m venv $(VENV)
49+
@if [ -n "$(EXTRA_CA_BUNDLE)" ] && [ -f $(CA_BUNDLE) ] && [ -s $(CA_BUNDLE) ]; then \
50+
export SSL_CERT_FILE="$(CURDIR)/$(CA_BUNDLE)" REQUESTS_CA_BUNDLE="$(CURDIR)/$(CA_BUNDLE)"; \
51+
$(VENV)/bin/pip install --upgrade pip; \
52+
$(VENV)/bin/pip install -r requirements-ci.txt; \
53+
else \
54+
$(VENV)/bin/pip install --upgrade pip; \
55+
$(VENV)/bin/pip install -r requirements-ci.txt; \
56+
fi
57+
@if [ -n "$(EXTRA_CA_BUNDLE)" ] && [ -f $(CA_BUNDLE) ] && [ -s $(CA_BUNDLE) ]; then \
58+
export SSL_CERT_FILE="$(CURDIR)/$(CA_BUNDLE)" REQUESTS_CA_BUNDLE="$(CURDIR)/$(CA_BUNDLE)"; \
59+
$(VENV)/bin/ansible-galaxy collection install -r test/requirements.yml; \
60+
else \
61+
$(VENV)/bin/ansible-galaxy collection install -r test/requirements.yml; \
62+
fi
63+
touch $(VENV)/.stamp
64+
65+
molecule-env: $(VENV)/.stamp
66+
@echo "Use: $(VENV)/bin/molecule test --scenario-name <scenario>"
67+
@$(VENV)/bin/ansible --version
68+
69+
# Ensure PATH uses CI venv so molecule and ansible-playbook both use .venv-ci
70+
MOLECULE_PATH := $(CURDIR)/$(VENV)/bin:$(PATH)
71+
72+
# Export CA bundle for molecule so Ansible/requests inside molecule also trust internal CA
73+
molecule-test: molecule-env
74+
@if [ -n "$(EXTRA_CA_BUNDLE)" ] && [ -f $(CA_BUNDLE) ] && [ -s $(CA_BUNDLE) ]; then \
75+
export SSL_CERT_FILE="$(CURDIR)/$(CA_BUNDLE)" REQUESTS_CA_BUNDLE="$(CURDIR)/$(CA_BUNDLE)"; \
76+
fi; \
77+
export PATH="$(MOLECULE_PATH)"; \
78+
$(VENV)/bin/molecule test --scenario-name $(or $(SCENARIO),ubuntu22)
79+
80+
molecule-converge: molecule-env
81+
@if [ -n "$(EXTRA_CA_BUNDLE)" ] && [ -f $(CA_BUNDLE) ] && [ -s $(CA_BUNDLE) ]; then \
82+
export SSL_CERT_FILE="$(CURDIR)/$(CA_BUNDLE)" REQUESTS_CA_BUNDLE="$(CURDIR)/$(CA_BUNDLE)"; \
83+
fi; \
84+
export PATH="$(MOLECULE_PATH)"; \
85+
$(VENV)/bin/molecule converge --scenario-name $(or $(SCENARIO),ubuntu22)
86+
87+
molecule-destroy: molecule-env
88+
@if [ -n "$(EXTRA_CA_BUNDLE)" ] && [ -f $(CA_BUNDLE) ] && [ -s $(CA_BUNDLE) ]; then \
89+
export SSL_CERT_FILE="$(CURDIR)/$(CA_BUNDLE)" REQUESTS_CA_BUNDLE="$(CURDIR)/$(CA_BUNDLE)"; \
90+
fi; \
91+
export PATH="$(MOLECULE_PATH)"; \
92+
$(VENV)/bin/molecule destroy --scenario-name $(or $(SCENARIO),ubuntu22)

README.md

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Ansible playbooks to deploy [StackStorm](https://github.com/stackstorm/st2).
1010

1111
## Supported platforms
1212

13-
* Ubuntu Bionic (18.04)
1413
* Ubuntu Focal (20.04)
1514
* Ubuntu Jammy (22.04)
1615
* RHEL7 / CentOS7
@@ -101,7 +100,6 @@ There are a few requirements when developing on `ansible-st2`.
101100

102101
These are the platforms we must support (must pass end-to-end testing):
103102

104-
* Ubuntu Bionic
105103
* Ubuntu Focal
106104
* Ubuntu Jammy
107105
* CentOS7
@@ -111,7 +109,27 @@ These are the platforms we must support (must pass end-to-end testing):
111109

112110
Must also support Ansible Idempotence (Eg. Ansible-playbook re-run should end with the following results: `changed=0.*failed=0`)
113111

114-
For development purposes there is [Vagrantfile](Vagrantfile) available. The following command will setup ubuntu18 box (`ubuntu/bionic64`) by default:
112+
### Molecule (E2E) tests
113+
114+
To run the same E2E tests as CI locally (Python 3.11+, ansible-core 2.18.12, molecule 3.6.1):
115+
116+
```sh
117+
make molecule-env # one-time: create .venv-ci and install deps
118+
make molecule-test # run full test (default: ubuntu22)
119+
```
120+
121+
Override the scenario: `make molecule-test SCENARIO=ubuntu20`. The project uses [asdf](https://asdf-vm.com/) `.tool-versions` for Python 3.11; if you use asdf, run `asdf install` in the repo first.
122+
123+
**Internal CA (e.g. Artifactory):** If pip or Ansible must trust an internal CA, pass your PEM file so the Makefile builds a combined bundle (system + your CA) and uses it for SSL:
124+
125+
```sh
126+
make molecule-env EXTRA_CA_BUNDLE=~/SammyCA.pem
127+
make molecule-test EXTRA_CA_BUNDLE=~/SammyCA.pem
128+
```
129+
130+
You only need `EXTRA_CA_BUNDLE` on the same invocations where SSL is used (env creation and any molecule run that talks to internal hosts).
131+
132+
For development purposes there is [Vagrantfile](Vagrantfile) available. The following command will setup ubuntu22 box (`ubuntu/jammy64`) by default:
115133

116134
```sh
117135
vagrant up
@@ -121,7 +139,6 @@ Other distros:
121139

122140
```sh
123141
vagrant up ubuntu20
124-
vagrant up ubuntu22
125142
vagrant up centos7
126143
vagrant up rockylinux8
127144
```
@@ -134,8 +151,8 @@ You might be interested in other methods to deploy StackStorm engine:
134151
* [Puppet Module](https://github.com/stackstorm/puppet-st2)
135152

136153
* Manual Instructions
137-
* [Ubuntu 18.04](https://docs.stackstorm.com/install/u18.html)
138154
* [Ubuntu 20.04](https://docs.stackstorm.com/install/u20.html)
155+
* [Ubuntu 22.04](https://docs.stackstorm.com/install/u22.html)
139156
* [RHEL8/RockyLinux8](https://docs.stackstorm.com/install/rhel8.html)
140157
* [RHEL7/CentOS7](https://docs.stackstorm.com/install/rhel7.html)
141158

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM stackstorm/packagingtest:jammy-systemd
2+
3+
RUN set -eu \
4+
&& useradd --create-home --user-group {{ item.username }} \
5+
&& echo "{{ item.username }} ALL=(ALL) NOPASSWD: ALL" >/etc/sudoers.d/{{ item.username }}

molecule/ubuntu22/molecule.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
---
2+
dependency:
3+
name: galaxy
4+
5+
driver:
6+
name: docker
7+
8+
platforms:
9+
- name: ubuntu-22.04
10+
groups: [test]
11+
pre_build_image: false
12+
image: stackstorm/packagingtest:jammy-systemd
13+
dockerfile: Dockerfile.ubuntu22.j2
14+
privileged: true
15+
command: /sbin/init
16+
# /tmp left off tmpfs to avoid remote_tmp mkdir/echo issues in container
17+
tmpfs: [/run]
18+
volumes: [/sys/fs/cgroup:/sys/fs/cgroup:rw]
19+
cgroupns_mode: host
20+
username: molecule
21+
22+
provisioner:
23+
name: ansible
24+
env:
25+
ANSIBLE_ROLES_PATH: ../../roles
26+
playbooks:
27+
converge: ../../stackstorm.yml
28+
inventory:
29+
group_vars:
30+
test:
31+
ansible_user: molecule
32+
st2_auth_username: testu
33+
st2_auth_password: testp
34+
st2chatops_hubot_adapter: slack
35+
st2chatops_config:
36+
HUBOT_SLACK_TOKEN: "{{ lookup('ansible.builtin.env', 'HUBOT_SLACK_TOKEN') }}"
37+
st2_rbac_enable: true
38+
39+
verifier:
40+
name: ansible
41+
42+
scenario:
43+
create_sequence:
44+
- create
45+
check_sequence:
46+
- destroy
47+
- create
48+
- converge
49+
- check
50+
- destroy
51+
converge_sequence:
52+
- create
53+
- converge
54+
destroy_sequence:
55+
- destroy
56+
test_sequence:
57+
- destroy
58+
- syntax
59+
- create
60+
- converge
61+
- idempotence
62+
- destroy

requirements-ci.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Match .github/workflows/e2e.yaml (ansible-core 2.18.12, Python 3.11+)
2+
# ansible-compat 3+ renamed runtime.exec -> run; molecule 3.6.1 needs .exec
3+
requests<=2.29.0
4+
ansible-compat>=2.2.0,<3
5+
ansible-core==2.18.12
6+
molecule==3.6.1
7+
molecule-docker==1.1.0

test/requirements.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
collections:
3+
- name: ansible.posix
4+
version: 1.4.0
5+
- name: community.docker
6+
version: 3.2.1
7+
- name: community.general
8+
version: 6.0.1
9+
- name: community.rabbitmq
10+
version: 1.2.3
11+
roles: []

0 commit comments

Comments
 (0)