From 0796edc2cf7db31b77a4414156a15487b8211c9a Mon Sep 17 00:00:00 2001 From: Miguel Angel Nieto Jimenez Date: Wed, 22 Oct 2025 15:33:24 +0200 Subject: [PATCH] Add FDP update automation for EDPM deployments Implement comprehensive FDP update workflow including: - New playbook fdp_update.yml orchestrating the update process - Role fdp_edpm_update_host_packages: Updates packages on EDPM hosts - Role fdp_update_container_images: Rebuilds container images with updated packages * Includes Molecule tests for validation * Jinja2 templates for Dockerfile and repo configuration - Role fdp_update_edpm_containers: Updates running EDPM containers This automation streamlines the process of updating Fast Data Path components across OpenStack EDPM (External Data Plane Management) deployments by coordinating host package updates, container image rebuilds, and container deployment updates. Assisted-By: Claude Signed-off-by: Miguel Angel Nieto Jimenez --- docs/dictionary/en-custom.txt | 2 + post-deployment.yml | 38 +++- roles/fdp_update_container_images/README.md | 105 ++++++++++ .../defaults/main.yml | 73 +++++++ .../fdp_update_container_images/meta/main.yml | 38 ++++ .../tasks/authenticate_registry.yml | 27 +++ .../tasks/configure_ca_cert.yml | 40 ++++ .../tasks/detect_registry.yml | 56 ++++++ .../tasks/fetch_images.yml | 38 ++++ .../tasks/main.yml | 78 ++++++++ .../tasks/process_image.yml | 67 +++++++ .../tasks/validate.yml | 38 ++++ .../templates/Dockerfile.j2 | 3 + .../templates/repo.j2 | 7 + roles/fdp_update_edpm/README.md | 184 ++++++++++++++++++ roles/fdp_update_edpm/defaults/main.yml | 132 +++++++++++++ roles/fdp_update_edpm/meta/main.yml | 39 ++++ .../tasks/configure_ca_cert.yml | 65 +++++++ .../tasks/create_deployment.yml | 61 ++++++ .../fdp_update_edpm/tasks/fetch_nodesets.yml | 32 +++ roles/fdp_update_edpm/tasks/main.yml | 83 ++++++++ .../fdp_update_edpm/tasks/process_nodeset.yml | 159 +++++++++++++++ .../tasks/setup_hypervisor_firewall.yml | 59 ++++++ .../tasks/update_container_images.yml | 89 +++++++++ .../tasks/update_host_packages.yml | 109 +++++++++++ roles/fdp_update_edpm/tasks/validate.yml | 33 ++++ zuul.d/molecule.yaml | 18 ++ zuul.d/projects.yaml | 2 + 28 files changed, 1674 insertions(+), 1 deletion(-) create mode 100644 roles/fdp_update_container_images/README.md create mode 100644 roles/fdp_update_container_images/defaults/main.yml create mode 100644 roles/fdp_update_container_images/meta/main.yml create mode 100644 roles/fdp_update_container_images/tasks/authenticate_registry.yml create mode 100644 roles/fdp_update_container_images/tasks/configure_ca_cert.yml create mode 100644 roles/fdp_update_container_images/tasks/detect_registry.yml create mode 100644 roles/fdp_update_container_images/tasks/fetch_images.yml create mode 100644 roles/fdp_update_container_images/tasks/main.yml create mode 100644 roles/fdp_update_container_images/tasks/process_image.yml create mode 100644 roles/fdp_update_container_images/tasks/validate.yml create mode 100644 roles/fdp_update_container_images/templates/Dockerfile.j2 create mode 100644 roles/fdp_update_container_images/templates/repo.j2 create mode 100644 roles/fdp_update_edpm/README.md create mode 100644 roles/fdp_update_edpm/defaults/main.yml create mode 100644 roles/fdp_update_edpm/meta/main.yml create mode 100644 roles/fdp_update_edpm/tasks/configure_ca_cert.yml create mode 100644 roles/fdp_update_edpm/tasks/create_deployment.yml create mode 100644 roles/fdp_update_edpm/tasks/fetch_nodesets.yml create mode 100644 roles/fdp_update_edpm/tasks/main.yml create mode 100644 roles/fdp_update_edpm/tasks/process_nodeset.yml create mode 100644 roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml create mode 100644 roles/fdp_update_edpm/tasks/update_container_images.yml create mode 100644 roles/fdp_update_edpm/tasks/update_host_packages.yml create mode 100644 roles/fdp_update_edpm/tasks/validate.yml diff --git a/docs/dictionary/en-custom.txt b/docs/dictionary/en-custom.txt index 6d203d5edd..3149b5c2a4 100644 --- a/docs/dictionary/en-custom.txt +++ b/docs/dictionary/en-custom.txt @@ -186,6 +186,7 @@ ezzmy favorit fbqufbqkfbzxrja fci +fdp fedoraproject fil filesystem @@ -414,6 +415,7 @@ openstack openstackclient openstackcontrolplane openstackdataplane +openstackdataplanedeployment openstackdataplanenodeset openstackdataplanenodesets openstackprovisioner diff --git a/post-deployment.yml b/post-deployment.yml index b0e66a41ce..ab7c250e39 100644 --- a/post-deployment.yml +++ b/post-deployment.yml @@ -8,7 +8,6 @@ tasks_from: admin_setup.yml tags: - admin-setup - - name: Run Test ansible.builtin.import_role: name: cifmw_setup @@ -26,6 +25,43 @@ tags: - compliance + # FDP Update - OpenStack package updates across all layers + - name: FDP Update - Validate required variables + when: cifmw_fdp_update_enabled | default(false) | bool + block: + - name: Validate required variables are set + ansible.builtin.assert: + that: + - cifmw_fdp_update_target_package is defined + - cifmw_fdp_update_target_package | length > 0 + - cifmw_fdp_update_repo_baseurl is defined + - cifmw_fdp_update_repo_baseurl | length > 0 + fail_msg: | + Required variables are missing! + + You must set: + - cifmw_fdp_update_target_package: Name of the RPM package to update + - cifmw_fdp_update_repo_baseurl: Repository base URL containing the updated package + success_msg: "Required variables validated successfully" + + - name: Update control plane container images + ansible.builtin.import_role: + name: fdp_update_container_images + vars: + cifmw_fdp_update_container_images_target_package: "{{ cifmw_fdp_update_target_package }}" + cifmw_fdp_update_container_images_repo_baseurl: "{{ cifmw_fdp_update_repo_baseurl }}" + cifmw_fdp_update_container_images_namespace: "{{ cifmw_fdp_update_namespace | default('openstack') }}" + when: cifmw_fdp_update_container_images_enabled | default(true) | bool + + - name: Update EDPM (containers and host packages) + ansible.builtin.import_role: + name: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_repo_baseurl: "{{ cifmw_fdp_update_repo_baseurl }}" + when: cifmw_fdp_update_edpm_enabled | default(true) | bool + tags: + - fdp-update + - name: Run compliance scan for computes hosts: "{{ groups['computes'] | default ([]) }}" gather_facts: true diff --git a/roles/fdp_update_container_images/README.md b/roles/fdp_update_container_images/README.md new file mode 100644 index 0000000000..51b5e5d08f --- /dev/null +++ b/roles/fdp_update_container_images/README.md @@ -0,0 +1,105 @@ +# fdp_update_container_images + +Ansible role to update specific RPM packages in OpenStack container images by rebuilding them with custom repositories. + +This role automates the process of: +1. Fetching container images from OpenStackVersion CR +2. Checking if target package exists in each image +3. Building new images with updated packages from custom repository +4. Pushing updated images to OpenShift internal registry +5. Patching OpenStackVersion CR to use the new images + +## Privilege escalation +None - Runs as the user executing Ansible + +## Parameters + +* `cifmw_fdp_update_container_images_basedir`: (String) Base directory. Defaults to `cifmw_basedir` which defaults to `~/ci-framework-data`. +* `cifmw_fdp_update_container_images_namespace`: (String) OpenShift namespace where OpenStack is deployed. Defaults to `openstack`. +* `cifmw_fdp_update_container_images_openstack_cr_name`: (String) Name of the OpenStackVersion CR. Defaults to `controlplane`. +* `cifmw_fdp_update_container_images_target_package`: (String) Name of the RPM package to update (e.g., `ovn24.03`). **Required**. +* `cifmw_fdp_update_container_images_repo_name`: (String) Repository name. Defaults to `custom-repo`. +* `cifmw_fdp_update_container_images_repo_baseurl`: (String) Repository base URL. **Required**. +* `cifmw_fdp_update_container_images_repo_enabled`: (Integer) Enable repository (0 or 1). Defaults to `1`. +* `cifmw_fdp_update_container_images_repo_gpgcheck`: (Integer) Enable GPG check (0 or 1). Defaults to `0`. +* `cifmw_fdp_update_container_images_repo_priority`: (Integer) Repository priority. Defaults to `0`. +* `cifmw_fdp_update_container_images_repo_sslverify`: (Integer) Enable SSL verification (0 or 1). Defaults to `0`. +* `cifmw_fdp_update_container_images_image_registry`: (String) External OpenShift image registry URL. Auto-detected from cluster if not specified. Leave empty for auto-detection. +* `cifmw_fdp_update_container_images_image_registry_internal`: (String) Internal OpenShift image registry URL. Defaults to `image-registry.openshift-image-registry.svc:5000`. +* `cifmw_fdp_update_container_images_image_name_prefix`: (String) Prefix for new image names. Defaults to `fdp-update`. +* `cifmw_fdp_update_container_images_temp_dir`: (String) Temporary directory for build context. Auto-generated if not specified. +* `cifmw_fdp_update_container_images_update_dnf_args`: (String) Additional arguments for dnf update command. Defaults to `--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }}`. + +## Examples + +### Update OVN package in all containers +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "ovn24.03" + cifmw_fdp_update_container_images_repo_name: "custom-repo" + cifmw_fdp_update_container_images_repo_baseurl: "http://example.com/custom-repo/" + cifmw_fdp_update_container_images_namespace: "openstack" + roles: + - role: "fdp_update_container_images" +``` + +### Update with custom registry and image prefix +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "ovn24.03" + cifmw_fdp_update_container_images_repo_baseurl: "http://custom-repo.example.com/repo/" + cifmw_fdp_update_container_images_image_registry: "registry.example.com" + cifmw_fdp_update_container_images_image_name_prefix: "ovn-hotfix" + roles: + - role: "fdp_update_container_images" +``` + +### Update with specific DNF arguments +```yaml +--- +- hosts: localhost + vars: + cifmw_fdp_update_container_images_target_package: "neutron-ovn-metadata-agent" + cifmw_fdp_update_container_images_repo_baseurl: "http://custom-repo.example.com/repo/" + cifmw_fdp_update_container_images_update_dnf_args: "--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }} --nobest" + roles: + - role: "fdp_update_container_images" +``` + +## How it works + +1. **Registry Setup**: + - Enables the default route for OpenShift image registry + - Auto-detects the registry hostname or uses the configured value +2. **Authentication**: Obtains a token from OpenShift and authenticates with the internal registry using TLS +3. **Image Discovery**: Queries the OpenStackVersion CR for all container images +4. **Package Check**: For each image, creates a temporary container to check if the target package is installed +5. **Image Build**: If the package exists, builds a new image with the updated package from the custom repository +6. **Registry Push**: Pushes the new image to the OpenShift internal registry +7. **CR Update**: Patches the OpenStackVersion CR's `spec.customContainerImages` field with the new image reference +8. **Summary**: Provides a summary of all updated images + +## Requirements + +* OpenShift CLI (`oc`) must be available +* Podman must be installed and accessible +* User must have permissions to: + - Create tokens in the target namespace + - Get and patch OpenStackVersion CRs + - Push images to the internal registry + - Patch image registry configuration (`configs.imageregistry.operator.openshift.io/cluster`) + +## Notes + +* The role uses podman to build and push images with TLS verification +* Each updated image gets a unique tag with timestamp: `--` +* Only images containing the target package will be updated +* The role cleans up temporary containers automatically +* All build contexts are created in a temporary directory that is cleaned up after execution +* The role automatically configures the OpenShift image registry for external access: + - Enables the default route if not already enabled + - Auto-detects the registry hostname from the route diff --git a/roles/fdp_update_container_images/defaults/main.yml b/roles/fdp_update_container_images/defaults/main.yml new file mode 100644 index 0000000000..371d4beb2a --- /dev/null +++ b/roles/fdp_update_container_images/defaults/main.yml @@ -0,0 +1,73 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================================================ +# Base Configuration +# ============================================================================ + +# Base directory for artifacts and temporary files +cifmw_fdp_update_container_images_basedir: "{{ cifmw_basedir | default(ansible_user_dir ~ '/ci-framework-data') }}" + +# OpenShift namespace where OpenStack is deployed +cifmw_fdp_update_container_images_namespace: "openstack" + +# Name of the OpenStackVersion custom resource +cifmw_fdp_update_container_images_openstack_cr_name: "controlplane" + +# Target package to update (REQUIRED - must be set by user) +cifmw_fdp_update_container_images_target_package: "" + +# List of images to update with the target package +# Only these images will be updated (no package scanning is performed) +cifmw_fdp_update_container_images_images_to_scan: + - ovnControllerImage + - ovnControllerOvsImage + - ovnNbDbclusterImage + - ovnNorthdImage + - ovnSbDbclusterImage + - ceilometerSgcoreImage + +# Repository configuration +cifmw_fdp_update_container_images_repo_name: "custom-repo" +cifmw_fdp_update_container_images_repo_baseurl: "" # REQUIRED - must be set by user +cifmw_fdp_update_container_images_repo_enabled: 1 +cifmw_fdp_update_container_images_repo_gpgcheck: 0 +cifmw_fdp_update_container_images_repo_priority: 0 +cifmw_fdp_update_container_images_repo_sslverify: 0 + +# Image registry configuration +# External registry URL (for compute nodes/EDPM and pushing images) +# Leave empty to auto-detect external route from OpenShift cluster +cifmw_fdp_update_container_images_image_registry: "" + +# Internal registry URL (for OpenShift pods to pull images) +# This is auto-detected and should not normally need to be changed +cifmw_fdp_update_container_images_image_registry_internal: "image-registry.openshift-image-registry.svc:5000" + +# Image naming +cifmw_fdp_update_container_images_image_name_prefix: "fdp-update" + +# Temporary directory for build context +cifmw_fdp_update_container_images_temp_dir: "" + +# DNF update arguments +cifmw_fdp_update_container_images_update_dnf_args: "--disablerepo='*' --enablerepo={{ cifmw_fdp_update_container_images_repo_name }}" + +# Internal variables (do not override) +_cifmw_fdp_update_container_images_modified_images: [] +_cifmw_fdp_update_container_images_updated_cr_keys: [] +_cifmw_fdp_update_container_images_total_images: 0 +_cifmw_fdp_update_container_images_processed_images: 0 diff --git a/roles/fdp_update_container_images/meta/main.yml b/roles/fdp_update_container_images/meta/main.yml new file mode 100644 index 0000000000..d727c787bd --- /dev/null +++ b/roles/fdp_update_container_images/meta/main.yml @@ -0,0 +1,38 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +galaxy_info: + author: Red Hat + description: Update RPM packages in OpenStack container images + company: Red Hat + license: Apache-2.0 + min_ansible_version: "2.15" + platforms: + - name: Fedora + versions: + - all + - name: EL + versions: + - "9" + galaxy_tags: + - openstack + - containers + - kubernetes + - openshift + - podman + - rpm + +dependencies: [] diff --git a/roles/fdp_update_container_images/tasks/authenticate_registry.yml b/roles/fdp_update_container_images/tasks/authenticate_registry.yml new file mode 100644 index 0000000000..f44ad679ee --- /dev/null +++ b/roles/fdp_update_container_images/tasks/authenticate_registry.yml @@ -0,0 +1,27 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Create registry token + ansible.builtin.command: oc create token builder -n {{ cifmw_fdp_update_container_images_namespace }} + register: _cifmw_fdp_update_container_images_token + changed_when: false + +- name: Authenticate podman with TLS verification + containers.podman.podman_login: + username: unused + password: "{{ _cifmw_fdp_update_container_images_token.stdout }}" + registry: "{{ cifmw_fdp_update_container_images_image_registry }}" + no_log: true diff --git a/roles/fdp_update_container_images/tasks/configure_ca_cert.yml b/roles/fdp_update_container_images/tasks/configure_ca_cert.yml new file mode 100644 index 0000000000..ea3fd29bda --- /dev/null +++ b/roles/fdp_update_container_images/tasks/configure_ca_cert.yml @@ -0,0 +1,40 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenShift ingress CA certificate + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: router-ca + namespace: openshift-ingress-operator + register: _cifmw_fdp_update_container_images_ca_secret + +- name: Extract CA certificate from secret + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_ca_cert_b64: + stdout: "{{ _cifmw_fdp_update_container_images_ca_secret.resources[0].data['tls.crt'] }}" + +- name: Decode CA certificate + ansible.builtin.copy: + content: "{{ _cifmw_fdp_update_container_images_ca_cert_b64.stdout | b64decode }}" + dest: /etc/pki/ca-trust/source/anchors/openshift-registry-ca.crt + mode: '0644' + become: true + +- name: Update CA trust + ansible.builtin.command: update-ca-trust extract + become: true + changed_when: true diff --git a/roles/fdp_update_container_images/tasks/detect_registry.yml b/roles/fdp_update_container_images/tasks/detect_registry.yml new file mode 100644 index 0000000000..a07f4793fd --- /dev/null +++ b/roles/fdp_update_container_images/tasks/detect_registry.yml @@ -0,0 +1,56 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Enable OpenShift registry route + kubernetes.core.k8s: + api_version: imageregistry.operator.openshift.io/v1 + kind: Config + name: cluster + state: patched + definition: + spec: + defaultRoute: true + register: _cifmw_fdp_update_container_images_enable_route + failed_when: false + +- name: Wait for route + ansible.builtin.pause: + seconds: 10 + when: _cifmw_fdp_update_container_images_enable_route.changed + +- name: Get registry route + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: default-route + namespace: openshift-image-registry + register: _cifmw_fdp_update_container_images_route_info + failed_when: false + +- name: Extract registry host from route + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_route: + stdout: "{{ _cifmw_fdp_update_container_images_route_info.resources[0].spec.host if _cifmw_fdp_update_container_images_route_info.resources | length > 0 else '' }}" + +- name: Set registry URL + ansible.builtin.set_fact: + cifmw_fdp_update_container_images_image_registry: "{{ _cifmw_fdp_update_container_images_route.stdout }}" + when: _cifmw_fdp_update_container_images_route.stdout | length > 0 + +- name: Verify registry URL + ansible.builtin.fail: + msg: "Failed to determine registry URL. Set cifmw_fdp_update_container_images_image_registry manually." + when: cifmw_fdp_update_container_images_image_registry is not defined or cifmw_fdp_update_container_images_image_registry | length == 0 diff --git a/roles/fdp_update_container_images/tasks/fetch_images.yml b/roles/fdp_update_container_images/tasks/fetch_images.yml new file mode 100644 index 0000000000..b3362efc83 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/fetch_images.yml @@ -0,0 +1,38 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenStackVersion CR + kubernetes.core.k8s_info: + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + name: "{{ cifmw_fdp_update_container_images_openstack_cr_name }}" + namespace: "{{ cifmw_fdp_update_container_images_namespace }}" + register: _cifmw_fdp_update_container_images_cr_info + +- name: Extract container images + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_container_images: "{{ _cifmw_fdp_update_container_images_cr_info.resources[0].status.containerImageVersionDefaults.values() | first | default({}) }}" + +- name: Filter images to process + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_image_entries: "{{ _cifmw_fdp_update_container_images_container_images | dict2items | selectattr('key', 'in', cifmw_fdp_update_container_images_images_to_scan) | list }}" + _cifmw_fdp_update_container_images_modified_images: [] + _cifmw_fdp_update_container_images_updated_cr_keys: [] + _cifmw_fdp_update_container_images_processed_images: 0 + +- name: Display images to process + ansible.builtin.debug: + msg: "Processing {{ _cifmw_fdp_update_container_images_image_entries | length }} images: {{ _cifmw_fdp_update_container_images_image_entries | map(attribute='key') | list | join(', ') }}" diff --git a/roles/fdp_update_container_images/tasks/main.yml b/roles/fdp_update_container_images/tasks/main.yml new file mode 100644 index 0000000000..903378e43a --- /dev/null +++ b/roles/fdp_update_container_images/tasks/main.yml @@ -0,0 +1,78 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Validate and Initialize +# ============================================ + +- name: Validate parameters and initialize + ansible.builtin.include_tasks: validate.yml + +# ============================================ +# Detect Registry +# ============================================ + +- name: Detect OpenShift registry URL + ansible.builtin.include_tasks: detect_registry.yml + +# ============================================ +# Configure Registry Authentication +# ============================================ + +- name: Configure registry CA certificate + ansible.builtin.include_tasks: configure_ca_cert.yml + +- name: Authenticate with registry + ansible.builtin.include_tasks: authenticate_registry.yml + +# ============================================ +# Fetch Images +# ============================================ + +- name: Fetch images to process + ansible.builtin.include_tasks: fetch_images.yml + +# ============================================ +# Process Each Image +# ============================================ + +- name: Build and push updated images + ansible.builtin.include_tasks: process_image.yml + loop: "{{ _cifmw_fdp_update_container_images_image_entries }}" + loop_control: + loop_var: image_entry + label: "{{ image_entry.key }}" + when: _cifmw_fdp_update_container_images_image_entries | length > 0 + +# ============================================ +# Summary +# ============================================ + +- name: Display summary + ansible.builtin.debug: + msg: + - "==========================================" + - "✓ Container image update complete" + - "Target package: {{ cifmw_fdp_update_container_images_target_package }}" + - "Images processed: {{ _cifmw_fdp_update_container_images_processed_images }}" + - "Updated: {{ _cifmw_fdp_update_container_images_updated_cr_keys | join(', ') if _cifmw_fdp_update_container_images_updated_cr_keys | length > 0 else 'None' }}" + - "==========================================" + +- name: Cleanup temporary directory + ansible.builtin.file: + path: "{{ _cifmw_fdp_update_container_images_temp_dir }}" + state: absent + when: _cifmw_fdp_update_container_images_temp_dir is defined diff --git a/roles/fdp_update_container_images/tasks/process_image.yml b/roles/fdp_update_container_images/tasks/process_image.yml new file mode 100644 index 0000000000..54b0173ce3 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/process_image.yml @@ -0,0 +1,67 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Create repository file + ansible.builtin.template: + src: repo.j2 + dest: "{{ _cifmw_fdp_update_container_images_temp_dir }}/{{ cifmw_fdp_update_container_images_repo_name }}.repo" + mode: '0644' + +- name: Create Dockerfile + ansible.builtin.template: + src: Dockerfile.j2 + dest: "{{ _cifmw_fdp_update_container_images_temp_dir }}/Dockerfile" + mode: '0644' + vars: + base_image: "{{ image_entry.value }}" + +- name: Generate image paths + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_new_image_path_external: "{{ cifmw_fdp_update_container_images_image_registry }}/{{ cifmw_fdp_update_container_images_namespace }}/{{ cifmw_fdp_update_container_images_image_name_prefix }}-{{ image_entry.key | lower }}-{{ ansible_date_time.epoch }}" + _cifmw_fdp_update_container_images_new_image_path_internal: "{{ cifmw_fdp_update_container_images_image_registry_internal }}/{{ cifmw_fdp_update_container_images_namespace }}/{{ cifmw_fdp_update_container_images_image_name_prefix }}-{{ image_entry.key | lower }}-{{ ansible_date_time.epoch }}" + +- name: Build and push image + containers.podman.podman_image: + name: "{{ _cifmw_fdp_update_container_images_new_image_path_external }}" + path: "{{ _cifmw_fdp_update_container_images_temp_dir }}" + build: + file: "{{ _cifmw_fdp_update_container_images_temp_dir }}/Dockerfile" + push: true + push_args: + dest: "{{ _cifmw_fdp_update_container_images_new_image_path_external }}" + state: build + +- name: Patch OpenStackVersion CR + kubernetes.core.k8s: + state: patched + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + name: "{{ cifmw_fdp_update_container_images_openstack_cr_name }}" + namespace: "{{ cifmw_fdp_update_container_images_namespace }}" + definition: + spec: + customContainerImages: + "{{ image_entry.key }}": "{{ _cifmw_fdp_update_container_images_new_image_path_internal }}" + +- name: Update tracking + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_modified_images: "{{ _cifmw_fdp_update_container_images_modified_images + [image_entry.key ~ ': ' ~ _cifmw_fdp_update_container_images_new_image_path_internal] }}" + _cifmw_fdp_update_container_images_updated_cr_keys: "{{ _cifmw_fdp_update_container_images_updated_cr_keys + [image_entry.key] }}" + _cifmw_fdp_update_container_images_processed_images: "{{ _cifmw_fdp_update_container_images_processed_images | int + 1 }}" + +- name: Display progress + ansible.builtin.debug: + msg: "✓ Updated {{ image_entry.key }} ({{ _cifmw_fdp_update_container_images_processed_images }}/{{ _cifmw_fdp_update_container_images_image_entries | length }})" diff --git a/roles/fdp_update_container_images/tasks/validate.yml b/roles/fdp_update_container_images/tasks/validate.yml new file mode 100644 index 0000000000..061632c224 --- /dev/null +++ b/roles/fdp_update_container_images/tasks/validate.yml @@ -0,0 +1,38 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Validate required parameters + ansible.builtin.assert: + that: + - cifmw_fdp_update_container_images_target_package is defined + - cifmw_fdp_update_container_images_target_package | length > 0 + - cifmw_fdp_update_container_images_repo_baseurl is defined + - cifmw_fdp_update_container_images_repo_baseurl | length > 0 + fail_msg: "Required: cifmw_fdp_update_container_images_target_package and cifmw_fdp_update_container_images_repo_baseurl" + +- name: Check oc command is available + ansible.builtin.command: oc version --client + changed_when: false + +- name: Create temporary directory + ansible.builtin.tempfile: + state: directory + prefix: "cifmw_fdp_update_build_" + register: _cifmw_fdp_update_container_images_temp_dir_result + +- name: Set temporary directory + ansible.builtin.set_fact: + _cifmw_fdp_update_container_images_temp_dir: "{{ cifmw_fdp_update_container_images_temp_dir if (cifmw_fdp_update_container_images_temp_dir is defined and cifmw_fdp_update_container_images_temp_dir | length > 0) else _cifmw_fdp_update_container_images_temp_dir_result.path }}" diff --git a/roles/fdp_update_container_images/templates/Dockerfile.j2 b/roles/fdp_update_container_images/templates/Dockerfile.j2 new file mode 100644 index 0000000000..f77f60d2c3 --- /dev/null +++ b/roles/fdp_update_container_images/templates/Dockerfile.j2 @@ -0,0 +1,3 @@ +FROM {{ base_image }} +COPY ./{{ cifmw_fdp_update_container_images_repo_name }}.repo /etc/yum.repos.d/ +RUN dnf update -y {{ cifmw_fdp_update_container_images_update_dnf_args }} {{ cifmw_fdp_update_container_images_target_package }}* diff --git a/roles/fdp_update_container_images/templates/repo.j2 b/roles/fdp_update_container_images/templates/repo.j2 new file mode 100644 index 0000000000..cee92cf1b2 --- /dev/null +++ b/roles/fdp_update_container_images/templates/repo.j2 @@ -0,0 +1,7 @@ +[{{ cifmw_fdp_update_container_images_repo_name }}] +name={{ cifmw_fdp_update_container_images_repo_name }} +baseurl={{ cifmw_fdp_update_container_images_repo_baseurl }} +enabled={{ cifmw_fdp_update_container_images_repo_enabled }} +gpgcheck={{ cifmw_fdp_update_container_images_repo_gpgcheck }} +priority={{ cifmw_fdp_update_container_images_repo_priority }} +sslverify={{ cifmw_fdp_update_container_images_repo_sslverify }} diff --git a/roles/fdp_update_edpm/README.md b/roles/fdp_update_edpm/README.md new file mode 100644 index 0000000000..59a11ee666 --- /dev/null +++ b/roles/fdp_update_edpm/README.md @@ -0,0 +1,184 @@ +# fdp_update_edpm + +Role for updating OpenStack EDPM (Edge Data Plane Management) nodes with custom container images and host packages. + +## Description + +This role provides a declarative approach to update EDPM nodes with: + +1. **Updates container images** by patching OpenStackDataPlaneNodeSet CRs with new image references +2. **Updates host packages** by configuring `edpm_bootstrap_packages` and `edpm_bootstrap_repos` in the nodeset +3. **Configures registry authentication** with OpenShift service account tokens +4. **Installs CA certificates** for secure registry access +5. **Optionally creates deployments** to apply the changes to EDPM nodes + +### Key Features + +- **Declarative approach**: Only modifies Kubernetes CRs, doesn't execute commands directly on EDPM nodes +- **Uses native EDPM capabilities**: Leverages `edpm_bootstrap` and `edpm_podman` roles from edpm-ansible +- **Secure by default**: Installs OpenShift CA certificates instead of using insecure registries +- **Flexible**: Supports updating containers, packages, or both +- **Idempotent**: Can be run multiple times safely + +## Requirements + +- OpenShift cluster with OpenStack operators installed +- Access to `oc` command +- OpenStackVersion CR with custom container images +- Custom repository with updated packages (if updating host packages) + +## Role Variables + +### General Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_namespace` | `"openstack"` | OpenShift namespace | +| `cifmw_fdp_update_edpm_nodeset_name` | `"all"` | NodeSet to update (`"all"` or specific name) | +| `cifmw_fdp_update_edpm_dry_run` | `false` | Show changes without applying | + +### Container Image Updates + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_containers_enabled` | `true` | Enable container image updates | +| `cifmw_fdp_update_edpm_image_registry` | `""` | External registry URL (auto-detected if empty) | +| `cifmw_fdp_update_edpm_image_variable_mapping` | See defaults | Mapping of image keys to EDPM variables | + +### Host Package Updates + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_packages_enabled` | `true` | Enable host package updates | +| `cifmw_fdp_update_edpm_repo_baseurl` | `""` | **REQUIRED** Repository base URL | +| `cifmw_fdp_update_edpm_repo_name` | `"fdp-update"` | Repository name | +| `cifmw_fdp_update_edpm_packages` | See defaults | List of packages to install/update | + +### Hypervisor Firewall Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_setup_hypervisor_firewall` | `true` | Enable/disable hypervisor firewall setup for registry access | +| `cifmw_fdp_update_compute_interface` | `"osp_trunk"` | Network interface on hypervisor connected to compute nodes (EDPM) | +| `cifmw_fdp_update_registry_interface` | `"ocpbm"` | Network interface on hypervisor connected to OpenShift/registry | +| `cifmw_fdp_update_compute_network` | `"192.168.122.0/24"` | Compute nodes network CIDR (source for NAT) | +| `cifmw_fdp_update_registry_network` | `"192.168.201.0/24"` | OpenShift/registry network CIDR (destination for NAT) | + +### Registry Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_configure_registry_ca` | `true` | Install OpenShift CA certificate via bootstrap command | +| `cifmw_fdp_update_edpm_configure_registry_auth` | `true` | Configure registry authentication | + +### Deployment Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `cifmw_fdp_update_edpm_auto_deploy` | `true` | Automatically create deployment | +| `cifmw_fdp_update_edpm_deployment_per_nodeset` | `true` | Create separate deployment per nodeset | +| `cifmw_fdp_update_edpm_wait_for_deployment` | `true` | Wait for deployment to complete | +| `cifmw_fdp_update_edpm_deployment_timeout` | `3600` | Deployment timeout (seconds) | +| `cifmw_fdp_update_edpm_deployment_services` | See defaults | Services to run in deployment | + +## Dependencies + +None (uses native OpenStack Data Plane operators and edpm-ansible roles) + +## Example Playbook + +### Update both containers and packages + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_namespace: openstack + cifmw_fdp_update_edpm_nodeset_name: openstack-edpm + cifmw_fdp_update_edpm_repo_baseurl: "http://example.com/repos/fdp-updates" + cifmw_fdp_update_edpm_packages: + - openvswitch3.5 + - openvswitch-selinux-extra-policy +``` + +### Update only containers + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_packages_enabled: false + cifmw_fdp_update_edpm_containers_enabled: true +``` + +### Update only packages + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_containers_enabled: false + cifmw_fdp_update_edpm_packages_enabled: true + cifmw_fdp_update_edpm_repo_baseurl: "http://example.com/repos/updates" +``` + +### Dry run (show changes without applying) + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_edpm_dry_run: true +``` + +### Custom network configuration + +```yaml +- hosts: localhost + roles: + - role: fdp_update_edpm + vars: + cifmw_fdp_update_compute_interface: "br-ex" + cifmw_fdp_update_registry_interface: "br-ocp" + cifmw_fdp_update_compute_network: "10.0.0.0/24" + cifmw_fdp_update_registry_network: "172.16.0.0/24" +``` + +## How It Works + +1. **Validates parameters**: Ensures required variables are set +2. **Configures hypervisor firewall** (if enabled): Sets up iptables rules to allow EDPM nodes to access the OpenShift registry +3. **Fetches NodeSets**: Gets OpenStackDataPlaneNodeSet CRs from the cluster +4. **Fetches container images** (if enabled): Gets custom images from OpenStackVersion CR +5. **For each NodeSet**: + - Patches container image variables (e.g., `edpm_ovn_controller_agent_image`) + - Patches `edpm_bootstrap_packages` with packages to install + - Patches `edpm_bootstrap_repos` with custom repository configuration + - Configures registry authentication (`edpm_container_registry_logins`) + - Installs CA certificate via `edpm_bootstrap_command` (if enabled) +6. **Creates deployment** (if enabled): Creates OpenStackDataPlaneDeployment CR +7. **Waits for completion** (if enabled): Monitors deployment until Ready + +## Architecture: Declarative vs Imperative + +This role follows the **declarative** approach of Kubernetes/OpenStack: + +- ❌ **Does NOT** SSH to nodes and run `dnf install` directly +- ❌ **Does NOT** SSH to nodes and run `systemctl restart` directly +- ✅ **Does** patch NodeSet CRs with desired state +- ✅ **Does** let OpenStack Data Plane Operator apply the changes +- ✅ **Does** use native `edpm_bootstrap` role for package installation +- ✅ **Does** use native `edpm_podman` role for container management +- ✅ **Does** use `edpm_bootstrap_command` for CA certificate installation + +## License + +Apache 2.0 + +## Author Information + +Red Hat OpenStack CI Framework Team diff --git a/roles/fdp_update_edpm/defaults/main.yml b/roles/fdp_update_edpm/defaults/main.yml new file mode 100644 index 0000000000..cc87b399c6 --- /dev/null +++ b/roles/fdp_update_edpm/defaults/main.yml @@ -0,0 +1,132 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# General Configuration +# ============================================ + +# OpenShift namespace where EDPM resources are deployed +cifmw_fdp_update_edpm_namespace: "openstack" + +# NodeSet selector - can be a specific name or 'all' for all nodesets +cifmw_fdp_update_edpm_nodeset_name: "all" + +# Dry run - show changes without applying +cifmw_fdp_update_edpm_dry_run: false + +# ============================================ +# Container Image Updates +# ============================================ + +# Enable/disable container image updates +cifmw_fdp_update_edpm_containers_enabled: true + +# Image registry URL (auto-detected from OpenShift if empty) +cifmw_fdp_update_edpm_image_registry: "" + +# Mapping of control plane image keys to EDPM ansible variables +# Only ovnControllerImage is used on EDPM compute nodes +cifmw_fdp_update_edpm_image_variable_mapping: + ovnControllerImage: edpm_ovn_controller_agent_image + +# ============================================ +# Host Package Updates +# ============================================ + +# Enable/disable host package updates +cifmw_fdp_update_edpm_packages_enabled: true + +# Repository configuration for host package updates +cifmw_fdp_update_edpm_repo_name: "fdp-update" +cifmw_fdp_update_edpm_repo_baseurl: "" # REQUIRED if packages_enabled is true +cifmw_fdp_update_edpm_repo_enabled: true +cifmw_fdp_update_edpm_repo_gpgcheck: false +cifmw_fdp_update_edpm_repo_priority: 1 + +# Packages to update on the host +# These will be added to edpm_bootstrap_packages in the nodeset +cifmw_fdp_update_edpm_packages: + - openvswitch3.5 + - openvswitch-selinux-extra-policy + +# ============================================ +# Hypervisor Firewall Configuration +# ============================================ + +# Enable/disable hypervisor firewall setup for registry access +cifmw_fdp_update_edpm_setup_hypervisor_firewall: true + +# Network interface on hypervisor connected to compute nodes (EDPM) +cifmw_fdp_update_compute_interface: "osp_trunk" + +# Network interface on hypervisor connected to OpenShift/registry +cifmw_fdp_update_registry_interface: "ocpbm" + +# Compute nodes network CIDR (source for NAT) +cifmw_fdp_update_compute_network: "192.168.122.0/24" + +# OpenShift/registry network CIDR (destination for NAT) +cifmw_fdp_update_registry_network: "192.168.201.0/24" + +# ============================================ +# Registry Configuration +# ============================================ + +# Configure OpenShift registry CA certificate on EDPM nodes +cifmw_fdp_update_edpm_configure_registry_ca: true + +# Configure registry authentication automatically +# Uses 'oc create token' or 'oc whoami -t' to get a service account token +cifmw_fdp_update_edpm_configure_registry_auth: true + +# ============================================ +# Deployment Configuration +# ============================================ + +# Automatically create OpenStackDataPlaneDeployment after updating NodeSets +# Creates a single deployment for all updated NodeSets +cifmw_fdp_update_edpm_auto_deploy: true + +# Wait for deployment to complete before continuing +cifmw_fdp_update_edpm_wait_for_deployment: true + +# Timeout for deployment completion (in seconds) +# Default: 3600 seconds (60 minutes / 1 hour) +cifmw_fdp_update_edpm_deployment_timeout: 3600 + +# Polling interval when waiting for deployment (in seconds) +cifmw_fdp_update_edpm_deployment_poll_interval: 30 + +# Services to run in the deployment +# For updates, we need to: +# 1. bootstrap - Install host packages and configure repos +# 2. configure-os - Configure registry authentication +# 3. configure-network - Ensure network is configured +# 4. Service-specific services (ovn, nova, etc) - Pull updated images and restart +cifmw_fdp_update_edpm_deployment_services: + - bootstrap # MUST be first to install packages and configure repos + - configure-os # MUST be second to authenticate before pulling images + - configure-network + - ovn + +# ============================================ +# Internal Variables (do not override) +# ============================================ + +_cifmw_fdp_update_edpm_updated_images: {} +_cifmw_fdp_update_edpm_nodesets: [] +_cifmw_fdp_update_edpm_updated_nodesets: [] +_cifmw_fdp_update_edpm_external_registry: "" diff --git a/roles/fdp_update_edpm/meta/main.yml b/roles/fdp_update_edpm/meta/main.yml new file mode 100644 index 0000000000..3bfc3f70f4 --- /dev/null +++ b/roles/fdp_update_edpm/meta/main.yml @@ -0,0 +1,39 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +galaxy_info: + author: Red Hat + description: Update OpenStack EDPM container images and host packages with FDP updates + company: Red Hat + license: Apache-2.0 + min_ansible_version: "2.15" + platforms: + - name: Fedora + versions: + - all + - name: EL + versions: + - "9" + galaxy_tags: + - openstack + - edpm + - dataplane + - kubernetes + - openshift + - rpm + - containers + +dependencies: [] diff --git a/roles/fdp_update_edpm/tasks/configure_ca_cert.yml b/roles/fdp_update_edpm/tasks/configure_ca_cert.yml new file mode 100644 index 0000000000..759a96b0fd --- /dev/null +++ b/roles/fdp_update_edpm/tasks/configure_ca_cert.yml @@ -0,0 +1,65 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This file configures OpenShift registry CA certificate on EDPM nodes +# Embeds CA certificate installation in edpm_bootstrap_command + +- name: Get OpenShift ingress CA certificate + kubernetes.core.k8s_info: + api_version: v1 + kind: Secret + name: router-ca + namespace: openshift-ingress-operator + register: _cifmw_fdp_update_edpm_ca_cert_result + +- name: Decode CA certificate + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_ca_cert: "{{ _cifmw_fdp_update_edpm_ca_cert_result.resources[0].data['tls.crt'] | b64decode }}" + +- name: Get current edpm_bootstrap_command from nodeset + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_bootstrap_result + failed_when: false + +- name: Build bootstrap command with CA certificate installation + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_with_ca: | + # Install OpenShift registry CA certificate + cat > /etc/pki/ca-trust/source/anchors/openshift-registry-ca.crt <<'EOF' + {{ _cifmw_fdp_update_edpm_ca_cert }} + EOF + update-ca-trust extract + + {{ _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_command | default('') if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) else '' }} + +- name: Patch NodeSet with updated bootstrap command + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_bootstrap_command: "{{ _cifmw_fdp_update_edpm_bootstrap_with_ca }}" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/create_deployment.yml b/roles/fdp_update_edpm/tasks/create_deployment.yml new file mode 100644 index 0000000000..ed17139a32 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/create_deployment.yml @@ -0,0 +1,61 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set deployment name + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_deployment_name: "edpm-fdp-update-{{ ansible_date_time.epoch }}" + +- name: Create OpenStackDataPlaneDeployment + kubernetes.core.k8s: + state: present + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneDeployment + definition: + metadata: + name: "{{ _cifmw_fdp_update_edpm_deployment_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + spec: + nodeSets: "{{ _cifmw_fdp_update_edpm_updated_nodesets }}" + servicesOverride: "{{ cifmw_fdp_update_edpm_deployment_services }}" + +- name: Display deployment information + ansible.builtin.debug: + msg: + - "Created deployment: {{ _cifmw_fdp_update_edpm_deployment_name }}" + - "NodeSets: {{ _cifmw_fdp_update_edpm_updated_nodesets }}" + - "Services: {{ cifmw_fdp_update_edpm_deployment_services }}" + +- name: Wait for deployment to complete + when: cifmw_fdp_update_edpm_wait_for_deployment | bool + block: + - name: Wait for deployment Ready condition + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneDeployment + name: "{{ _cifmw_fdp_update_edpm_deployment_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_deployment_result + until: >- + _cifmw_fdp_update_edpm_deployment_result.resources | length > 0 and + _cifmw_fdp_update_edpm_deployment_result.resources[0].status.conditions | + selectattr('type', 'equalto', 'Ready') | + map(attribute='status') | first | default('False') == 'True' + retries: "{{ (cifmw_fdp_update_edpm_deployment_timeout / cifmw_fdp_update_edpm_deployment_poll_interval) | int }}" + delay: "{{ cifmw_fdp_update_edpm_deployment_poll_interval }}" + + - name: Display deployment completion + ansible.builtin.debug: + msg: "Deployment {{ _cifmw_fdp_update_edpm_deployment_name }} completed successfully" diff --git a/roles/fdp_update_edpm/tasks/fetch_nodesets.yml b/roles/fdp_update_edpm/tasks/fetch_nodesets.yml new file mode 100644 index 0000000000..7c2f4fb086 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/fetch_nodesets.yml @@ -0,0 +1,32 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Get OpenStackDataPlaneNodeSets + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ cifmw_fdp_update_edpm_nodeset_name if cifmw_fdp_update_edpm_nodeset_name != 'all' else omit }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_nodesets_result + +- name: Parse NodeSets + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_nodesets: "{{ _cifmw_fdp_update_edpm_nodesets_result.resources }}" + +- name: Fail if no NodeSets found + ansible.builtin.fail: + msg: "No OpenStackDataPlaneNodeSets found in namespace {{ cifmw_fdp_update_edpm_namespace }}" + when: _cifmw_fdp_update_edpm_nodesets | length == 0 diff --git a/roles/fdp_update_edpm/tasks/main.yml b/roles/fdp_update_edpm/tasks/main.yml new file mode 100644 index 0000000000..9c5f29eb0f --- /dev/null +++ b/roles/fdp_update_edpm/tasks/main.yml @@ -0,0 +1,83 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Validate and Initialize +# ============================================ + +- name: Validate parameters and initialize + ansible.builtin.include_tasks: validate.yml + +# ============================================ +# Setup Hypervisor Firewall +# ============================================ + +- name: Setup hypervisor firewall for registry access + ansible.builtin.include_tasks: setup_hypervisor_firewall.yml + when: cifmw_fdp_update_edpm_setup_hypervisor_firewall | default(true) | bool + +# ============================================ +# Fetch NodeSets +# ============================================ + +- name: Fetch EDPM NodeSets + ansible.builtin.include_tasks: fetch_nodesets.yml + +# ============================================ +# Update Container Images (Optional) +# ============================================ + +- name: Update container images + when: cifmw_fdp_update_edpm_containers_enabled | bool + ansible.builtin.include_tasks: update_container_images.yml + +# ============================================ +# Process Each NodeSet +# ============================================ + +- name: Process each NodeSet + ansible.builtin.include_tasks: process_nodeset.yml + loop: "{{ _cifmw_fdp_update_edpm_nodesets }}" + loop_control: + loop_var: nodeset + label: "{{ nodeset.metadata.name }}" + +# ============================================ +# Deploy Updates to EDPM Nodes (Optional) +# ============================================ + +- name: Deploy updates to EDPM nodes + when: + - cifmw_fdp_update_edpm_auto_deploy | bool + - not cifmw_fdp_update_edpm_dry_run | bool + - _cifmw_fdp_update_edpm_updated_nodesets | default([]) | length > 0 + ansible.builtin.include_tasks: create_deployment.yml + +# ============================================ +# Summary +# ============================================ + +- name: Display update summary + ansible.builtin.debug: + msg: + - "==============================================" + - "EDPM Update Summary" + - "==============================================" + - "Updated {{ _cifmw_fdp_update_edpm_updated_nodesets | length }} NodeSet(s): {{ _cifmw_fdp_update_edpm_updated_nodesets }}" + - "Container images updated: {{ cifmw_fdp_update_edpm_containers_enabled }}" + - "Host packages updated: {{ cifmw_fdp_update_edpm_packages_enabled }}" + - "==============================================" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/process_nodeset.yml b/roles/fdp_update_edpm/tasks/process_nodeset.yml new file mode 100644 index 0000000000..43d9cadd96 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/process_nodeset.yml @@ -0,0 +1,159 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Set NodeSet name + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_current_nodeset_name: "{{ nodeset.metadata.name }}" + +# ============================================ +# Patch Container Images +# ============================================ + +- name: Patch container images in nodeset + when: + - cifmw_fdp_update_edpm_containers_enabled | bool + - _cifmw_fdp_update_edpm_updated_images is defined + - _cifmw_fdp_update_edpm_updated_images | length > 0 + block: + - name: Build EDPM image variables patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_image_vars_patch: {} + + - name: Add each EDPM variable to patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_image_vars_patch: >- + {{ + _cifmw_fdp_update_edpm_image_vars_patch | combine({ + cifmw_fdp_update_edpm_image_variable_mapping[item.key]: item.value + }) + }} + loop: "{{ _cifmw_fdp_update_edpm_updated_images | dict2items }}" + loop_control: + label: "{{ item.key }}" + + - name: Apply container images using k8s patch + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: "{{ _cifmw_fdp_update_edpm_image_vars_patch }}" + when: + - not cifmw_fdp_update_edpm_dry_run + - _cifmw_fdp_update_edpm_image_vars_patch | length > 0 + +# ============================================ +# Patch Host Packages and Repositories +# ============================================ + +- name: Patch host packages and repositories in nodeset + when: cifmw_fdp_update_edpm_packages_enabled | bool + ansible.builtin.include_tasks: update_host_packages.yml + +# ============================================ +# Configure Registry Authentication +# ============================================ + +- name: Configure registry authentication + when: + - not cifmw_fdp_update_edpm_dry_run + - cifmw_fdp_update_edpm_configure_registry_auth | bool + - _cifmw_fdp_update_edpm_external_registry is defined + - _cifmw_fdp_update_edpm_external_registry | length > 0 + block: + - name: Get authentication token for OpenShift registry + ansible.builtin.command: oc whoami -t + register: _cifmw_fdp_update_edpm_oc_token_result + changed_when: false + failed_when: false + + - name: Get existing registry logins + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_logins_result + failed_when: false + + - name: Parse existing registry logins + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_existing_logins: >- + {{ + _cifmw_fdp_update_edpm_current_logins_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_container_registry_logins | default({}) + if (_cifmw_fdp_update_edpm_current_logins_result.resources | length > 0) + else {} + }} + + - name: Merge with new registry login + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_logins: >- + {{ + _cifmw_fdp_update_edpm_existing_logins | combine({ + _cifmw_fdp_update_edpm_external_registry: { + 'serviceaccount': _cifmw_fdp_update_edpm_oc_token_result.stdout + } + }) + }} + when: + - _cifmw_fdp_update_edpm_oc_token_result.rc == 0 + - _cifmw_fdp_update_edpm_oc_token_result.stdout | length > 0 + + - name: Build registry authentication patch + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_registry_auth_patch: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_container_registry_logins: "{{ _cifmw_fdp_update_edpm_merged_logins }}" + when: + - _cifmw_fdp_update_edpm_oc_token_result.rc == 0 + - _cifmw_fdp_update_edpm_oc_token_result.stdout | length > 0 + + - name: Apply registry authentication configuration + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: "{{ _cifmw_fdp_update_edpm_registry_auth_patch }}" + when: + - _cifmw_fdp_update_edpm_oc_token_result.rc == 0 + - _cifmw_fdp_update_edpm_oc_token_result.stdout | length > 0 + +# ============================================ +# Configure Registry CA Certificate +# ============================================ + +- name: Configure registry CA certificate + when: cifmw_fdp_update_edpm_configure_registry_ca | bool + ansible.builtin.include_tasks: configure_ca_cert.yml + +# ============================================ +# Record NodeSet as Processed +# ============================================ + +- name: Record NodeSet as processed + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_nodesets: "{{ _cifmw_fdp_update_edpm_updated_nodesets + [_cifmw_fdp_update_edpm_current_nodeset_name] }}" + when: not cifmw_fdp_update_edpm_dry_run diff --git a/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml b/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml new file mode 100644 index 0000000000..e22b98b7f5 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/setup_hypervisor_firewall.yml @@ -0,0 +1,59 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Setup Hypervisor Firewall for Registry Access +# ============================================ +# This task configures iptables rules on the hypervisor to allow +# compute nodes (EDPM) to access the OpenShift registry for pulling +# container images during FDP updates. + +- name: Allow traffic from {{ cifmw_fdp_update_compute_interface }} to {{ cifmw_fdp_update_registry_interface }} (compute -> registry) + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_compute_interface }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: ACCEPT + action: insert + rule_num: '1' + +- name: Allow return traffic from {{ cifmw_fdp_update_registry_interface }} to {{ cifmw_fdp_update_compute_interface }} (registry -> compute) + become: true + ansible.builtin.iptables: + chain: FORWARD + in_interface: "{{ cifmw_fdp_update_registry_interface }}" + out_interface: "{{ cifmw_fdp_update_compute_interface }}" + ctstate: RELATED,ESTABLISHED + jump: ACCEPT + action: insert + rule_num: '1' + +- name: Enable NAT for compute nodes to access registry + become: true + ansible.builtin.iptables: + table: nat + chain: POSTROUTING + source: "{{ cifmw_fdp_update_compute_network }}" + destination: "{{ cifmw_fdp_update_registry_network }}" + out_interface: "{{ cifmw_fdp_update_registry_interface }}" + jump: MASQUERADE + +- name: Persist firewall rules + become: true + community.general.iptables_state: + state: saved + path: /etc/sysconfig/iptables diff --git a/roles/fdp_update_edpm/tasks/update_container_images.yml b/roles/fdp_update_edpm/tasks/update_container_images.yml new file mode 100644 index 0000000000..dc58cda5f5 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/update_container_images.yml @@ -0,0 +1,89 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# ============================================ +# Fetch Updated Container Images +# ============================================ + +- name: Get OpenStackVersion CR list + kubernetes.core.k8s_info: + api_version: core.openstack.org/v1beta1 + kind: OpenStackVersion + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_osv_result + +- name: Fail if no OpenStackVersion CR found + ansible.builtin.fail: + msg: "No OpenStackVersion CR found in namespace {{ cifmw_fdp_update_edpm_namespace }}" + when: _cifmw_fdp_update_edpm_osv_result.resources | length == 0 + +- name: Parse and filter EDPM-relevant custom images + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_images: >- + {{ + (_cifmw_fdp_update_edpm_osv_result.resources[0].spec.customContainerImages | default({})) | dict2items | + selectattr('key', 'in', cifmw_fdp_update_edpm_image_variable_mapping.keys()) | + items2dict + }} + +# ============================================ +# Convert Internal Registry URLs to External +# ============================================ + +- name: Convert internal registry URLs to external for EDPM compute nodes + when: _cifmw_fdp_update_edpm_updated_images | length > 0 + block: + - name: Determine external registry URL + block: + - name: Try to auto-detect registry route if not configured + kubernetes.core.k8s_info: + api_version: route.openshift.io/v1 + kind: Route + name: default-route + namespace: openshift-image-registry + register: _cifmw_fdp_update_edpm_registry_route_result + failed_when: false + when: cifmw_fdp_update_edpm_image_registry is not defined or cifmw_fdp_update_edpm_image_registry | length == 0 + + - name: Set external registry URL + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_external_registry: >- + {%- if cifmw_fdp_update_edpm_image_registry is defined and cifmw_fdp_update_edpm_image_registry | length > 0 -%} + {{ cifmw_fdp_update_edpm_image_registry }} + {%- elif _cifmw_fdp_update_edpm_registry_route_result.resources | default([]) | length > 0 -%} + {{ _cifmw_fdp_update_edpm_registry_route_result.resources[0].spec.host }} + {%- else -%} + UNDEFINED + {%- endif -%} + + - name: Fail if no external registry URL could be determined + ansible.builtin.fail: + msg: | + Cannot determine external registry URL! + EDPM compute nodes require an external registry URL to pull images. + Please set: cifmw_fdp_update_edpm_image_registry + when: _cifmw_fdp_update_edpm_external_registry == 'UNDEFINED' + + - name: Convert URLs (handle all internal registry variations) + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_images: "{{ dict(_cifmw_fdp_update_edpm_updated_images.keys() | zip(_cifmw_fdp_update_edpm_updated_images.values() | map('regex_replace', 'image-registry\\.openshift-image-registry\\.svc\\.cluster\\.local:5000', _cifmw_fdp_update_edpm_external_registry) | map('regex_replace', 'image-registry\\.openshift-image-registry\\.svc:5000', _cifmw_fdp_update_edpm_external_registry) | list)) }}" + +- name: Display container images to update + ansible.builtin.debug: + msg: + - "Container images found in OpenStackVersion CR:" + - "{{ _cifmw_fdp_update_edpm_updated_images }}" + when: _cifmw_fdp_update_edpm_updated_images | length > 0 diff --git a/roles/fdp_update_edpm/tasks/update_host_packages.yml b/roles/fdp_update_edpm/tasks/update_host_packages.yml new file mode 100644 index 0000000000..6e8d62d243 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/update_host_packages.yml @@ -0,0 +1,109 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# This file patches the nodeset with edpm_bootstrap_* variables +# The actual package installation happens during deployment via edpm_bootstrap role + +# ============================================ +# Get Current Bootstrap Configuration +# ============================================ + +- name: Get current bootstrap configuration from nodeset + kubernetes.core.k8s_info: + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + register: _cifmw_fdp_update_edpm_current_bootstrap_result + failed_when: false + +# ============================================ +# Merge New Packages with Existing +# ============================================ + +- name: Parse current bootstrap packages + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_packages_list: >- + {{ + _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_packages | default([]) + if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) + else [] + }} + +- name: Merge new packages with existing packages + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_packages: "{{ (_cifmw_fdp_update_edpm_bootstrap_packages_list + cifmw_fdp_update_edpm_packages) | unique }}" + +# ============================================ +# Build Repository Configuration +# ============================================ + +- name: Parse current bootstrap repos + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_repos_list: >- + {{ + _cifmw_fdp_update_edpm_current_bootstrap_result.resources[0].spec.nodeTemplate.ansible.ansibleVars.edpm_bootstrap_repos | default([]) + if (_cifmw_fdp_update_edpm_current_bootstrap_result.resources | length > 0) + else [] + }} + +- name: Build new repository configuration + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_new_repo: + name: "{{ cifmw_fdp_update_edpm_repo_name }}" + baseurl: "{{ cifmw_fdp_update_edpm_repo_baseurl }}" + enabled: "{{ cifmw_fdp_update_edpm_repo_enabled | int }}" + gpgcheck: "{{ cifmw_fdp_update_edpm_repo_gpgcheck | int }}" + priority: "{{ cifmw_fdp_update_edpm_repo_priority }}" + +- name: Check if repo already exists in nodeset + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_repo_exists: "{{ _cifmw_fdp_update_edpm_bootstrap_repos_list | selectattr('name', 'equalto', cifmw_fdp_update_edpm_repo_name) | list | length > 0 }}" + +- name: Remove existing repo if it exists + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_bootstrap_repos_list: "{{ _cifmw_fdp_update_edpm_bootstrap_repos_list | rejectattr('name', 'equalto', cifmw_fdp_update_edpm_repo_name) | list }}" + when: _cifmw_fdp_update_edpm_repo_exists | bool + +- name: Add new repo to repos list + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_merged_repos: "{{ _cifmw_fdp_update_edpm_bootstrap_repos_list + [_cifmw_fdp_update_edpm_new_repo] }}" + +# ============================================ +# Patch NodeSet with Bootstrap Configuration +# ============================================ + +- name: Patch nodeset with bootstrap packages and repos + kubernetes.core.k8s: + state: patched + api_version: dataplane.openstack.org/v1beta1 + kind: OpenStackDataPlaneNodeSet + name: "{{ _cifmw_fdp_update_edpm_current_nodeset_name }}" + namespace: "{{ cifmw_fdp_update_edpm_namespace }}" + definition: + spec: + nodeTemplate: + ansible: + ansibleVars: + edpm_bootstrap_packages: "{{ _cifmw_fdp_update_edpm_merged_packages }}" + edpm_bootstrap_repos: "{{ _cifmw_fdp_update_edpm_merged_repos }}" + when: not cifmw_fdp_update_edpm_dry_run + +- name: Display packages and repos configuration + ansible.builtin.debug: + msg: + - "Packages to install on host: {{ _cifmw_fdp_update_edpm_merged_packages }}" + - "Repositories configured: {{ _cifmw_fdp_update_edpm_merged_repos | map(attribute='name') | list }}" diff --git a/roles/fdp_update_edpm/tasks/validate.yml b/roles/fdp_update_edpm/tasks/validate.yml new file mode 100644 index 0000000000..2036e66ab6 --- /dev/null +++ b/roles/fdp_update_edpm/tasks/validate.yml @@ -0,0 +1,33 @@ +--- +# Copyright Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +- name: Validate package update configuration + ansible.builtin.assert: + that: + - cifmw_fdp_update_edpm_repo_baseurl is defined + - cifmw_fdp_update_edpm_repo_baseurl | length > 0 + - cifmw_fdp_update_edpm_packages is defined + - cifmw_fdp_update_edpm_packages | length > 0 + fail_msg: "Package updates require: cifmw_fdp_update_edpm_repo_baseurl and cifmw_fdp_update_edpm_packages" + when: cifmw_fdp_update_edpm_packages_enabled | bool + +- name: Verify oc command is available + ansible.builtin.command: oc version --client + changed_when: false + +- name: Initialize updated nodesets tracking list + ansible.builtin.set_fact: + _cifmw_fdp_update_edpm_updated_nodesets: [] diff --git a/zuul.d/molecule.yaml b/zuul.d/molecule.yaml index 10decae4bd..2ed0cc6a41 100644 --- a/zuul.d/molecule.yaml +++ b/zuul.d/molecule.yaml @@ -927,6 +927,24 @@ - ^.config/molecule/.* name: cifmw-molecule-cleanup_openstack parent: cifmw-molecule-noop +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/fdp_update_container_images/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-fdp_update_container_images + parent: cifmw-molecule-noop +- job: + files: + - ^common-requirements.txt + - ^test-requirements.txt + - ^roles/fdp_update_edpm/.* + - ^ci/playbooks/molecule.* + - ^.config/molecule/.* + name: cifmw-molecule-fdp_update_edpm + parent: cifmw-molecule-noop - job: files: - ^common-requirements.txt diff --git a/zuul.d/projects.yaml b/zuul.d/projects.yaml index f68e2c3351..b213366beb 100644 --- a/zuul.d/projects.yaml +++ b/zuul.d/projects.yaml @@ -55,6 +55,8 @@ - cifmw-molecule-edpm_kustomize - cifmw-molecule-edpm_prepare - cifmw-molecule-env_op_images + - cifmw-molecule-fdp_update_container_images + - cifmw-molecule-fdp_update_edpm - cifmw-molecule-federation - cifmw-molecule-fix_python_encodings - cifmw-molecule-hci_prepare