Skip to content

Commit 8a19589

Browse files
authored
Merge pull request #12 from cozystack/fix/multi-master-nodes
fix(kubeovn): derive MASTER_NODES from server group for multi-master support
2 parents 6eb8e37 + 68dd433 commit 8a19589

14 files changed

Lines changed: 278 additions & 6 deletions

.github/workflows/test.yml

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,49 @@ jobs:
6464
working-directory: ansible_collections/cozystack/installer
6565
run: ansible-test sanity --color
6666

67+
master-nodes:
68+
name: Multi-master MASTER_NODES
69+
runs-on: ubuntu-latest
70+
steps:
71+
- name: Checkout
72+
uses: actions/checkout@v6
73+
74+
- name: Set up Python
75+
uses: actions/setup-python@v6
76+
with:
77+
python-version: "3.14"
78+
79+
- name: Install Ansible and dependencies
80+
run: pip install ansible-core netaddr
81+
82+
- name: Install required collections
83+
run: ansible-galaxy collection install ansible.utils
84+
85+
- name: Test auto-detection from server group (3 nodes)
86+
run: >-
87+
ansible-playbook tests/test-master-nodes.yml
88+
--inventory tests/test-multi-master-inventory.yml
89+
90+
- name: Test single-node auto-detection (IP host key)
91+
run: >-
92+
ansible-playbook tests/test-master-nodes.yml
93+
--inventory tests/test-single-master-inventory.yml
94+
95+
- name: Test single-node explicit override (CI inventory)
96+
run: >-
97+
ansible-playbook tests/test-master-nodes.yml
98+
--inventory tests/ci-inventory.yml
99+
100+
- name: Test hostname host keys are rejected
101+
run: |
102+
if ansible-playbook tests/test-master-nodes.yml \
103+
--inventory tests/test-hostname-inventory.yml 2>&1; then
104+
echo "ERROR: Expected failure for hostname host keys, but playbook succeeded"
105+
exit 1
106+
else
107+
echo "OK: Hostname host keys correctly rejected"
108+
fi
109+
67110
e2e:
68111
name: E2E
69112
runs-on: ubuntu-latest
@@ -76,8 +119,8 @@ jobs:
76119
with:
77120
python-version: "3.14"
78121

79-
- name: Install Ansible
80-
run: pip install ansible-core
122+
- name: Install Ansible and dependencies
123+
run: pip install ansible-core netaddr
81124

82125
- name: Build and install collection
83126
run: |

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ Runs on `server[0]` only.
203203
| `cozystack_pod_gateway` | `10.42.0.1` | Pod gateway |
204204
| `cozystack_svc_cidr` | `10.43.0.0/16` | Service CIDR |
205205
| `cozystack_join_cidr` | `100.64.0.0/16` | Join CIDR |
206+
| `cozystack_master_nodes` | `""` (auto-detect) | Comma-separated control-plane node IPs for kube-ovn RAFT. Empty = auto-detect from `server` group |
206207
| `cozystack_operator_wait_timeout` | `300` | Timeout for operator/CRD readiness (seconds) |
207208

208209
## Using with k3s
@@ -229,6 +230,31 @@ or `examples/suse/`:
229230

230231
On cloud providers with NAT (OCI, AWS, GCP), nodes have internal IPs different from public IPs. KubeOVN validates the host IP against `NODE_IPS` and crashes if they don't match. Always use the IP visible on the node's network interface.
231232

233+
### Multi-master setup (kube-ovn RAFT)
234+
235+
Kube-ovn requires `MASTER_NODES` — a comma-separated list of all
236+
control-plane node IPs for OVN RAFT consensus. By default, the role
237+
auto-detects these IPs from the `server` inventory group host keys.
238+
239+
This works when host keys are internal IPs (the recommended inventory
240+
pattern):
241+
242+
```yaml
243+
server:
244+
hosts:
245+
10.0.0.10:
246+
ansible_host: 203.0.113.10
247+
10.0.0.11:
248+
ansible_host: 203.0.113.11
249+
```
250+
251+
If your inventory uses hostnames or non-IP host keys, set
252+
`cozystack_master_nodes` explicitly:
253+
254+
```yaml
255+
cozystack_master_nodes: "10.0.0.10,10.0.0.11,10.0.0.12"
256+
```
257+
232258
### Automatic Helm installation
233259

234260
The role installs Helm and the

examples/ubuntu/inventory.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@ cluster:
33
children:
44
server:
55
hosts:
6-
# Internal IP as host key, public IP as ansible_host
6+
# Internal IP as host key, public IP as ansible_host.
7+
# All server host keys are auto-collected as kube-ovn MASTER_NODES.
78
10.0.0.10:
89
ansible_host: 203.0.113.10
9-
agent:
10-
hosts:
1110
10.0.0.11:
1211
ansible_host: 203.0.113.11
1312
10.0.0.12:
1413
ansible_host: 203.0.113.12
14+
agent:
15+
hosts:
16+
10.0.0.20:
17+
ansible_host: 203.0.113.20
1518

1619
vars:
1720
ansible_port: 22
@@ -26,6 +29,10 @@ cluster:
2629
# Cozystack configuration (REQUIRED)
2730
cozystack_api_server_host: "10.0.0.10"
2831

32+
# kube-ovn master nodes (auto-detected from 'server' group host keys).
33+
# Override only if host keys are not internal IPs.
34+
# cozystack_master_nodes: "10.0.0.10,10.0.0.11,10.0.0.12"
35+
2936
# Platform Package configuration
3037
cozystack_root_host: "cozy.example.com"
3138
cozystack_platform_variant: "isp-full-generic"

galaxy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ homepage: https://cozystack.io
1616
documentation: https://cozystack.io/docs
1717
dependencies:
1818
ansible.posix: ">=1.0.0"
19+
ansible.utils: ">=2.0.0"
1920
kubernetes.core: ">=5.0.0"
2021
tags:
2122
- infrastructure

requirements.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
collections:
33
- name: ansible.posix
4+
- name: ansible.utils
45
- name: community.general
56
- name: kubernetes.core

roles/cozystack/defaults/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ cozystack_platform_variant: "isp-full-generic"
5353
# Leave empty to skip publishing config in the Platform Package
5454
cozystack_root_host: ""
5555

56+
# Comma-separated control-plane node IPs for kube-ovn RAFT consensus.
57+
# Empty = auto-detect from 'server' inventory group host keys.
58+
cozystack_master_nodes: ""
59+
5660
# Network CIDRs for the Platform Package (defaults match k3s)
5761
cozystack_pod_cidr: "10.42.0.0/16"
5862
cozystack_pod_gateway: "10.42.0.1"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
# Compute and validate master node IPs for kube-ovn.
3+
# Included from main.yml and tests.
4+
- name: Compute master node IPs for kube-ovn
5+
ansible.builtin.set_fact:
6+
_cozystack_master_nodes: >-
7+
{%- if cozystack_master_nodes | length > 0 -%}
8+
{{ cozystack_master_nodes }}
9+
{%- else -%}
10+
{{ groups['server'] | join(',') }}
11+
{%- endif -%}
12+
13+
- name: Validate master node IPs are non-empty
14+
ansible.builtin.assert:
15+
that:
16+
- _cozystack_master_nodes | length > 0
17+
fail_msg: >-
18+
Could not determine master node IPs for kube-ovn.
19+
Set cozystack_master_nodes explicitly in your inventory.
20+
21+
- name: Validate master node IPs are valid addresses
22+
ansible.builtin.assert:
23+
that:
24+
- (item | ansible.utils.ipaddr) != false
25+
fail_msg: >-
26+
'{{ item }}' is not a valid IP address in MASTER_NODES.
27+
Inventory host keys in the 'server' group must be IPs, not hostnames.
28+
Alternatively, set cozystack_master_nodes explicitly.
29+
loop: "{{ _cozystack_master_nodes.split(',') }}"

roles/cozystack/tasks/main.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
It must be the node's INTERNAL IP
1010
(visible on network interface, not public/NAT IP).
1111
12+
- name: Compute and validate master node IPs for kube-ovn
13+
ansible.builtin.include_tasks: compute-master-nodes.yml
14+
when: cozystack_create_platform_package
15+
1216
- name: Set architecture for Helm download
1317
ansible.builtin.set_fact:
1418
_cozystack_arch: "{{ 'amd64' if ansible_architecture == 'x86_64' else 'arm64' }}"

roles/cozystack/templates/platform-package.yml.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ spec:
1616
autoMount:
1717
enabled: true
1818
kube-ovn:
19-
MASTER_NODES: {{ cozystack_api_server_host | to_json }}
19+
MASTER_NODES: {{ _cozystack_master_nodes | to_json }}
2020
platform:
2121
values:
2222
networking:

tests/ci-inventory.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cluster:
2121

2222
# Cozystack configuration
2323
cozystack_api_server_host: "127.0.0.1"
24+
cozystack_master_nodes: "127.0.0.1"
2425
cozystack_root_host: "cozy.ci-test.local"
2526
cozystack_platform_variant: "isp-full-generic"
2627

0 commit comments

Comments
 (0)