incus-contrib/ansible/playbooks/showcase/common.yml

232 lines
7.4 KiB
YAML

---
# showcase/common.yml — Common setup tasks for all showcase instances
#
# Included by showcase-post-deploy.yml after name parsing.
# Uses vars from the parent play: incus_api, incus_cert, incus_key,
# base_packages, ffsdn_*, blueprint_name, component_name.
#
# Adds a temporary incusbr0 NIC for internet access during package
# installation (OVN SNAT may not provide outbound internet in all labs),
# then the deploy-instance playbook removes it after setup completes.
# ── Step 1: Add temporary internet NIC ──────────────────────────────
- name: Add temporary incusbr0 NIC for internet access
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}"
method: PATCH
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body_format: json
body:
devices:
eth-setup:
type: nic
network: incusbr0
name: eth1
status_code: [200, 202]
return_content: true
register: nic_add_result
- name: Wait for NIC addition if async
ansible.builtin.uri:
url: "{{ incus_api }}{{ nic_add_result.json.operation }}/wait?timeout=30"
method: GET
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
return_content: true
when: nic_add_result.status == 202
- name: Push NIC activation script
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/files?path=/tmp/activate-eth1.sh"
method: POST
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body: |
#!/bin/bash
# Configure eth1 for DHCP via systemd-networkd
mkdir -p /etc/systemd/network
cat > /etc/systemd/network/80-eth1.network << 'EOF'
[Match]
Name=eth1
[Network]
DHCP=yes
[DHCPv4]
RouteMetric=100
EOF
ip link set eth1 up
systemctl restart systemd-networkd
# Wait up to 15s for IPv4 address
for i in $(seq 1 15); do
if ip -4 addr show eth1 | grep -q 'inet '; then
exit 0
fi
sleep 1
done
# Last resort: try dhclient
dhclient eth1 2>/dev/null || true
sleep 2
headers:
Content-Type: "application/octet-stream"
X-Incus-type: "file"
X-Incus-mode: "0755"
status_code: [200]
- name: Activate temporary NIC inside container
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
method: POST
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body_format: json
body:
command: ["/bin/bash", "/tmp/activate-eth1.sh"]
record-output: true
interactive: false
wait-for-websocket: false
status_code: [202]
return_content: true
register: nic_activate_exec
- name: Wait for NIC activation (up to 30s)
ansible.builtin.uri:
url: "{{ incus_api }}{{ nic_activate_exec.json.operation }}/wait?timeout=30"
method: GET
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
return_content: true
- name: Wait for DHCP on temporary NIC (up to 30s)
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/state"
method: GET
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
return_content: true
register: nic_state
until: >-
nic_state.json.metadata.network is defined and
nic_state.json.metadata.network.eth1 is defined and
nic_state.json.metadata.network.eth1.addresses | selectattr('family', 'equalto', 'inet') | list | length > 0
retries: 6
delay: 5
# ── Step 2: Run base setup with internet access ────────────────────
- name: Generate base setup script
ansible.builtin.set_fact:
base_setup_script: |
#!/bin/bash
set -e
echo "=== Showcase base setup starting ==="
echo "Blueprint: {{ blueprint_name }}, Component: {{ component_name }}"
# Set hostname
hostname {{ ffsdn_instance_name }}
echo "{{ ffsdn_instance_name }}" > /etc/hostname
sed -i '/^127\.0\.1\.1/d' /etc/hosts
echo "127.0.1.1 {{ ffsdn_instance_name }}" >> /etc/hosts
echo "[OK] Hostname set to {{ ffsdn_instance_name }}"
# Update package cache and install base packages
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq {{ base_packages }} 2>&1 | tail -1
echo "[OK] Base packages installed"
# Set timezone
ln -sf /usr/share/zoneinfo/UTC /etc/localtime
echo "UTC" > /etc/timezone
echo "[OK] Timezone set to UTC"
# Write deployment metadata
cat > /etc/deploy-info << 'DEPLOYINFO'
blueprint={{ blueprint_name }}
component={{ component_name }}
hostname={{ ffsdn_instance_name }}
ip={{ ffsdn_instance_ip | default('unknown') }}
cluster={{ ffsdn_cluster_name | default('unknown') }}
deployed_by={{ ffsdn_deployed_by | default('unknown') }}
image={{ ffsdn_image_os | default('') }}/{{ ffsdn_image_release | default('') }}
DEPLOYINFO
echo "deployed=$(date -Iseconds)" >> /etc/deploy-info
echo "[OK] Deployment metadata written"
echo "=== Showcase base setup complete ==="
- name: Push base setup script to instance
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/files?path=/tmp/showcase-setup.sh"
method: POST
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body: "{{ base_setup_script }}"
headers:
Content-Type: "application/octet-stream"
X-Incus-type: "file"
X-Incus-mode: "0755"
status_code: [200]
- name: Execute base setup script
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
method: POST
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body_format: json
body:
command: ["/bin/bash", "/tmp/showcase-setup.sh"]
record-output: true
interactive: false
wait-for-websocket: false
environment:
DEBIAN_FRONTEND: "noninteractive"
status_code: [202]
return_content: true
register: base_setup_exec
- name: Wait for base setup to complete (up to 3 minutes)
ansible.builtin.uri:
url: "{{ incus_api }}{{ base_setup_exec.json.operation }}/wait?timeout=180"
method: GET
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
return_content: true
timeout: 200
register: base_setup_wait
failed_when: base_setup_wait.json.metadata.status != "Success"
- name: Verify base setup exit code
ansible.builtin.assert:
that:
- base_setup_wait.json.metadata.metadata.return | int == 0
fail_msg: "Base setup exited with code {{ base_setup_wait.json.metadata.metadata.return }}"
success_msg: "Base setup completed successfully"
- name: Clean up base setup script
ansible.builtin.uri:
url: "{{ incus_api }}/1.0/instances/{{ ffsdn_instance_name }}/exec"
method: POST
client_cert: "{{ incus_cert }}"
client_key: "{{ incus_key }}"
validate_certs: false
body_format: json
body:
command: ["/bin/rm", "-f", "/tmp/showcase-setup.sh"]
record-output: false
interactive: false
wait-for-websocket: false
status_code: [202]
ignore_errors: true