diff --git a/Makefile b/Makefile index 795d46e6a..69886995b 100644 --- a/Makefile +++ b/Makefile @@ -281,20 +281,28 @@ distro-clean: # Ansible dev lifecycle (experimental, parallel to dev-*.sh / reset-dev-env.sh). # See scripts/ansible/README.md and docs/development/improvements/ansible-dev-lifecycle.md. +# +# Variable overrides: pass EXTRA_VARS="key=val key2=val2" to forward as +# `--extra-vars` to ansible-playbook. Plain `-e` on the make command line is +# make's own flag and does NOT reach ansible. +# make ansible-dev-install EXTRA_VARS="spinifex_external_pool_start=192.168.1.90 spinifex_external_pool_end=192.168.1.99" +EXTRA_VARS ?= +_ANSIBLE_EXTRA = $(if $(strip $(EXTRA_VARS)),--extra-vars "$(EXTRA_VARS)",) + ansible-dev-preflight: - cd scripts/ansible && ansible-playbook playbooks/dev-preflight.yml + cd scripts/ansible && ansible-playbook playbooks/dev-preflight.yml $(_ANSIBLE_EXTRA) ansible-dev-teardown: - cd scripts/ansible && ansible-playbook playbooks/dev-teardown.yml + cd scripts/ansible && ansible-playbook playbooks/dev-teardown.yml $(_ANSIBLE_EXTRA) ansible-dev-install: - cd scripts/ansible && ansible-playbook playbooks/dev-install.yml + cd scripts/ansible && ansible-playbook playbooks/dev-install.yml $(_ANSIBLE_EXTRA) ansible-dev-reset: - cd scripts/ansible && ansible-playbook playbooks/dev-reset.yml + cd scripts/ansible && ansible-playbook playbooks/dev-reset.yml $(_ANSIBLE_EXTRA) ansible-dev-deploy: - cd scripts/ansible && ansible-playbook playbooks/dev-deploy.yml + cd scripts/ansible && ansible-playbook playbooks/dev-deploy.yml $(_ANSIBLE_EXTRA) .PHONY: build build-ui build-installer build-lb-agent build-system-image build-microvm-image install-microvm go_build go_run preflight test test-cover test-race test-actions test-harness manifest-check diff-coverage bench run \ deploy reinstall clean \ diff --git a/scripts/ansible/README.md b/scripts/ansible/README.md index 7e3ae7c86..7c1161b90 100644 --- a/scripts/ansible/README.md +++ b/scripts/ansible/README.md @@ -83,12 +83,39 @@ Useful overrides: | `teardown_process_wait_seconds` | `30` | Grace period for processes to exit | | `spinifex_region` | `ap-southeast-2` | Region passed to `spx admin init` | | `spinifex_az` | `{{ region }}a` | AZ passed to `spx admin init` | -| `spinifex_external_mode` | `pool` | `pool` \| `nat` external networking | +| `spinifex_external_mode` | `pool` | External networking mode — `pool` or empty (NAT removed) | +| `spinifex_external_no_external` | `false` | `true` → emit `--no-external` and skip external networking | +| `spinifex_external_pool_start` | `""` | **Required** for `pool` mode — first IP of the static WAN pool | +| `spinifex_external_pool_end` | `""` | **Required** for `pool` mode — last IP of the static WAN pool | +| `spinifex_external_gateway` | `""` | WAN gateway (auto-detected when blank) | +| `spinifex_external_prefix_len` | `""` | WAN prefix length (auto-detected when blank) | +| `spinifex_external_gateway_ip` | `""` | OVN router external-IP override (`--gateway-ip`) | + +`pool` mode is mandatory unless you set `spinifex_external_no_external=true`. +`spx admin init` rejects the run without a `--external-pool` range, so the +init role asserts `spinifex_external_pool_start/_end` upfront. Either persist +them in `vars/defaults.yml`, or pass them at invocation: + +Direct `ansible-playbook` (use `-e` here — this is ansible's flag): + +``` +ansible-playbook playbooks/dev-install.yml \ + -e spinifex_external_pool_start=192.168.1.150 \ + -e spinifex_external_pool_end=192.168.1.250 +``` + +Via `make` (use `EXTRA_VARS=` — make eats its own `-e`): + +``` +make ansible-dev-install \ + EXTRA_VARS="spinifex_external_pool_start=192.168.1.150 spinifex_external_pool_end=192.168.1.250" +``` `dev-reset.yml` automatically captures `region`, `az`, `external_mode`, -pool range, gateway, prefix-len, nat gateway_ip from the existing +pool range, gateway, prefix-len and `gateway_ip` from the existing `/etc/spinifex/spinifex.toml` before teardown and replays them into -`init`. Use `-e` to override. +`init`. Legacy `external_mode = "nat"` is coerced to `"pool"` with a warn. +Use `-e` to override. ## Leak catalog diff --git a/scripts/ansible/playbooks/dev-reset.yml b/scripts/ansible/playbooks/dev-reset.yml index 6ae496bc8..82fa47d77 100644 --- a/scripts/ansible/playbooks/dev-reset.yml +++ b/scripts/ansible/playbooks/dev-reset.yml @@ -23,6 +23,7 @@ when: reset_config_stat.stat.exists # List-concat-and-take-first pattern: missing regex match falls back to current default. + # `gateway\s*=` deliberately does not match `gateway_ip` / `gateway_lrp_*`. - name: capture — extract scalars ansible.builtin.set_fact: spinifex_region: "{{ (reset_config_txt | regex_findall('region\\s*=\\s*\"([^\"]+)\"') + [spinifex_region])[0] }}" @@ -30,11 +31,25 @@ spinifex_external_mode: "{{ (reset_config_txt | regex_findall('external_mode\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_mode])[0] }}" spinifex_external_pool_start: "{{ (reset_config_txt | regex_findall('range_start\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_pool_start])[0] }}" spinifex_external_pool_end: "{{ (reset_config_txt | regex_findall('range_end\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_pool_end])[0] }}" - spinifex_external_gateway: "{{ (reset_config_txt | regex_findall('gateway\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_gateway])[0] }}" + spinifex_external_gateway: "{{ (reset_config_txt | regex_findall('\\bgateway\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_gateway])[0] }}" spinifex_external_prefix_len: "{{ (reset_config_txt | regex_findall('prefix_len\\s*=\\s*([0-9]+)') + [spinifex_external_prefix_len | string])[0] }}" - spinifex_nat_gateway_ip: "{{ (reset_config_txt | regex_findall('gateway_ip\\s*=\\s*\"([^\"]+)\"') + [spinifex_nat_gateway_ip])[0] }}" + spinifex_external_gateway_ip: "{{ (reset_config_txt | regex_findall('gateway_ip\\s*=\\s*\"([^\"]+)\"') + [spinifex_external_gateway_ip])[0] }}" when: reset_config_stat.stat.exists + # Legacy: external_mode = "nat" was removed from spx. Coerce to "pool" + # so old configs still reset cleanly; warn so the operator notices. + - name: capture — coerce legacy external_mode=nat to pool + ansible.builtin.set_fact: + spinifex_external_mode: "pool" + when: spinifex_external_mode == 'nat' + + - name: capture — warn on legacy nat coercion + ansible.builtin.debug: + msg: "⚠️ Captured external_mode=nat from legacy config; coerced to 'pool' (NAT mode removed from spx admin init)." + when: + - reset_config_stat.stat.exists + - (reset_config_txt | regex_findall('external_mode\\s*=\\s*\"nat\"')) | length > 0 + - name: capture — summary ansible.builtin.debug: msg: | @@ -44,7 +59,7 @@ external_mode={{ spinifex_external_mode }} pool={{ spinifex_external_pool_start }}-{{ spinifex_external_pool_end }} gateway={{ spinifex_external_gateway }}, prefix={{ spinifex_external_prefix_len }} - nat_gateway={{ spinifex_nat_gateway_ip }} + gateway_ip={{ spinifex_external_gateway_ip }} {% else %} No existing config; using defaults from vars/defaults.yml (or -e overrides). {% endif %} diff --git a/scripts/ansible/roles/init/tasks/main.yml b/scripts/ansible/roles/init/tasks/main.yml index 6e2b91311..a6c1c9d07 100644 --- a/scripts/ansible/roles/init/tasks/main.yml +++ b/scripts/ansible/roles/init/tasks/main.yml @@ -8,28 +8,38 @@ --node {{ spinifex_node_name }} --nodes {{ spinifex_node_count }} +- name: init — no-external opt-out + ansible.builtin.set_fact: + init_external_flags: "--no-external" + when: spinifex_external_no_external | bool + +- name: init — assert pool range supplied when mode=pool + ansible.builtin.assert: + that: + - spinifex_external_pool_start | length > 0 + - spinifex_external_pool_end | length > 0 + fail_msg: | + spx admin init requires --external-pool when --external-mode=pool. + Set spinifex_external_pool_start / spinifex_external_pool_end in + scripts/ansible/vars/defaults.yml, or pass: + -e spinifex_external_pool_start=192.168.1.150 + -e spinifex_external_pool_end=192.168.1.250 + Pass -e spinifex_external_no_external=true to skip external networking. + when: + - not (spinifex_external_no_external | bool) + - spinifex_external_mode == 'pool' + - name: init — pool-mode external flags ansible.builtin.set_fact: init_external_flags: >- --external-mode=pool --external-pool={{ spinifex_external_pool_start }}-{{ spinifex_external_pool_end }} - --external-gateway={{ spinifex_external_gateway }} - --external-prefix-len={{ spinifex_external_prefix_len }} + {% if spinifex_external_gateway | length > 0 %}--external-gateway={{ spinifex_external_gateway }}{% endif %} + {% if spinifex_external_prefix_len | string | length > 0 %}--external-prefix-len={{ spinifex_external_prefix_len }}{% endif %} + {% if spinifex_external_gateway_ip | length > 0 %}--gateway-ip={{ spinifex_external_gateway_ip }}{% endif %} when: + - not (spinifex_external_no_external | bool) - spinifex_external_mode == 'pool' - - spinifex_external_pool_start | length > 0 - - spinifex_external_pool_end | length > 0 - -- name: init — NAT-mode external flags - ansible.builtin.set_fact: - init_external_flags: >- - --external-mode=nat - --gateway-ip={{ spinifex_nat_gateway_ip }} - --external-gateway={{ spinifex_external_gateway }} - --external-prefix-len={{ spinifex_external_prefix_len }} - when: - - spinifex_external_mode == 'nat' - - spinifex_nat_gateway_ip | length > 0 - name: init — assemble full flag string ansible.builtin.set_fact: @@ -79,6 +89,6 @@ msg: | Init complete: region={{ spinifex_region }}, az={{ spinifex_az }}, node={{ spinifex_node_name }} - external_mode={{ spinifex_external_mode }} + external_mode={{ 'disabled' if (spinifex_external_no_external | bool) else spinifex_external_mode }} spinifex.target: started CA: {{ spinifex_ca_trust_path }} diff --git a/scripts/ansible/vars/defaults.yml b/scripts/ansible/vars/defaults.yml index 8d275dae9..b6348279e 100644 --- a/scripts/ansible/vars/defaults.yml +++ b/scripts/ansible/vars/defaults.yml @@ -23,12 +23,20 @@ spinifex_node_name: node1 spinifex_node_count: 1 # External network. +# spx admin init contract (as of network-layer-redesign): +# external_mode : "pool" or "" (NAT path removed) +# external_pool : MANDATORY when mode=pool — set start/end below or pass -e. +# external_gw : auto-detected from default route when blank. +# external_prefix: auto-detected from WAN when blank. +# external_gw_ip : OVN router external-IP override (was nat_gateway_ip). +# no_external : true → emit --no-external (skip external networking). spinifex_external_mode: pool +spinifex_external_no_external: false spinifex_external_pool_start: "" spinifex_external_pool_end: "" spinifex_external_gateway: "" spinifex_external_prefix_len: "" -spinifex_nat_gateway_ip: "" +spinifex_external_gateway_ip: "" # Preflight checks. spinifex_ports: