diff --git a/docs/dictionary/en-custom.txt b/docs/dictionary/en-custom.txt index e5f0a6332a..add6797c83 100644 --- a/docs/dictionary/en-custom.txt +++ b/docs/dictionary/en-custom.txt @@ -153,6 +153,7 @@ dib dicts dirs disablecertificateverification +diskimage disksize distro dlrn diff --git a/roles/nat64_appliance/README.md b/roles/nat64_appliance/README.md index f7933cc078..36bd1c0cc8 100644 --- a/roles/nat64_appliance/README.md +++ b/roles/nat64_appliance/README.md @@ -25,6 +25,9 @@ * `cifmw_nat64_appliance_memory`: (Integer) Memory in GiB for the nat64 appliance VM. Defaults to: `2`. * `cifmw_nat64_appliance_cpus`: (Integer) Virtual CPUs for the nat64 appliance VM. Defaults to: `2`. * `cifmw_nat64_appliance_ssh_pub_keys`: (List) List of SSH public key for the nat64 appliance VM. Defaults to: `[]`. +* `cifmw_nat64_appliance_image_url`: (String) URL to download a pre-built NAT64 appliance image. If empty, the image will be built from source using diskimage-builder. Defaults to: `""`. +* `cifmw_nat64_appliance_image_checksum`: (String) Optional checksum for the downloaded image in the format `algorithm:hash` (e.g., `sha256:xxxxx`). Only used when `cifmw_nat64_appliance_image_url` is set. Defaults to: undefined. +* `cifmw_nat64_appliance_download_timeout`: (Integer) Timeout in seconds for image download. Only used when `cifmw_nat64_appliance_image_url` is set. Defaults to: `600`. * `cifmw_nat64_ipv6_prefix`: (String) IPv6 prefix for nat64. Defaults to: `fc00:abcd:abcd:fc00::/64`. * `cifmw_nat64_ipv6_tayga_address`: (String) Tayga IPv6 address. Defaults to: `fc00:abcd:abcd:fc00::3`. @@ -32,14 +35,28 @@ Include the `nat64_appliance` role in a playbook. For example: +### Build from source + +```yaml +- name: Build nat64-appliance from source + hosts: "{{ cifmw_target_host | default('localhost') }}" + roles: + - nat64_appliance ``` -- name: Build nat64-appliance + +### Download pre-built image + +```yaml +- name: Download pre-built nat64-appliance image hosts: "{{ cifmw_target_host | default('localhost') }}" + vars: + cifmw_nat64_appliance_image_url: "http://example.com/nat64-appliance.qcow2" + # cifmw_nat64_appliance_image_checksum: "sha256:xxxxx" # Optional roles: - nat64_appliance ``` -The built image will be in: `{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2` +The image will be in: `{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2` ## Using the nat64-appliance diff --git a/roles/nat64_appliance/defaults/main.yml b/roles/nat64_appliance/defaults/main.yml index 3c4ea8ac1b..6fdf18b8bf 100644 --- a/roles/nat64_appliance/defaults/main.yml +++ b/roles/nat64_appliance/defaults/main.yml @@ -40,6 +40,10 @@ cifmw_nat64_appliance_memory: 2 cifmw_nat64_appliance_cpus: 2 cifmw_nat64_appliance_ssh_pub_keys: [] +# Image download configuration +# Set cifmw_nat64_appliance_image_url to download a pre-built image +cifmw_nat64_appliance_image_url: "" +cifmw_nat64_appliance_download_timeout: 600 # 10 minutes cifmw_nat64_ipv6_prefix: "2620:cf:cf:fc00::/64" cifmw_nat64_ipv6_tayga_address: "2620:cf:cf:fc00::3" diff --git a/roles/nat64_appliance/molecule/default/converge.yml b/roles/nat64_appliance/molecule/default/converge.yml index 8421a4c576..c0ed9ecb9a 100644 --- a/roles/nat64_appliance/molecule/default/converge.yml +++ b/roles/nat64_appliance/molecule/default/converge.yml @@ -55,6 +55,7 @@ retries: 60 delay: 10 + # Build the image - name: Build nat64 appliance image vars: # TODO(hjensas): Running as root should not be required here. @@ -85,6 +86,81 @@ owner: "{{ ansible_user_id }}" group: "{{ ansible_user_gid }}" + # Test download functionality + - name: Set download test directory + ansible.builtin.set_fact: + cifmw_nat64_download_dir: "{{ cifmw_basedir }}/nat64_download" + cifmw_nat64_http_port: 8765 + + - name: Start HTTP server to serve the built image + ansible.builtin.shell: | + cd {{ cifmw_basedir }}/nat64_appliance + nohup python3 -m http.server {{ cifmw_nat64_http_port }} > /tmp/nat64_http_server.log 2>&1 & + echo $! > /tmp/nat64_http_server.pid + sleep 2 + + - name: Verify HTTP server is running + ansible.builtin.uri: + url: "http://localhost:{{ cifmw_nat64_http_port }}/nat64-appliance.qcow2" + method: HEAD + register: _http_check + until: _http_check.status == 200 + retries: 5 + delay: 2 + + - name: Download nat64 appliance image from HTTP server + vars: + cifmw_nat64_appliance_basedir: "{{ cifmw_nat64_download_dir }}" + cifmw_nat64_appliance_image_url: "http://localhost:{{ cifmw_nat64_http_port }}/nat64-appliance.qcow2" + ansible.builtin.include_role: + name: nat64_appliance + + - name: Verify downloaded image exists + ansible.builtin.stat: + path: "{{ cifmw_nat64_download_dir }}/nat64_appliance/nat64-appliance.qcow2" + checksum_algorithm: sha256 + register: _downloaded_image + failed_when: not _downloaded_image.stat.exists + + - name: Get built image info with checksum + ansible.builtin.stat: + path: "{{ cifmw_basedir }}/nat64_appliance/nat64-appliance.qcow2" + checksum_algorithm: sha256 + register: _built_image + + - name: Show download test results + ansible.builtin.debug: + msg: + - "Built image: {{ _built_image.stat.path }} ({{ _built_image.stat.size }} bytes, SHA256: {{ _built_image.stat.checksum }})" + - "Downloaded image: {{ _downloaded_image.stat.path }} ({{ _downloaded_image.stat.size }} bytes, SHA256: {{ _downloaded_image.stat.checksum }})" + + - name: Verify images are identical using checksum + ansible.builtin.assert: + that: + - _downloaded_image.stat.size > 0 + - _built_image.stat.size > 0 + - _downloaded_image.stat.checksum == _built_image.stat.checksum + fail_msg: | + Downloaded image differs from built image! + Built: {{ _built_image.stat.size }} bytes, SHA256: {{ _built_image.stat.checksum }} + Downloaded: {{ _downloaded_image.stat.size }} bytes, SHA256: {{ _downloaded_image.stat.checksum }} + success_msg: "Images are identical - SHA256: {{ _built_image.stat.checksum }} ({{ _built_image.stat.size }} bytes)" + + - name: Stop HTTP server + ansible.builtin.shell: | + if [ -f /tmp/nat64_http_server.pid ]; then + kill $(cat /tmp/nat64_http_server.pid) || true + rm -f /tmp/nat64_http_server.pid + fi + + # Deploy nat64 appliance for testing + - name: Copy downloaded image to working location for deployment + ansible.builtin.copy: + src: "{{ cifmw_nat64_download_dir }}/nat64_appliance/nat64-appliance.qcow2" + dest: "{{ cifmw_basedir }}/nat64_appliance/nat64-appliance.qcow2" + remote_src: true + mode: "0644" + - name: "Deploy the nat64 appliance and networks" vars: cifmw_nat64_appliance_ssh_pub_keys: diff --git a/roles/nat64_appliance/tasks/cleanup.yml b/roles/nat64_appliance/tasks/cleanup.yml index f58b4cc8af..02e6c9e6db 100644 --- a/roles/nat64_appliance/tasks/cleanup.yml +++ b/roles/nat64_appliance/tasks/cleanup.yml @@ -32,8 +32,19 @@ community.libvirt.virt: command: list_vms - - name: Stop the nat64_appliance VM + - name: Get nat64_appliance VM state when: cifmw_nat64_appliance_name in _list_vms.list_vms + register: _vm_state + community.libvirt.virt: + command: status + name: "{{ cifmw_nat64_appliance_name }}" + uri: "{{ cifmw_nat64_libvirt_uri }}" + + - name: Stop the nat64_appliance VM + when: + - cifmw_nat64_appliance_name in _list_vms.list_vms + - _vm_state.status is defined + - _vm_state.status == "running" community.libvirt.virt: command: destroy name: "{{ cifmw_nat64_appliance_name }}" diff --git a/roles/nat64_appliance/tasks/main.yml b/roles/nat64_appliance/tasks/main.yml index 2a9aa941ce..24ba0861e7 100644 --- a/roles/nat64_appliance/tasks/main.yml +++ b/roles/nat64_appliance/tasks/main.yml @@ -29,52 +29,66 @@ state: directory mode: "0755" -- name: Install required RPM packages - tags: - - packages - become: true - ansible.builtin.package: - name: - - python3-pip - - qemu-img - - dosfstools - - xfsprogs - state: present +- name: Build NAT64 appliance image from source + when: + - cifmw_nat64_appliance_image_url | length == 0 + block: + - name: Install required RPM packages + tags: + - packages + become: true + ansible.builtin.package: + name: + - python3-pip + - qemu-img + - dosfstools + - xfsprogs + state: present -- name: Install diskimage-builder in virtualenv - tags: - - packages - ansible.builtin.pip: - virtualenv_command: "python3 -m venv" - virtualenv: "{{ cifmw_nat64_appliance_venv_dir }}" - name: - - diskimage-builder - - setuptools + - name: Install diskimage-builder in virtualenv + tags: + - packages + ansible.builtin.pip: + virtualenv_command: "python3 -m venv" + virtualenv: "{{ cifmw_nat64_appliance_venv_dir }}" + name: + - diskimage-builder + - setuptools -- name: Copy files to cifmw_nat64_appliance_dir - ansible.builtin.copy: - src: "{{ item }}" - dest: "{{ cifmw_nat64_appliance_workdir }}/{{ item }}" - mode: preserve - loop: - - "elements/" - - nat64-appliance.yaml + - name: Copy files to cifmw_nat64_appliance_dir + ansible.builtin.copy: + src: "{{ item }}" + dest: "{{ cifmw_nat64_appliance_workdir }}/{{ item }}" + mode: preserve + loop: + - "elements/" + - nat64-appliance.yaml + + - name: Clone edpm-image-builder (reset-bls-entries dib element) + ansible.builtin.git: + repo: https://github.com/openstack-k8s-operators/edpm-image-builder.git + dest: "{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder" + version: main -- name: Clone edpm-image-builder (reset-bls-entries dib element) - ansible.builtin.git: - repo: https://github.com/openstack-k8s-operators/edpm-image-builder.git - dest: "{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder" - version: main + - name: Build the nat64-appliance image using DIB + become: "{{ cifmw_nat64_appliance_run_dib_as_root | default(false) | bool }}" + environment: + ELEMENTS_PATH: "{{ cifmw_nat64_appliance_workdir }}/elements:{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder/dib/" + DIB_IMAGE_CACHE: "{{ cifmw_nat64_appliance_workdir }}/cache" + DIB_DEBUG_TRACE: '1' + cifmw.general.ci_script: + chdir: "{{ cifmw_nat64_appliance_workdir }}" + output_dir: "{{ cifmw_nat64_appliance_basedir }}/artifacts" + creates: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" + script: "{{ cifmw_nat64_appliance_venv_dir }}/bin/diskimage-builder nat64-appliance.yaml {{ extra_args | default('') }}" + executable: "/bin/bash" -- name: Build the nat64-appliance image using DIB - become: "{{ cifmw_nat64_appliance_run_dib_as_root | default(false) | bool }}" - environment: - ELEMENTS_PATH: "{{ cifmw_nat64_appliance_workdir }}/elements:{{ cifmw_nat64_appliance_workdir }}/edpm-image-builder/dib/" - DIB_IMAGE_CACHE: "{{ cifmw_nat64_appliance_workdir }}/cache" - DIB_DEBUG_TRACE: '1' - cifmw.general.ci_script: - chdir: "{{ cifmw_nat64_appliance_workdir }}" - output_dir: "{{ cifmw_nat64_appliance_basedir }}/artifacts" - creates: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" - script: "{{ cifmw_nat64_appliance_venv_dir }}/bin/diskimage-builder nat64-appliance.yaml {{ extra_args | default('') }}" - executable: "/bin/bash" +- name: Download pre-built NAT64 appliance image + when: + - cifmw_nat64_appliance_image_url | length > 0 + ansible.builtin.get_url: + url: "{{ cifmw_nat64_appliance_image_url }}" + dest: "{{ cifmw_nat64_appliance_workdir }}/nat64-appliance.qcow2" + checksum: "{{ cifmw_nat64_appliance_image_checksum | default(omit) }}" + timeout: "{{ cifmw_nat64_appliance_download_timeout }}" + mode: "0644"