232 lines
7.4 KiB
YAML
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
|