Skip to content

Commit 36c628b

Browse files
authored
fix(plugins): replace ansible.utils.ipaddr with stdlib-based test plugin (#24)
* fix(plugins): replace ansible.utils.ipaddr with stdlib-based test plugin The role used ansible.utils.ipaddr to validate master node IPs, which requires the netaddr Python package. netaddr is not installed by ansible-galaxy collection install and was not documented as a prerequisite, causing runtime failures for users who followed the README. Replace the single ipaddr usage with a new test plugin that uses the Python standard library ipaddress module. The plugin has no external dependencies and supports both IPv4 and IPv6. - Add plugins/test/ip_address.py with is_ip_address test - Use cozystack.installer.is_ip_address in compute-master-nodes.yml - Drop ansible.utils collection dependency (galaxy.yml, requirements.yml) - Drop netaddr pip install and ansible.utils install from CI - Add IPv6 inventory fixture and CI step to verify IPv6 acceptance Closes #18 Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * test(plugins): address review feedback — add unit tests, changelog, IPv6 fix - Replace fe80::1 with 2001:db8::12 in IPv6 test inventory: link-local addresses without scope ID are not realistic cluster IPs and make the test misleading. - Add unit tests for plugins/test/ip_address.py with ansible-test units coverage for IPv4, IPv6, hostnames, malformed strings, and None input. - Add CI step to run ansible-test units. - Add version_added to plugin DOCUMENTATION. - Document the dependency drop and new test in CHANGELOG.rst. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * fix(plugins): enforce string type and bump collection version - is_ip_address now rejects non-string inputs. ipaddress.ip_address() silently accepts int/bool (treating them as 32-bit address values), violating the documented type: str contract. - Bump collection version to 1.2.3 to match CHANGELOG entry and plugin version_added so ansible-test sanity passes. - Unit tests cover int, bool, bytes, and list rejection. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * docs: bump example requirements to v1.2.3 and backfill CHANGELOG - Update examples/*/requirements.yml from 1.2.2 to v1.2.3. Also adopts the v prefix — git tags are v-prefixed and installs via type: git fail without it. - Fill in missing CHANGELOG entries for v1.1.3, v1.2.1 and v1.2.2 so the v1.2.3 entry does not appear to jump from v1.1.2. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * fix: unit test package init files and README chart version - Add empty __init__.py to tests/unit/, tests/unit/plugins/ and tests/unit/plugins/test/. ansible-test units (ansible-core >= 2.15) requires these for pytest to resolve the FQCN import of the plugin module, otherwise the new Run unit tests CI step would fail with a collection import error. - Fix stale cozystack_chart_version default in README (1.1.2 to 1.2.2). The actual default in roles/cozystack/defaults/main.yml is 1.2.2. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * test(plugins): document CIDR rejection behavior ipaddress.ip_address() rejects CIDR notation since CIDR represents a network rather than a single address. Add explicit test cases to document this for both IPv4 and IPv6 CIDR inputs. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * docs(changelog): fix RST title underline length The title 'cozystack.installer Release Notes' is 33 characters, but the overline and underline were only 28. RST requires them to be at least as long as the title, so tooling that parses the file strictly would reject it. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> * ci(sanity): install pytest for ansible-test units ansible-test units runs pytest against the controller interpreter and expects pytest (plus the -n auto helpers pytest-xdist/pytest-forked and the commonly-used pytest-mock) to be importable there. Without these the job fails with 'No module named pytest' before any test runs. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la> --------- Signed-off-by: Aleksei Sviridkin <f@lex.la>
1 parent 07f63dd commit 36c628b

15 files changed

Lines changed: 211 additions & 18 deletions

File tree

.github/workflows/test.yml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,17 @@ jobs:
5757
with:
5858
python-version: "3.14"
5959

60-
- name: Install ansible-core
61-
run: pip install ansible-core
60+
- name: Install ansible-core and unit test dependencies
61+
run: pip install ansible-core pytest pytest-xdist pytest-forked pytest-mock
6262

6363
- name: Run sanity tests
6464
working-directory: ansible_collections/cozystack/installer
6565
run: ansible-test sanity --color
6666

67+
- name: Run unit tests
68+
working-directory: ansible_collections/cozystack/installer
69+
run: ansible-test units --color --python 3.14
70+
6771
master-nodes:
6872
name: Multi-master MASTER_NODES
6973
runs-on: ubuntu-latest
@@ -76,11 +80,13 @@ jobs:
7680
with:
7781
python-version: "3.14"
7882

79-
- name: Install Ansible and dependencies
80-
run: pip install ansible-core netaddr
83+
- name: Install Ansible
84+
run: pip install ansible-core
8185

82-
- name: Install required collections
83-
run: ansible-galaxy collection install ansible.utils
86+
- name: Build and install collection
87+
run: |
88+
ansible-galaxy collection build
89+
ansible-galaxy collection install cozystack-installer-*.tar.gz --force
8490
8591
- name: Test auto-detection from server group (3 nodes)
8692
run: >-
@@ -97,6 +103,11 @@ jobs:
97103
ansible-playbook tests/test-master-nodes.yml
98104
--inventory tests/ci-inventory.yml
99105
106+
- name: Test IPv6 host keys are accepted
107+
run: >-
108+
ansible-playbook tests/test-master-nodes.yml
109+
--inventory tests/test-ipv6-inventory.yml
110+
100111
- name: Test hostname host keys are rejected
101112
run: |
102113
set +e
@@ -130,8 +141,8 @@ jobs:
130141
with:
131142
python-version: "3.14"
132143

133-
- name: Install Ansible and dependencies
134-
run: pip install ansible-core netaddr
144+
- name: Install Ansible
145+
run: pip install ansible-core
135146

136147
- name: Build and install collection
137148
run: |

CHANGELOG.rst

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
1-
============================
1+
=================================
22
cozystack.installer Release Notes
3-
============================
3+
=================================
4+
5+
v1.2.3
6+
======
7+
8+
- Drop ``ansible.utils`` collection dependency and ``netaddr`` Python
9+
package requirement. Master node IP validation now uses a bundled
10+
``cozystack.installer.is_ip_address`` Jinja2 test backed by the
11+
Python standard library ``ipaddress`` module.
12+
- Add IPv6 inventory fixture and CI coverage for IPv6 host keys.
13+
14+
v1.2.2
15+
======
16+
17+
Synced with Cozystack v1.2.2.
18+
19+
- Bump ``cozystack_chart_version`` to ``1.2.2``
20+
21+
v1.2.1
22+
======
23+
24+
Synced with Cozystack v1.2.1.
25+
26+
- Bump ``cozystack_chart_version`` to ``1.2.1``
27+
- Derive ``MASTER_NODES`` for kube-ovn from the ``server`` inventory
28+
group; add ``cozystack_master_nodes`` override for multi-master setups
29+
- Validate master node entries are valid IP addresses, not hostnames
30+
31+
v1.1.3
32+
======
33+
34+
Synced with Cozystack v1.1.3.
35+
36+
- Bump ``cozystack_chart_version`` to ``1.1.3``
437

538
v1.1.2
639
======

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ Runs on `server[0]` only.
187187
| Variable | Default | Description |
188188
| --- | --- | --- |
189189
| `cozystack_chart_ref` | `oci://ghcr.io/cozystack/cozystack/cozy-installer` | Helm chart OCI reference |
190-
| `cozystack_chart_version` | `1.1.2` | Helm chart version |
190+
| `cozystack_chart_version` | `1.2.2` | Helm chart version |
191191
| `cozystack_release_name` | `cozy-installer` | Helm release name |
192192
| `cozystack_namespace` | `cozy-system` | Namespace for operator and resources |
193193
| `cozystack_release_namespace` | `kube-system` | Namespace for Helm release secret |

examples/rhel/requirements.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ collections:
1010
- name: cozystack.installer
1111
source: https://github.com/cozystack/ansible-cozystack.git
1212
type: git
13-
version: 1.2.2
13+
version: v1.2.3

examples/suse/requirements.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ collections:
1010
- name: cozystack.installer
1111
source: https://github.com/cozystack/ansible-cozystack.git
1212
type: git
13-
version: 1.2.2
13+
version: v1.2.3

examples/ubuntu/requirements.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ collections:
1010
- name: cozystack.installer
1111
source: https://github.com/cozystack/ansible-cozystack.git
1212
type: git
13-
version: 1.2.2
13+
version: v1.2.3

galaxy.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
namespace: cozystack
33
name: installer
4-
version: 1.2.2
4+
version: 1.2.3
55
readme: README.md
66
authors:
77
- Aleksei Sviridkin <f@lex.la>
@@ -16,7 +16,6 @@ homepage: https://cozystack.io
1616
documentation: https://cozystack.io/docs
1717
dependencies:
1818
ansible.posix: ">=1.0.0"
19-
ansible.utils: ">=2.0.0"
2019
kubernetes.core: ">=5.0.0"
2120
tags:
2221
- infrastructure

plugins/test/ip_address.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Copyright: (c) 2026, Cozystack Contributors
4+
# Apache License 2.0 (see LICENSE file in the repository root)
5+
6+
from __future__ import absolute_import, division, print_function
7+
8+
__metaclass__ = type
9+
10+
DOCUMENTATION = """
11+
name: is_ip_address
12+
author: Cozystack Contributors
13+
version_added: "1.2.3"
14+
short_description: Test whether a string is a valid IPv4 or IPv6 address
15+
description:
16+
- Returns True if the input is a valid IPv4 or IPv6 address.
17+
- Uses the Python standard library C(ipaddress) module, so no external
18+
dependencies (such as C(netaddr)) are required.
19+
options:
20+
_input:
21+
description: The string to test.
22+
type: str
23+
required: true
24+
"""
25+
26+
EXAMPLES = """
27+
- name: Validate an IP address
28+
ansible.builtin.assert:
29+
that:
30+
- "'10.0.0.1' is cozystack.installer.is_ip_address"
31+
- "'2001:db8::1' is cozystack.installer.is_ip_address"
32+
- "'node1.example.com' is not cozystack.installer.is_ip_address"
33+
"""
34+
35+
RETURN = """
36+
_value:
37+
description: True if input is a valid IP address, otherwise False.
38+
type: bool
39+
"""
40+
41+
from ipaddress import ip_address
42+
43+
44+
def is_ip_address(value):
45+
if not isinstance(value, str):
46+
return False
47+
try:
48+
ip_address(value)
49+
except (ValueError, TypeError):
50+
return False
51+
return True
52+
53+
54+
class TestModule:
55+
def tests(self):
56+
return {"is_ip_address": is_ip_address}

requirements.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
22
collections:
33
- name: ansible.posix
4-
- name: ansible.utils
54
- name: community.general
65
- name: kubernetes.core

roles/cozystack/tasks/compute-master-nodes.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
- name: Validate master node IPs are valid addresses
2222
ansible.builtin.assert:
2323
that:
24-
- (item | ansible.utils.ipaddr) != false
24+
- item is cozystack.installer.is_ip_address
2525
fail_msg: >-
2626
'{{ item }}' is not a valid IP address in MASTER_NODES.
2727
Inventory host keys in the 'server' group must be IPs, not hostnames.

0 commit comments

Comments
 (0)