diff --git a/.github/workflows/ansible-lint.yml b/.github/workflows/ansible-lint.yml index fbe78977fa..aea0698715 100644 --- a/.github/workflows/ansible-lint.yml +++ b/.github/workflows/ansible-lint.yml @@ -10,6 +10,7 @@ on: - pub/q2_dev - pub/telemetry - pub/q2_upgrade + - pub/q2_ansible jobs: build: diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 6b2b1f4d3d..3aaded93be 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -10,6 +10,7 @@ on: - pub/q2_dev - pub/telemetry - pub/q2_upgrade + - pub/q2_ansible jobs: build: diff --git a/build_image_aarch64/ansible.cfg b/build_image_aarch64/ansible.cfg index dba4437510..2ddcf7b8bc 100644 --- a/build_image_aarch64/ansible.cfg +++ b/build_image_aarch64/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/build_image_aarch64/build_image_aarch64.yml b/build_image_aarch64/build_image_aarch64.yml index a30f66e471..4faed8e057 100644 --- a/build_image_aarch64/build_image_aarch64.yml +++ b/build_image_aarch64/build_image_aarch64.yml @@ -24,7 +24,7 @@ - name: Set dynamic run tags including 'build_aarch_image' when: not config_file_status | default(false) | bool ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['build_aarch_image']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['build_aarch_image']) | unique }}" cacheable: true - name: Invoke validate_config.yml to perform L1 and L2 validations with build_image tag @@ -137,6 +137,16 @@ roles: - prepare_arm_node +- name: Pre-flight SELinux policy fix on aarch64 node + hosts: admin_aarch64 + connection: ssh + gather_facts: false + tasks: + - name: Install SELinux policy module for container runtime + ansible.builtin.include_role: + name: image_creation + tasks_from: preflight_selinux_check.yml + - name: Fetch packages for aarch64 hosts: localhost connection: local diff --git a/build_image_aarch64/roles/image_creation/files/omnia-crun-bpf.te b/build_image_aarch64/roles/image_creation/files/omnia-crun-bpf.te new file mode 100644 index 0000000000..b92fbb1be8 --- /dev/null +++ b/build_image_aarch64/roles/image_creation/files/omnia-crun-bpf.te @@ -0,0 +1,15 @@ +module omnia-crun-bpf 1.0; + +require { + type init_t; + type container_runtime_t; + class bpf prog_run; +} + +#============= init_t ============== +# Fix: container-selinux policy regression on RHEL 10.2 (kernel 6.12+, crun 1.27+). +# systemd (init_t) needs prog_run on container_runtime_t bpf programs to install +# eBPF device filters on container cgroups. Without this, Podman containers fail: +# "crun: systemd failed to install eBPF device filter on cgroup ..." +# Retire this module once an updated container-selinux ships the fix. +allow init_t container_runtime_t:bpf prog_run; diff --git a/build_image_aarch64/roles/image_creation/tasks/build_image_common.yml b/build_image_aarch64/roles/image_creation/tasks/build_image_common.yml index 1fba00e504..412566d8c7 100644 --- a/build_image_aarch64/roles/image_creation/tasks/build_image_common.yml +++ b/build_image_aarch64/roles/image_creation/tasks/build_image_common.yml @@ -65,3 +65,17 @@ {{ '-e AWS_REQUEST_CHECKSUM_CALCULATION=when_required -e AWS_RESPONSE_CHECKSUM_VALIDATION=when_required' if s3_configurations.provider == 'powerscale' else '' }} + +- name: Verify Podman can run containers + ansible.builtin.command: + cmd: podman run --rm localhost/{{ aarch64_local_tag }} echo ok + register: _podman_verify + changed_when: false + failed_when: false + delegate_to: "{{ aarch64_build_host }}" + connection: ssh + +- name: Fail if Podman container runtime is broken + ansible.builtin.fail: + msg: "{{ podman_verify_fail_msg }} Error: {{ _podman_verify.stderr | default('unknown') }}" + when: _podman_verify.rc != 0 diff --git a/build_image_aarch64/roles/image_creation/tasks/preflight_selinux_check.yml b/build_image_aarch64/roles/image_creation/tasks/preflight_selinux_check.yml new file mode 100644 index 0000000000..8327426318 --- /dev/null +++ b/build_image_aarch64/roles/image_creation/tasks/preflight_selinux_check.yml @@ -0,0 +1,75 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. 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. +--- + +# Pre-flight: Install minimal SELinux policy module to fix container-selinux +# regression on RHEL 10.2 (crun 1.27 + kernel 6.12). SELinux stays enforcing. +# Retire this when an updated container-selinux ships the bpf prog_run rule. + +- name: Install omnia-crun-bpf SELinux policy module + block: + - name: Ensure SELinux policy build tools are present + ansible.builtin.package: + name: + - policycoreutils + - checkpolicy + state: present + + - name: Check if omnia-crun-bpf SELinux module is loaded + ansible.builtin.command: semodule -lfull + register: _selinux_modules + changed_when: false + + - name: Create SELinux custom policy directory + ansible.builtin.file: + path: "{{ selinux_policy_dir }}" + state: directory + mode: "0755" + when: selinux_module_name not in _selinux_modules.stdout + + - name: Copy omnia-crun-bpf policy source + ansible.builtin.copy: + src: omnia-crun-bpf.te + dest: "{{ selinux_policy_dir }}/omnia-crun-bpf.te" + mode: "0600" + when: selinux_module_name not in _selinux_modules.stdout + + - name: Compile SELinux policy module + ansible.builtin.command: + cmd: >- + checkmodule -M -m + -o {{ selinux_policy_dir }}/omnia-crun-bpf.mod + {{ selinux_policy_dir }}/omnia-crun-bpf.te + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + - name: Package SELinux policy module + ansible.builtin.command: + cmd: >- + semodule_package + -o {{ selinux_policy_dir }}/omnia-crun-bpf.pp + -m {{ selinux_policy_dir }}/omnia-crun-bpf.mod + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + - name: Load SELinux policy module + ansible.builtin.command: + cmd: semodule -X 300 -i {{ selinux_policy_dir }}/omnia-crun-bpf.pp + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + rescue: + - name: Warn that SELinux policy module installation failed + ansible.builtin.debug: + msg: "{{ selinux_install_warn_msg }}" diff --git a/build_image_aarch64/roles/image_creation/vars/main.yml b/build_image_aarch64/roles/image_creation/vars/main.yml index 7a1e7b2c2e..97773fd26c 100644 --- a/build_image_aarch64/roles/image_creation/vars/main.yml +++ b/build_image_aarch64/roles/image_creation/vars/main.yml @@ -54,3 +54,16 @@ compute_image_failure_msg: | openchami_compute_image_config_template: "{{ role_path }}/templates/images/rhel-compute-config.yaml.j2" storage_config_file_path: "{{ input_project_dir }}/storage_config.yml" storage_config_syntax_fail_msg: "Failed to load storage_config.yml due to syntax error" + +# preflight_selinux_check.yml +selinux_module_name: "omnia-crun-bpf" +selinux_policy_dir: "/etc/selinux/targeted/custom" +podman_verify_fail_msg: >- + Podman cannot start containers on this node. + Ensure the node was rebooted after the kernel update and that the + omnia-crun-bpf SELinux module loaded successfully + (semodule -lfull | grep omnia-crun-bpf). +selinux_install_warn_msg: >- + WARNING: Failed to install omnia-crun-bpf SELinux policy module. + Build will continue but may fail if the eBPF device filter issue is present. + Check SELinux policy tools and audit log on this node. diff --git a/build_image_x86_64/ansible.cfg b/build_image_x86_64/ansible.cfg index eec7b1c4cf..4d5729de9a 100644 --- a/build_image_x86_64/ansible.cfg +++ b/build_image_x86_64/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/build_image_x86_64/build_image_x86_64.yml b/build_image_x86_64/build_image_x86_64.yml index 1909803155..7cf90772e8 100644 --- a/build_image_x86_64/build_image_x86_64.yml +++ b/build_image_x86_64/build_image_x86_64.yml @@ -24,7 +24,7 @@ - name: Set dynamic run tags including 'build_image' when: not config_file_status | default(false) | bool ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['build_image']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['build_image']) | unique }}" cacheable: true - name: Invoke validate_config.yml to perform L1 and L2 validations with build_image tag @@ -97,6 +97,16 @@ oim_group: true tags: always +- name: Pre-flight SELinux policy fix on OIM node + hosts: oim + connection: ssh + gather_facts: false + tasks: + - name: Install SELinux policy module for container runtime + ansible.builtin.include_role: + name: image_creation + tasks_from: preflight_selinux_check.yml + - name: Configure auth for OpenCHAMI hosts: oim connection: ssh diff --git a/build_image_x86_64/roles/image_creation/files/omnia-crun-bpf.te b/build_image_x86_64/roles/image_creation/files/omnia-crun-bpf.te new file mode 100644 index 0000000000..b92fbb1be8 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/files/omnia-crun-bpf.te @@ -0,0 +1,15 @@ +module omnia-crun-bpf 1.0; + +require { + type init_t; + type container_runtime_t; + class bpf prog_run; +} + +#============= init_t ============== +# Fix: container-selinux policy regression on RHEL 10.2 (kernel 6.12+, crun 1.27+). +# systemd (init_t) needs prog_run on container_runtime_t bpf programs to install +# eBPF device filters on container cgroups. Without this, Podman containers fail: +# "crun: systemd failed to install eBPF device filter on cgroup ..." +# Retire this module once an updated container-selinux ships the fix. +allow init_t container_runtime_t:bpf prog_run; diff --git a/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml b/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml index 2d58c20623..5d32246379 100644 --- a/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml +++ b/build_image_x86_64/roles/image_creation/tasks/build_image_common.yml @@ -64,3 +64,15 @@ {{ '-e AWS_REQUEST_CHECKSUM_CALCULATION=when_required -e AWS_RESPONSE_CHECKSUM_VALIDATION=when_required' if s3_configurations.provider == 'powerscale' else '' }} + +- name: Verify Podman can run containers + ansible.builtin.command: + cmd: podman run --rm localhost/{{ x86_64_local_tag }} echo ok + register: _podman_verify + changed_when: false + failed_when: false + +- name: Fail if Podman container runtime is broken + ansible.builtin.fail: + msg: "{{ podman_verify_fail_msg }} Error: {{ _podman_verify.stderr | default('unknown') }}" + when: _podman_verify.rc != 0 diff --git a/build_image_x86_64/roles/image_creation/tasks/preflight_selinux_check.yml b/build_image_x86_64/roles/image_creation/tasks/preflight_selinux_check.yml new file mode 100644 index 0000000000..8327426318 --- /dev/null +++ b/build_image_x86_64/roles/image_creation/tasks/preflight_selinux_check.yml @@ -0,0 +1,75 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. 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. +--- + +# Pre-flight: Install minimal SELinux policy module to fix container-selinux +# regression on RHEL 10.2 (crun 1.27 + kernel 6.12). SELinux stays enforcing. +# Retire this when an updated container-selinux ships the bpf prog_run rule. + +- name: Install omnia-crun-bpf SELinux policy module + block: + - name: Ensure SELinux policy build tools are present + ansible.builtin.package: + name: + - policycoreutils + - checkpolicy + state: present + + - name: Check if omnia-crun-bpf SELinux module is loaded + ansible.builtin.command: semodule -lfull + register: _selinux_modules + changed_when: false + + - name: Create SELinux custom policy directory + ansible.builtin.file: + path: "{{ selinux_policy_dir }}" + state: directory + mode: "0755" + when: selinux_module_name not in _selinux_modules.stdout + + - name: Copy omnia-crun-bpf policy source + ansible.builtin.copy: + src: omnia-crun-bpf.te + dest: "{{ selinux_policy_dir }}/omnia-crun-bpf.te" + mode: "0600" + when: selinux_module_name not in _selinux_modules.stdout + + - name: Compile SELinux policy module + ansible.builtin.command: + cmd: >- + checkmodule -M -m + -o {{ selinux_policy_dir }}/omnia-crun-bpf.mod + {{ selinux_policy_dir }}/omnia-crun-bpf.te + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + - name: Package SELinux policy module + ansible.builtin.command: + cmd: >- + semodule_package + -o {{ selinux_policy_dir }}/omnia-crun-bpf.pp + -m {{ selinux_policy_dir }}/omnia-crun-bpf.mod + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + - name: Load SELinux policy module + ansible.builtin.command: + cmd: semodule -X 300 -i {{ selinux_policy_dir }}/omnia-crun-bpf.pp + changed_when: true + when: selinux_module_name not in _selinux_modules.stdout + + rescue: + - name: Warn that SELinux policy module installation failed + ansible.builtin.debug: + msg: "{{ selinux_install_warn_msg }}" diff --git a/build_image_x86_64/roles/image_creation/vars/main.yml b/build_image_x86_64/roles/image_creation/vars/main.yml index 1a6e34c16c..84785d385b 100644 --- a/build_image_x86_64/roles/image_creation/vars/main.yml +++ b/build_image_x86_64/roles/image_creation/vars/main.yml @@ -61,3 +61,16 @@ network_spec: "{{ input_project_dir }}/network_spec.yml" network_spec_syntax_fail_msg: "Failed to load network_spec.yml due to syntax error" storage_config_file_path: "{{ input_project_dir }}/storage_config.yml" storage_config_syntax_fail_msg: "Failed to load storage_config.yml due to syntax error" + +# preflight_selinux_check.yml +selinux_module_name: "omnia-crun-bpf" +selinux_policy_dir: "/etc/selinux/targeted/custom" +podman_verify_fail_msg: >- + Podman cannot start containers on this node. + Ensure the node was rebooted after the kernel update and that the + omnia-crun-bpf SELinux module loaded successfully + (semodule -lfull | grep omnia-crun-bpf). +selinux_install_warn_msg: >- + WARNING: Failed to install omnia-crun-bpf SELinux policy module. + Build will continue but may fail if the eBPF device filter issue is present. + Check SELinux policy tools and audit log on this node. diff --git a/build_stream/core/catalog/CATALOG_GENERATOR.md b/build_stream/core/catalog/CATALOG_GENERATOR.md new file mode 100644 index 0000000000..22ef3613a1 --- /dev/null +++ b/build_stream/core/catalog/CATALOG_GENERATOR.md @@ -0,0 +1,106 @@ +# Catalog generator + +This directory contains utility tools for catalog generation and validation. + +## Tools + +### 1. generate_catalog_examples.py + +Generates example catalog JSON files from input configuration by cycling through different mapping/software_config combinations. + +**Location:** `build_stream/generate_catalog_examples.py` + +**Usage:** +```bash +cd /omnia/build_stream +python3 generate_catalog_examples.py --base-dir /omnia/input/project_default/ +``` + +**What it does:** +- Copies mapping files from `examples/catalog/mapping_file_software_config/` to the input directory +- Generates catalogs for each mapping variant (slurm-only, nfs-provisioner, etc.) +- Outputs generated catalogs to `examples/catalog/` directory +- Provides a summary of packages and layers generated + +**Generated catalogs:** +- `catalog_rhel_aarch64_with_slurm_only.json` +- `catalog_rhel_x86_64_with_slurm_only.json` +- `catalog_rhel_with_nfs_provisioner.json` +- `catalog_rhel_x86_64.json` +- `catalog_rhel.json` + +--- + +### 2. diff_input_configs.py + +Compares two input directories (expected vs actual) and reports per-file, per-cluster package differences. +This can be used independantly or after running the catalog generator to check the differences. + +**Location:** `build_stream/core/catalog/tests/diff_input_configs.py` + +**Usage:** +```bash +cd /omnia/build_stream/core/catalog/tests +python3 diff_input_configs.py \ + --expected /omnia/input \ + --actual /tmp/adapter_output_test/input +``` + +**Optional arguments:** +- `--file-level`: Compare packages at file level (flatten all clusters) instead of per-cluster +- `--report `: Write a human-readable table report to the given file +- `--pxe-mapping `: Path to PXE mapping CSV file for information display +- `--catalog `: Path to catalog file for information display + +**What it does:** +1. Compares `software_config.json` (softwares list and versions) +2. Walks `config////*.json` in both directories +3. For each matching JSON, compares packages per cluster section +4. Reports missing files, extra files, and per-cluster diffs +5. Handles versioned filenames (e.g., `service_k8s_v1.35.1.json` matches `service_k8s.json`) +6. Ignores common package extraction and `_first` cluster merging artifacts + +**Programmatic usage (for tests):** +```python +from diff_input_configs import run_diff_for_test + +passed, issue_count, report_path = run_diff_for_test( + expected_dir="/path/to/expected", + actual_dir="/path/to/actual", + report_file="/path/to/report.txt" # optional, uses temp file if not provided +) +# Returns: (passed: bool, issue_count: int, report_path: str) +``` + +**Exit codes:** +- `0`: No differences found +- `1`: Differences found + +--- + +### 3. test_catalog_diff_regression.py + +Regression test suite that validates catalog generation and adapter policy output. + +**Location:** `build_stream/core/catalog/tests/test_catalog_diff_regression.py` + +**Core idea:** +Validates the end-to-end flow: catalog → adapter policy → input configs, ensuring the generated output matches the expected input configuration files. + +**Steps:** +1. Loads example catalog (`catalog_rhel.json`) +2. Runs generator to create root JSONs (functional_layer.json, infrastructure.json, etc.) +3. Runs adapter policy to generate input configs from root JSONs +4. Uses `diff_input_configs.py` to compare generated output with expected input configs +5. Validates functional layers match PXE mapping expectations +6. Checks specific package routing and architecture constraints + +**Usage:** +```bash +cd /omnia/build_stream/core/catalog/tests +python3 -m pytest test_catalog_diff_regression.py -v +``` + +**Test classes:** +- `TestAdapterDiffReport`: Verifies adapter output matches expected configs using diff tool +- `TestCatalogFunctionalLayers`: Validates functional layers against PXE mapping and architecture constraints diff --git a/build_stream/core/catalog/tests/test_generate_catalog_id.py b/build_stream/core/catalog/tests/test_generate_catalog_id.py new file mode 100644 index 0000000000..00807b3e41 --- /dev/null +++ b/build_stream/core/catalog/tests/test_generate_catalog_id.py @@ -0,0 +1,84 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. 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. + +import unittest +import sys +from pathlib import Path + +# Add parent directory to path to import generate_catalog +sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent)) + +from generate_catalog import _generate_human_readable_id + +class TestGenerateHumanReadableId(unittest.TestCase): + def setUp(self): + self.used_ids = set() + + def test_basic_names(self): + # Should remain unchanged + self.assertEqual(_generate_human_readable_id("apptainer", "rpm", None, self.used_ids), "apptainer") + self.assertEqual(_generate_human_readable_id("device-mapper-multipath", "rpm", None, self.used_ids), "device-mapper-multipath") + + def test_version_in_name_exact(self): + # Should strip exact version suffix + self.assertEqual(_generate_human_readable_id("external-snapshotter-v8.4.0", "git", "v8.4.0", self.used_ids), "external-snapshotter") + + def test_version_in_name_v_prefixed(self): + # Should strip if 'v' prefix is in name but not in version + self.assertEqual(_generate_human_readable_id("app-v1.0.0", "rpm", "1.0.0", self.used_ids), "app") + + def test_version_in_name_dots_replaced(self): + # Should strip if dots are replaced by hyphens + self.assertEqual(_generate_human_readable_id("helm-charts-2-16-0", "git", "2.16.0", self.used_ids), "helm-charts") + + def test_pip_module_format(self): + # PyMySQL==1.1.2 -> PyMySQL + self.assertEqual(_generate_human_readable_id("PyMySQL==1.1.2", "pip_module", None, self.used_ids), "PyMySQL") + + def test_regex_fallback_no_version(self): + # Regex should strip the version even without explicit pkg_version + self.assertEqual(_generate_human_readable_id("calico-v3.31.4", "manifest", None, self.used_ids), "calico") + self.assertEqual(_generate_human_readable_id("cert-manager-v1-10-0", "tarball", None, self.used_ids), "cert-manager") + self.assertEqual(_generate_human_readable_id("helm-v3-20-1-amd64", "tarball", None, self.used_ids), "helm-amd64") + self.assertEqual(_generate_human_readable_id("helm-v3-20-1-chart", "tarball", None, self.used_ids), "helm-chart") + self.assertEqual(_generate_human_readable_id("helm-v3-20-1-anything-suffixed", "tarball", None, self.used_ids), "helm-anything-suffixed") + self.assertEqual(_generate_human_readable_id("metallb-native-v0-15-3", "manifest", None, self.used_ids), "metallb-native") + self.assertEqual(_generate_human_readable_id("strimzi-kafka-operator-helm-3-chart-0-48-0", "tarball", None, self.used_ids), "strimzi-kafka-operator-helm-3-chart") + self.assertEqual(_generate_human_readable_id("victoria-metrics-operator-0-59-3", "tarball", None, self.used_ids), "victoria-metrics-operator") + self.assertEqual(_generate_human_readable_id("python3-PyMySQL-1.1.2", "rpm", None, self.used_ids), "python3-PyMySQL") + self.assertEqual(_generate_human_readable_id("nfs-subdir-external-provisioner-4-0-18", "tarball", None, self.used_ids), "nfs-subdir-external-provisioner") + + def test_docker_image_without_tag_in_name(self): + # Docker images usually don't have the tag in the name field, just the image path + self.assertEqual(_generate_human_readable_id("docker.io/library/python", "image", "3.12-slim", self.used_ids), "docker.io/library/python") + + def test_collision_handling(self): + # First call gets the base name + id1 = _generate_human_readable_id("calico", "rpm", None, self.used_ids) + self.assertEqual(id1, "calico") + + # Second call with the same base name gets _1 + id2 = _generate_human_readable_id("calico-v1.0.0", "tarball", None, self.used_ids) + self.assertEqual(id2, "calico_1") + + # Third call gets _2 + id3 = _generate_human_readable_id("calico-v2.0.0", "manifest", None, self.used_ids) + self.assertEqual(id3, "calico_2") + + self.assertIn("calico", self.used_ids) + self.assertIn("calico_1", self.used_ids) + self.assertIn("calico_2", self.used_ids) + +if __name__ == "__main__": + unittest.main() diff --git a/build_stream/generate_catalog.py b/build_stream/generate_catalog.py index 712c5b5552..51e7178583 100644 --- a/build_stream/generate_catalog.py +++ b/build_stream/generate_catalog.py @@ -177,37 +177,43 @@ def _merge_package_entries(dst, src): def _generate_human_readable_id(pkg_name, pkg_type, pkg_version, used_ids): """Generate a human-readable package ID with collision handling. - Format: {sanitized_name}_{version}_{type} + Format: {name} (the version is stripped from the name) If collision occurs, append counter: {base_id}_{counter} """ # Extract version from package name if present (e.g., PyMySQL==1.1.2) name_for_id = pkg_name - if '==' in pkg_name and pkg_type == 'pip_module': - # For pip modules, name==version format + if '==' in pkg_name: parts = pkg_name.split('==') - if len(parts) == 2: - name_for_id = parts[0] - if not pkg_version: - pkg_version = parts[1] - elif '-' in pkg_name and pkg_type == 'rpm' and not pkg_version: - # Some RPMs have version in name (e.g., python3-PyMySQL-1.1.2) - # Try to extract version if it looks like a version number - parts = pkg_name.rsplit('-', 1) - if len(parts) == 2 and re.match(r'^\d', parts[1]): - name_for_id = parts[0] + name_for_id = parts[0] + if not pkg_version: pkg_version = parts[1] + + # Try exact match removal if version is known + if pkg_version and isinstance(pkg_version, str): + # match at the end with 'v' prefixed + if name_for_id.endswith('v' + pkg_version): + name_for_id = name_for_id[:-(len(pkg_version) + 1)] + # exact match at the end + elif name_for_id.endswith(pkg_version): + name_for_id = name_for_id[:-len(pkg_version)] + # match with dots replaced by hyphens + elif name_for_id.endswith(pkg_version.replace('.', '-')): + name_for_id = name_for_id[:-len(pkg_version)] + + # Use regex to strip version-like suffixes for remaining cases + # Matches: + # 1. -v followed by digits/dots/hyphens (e.g. -v1.2.3, -v2) + # 2. - followed by multi-part digits (e.g. -2-16-0, -1.1.2) + # 3. - followed by single digit at the end (e.g. -3$) + # Preserves trailing non-version suffixes (e.g. -amd64, -chart) + version_regex = r'[-_](?:v\d+(?:[-.]\d+)*|\d+(?:[-.]\d+)+|\d+$)(?=[-_]|$)' + name_for_id = re.sub(version_regex, '', name_for_id) - # Sanitize package name: replace special chars with hyphens - sanitized = re.sub(r'[/@:.]', '-', name_for_id) - sanitized = re.sub(r'-+', '-', sanitized).strip('-') - - # Truncate very long names to reasonable length - if len(sanitized) > 50: - sanitized = sanitized[:50] + # Clean up trailing separators + name_for_id = name_for_id.rstrip('-_') # Build base ID - version_part = pkg_version if pkg_version else 'na' - base_id = f"{sanitized}_{version_part}_{pkg_type}" + base_id = name_for_id # Handle collisions if base_id not in used_ids: diff --git a/build_stream/playbook-watcher/playbook_watcher_service.py b/build_stream/playbook-watcher/playbook_watcher_service.py index c625b60a72..170fa247cb 100644 --- a/build_stream/playbook-watcher/playbook_watcher_service.py +++ b/build_stream/playbook-watcher/playbook_watcher_service.py @@ -84,8 +84,8 @@ def log_secure_info( HOST_LOG_BASE_DIR = NFS_SHARE_PATH / "omnia" / "log" / "build_stream" CONTAINER_LOG_BASE_DIR = Path("/opt/omnia/log/build_stream") -# Build Stream artifacts directory (configurable via environment variable) -BUILD_STREAM_ROOT = Path(os.getenv("BUILD_STREAM_ROOT", "/opt/omnia/build_stream_root")) +# Build Stream artifacts directory (constructed from NFS_SHARE_PATH like HOST_LOG_BASE_DIR) +BUILD_STREAM_ROOT = NFS_SHARE_PATH / "omnia" / "build_stream_root" ARTIFACTS_DIR = BUILD_STREAM_ROOT / "artifacts" POLL_INTERVAL_SECONDS = int(os.getenv("POLL_INTERVAL_SECONDS", "2")) diff --git a/build_stream/requirements-dev.txt b/build_stream/requirements-dev.txt index 6cae6350c7..f7abb54867 100644 --- a/build_stream/requirements-dev.txt +++ b/build_stream/requirements-dev.txt @@ -11,5 +11,5 @@ httpx>=0.25.0 # Code quality pylint>=3.0.0 -black>=23.0.0 +black>=26.5.0 isort>=5.12.0 diff --git a/build_stream/requirements.txt b/build_stream/requirements.txt index 631dbb182e..b47e1cf326 100644 --- a/build_stream/requirements.txt +++ b/build_stream/requirements.txt @@ -8,7 +8,7 @@ pydantic>=2.5.0 # Authentication PyJWT>=2.8.0 -cryptography>=41.0.0 +cryptography>=48.0.0 argon2-cffi>=23.1.0 # Dependency injection diff --git a/common/library/module_utils/discovery/standard_functions.py b/common/library/module_utils/discovery/standard_functions.py index 3af21a4c79..111f06de4d 100644 --- a/common/library/module_utils/discovery/standard_functions.py +++ b/common/library/module_utils/discovery/standard_functions.py @@ -82,7 +82,7 @@ def update_json(new_data, filepath): """ if os.path.exists(filepath): # Load existing data - with open(filepath, 'r') as f: + with open(filepath, 'r', encoding='utf-8') as f: try: existing_data = json.load(f) except json.JSONDecodeError: @@ -94,5 +94,5 @@ def update_json(new_data, filepath): existing_data.update(new_data) # Write back to file - with open(filepath, 'w') as f: + with open(filepath, 'w', encoding='utf-8') as f: json.dump(existing_data, f, indent=2) diff --git a/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py b/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py index 605b437b9d..f17d9c568c 100644 --- a/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py +++ b/common/library/module_utils/input_validation/common_utils/en_us_validation_msg.py @@ -102,6 +102,18 @@ " is not currently supported and is reserved for future use. Please remove or update this role" " to avoid configuration errors.") +# Mapping file and software_config.json consistency validation messages +SERVICE_K8S_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG = ( + "Service Kubernetes functional groups (service_kube_node_* or service_kube_control_plane_*) " + "are defined in the PXE mapping file, but 'service_k8s' is not configured in software_config.json. " + "Please add 'service_k8s' to the 'softwares' list in software_config.json to deploy the service cluster." +) +SLURM_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG = ( + "Slurm functional groups (slurm_control_node_* or slurm_node_*) " + "are defined in the PXE mapping file, but 'slurm_custom' is not configured in software_config.json. " + "Please add 'slurm_custom' to the 'softwares' list in software_config.json to deploy the Slurm cluster." +) + # Functional Groups Config Validation Messages EMPTY_OR_SYNTAX_ERROR_FUNCTIONAL_GROUPS_CONFIG_MSG = ( diff --git a/common/library/module_utils/input_validation/common_utils/validation_utils.py b/common/library/module_utils/input_validation/common_utils/validation_utils.py index 395da87ec9..df1a5ed8e7 100644 --- a/common/library/module_utils/input_validation/common_utils/validation_utils.py +++ b/common/library/module_utils/input_validation/common_utils/validation_utils.py @@ -45,7 +45,7 @@ def load_yaml_as_json(yaml_file, omnia_base_dir, project_name, logger, module): if is_file_encrypted(yaml_file): data = process_encrypted_file(yaml_file, omnia_base_dir, project_name, logger, module) return data - with open(yaml_file, "r") as f: + with open(yaml_file, "r", encoding="utf-8") as f: data = yaml.safe_load(f) return data except FileNotFoundError: @@ -167,7 +167,7 @@ def load_json(file_path): ValueError: If the JSON parsing fails. """ try: - with open(file_path, 'r') as file: + with open(file_path, 'r', encoding='utf-8') as file: return json.load(file) except FileNotFoundError as exc: raise FileNotFoundError(f"Error: File '{file_path}' not found.") from exc @@ -221,7 +221,7 @@ def is_file_encrypted(file_path): bool: True if the file is encrypted, False otherwise. """ try: - with open(file_path, 'r') as file: + with open(file_path, 'r', encoding='utf-8') as file: first_line = file.readline().strip() return first_line.startswith('$ANSIBLE_VAULT') except (IOError, OSError): @@ -245,7 +245,7 @@ def process_encrypted_file(yaml_file, omnia_base_dir, project_name, logger, modu decrypted_file = decrypt_file(omnia_base_dir, project_name, yaml_file, vault_password_file) if decrypted_file: try: - with open(yaml_file, "r") as f: + with open(yaml_file, "r", encoding="utf-8") as f: data = yaml.safe_load(f) encrypt_file(omnia_base_dir, project_name, yaml_file, vault_password_file) return data diff --git a/common/library/module_utils/input_validation/validation_flows/local_repo_validation.py b/common/library/module_utils/input_validation/validation_flows/local_repo_validation.py index e81ecd8be7..8167984fb1 100644 --- a/common/library/module_utils/input_validation/validation_flows/local_repo_validation.py +++ b/common/library/module_utils/input_validation/validation_flows/local_repo_validation.py @@ -43,39 +43,43 @@ def check_subscription_status(logger=None): # 1. Check system entitlement certs first system_entitlement_certs = glob.glob(config.SYSTEM_ENTITLEMENT_PATH) has_system_entitlement = len(system_entitlement_certs) > 0 - + if has_system_entitlement: # System entitlement found - use system paths only entitlement_certs = system_entitlement_certs has_entitlement = True repo_file_to_check = config.SYSTEM_REDHAT_REPO - + if logger: - logger.info(f"Found {len(system_entitlement_certs)} system entitlement certs - using system paths only") + logger.info( + f"Found {len(system_entitlement_certs)} system entitlement certs" + " - using system paths only") else: # No system entitlement - check Omnia paths omnia_entitlement_certs = glob.glob(config.OMNIA_ENTITLEMENT_PATH) entitlement_certs = omnia_entitlement_certs has_entitlement = len(omnia_entitlement_certs) > 0 repo_file_to_check = config.OMNIA_REDHAT_REPO - + if logger: - logger.info(f"No system entitlement found - checking Omnia paths: {len(omnia_entitlement_certs)} certs found") + logger.info( + f"No system entitlement found - checking Omnia paths:" + f" {len(omnia_entitlement_certs)} certs found") # 2. Check repos based on which entitlement path was used has_repos = False repo_urls = [] redhat_repo_used = None - + if os.path.exists(repo_file_to_check): try: - with open(repo_file_to_check, "r") as f: + with open(repo_file_to_check, "r", encoding="utf-8") as f: for line in f: if line.startswith("baseurl ="): url = line.split("=", 1)[1].strip() if re.search(r"(codeready-builder|baseos|appstream)", url, re.IGNORECASE): repo_urls.append(url) - + if repo_urls: has_repos = True redhat_repo_used = repo_file_to_check @@ -91,7 +95,7 @@ def check_subscription_status(logger=None): # 3. Subscription enabled if entitlement and repos are found in the same source subscription_enabled = has_entitlement and has_repos - + if logger: logger.info( f"Subscription enabled: {subscription_enabled} " @@ -111,24 +115,24 @@ def validate_local_repo_config(input_file_path, data, omnia_repo_url_rhel fields are present and accessible. """ errors = [] - base_repo_names = [] local_repo_yml = create_file_path(input_file_path, file_names["local_repo_config"]) - - user_registry = data.get("user_registry") + + user_registry = data.get("user_registry") if user_registry: for registry in user_registry: - host = registry.get("host") cert_path = registry.get("cert_path") key_path = registry.get("key_path") - + # Validate user_registry certificate and key paths if cert_path and not os.path.exists(cert_path): - errors.append(create_error_msg(local_repo_yml, "user_registry", - f"Certificate file not found: {cert_path}")) - + errors.append(create_error_msg( + local_repo_yml, "user_registry", + f"Certificate file not found: {cert_path}")) + if key_path and not os.path.exists(key_path): - errors.append(create_error_msg(local_repo_yml, "user_registry", - f"Key file not found: {key_path}")) + errors.append(create_error_msg( + local_repo_yml, "user_registry", + f"Key file not found: {key_path}")) # Validate user_repo_url entries have a 'name' field for repo_key in ("user_repo_url_x86_64", "user_repo_url_aarch64"): @@ -156,11 +160,12 @@ def validate_local_repo_config(input_file_path, data, for arch in all_archs: arch_repo_names = [] arch_list = url_list + [url+'_'+arch for url in url_list] - # define base repos dynamically for this arch if subscription registered + base_subscription_repos = [] + # define base repos dynamically for this arch if subscription registered if sub_result: base_subscription_repos = ["baseos", "appstream", "codeready-builder"] logger.info(f"Base subscription repos for {arch}: {base_subscription_repos}") - + # Collect repo names from standard repo lists # Names are kept as-is (short format); build_repo_name() is applied at runtime for repurl in arch_list: @@ -194,11 +199,11 @@ def validate_local_repo_config(input_file_path, data, raw_name = x.get('name') if raw_name: arch_repo_names.append(raw_name) - + # Add base subscription repos to the final list (they will be dynamically generated) if sub_result: arch_repo_names = arch_repo_names + base_subscription_repos - + repo_names[arch] = arch_repo_names logger.info(f"Total repos for {arch}: {repo_names[arch]}") @@ -232,7 +237,6 @@ def validate_local_repo_config(input_file_path, data, ) ) - os_ver_path = f"/{software_config_json['cluster_os_type']}/{software_config_json['cluster_os_version']}/" supported_subgroups = config.ADDITIONAL_PACKAGES_SUPPORTED_SUBGROUPS additional_packages_warnings = False @@ -244,7 +248,7 @@ def validate_local_repo_config(input_file_path, data, for arch in arch_list: # Use get_json_file_path for proper versioned JSON file resolution json_path = get_json_file_path( - sw, cluster_os_type, cluster_os_version, + sw, cluster_os_type, cluster_os_version, software_config_file_path, arch, software_version=software_version) if not json_path or not os.path.exists(json_path): @@ -254,7 +258,10 @@ def validate_local_repo_config(input_file_path, data, else: expected_file = f"{sw}.json" errors.append( - create_error_msg(sw + '/' + arch, f"{sw} JSON file not found for architecture {arch}.", expected_file)) + create_error_msg( + sw + '/' + arch, + f"{sw} JSON file not found for architecture {arch}.", + expected_file)) else: curr_json = load_json(json_path) pkg_list = curr_json[sw]['cluster'] @@ -278,7 +285,8 @@ def validate_local_repo_config(input_file_path, data, elif json_key not in user_subgroups: logger.warning( f"{sw}/{arch}: {json_path} - " - f"Subgroup '{json_key}' is present in JSON but not listed under additional_packages in software_config.json.") + f"Subgroup '{json_key}' is present in JSON but not listed" + f" under additional_packages in software_config.json.") additional_packages_warnings = True if sw in software_config_json: for sub_pkg in software_config_json[sw]: @@ -289,12 +297,11 @@ def validate_local_repo_config(input_file_path, data, if sw == "additional_packages": if sub_sw not in supported_subgroups.get(arch, []): continue - else: - logger.warning( - f"{sw}/{arch}: {json_path} - " - f"Software {sub_sw} not found in {sw}.") - additional_packages_warnings = True - continue + logger.warning( + f"{sw}/{arch}: {json_path} - " + f"Software {sub_sw} not found in {sw}.") + additional_packages_warnings = True + continue errors.append( create_error_msg(sw + '/' + arch, json_path, @@ -317,10 +324,10 @@ def validate_local_repo_config(input_file_path, data, create_error_msg(sw + '/' + arch, f"Repo name {repo_name} not found.", json_path)) - + if additional_packages_warnings: logger.info( "[INFO] Additional packages validation completed with warnings. " "Please review the log file for additional_packages configuration details.") - + return errors diff --git a/common/library/module_utils/input_validation/validation_flows/provision_validation.py b/common/library/module_utils/input_validation/validation_flows/provision_validation.py index 1a9f610d69..6b7fdabcef 100644 --- a/common/library/module_utils/input_validation/validation_flows/provision_validation.py +++ b/common/library/module_utils/input_validation/validation_flows/provision_validation.py @@ -915,6 +915,89 @@ def validate_aarch64_local_path_compatibility(pxe_mapping_file_path): if aarch64_found: raise ValueError(en_us_validation_msg.PXE_MAPPING_AARCH64_LOCAL_PATH_MSG) +def validate_functional_groups_software_consistency(pxe_mapping_file_path, software_config_json, logger): + """ + Validates that functional groups in the PXE mapping file have corresponding + software configured in software_config.json. + + This ensures that: + - If service_kube_node_* or service_kube_control_plane_* functional groups exist + in the mapping file, then 'service_k8s' must be in software_config.json + - If slurm_control_node_* or slurm_node_* functional groups exist in the mapping file, + then 'slurm_custom' must be in software_config.json + + Args: + pxe_mapping_file_path (str): Path to the PXE mapping file. + software_config_json (dict): Parsed software_config.json data. + logger (Logger): Logger instance for logging messages. + + Raises: + ValueError: If functional groups are defined without corresponding software. + """ + if not pxe_mapping_file_path or not os.path.isfile(pxe_mapping_file_path): + return + + # Read the mapping file to find functional groups + with open(pxe_mapping_file_path, "r", encoding="utf-8") as fh: + raw_lines = fh.readlines() + + non_comment_lines = [ln for ln in raw_lines if ln.strip()] + if not non_comment_lines: + return + + reader = csv.DictReader(non_comment_lines) + fieldname_map = {fn.strip().upper(): fn for fn in reader.fieldnames} + fg_col = fieldname_map.get("FUNCTIONAL_GROUP_NAME") + + if not fg_col: + return + + # Track which functional groups are found + has_service_k8s_fg = False + has_slurm_fg = False + + for row in reader: + fg_name = row.get(fg_col, "").strip() if row.get(fg_col) else "" + if not fg_name: + continue + + # Check for service k8s functional groups + if fg_name.startswith('service_kube_node_') or fg_name.startswith('service_kube_control_plane_'): + has_service_k8s_fg = True + logger.info(f"Found service k8s functional group in mapping file: {fg_name}") + + # Check for slurm functional groups + if fg_name.startswith('slurm_control_node_') or fg_name.startswith('slurm_node_'): + has_slurm_fg = True + logger.info(f"Found slurm functional group in mapping file: {fg_name}") + + # Get list of software names from software_config.json + software_names = [] + if software_config_json and "softwares" in software_config_json: + software_names = [sw.get("name", "") for sw in software_config_json.get("softwares", [])] + + logger.info(f"Software configured in software_config.json: {software_names}") + + # Validate service_k8s and slurm_custom, collecting all errors + consistency_errors = [] + + if has_service_k8s_fg and "service_k8s" not in software_names: + logger.error("Service k8s functional groups found but service_k8s not in software_config.json") + consistency_errors.append(en_us_validation_msg.SERVICE_K8S_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG) + + if has_slurm_fg and "slurm_custom" not in software_names: + logger.error("Slurm functional groups found but slurm_custom not in software_config.json") + consistency_errors.append(en_us_validation_msg.SLURM_FUNCTIONAL_GROUP_WITHOUT_SOFTWARE_MSG) + + if consistency_errors: + raise ValueError(" | ".join(consistency_errors)) + + # Log success + if has_service_k8s_fg and "service_k8s" in software_names: + logger.info("✓ Service k8s functional groups validated: service_k8s found in software_config.json") + if has_slurm_fg and "slurm_custom" in software_names: + logger.info("✓ Slurm functional groups validated: slurm_custom found in software_config.json") + def validate_provision_config( input_file_path, data, logger, module, omnia_base_dir, module_utils_base, project_name ): @@ -993,6 +1076,7 @@ def validate_provision_config( validate_parent_service_tag_hierarchy(pxe_mapping_file_path) validate_slurm_login_compiler_prefix(pxe_mapping_file_path) validate_aarch64_local_path_compatibility(pxe_mapping_file_path) + validate_functional_groups_software_consistency(pxe_mapping_file_path, software_config_json, logger) # Validate ADMIN_IPs against network_spec.yml ranges # network_spec_path = create_file_path(input_file_path, file_names["network_spec"]) diff --git a/common/library/module_utils/local_repo/process_metadata.py b/common/library/module_utils/local_repo/process_metadata.py index 936788dda4..9ddbaef320 100644 --- a/common/library/module_utils/local_repo/process_metadata.py +++ b/common/library/module_utils/local_repo/process_metadata.py @@ -32,7 +32,7 @@ def load_yaml(path): """ if not os.path.isfile(path): return {} - with open(path, 'r') as f: + with open(path, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {} def write_yaml(path, data): @@ -42,7 +42,7 @@ def write_yaml(path, data): Uses block-style formatting (not flow style). """ os.makedirs(os.path.dirname(path), exist_ok=True) - with open(path, 'w') as f: + with open(path, 'w', encoding='utf-8') as f: yaml.dump(data, f, default_flow_style=False) def load_config(config_path: str) -> dict: @@ -53,7 +53,7 @@ def load_config(config_path: str) -> dict: """ if not os.path.exists(config_path): raise FileNotFoundError(f"Config file not found: {config_path}") - with open(config_path) as f: + with open(config_path, encoding='utf-8') as f: return json.load(f) def generate_policy_dict(repo_list, default_policy): diff --git a/common/library/module_utils/local_repo/process_parallel.py b/common/library/module_utils/local_repo/process_parallel.py index 2c55098c98..63c8560ba2 100644 --- a/common/library/module_utils/local_repo/process_parallel.py +++ b/common/library/module_utils/local_repo/process_parallel.py @@ -42,17 +42,20 @@ def load_docker_credentials(vault_yml_path, vault_password_file): """ - Decrypts an Ansible Vault YAML file, extracts docker_username and docker_password, - and validates them using Docker Hub API. + Loads docker_username and docker_password from a credentials YAML file, + decrypting it with Ansible Vault only when the file is actually encrypted, + and validates the credentials using the Docker Hub API. Validation Logic: + - If the file is vault-encrypted, decrypts it using ansible-vault view. + - If the file is plain YAML (e.g. during upgrade staging), reads it directly. - Validates credentials via Docker Hub REST API - Returns credentials if authentication succeeds (HTTP 200) - Raises RuntimeError for all authentication failures Args: - vault_yml_path (str): Path to the encrypted Ansible Vault YAML file. - vault_password_file (str): Path to the vault password file. + vault_yml_path (str): Path to the Ansible Vault YAML file (may or may not be encrypted). + vault_password_file (str): Path to the vault password file (used only when encrypted). Returns: tuple: (docker_username, docker_password) or (None, None) if not provided. @@ -63,17 +66,25 @@ def load_docker_credentials(vault_yml_path, vault_password_file): is not installed. """ try: - env = os.environ.copy() - env["ANSIBLE_VAULT_PASSWORD_FILE"] = vault_password_file - - result = subprocess.run( - ["ansible-vault", "view", vault_yml_path], - capture_output=True, - text=True, - check=True, - env=env - ) - data = yaml.safe_load(result.stdout) + # Check if the file is vault-encrypted before attempting decryption. + # If it is plain YAML (e.g. during upgrade where the staging copy was + # never encrypted), read it directly to avoid the + # "input is not vault encrypted data" error. + if is_encrypted(vault_yml_path): + env = os.environ.copy() + env["ANSIBLE_VAULT_PASSWORD_FILE"] = vault_password_file + + result = subprocess.run( + ["ansible-vault", "view", vault_yml_path], + capture_output=True, + text=True, + check=True, + env=env + ) + data = yaml.safe_load(result.stdout) + else: + with open(vault_yml_path, "r", encoding="utf-8") as fh: + data = yaml.safe_load(fh) docker_username = data.get("docker_username") docker_password = data.get("docker_password") @@ -142,7 +153,7 @@ def log_table_output(table_output, log_file): # Ensure the directory for the log file exists os.makedirs(os.path.dirname(log_file), exist_ok=True) # Write the table output to the log file - with open(log_file, "w") as file: + with open(log_file, "w", encoding="utf-8") as file: file.write("Command Execution Results Table:\n") # Add a header to the table file.write(table_output) # Write the actual table content except Exception as e: diff --git a/common/library/module_utils/local_repo/software_utils.py b/common/library/module_utils/local_repo/software_utils.py index d3306d58b8..2c8a3b3da0 100644 --- a/common/library/module_utils/local_repo/software_utils.py +++ b/common/library/module_utils/local_repo/software_utils.py @@ -17,14 +17,18 @@ This module util contains all custom software utilities used across custom modules """ from collections import defaultdict +import logging import os import json import csv import re import shlex +import ssl import yaml from jinja2 import Template import requests +from requests.adapters import HTTPAdapter +from urllib3.poolmanager import PoolManager from ansible.module_utils.local_repo.standard_logger import setup_standard_logger from ansible.module_utils.local_repo.common_functions import is_encrypted, process_file, get_arch_from_sw_config from ansible.module_utils.local_repo.parse_and_download import execute_command @@ -92,7 +96,7 @@ def load_json(file_path): ValueError: If the JSON parsing fails. """ try: - with open(file_path, 'r') as file: + with open(file_path, 'r', encoding='utf-8') as file: return json.load(file) except FileNotFoundError as exc: raise FileNotFoundError(f"Error: File '{file_path}' not found.") from exc @@ -170,6 +174,35 @@ def get_csv_file_path(software_name, user_csv_dir, arch): return status_csv_file_path +class _RelaxedCAAdapter(HTTPAdapter): + """HTTPAdapter that loads a custom CA but clears VERIFY_X509_STRICT. + + Python 3.13+ enforces strict RFC 5280 Basic Constraints validation, + rejecting CA certs where the extension is not marked critical. Some + vendor CAs (e.g. Red Hat redhat-uep.pem) have non-critical Basic + Constraints which OpenSSL/curl accept. This adapter restores the + Python 3.12 behavior while keeping full chain and hostname validation. + + Remove this workaround once the upstream CA is reissued with the + Basic Constraints extension marked critical. + """ + + def __init__(self, ca_cert, client_cert, client_key, *args, **kwargs): + self._ca_cert = ca_cert + self._client_cert = client_cert + self._client_key = client_key + super().__init__(*args, **kwargs) + + def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs): + ctx = ssl.create_default_context(cafile=self._ca_cert) + ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT + if self._client_cert and self._client_key: + ctx.load_cert_chain(self._client_cert, self._client_key) + self.poolmanager = PoolManager( + num_pools=connections, maxsize=maxsize, + block=block, ssl_context=ctx, **pool_kwargs) + + def is_remote_url_reachable(remote_url, timeout=10, client_cert=None, client_key=None, ca_cert=None): """ @@ -186,20 +219,41 @@ def is_remote_url_reachable(remote_url, timeout=10, Returns: bool: True if the URL is reachable (HTTP status 200), False otherwise. """ + logger = logging.getLogger(__name__) try: # Check if SSL certs are provided and handle accordingly if client_cert and client_key and ca_cert: - response = requests.get( - remote_url, - cert=(client_cert, client_key), - verify=ca_cert, - timeout=timeout - ) + try: + response = requests.get( + remote_url, + cert=(client_cert, client_key), + verify=ca_cert, + timeout=timeout + ) + except requests.exceptions.SSLError as ssl_exc: + # Python 3.13+ rejects CA certs with non-critical Basic + # Constraints (RFC 5280 strict mode). Retry against the + # SAME CA with VERIFY_X509_STRICT cleared — still validates + # the full chain and hostname, just relaxes the one check. + logger.warning( + f"Strict SSL verification failed for {remote_url}: " + f"{ssl_exc}. Retrying with VERIFY_X509_STRICT cleared.") + session = requests.Session() + adapter = _RelaxedCAAdapter( + ca_cert, client_cert, client_key) + session.mount("https://", adapter) + response = session.get(remote_url, timeout=timeout) else: # Proceed with a regular HTTP request if no SSL certs are provided response = requests.get(remote_url, timeout=timeout) + if response.status_code != 200: + logger.error( + f"URL {remote_url} returned HTTP {response.status_code}") return response.status_code == 200 - except Exception: + except Exception as exc: + logger.error( + f"URL reachability exception for {remote_url}: " + f"{type(exc).__name__}: {exc}") return False def transform_package_dict(data, arch_val,logger): @@ -396,6 +450,10 @@ def parse_repo_urls(repo_config, local_repo_config_path, ) logger.info(f"Processing RHEL repo '{name}' for arch '{arch}' - URL: {url}") + logger.info(f"RHEL SSL paths: ca_cert={ca_cert}, client_key={client_key}, client_cert={client_cert}") + logger.info(f"RHEL SSL files exist: ca_cert={os.path.exists(ca_cert) if ca_cert else 'N/A'}, " + f"client_key={os.path.exists(client_key) if client_key else 'N/A'}, " + f"client_cert={os.path.exists(client_cert) if client_cert else 'N/A'}") for path in [ca_cert, client_key, client_cert]: mode = "decrypt" @@ -573,7 +631,7 @@ def get_csv_software(file_name): if not os.path.isfile(file_name): return csv_software - with open(file_name, mode='r') as csv_file: + with open(file_name, mode='r', encoding='utf-8') as csv_file: reader = csv.DictReader(csv_file) csv_software = [row.get(CSV_COLUMNS["column1"], "").strip() for row in reader] @@ -596,7 +654,7 @@ def get_failed_software(file_path): if not os.path.isfile(file_path): return failed_software - with open(file_path, mode='r') as csv_file: + with open(file_path, mode='r', encoding='utf-8') as csv_file: reader = csv.DictReader(csv_file) failed_software = [ str(row.get(CSV_COLUMNS["column1"]) or "").strip() @@ -796,7 +854,7 @@ def check_csv_existence(path): def read_status_csv(csv_path): """Reads the status.csv file and returns a list of row dictionaries.""" - with open(csv_path, mode='r', newline='') as file: + with open(csv_path, mode='r', newline='', encoding='utf-8') as file: reader = csv.DictReader(file) return [row for row in reader] @@ -911,7 +969,7 @@ def process_software(software, fresh_installation, json_path, csv_path, subgroup return combined, failed_packages def get_software_names(json_file_path): - with open(json_file_path, "r") as f: + with open(json_file_path, "r", encoding="utf-8") as f: data = json.load(f) softwares = data.get("softwares", []) diff --git a/common/library/module_utils/upgrade/upgrade_hop_calculator_lib.py b/common/library/module_utils/upgrade/upgrade_hop_calculator_lib.py index e7b77fea58..d888ebdd56 100644 --- a/common/library/module_utils/upgrade/upgrade_hop_calculator_lib.py +++ b/common/library/module_utils/upgrade/upgrade_hop_calculator_lib.py @@ -253,7 +253,7 @@ def update_software_config( - total_hops: Total number of hops """ # Load current config - with open(input_file) as f: + with open(input_file, encoding='utf-8') as f: config = json.load(f) # Find final version for each software (last hop in chain) @@ -293,7 +293,7 @@ def update_software_config( }) # Write updated config - with open(input_file, 'w') as f: + with open(input_file, 'w', encoding='utf-8') as f: json.dump(config, f, indent=4) # Output result @@ -372,7 +372,7 @@ def update_component_json_repos( # Read JSON file try: - with open(json_path, 'r') as f: + with open(json_path, 'r', encoding='utf-8') as f: json_data = json.load(f) except Exception as e: msg = f" Error reading {json_path}: {e}" @@ -396,7 +396,7 @@ def update_component_json_repos( # Write updated JSON file if updated: try: - with open(json_path, 'w') as f: + with open(json_path, 'w', encoding='utf-8') as f: json.dump(json_data, f, indent=4) msg = f" Success: Updated {json_path}" messages.append(msg) diff --git a/common/library/modules/create_upgrade_staging.py b/common/library/modules/create_upgrade_staging.py index 2e98a4ffbf..66edc14954 100644 --- a/common/library/modules/create_upgrade_staging.py +++ b/common/library/modules/create_upgrade_staging.py @@ -93,7 +93,7 @@ def create_staging( else: print(f"Preserved unchanged: {name}") - with open(os.path.join(staging_dir, 'software_config.json'), 'w') as f: + with open(os.path.join(staging_dir, 'software_config.json'), 'w', encoding='utf-8') as f: json.dump(sw_config, f, indent=4) print(f"software_config.json written to staging ({sw_delta_count} version(s) updated)") @@ -102,7 +102,7 @@ def create_staging( local_repo_config_path = os.path.join(input_dir, 'local_repo_config.yml') base_config = {} if os.path.exists(local_repo_config_path): - with open(local_repo_config_path) as f: + with open(local_repo_config_path, encoding='utf-8') as f: base_config = yaml.safe_load(f) or {} print(f"Loaded base local_repo_config.yml from {local_repo_config_path}") else: @@ -123,7 +123,7 @@ def create_staging( repos_added = 0 if os.path.exists(repos_file): - with open(repos_file) as f: + with open(repos_file, encoding='utf-8') as f: repos = yaml.safe_load(f) or {} # Collect Omnia versions whose repos need to be merged. @@ -186,7 +186,7 @@ def create_staging( print(f"local_repo_config.yml: {repos_added} repo(s) added from repos.yml to base config") - with open(os.path.join(staging_dir, 'local_repo_config.yml'), 'w') as f: + with open(os.path.join(staging_dir, 'local_repo_config.yml'), 'w', encoding='utf-8') as f: yaml.dump(base_config, f, default_flow_style=False, sort_keys=False) # --- 4. Copy vault credentials files if they exist --- diff --git a/common/library/modules/fetch_credential_rule.py b/common/library/modules/fetch_credential_rule.py index 1038b3d9c0..4142ba1a35 100644 --- a/common/library/modules/fetch_credential_rule.py +++ b/common/library/modules/fetch_credential_rule.py @@ -24,7 +24,7 @@ def load_rules(file_path): """Loads validation rules from JSON file.""" - with open(file_path, 'r') as file: + with open(file_path, 'r', encoding='utf-8') as file: return json.load(file) def fetch_rule(field, rules): diff --git a/common/library/modules/functional_group_parser.py b/common/library/modules/functional_group_parser.py index 418ba79fe4..9c5cc6d107 100644 --- a/common/library/modules/functional_group_parser.py +++ b/common/library/modules/functional_group_parser.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/python from ansible.module_utils.basic import AnsibleModule import yaml @@ -37,7 +37,7 @@ def normalize_functional_groups(data): def get_functional_groups(config_path): - with open(config_path, "r") as f: + with open(config_path, "r", encoding="utf-8") as f: data = yaml.safe_load(f) return normalize_functional_groups(data) diff --git a/common/library/modules/generate_discovery_report.py b/common/library/modules/generate_discovery_report.py index 8b23d43f8e..24581022c2 100644 --- a/common/library/modules/generate_discovery_report.py +++ b/common/library/modules/generate_discovery_report.py @@ -85,7 +85,7 @@ def generate_report(servers, output_file): os.makedirs(output_dir, exist_ok=True) server_count = 0 - with open(output_file, 'w', newline='') as csvfile: + with open(output_file, 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(REPORT_HEADERS) diff --git a/common/library/modules/generate_functional_groups.py b/common/library/modules/generate_functional_groups.py index f6c3c0857b..5d8e820866 100644 --- a/common/library/modules/generate_functional_groups.py +++ b/common/library/modules/generate_functional_groups.py @@ -29,7 +29,7 @@ def load_omnia_config(omnia_config_path, module): module.fail_json(msg=f"omnia_config.yml not found: {omnia_config_path}") try: - with open(omnia_config_path) as f: + with open(omnia_config_path, encoding='utf-8') as f: config = yaml.safe_load(f) or {} kube_name = None @@ -61,7 +61,7 @@ def parse_csv(filename, module): kube_control_seen = False try: - with open(filename, newline="") as f: + with open(filename, newline="", encoding="utf-8") as f: cleaned_lines = [line.strip() for line in f if line.strip()] header = cleaned_lines[0].split(",") expected_columns = len(header) @@ -131,7 +131,7 @@ def build_yaml(new_groups, new_func_groups, kube_cluster_name, slurm_cluster_nam def dump_yaml_with_comments(data, filename): """Write YAML data to file with custom formatting and comments.""" - with open(filename, "w") as f: + with open(filename, "w", encoding="utf-8") as f: f.write("# ---------------------------------------------------------------------------\n") f.write("# Groups definition\n") f.write("# ---------------------------------------------------------------------------\n") diff --git a/common/library/modules/get_service_cluster_info.py b/common/library/modules/get_service_cluster_info.py index bcb0f3af3e..5fcb73520a 100644 --- a/common/library/modules/get_service_cluster_info.py +++ b/common/library/modules/get_service_cluster_info.py @@ -24,7 +24,7 @@ def load_functional_groups_yaml(path, module): """Load functional group names from YAML.""" try: - with open(path, 'r') as f: + with open(path, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) return data.get("groups", {}) except ValueError as e: diff --git a/discovery/ansible.cfg b/discovery/ansible.cfg index a30bba0211..b7f517ca21 100644 --- a/discovery/ansible.cfg +++ b/discovery/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = library:../common/library/modules module_utils = ../common/library/module_utils diff --git a/discovery/discovery.yml b/discovery/discovery.yml index 8adfa0e5d1..1dec83db67 100644 --- a/discovery/discovery.yml +++ b/discovery/discovery.yml @@ -27,7 +27,7 @@ tasks: - name: Set dynamic run tags for discovery validation ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['discovery']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['discovery']) | unique }}" cacheable: true - name: Invoke validate_config.yml to perform L1 and L2 validations with discovery tag diff --git a/discovery/roles/ome_discovery/tasks/generate_discovery_report.yml b/discovery/roles/ome_discovery/tasks/generate_discovery_report.yml index f003ea40fb..686f5fee2c 100644 --- a/discovery/roles/ome_discovery/tasks/generate_discovery_report.yml +++ b/discovery/roles/ome_discovery/tasks/generate_discovery_report.yml @@ -56,10 +56,7 @@ - "" - "3. Update HOSTNAME, FUNCTIONAL_GROUP_NAME, GROUP_NAME as needed." - "" - - "4. Update the following parameter in provision_config.yml:" - - " pxe_mapping_file_path: {{ pxe_mapping_output_file }}" - - "" - - "5. Run:" + - "4. Run:" - " ansible-playbook provision/provision.yml" - "============================================================" @@ -84,12 +81,12 @@ - "" - "3. Update HOSTNAME, FUNCTIONAL_GROUP_NAME, GROUP_NAME as needed." - "" - - "4. Update the following parameter in provision_config.yml:" - - " pxe_mapping_file_path: {{ pxe_mapping_output_file }}" - - "" - - "5. If using BuildStream, manually copy the PXE mapping file to GitLab:" - - " input/pxe_mapping_file.csv" + - "4. If GitLab server is not yet up, copy the generated file to" + - " /opt/omnia/input/project_default/pxe_mapping_file.csv in the omnia_core container" - "" - - "6. Run:" - - " ansible-playbook provision/provision.yml" + - "5. If the GitLab server is up and running, copy the file to" + - " input/pxe_mapping_file.csv in the GitLab project and commit the changes" + - " after building the images using the build pipeline. Committing the PXE mapping" + - " file will automatically trigger the deploy pipeline and deploy the images on" + - " the nodes listed in the newly committed PXE mapping file." - "============================================================" diff --git a/examples/catalog/catalog_rhel.json b/examples/catalog/catalog_rhel.json index 5defce4134..4132c82c20 100644 --- a/examples/catalog/catalog_rhel.json +++ b/examples/catalog/catalog_rhel.json @@ -7,258 +7,257 @@ { "Name": "login_compiler_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "login_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "os_x86_64", "FunctionalPackages": [ - "openssl-libs_na_rpm", - "ovis-ldms_na_rpm", - "python3-cython_na_rpm", - "python3-devel_na_rpm" + "openssl-libs", + "ovis-ldms", + "python3-cython", + "python3-devel" ] }, { "Name": "service_kube_control_plane_x86_64", "FunctionalPackages": [ - "PyMySQL_1.1.2_pip_module", - "apptainer_na_rpm", - "calico-v3-31-4_na_manifest", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-calico-cni_v3.31.4_image", - "docker-io-calico-kube-controllers_v3.31.4_image", - "docker-io-calico-node_v3.31.4_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-kube-vip-kube-vip_v0.8.9_image", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "helm-v3-20-1-amd64_na_tarball", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubectl_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "metallb-native-v0-15-3_na_manifest", - "nfs-subdir-external-provisioner-4-0-18_na_tarball", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prettytable_3.14.0_pip_module", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "python3_3.12.9_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-coredns-coredns_v1.13.1_image", - "registry-k8s-io-etcd_3.6.6-0_image", - "registry-k8s-io-kube-apiserver_v1.35.1_image", - "registry-k8s-io-kube-controller-manager_v1.35.1_image", - "registry-k8s-io-kube-proxy_v1.35.1_image", - "registry-k8s-io-kube-scheduler_v1.35.1_image", - "registry-k8s-io-pause_3.10.1_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "PyMySQL", + "apptainer", + "calico", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/calico/cni", + "docker.io/calico/kube-controllers", + "docker.io/calico/node", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/kube-vip/kube-vip", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-amd64", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubectl", + "kubelet", + "kubernetes", + "lsscsi", + "metallb-native", + "nfs-subdir-external-provisioner", + "omsdk", + "podman", + "prettytable", + "prometheus_client", + "python3", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/coredns/coredns", + "registry.k8s.io/etcd", + "registry.k8s.io/kube-apiserver", + "registry.k8s.io/kube-controller-manager", + "registry.k8s.io/kube-proxy", + "registry.k8s.io/kube-scheduler", + "registry.k8s.io/pause", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "service_kube_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-controller_v0.15.3_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "apptainer", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubelet", + "kubernetes", + "lsscsi", + "omsdk", + "podman", + "prometheus_client", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/controller", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "slurm_control_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "mariadb-server_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-PyMySQL_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmctld_na_rpm", - "slurm-slurmdbd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "mariadb-server", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-PyMySQL", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-slurmctld", + "slurm-slurmdbd" ] }, { "Name": "slurm_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "kernel-devel_na_rpm", - "kernel-headers_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-pam_slurm_na_rpm", - "slurm-slurmd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "kernel-devel", + "kernel-headers", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-pam_slurm", + "slurm-slurmd" ] } ], @@ -267,106 +266,106 @@ "Name": "RHEL", "Version": "10.0", "osPackages": [ - "NetworkManager_na_rpm", - "authselect_na_rpm", - "autoconf_na_rpm", - "automake_na_rpm", - "bash-completion_na_rpm", - "bash_na_rpm", - "binutils-devel_na_rpm", - "binutils_na_rpm", - "bzip2_na_rpm", - "chrony_na_rpm", - "cloud-init_na_rpm", - "clustershell_na_rpm", - "cmake_na_rpm", - "coreutils_na_rpm", - "cryptsetup_na_rpm", - "curl_na_rpm", - "device-mapper_na_rpm", - "dmidecode_na_rpm", - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image", - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image", - "dracut-live_na_rpm", - "dracut-network_na_rpm", - "dracut_na_rpm", - "emacs_na_rpm", - "file_na_rpm", - "findutils_na_rpm", - "fping_na_rpm", - "gawk_na_rpm", - "gcc-c++_na_rpm", - "gcc-gfortran_na_rpm", - "gcc_na_rpm", - "gdb-gdbserver_na_rpm", - "gdb_na_rpm", - "gedit_na_rpm", - "glibc-langpack-en_na_rpm", - "grep_na_rpm", - "gzip_na_rpm", - "hwloc-libs_na_rpm", - "hwloc_na_rpm", - "iperf3_na_rpm", - "ipmitool_na_rpm", - "iproute_na_rpm", - "iputils_na_rpm", - "kbd_na_rpm", - "kernel-tools_na_rpm", - "kernel_na_rpm", - "kexec-tools_na_rpm", - "libcurl_na_rpm", - "libtool_na_rpm", - "lldb-devel_na_rpm", - "lldb_na_rpm", - "lshw_na_rpm", - "lsof_na_rpm", - "ltrace_na_rpm", - "lvm2_na_rpm", - "make_na_rpm", - "man-db_na_rpm", - "man-pages_na_rpm", - "munge-devel_na_rpm", - "nfs-utils_na_rpm", - "nfs4-acl-tools_na_rpm", - "nm-connection-editor_na_rpm", - "nss-pam-ldapd_na_rpm", - "oddjob-mkhomedir_na_rpm", - "openldap-clients_na_rpm", - "openmpi_5.0.8_tarball", - "openssh-clients_na_rpm", - "openssh-server_na_rpm", - "openssh_na_rpm", - "openssl-devel_na_rpm", - "openssl-libs_na_rpm_1", - "ovis-ldms_na_rpm_1", - "papi-devel_na_rpm", - "papi-libs_na_rpm", - "papi_na_rpm", - "pciutils_na_rpm", - "perf_na_rpm", - "pmix-devel_na_rpm", - "python3-cython_na_rpm_1", - "python3-devel_na_rpm_1", - "rsync_na_rpm", - "rsyslog_na_rpm", - "sed_na_rpm", - "squashfs-tools_na_rpm", - "sssd_na_rpm", - "strace_na_rpm", - "sudo_na_rpm", - "systemd-udev_na_rpm", - "systemd_na_rpm", - "tar_na_rpm", - "tcpdump_na_rpm", - "traceroute_na_rpm", - "ucx_1.19.0_tarball", - "util-linux_na_rpm", - "valgrind-devel_na_rpm", - "valgrind_na_rpm", - "vim-enhanced_na_rpm_1", - "wget_na_rpm", - "which_na_rpm", - "zsh_na_rpm" + "NetworkManager", + "authselect", + "autoconf", + "automake", + "bash", + "bash-completion", + "binutils", + "binutils-devel", + "bzip2", + "chrony", + "cloud-init", + "clustershell", + "cmake", + "coreutils", + "cryptsetup", + "curl", + "device-mapper", + "dmidecode", + "docker.io/dellhpcomniaaisolution/image-build-aarch64", + "docker.io/dellhpcomniaaisolution/image-build-el10", + "dracut", + "dracut-live", + "dracut-network", + "emacs", + "file", + "findutils", + "fping", + "gawk", + "gcc", + "gcc-c++", + "gcc-gfortran", + "gdb", + "gdb-gdbserver", + "gedit", + "glibc-langpack-en", + "grep", + "gzip", + "hwloc", + "hwloc-libs", + "iperf3", + "ipmitool", + "iproute", + "iputils", + "kbd", + "kernel", + "kernel-tools", + "kexec-tools", + "libcurl", + "libtool", + "lldb", + "lldb-devel", + "lshw", + "lsof", + "ltrace", + "lvm2", + "make", + "man-db", + "man-pages", + "munge-devel", + "nfs-utils", + "nfs4-acl-tools", + "nm-connection-editor", + "nss-pam-ldapd", + "oddjob-mkhomedir", + "openldap-clients", + "openmpi", + "openssh", + "openssh-clients", + "openssh-server", + "openssl-devel", + "openssl-libs_1", + "ovis-ldms_1", + "papi-devel", + "papi-libs", + "papi_1", + "pciutils", + "perf", + "pmix-devel", + "python3-cython_1", + "python3-devel_1", + "rsync", + "rsyslog", + "sed", + "squashfs-tools", + "sssd", + "strace", + "sudo", + "systemd", + "systemd-udev", + "tar", + "tcpdump", + "traceroute", + "ucx", + "util-linux", + "valgrind", + "valgrind-devel", + "vim-enhanced_1", + "wget", + "which", + "zsh" ] } ], @@ -374,29 +373,29 @@ { "Name": "csi", "InfrastructurePackages": [ - "csi-powerscale-v2-16-0_v2.16.0_git", - "docker-io-dellemc-csm-encryption_v0.6.0_image", - "external-snapshotter-v8-4-0_v8.4.0_git", - "helm-charts-2-16-0_csi-isilon-2.16.0_git", - "quay-io-dell-container-storage-modules-csi-isilon_v2.16.0_image", - "quay-io-dell-container-storage-modules-csi-metadat_v1.13.0_image", - "quay-io-dell-container-storage-modules-csm-authori_v2.4.0_image", - "quay-io-dell-container-storage-modules-dell-csi-re_v1.14.0_image", - "quay-io-dell-container-storage-modules-podmon_v1.15.0_image", - "registry-k8s-io-sig-storage-csi-attacher_v4.10.0_image", - "registry-k8s-io-sig-storage-csi-external-health-mo_v0.16.0_image", - "registry-k8s-io-sig-storage-csi-node-driver-regist_v2.15.0_image", - "registry-k8s-io-sig-storage-csi-provisioner_v6.1.0_image", - "registry-k8s-io-sig-storage-csi-resizer_v2.0.0_image", - "registry-k8s-io-sig-storage-csi-snapshotter_v8.4.0_image", - "registry-k8s-io-sig-storage-snapshot-controller_v8.4.0_image" + "csi-powerscale", + "docker.io/dellemc/csm-encryption", + "external-snapshotter", + "helm-charts_1", + "quay.io/dell/container-storage-modules/csi-isilon", + "quay.io/dell/container-storage-modules/csi-metadata-retriever", + "quay.io/dell/container-storage-modules/csm-authorization-sidecar", + "quay.io/dell/container-storage-modules/dell-csi-replicator", + "quay.io/dell/container-storage-modules/podmon", + "registry.k8s.io/sig-storage/csi-attacher", + "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", + "registry.k8s.io/sig-storage/csi-node-driver-registrar", + "registry.k8s.io/sig-storage/csi-provisioner", + "registry.k8s.io/sig-storage/csi-resizer", + "registry.k8s.io/sig-storage/csi-snapshotter", + "registry.k8s.io/sig-storage/snapshot-controller" ] } ], "Drivers": [], "DriverPackages": {}, "FunctionalPackages": { - "PyMySQL_1.1.2_pip_module": { + "PyMySQL": { "Name": "PyMySQL==1.1.2", "SupportedOS": [ { @@ -409,7 +408,7 @@ ], "Type": "pip_module" }, - "apptainer_na_rpm": { + "apptainer": { "Name": "apptainer", "SupportedOS": [ { @@ -433,7 +432,7 @@ } ] }, - "calico-v3-31-4_na_manifest": { + "calico": { "Name": "calico-v3.31.4", "SupportedOS": [ { @@ -452,7 +451,7 @@ } ] }, - "cert-manager-v1-10-0_na_tarball": { + "cert-manager": { "Name": "cert-manager-v1.10.0", "SupportedOS": [ { @@ -471,7 +470,7 @@ } ] }, - "cffi_1.17.1_pip_module": { + "cffi": { "Name": "cffi==1.17.1", "SupportedOS": [ { @@ -484,7 +483,7 @@ ], "Type": "pip_module" }, - "container-selinux_na_rpm": { + "container-selinux": { "Name": "container-selinux", "SupportedOS": [ { @@ -503,7 +502,7 @@ } ] }, - "cri-o_1.35.1_rpm": { + "cri-o": { "Name": "cri-o-1.35.1", "SupportedOS": [ { @@ -522,7 +521,7 @@ } ] }, - "cryptography_45.0.7_pip_module": { + "cryptography": { "Name": "cryptography==45.0.7", "SupportedOS": [ { @@ -535,7 +534,7 @@ ], "Type": "pip_module" }, - "device-mapper-multipath_na_rpm": { + "device-mapper-multipath": { "Name": "device-mapper-multipath", "SupportedOS": [ { @@ -559,7 +558,7 @@ } ] }, - "doca-ofed_na_rpm_repo": { + "doca-ofed": { "Name": "doca-ofed", "SupportedOS": [ { @@ -583,7 +582,7 @@ } ] }, - "docker-io-alpine-kubectl_1.35.1_image": { + "docker.io/alpine/kubectl": { "Name": "docker.io/alpine/kubectl", "SupportedOS": [ { @@ -598,7 +597,7 @@ "Tag": "1.35.1", "Version": "1.35.1" }, - "docker-io-calico-cni_v3.31.4_image": { + "docker.io/calico/cni": { "Name": "docker.io/calico/cni", "SupportedOS": [ { @@ -613,7 +612,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-kube-controllers_v3.31.4_image": { + "docker.io/calico/kube-controllers": { "Name": "docker.io/calico/kube-controllers", "SupportedOS": [ { @@ -628,7 +627,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-node_v3.31.4_image": { + "docker.io/calico/node": { "Name": "docker.io/calico/node", "SupportedOS": [ { @@ -643,7 +642,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-curlimages-curl_8.17.0_image": { + "docker.io/curlimages/curl": { "Name": "docker.io/curlimages/curl", "SupportedOS": [ { @@ -658,7 +657,7 @@ "Tag": "8.17.0", "Version": "8.17.0" }, - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image": { + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver": { "Name": "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", "SupportedOS": [ { @@ -673,7 +672,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/kafkapump": { "Name": "docker.io/dellhpcomniaaisolution/kafkapump", "SupportedOS": [ { @@ -688,7 +687,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image": { + "docker.io/dellhpcomniaaisolution/ubuntu-ldms": { "Name": "docker.io/dellhpcomniaaisolution/ubuntu-ldms", "SupportedOS": [ { @@ -703,7 +702,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/victoriapump": { "Name": "docker.io/dellhpcomniaaisolution/victoriapump", "SupportedOS": [ { @@ -718,7 +717,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-library-busybox_1.36_image": { + "docker.io/library/busybox": { "Name": "docker.io/library/busybox", "SupportedOS": [ { @@ -733,7 +732,7 @@ "Tag": "1.36", "Version": "1.36" }, - "docker-io-library-mysql_9.3.0_image": { + "docker.io/library/mysql": { "Name": "docker.io/library/mysql", "SupportedOS": [ { @@ -748,7 +747,7 @@ "Tag": "9.3.0", "Version": "9.3.0" }, - "docker-io-library-python_3.12-slim_image": { + "docker.io/library/python": { "Name": "docker.io/library/python", "SupportedOS": [ { @@ -763,7 +762,7 @@ "Tag": "3.12-slim", "Version": "3.12-slim" }, - "docker-io-nginxinc-nginx-unprivileged_1.29_image": { + "docker.io/nginxinc/nginx-unprivileged": { "Name": "docker.io/nginxinc/nginx-unprivileged", "SupportedOS": [ { @@ -778,7 +777,7 @@ "Tag": "1.29", "Version": "1.29" }, - "docker-io-rmohr-activemq_5.15.9_image": { + "docker.io/rmohr/activemq": { "Name": "docker.io/rmohr/activemq", "SupportedOS": [ { @@ -793,7 +792,7 @@ "Tag": "5.15.9", "Version": "5.15.9" }, - "docker-io-timberio-vector_0.54.0-debian_image": { + "docker.io/timberio/vector": { "Name": "docker.io/timberio/vector", "SupportedOS": [ { @@ -808,7 +807,7 @@ "Tag": "0.54.0-debian", "Version": "0.54.0-debian" }, - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image": { + "docker.io/victoriametrics/operator": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -820,10 +819,10 @@ "x86_64" ], "Type": "image", - "Tag": "config-reloader-v0.68.3", - "Version": "config-reloader-v0.68.3" + "Tag": "v0.68.3", + "Version": "v0.68.3" }, - "docker-io-victoriametrics-operator_v0.68.3_image": { + "docker.io/victoriametrics/operator_1": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -835,10 +834,10 @@ "x86_64" ], "Type": "image", - "Tag": "v0.68.3", - "Version": "v0.68.3" + "Tag": "config-reloader-v0.68.3", + "Version": "config-reloader-v0.68.3" }, - "docker-io-victoriametrics-victoria-logs_v1.50.0_image": { + "docker.io/victoriametrics/victoria-logs": { "Name": "docker.io/victoriametrics/victoria-logs", "SupportedOS": [ { @@ -853,7 +852,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image": { + "docker.io/victoriametrics/victoria-metrics": { "Name": "docker.io/victoriametrics/victoria-metrics", "SupportedOS": [ { @@ -868,7 +867,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vlagent_v1.50.0_image": { + "docker.io/victoriametrics/vlagent": { "Name": "docker.io/victoriametrics/vlagent", "SupportedOS": [ { @@ -883,7 +882,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-vmagent_v1.128.0_image": { + "docker.io/victoriametrics/vmagent": { "Name": "docker.io/victoriametrics/vmagent", "SupportedOS": [ { @@ -898,7 +897,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vminsert": { "Name": "docker.io/victoriametrics/vminsert", "SupportedOS": [ { @@ -913,7 +912,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmselect": { "Name": "docker.io/victoriametrics/vmselect", "SupportedOS": [ { @@ -928,7 +927,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmstorage": { "Name": "docker.io/victoriametrics/vmstorage", "SupportedOS": [ { @@ -943,7 +942,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "firewalld_na_rpm": { + "firewalld": { "Name": "firewalld", "SupportedOS": [ { @@ -967,7 +966,7 @@ } ] }, - "fuse-overlayfs_na_rpm": { + "fuse-overlayfs": { "Name": "fuse-overlayfs", "SupportedOS": [ { @@ -986,7 +985,7 @@ } ] }, - "geopm_na_tarball": { + "geopm": { "Name": "geopm", "SupportedOS": [ { @@ -1010,7 +1009,7 @@ } ] }, - "ghcr-io-kube-vip-kube-vip_v0.8.9_image": { + "ghcr.io/kube-vip/kube-vip": { "Name": "ghcr.io/kube-vip/kube-vip", "SupportedOS": [ { @@ -1025,7 +1024,7 @@ "Tag": "v0.8.9", "Version": "v0.8.9" }, - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image": { + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector": { "Name": "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", "SupportedOS": [ { @@ -1040,7 +1039,7 @@ "Tag": "0.143.1", "Version": "0.143.1" }, - "git_na_rpm": { + "git": { "Name": "git", "SupportedOS": [ { @@ -1059,8 +1058,8 @@ } ] }, - "helm-charts_container-storage-modules-1.9.2_git": { - "Name": "helm-charts", + "helm-amd64": { + "Name": "helm-v3.20.1-amd64", "SupportedOS": [ { "Name": "RHEL", @@ -1070,17 +1069,16 @@ "Architecture": [ "x86_64" ], - "Type": "git", - "Version": "container-storage-modules-1.9.2", + "Type": "tarball", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://github.com/dell/helm-charts.git" + "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" } ] }, - "helm-v3-20-1-amd64_na_tarball": { - "Name": "helm-v3.20.1-amd64", + "helm-charts": { + "Name": "helm-charts", "SupportedOS": [ { "Name": "RHEL", @@ -1090,15 +1088,16 @@ "Architecture": [ "x86_64" ], - "Type": "tarball", + "Type": "git", + "Version": "container-storage-modules-1.9.2", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" + "Uri": "https://github.com/dell/helm-charts.git" } ] }, - "imb_na_tarball": { + "imb": { "Name": "imb", "SupportedOS": [ { @@ -1122,7 +1121,7 @@ } ] }, - "iscsi-initiator-utils_na_rpm": { + "iscsi-initiator-utils": { "Name": "iscsi-initiator-utils", "SupportedOS": [ { @@ -1146,7 +1145,7 @@ } ] }, - "karavi-observability_v1.12.0_git": { + "karavi-observability": { "Name": "karavi-observability", "SupportedOS": [ { @@ -1166,7 +1165,7 @@ } ] }, - "kernel-devel_na_rpm": { + "kernel-devel": { "Name": "kernel-devel", "SupportedOS": [ { @@ -1190,7 +1189,7 @@ } ] }, - "kernel-headers_na_rpm": { + "kernel-headers": { "Name": "kernel-headers", "SupportedOS": [ { @@ -1214,7 +1213,7 @@ } ] }, - "kubeadm_1.35.1_rpm": { + "kubeadm": { "Name": "kubeadm-1.35.1", "SupportedOS": [ { @@ -1233,7 +1232,7 @@ } ] }, - "kubectl_1.35.1_rpm": { + "kubectl": { "Name": "kubectl-1.35.1", "SupportedOS": [ { @@ -1252,7 +1251,7 @@ } ] }, - "kubelet_1.35.1_rpm": { + "kubelet": { "Name": "kubelet-1.35.1", "SupportedOS": [ { @@ -1271,7 +1270,7 @@ } ] }, - "kubernetes_33.1.0_pip_module": { + "kubernetes": { "Name": "kubernetes==33.1.0", "SupportedOS": [ { @@ -1284,7 +1283,7 @@ ], "Type": "pip_module" }, - "likwid_na_tarball": { + "likwid": { "Name": "likwid", "SupportedOS": [ { @@ -1308,7 +1307,7 @@ } ] }, - "lsscsi_na_rpm": { + "lsscsi": { "Name": "lsscsi", "SupportedOS": [ { @@ -1332,7 +1331,7 @@ } ] }, - "mariadb-server_na_rpm": { + "mariadb-server": { "Name": "mariadb-server", "SupportedOS": [ { @@ -1356,7 +1355,7 @@ } ] }, - "metallb-native-v0-15-3_na_manifest": { + "metallb-native": { "Name": "metallb-native-v0.15.3", "SupportedOS": [ { @@ -1375,7 +1374,7 @@ } ] }, - "msr-safe_na_tarball": { + "msr-safe": { "Name": "msr-safe", "SupportedOS": [ { @@ -1394,7 +1393,7 @@ } ] }, - "munge_na_rpm": { + "munge": { "Name": "munge", "SupportedOS": [ { @@ -1418,7 +1417,7 @@ } ] }, - "nfs-subdir-external-provisioner-4-0-18_na_tarball": { + "nfs-subdir-external-provisioner": { "Name": "nfs-subdir-external-provisioner-4.0.18", "SupportedOS": [ { @@ -1437,7 +1436,7 @@ } ] }, - "nvcr-io-nvidia-hpc-benchmarks_25.09_image": { + "nvcr.io/nvidia/hpc-benchmarks": { "Name": "nvcr.io/nvidia/hpc-benchmarks", "SupportedOS": [ { @@ -1453,45 +1452,7 @@ "Tag": "25.09", "Version": "25.09" }, - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_aarch64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "aarch64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "aarch64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_aarch64_cuda_13.0.tar.gz" - } - ] - }, - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "x86_64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "x86_64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } - ] - }, - "omsdk_1.2.518_pip_module": { + "omsdk": { "Name": "omsdk==1.2.518", "SupportedOS": [ { @@ -1504,7 +1465,7 @@ ], "Type": "pip_module" }, - "openssl-libs_na_rpm": { + "openssl-libs": { "Name": "openssl-libs", "SupportedOS": [ { @@ -1528,7 +1489,7 @@ } ] }, - "osu-micro-benchmarks_na_tarball": { + "osu-micro-benchmarks": { "Name": "osu-micro-benchmarks", "SupportedOS": [ { @@ -1552,7 +1513,7 @@ } ] }, - "ovis-ldms_na_rpm": { + "ovis-ldms": { "Name": "ovis-ldms", "SupportedOS": [ { @@ -1576,7 +1537,7 @@ } ] }, - "papi_na_tarball": { + "papi": { "Name": "papi", "SupportedOS": [ { @@ -1600,7 +1561,7 @@ } ] }, - "pmix_na_rpm": { + "pmix": { "Name": "pmix", "SupportedOS": [ { @@ -1624,7 +1585,7 @@ } ] }, - "podman_na_rpm": { + "podman": { "Name": "podman", "SupportedOS": [ { @@ -1643,7 +1604,7 @@ } ] }, - "prettytable_3.14.0_pip_module": { + "prettytable": { "Name": "prettytable==3.14.0", "SupportedOS": [ { @@ -1656,7 +1617,7 @@ ], "Type": "pip_module" }, - "prometheus_client_0.20.0_pip_module": { + "prometheus_client": { "Name": "prometheus_client==0.20.0", "SupportedOS": [ { @@ -1669,8 +1630,8 @@ ], "Type": "pip_module" }, - "python3-PyMySQL_na_rpm": { - "Name": "python3-PyMySQL", + "python3": { + "Name": "python3-3.12.9", "SupportedOS": [ { "Name": "RHEL", @@ -1678,23 +1639,18 @@ } ], "Architecture": [ - "aarch64", "x86_64" ], "Type": "rpm", "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" - }, - { - "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "python3-cython_na_rpm": { - "Name": "python3-cython", + "python3-PyMySQL": { + "Name": "python3-PyMySQL", "SupportedOS": [ { "Name": "RHEL", @@ -1709,16 +1665,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "codeready-builder" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "codeready-builder" + "RepoName": "appstream" } ] }, - "python3-devel_na_rpm": { - "Name": "python3-devel", + "python3-cython": { + "Name": "python3-cython", "SupportedOS": [ { "Name": "RHEL", @@ -1733,16 +1689,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "codeready-builder" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "codeready-builder" } ] }, - "python3-firewall_na_rpm": { - "Name": "python3-firewall", + "python3-devel": { + "Name": "python3-devel", "SupportedOS": [ { "Name": "RHEL", @@ -1757,16 +1713,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "python3_3.12.9_rpm": { - "Name": "python3-3.12.9", + "python3-firewall": { + "Name": "python3-firewall", "SupportedOS": [ { "Name": "RHEL", @@ -1774,6 +1730,7 @@ } ], "Architecture": [ + "aarch64", "x86_64" ], "Type": "rpm", @@ -1781,10 +1738,14 @@ { "Architecture": "x86_64", "RepoName": "baseos" + }, + { + "Architecture": "aarch64", + "RepoName": "baseos" } ] }, - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image": { + "quay.io/dell/container-storage-modules/csm-metrics-powerscale": { "Name": "quay.io/dell/container-storage-modules/csm-metrics-powerscale", "SupportedOS": [ { @@ -1799,7 +1760,7 @@ "Tag": "v1.11.0", "Version": "v1.11.0" }, - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image": { + "quay.io/jetstack/cert-manager-acmesolver": { "Name": "quay.io/jetstack/cert-manager-acmesolver", "SupportedOS": [ { @@ -1814,7 +1775,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image": { + "quay.io/jetstack/cert-manager-cainjector": { "Name": "quay.io/jetstack/cert-manager-cainjector", "SupportedOS": [ { @@ -1829,7 +1790,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-controller_v1.10.0_image": { + "quay.io/jetstack/cert-manager-controller": { "Name": "quay.io/jetstack/cert-manager-controller", "SupportedOS": [ { @@ -1844,7 +1805,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image": { + "quay.io/jetstack/cert-manager-webhook": { "Name": "quay.io/jetstack/cert-manager-webhook", "SupportedOS": [ { @@ -1859,7 +1820,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-metallb-controller_v0.15.3_image": { + "quay.io/metallb/controller": { "Name": "quay.io/metallb/controller", "SupportedOS": [ { @@ -1874,7 +1835,7 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-metallb-speaker_v0.15.3_image": { + "quay.io/metallb/speaker": { "Name": "quay.io/metallb/speaker", "SupportedOS": [ { @@ -1889,8 +1850,8 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-strimzi-kafka-bridge_0.33.1_image": { - "Name": "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/kafka": { + "Name": "quay.io/strimzi/kafka", "SupportedOS": [ { "Name": "RHEL", @@ -1901,11 +1862,11 @@ "x86_64" ], "Type": "image", - "Tag": "0.33.1", - "Version": "0.33.1" + "Tag": "0.48.0-kafka-4.1.0", + "Version": "0.48.0-kafka-4.1.0" }, - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image": { - "Name": "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge": { + "Name": "quay.io/strimzi/kafka-bridge", "SupportedOS": [ { "Name": "RHEL", @@ -1916,10 +1877,10 @@ "x86_64" ], "Type": "image", - "Tag": "0.48.0-kafka-4.1.0", - "Version": "0.48.0-kafka-4.1.0" + "Tag": "0.33.1", + "Version": "0.33.1" }, - "quay-io-strimzi-operator_0.48.0_image": { + "quay.io/strimzi/operator": { "Name": "quay.io/strimzi/operator", "SupportedOS": [ { @@ -1934,7 +1895,7 @@ "Tag": "0.48.0", "Version": "0.48.0" }, - "registry-k8s-io-coredns-coredns_v1.13.1_image": { + "registry.k8s.io/coredns/coredns": { "Name": "registry.k8s.io/coredns/coredns", "SupportedOS": [ { @@ -1949,7 +1910,7 @@ "Tag": "v1.13.1", "Version": "v1.13.1" }, - "registry-k8s-io-etcd_3.6.6-0_image": { + "registry.k8s.io/etcd": { "Name": "registry.k8s.io/etcd", "SupportedOS": [ { @@ -1964,7 +1925,7 @@ "Tag": "3.6.6-0", "Version": "3.6.6-0" }, - "registry-k8s-io-kube-apiserver_v1.35.1_image": { + "registry.k8s.io/kube-apiserver": { "Name": "registry.k8s.io/kube-apiserver", "SupportedOS": [ { @@ -1979,7 +1940,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-controller-manager_v1.35.1_image": { + "registry.k8s.io/kube-controller-manager": { "Name": "registry.k8s.io/kube-controller-manager", "SupportedOS": [ { @@ -1994,7 +1955,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-proxy_v1.35.1_image": { + "registry.k8s.io/kube-proxy": { "Name": "registry.k8s.io/kube-proxy", "SupportedOS": [ { @@ -2009,7 +1970,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-scheduler_v1.35.1_image": { + "registry.k8s.io/kube-scheduler": { "Name": "registry.k8s.io/kube-scheduler", "SupportedOS": [ { @@ -2024,7 +1985,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-pause_3.10.1_image": { + "registry.k8s.io/pause": { "Name": "registry.k8s.io/pause", "SupportedOS": [ { @@ -2039,7 +2000,7 @@ "Tag": "3.10.1", "Version": "3.10.1" }, - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image": { + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner": { "Name": "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", "SupportedOS": [ { @@ -2054,7 +2015,7 @@ "Tag": "v4.0.2", "Version": "v4.0.2" }, - "sg3_utils_na_rpm": { + "sg3_utils": { "Name": "sg3_utils", "SupportedOS": [ { @@ -2078,7 +2039,7 @@ } ] }, - "sionlib_na_tarball": { + "sionlib": { "Name": "sionlib", "SupportedOS": [ { @@ -2102,8 +2063,8 @@ } ] }, - "slurm-pam_slurm_na_rpm": { - "Name": "slurm-pam_slurm", + "slurm": { + "Name": "slurm", "SupportedOS": [ { "Name": "RHEL", @@ -2126,8 +2087,8 @@ } ] }, - "slurm-slurmctld_na_rpm": { - "Name": "slurm-slurmctld", + "slurm-pam_slurm": { + "Name": "slurm-pam_slurm", "SupportedOS": [ { "Name": "RHEL", @@ -2150,8 +2111,8 @@ } ] }, - "slurm-slurmd_na_rpm": { - "Name": "slurm-slurmd", + "slurm-slurmctld": { + "Name": "slurm-slurmctld", "SupportedOS": [ { "Name": "RHEL", @@ -2174,8 +2135,8 @@ } ] }, - "slurm-slurmdbd_na_rpm": { - "Name": "slurm-slurmdbd", + "slurm-slurmd": { + "Name": "slurm-slurmd", "SupportedOS": [ { "Name": "RHEL", @@ -2198,8 +2159,8 @@ } ] }, - "slurm_na_rpm": { - "Name": "slurm", + "slurm-slurmdbd": { + "Name": "slurm-slurmdbd", "SupportedOS": [ { "Name": "RHEL", @@ -2222,7 +2183,7 @@ } ] }, - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball": { + "strimzi-kafka-operator-helm-3-chart": { "Name": "strimzi-kafka-operator-helm-3-chart-0.48.0", "SupportedOS": [ { @@ -2241,7 +2202,7 @@ } ] }, - "victoria-metrics-operator-0-59-3_na_tarball": { + "victoria-metrics-operator": { "Name": "victoria-metrics-operator-0.59.3", "SupportedOS": [ { @@ -2260,7 +2221,7 @@ } ] }, - "vim-enhanced_na_rpm": { + "vim-enhanced": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -2286,7 +2247,7 @@ } }, "OSPackages": { - "NetworkManager_na_rpm": { + "NetworkManager": { "Name": "NetworkManager", "SupportedOS": [ { @@ -2310,7 +2271,7 @@ } ] }, - "authselect_na_rpm": { + "authselect": { "Name": "authselect", "SupportedOS": [ { @@ -2334,7 +2295,7 @@ } ] }, - "autoconf_na_rpm": { + "autoconf": { "Name": "autoconf", "SupportedOS": [ { @@ -2358,7 +2319,7 @@ } ] }, - "automake_na_rpm": { + "automake": { "Name": "automake", "SupportedOS": [ { @@ -2382,8 +2343,8 @@ } ] }, - "bash-completion_na_rpm": { - "Name": "bash-completion", + "bash": { + "Name": "bash", "SupportedOS": [ { "Name": "RHEL", @@ -2406,8 +2367,8 @@ } ] }, - "bash_na_rpm": { - "Name": "bash", + "bash-completion": { + "Name": "bash-completion", "SupportedOS": [ { "Name": "RHEL", @@ -2430,8 +2391,8 @@ } ] }, - "binutils-devel_na_rpm": { - "Name": "binutils-devel", + "binutils": { + "Name": "binutils", "SupportedOS": [ { "Name": "RHEL", @@ -2446,16 +2407,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "binutils_na_rpm": { - "Name": "binutils", + "binutils-devel": { + "Name": "binutils-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2470,15 +2431,15 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "bzip2_na_rpm": { + "bzip2": { "Name": "bzip2", "SupportedOS": [ { @@ -2502,7 +2463,7 @@ } ] }, - "chrony_na_rpm": { + "chrony": { "Name": "chrony", "SupportedOS": [ { @@ -2526,7 +2487,7 @@ } ] }, - "cloud-init_na_rpm": { + "cloud-init": { "Name": "cloud-init", "SupportedOS": [ { @@ -2550,7 +2511,7 @@ } ] }, - "clustershell_na_rpm": { + "clustershell": { "Name": "clustershell", "SupportedOS": [ { @@ -2574,7 +2535,7 @@ } ] }, - "cmake_na_rpm": { + "cmake": { "Name": "cmake", "SupportedOS": [ { @@ -2598,7 +2559,7 @@ } ] }, - "coreutils_na_rpm": { + "coreutils": { "Name": "coreutils", "SupportedOS": [ { @@ -2622,7 +2583,7 @@ } ] }, - "cryptsetup_na_rpm": { + "cryptsetup": { "Name": "cryptsetup", "SupportedOS": [ { @@ -2646,7 +2607,7 @@ } ] }, - "curl_na_rpm": { + "curl": { "Name": "curl", "SupportedOS": [ { @@ -2670,7 +2631,7 @@ } ] }, - "device-mapper_na_rpm": { + "device-mapper": { "Name": "device-mapper", "SupportedOS": [ { @@ -2694,7 +2655,7 @@ } ] }, - "dmidecode_na_rpm": { + "dmidecode": { "Name": "dmidecode", "SupportedOS": [ { @@ -2718,7 +2679,7 @@ } ] }, - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-aarch64": { "Name": "docker.io/dellhpcomniaaisolution/image-build-aarch64", "SupportedOS": [ { @@ -2733,7 +2694,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-el10": { "Name": "docker.io/dellhpcomniaaisolution/image-build-el10", "SupportedOS": [ { @@ -2748,8 +2709,8 @@ "Tag": "1.1", "Version": "1.1" }, - "dracut-live_na_rpm": { - "Name": "dracut-live", + "dracut": { + "Name": "dracut", "SupportedOS": [ { "Name": "RHEL", @@ -2764,16 +2725,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "dracut-network_na_rpm": { - "Name": "dracut-network", + "dracut-live": { + "Name": "dracut-live", "SupportedOS": [ { "Name": "RHEL", @@ -2788,16 +2749,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "dracut_na_rpm": { - "Name": "dracut", + "dracut-network": { + "Name": "dracut-network", "SupportedOS": [ { "Name": "RHEL", @@ -2820,7 +2781,7 @@ } ] }, - "emacs_na_rpm": { + "emacs": { "Name": "emacs", "SupportedOS": [ { @@ -2844,7 +2805,7 @@ } ] }, - "file_na_rpm": { + "file": { "Name": "file", "SupportedOS": [ { @@ -2868,7 +2829,7 @@ } ] }, - "findutils_na_rpm": { + "findutils": { "Name": "findutils", "SupportedOS": [ { @@ -2892,7 +2853,7 @@ } ] }, - "fping_na_rpm": { + "fping": { "Name": "fping", "SupportedOS": [ { @@ -2916,7 +2877,7 @@ } ] }, - "gawk_na_rpm": { + "gawk": { "Name": "gawk", "SupportedOS": [ { @@ -2940,8 +2901,8 @@ } ] }, - "gcc-c++_na_rpm": { - "Name": "gcc-c++", + "gcc": { + "Name": "gcc", "SupportedOS": [ { "Name": "RHEL", @@ -2964,8 +2925,8 @@ } ] }, - "gcc-gfortran_na_rpm": { - "Name": "gcc-gfortran", + "gcc-c++": { + "Name": "gcc-c++", "SupportedOS": [ { "Name": "RHEL", @@ -2988,8 +2949,8 @@ } ] }, - "gcc_na_rpm": { - "Name": "gcc", + "gcc-gfortran": { + "Name": "gcc-gfortran", "SupportedOS": [ { "Name": "RHEL", @@ -3012,8 +2973,8 @@ } ] }, - "gdb-gdbserver_na_rpm": { - "Name": "gdb-gdbserver", + "gdb": { + "Name": "gdb", "SupportedOS": [ { "Name": "RHEL", @@ -3036,8 +2997,8 @@ } ] }, - "gdb_na_rpm": { - "Name": "gdb", + "gdb-gdbserver": { + "Name": "gdb-gdbserver", "SupportedOS": [ { "Name": "RHEL", @@ -3060,7 +3021,7 @@ } ] }, - "gedit_na_rpm": { + "gedit": { "Name": "gedit", "SupportedOS": [ { @@ -3084,7 +3045,7 @@ } ] }, - "glibc-langpack-en_na_rpm": { + "glibc-langpack-en": { "Name": "glibc-langpack-en", "SupportedOS": [ { @@ -3108,7 +3069,7 @@ } ] }, - "grep_na_rpm": { + "grep": { "Name": "grep", "SupportedOS": [ { @@ -3132,7 +3093,7 @@ } ] }, - "gzip_na_rpm": { + "gzip": { "Name": "gzip", "SupportedOS": [ { @@ -3156,8 +3117,8 @@ } ] }, - "hwloc-libs_na_rpm": { - "Name": "hwloc-libs", + "hwloc": { + "Name": "hwloc", "SupportedOS": [ { "Name": "RHEL", @@ -3180,8 +3141,8 @@ } ] }, - "hwloc_na_rpm": { - "Name": "hwloc", + "hwloc-libs": { + "Name": "hwloc-libs", "SupportedOS": [ { "Name": "RHEL", @@ -3204,7 +3165,7 @@ } ] }, - "iperf3_na_rpm": { + "iperf3": { "Name": "iperf3", "SupportedOS": [ { @@ -3228,7 +3189,7 @@ } ] }, - "ipmitool_na_rpm": { + "ipmitool": { "Name": "ipmitool", "SupportedOS": [ { @@ -3252,7 +3213,7 @@ } ] }, - "iproute_na_rpm": { + "iproute": { "Name": "iproute", "SupportedOS": [ { @@ -3276,7 +3237,7 @@ } ] }, - "iputils_na_rpm": { + "iputils": { "Name": "iputils", "SupportedOS": [ { @@ -3300,7 +3261,7 @@ } ] }, - "kbd_na_rpm": { + "kbd": { "Name": "kbd", "SupportedOS": [ { @@ -3324,8 +3285,8 @@ } ] }, - "kernel-tools_na_rpm": { - "Name": "kernel-tools", + "kernel": { + "Name": "kernel", "SupportedOS": [ { "Name": "RHEL", @@ -3348,8 +3309,8 @@ } ] }, - "kernel_na_rpm": { - "Name": "kernel", + "kernel-tools": { + "Name": "kernel-tools", "SupportedOS": [ { "Name": "RHEL", @@ -3372,7 +3333,7 @@ } ] }, - "kexec-tools_na_rpm": { + "kexec-tools": { "Name": "kexec-tools", "SupportedOS": [ { @@ -3396,7 +3357,7 @@ } ] }, - "libcurl_na_rpm": { + "libcurl": { "Name": "libcurl", "SupportedOS": [ { @@ -3420,7 +3381,7 @@ } ] }, - "libtool_na_rpm": { + "libtool": { "Name": "libtool", "SupportedOS": [ { @@ -3444,8 +3405,8 @@ } ] }, - "lldb-devel_na_rpm": { - "Name": "lldb-devel", + "lldb": { + "Name": "lldb", "SupportedOS": [ { "Name": "RHEL", @@ -3468,8 +3429,8 @@ } ] }, - "lldb_na_rpm": { - "Name": "lldb", + "lldb-devel": { + "Name": "lldb-devel", "SupportedOS": [ { "Name": "RHEL", @@ -3492,7 +3453,7 @@ } ] }, - "lshw_na_rpm": { + "lshw": { "Name": "lshw", "SupportedOS": [ { @@ -3516,7 +3477,7 @@ } ] }, - "lsof_na_rpm": { + "lsof": { "Name": "lsof", "SupportedOS": [ { @@ -3540,7 +3501,7 @@ } ] }, - "ltrace_na_rpm": { + "ltrace": { "Name": "ltrace", "SupportedOS": [ { @@ -3564,7 +3525,7 @@ } ] }, - "lvm2_na_rpm": { + "lvm2": { "Name": "lvm2", "SupportedOS": [ { @@ -3588,7 +3549,7 @@ } ] }, - "make_na_rpm": { + "make": { "Name": "make", "SupportedOS": [ { @@ -3612,7 +3573,7 @@ } ] }, - "man-db_na_rpm": { + "man-db": { "Name": "man-db", "SupportedOS": [ { @@ -3636,7 +3597,7 @@ } ] }, - "man-pages_na_rpm": { + "man-pages": { "Name": "man-pages", "SupportedOS": [ { @@ -3660,7 +3621,7 @@ } ] }, - "munge-devel_na_rpm": { + "munge-devel": { "Name": "munge-devel", "SupportedOS": [ { @@ -3684,7 +3645,7 @@ } ] }, - "nfs-utils_na_rpm": { + "nfs-utils": { "Name": "nfs-utils", "SupportedOS": [ { @@ -3708,7 +3669,7 @@ } ] }, - "nfs4-acl-tools_na_rpm": { + "nfs4-acl-tools": { "Name": "nfs4-acl-tools", "SupportedOS": [ { @@ -3732,7 +3693,7 @@ } ] }, - "nm-connection-editor_na_rpm": { + "nm-connection-editor": { "Name": "nm-connection-editor", "SupportedOS": [ { @@ -3756,7 +3717,7 @@ } ] }, - "nss-pam-ldapd_na_rpm": { + "nss-pam-ldapd": { "Name": "nss-pam-ldapd", "SupportedOS": [ { @@ -3780,7 +3741,7 @@ } ] }, - "oddjob-mkhomedir_na_rpm": { + "oddjob-mkhomedir": { "Name": "oddjob-mkhomedir", "SupportedOS": [ { @@ -3804,7 +3765,7 @@ } ] }, - "openldap-clients_na_rpm": { + "openldap-clients": { "Name": "openldap-clients", "SupportedOS": [ { @@ -3828,7 +3789,7 @@ } ] }, - "openmpi_5.0.8_tarball": { + "openmpi": { "Name": "openmpi", "SupportedOS": [ { @@ -3853,8 +3814,8 @@ } ] }, - "openssh-clients_na_rpm": { - "Name": "openssh-clients", + "openssh": { + "Name": "openssh", "SupportedOS": [ { "Name": "RHEL", @@ -3877,8 +3838,8 @@ } ] }, - "openssh-server_na_rpm": { - "Name": "openssh-server", + "openssh-clients": { + "Name": "openssh-clients", "SupportedOS": [ { "Name": "RHEL", @@ -3901,8 +3862,8 @@ } ] }, - "openssh_na_rpm": { - "Name": "openssh", + "openssh-server": { + "Name": "openssh-server", "SupportedOS": [ { "Name": "RHEL", @@ -3925,7 +3886,7 @@ } ] }, - "openssl-devel_na_rpm": { + "openssl-devel": { "Name": "openssl-devel", "SupportedOS": [ { @@ -3949,7 +3910,7 @@ } ] }, - "openssl-libs_na_rpm_1": { + "openssl-libs_1": { "Name": "openssl-libs", "SupportedOS": [ { @@ -3973,7 +3934,7 @@ } ] }, - "ovis-ldms_na_rpm_1": { + "ovis-ldms_1": { "Name": "ovis-ldms", "SupportedOS": [ { @@ -3997,7 +3958,7 @@ } ] }, - "papi-devel_na_rpm": { + "papi-devel": { "Name": "papi-devel", "SupportedOS": [ { @@ -4021,7 +3982,7 @@ } ] }, - "papi-libs_na_rpm": { + "papi-libs": { "Name": "papi-libs", "SupportedOS": [ { @@ -4045,7 +4006,7 @@ } ] }, - "papi_na_rpm": { + "papi_1": { "Name": "papi", "SupportedOS": [ { @@ -4069,7 +4030,7 @@ } ] }, - "pciutils_na_rpm": { + "pciutils": { "Name": "pciutils", "SupportedOS": [ { @@ -4093,7 +4054,7 @@ } ] }, - "perf_na_rpm": { + "perf": { "Name": "perf", "SupportedOS": [ { @@ -4117,7 +4078,7 @@ } ] }, - "pmix-devel_na_rpm": { + "pmix-devel": { "Name": "pmix-devel", "SupportedOS": [ { @@ -4141,7 +4102,7 @@ } ] }, - "python3-cython_na_rpm_1": { + "python3-cython_1": { "Name": "python3-cython", "SupportedOS": [ { @@ -4165,7 +4126,7 @@ } ] }, - "python3-devel_na_rpm_1": { + "python3-devel_1": { "Name": "python3-devel", "SupportedOS": [ { @@ -4189,7 +4150,7 @@ } ] }, - "rsync_na_rpm": { + "rsync": { "Name": "rsync", "SupportedOS": [ { @@ -4213,7 +4174,7 @@ } ] }, - "rsyslog_na_rpm": { + "rsyslog": { "Name": "rsyslog", "SupportedOS": [ { @@ -4237,7 +4198,7 @@ } ] }, - "sed_na_rpm": { + "sed": { "Name": "sed", "SupportedOS": [ { @@ -4261,7 +4222,7 @@ } ] }, - "squashfs-tools_na_rpm": { + "squashfs-tools": { "Name": "squashfs-tools", "SupportedOS": [ { @@ -4285,7 +4246,7 @@ } ] }, - "sssd_na_rpm": { + "sssd": { "Name": "sssd", "SupportedOS": [ { @@ -4309,7 +4270,7 @@ } ] }, - "strace_na_rpm": { + "strace": { "Name": "strace", "SupportedOS": [ { @@ -4333,7 +4294,7 @@ } ] }, - "sudo_na_rpm": { + "sudo": { "Name": "sudo", "SupportedOS": [ { @@ -4357,8 +4318,8 @@ } ] }, - "systemd-udev_na_rpm": { - "Name": "systemd-udev", + "systemd": { + "Name": "systemd", "SupportedOS": [ { "Name": "RHEL", @@ -4381,8 +4342,8 @@ } ] }, - "systemd_na_rpm": { - "Name": "systemd", + "systemd-udev": { + "Name": "systemd-udev", "SupportedOS": [ { "Name": "RHEL", @@ -4405,7 +4366,7 @@ } ] }, - "tar_na_rpm": { + "tar": { "Name": "tar", "SupportedOS": [ { @@ -4429,7 +4390,7 @@ } ] }, - "tcpdump_na_rpm": { + "tcpdump": { "Name": "tcpdump", "SupportedOS": [ { @@ -4453,7 +4414,7 @@ } ] }, - "traceroute_na_rpm": { + "traceroute": { "Name": "traceroute", "SupportedOS": [ { @@ -4477,7 +4438,7 @@ } ] }, - "ucx_1.19.0_tarball": { + "ucx": { "Name": "ucx", "SupportedOS": [ { @@ -4502,7 +4463,7 @@ } ] }, - "util-linux_na_rpm": { + "util-linux": { "Name": "util-linux", "SupportedOS": [ { @@ -4526,8 +4487,8 @@ } ] }, - "valgrind-devel_na_rpm": { - "Name": "valgrind-devel", + "valgrind": { + "Name": "valgrind", "SupportedOS": [ { "Name": "RHEL", @@ -4550,8 +4511,8 @@ } ] }, - "valgrind_na_rpm": { - "Name": "valgrind", + "valgrind-devel": { + "Name": "valgrind-devel", "SupportedOS": [ { "Name": "RHEL", @@ -4574,7 +4535,7 @@ } ] }, - "vim-enhanced_na_rpm_1": { + "vim-enhanced_1": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -4598,7 +4559,7 @@ } ] }, - "wget_na_rpm": { + "wget": { "Name": "wget", "SupportedOS": [ { @@ -4622,7 +4583,7 @@ } ] }, - "which_na_rpm": { + "which": { "Name": "which", "SupportedOS": [ { @@ -4646,7 +4607,7 @@ } ] }, - "zsh_na_rpm": { + "zsh": { "Name": "zsh", "SupportedOS": [ { @@ -4673,7 +4634,7 @@ }, "Miscellaneous": [], "InfrastructurePackages": { - "csi-powerscale-v2-16-0_v2.16.0_git": { + "csi-powerscale": { "Name": "csi-powerscale-v2.16.0", "Type": "git", "Version": "v2.16.0", @@ -4692,7 +4653,7 @@ } ] }, - "docker-io-dellemc-csm-encryption_v0.6.0_image": { + "docker.io/dellemc/csm-encryption": { "Name": "docker.io/dellemc/csm-encryption", "Type": "image", "Version": "v0.6.0", @@ -4706,7 +4667,7 @@ ], "Tag": "v0.6.0" }, - "external-snapshotter-v8-4-0_v8.4.0_git": { + "external-snapshotter": { "Name": "external-snapshotter-v8.4.0", "Type": "git", "Version": "v8.4.0", @@ -4725,7 +4686,7 @@ } ] }, - "helm-charts-2-16-0_csi-isilon-2.16.0_git": { + "helm-charts_1": { "Name": "helm-charts-2.16.0", "Type": "git", "Version": "csi-isilon-2.16.0", @@ -4744,7 +4705,7 @@ } ] }, - "quay-io-dell-container-storage-modules-csi-isilon_v2.16.0_image": { + "quay.io/dell/container-storage-modules/csi-isilon": { "Name": "quay.io/dell/container-storage-modules/csi-isilon", "Type": "image", "Version": "v2.16.0", @@ -4758,7 +4719,7 @@ ], "Tag": "v2.16.0" }, - "quay-io-dell-container-storage-modules-csi-metadat_v1.13.0_image": { + "quay.io/dell/container-storage-modules/csi-metadata-retriever": { "Name": "quay.io/dell/container-storage-modules/csi-metadata-retriever", "Type": "image", "Version": "v1.13.0", @@ -4772,7 +4733,7 @@ ], "Tag": "v1.13.0" }, - "quay-io-dell-container-storage-modules-csm-authori_v2.4.0_image": { + "quay.io/dell/container-storage-modules/csm-authorization-sidecar": { "Name": "quay.io/dell/container-storage-modules/csm-authorization-sidecar", "Type": "image", "Version": "v2.4.0", @@ -4786,7 +4747,7 @@ ], "Tag": "v2.4.0" }, - "quay-io-dell-container-storage-modules-dell-csi-re_v1.14.0_image": { + "quay.io/dell/container-storage-modules/dell-csi-replicator": { "Name": "quay.io/dell/container-storage-modules/dell-csi-replicator", "Type": "image", "Version": "v1.14.0", @@ -4800,7 +4761,7 @@ ], "Tag": "v1.14.0" }, - "quay-io-dell-container-storage-modules-podmon_v1.15.0_image": { + "quay.io/dell/container-storage-modules/podmon": { "Name": "quay.io/dell/container-storage-modules/podmon", "Type": "image", "Version": "v1.15.0", @@ -4814,7 +4775,7 @@ ], "Tag": "v1.15.0" }, - "registry-k8s-io-sig-storage-csi-attacher_v4.10.0_image": { + "registry.k8s.io/sig-storage/csi-attacher": { "Name": "registry.k8s.io/sig-storage/csi-attacher", "Type": "image", "Version": "v4.10.0", @@ -4828,7 +4789,7 @@ ], "Tag": "v4.10.0" }, - "registry-k8s-io-sig-storage-csi-external-health-mo_v0.16.0_image": { + "registry.k8s.io/sig-storage/csi-external-health-monitor-controller": { "Name": "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", "Type": "image", "Version": "v0.16.0", @@ -4842,7 +4803,7 @@ ], "Tag": "v0.16.0" }, - "registry-k8s-io-sig-storage-csi-node-driver-regist_v2.15.0_image": { + "registry.k8s.io/sig-storage/csi-node-driver-registrar": { "Name": "registry.k8s.io/sig-storage/csi-node-driver-registrar", "Type": "image", "Version": "v2.15.0", @@ -4856,7 +4817,7 @@ ], "Tag": "v2.15.0" }, - "registry-k8s-io-sig-storage-csi-provisioner_v6.1.0_image": { + "registry.k8s.io/sig-storage/csi-provisioner": { "Name": "registry.k8s.io/sig-storage/csi-provisioner", "Type": "image", "Version": "v6.1.0", @@ -4870,7 +4831,7 @@ ], "Tag": "v6.1.0" }, - "registry-k8s-io-sig-storage-csi-resizer_v2.0.0_image": { + "registry.k8s.io/sig-storage/csi-resizer": { "Name": "registry.k8s.io/sig-storage/csi-resizer", "Type": "image", "Version": "v2.0.0", @@ -4884,7 +4845,7 @@ ], "Tag": "v2.0.0" }, - "registry-k8s-io-sig-storage-csi-snapshotter_v8.4.0_image": { + "registry.k8s.io/sig-storage/csi-snapshotter": { "Name": "registry.k8s.io/sig-storage/csi-snapshotter", "Type": "image", "Version": "v8.4.0", @@ -4898,7 +4859,7 @@ ], "Tag": "v8.4.0" }, - "registry-k8s-io-sig-storage-snapshot-controller_v8.4.0_image": { + "registry.k8s.io/sig-storage/snapshot-controller": { "Name": "registry.k8s.io/sig-storage/snapshot-controller", "Type": "image", "Version": "v8.4.0", diff --git a/examples/catalog/catalog_rhel_aarch64_with_slurm_only.json b/examples/catalog/catalog_rhel_aarch64_with_slurm_only.json index 570caa686d..9dc880c004 100644 --- a/examples/catalog/catalog_rhel_aarch64_with_slurm_only.json +++ b/examples/catalog/catalog_rhel_aarch64_with_slurm_only.json @@ -7,104 +7,103 @@ { "Name": "login_compiler_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "login_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "slurm_control_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "mariadb-server_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-PyMySQL_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmctld_na_rpm", - "slurm-slurmdbd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "mariadb-server", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-PyMySQL", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-slurmctld", + "slurm-slurmdbd" ] }, { "Name": "slurm_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "kernel-devel_na_rpm", - "kernel-headers_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-pam_slurm_na_rpm", - "slurm-slurmd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "kernel-devel", + "kernel-headers", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-pam_slurm", + "slurm-slurmd" ] } ], @@ -113,98 +112,98 @@ "Name": "RHEL", "Version": "10.0", "osPackages": [ - "NetworkManager_na_rpm", - "authselect_na_rpm", - "autoconf_na_rpm", - "automake_na_rpm", - "bash-completion_na_rpm", - "bash_na_rpm", - "binutils-devel_na_rpm", - "binutils_na_rpm", - "bzip2_na_rpm", - "chrony_na_rpm", - "cloud-init_na_rpm", - "clustershell_na_rpm", - "cmake_na_rpm", - "coreutils_na_rpm", - "cryptsetup_na_rpm", - "curl_na_rpm", - "device-mapper_na_rpm", - "dmidecode_na_rpm", - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image", - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image", - "dracut-live_na_rpm", - "dracut-network_na_rpm", - "dracut_na_rpm", - "emacs_na_rpm", - "file_na_rpm", - "findutils_na_rpm", - "fping_na_rpm", - "gawk_na_rpm", - "gcc-c++_na_rpm", - "gcc-gfortran_na_rpm", - "gcc_na_rpm", - "gdb-gdbserver_na_rpm", - "gdb_na_rpm", - "gedit_na_rpm", - "glibc-langpack-en_na_rpm", - "grep_na_rpm", - "gzip_na_rpm", - "hwloc-libs_na_rpm", - "hwloc_na_rpm", - "iperf3_na_rpm", - "ipmitool_na_rpm", - "iproute_na_rpm", - "iputils_na_rpm", - "kbd_na_rpm", - "kernel-tools_na_rpm", - "kernel_na_rpm", - "kexec-tools_na_rpm", - "libcurl_na_rpm", - "libtool_na_rpm", - "lldb-devel_na_rpm", - "lldb_na_rpm", - "lshw_na_rpm", - "lsof_na_rpm", - "ltrace_na_rpm", - "lvm2_na_rpm", - "make_na_rpm", - "man-db_na_rpm", - "man-pages_na_rpm", - "nfs-utils_na_rpm", - "nfs4-acl-tools_na_rpm", - "nm-connection-editor_na_rpm", - "nss-pam-ldapd_na_rpm", - "oddjob-mkhomedir_na_rpm", - "openldap-clients_na_rpm", - "openssh-clients_na_rpm", - "openssh-server_na_rpm", - "openssh_na_rpm", - "openssl-devel_na_rpm", - "papi-devel_na_rpm", - "papi-libs_na_rpm", - "papi_na_rpm", - "pciutils_na_rpm", - "perf_na_rpm", - "rsync_na_rpm", - "rsyslog_na_rpm", - "sed_na_rpm", - "squashfs-tools_na_rpm", - "sssd_na_rpm", - "strace_na_rpm", - "sudo_na_rpm", - "systemd-udev_na_rpm", - "systemd_na_rpm", - "tar_na_rpm", - "tcpdump_na_rpm", - "traceroute_na_rpm", - "util-linux_na_rpm", - "valgrind-devel_na_rpm", - "valgrind_na_rpm", - "vim-enhanced_na_rpm", - "wget_na_rpm", - "which_na_rpm", - "zsh_na_rpm" + "NetworkManager", + "authselect", + "autoconf", + "automake", + "bash", + "bash-completion", + "binutils", + "binutils-devel", + "bzip2", + "chrony", + "cloud-init", + "clustershell", + "cmake", + "coreutils", + "cryptsetup", + "curl", + "device-mapper", + "dmidecode", + "docker.io/dellhpcomniaaisolution/image-build-aarch64", + "docker.io/dellhpcomniaaisolution/image-build-el10", + "dracut", + "dracut-live", + "dracut-network", + "emacs", + "file", + "findutils", + "fping", + "gawk", + "gcc", + "gcc-c++", + "gcc-gfortran", + "gdb", + "gdb-gdbserver", + "gedit", + "glibc-langpack-en", + "grep", + "gzip", + "hwloc", + "hwloc-libs", + "iperf3", + "ipmitool", + "iproute", + "iputils", + "kbd", + "kernel", + "kernel-tools", + "kexec-tools", + "libcurl", + "libtool", + "lldb", + "lldb-devel", + "lshw", + "lsof", + "ltrace", + "lvm2", + "make", + "man-db", + "man-pages", + "nfs-utils", + "nfs4-acl-tools", + "nm-connection-editor", + "nss-pam-ldapd", + "oddjob-mkhomedir", + "openldap-clients", + "openssh", + "openssh-clients", + "openssh-server", + "openssl-devel", + "papi-devel", + "papi-libs", + "papi_1", + "pciutils", + "perf", + "rsync", + "rsyslog", + "sed", + "squashfs-tools", + "sssd", + "strace", + "sudo", + "systemd", + "systemd-udev", + "tar", + "tcpdump", + "traceroute", + "util-linux", + "valgrind", + "valgrind-devel", + "vim-enhanced", + "wget", + "which", + "zsh" ] } ], @@ -212,7 +211,7 @@ "Drivers": [], "DriverPackages": {}, "FunctionalPackages": { - "apptainer_na_rpm": { + "apptainer": { "Name": "apptainer", "SupportedOS": [ { @@ -236,7 +235,7 @@ } ] }, - "device-mapper-multipath_na_rpm": { + "device-mapper-multipath": { "Name": "device-mapper-multipath", "SupportedOS": [ { @@ -260,7 +259,7 @@ } ] }, - "doca-ofed_na_rpm_repo": { + "doca-ofed": { "Name": "doca-ofed", "SupportedOS": [ { @@ -284,7 +283,7 @@ } ] }, - "firewalld_na_rpm": { + "firewalld": { "Name": "firewalld", "SupportedOS": [ { @@ -308,7 +307,7 @@ } ] }, - "geopm_na_tarball": { + "geopm": { "Name": "geopm", "SupportedOS": [ { @@ -332,7 +331,7 @@ } ] }, - "imb_na_tarball": { + "imb": { "Name": "imb", "SupportedOS": [ { @@ -356,7 +355,7 @@ } ] }, - "iscsi-initiator-utils_na_rpm": { + "iscsi-initiator-utils": { "Name": "iscsi-initiator-utils", "SupportedOS": [ { @@ -380,7 +379,7 @@ } ] }, - "kernel-devel_na_rpm": { + "kernel-devel": { "Name": "kernel-devel", "SupportedOS": [ { @@ -404,7 +403,7 @@ } ] }, - "kernel-headers_na_rpm": { + "kernel-headers": { "Name": "kernel-headers", "SupportedOS": [ { @@ -428,7 +427,7 @@ } ] }, - "likwid_na_tarball": { + "likwid": { "Name": "likwid", "SupportedOS": [ { @@ -452,7 +451,7 @@ } ] }, - "lsscsi_na_rpm": { + "lsscsi": { "Name": "lsscsi", "SupportedOS": [ { @@ -476,7 +475,7 @@ } ] }, - "mariadb-server_na_rpm": { + "mariadb-server": { "Name": "mariadb-server", "SupportedOS": [ { @@ -500,7 +499,7 @@ } ] }, - "msr-safe_na_tarball": { + "msr-safe": { "Name": "msr-safe", "SupportedOS": [ { @@ -519,7 +518,7 @@ } ] }, - "munge_na_rpm": { + "munge": { "Name": "munge", "SupportedOS": [ { @@ -543,7 +542,7 @@ } ] }, - "nvcr-io-nvidia-hpc-benchmarks_25.09_image": { + "nvcr.io/nvidia/hpc-benchmarks": { "Name": "nvcr.io/nvidia/hpc-benchmarks", "SupportedOS": [ { @@ -559,45 +558,7 @@ "Tag": "25.09", "Version": "25.09" }, - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_aarch64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "aarch64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "aarch64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_aarch64_cuda_13.0.tar.gz" - } - ] - }, - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "x86_64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "x86_64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } - ] - }, - "osu-micro-benchmarks_na_tarball": { + "osu-micro-benchmarks": { "Name": "osu-micro-benchmarks", "SupportedOS": [ { @@ -621,7 +582,7 @@ } ] }, - "papi_na_tarball": { + "papi": { "Name": "papi", "SupportedOS": [ { @@ -645,7 +606,7 @@ } ] }, - "pmix_na_rpm": { + "pmix": { "Name": "pmix", "SupportedOS": [ { @@ -669,7 +630,7 @@ } ] }, - "python3-PyMySQL_na_rpm": { + "python3-PyMySQL": { "Name": "python3-PyMySQL", "SupportedOS": [ { @@ -693,7 +654,7 @@ } ] }, - "python3-firewall_na_rpm": { + "python3-firewall": { "Name": "python3-firewall", "SupportedOS": [ { @@ -717,7 +678,7 @@ } ] }, - "sg3_utils_na_rpm": { + "sg3_utils": { "Name": "sg3_utils", "SupportedOS": [ { @@ -741,7 +702,7 @@ } ] }, - "sionlib_na_tarball": { + "sionlib": { "Name": "sionlib", "SupportedOS": [ { @@ -765,8 +726,8 @@ } ] }, - "slurm-pam_slurm_na_rpm": { - "Name": "slurm-pam_slurm", + "slurm": { + "Name": "slurm", "SupportedOS": [ { "Name": "RHEL", @@ -789,8 +750,8 @@ } ] }, - "slurm-slurmctld_na_rpm": { - "Name": "slurm-slurmctld", + "slurm-pam_slurm": { + "Name": "slurm-pam_slurm", "SupportedOS": [ { "Name": "RHEL", @@ -813,8 +774,8 @@ } ] }, - "slurm-slurmd_na_rpm": { - "Name": "slurm-slurmd", + "slurm-slurmctld": { + "Name": "slurm-slurmctld", "SupportedOS": [ { "Name": "RHEL", @@ -837,8 +798,8 @@ } ] }, - "slurm-slurmdbd_na_rpm": { - "Name": "slurm-slurmdbd", + "slurm-slurmd": { + "Name": "slurm-slurmd", "SupportedOS": [ { "Name": "RHEL", @@ -861,8 +822,8 @@ } ] }, - "slurm_na_rpm": { - "Name": "slurm", + "slurm-slurmdbd": { + "Name": "slurm-slurmdbd", "SupportedOS": [ { "Name": "RHEL", @@ -887,7 +848,7 @@ } }, "OSPackages": { - "NetworkManager_na_rpm": { + "NetworkManager": { "Name": "NetworkManager", "SupportedOS": [ { @@ -911,7 +872,7 @@ } ] }, - "authselect_na_rpm": { + "authselect": { "Name": "authselect", "SupportedOS": [ { @@ -935,7 +896,7 @@ } ] }, - "autoconf_na_rpm": { + "autoconf": { "Name": "autoconf", "SupportedOS": [ { @@ -959,7 +920,7 @@ } ] }, - "automake_na_rpm": { + "automake": { "Name": "automake", "SupportedOS": [ { @@ -983,8 +944,8 @@ } ] }, - "bash-completion_na_rpm": { - "Name": "bash-completion", + "bash": { + "Name": "bash", "SupportedOS": [ { "Name": "RHEL", @@ -1007,8 +968,8 @@ } ] }, - "bash_na_rpm": { - "Name": "bash", + "bash-completion": { + "Name": "bash-completion", "SupportedOS": [ { "Name": "RHEL", @@ -1031,8 +992,8 @@ } ] }, - "binutils-devel_na_rpm": { - "Name": "binutils-devel", + "binutils": { + "Name": "binutils", "SupportedOS": [ { "Name": "RHEL", @@ -1047,16 +1008,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "binutils_na_rpm": { - "Name": "binutils", + "binutils-devel": { + "Name": "binutils-devel", "SupportedOS": [ { "Name": "RHEL", @@ -1071,15 +1032,15 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "bzip2_na_rpm": { + "bzip2": { "Name": "bzip2", "SupportedOS": [ { @@ -1103,7 +1064,7 @@ } ] }, - "chrony_na_rpm": { + "chrony": { "Name": "chrony", "SupportedOS": [ { @@ -1127,7 +1088,7 @@ } ] }, - "cloud-init_na_rpm": { + "cloud-init": { "Name": "cloud-init", "SupportedOS": [ { @@ -1151,7 +1112,7 @@ } ] }, - "clustershell_na_rpm": { + "clustershell": { "Name": "clustershell", "SupportedOS": [ { @@ -1175,7 +1136,7 @@ } ] }, - "cmake_na_rpm": { + "cmake": { "Name": "cmake", "SupportedOS": [ { @@ -1199,7 +1160,7 @@ } ] }, - "coreutils_na_rpm": { + "coreutils": { "Name": "coreutils", "SupportedOS": [ { @@ -1223,7 +1184,7 @@ } ] }, - "cryptsetup_na_rpm": { + "cryptsetup": { "Name": "cryptsetup", "SupportedOS": [ { @@ -1247,7 +1208,7 @@ } ] }, - "curl_na_rpm": { + "curl": { "Name": "curl", "SupportedOS": [ { @@ -1271,7 +1232,7 @@ } ] }, - "device-mapper_na_rpm": { + "device-mapper": { "Name": "device-mapper", "SupportedOS": [ { @@ -1295,7 +1256,7 @@ } ] }, - "dmidecode_na_rpm": { + "dmidecode": { "Name": "dmidecode", "SupportedOS": [ { @@ -1319,7 +1280,7 @@ } ] }, - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-aarch64": { "Name": "docker.io/dellhpcomniaaisolution/image-build-aarch64", "SupportedOS": [ { @@ -1334,7 +1295,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-el10": { "Name": "docker.io/dellhpcomniaaisolution/image-build-el10", "SupportedOS": [ { @@ -1349,8 +1310,8 @@ "Tag": "1.1", "Version": "1.1" }, - "dracut-live_na_rpm": { - "Name": "dracut-live", + "dracut": { + "Name": "dracut", "SupportedOS": [ { "Name": "RHEL", @@ -1365,16 +1326,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "dracut-network_na_rpm": { - "Name": "dracut-network", + "dracut-live": { + "Name": "dracut-live", "SupportedOS": [ { "Name": "RHEL", @@ -1389,16 +1350,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "dracut_na_rpm": { - "Name": "dracut", + "dracut-network": { + "Name": "dracut-network", "SupportedOS": [ { "Name": "RHEL", @@ -1421,7 +1382,7 @@ } ] }, - "emacs_na_rpm": { + "emacs": { "Name": "emacs", "SupportedOS": [ { @@ -1445,7 +1406,7 @@ } ] }, - "file_na_rpm": { + "file": { "Name": "file", "SupportedOS": [ { @@ -1469,7 +1430,7 @@ } ] }, - "findutils_na_rpm": { + "findutils": { "Name": "findutils", "SupportedOS": [ { @@ -1493,7 +1454,7 @@ } ] }, - "fping_na_rpm": { + "fping": { "Name": "fping", "SupportedOS": [ { @@ -1517,7 +1478,7 @@ } ] }, - "gawk_na_rpm": { + "gawk": { "Name": "gawk", "SupportedOS": [ { @@ -1541,8 +1502,8 @@ } ] }, - "gcc-c++_na_rpm": { - "Name": "gcc-c++", + "gcc": { + "Name": "gcc", "SupportedOS": [ { "Name": "RHEL", @@ -1565,8 +1526,8 @@ } ] }, - "gcc-gfortran_na_rpm": { - "Name": "gcc-gfortran", + "gcc-c++": { + "Name": "gcc-c++", "SupportedOS": [ { "Name": "RHEL", @@ -1589,8 +1550,8 @@ } ] }, - "gcc_na_rpm": { - "Name": "gcc", + "gcc-gfortran": { + "Name": "gcc-gfortran", "SupportedOS": [ { "Name": "RHEL", @@ -1613,8 +1574,8 @@ } ] }, - "gdb-gdbserver_na_rpm": { - "Name": "gdb-gdbserver", + "gdb": { + "Name": "gdb", "SupportedOS": [ { "Name": "RHEL", @@ -1637,8 +1598,8 @@ } ] }, - "gdb_na_rpm": { - "Name": "gdb", + "gdb-gdbserver": { + "Name": "gdb-gdbserver", "SupportedOS": [ { "Name": "RHEL", @@ -1661,7 +1622,7 @@ } ] }, - "gedit_na_rpm": { + "gedit": { "Name": "gedit", "SupportedOS": [ { @@ -1685,7 +1646,7 @@ } ] }, - "glibc-langpack-en_na_rpm": { + "glibc-langpack-en": { "Name": "glibc-langpack-en", "SupportedOS": [ { @@ -1709,7 +1670,7 @@ } ] }, - "grep_na_rpm": { + "grep": { "Name": "grep", "SupportedOS": [ { @@ -1733,7 +1694,7 @@ } ] }, - "gzip_na_rpm": { + "gzip": { "Name": "gzip", "SupportedOS": [ { @@ -1757,8 +1718,8 @@ } ] }, - "hwloc-libs_na_rpm": { - "Name": "hwloc-libs", + "hwloc": { + "Name": "hwloc", "SupportedOS": [ { "Name": "RHEL", @@ -1781,8 +1742,8 @@ } ] }, - "hwloc_na_rpm": { - "Name": "hwloc", + "hwloc-libs": { + "Name": "hwloc-libs", "SupportedOS": [ { "Name": "RHEL", @@ -1805,7 +1766,7 @@ } ] }, - "iperf3_na_rpm": { + "iperf3": { "Name": "iperf3", "SupportedOS": [ { @@ -1829,7 +1790,7 @@ } ] }, - "ipmitool_na_rpm": { + "ipmitool": { "Name": "ipmitool", "SupportedOS": [ { @@ -1853,7 +1814,7 @@ } ] }, - "iproute_na_rpm": { + "iproute": { "Name": "iproute", "SupportedOS": [ { @@ -1877,7 +1838,7 @@ } ] }, - "iputils_na_rpm": { + "iputils": { "Name": "iputils", "SupportedOS": [ { @@ -1901,7 +1862,7 @@ } ] }, - "kbd_na_rpm": { + "kbd": { "Name": "kbd", "SupportedOS": [ { @@ -1925,8 +1886,8 @@ } ] }, - "kernel-tools_na_rpm": { - "Name": "kernel-tools", + "kernel": { + "Name": "kernel", "SupportedOS": [ { "Name": "RHEL", @@ -1949,8 +1910,8 @@ } ] }, - "kernel_na_rpm": { - "Name": "kernel", + "kernel-tools": { + "Name": "kernel-tools", "SupportedOS": [ { "Name": "RHEL", @@ -1973,7 +1934,7 @@ } ] }, - "kexec-tools_na_rpm": { + "kexec-tools": { "Name": "kexec-tools", "SupportedOS": [ { @@ -1997,7 +1958,7 @@ } ] }, - "libcurl_na_rpm": { + "libcurl": { "Name": "libcurl", "SupportedOS": [ { @@ -2021,7 +1982,7 @@ } ] }, - "libtool_na_rpm": { + "libtool": { "Name": "libtool", "SupportedOS": [ { @@ -2045,8 +2006,8 @@ } ] }, - "lldb-devel_na_rpm": { - "Name": "lldb-devel", + "lldb": { + "Name": "lldb", "SupportedOS": [ { "Name": "RHEL", @@ -2069,8 +2030,8 @@ } ] }, - "lldb_na_rpm": { - "Name": "lldb", + "lldb-devel": { + "Name": "lldb-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2093,7 +2054,7 @@ } ] }, - "lshw_na_rpm": { + "lshw": { "Name": "lshw", "SupportedOS": [ { @@ -2117,7 +2078,7 @@ } ] }, - "lsof_na_rpm": { + "lsof": { "Name": "lsof", "SupportedOS": [ { @@ -2141,7 +2102,7 @@ } ] }, - "ltrace_na_rpm": { + "ltrace": { "Name": "ltrace", "SupportedOS": [ { @@ -2165,7 +2126,7 @@ } ] }, - "lvm2_na_rpm": { + "lvm2": { "Name": "lvm2", "SupportedOS": [ { @@ -2189,7 +2150,7 @@ } ] }, - "make_na_rpm": { + "make": { "Name": "make", "SupportedOS": [ { @@ -2213,7 +2174,7 @@ } ] }, - "man-db_na_rpm": { + "man-db": { "Name": "man-db", "SupportedOS": [ { @@ -2237,7 +2198,7 @@ } ] }, - "man-pages_na_rpm": { + "man-pages": { "Name": "man-pages", "SupportedOS": [ { @@ -2261,7 +2222,7 @@ } ] }, - "nfs-utils_na_rpm": { + "nfs-utils": { "Name": "nfs-utils", "SupportedOS": [ { @@ -2285,7 +2246,7 @@ } ] }, - "nfs4-acl-tools_na_rpm": { + "nfs4-acl-tools": { "Name": "nfs4-acl-tools", "SupportedOS": [ { @@ -2309,7 +2270,7 @@ } ] }, - "nm-connection-editor_na_rpm": { + "nm-connection-editor": { "Name": "nm-connection-editor", "SupportedOS": [ { @@ -2333,7 +2294,7 @@ } ] }, - "nss-pam-ldapd_na_rpm": { + "nss-pam-ldapd": { "Name": "nss-pam-ldapd", "SupportedOS": [ { @@ -2357,7 +2318,7 @@ } ] }, - "oddjob-mkhomedir_na_rpm": { + "oddjob-mkhomedir": { "Name": "oddjob-mkhomedir", "SupportedOS": [ { @@ -2381,7 +2342,7 @@ } ] }, - "openldap-clients_na_rpm": { + "openldap-clients": { "Name": "openldap-clients", "SupportedOS": [ { @@ -2405,8 +2366,8 @@ } ] }, - "openssh-clients_na_rpm": { - "Name": "openssh-clients", + "openssh": { + "Name": "openssh", "SupportedOS": [ { "Name": "RHEL", @@ -2429,8 +2390,8 @@ } ] }, - "openssh-server_na_rpm": { - "Name": "openssh-server", + "openssh-clients": { + "Name": "openssh-clients", "SupportedOS": [ { "Name": "RHEL", @@ -2453,8 +2414,8 @@ } ] }, - "openssh_na_rpm": { - "Name": "openssh", + "openssh-server": { + "Name": "openssh-server", "SupportedOS": [ { "Name": "RHEL", @@ -2477,7 +2438,7 @@ } ] }, - "openssl-devel_na_rpm": { + "openssl-devel": { "Name": "openssl-devel", "SupportedOS": [ { @@ -2501,7 +2462,7 @@ } ] }, - "papi-devel_na_rpm": { + "papi-devel": { "Name": "papi-devel", "SupportedOS": [ { @@ -2525,7 +2486,7 @@ } ] }, - "papi-libs_na_rpm": { + "papi-libs": { "Name": "papi-libs", "SupportedOS": [ { @@ -2549,7 +2510,7 @@ } ] }, - "papi_na_rpm": { + "papi_1": { "Name": "papi", "SupportedOS": [ { @@ -2573,7 +2534,7 @@ } ] }, - "pciutils_na_rpm": { + "pciutils": { "Name": "pciutils", "SupportedOS": [ { @@ -2597,7 +2558,7 @@ } ] }, - "perf_na_rpm": { + "perf": { "Name": "perf", "SupportedOS": [ { @@ -2621,7 +2582,7 @@ } ] }, - "rsync_na_rpm": { + "rsync": { "Name": "rsync", "SupportedOS": [ { @@ -2645,7 +2606,7 @@ } ] }, - "rsyslog_na_rpm": { + "rsyslog": { "Name": "rsyslog", "SupportedOS": [ { @@ -2669,7 +2630,7 @@ } ] }, - "sed_na_rpm": { + "sed": { "Name": "sed", "SupportedOS": [ { @@ -2693,7 +2654,7 @@ } ] }, - "squashfs-tools_na_rpm": { + "squashfs-tools": { "Name": "squashfs-tools", "SupportedOS": [ { @@ -2717,7 +2678,7 @@ } ] }, - "sssd_na_rpm": { + "sssd": { "Name": "sssd", "SupportedOS": [ { @@ -2741,7 +2702,7 @@ } ] }, - "strace_na_rpm": { + "strace": { "Name": "strace", "SupportedOS": [ { @@ -2765,7 +2726,7 @@ } ] }, - "sudo_na_rpm": { + "sudo": { "Name": "sudo", "SupportedOS": [ { @@ -2789,8 +2750,8 @@ } ] }, - "systemd-udev_na_rpm": { - "Name": "systemd-udev", + "systemd": { + "Name": "systemd", "SupportedOS": [ { "Name": "RHEL", @@ -2813,8 +2774,8 @@ } ] }, - "systemd_na_rpm": { - "Name": "systemd", + "systemd-udev": { + "Name": "systemd-udev", "SupportedOS": [ { "Name": "RHEL", @@ -2837,7 +2798,7 @@ } ] }, - "tar_na_rpm": { + "tar": { "Name": "tar", "SupportedOS": [ { @@ -2861,7 +2822,7 @@ } ] }, - "tcpdump_na_rpm": { + "tcpdump": { "Name": "tcpdump", "SupportedOS": [ { @@ -2885,7 +2846,7 @@ } ] }, - "traceroute_na_rpm": { + "traceroute": { "Name": "traceroute", "SupportedOS": [ { @@ -2909,7 +2870,7 @@ } ] }, - "util-linux_na_rpm": { + "util-linux": { "Name": "util-linux", "SupportedOS": [ { @@ -2933,8 +2894,8 @@ } ] }, - "valgrind-devel_na_rpm": { - "Name": "valgrind-devel", + "valgrind": { + "Name": "valgrind", "SupportedOS": [ { "Name": "RHEL", @@ -2957,8 +2918,8 @@ } ] }, - "valgrind_na_rpm": { - "Name": "valgrind", + "valgrind-devel": { + "Name": "valgrind-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2981,7 +2942,7 @@ } ] }, - "vim-enhanced_na_rpm": { + "vim-enhanced": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -3005,7 +2966,7 @@ } ] }, - "wget_na_rpm": { + "wget": { "Name": "wget", "SupportedOS": [ { @@ -3029,7 +2990,7 @@ } ] }, - "which_na_rpm": { + "which": { "Name": "which", "SupportedOS": [ { @@ -3053,7 +3014,7 @@ } ] }, - "zsh_na_rpm": { + "zsh": { "Name": "zsh", "SupportedOS": [ { diff --git a/examples/catalog/catalog_rhel_with_nfs_provisioner.json b/examples/catalog/catalog_rhel_with_nfs_provisioner.json index 69d40eb4f6..556c97d65e 100644 --- a/examples/catalog/catalog_rhel_with_nfs_provisioner.json +++ b/examples/catalog/catalog_rhel_with_nfs_provisioner.json @@ -7,249 +7,248 @@ { "Name": "login_compiler_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "login_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "service_kube_control_plane_x86_64", "FunctionalPackages": [ - "PyMySQL_1.1.2_pip_module", - "apptainer_na_rpm", - "calico-v3-31-4_na_manifest", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-calico-cni_v3.31.4_image", - "docker-io-calico-kube-controllers_v3.31.4_image", - "docker-io-calico-node_v3.31.4_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-kube-vip-kube-vip_v0.8.9_image", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "helm-v3-20-1-amd64_na_tarball", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubectl_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "metallb-native-v0-15-3_na_manifest", - "nfs-subdir-external-provisioner-4-0-18_na_tarball", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prettytable_3.14.0_pip_module", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "python3_3.12.9_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-coredns-coredns_v1.13.1_image", - "registry-k8s-io-etcd_3.6.6-0_image", - "registry-k8s-io-kube-apiserver_v1.35.1_image", - "registry-k8s-io-kube-controller-manager_v1.35.1_image", - "registry-k8s-io-kube-proxy_v1.35.1_image", - "registry-k8s-io-kube-scheduler_v1.35.1_image", - "registry-k8s-io-pause_3.10.1_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "PyMySQL", + "apptainer", + "calico", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/calico/cni", + "docker.io/calico/kube-controllers", + "docker.io/calico/node", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/kube-vip/kube-vip", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-amd64", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubectl", + "kubelet", + "kubernetes", + "lsscsi", + "metallb-native", + "nfs-subdir-external-provisioner", + "omsdk", + "podman", + "prettytable", + "prometheus_client", + "python3", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/coredns/coredns", + "registry.k8s.io/etcd", + "registry.k8s.io/kube-apiserver", + "registry.k8s.io/kube-controller-manager", + "registry.k8s.io/kube-proxy", + "registry.k8s.io/kube-scheduler", + "registry.k8s.io/pause", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "service_kube_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-controller_v0.15.3_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "apptainer", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubelet", + "kubernetes", + "lsscsi", + "omsdk", + "podman", + "prometheus_client", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/controller", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "slurm_control_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "mariadb-server_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-PyMySQL_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmctld_na_rpm", - "slurm-slurmdbd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "mariadb-server", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-PyMySQL", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-slurmctld", + "slurm-slurmdbd" ] }, { "Name": "slurm_node_aarch64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "kernel-devel_na_rpm", - "kernel-headers_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-pam_slurm_na_rpm", - "slurm-slurmd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "kernel-devel", + "kernel-headers", + "likwid", + "lsscsi", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-pam_slurm", + "slurm-slurmd" ] } ], @@ -258,106 +257,106 @@ "Name": "RHEL", "Version": "10.0", "osPackages": [ - "NetworkManager_na_rpm", - "authselect_na_rpm", - "autoconf_na_rpm", - "automake_na_rpm", - "bash-completion_na_rpm", - "bash_na_rpm", - "binutils-devel_na_rpm", - "binutils_na_rpm", - "bzip2_na_rpm", - "chrony_na_rpm", - "cloud-init_na_rpm", - "clustershell_na_rpm", - "cmake_na_rpm", - "coreutils_na_rpm", - "cryptsetup_na_rpm", - "curl_na_rpm", - "device-mapper_na_rpm", - "dmidecode_na_rpm", - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image", - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image", - "dracut-live_na_rpm", - "dracut-network_na_rpm", - "dracut_na_rpm", - "emacs_na_rpm", - "file_na_rpm", - "findutils_na_rpm", - "fping_na_rpm", - "gawk_na_rpm", - "gcc-c++_na_rpm", - "gcc-gfortran_na_rpm", - "gcc_na_rpm", - "gdb-gdbserver_na_rpm", - "gdb_na_rpm", - "gedit_na_rpm", - "glibc-langpack-en_na_rpm", - "grep_na_rpm", - "gzip_na_rpm", - "hwloc-libs_na_rpm", - "hwloc_na_rpm", - "iperf3_na_rpm", - "ipmitool_na_rpm", - "iproute_na_rpm", - "iputils_na_rpm", - "kbd_na_rpm", - "kernel-tools_na_rpm", - "kernel_na_rpm", - "kexec-tools_na_rpm", - "libcurl_na_rpm", - "libtool_na_rpm", - "lldb-devel_na_rpm", - "lldb_na_rpm", - "lshw_na_rpm", - "lsof_na_rpm", - "ltrace_na_rpm", - "lvm2_na_rpm", - "make_na_rpm", - "man-db_na_rpm", - "man-pages_na_rpm", - "munge-devel_na_rpm", - "nfs-utils_na_rpm", - "nfs4-acl-tools_na_rpm", - "nm-connection-editor_na_rpm", - "nss-pam-ldapd_na_rpm", - "oddjob-mkhomedir_na_rpm", - "openldap-clients_na_rpm", - "openmpi_5.0.8_tarball", - "openssh-clients_na_rpm", - "openssh-server_na_rpm", - "openssh_na_rpm", - "openssl-devel_na_rpm", - "openssl-libs_na_rpm", - "ovis-ldms_na_rpm", - "papi-devel_na_rpm", - "papi-libs_na_rpm", - "papi_na_rpm", - "pciutils_na_rpm", - "perf_na_rpm", - "pmix-devel_na_rpm", - "python3-cython_na_rpm", - "python3-devel_na_rpm", - "rsync_na_rpm", - "rsyslog_na_rpm", - "sed_na_rpm", - "squashfs-tools_na_rpm", - "sssd_na_rpm", - "strace_na_rpm", - "sudo_na_rpm", - "systemd-udev_na_rpm", - "systemd_na_rpm", - "tar_na_rpm", - "tcpdump_na_rpm", - "traceroute_na_rpm", - "ucx_1.19.0_tarball", - "util-linux_na_rpm", - "valgrind-devel_na_rpm", - "valgrind_na_rpm", - "vim-enhanced_na_rpm_1", - "wget_na_rpm", - "which_na_rpm", - "zsh_na_rpm" + "NetworkManager", + "authselect", + "autoconf", + "automake", + "bash", + "bash-completion", + "binutils", + "binutils-devel", + "bzip2", + "chrony", + "cloud-init", + "clustershell", + "cmake", + "coreutils", + "cryptsetup", + "curl", + "device-mapper", + "dmidecode", + "docker.io/dellhpcomniaaisolution/image-build-aarch64", + "docker.io/dellhpcomniaaisolution/image-build-el10", + "dracut", + "dracut-live", + "dracut-network", + "emacs", + "file", + "findutils", + "fping", + "gawk", + "gcc", + "gcc-c++", + "gcc-gfortran", + "gdb", + "gdb-gdbserver", + "gedit", + "glibc-langpack-en", + "grep", + "gzip", + "hwloc", + "hwloc-libs", + "iperf3", + "ipmitool", + "iproute", + "iputils", + "kbd", + "kernel", + "kernel-tools", + "kexec-tools", + "libcurl", + "libtool", + "lldb", + "lldb-devel", + "lshw", + "lsof", + "ltrace", + "lvm2", + "make", + "man-db", + "man-pages", + "munge-devel", + "nfs-utils", + "nfs4-acl-tools", + "nm-connection-editor", + "nss-pam-ldapd", + "oddjob-mkhomedir", + "openldap-clients", + "openmpi", + "openssh", + "openssh-clients", + "openssh-server", + "openssl-devel", + "openssl-libs", + "ovis-ldms", + "papi-devel", + "papi-libs", + "papi_1", + "pciutils", + "perf", + "pmix-devel", + "python3-cython", + "python3-devel", + "rsync", + "rsyslog", + "sed", + "squashfs-tools", + "sssd", + "strace", + "sudo", + "systemd", + "systemd-udev", + "tar", + "tcpdump", + "traceroute", + "ucx", + "util-linux", + "valgrind", + "valgrind-devel", + "vim-enhanced_1", + "wget", + "which", + "zsh" ] } ], @@ -365,7 +364,7 @@ "Drivers": [], "DriverPackages": {}, "FunctionalPackages": { - "PyMySQL_1.1.2_pip_module": { + "PyMySQL": { "Name": "PyMySQL==1.1.2", "SupportedOS": [ { @@ -378,7 +377,7 @@ ], "Type": "pip_module" }, - "apptainer_na_rpm": { + "apptainer": { "Name": "apptainer", "SupportedOS": [ { @@ -402,7 +401,7 @@ } ] }, - "calico-v3-31-4_na_manifest": { + "calico": { "Name": "calico-v3.31.4", "SupportedOS": [ { @@ -421,7 +420,7 @@ } ] }, - "cert-manager-v1-10-0_na_tarball": { + "cert-manager": { "Name": "cert-manager-v1.10.0", "SupportedOS": [ { @@ -440,7 +439,7 @@ } ] }, - "cffi_1.17.1_pip_module": { + "cffi": { "Name": "cffi==1.17.1", "SupportedOS": [ { @@ -453,7 +452,7 @@ ], "Type": "pip_module" }, - "container-selinux_na_rpm": { + "container-selinux": { "Name": "container-selinux", "SupportedOS": [ { @@ -472,7 +471,7 @@ } ] }, - "cri-o_1.35.1_rpm": { + "cri-o": { "Name": "cri-o-1.35.1", "SupportedOS": [ { @@ -491,7 +490,7 @@ } ] }, - "cryptography_45.0.7_pip_module": { + "cryptography": { "Name": "cryptography==45.0.7", "SupportedOS": [ { @@ -504,7 +503,7 @@ ], "Type": "pip_module" }, - "device-mapper-multipath_na_rpm": { + "device-mapper-multipath": { "Name": "device-mapper-multipath", "SupportedOS": [ { @@ -528,7 +527,7 @@ } ] }, - "doca-ofed_na_rpm_repo": { + "doca-ofed": { "Name": "doca-ofed", "SupportedOS": [ { @@ -552,7 +551,7 @@ } ] }, - "docker-io-alpine-kubectl_1.35.1_image": { + "docker.io/alpine/kubectl": { "Name": "docker.io/alpine/kubectl", "SupportedOS": [ { @@ -567,7 +566,7 @@ "Tag": "1.35.1", "Version": "1.35.1" }, - "docker-io-calico-cni_v3.31.4_image": { + "docker.io/calico/cni": { "Name": "docker.io/calico/cni", "SupportedOS": [ { @@ -582,7 +581,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-kube-controllers_v3.31.4_image": { + "docker.io/calico/kube-controllers": { "Name": "docker.io/calico/kube-controllers", "SupportedOS": [ { @@ -597,7 +596,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-node_v3.31.4_image": { + "docker.io/calico/node": { "Name": "docker.io/calico/node", "SupportedOS": [ { @@ -612,7 +611,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-curlimages-curl_8.17.0_image": { + "docker.io/curlimages/curl": { "Name": "docker.io/curlimages/curl", "SupportedOS": [ { @@ -627,7 +626,7 @@ "Tag": "8.17.0", "Version": "8.17.0" }, - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image": { + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver": { "Name": "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", "SupportedOS": [ { @@ -642,7 +641,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/kafkapump": { "Name": "docker.io/dellhpcomniaaisolution/kafkapump", "SupportedOS": [ { @@ -657,7 +656,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image": { + "docker.io/dellhpcomniaaisolution/ubuntu-ldms": { "Name": "docker.io/dellhpcomniaaisolution/ubuntu-ldms", "SupportedOS": [ { @@ -672,7 +671,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/victoriapump": { "Name": "docker.io/dellhpcomniaaisolution/victoriapump", "SupportedOS": [ { @@ -687,7 +686,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-library-busybox_1.36_image": { + "docker.io/library/busybox": { "Name": "docker.io/library/busybox", "SupportedOS": [ { @@ -702,7 +701,7 @@ "Tag": "1.36", "Version": "1.36" }, - "docker-io-library-mysql_9.3.0_image": { + "docker.io/library/mysql": { "Name": "docker.io/library/mysql", "SupportedOS": [ { @@ -717,7 +716,7 @@ "Tag": "9.3.0", "Version": "9.3.0" }, - "docker-io-library-python_3.12-slim_image": { + "docker.io/library/python": { "Name": "docker.io/library/python", "SupportedOS": [ { @@ -732,7 +731,7 @@ "Tag": "3.12-slim", "Version": "3.12-slim" }, - "docker-io-nginxinc-nginx-unprivileged_1.29_image": { + "docker.io/nginxinc/nginx-unprivileged": { "Name": "docker.io/nginxinc/nginx-unprivileged", "SupportedOS": [ { @@ -747,7 +746,7 @@ "Tag": "1.29", "Version": "1.29" }, - "docker-io-rmohr-activemq_5.15.9_image": { + "docker.io/rmohr/activemq": { "Name": "docker.io/rmohr/activemq", "SupportedOS": [ { @@ -762,7 +761,7 @@ "Tag": "5.15.9", "Version": "5.15.9" }, - "docker-io-timberio-vector_0.54.0-debian_image": { + "docker.io/timberio/vector": { "Name": "docker.io/timberio/vector", "SupportedOS": [ { @@ -777,7 +776,7 @@ "Tag": "0.54.0-debian", "Version": "0.54.0-debian" }, - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image": { + "docker.io/victoriametrics/operator": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -789,10 +788,10 @@ "x86_64" ], "Type": "image", - "Tag": "config-reloader-v0.68.3", - "Version": "config-reloader-v0.68.3" + "Tag": "v0.68.3", + "Version": "v0.68.3" }, - "docker-io-victoriametrics-operator_v0.68.3_image": { + "docker.io/victoriametrics/operator_1": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -804,10 +803,10 @@ "x86_64" ], "Type": "image", - "Tag": "v0.68.3", - "Version": "v0.68.3" + "Tag": "config-reloader-v0.68.3", + "Version": "config-reloader-v0.68.3" }, - "docker-io-victoriametrics-victoria-logs_v1.50.0_image": { + "docker.io/victoriametrics/victoria-logs": { "Name": "docker.io/victoriametrics/victoria-logs", "SupportedOS": [ { @@ -822,7 +821,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image": { + "docker.io/victoriametrics/victoria-metrics": { "Name": "docker.io/victoriametrics/victoria-metrics", "SupportedOS": [ { @@ -837,7 +836,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vlagent_v1.50.0_image": { + "docker.io/victoriametrics/vlagent": { "Name": "docker.io/victoriametrics/vlagent", "SupportedOS": [ { @@ -852,7 +851,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-vmagent_v1.128.0_image": { + "docker.io/victoriametrics/vmagent": { "Name": "docker.io/victoriametrics/vmagent", "SupportedOS": [ { @@ -867,7 +866,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vminsert": { "Name": "docker.io/victoriametrics/vminsert", "SupportedOS": [ { @@ -882,7 +881,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmselect": { "Name": "docker.io/victoriametrics/vmselect", "SupportedOS": [ { @@ -897,7 +896,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmstorage": { "Name": "docker.io/victoriametrics/vmstorage", "SupportedOS": [ { @@ -912,7 +911,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "firewalld_na_rpm": { + "firewalld": { "Name": "firewalld", "SupportedOS": [ { @@ -936,7 +935,7 @@ } ] }, - "fuse-overlayfs_na_rpm": { + "fuse-overlayfs": { "Name": "fuse-overlayfs", "SupportedOS": [ { @@ -955,7 +954,7 @@ } ] }, - "geopm_na_tarball": { + "geopm": { "Name": "geopm", "SupportedOS": [ { @@ -979,7 +978,7 @@ } ] }, - "ghcr-io-kube-vip-kube-vip_v0.8.9_image": { + "ghcr.io/kube-vip/kube-vip": { "Name": "ghcr.io/kube-vip/kube-vip", "SupportedOS": [ { @@ -994,7 +993,7 @@ "Tag": "v0.8.9", "Version": "v0.8.9" }, - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image": { + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector": { "Name": "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", "SupportedOS": [ { @@ -1009,7 +1008,7 @@ "Tag": "0.143.1", "Version": "0.143.1" }, - "git_na_rpm": { + "git": { "Name": "git", "SupportedOS": [ { @@ -1028,8 +1027,8 @@ } ] }, - "helm-charts_container-storage-modules-1.9.2_git": { - "Name": "helm-charts", + "helm-amd64": { + "Name": "helm-v3.20.1-amd64", "SupportedOS": [ { "Name": "RHEL", @@ -1039,17 +1038,16 @@ "Architecture": [ "x86_64" ], - "Type": "git", - "Version": "container-storage-modules-1.9.2", + "Type": "tarball", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://github.com/dell/helm-charts.git" + "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" } ] }, - "helm-v3-20-1-amd64_na_tarball": { - "Name": "helm-v3.20.1-amd64", + "helm-charts": { + "Name": "helm-charts", "SupportedOS": [ { "Name": "RHEL", @@ -1059,15 +1057,16 @@ "Architecture": [ "x86_64" ], - "Type": "tarball", + "Type": "git", + "Version": "container-storage-modules-1.9.2", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" + "Uri": "https://github.com/dell/helm-charts.git" } ] }, - "imb_na_tarball": { + "imb": { "Name": "imb", "SupportedOS": [ { @@ -1091,7 +1090,7 @@ } ] }, - "iscsi-initiator-utils_na_rpm": { + "iscsi-initiator-utils": { "Name": "iscsi-initiator-utils", "SupportedOS": [ { @@ -1115,7 +1114,7 @@ } ] }, - "karavi-observability_v1.12.0_git": { + "karavi-observability": { "Name": "karavi-observability", "SupportedOS": [ { @@ -1135,7 +1134,7 @@ } ] }, - "kernel-devel_na_rpm": { + "kernel-devel": { "Name": "kernel-devel", "SupportedOS": [ { @@ -1159,7 +1158,7 @@ } ] }, - "kernel-headers_na_rpm": { + "kernel-headers": { "Name": "kernel-headers", "SupportedOS": [ { @@ -1183,7 +1182,7 @@ } ] }, - "kubeadm_1.35.1_rpm": { + "kubeadm": { "Name": "kubeadm-1.35.1", "SupportedOS": [ { @@ -1202,7 +1201,7 @@ } ] }, - "kubectl_1.35.1_rpm": { + "kubectl": { "Name": "kubectl-1.35.1", "SupportedOS": [ { @@ -1221,7 +1220,7 @@ } ] }, - "kubelet_1.35.1_rpm": { + "kubelet": { "Name": "kubelet-1.35.1", "SupportedOS": [ { @@ -1240,7 +1239,7 @@ } ] }, - "kubernetes_33.1.0_pip_module": { + "kubernetes": { "Name": "kubernetes==33.1.0", "SupportedOS": [ { @@ -1253,7 +1252,7 @@ ], "Type": "pip_module" }, - "likwid_na_tarball": { + "likwid": { "Name": "likwid", "SupportedOS": [ { @@ -1277,7 +1276,7 @@ } ] }, - "lsscsi_na_rpm": { + "lsscsi": { "Name": "lsscsi", "SupportedOS": [ { @@ -1301,7 +1300,7 @@ } ] }, - "mariadb-server_na_rpm": { + "mariadb-server": { "Name": "mariadb-server", "SupportedOS": [ { @@ -1325,7 +1324,7 @@ } ] }, - "metallb-native-v0-15-3_na_manifest": { + "metallb-native": { "Name": "metallb-native-v0.15.3", "SupportedOS": [ { @@ -1344,7 +1343,7 @@ } ] }, - "msr-safe_na_tarball": { + "msr-safe": { "Name": "msr-safe", "SupportedOS": [ { @@ -1363,7 +1362,7 @@ } ] }, - "munge_na_rpm": { + "munge": { "Name": "munge", "SupportedOS": [ { @@ -1387,7 +1386,7 @@ } ] }, - "nfs-subdir-external-provisioner-4-0-18_na_tarball": { + "nfs-subdir-external-provisioner": { "Name": "nfs-subdir-external-provisioner-4.0.18", "SupportedOS": [ { @@ -1406,7 +1405,7 @@ } ] }, - "nvcr-io-nvidia-hpc-benchmarks_25.09_image": { + "nvcr.io/nvidia/hpc-benchmarks": { "Name": "nvcr.io/nvidia/hpc-benchmarks", "SupportedOS": [ { @@ -1422,45 +1421,7 @@ "Tag": "25.09", "Version": "25.09" }, - "nvhpc_2025_2511_Linux_aarch64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_aarch64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "aarch64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "aarch64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_aarch64_cuda_13.0.tar.gz" - } - ] - }, - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "x86_64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "x86_64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } - ] - }, - "omsdk_1.2.518_pip_module": { + "omsdk": { "Name": "omsdk==1.2.518", "SupportedOS": [ { @@ -1473,7 +1434,7 @@ ], "Type": "pip_module" }, - "osu-micro-benchmarks_na_tarball": { + "osu-micro-benchmarks": { "Name": "osu-micro-benchmarks", "SupportedOS": [ { @@ -1497,7 +1458,7 @@ } ] }, - "papi_na_tarball": { + "papi": { "Name": "papi", "SupportedOS": [ { @@ -1521,7 +1482,7 @@ } ] }, - "pmix_na_rpm": { + "pmix": { "Name": "pmix", "SupportedOS": [ { @@ -1545,7 +1506,7 @@ } ] }, - "podman_na_rpm": { + "podman": { "Name": "podman", "SupportedOS": [ { @@ -1564,7 +1525,7 @@ } ] }, - "prettytable_3.14.0_pip_module": { + "prettytable": { "Name": "prettytable==3.14.0", "SupportedOS": [ { @@ -1577,7 +1538,7 @@ ], "Type": "pip_module" }, - "prometheus_client_0.20.0_pip_module": { + "prometheus_client": { "Name": "prometheus_client==0.20.0", "SupportedOS": [ { @@ -1590,8 +1551,8 @@ ], "Type": "pip_module" }, - "python3-PyMySQL_na_rpm": { - "Name": "python3-PyMySQL", + "python3": { + "Name": "python3-3.12.9", "SupportedOS": [ { "Name": "RHEL", @@ -1599,23 +1560,18 @@ } ], "Architecture": [ - "aarch64", "x86_64" ], "Type": "rpm", "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" - }, - { - "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "python3-firewall_na_rpm": { - "Name": "python3-firewall", + "python3-PyMySQL": { + "Name": "python3-PyMySQL", "SupportedOS": [ { "Name": "RHEL", @@ -1630,16 +1586,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "python3_3.12.9_rpm": { - "Name": "python3-3.12.9", + "python3-firewall": { + "Name": "python3-firewall", "SupportedOS": [ { "Name": "RHEL", @@ -1647,6 +1603,7 @@ } ], "Architecture": [ + "aarch64", "x86_64" ], "Type": "rpm", @@ -1654,10 +1611,14 @@ { "Architecture": "x86_64", "RepoName": "baseos" + }, + { + "Architecture": "aarch64", + "RepoName": "baseos" } ] }, - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image": { + "quay.io/dell/container-storage-modules/csm-metrics-powerscale": { "Name": "quay.io/dell/container-storage-modules/csm-metrics-powerscale", "SupportedOS": [ { @@ -1672,7 +1633,7 @@ "Tag": "v1.11.0", "Version": "v1.11.0" }, - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image": { + "quay.io/jetstack/cert-manager-acmesolver": { "Name": "quay.io/jetstack/cert-manager-acmesolver", "SupportedOS": [ { @@ -1687,7 +1648,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image": { + "quay.io/jetstack/cert-manager-cainjector": { "Name": "quay.io/jetstack/cert-manager-cainjector", "SupportedOS": [ { @@ -1702,7 +1663,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-controller_v1.10.0_image": { + "quay.io/jetstack/cert-manager-controller": { "Name": "quay.io/jetstack/cert-manager-controller", "SupportedOS": [ { @@ -1717,7 +1678,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image": { + "quay.io/jetstack/cert-manager-webhook": { "Name": "quay.io/jetstack/cert-manager-webhook", "SupportedOS": [ { @@ -1732,7 +1693,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-metallb-controller_v0.15.3_image": { + "quay.io/metallb/controller": { "Name": "quay.io/metallb/controller", "SupportedOS": [ { @@ -1747,7 +1708,7 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-metallb-speaker_v0.15.3_image": { + "quay.io/metallb/speaker": { "Name": "quay.io/metallb/speaker", "SupportedOS": [ { @@ -1762,8 +1723,8 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-strimzi-kafka-bridge_0.33.1_image": { - "Name": "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/kafka": { + "Name": "quay.io/strimzi/kafka", "SupportedOS": [ { "Name": "RHEL", @@ -1774,11 +1735,11 @@ "x86_64" ], "Type": "image", - "Tag": "0.33.1", - "Version": "0.33.1" + "Tag": "0.48.0-kafka-4.1.0", + "Version": "0.48.0-kafka-4.1.0" }, - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image": { - "Name": "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge": { + "Name": "quay.io/strimzi/kafka-bridge", "SupportedOS": [ { "Name": "RHEL", @@ -1789,10 +1750,10 @@ "x86_64" ], "Type": "image", - "Tag": "0.48.0-kafka-4.1.0", - "Version": "0.48.0-kafka-4.1.0" + "Tag": "0.33.1", + "Version": "0.33.1" }, - "quay-io-strimzi-operator_0.48.0_image": { + "quay.io/strimzi/operator": { "Name": "quay.io/strimzi/operator", "SupportedOS": [ { @@ -1807,7 +1768,7 @@ "Tag": "0.48.0", "Version": "0.48.0" }, - "registry-k8s-io-coredns-coredns_v1.13.1_image": { + "registry.k8s.io/coredns/coredns": { "Name": "registry.k8s.io/coredns/coredns", "SupportedOS": [ { @@ -1822,7 +1783,7 @@ "Tag": "v1.13.1", "Version": "v1.13.1" }, - "registry-k8s-io-etcd_3.6.6-0_image": { + "registry.k8s.io/etcd": { "Name": "registry.k8s.io/etcd", "SupportedOS": [ { @@ -1837,7 +1798,7 @@ "Tag": "3.6.6-0", "Version": "3.6.6-0" }, - "registry-k8s-io-kube-apiserver_v1.35.1_image": { + "registry.k8s.io/kube-apiserver": { "Name": "registry.k8s.io/kube-apiserver", "SupportedOS": [ { @@ -1852,7 +1813,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-controller-manager_v1.35.1_image": { + "registry.k8s.io/kube-controller-manager": { "Name": "registry.k8s.io/kube-controller-manager", "SupportedOS": [ { @@ -1867,7 +1828,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-proxy_v1.35.1_image": { + "registry.k8s.io/kube-proxy": { "Name": "registry.k8s.io/kube-proxy", "SupportedOS": [ { @@ -1882,7 +1843,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-scheduler_v1.35.1_image": { + "registry.k8s.io/kube-scheduler": { "Name": "registry.k8s.io/kube-scheduler", "SupportedOS": [ { @@ -1897,7 +1858,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-pause_3.10.1_image": { + "registry.k8s.io/pause": { "Name": "registry.k8s.io/pause", "SupportedOS": [ { @@ -1912,7 +1873,7 @@ "Tag": "3.10.1", "Version": "3.10.1" }, - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image": { + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner": { "Name": "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", "SupportedOS": [ { @@ -1927,7 +1888,7 @@ "Tag": "v4.0.2", "Version": "v4.0.2" }, - "sg3_utils_na_rpm": { + "sg3_utils": { "Name": "sg3_utils", "SupportedOS": [ { @@ -1951,7 +1912,7 @@ } ] }, - "sionlib_na_tarball": { + "sionlib": { "Name": "sionlib", "SupportedOS": [ { @@ -1975,8 +1936,8 @@ } ] }, - "slurm-pam_slurm_na_rpm": { - "Name": "slurm-pam_slurm", + "slurm": { + "Name": "slurm", "SupportedOS": [ { "Name": "RHEL", @@ -1999,8 +1960,8 @@ } ] }, - "slurm-slurmctld_na_rpm": { - "Name": "slurm-slurmctld", + "slurm-pam_slurm": { + "Name": "slurm-pam_slurm", "SupportedOS": [ { "Name": "RHEL", @@ -2023,8 +1984,8 @@ } ] }, - "slurm-slurmd_na_rpm": { - "Name": "slurm-slurmd", + "slurm-slurmctld": { + "Name": "slurm-slurmctld", "SupportedOS": [ { "Name": "RHEL", @@ -2047,8 +2008,8 @@ } ] }, - "slurm-slurmdbd_na_rpm": { - "Name": "slurm-slurmdbd", + "slurm-slurmd": { + "Name": "slurm-slurmd", "SupportedOS": [ { "Name": "RHEL", @@ -2071,8 +2032,8 @@ } ] }, - "slurm_na_rpm": { - "Name": "slurm", + "slurm-slurmdbd": { + "Name": "slurm-slurmdbd", "SupportedOS": [ { "Name": "RHEL", @@ -2095,7 +2056,7 @@ } ] }, - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball": { + "strimzi-kafka-operator-helm-3-chart": { "Name": "strimzi-kafka-operator-helm-3-chart-0.48.0", "SupportedOS": [ { @@ -2114,7 +2075,7 @@ } ] }, - "victoria-metrics-operator-0-59-3_na_tarball": { + "victoria-metrics-operator": { "Name": "victoria-metrics-operator-0.59.3", "SupportedOS": [ { @@ -2133,7 +2094,7 @@ } ] }, - "vim-enhanced_na_rpm": { + "vim-enhanced": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -2159,7 +2120,7 @@ } }, "OSPackages": { - "NetworkManager_na_rpm": { + "NetworkManager": { "Name": "NetworkManager", "SupportedOS": [ { @@ -2183,7 +2144,7 @@ } ] }, - "authselect_na_rpm": { + "authselect": { "Name": "authselect", "SupportedOS": [ { @@ -2207,7 +2168,7 @@ } ] }, - "autoconf_na_rpm": { + "autoconf": { "Name": "autoconf", "SupportedOS": [ { @@ -2231,7 +2192,7 @@ } ] }, - "automake_na_rpm": { + "automake": { "Name": "automake", "SupportedOS": [ { @@ -2255,8 +2216,8 @@ } ] }, - "bash-completion_na_rpm": { - "Name": "bash-completion", + "bash": { + "Name": "bash", "SupportedOS": [ { "Name": "RHEL", @@ -2279,8 +2240,8 @@ } ] }, - "bash_na_rpm": { - "Name": "bash", + "bash-completion": { + "Name": "bash-completion", "SupportedOS": [ { "Name": "RHEL", @@ -2303,8 +2264,8 @@ } ] }, - "binutils-devel_na_rpm": { - "Name": "binutils-devel", + "binutils": { + "Name": "binutils", "SupportedOS": [ { "Name": "RHEL", @@ -2319,16 +2280,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "binutils_na_rpm": { - "Name": "binutils", + "binutils-devel": { + "Name": "binutils-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2343,15 +2304,15 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "bzip2_na_rpm": { + "bzip2": { "Name": "bzip2", "SupportedOS": [ { @@ -2375,7 +2336,7 @@ } ] }, - "chrony_na_rpm": { + "chrony": { "Name": "chrony", "SupportedOS": [ { @@ -2399,7 +2360,7 @@ } ] }, - "cloud-init_na_rpm": { + "cloud-init": { "Name": "cloud-init", "SupportedOS": [ { @@ -2423,7 +2384,7 @@ } ] }, - "clustershell_na_rpm": { + "clustershell": { "Name": "clustershell", "SupportedOS": [ { @@ -2447,7 +2408,7 @@ } ] }, - "cmake_na_rpm": { + "cmake": { "Name": "cmake", "SupportedOS": [ { @@ -2471,7 +2432,7 @@ } ] }, - "coreutils_na_rpm": { + "coreutils": { "Name": "coreutils", "SupportedOS": [ { @@ -2495,7 +2456,7 @@ } ] }, - "cryptsetup_na_rpm": { + "cryptsetup": { "Name": "cryptsetup", "SupportedOS": [ { @@ -2519,7 +2480,7 @@ } ] }, - "curl_na_rpm": { + "curl": { "Name": "curl", "SupportedOS": [ { @@ -2543,7 +2504,7 @@ } ] }, - "device-mapper_na_rpm": { + "device-mapper": { "Name": "device-mapper", "SupportedOS": [ { @@ -2567,7 +2528,7 @@ } ] }, - "dmidecode_na_rpm": { + "dmidecode": { "Name": "dmidecode", "SupportedOS": [ { @@ -2591,7 +2552,7 @@ } ] }, - "docker-io-dellhpcomniaaisolution-image-build-aarch_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-aarch64": { "Name": "docker.io/dellhpcomniaaisolution/image-build-aarch64", "SupportedOS": [ { @@ -2606,7 +2567,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-el10": { "Name": "docker.io/dellhpcomniaaisolution/image-build-el10", "SupportedOS": [ { @@ -2621,8 +2582,8 @@ "Tag": "1.1", "Version": "1.1" }, - "dracut-live_na_rpm": { - "Name": "dracut-live", + "dracut": { + "Name": "dracut", "SupportedOS": [ { "Name": "RHEL", @@ -2637,16 +2598,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" }, { "Architecture": "aarch64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "dracut-network_na_rpm": { - "Name": "dracut-network", + "dracut-live": { + "Name": "dracut-live", "SupportedOS": [ { "Name": "RHEL", @@ -2661,16 +2622,16 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" }, { "Architecture": "aarch64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "dracut_na_rpm": { - "Name": "dracut", + "dracut-network": { + "Name": "dracut-network", "SupportedOS": [ { "Name": "RHEL", @@ -2693,7 +2654,7 @@ } ] }, - "emacs_na_rpm": { + "emacs": { "Name": "emacs", "SupportedOS": [ { @@ -2717,7 +2678,7 @@ } ] }, - "file_na_rpm": { + "file": { "Name": "file", "SupportedOS": [ { @@ -2741,7 +2702,7 @@ } ] }, - "findutils_na_rpm": { + "findutils": { "Name": "findutils", "SupportedOS": [ { @@ -2765,7 +2726,7 @@ } ] }, - "fping_na_rpm": { + "fping": { "Name": "fping", "SupportedOS": [ { @@ -2789,7 +2750,7 @@ } ] }, - "gawk_na_rpm": { + "gawk": { "Name": "gawk", "SupportedOS": [ { @@ -2813,8 +2774,8 @@ } ] }, - "gcc-c++_na_rpm": { - "Name": "gcc-c++", + "gcc": { + "Name": "gcc", "SupportedOS": [ { "Name": "RHEL", @@ -2837,8 +2798,8 @@ } ] }, - "gcc-gfortran_na_rpm": { - "Name": "gcc-gfortran", + "gcc-c++": { + "Name": "gcc-c++", "SupportedOS": [ { "Name": "RHEL", @@ -2861,8 +2822,8 @@ } ] }, - "gcc_na_rpm": { - "Name": "gcc", + "gcc-gfortran": { + "Name": "gcc-gfortran", "SupportedOS": [ { "Name": "RHEL", @@ -2885,8 +2846,8 @@ } ] }, - "gdb-gdbserver_na_rpm": { - "Name": "gdb-gdbserver", + "gdb": { + "Name": "gdb", "SupportedOS": [ { "Name": "RHEL", @@ -2909,8 +2870,8 @@ } ] }, - "gdb_na_rpm": { - "Name": "gdb", + "gdb-gdbserver": { + "Name": "gdb-gdbserver", "SupportedOS": [ { "Name": "RHEL", @@ -2933,7 +2894,7 @@ } ] }, - "gedit_na_rpm": { + "gedit": { "Name": "gedit", "SupportedOS": [ { @@ -2957,7 +2918,7 @@ } ] }, - "glibc-langpack-en_na_rpm": { + "glibc-langpack-en": { "Name": "glibc-langpack-en", "SupportedOS": [ { @@ -2981,7 +2942,7 @@ } ] }, - "grep_na_rpm": { + "grep": { "Name": "grep", "SupportedOS": [ { @@ -3005,7 +2966,7 @@ } ] }, - "gzip_na_rpm": { + "gzip": { "Name": "gzip", "SupportedOS": [ { @@ -3029,8 +2990,8 @@ } ] }, - "hwloc-libs_na_rpm": { - "Name": "hwloc-libs", + "hwloc": { + "Name": "hwloc", "SupportedOS": [ { "Name": "RHEL", @@ -3053,8 +3014,8 @@ } ] }, - "hwloc_na_rpm": { - "Name": "hwloc", + "hwloc-libs": { + "Name": "hwloc-libs", "SupportedOS": [ { "Name": "RHEL", @@ -3077,7 +3038,7 @@ } ] }, - "iperf3_na_rpm": { + "iperf3": { "Name": "iperf3", "SupportedOS": [ { @@ -3101,7 +3062,7 @@ } ] }, - "ipmitool_na_rpm": { + "ipmitool": { "Name": "ipmitool", "SupportedOS": [ { @@ -3125,7 +3086,7 @@ } ] }, - "iproute_na_rpm": { + "iproute": { "Name": "iproute", "SupportedOS": [ { @@ -3149,7 +3110,7 @@ } ] }, - "iputils_na_rpm": { + "iputils": { "Name": "iputils", "SupportedOS": [ { @@ -3173,7 +3134,7 @@ } ] }, - "kbd_na_rpm": { + "kbd": { "Name": "kbd", "SupportedOS": [ { @@ -3197,8 +3158,8 @@ } ] }, - "kernel-tools_na_rpm": { - "Name": "kernel-tools", + "kernel": { + "Name": "kernel", "SupportedOS": [ { "Name": "RHEL", @@ -3221,8 +3182,8 @@ } ] }, - "kernel_na_rpm": { - "Name": "kernel", + "kernel-tools": { + "Name": "kernel-tools", "SupportedOS": [ { "Name": "RHEL", @@ -3245,7 +3206,7 @@ } ] }, - "kexec-tools_na_rpm": { + "kexec-tools": { "Name": "kexec-tools", "SupportedOS": [ { @@ -3269,7 +3230,7 @@ } ] }, - "libcurl_na_rpm": { + "libcurl": { "Name": "libcurl", "SupportedOS": [ { @@ -3293,7 +3254,7 @@ } ] }, - "libtool_na_rpm": { + "libtool": { "Name": "libtool", "SupportedOS": [ { @@ -3317,8 +3278,8 @@ } ] }, - "lldb-devel_na_rpm": { - "Name": "lldb-devel", + "lldb": { + "Name": "lldb", "SupportedOS": [ { "Name": "RHEL", @@ -3341,8 +3302,8 @@ } ] }, - "lldb_na_rpm": { - "Name": "lldb", + "lldb-devel": { + "Name": "lldb-devel", "SupportedOS": [ { "Name": "RHEL", @@ -3365,7 +3326,7 @@ } ] }, - "lshw_na_rpm": { + "lshw": { "Name": "lshw", "SupportedOS": [ { @@ -3389,7 +3350,7 @@ } ] }, - "lsof_na_rpm": { + "lsof": { "Name": "lsof", "SupportedOS": [ { @@ -3413,7 +3374,7 @@ } ] }, - "ltrace_na_rpm": { + "ltrace": { "Name": "ltrace", "SupportedOS": [ { @@ -3437,7 +3398,7 @@ } ] }, - "lvm2_na_rpm": { + "lvm2": { "Name": "lvm2", "SupportedOS": [ { @@ -3461,7 +3422,7 @@ } ] }, - "make_na_rpm": { + "make": { "Name": "make", "SupportedOS": [ { @@ -3485,7 +3446,7 @@ } ] }, - "man-db_na_rpm": { + "man-db": { "Name": "man-db", "SupportedOS": [ { @@ -3509,7 +3470,7 @@ } ] }, - "man-pages_na_rpm": { + "man-pages": { "Name": "man-pages", "SupportedOS": [ { @@ -3533,7 +3494,7 @@ } ] }, - "munge-devel_na_rpm": { + "munge-devel": { "Name": "munge-devel", "SupportedOS": [ { @@ -3557,7 +3518,7 @@ } ] }, - "nfs-utils_na_rpm": { + "nfs-utils": { "Name": "nfs-utils", "SupportedOS": [ { @@ -3581,7 +3542,7 @@ } ] }, - "nfs4-acl-tools_na_rpm": { + "nfs4-acl-tools": { "Name": "nfs4-acl-tools", "SupportedOS": [ { @@ -3605,7 +3566,7 @@ } ] }, - "nm-connection-editor_na_rpm": { + "nm-connection-editor": { "Name": "nm-connection-editor", "SupportedOS": [ { @@ -3629,7 +3590,7 @@ } ] }, - "nss-pam-ldapd_na_rpm": { + "nss-pam-ldapd": { "Name": "nss-pam-ldapd", "SupportedOS": [ { @@ -3653,7 +3614,7 @@ } ] }, - "oddjob-mkhomedir_na_rpm": { + "oddjob-mkhomedir": { "Name": "oddjob-mkhomedir", "SupportedOS": [ { @@ -3677,7 +3638,7 @@ } ] }, - "openldap-clients_na_rpm": { + "openldap-clients": { "Name": "openldap-clients", "SupportedOS": [ { @@ -3701,7 +3662,7 @@ } ] }, - "openmpi_5.0.8_tarball": { + "openmpi": { "Name": "openmpi", "SupportedOS": [ { @@ -3726,8 +3687,8 @@ } ] }, - "openssh-clients_na_rpm": { - "Name": "openssh-clients", + "openssh": { + "Name": "openssh", "SupportedOS": [ { "Name": "RHEL", @@ -3750,8 +3711,8 @@ } ] }, - "openssh-server_na_rpm": { - "Name": "openssh-server", + "openssh-clients": { + "Name": "openssh-clients", "SupportedOS": [ { "Name": "RHEL", @@ -3774,8 +3735,8 @@ } ] }, - "openssh_na_rpm": { - "Name": "openssh", + "openssh-server": { + "Name": "openssh-server", "SupportedOS": [ { "Name": "RHEL", @@ -3798,7 +3759,7 @@ } ] }, - "openssl-devel_na_rpm": { + "openssl-devel": { "Name": "openssl-devel", "SupportedOS": [ { @@ -3822,7 +3783,7 @@ } ] }, - "openssl-libs_na_rpm": { + "openssl-libs": { "Name": "openssl-libs", "SupportedOS": [ { @@ -3846,7 +3807,7 @@ } ] }, - "ovis-ldms_na_rpm": { + "ovis-ldms": { "Name": "ovis-ldms", "SupportedOS": [ { @@ -3870,7 +3831,7 @@ } ] }, - "papi-devel_na_rpm": { + "papi-devel": { "Name": "papi-devel", "SupportedOS": [ { @@ -3894,7 +3855,7 @@ } ] }, - "papi-libs_na_rpm": { + "papi-libs": { "Name": "papi-libs", "SupportedOS": [ { @@ -3918,7 +3879,7 @@ } ] }, - "papi_na_rpm": { + "papi_1": { "Name": "papi", "SupportedOS": [ { @@ -3942,7 +3903,7 @@ } ] }, - "pciutils_na_rpm": { + "pciutils": { "Name": "pciutils", "SupportedOS": [ { @@ -3966,7 +3927,7 @@ } ] }, - "perf_na_rpm": { + "perf": { "Name": "perf", "SupportedOS": [ { @@ -3990,7 +3951,7 @@ } ] }, - "pmix-devel_na_rpm": { + "pmix-devel": { "Name": "pmix-devel", "SupportedOS": [ { @@ -4014,7 +3975,7 @@ } ] }, - "python3-cython_na_rpm": { + "python3-cython": { "Name": "python3-cython", "SupportedOS": [ { @@ -4038,7 +3999,7 @@ } ] }, - "python3-devel_na_rpm": { + "python3-devel": { "Name": "python3-devel", "SupportedOS": [ { @@ -4062,7 +4023,7 @@ } ] }, - "rsync_na_rpm": { + "rsync": { "Name": "rsync", "SupportedOS": [ { @@ -4086,7 +4047,7 @@ } ] }, - "rsyslog_na_rpm": { + "rsyslog": { "Name": "rsyslog", "SupportedOS": [ { @@ -4110,7 +4071,7 @@ } ] }, - "sed_na_rpm": { + "sed": { "Name": "sed", "SupportedOS": [ { @@ -4134,7 +4095,7 @@ } ] }, - "squashfs-tools_na_rpm": { + "squashfs-tools": { "Name": "squashfs-tools", "SupportedOS": [ { @@ -4158,7 +4119,7 @@ } ] }, - "sssd_na_rpm": { + "sssd": { "Name": "sssd", "SupportedOS": [ { @@ -4182,7 +4143,7 @@ } ] }, - "strace_na_rpm": { + "strace": { "Name": "strace", "SupportedOS": [ { @@ -4206,7 +4167,7 @@ } ] }, - "sudo_na_rpm": { + "sudo": { "Name": "sudo", "SupportedOS": [ { @@ -4230,8 +4191,8 @@ } ] }, - "systemd-udev_na_rpm": { - "Name": "systemd-udev", + "systemd": { + "Name": "systemd", "SupportedOS": [ { "Name": "RHEL", @@ -4254,8 +4215,8 @@ } ] }, - "systemd_na_rpm": { - "Name": "systemd", + "systemd-udev": { + "Name": "systemd-udev", "SupportedOS": [ { "Name": "RHEL", @@ -4278,7 +4239,7 @@ } ] }, - "tar_na_rpm": { + "tar": { "Name": "tar", "SupportedOS": [ { @@ -4302,7 +4263,7 @@ } ] }, - "tcpdump_na_rpm": { + "tcpdump": { "Name": "tcpdump", "SupportedOS": [ { @@ -4326,7 +4287,7 @@ } ] }, - "traceroute_na_rpm": { + "traceroute": { "Name": "traceroute", "SupportedOS": [ { @@ -4350,7 +4311,7 @@ } ] }, - "ucx_1.19.0_tarball": { + "ucx": { "Name": "ucx", "SupportedOS": [ { @@ -4375,7 +4336,7 @@ } ] }, - "util-linux_na_rpm": { + "util-linux": { "Name": "util-linux", "SupportedOS": [ { @@ -4399,8 +4360,8 @@ } ] }, - "valgrind-devel_na_rpm": { - "Name": "valgrind-devel", + "valgrind": { + "Name": "valgrind", "SupportedOS": [ { "Name": "RHEL", @@ -4423,8 +4384,8 @@ } ] }, - "valgrind_na_rpm": { - "Name": "valgrind", + "valgrind-devel": { + "Name": "valgrind-devel", "SupportedOS": [ { "Name": "RHEL", @@ -4447,7 +4408,7 @@ } ] }, - "vim-enhanced_na_rpm_1": { + "vim-enhanced_1": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -4471,7 +4432,7 @@ } ] }, - "wget_na_rpm": { + "wget": { "Name": "wget", "SupportedOS": [ { @@ -4495,7 +4456,7 @@ } ] }, - "which_na_rpm": { + "which": { "Name": "which", "SupportedOS": [ { @@ -4519,7 +4480,7 @@ } ] }, - "zsh_na_rpm": { + "zsh": { "Name": "zsh", "SupportedOS": [ { diff --git a/examples/catalog/catalog_rhel_x86_64.json b/examples/catalog/catalog_rhel_x86_64.json index e14c517ba7..a70b4f94aa 100644 --- a/examples/catalog/catalog_rhel_x86_64.json +++ b/examples/catalog/catalog_rhel_x86_64.json @@ -7,260 +7,259 @@ { "Name": "login_compiler_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "login_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "os_x86_64", "FunctionalPackages": [ - "openssl-libs_na_rpm", - "ovis-ldms_na_rpm", - "python3-cython_na_rpm", - "python3-devel_na_rpm" + "openssl-libs", + "ovis-ldms", + "python3-cython", + "python3-devel" ] }, { "Name": "service_kube_control_plane_x86_64", "FunctionalPackages": [ - "PyMySQL_1.1.2_pip_module", - "apptainer_na_rpm", - "calico-v3-31-4_na_manifest", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-calico-cni_v3.31.4_image", - "docker-io-calico-kube-controllers_v3.31.4_image", - "docker-io-calico-node_v3.31.4_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-kube-vip-kube-vip_v0.8.9_image", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "helm-v3-20-1-amd64_na_tarball", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubectl_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "metallb-native-v0-15-3_na_manifest", - "nfs-subdir-external-provisioner-4-0-18_na_tarball", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prettytable_3.14.0_pip_module", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "python3_3.12.9_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-coredns-coredns_v1.13.1_image", - "registry-k8s-io-etcd_3.6.6-0_image", - "registry-k8s-io-kube-apiserver_v1.35.1_image", - "registry-k8s-io-kube-controller-manager_v1.35.1_image", - "registry-k8s-io-kube-proxy_v1.35.1_image", - "registry-k8s-io-kube-scheduler_v1.35.1_image", - "registry-k8s-io-pause_3.10.1_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "PyMySQL", + "apptainer", + "calico", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/calico/cni", + "docker.io/calico/kube-controllers", + "docker.io/calico/node", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/kube-vip/kube-vip", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-amd64", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubectl", + "kubelet", + "kubernetes", + "lsscsi", + "metallb-native", + "nfs-subdir-external-provisioner", + "omsdk", + "podman", + "prettytable", + "prometheus_client", + "python3", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/coredns/coredns", + "registry.k8s.io/etcd", + "registry.k8s.io/kube-apiserver", + "registry.k8s.io/kube-controller-manager", + "registry.k8s.io/kube-proxy", + "registry.k8s.io/kube-scheduler", + "registry.k8s.io/pause", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "service_kube_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "cert-manager-v1-10-0_na_tarball", - "cffi_1.17.1_pip_module", - "container-selinux_na_rpm", - "cri-o_1.35.1_rpm", - "cryptography_45.0.7_pip_module", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "docker-io-alpine-kubectl_1.35.1_image", - "docker-io-curlimages-curl_8.17.0_image", - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image", - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image", - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image", - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image", - "docker-io-library-busybox_1.36_image", - "docker-io-library-mysql_9.3.0_image", - "docker-io-library-python_3.12-slim_image", - "docker-io-nginxinc-nginx-unprivileged_1.29_image", - "docker-io-rmohr-activemq_5.15.9_image", - "docker-io-timberio-vector_0.54.0-debian_image", - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image", - "docker-io-victoriametrics-operator_v0.68.3_image", - "docker-io-victoriametrics-victoria-logs_v1.50.0_image", - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image", - "docker-io-victoriametrics-vlagent_v1.50.0_image", - "docker-io-victoriametrics-vmagent_v1.128.0_image", - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image", - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image", - "firewalld_na_rpm", - "fuse-overlayfs_na_rpm", - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image", - "git_na_rpm", - "helm-charts_container-storage-modules-1.9.2_git", - "iscsi-initiator-utils_na_rpm", - "karavi-observability_v1.12.0_git", - "kubeadm_1.35.1_rpm", - "kubelet_1.35.1_rpm", - "kubernetes_33.1.0_pip_module", - "lsscsi_na_rpm", - "omsdk_1.2.518_pip_module", - "podman_na_rpm", - "prometheus_client_0.20.0_pip_module", - "python3-firewall_na_rpm", - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image", - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image", - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image", - "quay-io-jetstack-cert-manager-controller_v1.10.0_image", - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image", - "quay-io-metallb-controller_v0.15.3_image", - "quay-io-metallb-speaker_v0.15.3_image", - "quay-io-strimzi-kafka-bridge_0.33.1_image", - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image", - "quay-io-strimzi-operator_0.48.0_image", - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image", - "sg3_utils_na_rpm", - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball", - "victoria-metrics-operator-0-59-3_na_tarball", - "vim-enhanced_na_rpm" + "apptainer", + "cert-manager", + "cffi", + "container-selinux", + "cri-o", + "cryptography", + "device-mapper-multipath", + "doca-ofed", + "docker.io/alpine/kubectl", + "docker.io/curlimages/curl", + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", + "docker.io/dellhpcomniaaisolution/kafkapump", + "docker.io/dellhpcomniaaisolution/ubuntu-ldms", + "docker.io/dellhpcomniaaisolution/victoriapump", + "docker.io/library/busybox", + "docker.io/library/mysql", + "docker.io/library/python", + "docker.io/nginxinc/nginx-unprivileged", + "docker.io/rmohr/activemq", + "docker.io/timberio/vector", + "docker.io/victoriametrics/operator", + "docker.io/victoriametrics/operator_1", + "docker.io/victoriametrics/victoria-logs", + "docker.io/victoriametrics/victoria-metrics", + "docker.io/victoriametrics/vlagent", + "docker.io/victoriametrics/vmagent", + "docker.io/victoriametrics/vminsert", + "docker.io/victoriametrics/vmselect", + "docker.io/victoriametrics/vmstorage", + "firewalld", + "fuse-overlayfs", + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", + "git", + "helm-charts", + "iscsi-initiator-utils", + "karavi-observability", + "kubeadm", + "kubelet", + "kubernetes", + "lsscsi", + "omsdk", + "podman", + "prometheus_client", + "python3-firewall", + "quay.io/dell/container-storage-modules/csm-metrics-powerscale", + "quay.io/jetstack/cert-manager-acmesolver", + "quay.io/jetstack/cert-manager-cainjector", + "quay.io/jetstack/cert-manager-controller", + "quay.io/jetstack/cert-manager-webhook", + "quay.io/metallb/controller", + "quay.io/metallb/speaker", + "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/operator", + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", + "sg3_utils", + "strimzi-kafka-operator-helm-3-chart", + "victoria-metrics-operator", + "vim-enhanced" ] }, { "Name": "slurm_control_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "mariadb-server_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-PyMySQL_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmctld_na_rpm", - "slurm-slurmdbd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "mariadb-server", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-PyMySQL", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-slurmctld", + "slurm-slurmdbd" ] }, { "Name": "slurm_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "kernel-devel_na_rpm", - "kernel-headers_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-pam_slurm_na_rpm", - "slurm-slurmd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "kernel-devel", + "kernel-headers", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-pam_slurm", + "slurm-slurmd" ] } ], @@ -269,105 +268,105 @@ "Name": "RHEL", "Version": "10.0", "osPackages": [ - "NetworkManager_na_rpm", - "authselect_na_rpm", - "autoconf_na_rpm", - "automake_na_rpm", - "bash-completion_na_rpm", - "bash_na_rpm", - "binutils-devel_na_rpm", - "binutils_na_rpm", - "bzip2_na_rpm", - "chrony_na_rpm", - "cloud-init_na_rpm", - "clustershell_na_rpm", - "cmake_na_rpm", - "coreutils_na_rpm", - "cryptsetup_na_rpm", - "curl_na_rpm", - "device-mapper_na_rpm", - "dmidecode_na_rpm", - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image", - "dracut-live_na_rpm", - "dracut-network_na_rpm", - "dracut_na_rpm", - "emacs_na_rpm", - "file_na_rpm", - "findutils_na_rpm", - "fping_na_rpm", - "gawk_na_rpm", - "gcc-c++_na_rpm", - "gcc-gfortran_na_rpm", - "gcc_na_rpm", - "gdb-gdbserver_na_rpm", - "gdb_na_rpm", - "gedit_na_rpm", - "glibc-langpack-en_na_rpm", - "grep_na_rpm", - "gzip_na_rpm", - "hwloc-libs_na_rpm", - "hwloc_na_rpm", - "iperf3_na_rpm", - "ipmitool_na_rpm", - "iproute_na_rpm", - "iputils_na_rpm", - "kbd_na_rpm", - "kernel-tools_na_rpm", - "kernel_na_rpm", - "kexec-tools_na_rpm", - "libcurl_na_rpm", - "libtool_na_rpm", - "lldb-devel_na_rpm", - "lldb_na_rpm", - "lshw_na_rpm", - "lsof_na_rpm", - "ltrace_na_rpm", - "lvm2_na_rpm", - "make_na_rpm", - "man-db_na_rpm", - "man-pages_na_rpm", - "munge-devel_na_rpm", - "nfs-utils_na_rpm", - "nfs4-acl-tools_na_rpm", - "nm-connection-editor_na_rpm", - "nss-pam-ldapd_na_rpm", - "oddjob-mkhomedir_na_rpm", - "openldap-clients_na_rpm", - "openmpi_5.0.8_tarball", - "openssh-clients_na_rpm", - "openssh-server_na_rpm", - "openssh_na_rpm", - "openssl-devel_na_rpm", - "openssl-libs_na_rpm_1", - "ovis-ldms_na_rpm_1", - "papi-devel_na_rpm", - "papi-libs_na_rpm", - "papi_na_rpm", - "pciutils_na_rpm", - "perf_na_rpm", - "pmix-devel_na_rpm", - "python3-cython_na_rpm_1", - "python3-devel_na_rpm_1", - "rsync_na_rpm", - "rsyslog_na_rpm", - "sed_na_rpm", - "squashfs-tools_na_rpm", - "sssd_na_rpm", - "strace_na_rpm", - "sudo_na_rpm", - "systemd-udev_na_rpm", - "systemd_na_rpm", - "tar_na_rpm", - "tcpdump_na_rpm", - "traceroute_na_rpm", - "ucx_1.19.0_tarball", - "util-linux_na_rpm", - "valgrind-devel_na_rpm", - "valgrind_na_rpm", - "vim-enhanced_na_rpm_1", - "wget_na_rpm", - "which_na_rpm", - "zsh_na_rpm" + "NetworkManager", + "authselect", + "autoconf", + "automake", + "bash", + "bash-completion", + "binutils", + "binutils-devel", + "bzip2", + "chrony", + "cloud-init", + "clustershell", + "cmake", + "coreutils", + "cryptsetup", + "curl", + "device-mapper", + "dmidecode", + "docker.io/dellhpcomniaaisolution/image-build-el10", + "dracut", + "dracut-live", + "dracut-network", + "emacs", + "file", + "findutils", + "fping", + "gawk", + "gcc", + "gcc-c++", + "gcc-gfortran", + "gdb", + "gdb-gdbserver", + "gedit", + "glibc-langpack-en", + "grep", + "gzip", + "hwloc", + "hwloc-libs", + "iperf3", + "ipmitool", + "iproute", + "iputils", + "kbd", + "kernel", + "kernel-tools", + "kexec-tools", + "libcurl", + "libtool", + "lldb", + "lldb-devel", + "lshw", + "lsof", + "ltrace", + "lvm2", + "make", + "man-db", + "man-pages", + "munge-devel", + "nfs-utils", + "nfs4-acl-tools", + "nm-connection-editor", + "nss-pam-ldapd", + "oddjob-mkhomedir", + "openldap-clients", + "openmpi", + "openssh", + "openssh-clients", + "openssh-server", + "openssl-devel", + "openssl-libs_1", + "ovis-ldms_1", + "papi-devel", + "papi-libs", + "papi_1", + "pciutils", + "perf", + "pmix-devel", + "python3-cython_1", + "python3-devel_1", + "rsync", + "rsyslog", + "sed", + "squashfs-tools", + "sssd", + "strace", + "sudo", + "systemd", + "systemd-udev", + "tar", + "tcpdump", + "traceroute", + "ucx", + "util-linux", + "valgrind", + "valgrind-devel", + "vim-enhanced_1", + "wget", + "which", + "zsh" ] } ], @@ -375,29 +374,29 @@ { "Name": "csi", "InfrastructurePackages": [ - "csi-powerscale-v2-16-0_v2.16.0_git", - "docker-io-dellemc-csm-encryption_v0.6.0_image", - "external-snapshotter-v8-4-0_v8.4.0_git", - "helm-charts-2-16-0_csi-isilon-2.16.0_git", - "quay-io-dell-container-storage-modules-csi-isilon_v2.16.0_image", - "quay-io-dell-container-storage-modules-csi-metadat_v1.13.0_image", - "quay-io-dell-container-storage-modules-csm-authori_v2.4.0_image", - "quay-io-dell-container-storage-modules-dell-csi-re_v1.14.0_image", - "quay-io-dell-container-storage-modules-podmon_v1.15.0_image", - "registry-k8s-io-sig-storage-csi-attacher_v4.10.0_image", - "registry-k8s-io-sig-storage-csi-external-health-mo_v0.16.0_image", - "registry-k8s-io-sig-storage-csi-node-driver-regist_v2.15.0_image", - "registry-k8s-io-sig-storage-csi-provisioner_v6.1.0_image", - "registry-k8s-io-sig-storage-csi-resizer_v2.0.0_image", - "registry-k8s-io-sig-storage-csi-snapshotter_v8.4.0_image", - "registry-k8s-io-sig-storage-snapshot-controller_v8.4.0_image" + "csi-powerscale", + "docker.io/dellemc/csm-encryption", + "external-snapshotter", + "helm-charts_1", + "quay.io/dell/container-storage-modules/csi-isilon", + "quay.io/dell/container-storage-modules/csi-metadata-retriever", + "quay.io/dell/container-storage-modules/csm-authorization-sidecar", + "quay.io/dell/container-storage-modules/dell-csi-replicator", + "quay.io/dell/container-storage-modules/podmon", + "registry.k8s.io/sig-storage/csi-attacher", + "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", + "registry.k8s.io/sig-storage/csi-node-driver-registrar", + "registry.k8s.io/sig-storage/csi-provisioner", + "registry.k8s.io/sig-storage/csi-resizer", + "registry.k8s.io/sig-storage/csi-snapshotter", + "registry.k8s.io/sig-storage/snapshot-controller" ] } ], "Drivers": [], "DriverPackages": {}, "FunctionalPackages": { - "PyMySQL_1.1.2_pip_module": { + "PyMySQL": { "Name": "PyMySQL==1.1.2", "SupportedOS": [ { @@ -410,7 +409,7 @@ ], "Type": "pip_module" }, - "apptainer_na_rpm": { + "apptainer": { "Name": "apptainer", "SupportedOS": [ { @@ -429,7 +428,7 @@ } ] }, - "calico-v3-31-4_na_manifest": { + "calico": { "Name": "calico-v3.31.4", "SupportedOS": [ { @@ -448,7 +447,7 @@ } ] }, - "cert-manager-v1-10-0_na_tarball": { + "cert-manager": { "Name": "cert-manager-v1.10.0", "SupportedOS": [ { @@ -467,7 +466,7 @@ } ] }, - "cffi_1.17.1_pip_module": { + "cffi": { "Name": "cffi==1.17.1", "SupportedOS": [ { @@ -480,7 +479,7 @@ ], "Type": "pip_module" }, - "container-selinux_na_rpm": { + "container-selinux": { "Name": "container-selinux", "SupportedOS": [ { @@ -499,7 +498,7 @@ } ] }, - "cri-o_1.35.1_rpm": { + "cri-o": { "Name": "cri-o-1.35.1", "SupportedOS": [ { @@ -518,7 +517,7 @@ } ] }, - "cryptography_45.0.7_pip_module": { + "cryptography": { "Name": "cryptography==45.0.7", "SupportedOS": [ { @@ -531,7 +530,7 @@ ], "Type": "pip_module" }, - "device-mapper-multipath_na_rpm": { + "device-mapper-multipath": { "Name": "device-mapper-multipath", "SupportedOS": [ { @@ -550,7 +549,7 @@ } ] }, - "doca-ofed_na_rpm_repo": { + "doca-ofed": { "Name": "doca-ofed", "SupportedOS": [ { @@ -569,7 +568,7 @@ } ] }, - "docker-io-alpine-kubectl_1.35.1_image": { + "docker.io/alpine/kubectl": { "Name": "docker.io/alpine/kubectl", "SupportedOS": [ { @@ -584,7 +583,7 @@ "Tag": "1.35.1", "Version": "1.35.1" }, - "docker-io-calico-cni_v3.31.4_image": { + "docker.io/calico/cni": { "Name": "docker.io/calico/cni", "SupportedOS": [ { @@ -599,7 +598,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-kube-controllers_v3.31.4_image": { + "docker.io/calico/kube-controllers": { "Name": "docker.io/calico/kube-controllers", "SupportedOS": [ { @@ -614,7 +613,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-calico-node_v3.31.4_image": { + "docker.io/calico/node": { "Name": "docker.io/calico/node", "SupportedOS": [ { @@ -629,7 +628,7 @@ "Tag": "v3.31.4", "Version": "v3.31.4" }, - "docker-io-curlimages-curl_8.17.0_image": { + "docker.io/curlimages/curl": { "Name": "docker.io/curlimages/curl", "SupportedOS": [ { @@ -644,7 +643,7 @@ "Tag": "8.17.0", "Version": "8.17.0" }, - "docker-io-dellhpcomniaaisolution-idrac_telemetry_r_1.3_image": { + "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver": { "Name": "docker.io/dellhpcomniaaisolution/idrac_telemetry_receiver", "SupportedOS": [ { @@ -659,7 +658,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-kafkapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/kafkapump": { "Name": "docker.io/dellhpcomniaaisolution/kafkapump", "SupportedOS": [ { @@ -674,7 +673,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-dellhpcomniaaisolution-ubuntu-ldms_1.1_image": { + "docker.io/dellhpcomniaaisolution/ubuntu-ldms": { "Name": "docker.io/dellhpcomniaaisolution/ubuntu-ldms", "SupportedOS": [ { @@ -689,7 +688,7 @@ "Tag": "1.1", "Version": "1.1" }, - "docker-io-dellhpcomniaaisolution-victoriapump_1.3_image": { + "docker.io/dellhpcomniaaisolution/victoriapump": { "Name": "docker.io/dellhpcomniaaisolution/victoriapump", "SupportedOS": [ { @@ -704,7 +703,7 @@ "Tag": "1.3", "Version": "1.3" }, - "docker-io-library-busybox_1.36_image": { + "docker.io/library/busybox": { "Name": "docker.io/library/busybox", "SupportedOS": [ { @@ -719,7 +718,7 @@ "Tag": "1.36", "Version": "1.36" }, - "docker-io-library-mysql_9.3.0_image": { + "docker.io/library/mysql": { "Name": "docker.io/library/mysql", "SupportedOS": [ { @@ -734,7 +733,7 @@ "Tag": "9.3.0", "Version": "9.3.0" }, - "docker-io-library-python_3.12-slim_image": { + "docker.io/library/python": { "Name": "docker.io/library/python", "SupportedOS": [ { @@ -749,7 +748,7 @@ "Tag": "3.12-slim", "Version": "3.12-slim" }, - "docker-io-nginxinc-nginx-unprivileged_1.29_image": { + "docker.io/nginxinc/nginx-unprivileged": { "Name": "docker.io/nginxinc/nginx-unprivileged", "SupportedOS": [ { @@ -764,7 +763,7 @@ "Tag": "1.29", "Version": "1.29" }, - "docker-io-rmohr-activemq_5.15.9_image": { + "docker.io/rmohr/activemq": { "Name": "docker.io/rmohr/activemq", "SupportedOS": [ { @@ -779,7 +778,7 @@ "Tag": "5.15.9", "Version": "5.15.9" }, - "docker-io-timberio-vector_0.54.0-debian_image": { + "docker.io/timberio/vector": { "Name": "docker.io/timberio/vector", "SupportedOS": [ { @@ -794,7 +793,7 @@ "Tag": "0.54.0-debian", "Version": "0.54.0-debian" }, - "docker-io-victoriametrics-operator_config-reloader-v0.68.3_image": { + "docker.io/victoriametrics/operator": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -806,10 +805,10 @@ "x86_64" ], "Type": "image", - "Tag": "config-reloader-v0.68.3", - "Version": "config-reloader-v0.68.3" + "Tag": "v0.68.3", + "Version": "v0.68.3" }, - "docker-io-victoriametrics-operator_v0.68.3_image": { + "docker.io/victoriametrics/operator_1": { "Name": "docker.io/victoriametrics/operator", "SupportedOS": [ { @@ -821,10 +820,10 @@ "x86_64" ], "Type": "image", - "Tag": "v0.68.3", - "Version": "v0.68.3" + "Tag": "config-reloader-v0.68.3", + "Version": "config-reloader-v0.68.3" }, - "docker-io-victoriametrics-victoria-logs_v1.50.0_image": { + "docker.io/victoriametrics/victoria-logs": { "Name": "docker.io/victoriametrics/victoria-logs", "SupportedOS": [ { @@ -839,7 +838,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-victoria-metrics_v1.128.0_image": { + "docker.io/victoriametrics/victoria-metrics": { "Name": "docker.io/victoriametrics/victoria-metrics", "SupportedOS": [ { @@ -854,7 +853,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vlagent_v1.50.0_image": { + "docker.io/victoriametrics/vlagent": { "Name": "docker.io/victoriametrics/vlagent", "SupportedOS": [ { @@ -869,7 +868,7 @@ "Tag": "v1.50.0", "Version": "v1.50.0" }, - "docker-io-victoriametrics-vmagent_v1.128.0_image": { + "docker.io/victoriametrics/vmagent": { "Name": "docker.io/victoriametrics/vmagent", "SupportedOS": [ { @@ -884,7 +883,7 @@ "Tag": "v1.128.0", "Version": "v1.128.0" }, - "docker-io-victoriametrics-vminsert_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vminsert": { "Name": "docker.io/victoriametrics/vminsert", "SupportedOS": [ { @@ -899,7 +898,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmselect_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmselect": { "Name": "docker.io/victoriametrics/vmselect", "SupportedOS": [ { @@ -914,7 +913,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "docker-io-victoriametrics-vmstorage_v1.128.0-cluster_image": { + "docker.io/victoriametrics/vmstorage": { "Name": "docker.io/victoriametrics/vmstorage", "SupportedOS": [ { @@ -929,7 +928,7 @@ "Tag": "v1.128.0-cluster", "Version": "v1.128.0-cluster" }, - "firewalld_na_rpm": { + "firewalld": { "Name": "firewalld", "SupportedOS": [ { @@ -948,7 +947,7 @@ } ] }, - "fuse-overlayfs_na_rpm": { + "fuse-overlayfs": { "Name": "fuse-overlayfs", "SupportedOS": [ { @@ -967,7 +966,7 @@ } ] }, - "geopm_na_tarball": { + "geopm": { "Name": "geopm", "SupportedOS": [ { @@ -986,7 +985,7 @@ } ] }, - "ghcr-io-kube-vip-kube-vip_v0.8.9_image": { + "ghcr.io/kube-vip/kube-vip": { "Name": "ghcr.io/kube-vip/kube-vip", "SupportedOS": [ { @@ -1001,7 +1000,7 @@ "Tag": "v0.8.9", "Version": "v0.8.9" }, - "ghcr-io-open-telemetry-opentelemetry-collector-rel_0.143.1_image": { + "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector": { "Name": "ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector", "SupportedOS": [ { @@ -1016,7 +1015,7 @@ "Tag": "0.143.1", "Version": "0.143.1" }, - "git_na_rpm": { + "git": { "Name": "git", "SupportedOS": [ { @@ -1035,8 +1034,8 @@ } ] }, - "helm-charts_container-storage-modules-1.9.2_git": { - "Name": "helm-charts", + "helm-amd64": { + "Name": "helm-v3.20.1-amd64", "SupportedOS": [ { "Name": "RHEL", @@ -1046,17 +1045,16 @@ "Architecture": [ "x86_64" ], - "Type": "git", - "Version": "container-storage-modules-1.9.2", + "Type": "tarball", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://github.com/dell/helm-charts.git" + "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" } ] }, - "helm-v3-20-1-amd64_na_tarball": { - "Name": "helm-v3.20.1-amd64", + "helm-charts": { + "Name": "helm-charts", "SupportedOS": [ { "Name": "RHEL", @@ -1066,15 +1064,16 @@ "Architecture": [ "x86_64" ], - "Type": "tarball", + "Type": "git", + "Version": "container-storage-modules-1.9.2", "Sources": [ { "Architecture": "x86_64", - "Uri": "https://get.helm.sh/helm-v3.20.1-linux-amd64.tar.gz" + "Uri": "https://github.com/dell/helm-charts.git" } ] }, - "imb_na_tarball": { + "imb": { "Name": "imb", "SupportedOS": [ { @@ -1093,7 +1092,7 @@ } ] }, - "iscsi-initiator-utils_na_rpm": { + "iscsi-initiator-utils": { "Name": "iscsi-initiator-utils", "SupportedOS": [ { @@ -1112,7 +1111,7 @@ } ] }, - "karavi-observability_v1.12.0_git": { + "karavi-observability": { "Name": "karavi-observability", "SupportedOS": [ { @@ -1132,7 +1131,7 @@ } ] }, - "kernel-devel_na_rpm": { + "kernel-devel": { "Name": "kernel-devel", "SupportedOS": [ { @@ -1151,7 +1150,7 @@ } ] }, - "kernel-headers_na_rpm": { + "kernel-headers": { "Name": "kernel-headers", "SupportedOS": [ { @@ -1170,7 +1169,7 @@ } ] }, - "kubeadm_1.35.1_rpm": { + "kubeadm": { "Name": "kubeadm-1.35.1", "SupportedOS": [ { @@ -1189,7 +1188,7 @@ } ] }, - "kubectl_1.35.1_rpm": { + "kubectl": { "Name": "kubectl-1.35.1", "SupportedOS": [ { @@ -1208,7 +1207,7 @@ } ] }, - "kubelet_1.35.1_rpm": { + "kubelet": { "Name": "kubelet-1.35.1", "SupportedOS": [ { @@ -1227,7 +1226,7 @@ } ] }, - "kubernetes_33.1.0_pip_module": { + "kubernetes": { "Name": "kubernetes==33.1.0", "SupportedOS": [ { @@ -1240,7 +1239,7 @@ ], "Type": "pip_module" }, - "likwid_na_tarball": { + "likwid": { "Name": "likwid", "SupportedOS": [ { @@ -1259,7 +1258,7 @@ } ] }, - "lsscsi_na_rpm": { + "lsscsi": { "Name": "lsscsi", "SupportedOS": [ { @@ -1278,7 +1277,7 @@ } ] }, - "mariadb-server_na_rpm": { + "mariadb-server": { "Name": "mariadb-server", "SupportedOS": [ { @@ -1297,7 +1296,7 @@ } ] }, - "metallb-native-v0-15-3_na_manifest": { + "metallb-native": { "Name": "metallb-native-v0.15.3", "SupportedOS": [ { @@ -1316,7 +1315,7 @@ } ] }, - "msr-safe_na_tarball": { + "msr-safe": { "Name": "msr-safe", "SupportedOS": [ { @@ -1335,7 +1334,7 @@ } ] }, - "munge_na_rpm": { + "munge": { "Name": "munge", "SupportedOS": [ { @@ -1354,7 +1353,7 @@ } ] }, - "nfs-subdir-external-provisioner-4-0-18_na_tarball": { + "nfs-subdir-external-provisioner": { "Name": "nfs-subdir-external-provisioner-4.0.18", "SupportedOS": [ { @@ -1373,7 +1372,7 @@ } ] }, - "nvcr-io-nvidia-hpc-benchmarks_25.09_image": { + "nvcr.io/nvidia/hpc-benchmarks": { "Name": "nvcr.io/nvidia/hpc-benchmarks", "SupportedOS": [ { @@ -1388,26 +1387,7 @@ "Tag": "25.09", "Version": "25.09" }, - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "x86_64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "x86_64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } - ] - }, - "omsdk_1.2.518_pip_module": { + "omsdk": { "Name": "omsdk==1.2.518", "SupportedOS": [ { @@ -1420,7 +1400,7 @@ ], "Type": "pip_module" }, - "openssl-libs_na_rpm": { + "openssl-libs": { "Name": "openssl-libs", "SupportedOS": [ { @@ -1439,7 +1419,7 @@ } ] }, - "osu-micro-benchmarks_na_tarball": { + "osu-micro-benchmarks": { "Name": "osu-micro-benchmarks", "SupportedOS": [ { @@ -1458,7 +1438,7 @@ } ] }, - "ovis-ldms_na_rpm": { + "ovis-ldms": { "Name": "ovis-ldms", "SupportedOS": [ { @@ -1477,7 +1457,7 @@ } ] }, - "papi_na_tarball": { + "papi": { "Name": "papi", "SupportedOS": [ { @@ -1496,7 +1476,7 @@ } ] }, - "pmix_na_rpm": { + "pmix": { "Name": "pmix", "SupportedOS": [ { @@ -1515,7 +1495,7 @@ } ] }, - "podman_na_rpm": { + "podman": { "Name": "podman", "SupportedOS": [ { @@ -1534,7 +1514,7 @@ } ] }, - "prettytable_3.14.0_pip_module": { + "prettytable": { "Name": "prettytable==3.14.0", "SupportedOS": [ { @@ -1547,7 +1527,7 @@ ], "Type": "pip_module" }, - "prometheus_client_0.20.0_pip_module": { + "prometheus_client": { "Name": "prometheus_client==0.20.0", "SupportedOS": [ { @@ -1560,8 +1540,8 @@ ], "Type": "pip_module" }, - "python3-PyMySQL_na_rpm": { - "Name": "python3-PyMySQL", + "python3": { + "Name": "python3-3.12.9", "SupportedOS": [ { "Name": "RHEL", @@ -1575,12 +1555,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "python3-cython_na_rpm": { - "Name": "python3-cython", + "python3-PyMySQL": { + "Name": "python3-PyMySQL", "SupportedOS": [ { "Name": "RHEL", @@ -1594,12 +1574,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "codeready-builder" + "RepoName": "appstream" } ] }, - "python3-devel_na_rpm": { - "Name": "python3-devel", + "python3-cython": { + "Name": "python3-cython", "SupportedOS": [ { "Name": "RHEL", @@ -1613,12 +1593,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "codeready-builder" } ] }, - "python3-firewall_na_rpm": { - "Name": "python3-firewall", + "python3-devel": { + "Name": "python3-devel", "SupportedOS": [ { "Name": "RHEL", @@ -1632,12 +1612,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "python3_3.12.9_rpm": { - "Name": "python3-3.12.9", + "python3-firewall": { + "Name": "python3-firewall", "SupportedOS": [ { "Name": "RHEL", @@ -1655,7 +1635,7 @@ } ] }, - "quay-io-dell-container-storage-modules-csm-metrics_v1.11.0_image": { + "quay.io/dell/container-storage-modules/csm-metrics-powerscale": { "Name": "quay.io/dell/container-storage-modules/csm-metrics-powerscale", "SupportedOS": [ { @@ -1670,7 +1650,7 @@ "Tag": "v1.11.0", "Version": "v1.11.0" }, - "quay-io-jetstack-cert-manager-acmesolver_v1.10.0_image": { + "quay.io/jetstack/cert-manager-acmesolver": { "Name": "quay.io/jetstack/cert-manager-acmesolver", "SupportedOS": [ { @@ -1685,7 +1665,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-cainjector_v1.10.0_image": { + "quay.io/jetstack/cert-manager-cainjector": { "Name": "quay.io/jetstack/cert-manager-cainjector", "SupportedOS": [ { @@ -1700,7 +1680,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-controller_v1.10.0_image": { + "quay.io/jetstack/cert-manager-controller": { "Name": "quay.io/jetstack/cert-manager-controller", "SupportedOS": [ { @@ -1715,7 +1695,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-jetstack-cert-manager-webhook_v1.10.0_image": { + "quay.io/jetstack/cert-manager-webhook": { "Name": "quay.io/jetstack/cert-manager-webhook", "SupportedOS": [ { @@ -1730,7 +1710,7 @@ "Tag": "v1.10.0", "Version": "v1.10.0" }, - "quay-io-metallb-controller_v0.15.3_image": { + "quay.io/metallb/controller": { "Name": "quay.io/metallb/controller", "SupportedOS": [ { @@ -1745,7 +1725,7 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-metallb-speaker_v0.15.3_image": { + "quay.io/metallb/speaker": { "Name": "quay.io/metallb/speaker", "SupportedOS": [ { @@ -1760,8 +1740,8 @@ "Tag": "v0.15.3", "Version": "v0.15.3" }, - "quay-io-strimzi-kafka-bridge_0.33.1_image": { - "Name": "quay.io/strimzi/kafka-bridge", + "quay.io/strimzi/kafka": { + "Name": "quay.io/strimzi/kafka", "SupportedOS": [ { "Name": "RHEL", @@ -1772,11 +1752,11 @@ "x86_64" ], "Type": "image", - "Tag": "0.33.1", - "Version": "0.33.1" + "Tag": "0.48.0-kafka-4.1.0", + "Version": "0.48.0-kafka-4.1.0" }, - "quay-io-strimzi-kafka_0.48.0-kafka-4.1.0_image": { - "Name": "quay.io/strimzi/kafka", + "quay.io/strimzi/kafka-bridge": { + "Name": "quay.io/strimzi/kafka-bridge", "SupportedOS": [ { "Name": "RHEL", @@ -1787,10 +1767,10 @@ "x86_64" ], "Type": "image", - "Tag": "0.48.0-kafka-4.1.0", - "Version": "0.48.0-kafka-4.1.0" + "Tag": "0.33.1", + "Version": "0.33.1" }, - "quay-io-strimzi-operator_0.48.0_image": { + "quay.io/strimzi/operator": { "Name": "quay.io/strimzi/operator", "SupportedOS": [ { @@ -1805,7 +1785,7 @@ "Tag": "0.48.0", "Version": "0.48.0" }, - "registry-k8s-io-coredns-coredns_v1.13.1_image": { + "registry.k8s.io/coredns/coredns": { "Name": "registry.k8s.io/coredns/coredns", "SupportedOS": [ { @@ -1820,7 +1800,7 @@ "Tag": "v1.13.1", "Version": "v1.13.1" }, - "registry-k8s-io-etcd_3.6.6-0_image": { + "registry.k8s.io/etcd": { "Name": "registry.k8s.io/etcd", "SupportedOS": [ { @@ -1835,7 +1815,7 @@ "Tag": "3.6.6-0", "Version": "3.6.6-0" }, - "registry-k8s-io-kube-apiserver_v1.35.1_image": { + "registry.k8s.io/kube-apiserver": { "Name": "registry.k8s.io/kube-apiserver", "SupportedOS": [ { @@ -1850,7 +1830,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-controller-manager_v1.35.1_image": { + "registry.k8s.io/kube-controller-manager": { "Name": "registry.k8s.io/kube-controller-manager", "SupportedOS": [ { @@ -1865,7 +1845,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-proxy_v1.35.1_image": { + "registry.k8s.io/kube-proxy": { "Name": "registry.k8s.io/kube-proxy", "SupportedOS": [ { @@ -1880,7 +1860,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-kube-scheduler_v1.35.1_image": { + "registry.k8s.io/kube-scheduler": { "Name": "registry.k8s.io/kube-scheduler", "SupportedOS": [ { @@ -1895,7 +1875,7 @@ "Tag": "v1.35.1", "Version": "v1.35.1" }, - "registry-k8s-io-pause_3.10.1_image": { + "registry.k8s.io/pause": { "Name": "registry.k8s.io/pause", "SupportedOS": [ { @@ -1910,7 +1890,7 @@ "Tag": "3.10.1", "Version": "3.10.1" }, - "registry-k8s-io-sig-storage-nfs-subdir-external-pr_v4.0.2_image": { + "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner": { "Name": "registry.k8s.io/sig-storage/nfs-subdir-external-provisioner", "SupportedOS": [ { @@ -1925,7 +1905,7 @@ "Tag": "v4.0.2", "Version": "v4.0.2" }, - "sg3_utils_na_rpm": { + "sg3_utils": { "Name": "sg3_utils", "SupportedOS": [ { @@ -1944,7 +1924,7 @@ } ] }, - "sionlib_na_tarball": { + "sionlib": { "Name": "sionlib", "SupportedOS": [ { @@ -1963,8 +1943,8 @@ } ] }, - "slurm-pam_slurm_na_rpm": { - "Name": "slurm-pam_slurm", + "slurm": { + "Name": "slurm", "SupportedOS": [ { "Name": "RHEL", @@ -1982,8 +1962,8 @@ } ] }, - "slurm-slurmctld_na_rpm": { - "Name": "slurm-slurmctld", + "slurm-pam_slurm": { + "Name": "slurm-pam_slurm", "SupportedOS": [ { "Name": "RHEL", @@ -2001,8 +1981,8 @@ } ] }, - "slurm-slurmd_na_rpm": { - "Name": "slurm-slurmd", + "slurm-slurmctld": { + "Name": "slurm-slurmctld", "SupportedOS": [ { "Name": "RHEL", @@ -2020,8 +2000,8 @@ } ] }, - "slurm-slurmdbd_na_rpm": { - "Name": "slurm-slurmdbd", + "slurm-slurmd": { + "Name": "slurm-slurmd", "SupportedOS": [ { "Name": "RHEL", @@ -2039,8 +2019,8 @@ } ] }, - "slurm_na_rpm": { - "Name": "slurm", + "slurm-slurmdbd": { + "Name": "slurm-slurmdbd", "SupportedOS": [ { "Name": "RHEL", @@ -2058,7 +2038,7 @@ } ] }, - "strimzi-kafka-operator-helm-3-chart-0-48-0_na_tarball": { + "strimzi-kafka-operator-helm-3-chart": { "Name": "strimzi-kafka-operator-helm-3-chart-0.48.0", "SupportedOS": [ { @@ -2077,7 +2057,7 @@ } ] }, - "victoria-metrics-operator-0-59-3_na_tarball": { + "victoria-metrics-operator": { "Name": "victoria-metrics-operator-0.59.3", "SupportedOS": [ { @@ -2096,7 +2076,7 @@ } ] }, - "vim-enhanced_na_rpm": { + "vim-enhanced": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -2117,7 +2097,7 @@ } }, "OSPackages": { - "NetworkManager_na_rpm": { + "NetworkManager": { "Name": "NetworkManager", "SupportedOS": [ { @@ -2136,7 +2116,7 @@ } ] }, - "authselect_na_rpm": { + "authselect": { "Name": "authselect", "SupportedOS": [ { @@ -2155,7 +2135,7 @@ } ] }, - "autoconf_na_rpm": { + "autoconf": { "Name": "autoconf", "SupportedOS": [ { @@ -2174,7 +2154,7 @@ } ] }, - "automake_na_rpm": { + "automake": { "Name": "automake", "SupportedOS": [ { @@ -2193,8 +2173,8 @@ } ] }, - "bash-completion_na_rpm": { - "Name": "bash-completion", + "bash": { + "Name": "bash", "SupportedOS": [ { "Name": "RHEL", @@ -2212,8 +2192,8 @@ } ] }, - "bash_na_rpm": { - "Name": "bash", + "bash-completion": { + "Name": "bash-completion", "SupportedOS": [ { "Name": "RHEL", @@ -2231,8 +2211,8 @@ } ] }, - "binutils-devel_na_rpm": { - "Name": "binutils-devel", + "binutils": { + "Name": "binutils", "SupportedOS": [ { "Name": "RHEL", @@ -2246,12 +2226,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "binutils_na_rpm": { - "Name": "binutils", + "binutils-devel": { + "Name": "binutils-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2265,11 +2245,11 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "bzip2_na_rpm": { + "bzip2": { "Name": "bzip2", "SupportedOS": [ { @@ -2288,7 +2268,7 @@ } ] }, - "chrony_na_rpm": { + "chrony": { "Name": "chrony", "SupportedOS": [ { @@ -2307,7 +2287,7 @@ } ] }, - "cloud-init_na_rpm": { + "cloud-init": { "Name": "cloud-init", "SupportedOS": [ { @@ -2326,7 +2306,7 @@ } ] }, - "clustershell_na_rpm": { + "clustershell": { "Name": "clustershell", "SupportedOS": [ { @@ -2345,7 +2325,7 @@ } ] }, - "cmake_na_rpm": { + "cmake": { "Name": "cmake", "SupportedOS": [ { @@ -2364,7 +2344,7 @@ } ] }, - "coreutils_na_rpm": { + "coreutils": { "Name": "coreutils", "SupportedOS": [ { @@ -2383,7 +2363,7 @@ } ] }, - "cryptsetup_na_rpm": { + "cryptsetup": { "Name": "cryptsetup", "SupportedOS": [ { @@ -2402,7 +2382,7 @@ } ] }, - "curl_na_rpm": { + "curl": { "Name": "curl", "SupportedOS": [ { @@ -2421,7 +2401,7 @@ } ] }, - "device-mapper_na_rpm": { + "device-mapper": { "Name": "device-mapper", "SupportedOS": [ { @@ -2440,7 +2420,7 @@ } ] }, - "dmidecode_na_rpm": { + "dmidecode": { "Name": "dmidecode", "SupportedOS": [ { @@ -2459,7 +2439,7 @@ } ] }, - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-el10": { "Name": "docker.io/dellhpcomniaaisolution/image-build-el10", "SupportedOS": [ { @@ -2474,8 +2454,8 @@ "Tag": "1.1", "Version": "1.1" }, - "dracut-live_na_rpm": { - "Name": "dracut-live", + "dracut": { + "Name": "dracut", "SupportedOS": [ { "Name": "RHEL", @@ -2489,12 +2469,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "dracut-network_na_rpm": { - "Name": "dracut-network", + "dracut-live": { + "Name": "dracut-live", "SupportedOS": [ { "Name": "RHEL", @@ -2508,12 +2488,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "dracut_na_rpm": { - "Name": "dracut", + "dracut-network": { + "Name": "dracut-network", "SupportedOS": [ { "Name": "RHEL", @@ -2531,7 +2511,7 @@ } ] }, - "emacs_na_rpm": { + "emacs": { "Name": "emacs", "SupportedOS": [ { @@ -2550,7 +2530,7 @@ } ] }, - "file_na_rpm": { + "file": { "Name": "file", "SupportedOS": [ { @@ -2569,7 +2549,7 @@ } ] }, - "findutils_na_rpm": { + "findutils": { "Name": "findutils", "SupportedOS": [ { @@ -2588,7 +2568,7 @@ } ] }, - "fping_na_rpm": { + "fping": { "Name": "fping", "SupportedOS": [ { @@ -2607,7 +2587,7 @@ } ] }, - "gawk_na_rpm": { + "gawk": { "Name": "gawk", "SupportedOS": [ { @@ -2626,8 +2606,8 @@ } ] }, - "gcc-c++_na_rpm": { - "Name": "gcc-c++", + "gcc": { + "Name": "gcc", "SupportedOS": [ { "Name": "RHEL", @@ -2645,8 +2625,8 @@ } ] }, - "gcc-gfortran_na_rpm": { - "Name": "gcc-gfortran", + "gcc-c++": { + "Name": "gcc-c++", "SupportedOS": [ { "Name": "RHEL", @@ -2664,8 +2644,8 @@ } ] }, - "gcc_na_rpm": { - "Name": "gcc", + "gcc-gfortran": { + "Name": "gcc-gfortran", "SupportedOS": [ { "Name": "RHEL", @@ -2683,8 +2663,8 @@ } ] }, - "gdb-gdbserver_na_rpm": { - "Name": "gdb-gdbserver", + "gdb": { + "Name": "gdb", "SupportedOS": [ { "Name": "RHEL", @@ -2702,8 +2682,8 @@ } ] }, - "gdb_na_rpm": { - "Name": "gdb", + "gdb-gdbserver": { + "Name": "gdb-gdbserver", "SupportedOS": [ { "Name": "RHEL", @@ -2721,7 +2701,7 @@ } ] }, - "gedit_na_rpm": { + "gedit": { "Name": "gedit", "SupportedOS": [ { @@ -2740,7 +2720,7 @@ } ] }, - "glibc-langpack-en_na_rpm": { + "glibc-langpack-en": { "Name": "glibc-langpack-en", "SupportedOS": [ { @@ -2759,7 +2739,7 @@ } ] }, - "grep_na_rpm": { + "grep": { "Name": "grep", "SupportedOS": [ { @@ -2778,7 +2758,7 @@ } ] }, - "gzip_na_rpm": { + "gzip": { "Name": "gzip", "SupportedOS": [ { @@ -2797,8 +2777,8 @@ } ] }, - "hwloc-libs_na_rpm": { - "Name": "hwloc-libs", + "hwloc": { + "Name": "hwloc", "SupportedOS": [ { "Name": "RHEL", @@ -2816,8 +2796,8 @@ } ] }, - "hwloc_na_rpm": { - "Name": "hwloc", + "hwloc-libs": { + "Name": "hwloc-libs", "SupportedOS": [ { "Name": "RHEL", @@ -2835,7 +2815,7 @@ } ] }, - "iperf3_na_rpm": { + "iperf3": { "Name": "iperf3", "SupportedOS": [ { @@ -2854,7 +2834,7 @@ } ] }, - "ipmitool_na_rpm": { + "ipmitool": { "Name": "ipmitool", "SupportedOS": [ { @@ -2873,7 +2853,7 @@ } ] }, - "iproute_na_rpm": { + "iproute": { "Name": "iproute", "SupportedOS": [ { @@ -2892,7 +2872,7 @@ } ] }, - "iputils_na_rpm": { + "iputils": { "Name": "iputils", "SupportedOS": [ { @@ -2911,7 +2891,7 @@ } ] }, - "kbd_na_rpm": { + "kbd": { "Name": "kbd", "SupportedOS": [ { @@ -2930,8 +2910,8 @@ } ] }, - "kernel-tools_na_rpm": { - "Name": "kernel-tools", + "kernel": { + "Name": "kernel", "SupportedOS": [ { "Name": "RHEL", @@ -2949,8 +2929,8 @@ } ] }, - "kernel_na_rpm": { - "Name": "kernel", + "kernel-tools": { + "Name": "kernel-tools", "SupportedOS": [ { "Name": "RHEL", @@ -2968,7 +2948,7 @@ } ] }, - "kexec-tools_na_rpm": { + "kexec-tools": { "Name": "kexec-tools", "SupportedOS": [ { @@ -2987,7 +2967,7 @@ } ] }, - "libcurl_na_rpm": { + "libcurl": { "Name": "libcurl", "SupportedOS": [ { @@ -3006,7 +2986,7 @@ } ] }, - "libtool_na_rpm": { + "libtool": { "Name": "libtool", "SupportedOS": [ { @@ -3025,8 +3005,8 @@ } ] }, - "lldb-devel_na_rpm": { - "Name": "lldb-devel", + "lldb": { + "Name": "lldb", "SupportedOS": [ { "Name": "RHEL", @@ -3044,8 +3024,8 @@ } ] }, - "lldb_na_rpm": { - "Name": "lldb", + "lldb-devel": { + "Name": "lldb-devel", "SupportedOS": [ { "Name": "RHEL", @@ -3063,7 +3043,7 @@ } ] }, - "lshw_na_rpm": { + "lshw": { "Name": "lshw", "SupportedOS": [ { @@ -3082,7 +3062,7 @@ } ] }, - "lsof_na_rpm": { + "lsof": { "Name": "lsof", "SupportedOS": [ { @@ -3101,7 +3081,7 @@ } ] }, - "ltrace_na_rpm": { + "ltrace": { "Name": "ltrace", "SupportedOS": [ { @@ -3120,7 +3100,7 @@ } ] }, - "lvm2_na_rpm": { + "lvm2": { "Name": "lvm2", "SupportedOS": [ { @@ -3139,7 +3119,7 @@ } ] }, - "make_na_rpm": { + "make": { "Name": "make", "SupportedOS": [ { @@ -3158,7 +3138,7 @@ } ] }, - "man-db_na_rpm": { + "man-db": { "Name": "man-db", "SupportedOS": [ { @@ -3177,7 +3157,7 @@ } ] }, - "man-pages_na_rpm": { + "man-pages": { "Name": "man-pages", "SupportedOS": [ { @@ -3196,7 +3176,7 @@ } ] }, - "munge-devel_na_rpm": { + "munge-devel": { "Name": "munge-devel", "SupportedOS": [ { @@ -3215,7 +3195,7 @@ } ] }, - "nfs-utils_na_rpm": { + "nfs-utils": { "Name": "nfs-utils", "SupportedOS": [ { @@ -3234,7 +3214,7 @@ } ] }, - "nfs4-acl-tools_na_rpm": { + "nfs4-acl-tools": { "Name": "nfs4-acl-tools", "SupportedOS": [ { @@ -3253,7 +3233,7 @@ } ] }, - "nm-connection-editor_na_rpm": { + "nm-connection-editor": { "Name": "nm-connection-editor", "SupportedOS": [ { @@ -3272,7 +3252,7 @@ } ] }, - "nss-pam-ldapd_na_rpm": { + "nss-pam-ldapd": { "Name": "nss-pam-ldapd", "SupportedOS": [ { @@ -3291,7 +3271,7 @@ } ] }, - "oddjob-mkhomedir_na_rpm": { + "oddjob-mkhomedir": { "Name": "oddjob-mkhomedir", "SupportedOS": [ { @@ -3310,7 +3290,7 @@ } ] }, - "openldap-clients_na_rpm": { + "openldap-clients": { "Name": "openldap-clients", "SupportedOS": [ { @@ -3329,7 +3309,7 @@ } ] }, - "openmpi_5.0.8_tarball": { + "openmpi": { "Name": "openmpi", "SupportedOS": [ { @@ -3349,8 +3329,8 @@ } ] }, - "openssh-clients_na_rpm": { - "Name": "openssh-clients", + "openssh": { + "Name": "openssh", "SupportedOS": [ { "Name": "RHEL", @@ -3368,8 +3348,8 @@ } ] }, - "openssh-server_na_rpm": { - "Name": "openssh-server", + "openssh-clients": { + "Name": "openssh-clients", "SupportedOS": [ { "Name": "RHEL", @@ -3387,8 +3367,8 @@ } ] }, - "openssh_na_rpm": { - "Name": "openssh", + "openssh-server": { + "Name": "openssh-server", "SupportedOS": [ { "Name": "RHEL", @@ -3406,7 +3386,7 @@ } ] }, - "openssl-devel_na_rpm": { + "openssl-devel": { "Name": "openssl-devel", "SupportedOS": [ { @@ -3425,7 +3405,7 @@ } ] }, - "openssl-libs_na_rpm_1": { + "openssl-libs_1": { "Name": "openssl-libs", "SupportedOS": [ { @@ -3444,7 +3424,7 @@ } ] }, - "ovis-ldms_na_rpm_1": { + "ovis-ldms_1": { "Name": "ovis-ldms", "SupportedOS": [ { @@ -3463,7 +3443,7 @@ } ] }, - "papi-devel_na_rpm": { + "papi-devel": { "Name": "papi-devel", "SupportedOS": [ { @@ -3482,7 +3462,7 @@ } ] }, - "papi-libs_na_rpm": { + "papi-libs": { "Name": "papi-libs", "SupportedOS": [ { @@ -3501,7 +3481,7 @@ } ] }, - "papi_na_rpm": { + "papi_1": { "Name": "papi", "SupportedOS": [ { @@ -3520,7 +3500,7 @@ } ] }, - "pciutils_na_rpm": { + "pciutils": { "Name": "pciutils", "SupportedOS": [ { @@ -3539,7 +3519,7 @@ } ] }, - "perf_na_rpm": { + "perf": { "Name": "perf", "SupportedOS": [ { @@ -3558,7 +3538,7 @@ } ] }, - "pmix-devel_na_rpm": { + "pmix-devel": { "Name": "pmix-devel", "SupportedOS": [ { @@ -3577,7 +3557,7 @@ } ] }, - "python3-cython_na_rpm_1": { + "python3-cython_1": { "Name": "python3-cython", "SupportedOS": [ { @@ -3596,7 +3576,7 @@ } ] }, - "python3-devel_na_rpm_1": { + "python3-devel_1": { "Name": "python3-devel", "SupportedOS": [ { @@ -3615,7 +3595,7 @@ } ] }, - "rsync_na_rpm": { + "rsync": { "Name": "rsync", "SupportedOS": [ { @@ -3634,7 +3614,7 @@ } ] }, - "rsyslog_na_rpm": { + "rsyslog": { "Name": "rsyslog", "SupportedOS": [ { @@ -3653,7 +3633,7 @@ } ] }, - "sed_na_rpm": { + "sed": { "Name": "sed", "SupportedOS": [ { @@ -3672,7 +3652,7 @@ } ] }, - "squashfs-tools_na_rpm": { + "squashfs-tools": { "Name": "squashfs-tools", "SupportedOS": [ { @@ -3691,7 +3671,7 @@ } ] }, - "sssd_na_rpm": { + "sssd": { "Name": "sssd", "SupportedOS": [ { @@ -3710,7 +3690,7 @@ } ] }, - "strace_na_rpm": { + "strace": { "Name": "strace", "SupportedOS": [ { @@ -3729,7 +3709,7 @@ } ] }, - "sudo_na_rpm": { + "sudo": { "Name": "sudo", "SupportedOS": [ { @@ -3748,8 +3728,8 @@ } ] }, - "systemd-udev_na_rpm": { - "Name": "systemd-udev", + "systemd": { + "Name": "systemd", "SupportedOS": [ { "Name": "RHEL", @@ -3767,8 +3747,8 @@ } ] }, - "systemd_na_rpm": { - "Name": "systemd", + "systemd-udev": { + "Name": "systemd-udev", "SupportedOS": [ { "Name": "RHEL", @@ -3786,7 +3766,7 @@ } ] }, - "tar_na_rpm": { + "tar": { "Name": "tar", "SupportedOS": [ { @@ -3805,7 +3785,7 @@ } ] }, - "tcpdump_na_rpm": { + "tcpdump": { "Name": "tcpdump", "SupportedOS": [ { @@ -3824,7 +3804,7 @@ } ] }, - "traceroute_na_rpm": { + "traceroute": { "Name": "traceroute", "SupportedOS": [ { @@ -3843,7 +3823,7 @@ } ] }, - "ucx_1.19.0_tarball": { + "ucx": { "Name": "ucx", "SupportedOS": [ { @@ -3863,7 +3843,7 @@ } ] }, - "util-linux_na_rpm": { + "util-linux": { "Name": "util-linux", "SupportedOS": [ { @@ -3882,8 +3862,8 @@ } ] }, - "valgrind-devel_na_rpm": { - "Name": "valgrind-devel", + "valgrind": { + "Name": "valgrind", "SupportedOS": [ { "Name": "RHEL", @@ -3901,8 +3881,8 @@ } ] }, - "valgrind_na_rpm": { - "Name": "valgrind", + "valgrind-devel": { + "Name": "valgrind-devel", "SupportedOS": [ { "Name": "RHEL", @@ -3920,7 +3900,7 @@ } ] }, - "vim-enhanced_na_rpm_1": { + "vim-enhanced_1": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -3939,7 +3919,7 @@ } ] }, - "wget_na_rpm": { + "wget": { "Name": "wget", "SupportedOS": [ { @@ -3958,7 +3938,7 @@ } ] }, - "which_na_rpm": { + "which": { "Name": "which", "SupportedOS": [ { @@ -3977,7 +3957,7 @@ } ] }, - "zsh_na_rpm": { + "zsh": { "Name": "zsh", "SupportedOS": [ { @@ -3999,7 +3979,7 @@ }, "Miscellaneous": [], "InfrastructurePackages": { - "csi-powerscale-v2-16-0_v2.16.0_git": { + "csi-powerscale": { "Name": "csi-powerscale-v2.16.0", "Type": "git", "Version": "v2.16.0", @@ -4018,7 +3998,7 @@ } ] }, - "docker-io-dellemc-csm-encryption_v0.6.0_image": { + "docker.io/dellemc/csm-encryption": { "Name": "docker.io/dellemc/csm-encryption", "Type": "image", "Version": "v0.6.0", @@ -4032,7 +4012,7 @@ ], "Tag": "v0.6.0" }, - "external-snapshotter-v8-4-0_v8.4.0_git": { + "external-snapshotter": { "Name": "external-snapshotter-v8.4.0", "Type": "git", "Version": "v8.4.0", @@ -4051,7 +4031,7 @@ } ] }, - "helm-charts-2-16-0_csi-isilon-2.16.0_git": { + "helm-charts_1": { "Name": "helm-charts-2.16.0", "Type": "git", "Version": "csi-isilon-2.16.0", @@ -4070,7 +4050,7 @@ } ] }, - "quay-io-dell-container-storage-modules-csi-isilon_v2.16.0_image": { + "quay.io/dell/container-storage-modules/csi-isilon": { "Name": "quay.io/dell/container-storage-modules/csi-isilon", "Type": "image", "Version": "v2.16.0", @@ -4084,7 +4064,7 @@ ], "Tag": "v2.16.0" }, - "quay-io-dell-container-storage-modules-csi-metadat_v1.13.0_image": { + "quay.io/dell/container-storage-modules/csi-metadata-retriever": { "Name": "quay.io/dell/container-storage-modules/csi-metadata-retriever", "Type": "image", "Version": "v1.13.0", @@ -4098,7 +4078,7 @@ ], "Tag": "v1.13.0" }, - "quay-io-dell-container-storage-modules-csm-authori_v2.4.0_image": { + "quay.io/dell/container-storage-modules/csm-authorization-sidecar": { "Name": "quay.io/dell/container-storage-modules/csm-authorization-sidecar", "Type": "image", "Version": "v2.4.0", @@ -4112,7 +4092,7 @@ ], "Tag": "v2.4.0" }, - "quay-io-dell-container-storage-modules-dell-csi-re_v1.14.0_image": { + "quay.io/dell/container-storage-modules/dell-csi-replicator": { "Name": "quay.io/dell/container-storage-modules/dell-csi-replicator", "Type": "image", "Version": "v1.14.0", @@ -4126,7 +4106,7 @@ ], "Tag": "v1.14.0" }, - "quay-io-dell-container-storage-modules-podmon_v1.15.0_image": { + "quay.io/dell/container-storage-modules/podmon": { "Name": "quay.io/dell/container-storage-modules/podmon", "Type": "image", "Version": "v1.15.0", @@ -4140,7 +4120,7 @@ ], "Tag": "v1.15.0" }, - "registry-k8s-io-sig-storage-csi-attacher_v4.10.0_image": { + "registry.k8s.io/sig-storage/csi-attacher": { "Name": "registry.k8s.io/sig-storage/csi-attacher", "Type": "image", "Version": "v4.10.0", @@ -4154,7 +4134,7 @@ ], "Tag": "v4.10.0" }, - "registry-k8s-io-sig-storage-csi-external-health-mo_v0.16.0_image": { + "registry.k8s.io/sig-storage/csi-external-health-monitor-controller": { "Name": "registry.k8s.io/sig-storage/csi-external-health-monitor-controller", "Type": "image", "Version": "v0.16.0", @@ -4168,7 +4148,7 @@ ], "Tag": "v0.16.0" }, - "registry-k8s-io-sig-storage-csi-node-driver-regist_v2.15.0_image": { + "registry.k8s.io/sig-storage/csi-node-driver-registrar": { "Name": "registry.k8s.io/sig-storage/csi-node-driver-registrar", "Type": "image", "Version": "v2.15.0", @@ -4182,7 +4162,7 @@ ], "Tag": "v2.15.0" }, - "registry-k8s-io-sig-storage-csi-provisioner_v6.1.0_image": { + "registry.k8s.io/sig-storage/csi-provisioner": { "Name": "registry.k8s.io/sig-storage/csi-provisioner", "Type": "image", "Version": "v6.1.0", @@ -4196,7 +4176,7 @@ ], "Tag": "v6.1.0" }, - "registry-k8s-io-sig-storage-csi-resizer_v2.0.0_image": { + "registry.k8s.io/sig-storage/csi-resizer": { "Name": "registry.k8s.io/sig-storage/csi-resizer", "Type": "image", "Version": "v2.0.0", @@ -4210,7 +4190,7 @@ ], "Tag": "v2.0.0" }, - "registry-k8s-io-sig-storage-csi-snapshotter_v8.4.0_image": { + "registry.k8s.io/sig-storage/csi-snapshotter": { "Name": "registry.k8s.io/sig-storage/csi-snapshotter", "Type": "image", "Version": "v8.4.0", @@ -4224,7 +4204,7 @@ ], "Tag": "v8.4.0" }, - "registry-k8s-io-sig-storage-snapshot-controller_v8.4.0_image": { + "registry.k8s.io/sig-storage/snapshot-controller": { "Name": "registry.k8s.io/sig-storage/snapshot-controller", "Type": "image", "Version": "v8.4.0", diff --git a/examples/catalog/catalog_rhel_x86_64_with_slurm_only.json b/examples/catalog/catalog_rhel_x86_64_with_slurm_only.json index 1a799a3b19..7c8d819d0e 100644 --- a/examples/catalog/catalog_rhel_x86_64_with_slurm_only.json +++ b/examples/catalog/catalog_rhel_x86_64_with_slurm_only.json @@ -7,106 +7,105 @@ { "Name": "login_compiler_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "login_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmd_na_rpm", - "slurm_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm", + "slurm-slurmd" ] }, { "Name": "slurm_control_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "mariadb-server_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-PyMySQL_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-slurmctld_na_rpm", - "slurm-slurmdbd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "likwid", + "lsscsi", + "mariadb-server", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-PyMySQL", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-slurmctld", + "slurm-slurmdbd" ] }, { "Name": "slurm_node_x86_64", "FunctionalPackages": [ - "apptainer_na_rpm", - "device-mapper-multipath_na_rpm", - "doca-ofed_na_rpm_repo", - "firewalld_na_rpm", - "geopm_na_tarball", - "imb_na_tarball", - "iscsi-initiator-utils_na_rpm", - "kernel-devel_na_rpm", - "kernel-headers_na_rpm", - "likwid_na_tarball", - "lsscsi_na_rpm", - "msr-safe_na_tarball", - "munge_na_rpm", - "nvcr-io-nvidia-hpc-benchmarks_25.09_image", - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball", - "osu-micro-benchmarks_na_tarball", - "papi_na_tarball", - "pmix_na_rpm", - "python3-firewall_na_rpm", - "sg3_utils_na_rpm", - "sionlib_na_tarball", - "slurm-pam_slurm_na_rpm", - "slurm-slurmd_na_rpm" + "apptainer", + "device-mapper-multipath", + "doca-ofed", + "firewalld", + "geopm", + "imb", + "iscsi-initiator-utils", + "kernel-devel", + "kernel-headers", + "likwid", + "lsscsi", + "msr-safe", + "munge", + "nvcr.io/nvidia/hpc-benchmarks", + "osu-micro-benchmarks", + "papi", + "pmix", + "python3-firewall", + "sg3_utils", + "sionlib", + "slurm-pam_slurm", + "slurm-slurmd" ] } ], @@ -115,97 +114,97 @@ "Name": "RHEL", "Version": "10.0", "osPackages": [ - "NetworkManager_na_rpm", - "authselect_na_rpm", - "autoconf_na_rpm", - "automake_na_rpm", - "bash-completion_na_rpm", - "bash_na_rpm", - "binutils-devel_na_rpm", - "binutils_na_rpm", - "bzip2_na_rpm", - "chrony_na_rpm", - "cloud-init_na_rpm", - "clustershell_na_rpm", - "cmake_na_rpm", - "coreutils_na_rpm", - "cryptsetup_na_rpm", - "curl_na_rpm", - "device-mapper_na_rpm", - "dmidecode_na_rpm", - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image", - "dracut-live_na_rpm", - "dracut-network_na_rpm", - "dracut_na_rpm", - "emacs_na_rpm", - "file_na_rpm", - "findutils_na_rpm", - "fping_na_rpm", - "gawk_na_rpm", - "gcc-c++_na_rpm", - "gcc-gfortran_na_rpm", - "gcc_na_rpm", - "gdb-gdbserver_na_rpm", - "gdb_na_rpm", - "gedit_na_rpm", - "glibc-langpack-en_na_rpm", - "grep_na_rpm", - "gzip_na_rpm", - "hwloc-libs_na_rpm", - "hwloc_na_rpm", - "iperf3_na_rpm", - "ipmitool_na_rpm", - "iproute_na_rpm", - "iputils_na_rpm", - "kbd_na_rpm", - "kernel-tools_na_rpm", - "kernel_na_rpm", - "kexec-tools_na_rpm", - "libcurl_na_rpm", - "libtool_na_rpm", - "lldb-devel_na_rpm", - "lldb_na_rpm", - "lshw_na_rpm", - "lsof_na_rpm", - "ltrace_na_rpm", - "lvm2_na_rpm", - "make_na_rpm", - "man-db_na_rpm", - "man-pages_na_rpm", - "nfs-utils_na_rpm", - "nfs4-acl-tools_na_rpm", - "nm-connection-editor_na_rpm", - "nss-pam-ldapd_na_rpm", - "oddjob-mkhomedir_na_rpm", - "openldap-clients_na_rpm", - "openssh-clients_na_rpm", - "openssh-server_na_rpm", - "openssh_na_rpm", - "openssl-devel_na_rpm", - "papi-devel_na_rpm", - "papi-libs_na_rpm", - "papi_na_rpm", - "pciutils_na_rpm", - "perf_na_rpm", - "rsync_na_rpm", - "rsyslog_na_rpm", - "sed_na_rpm", - "squashfs-tools_na_rpm", - "sssd_na_rpm", - "strace_na_rpm", - "sudo_na_rpm", - "systemd-udev_na_rpm", - "systemd_na_rpm", - "tar_na_rpm", - "tcpdump_na_rpm", - "traceroute_na_rpm", - "util-linux_na_rpm", - "valgrind-devel_na_rpm", - "valgrind_na_rpm", - "vim-enhanced_na_rpm", - "wget_na_rpm", - "which_na_rpm", - "zsh_na_rpm" + "NetworkManager", + "authselect", + "autoconf", + "automake", + "bash", + "bash-completion", + "binutils", + "binutils-devel", + "bzip2", + "chrony", + "cloud-init", + "clustershell", + "cmake", + "coreutils", + "cryptsetup", + "curl", + "device-mapper", + "dmidecode", + "docker.io/dellhpcomniaaisolution/image-build-el10", + "dracut", + "dracut-live", + "dracut-network", + "emacs", + "file", + "findutils", + "fping", + "gawk", + "gcc", + "gcc-c++", + "gcc-gfortran", + "gdb", + "gdb-gdbserver", + "gedit", + "glibc-langpack-en", + "grep", + "gzip", + "hwloc", + "hwloc-libs", + "iperf3", + "ipmitool", + "iproute", + "iputils", + "kbd", + "kernel", + "kernel-tools", + "kexec-tools", + "libcurl", + "libtool", + "lldb", + "lldb-devel", + "lshw", + "lsof", + "ltrace", + "lvm2", + "make", + "man-db", + "man-pages", + "nfs-utils", + "nfs4-acl-tools", + "nm-connection-editor", + "nss-pam-ldapd", + "oddjob-mkhomedir", + "openldap-clients", + "openssh", + "openssh-clients", + "openssh-server", + "openssl-devel", + "papi-devel", + "papi-libs", + "papi_1", + "pciutils", + "perf", + "rsync", + "rsyslog", + "sed", + "squashfs-tools", + "sssd", + "strace", + "sudo", + "systemd", + "systemd-udev", + "tar", + "tcpdump", + "traceroute", + "util-linux", + "valgrind", + "valgrind-devel", + "vim-enhanced", + "wget", + "which", + "zsh" ] } ], @@ -213,7 +212,7 @@ "Drivers": [], "DriverPackages": {}, "FunctionalPackages": { - "apptainer_na_rpm": { + "apptainer": { "Name": "apptainer", "SupportedOS": [ { @@ -232,7 +231,7 @@ } ] }, - "device-mapper-multipath_na_rpm": { + "device-mapper-multipath": { "Name": "device-mapper-multipath", "SupportedOS": [ { @@ -251,7 +250,7 @@ } ] }, - "doca-ofed_na_rpm_repo": { + "doca-ofed": { "Name": "doca-ofed", "SupportedOS": [ { @@ -270,7 +269,7 @@ } ] }, - "firewalld_na_rpm": { + "firewalld": { "Name": "firewalld", "SupportedOS": [ { @@ -289,7 +288,7 @@ } ] }, - "geopm_na_tarball": { + "geopm": { "Name": "geopm", "SupportedOS": [ { @@ -308,7 +307,7 @@ } ] }, - "imb_na_tarball": { + "imb": { "Name": "imb", "SupportedOS": [ { @@ -327,7 +326,7 @@ } ] }, - "iscsi-initiator-utils_na_rpm": { + "iscsi-initiator-utils": { "Name": "iscsi-initiator-utils", "SupportedOS": [ { @@ -346,7 +345,7 @@ } ] }, - "kernel-devel_na_rpm": { + "kernel-devel": { "Name": "kernel-devel", "SupportedOS": [ { @@ -365,7 +364,7 @@ } ] }, - "kernel-headers_na_rpm": { + "kernel-headers": { "Name": "kernel-headers", "SupportedOS": [ { @@ -384,7 +383,7 @@ } ] }, - "likwid_na_tarball": { + "likwid": { "Name": "likwid", "SupportedOS": [ { @@ -403,7 +402,7 @@ } ] }, - "lsscsi_na_rpm": { + "lsscsi": { "Name": "lsscsi", "SupportedOS": [ { @@ -422,7 +421,7 @@ } ] }, - "mariadb-server_na_rpm": { + "mariadb-server": { "Name": "mariadb-server", "SupportedOS": [ { @@ -441,7 +440,7 @@ } ] }, - "msr-safe_na_tarball": { + "msr-safe": { "Name": "msr-safe", "SupportedOS": [ { @@ -460,7 +459,7 @@ } ] }, - "munge_na_rpm": { + "munge": { "Name": "munge", "SupportedOS": [ { @@ -479,7 +478,7 @@ } ] }, - "nvcr-io-nvidia-hpc-benchmarks_25.09_image": { + "nvcr.io/nvidia/hpc-benchmarks": { "Name": "nvcr.io/nvidia/hpc-benchmarks", "SupportedOS": [ { @@ -494,26 +493,7 @@ "Tag": "25.09", "Version": "25.09" }, - "nvhpc_2025_2511_Linux_x86_64_cuda_13-0_na_tarball": { - "Name": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "SupportedOS": [ - { - "Name": "RHEL", - "Version": "10.0" - } - ], - "Architecture": [ - "x86_64" - ], - "Type": "tarball", - "Sources": [ - { - "Architecture": "x86_64", - "Uri": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } - ] - }, - "osu-micro-benchmarks_na_tarball": { + "osu-micro-benchmarks": { "Name": "osu-micro-benchmarks", "SupportedOS": [ { @@ -532,7 +512,7 @@ } ] }, - "papi_na_tarball": { + "papi": { "Name": "papi", "SupportedOS": [ { @@ -551,7 +531,7 @@ } ] }, - "pmix_na_rpm": { + "pmix": { "Name": "pmix", "SupportedOS": [ { @@ -570,7 +550,7 @@ } ] }, - "python3-PyMySQL_na_rpm": { + "python3-PyMySQL": { "Name": "python3-PyMySQL", "SupportedOS": [ { @@ -589,7 +569,7 @@ } ] }, - "python3-firewall_na_rpm": { + "python3-firewall": { "Name": "python3-firewall", "SupportedOS": [ { @@ -608,7 +588,7 @@ } ] }, - "sg3_utils_na_rpm": { + "sg3_utils": { "Name": "sg3_utils", "SupportedOS": [ { @@ -627,7 +607,7 @@ } ] }, - "sionlib_na_tarball": { + "sionlib": { "Name": "sionlib", "SupportedOS": [ { @@ -646,8 +626,8 @@ } ] }, - "slurm-pam_slurm_na_rpm": { - "Name": "slurm-pam_slurm", + "slurm": { + "Name": "slurm", "SupportedOS": [ { "Name": "RHEL", @@ -665,8 +645,8 @@ } ] }, - "slurm-slurmctld_na_rpm": { - "Name": "slurm-slurmctld", + "slurm-pam_slurm": { + "Name": "slurm-pam_slurm", "SupportedOS": [ { "Name": "RHEL", @@ -684,8 +664,8 @@ } ] }, - "slurm-slurmd_na_rpm": { - "Name": "slurm-slurmd", + "slurm-slurmctld": { + "Name": "slurm-slurmctld", "SupportedOS": [ { "Name": "RHEL", @@ -703,8 +683,8 @@ } ] }, - "slurm-slurmdbd_na_rpm": { - "Name": "slurm-slurmdbd", + "slurm-slurmd": { + "Name": "slurm-slurmd", "SupportedOS": [ { "Name": "RHEL", @@ -722,8 +702,8 @@ } ] }, - "slurm_na_rpm": { - "Name": "slurm", + "slurm-slurmdbd": { + "Name": "slurm-slurmdbd", "SupportedOS": [ { "Name": "RHEL", @@ -743,7 +723,7 @@ } }, "OSPackages": { - "NetworkManager_na_rpm": { + "NetworkManager": { "Name": "NetworkManager", "SupportedOS": [ { @@ -762,7 +742,7 @@ } ] }, - "authselect_na_rpm": { + "authselect": { "Name": "authselect", "SupportedOS": [ { @@ -781,7 +761,7 @@ } ] }, - "autoconf_na_rpm": { + "autoconf": { "Name": "autoconf", "SupportedOS": [ { @@ -800,7 +780,7 @@ } ] }, - "automake_na_rpm": { + "automake": { "Name": "automake", "SupportedOS": [ { @@ -819,8 +799,8 @@ } ] }, - "bash-completion_na_rpm": { - "Name": "bash-completion", + "bash": { + "Name": "bash", "SupportedOS": [ { "Name": "RHEL", @@ -838,8 +818,8 @@ } ] }, - "bash_na_rpm": { - "Name": "bash", + "bash-completion": { + "Name": "bash-completion", "SupportedOS": [ { "Name": "RHEL", @@ -857,8 +837,8 @@ } ] }, - "binutils-devel_na_rpm": { - "Name": "binutils-devel", + "binutils": { + "Name": "binutils", "SupportedOS": [ { "Name": "RHEL", @@ -872,12 +852,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "binutils_na_rpm": { - "Name": "binutils", + "binutils-devel": { + "Name": "binutils-devel", "SupportedOS": [ { "Name": "RHEL", @@ -891,11 +871,11 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "bzip2_na_rpm": { + "bzip2": { "Name": "bzip2", "SupportedOS": [ { @@ -914,7 +894,7 @@ } ] }, - "chrony_na_rpm": { + "chrony": { "Name": "chrony", "SupportedOS": [ { @@ -933,7 +913,7 @@ } ] }, - "cloud-init_na_rpm": { + "cloud-init": { "Name": "cloud-init", "SupportedOS": [ { @@ -952,7 +932,7 @@ } ] }, - "clustershell_na_rpm": { + "clustershell": { "Name": "clustershell", "SupportedOS": [ { @@ -971,7 +951,7 @@ } ] }, - "cmake_na_rpm": { + "cmake": { "Name": "cmake", "SupportedOS": [ { @@ -990,7 +970,7 @@ } ] }, - "coreutils_na_rpm": { + "coreutils": { "Name": "coreutils", "SupportedOS": [ { @@ -1009,7 +989,7 @@ } ] }, - "cryptsetup_na_rpm": { + "cryptsetup": { "Name": "cryptsetup", "SupportedOS": [ { @@ -1028,7 +1008,7 @@ } ] }, - "curl_na_rpm": { + "curl": { "Name": "curl", "SupportedOS": [ { @@ -1047,7 +1027,7 @@ } ] }, - "device-mapper_na_rpm": { + "device-mapper": { "Name": "device-mapper", "SupportedOS": [ { @@ -1066,7 +1046,7 @@ } ] }, - "dmidecode_na_rpm": { + "dmidecode": { "Name": "dmidecode", "SupportedOS": [ { @@ -1085,7 +1065,7 @@ } ] }, - "docker-io-dellhpcomniaaisolution-image-build-el10_1.1_image": { + "docker.io/dellhpcomniaaisolution/image-build-el10": { "Name": "docker.io/dellhpcomniaaisolution/image-build-el10", "SupportedOS": [ { @@ -1100,8 +1080,8 @@ "Tag": "1.1", "Version": "1.1" }, - "dracut-live_na_rpm": { - "Name": "dracut-live", + "dracut": { + "Name": "dracut", "SupportedOS": [ { "Name": "RHEL", @@ -1115,12 +1095,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "appstream" + "RepoName": "baseos" } ] }, - "dracut-network_na_rpm": { - "Name": "dracut-network", + "dracut-live": { + "Name": "dracut-live", "SupportedOS": [ { "Name": "RHEL", @@ -1134,12 +1114,12 @@ "Sources": [ { "Architecture": "x86_64", - "RepoName": "baseos" + "RepoName": "appstream" } ] }, - "dracut_na_rpm": { - "Name": "dracut", + "dracut-network": { + "Name": "dracut-network", "SupportedOS": [ { "Name": "RHEL", @@ -1157,7 +1137,7 @@ } ] }, - "emacs_na_rpm": { + "emacs": { "Name": "emacs", "SupportedOS": [ { @@ -1176,7 +1156,7 @@ } ] }, - "file_na_rpm": { + "file": { "Name": "file", "SupportedOS": [ { @@ -1195,7 +1175,7 @@ } ] }, - "findutils_na_rpm": { + "findutils": { "Name": "findutils", "SupportedOS": [ { @@ -1214,7 +1194,7 @@ } ] }, - "fping_na_rpm": { + "fping": { "Name": "fping", "SupportedOS": [ { @@ -1233,7 +1213,7 @@ } ] }, - "gawk_na_rpm": { + "gawk": { "Name": "gawk", "SupportedOS": [ { @@ -1252,8 +1232,8 @@ } ] }, - "gcc-c++_na_rpm": { - "Name": "gcc-c++", + "gcc": { + "Name": "gcc", "SupportedOS": [ { "Name": "RHEL", @@ -1271,8 +1251,8 @@ } ] }, - "gcc-gfortran_na_rpm": { - "Name": "gcc-gfortran", + "gcc-c++": { + "Name": "gcc-c++", "SupportedOS": [ { "Name": "RHEL", @@ -1290,8 +1270,8 @@ } ] }, - "gcc_na_rpm": { - "Name": "gcc", + "gcc-gfortran": { + "Name": "gcc-gfortran", "SupportedOS": [ { "Name": "RHEL", @@ -1309,8 +1289,8 @@ } ] }, - "gdb-gdbserver_na_rpm": { - "Name": "gdb-gdbserver", + "gdb": { + "Name": "gdb", "SupportedOS": [ { "Name": "RHEL", @@ -1328,8 +1308,8 @@ } ] }, - "gdb_na_rpm": { - "Name": "gdb", + "gdb-gdbserver": { + "Name": "gdb-gdbserver", "SupportedOS": [ { "Name": "RHEL", @@ -1347,7 +1327,7 @@ } ] }, - "gedit_na_rpm": { + "gedit": { "Name": "gedit", "SupportedOS": [ { @@ -1366,7 +1346,7 @@ } ] }, - "glibc-langpack-en_na_rpm": { + "glibc-langpack-en": { "Name": "glibc-langpack-en", "SupportedOS": [ { @@ -1385,7 +1365,7 @@ } ] }, - "grep_na_rpm": { + "grep": { "Name": "grep", "SupportedOS": [ { @@ -1404,7 +1384,7 @@ } ] }, - "gzip_na_rpm": { + "gzip": { "Name": "gzip", "SupportedOS": [ { @@ -1423,8 +1403,8 @@ } ] }, - "hwloc-libs_na_rpm": { - "Name": "hwloc-libs", + "hwloc": { + "Name": "hwloc", "SupportedOS": [ { "Name": "RHEL", @@ -1442,8 +1422,8 @@ } ] }, - "hwloc_na_rpm": { - "Name": "hwloc", + "hwloc-libs": { + "Name": "hwloc-libs", "SupportedOS": [ { "Name": "RHEL", @@ -1461,7 +1441,7 @@ } ] }, - "iperf3_na_rpm": { + "iperf3": { "Name": "iperf3", "SupportedOS": [ { @@ -1480,7 +1460,7 @@ } ] }, - "ipmitool_na_rpm": { + "ipmitool": { "Name": "ipmitool", "SupportedOS": [ { @@ -1499,7 +1479,7 @@ } ] }, - "iproute_na_rpm": { + "iproute": { "Name": "iproute", "SupportedOS": [ { @@ -1518,7 +1498,7 @@ } ] }, - "iputils_na_rpm": { + "iputils": { "Name": "iputils", "SupportedOS": [ { @@ -1537,7 +1517,7 @@ } ] }, - "kbd_na_rpm": { + "kbd": { "Name": "kbd", "SupportedOS": [ { @@ -1556,8 +1536,8 @@ } ] }, - "kernel-tools_na_rpm": { - "Name": "kernel-tools", + "kernel": { + "Name": "kernel", "SupportedOS": [ { "Name": "RHEL", @@ -1575,8 +1555,8 @@ } ] }, - "kernel_na_rpm": { - "Name": "kernel", + "kernel-tools": { + "Name": "kernel-tools", "SupportedOS": [ { "Name": "RHEL", @@ -1594,7 +1574,7 @@ } ] }, - "kexec-tools_na_rpm": { + "kexec-tools": { "Name": "kexec-tools", "SupportedOS": [ { @@ -1613,7 +1593,7 @@ } ] }, - "libcurl_na_rpm": { + "libcurl": { "Name": "libcurl", "SupportedOS": [ { @@ -1632,7 +1612,7 @@ } ] }, - "libtool_na_rpm": { + "libtool": { "Name": "libtool", "SupportedOS": [ { @@ -1651,8 +1631,8 @@ } ] }, - "lldb-devel_na_rpm": { - "Name": "lldb-devel", + "lldb": { + "Name": "lldb", "SupportedOS": [ { "Name": "RHEL", @@ -1670,8 +1650,8 @@ } ] }, - "lldb_na_rpm": { - "Name": "lldb", + "lldb-devel": { + "Name": "lldb-devel", "SupportedOS": [ { "Name": "RHEL", @@ -1689,7 +1669,7 @@ } ] }, - "lshw_na_rpm": { + "lshw": { "Name": "lshw", "SupportedOS": [ { @@ -1708,7 +1688,7 @@ } ] }, - "lsof_na_rpm": { + "lsof": { "Name": "lsof", "SupportedOS": [ { @@ -1727,7 +1707,7 @@ } ] }, - "ltrace_na_rpm": { + "ltrace": { "Name": "ltrace", "SupportedOS": [ { @@ -1746,7 +1726,7 @@ } ] }, - "lvm2_na_rpm": { + "lvm2": { "Name": "lvm2", "SupportedOS": [ { @@ -1765,7 +1745,7 @@ } ] }, - "make_na_rpm": { + "make": { "Name": "make", "SupportedOS": [ { @@ -1784,7 +1764,7 @@ } ] }, - "man-db_na_rpm": { + "man-db": { "Name": "man-db", "SupportedOS": [ { @@ -1803,7 +1783,7 @@ } ] }, - "man-pages_na_rpm": { + "man-pages": { "Name": "man-pages", "SupportedOS": [ { @@ -1822,7 +1802,7 @@ } ] }, - "nfs-utils_na_rpm": { + "nfs-utils": { "Name": "nfs-utils", "SupportedOS": [ { @@ -1841,7 +1821,7 @@ } ] }, - "nfs4-acl-tools_na_rpm": { + "nfs4-acl-tools": { "Name": "nfs4-acl-tools", "SupportedOS": [ { @@ -1860,7 +1840,7 @@ } ] }, - "nm-connection-editor_na_rpm": { + "nm-connection-editor": { "Name": "nm-connection-editor", "SupportedOS": [ { @@ -1879,7 +1859,7 @@ } ] }, - "nss-pam-ldapd_na_rpm": { + "nss-pam-ldapd": { "Name": "nss-pam-ldapd", "SupportedOS": [ { @@ -1898,7 +1878,7 @@ } ] }, - "oddjob-mkhomedir_na_rpm": { + "oddjob-mkhomedir": { "Name": "oddjob-mkhomedir", "SupportedOS": [ { @@ -1917,7 +1897,7 @@ } ] }, - "openldap-clients_na_rpm": { + "openldap-clients": { "Name": "openldap-clients", "SupportedOS": [ { @@ -1936,8 +1916,8 @@ } ] }, - "openssh-clients_na_rpm": { - "Name": "openssh-clients", + "openssh": { + "Name": "openssh", "SupportedOS": [ { "Name": "RHEL", @@ -1955,8 +1935,8 @@ } ] }, - "openssh-server_na_rpm": { - "Name": "openssh-server", + "openssh-clients": { + "Name": "openssh-clients", "SupportedOS": [ { "Name": "RHEL", @@ -1974,8 +1954,8 @@ } ] }, - "openssh_na_rpm": { - "Name": "openssh", + "openssh-server": { + "Name": "openssh-server", "SupportedOS": [ { "Name": "RHEL", @@ -1993,7 +1973,7 @@ } ] }, - "openssl-devel_na_rpm": { + "openssl-devel": { "Name": "openssl-devel", "SupportedOS": [ { @@ -2012,7 +1992,7 @@ } ] }, - "papi-devel_na_rpm": { + "papi-devel": { "Name": "papi-devel", "SupportedOS": [ { @@ -2031,7 +2011,7 @@ } ] }, - "papi-libs_na_rpm": { + "papi-libs": { "Name": "papi-libs", "SupportedOS": [ { @@ -2050,7 +2030,7 @@ } ] }, - "papi_na_rpm": { + "papi_1": { "Name": "papi", "SupportedOS": [ { @@ -2069,7 +2049,7 @@ } ] }, - "pciutils_na_rpm": { + "pciutils": { "Name": "pciutils", "SupportedOS": [ { @@ -2088,7 +2068,7 @@ } ] }, - "perf_na_rpm": { + "perf": { "Name": "perf", "SupportedOS": [ { @@ -2107,7 +2087,7 @@ } ] }, - "rsync_na_rpm": { + "rsync": { "Name": "rsync", "SupportedOS": [ { @@ -2126,7 +2106,7 @@ } ] }, - "rsyslog_na_rpm": { + "rsyslog": { "Name": "rsyslog", "SupportedOS": [ { @@ -2145,7 +2125,7 @@ } ] }, - "sed_na_rpm": { + "sed": { "Name": "sed", "SupportedOS": [ { @@ -2164,7 +2144,7 @@ } ] }, - "squashfs-tools_na_rpm": { + "squashfs-tools": { "Name": "squashfs-tools", "SupportedOS": [ { @@ -2183,7 +2163,7 @@ } ] }, - "sssd_na_rpm": { + "sssd": { "Name": "sssd", "SupportedOS": [ { @@ -2202,7 +2182,7 @@ } ] }, - "strace_na_rpm": { + "strace": { "Name": "strace", "SupportedOS": [ { @@ -2221,7 +2201,7 @@ } ] }, - "sudo_na_rpm": { + "sudo": { "Name": "sudo", "SupportedOS": [ { @@ -2240,8 +2220,8 @@ } ] }, - "systemd-udev_na_rpm": { - "Name": "systemd-udev", + "systemd": { + "Name": "systemd", "SupportedOS": [ { "Name": "RHEL", @@ -2259,8 +2239,8 @@ } ] }, - "systemd_na_rpm": { - "Name": "systemd", + "systemd-udev": { + "Name": "systemd-udev", "SupportedOS": [ { "Name": "RHEL", @@ -2278,7 +2258,7 @@ } ] }, - "tar_na_rpm": { + "tar": { "Name": "tar", "SupportedOS": [ { @@ -2297,7 +2277,7 @@ } ] }, - "tcpdump_na_rpm": { + "tcpdump": { "Name": "tcpdump", "SupportedOS": [ { @@ -2316,7 +2296,7 @@ } ] }, - "traceroute_na_rpm": { + "traceroute": { "Name": "traceroute", "SupportedOS": [ { @@ -2335,7 +2315,7 @@ } ] }, - "util-linux_na_rpm": { + "util-linux": { "Name": "util-linux", "SupportedOS": [ { @@ -2354,8 +2334,8 @@ } ] }, - "valgrind-devel_na_rpm": { - "Name": "valgrind-devel", + "valgrind": { + "Name": "valgrind", "SupportedOS": [ { "Name": "RHEL", @@ -2373,8 +2353,8 @@ } ] }, - "valgrind_na_rpm": { - "Name": "valgrind", + "valgrind-devel": { + "Name": "valgrind-devel", "SupportedOS": [ { "Name": "RHEL", @@ -2392,7 +2372,7 @@ } ] }, - "vim-enhanced_na_rpm": { + "vim-enhanced": { "Name": "vim-enhanced", "SupportedOS": [ { @@ -2411,7 +2391,7 @@ } ] }, - "wget_na_rpm": { + "wget": { "Name": "wget", "SupportedOS": [ { @@ -2430,7 +2410,7 @@ } ] }, - "which_na_rpm": { + "which": { "Name": "which", "SupportedOS": [ { @@ -2449,7 +2429,7 @@ } ] }, - "zsh_na_rpm": { + "zsh": { "Name": "zsh", "SupportedOS": [ { diff --git a/gitlab/ansible.cfg b/gitlab/ansible.cfg index bbc7c851d0..2e53b46c4a 100644 --- a/gitlab/ansible.cfg +++ b/gitlab/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/gitlab/cleanup_gitlab.yml b/gitlab/cleanup_gitlab.yml index ee2250201e..a622151d95 100644 --- a/gitlab/cleanup_gitlab.yml +++ b/gitlab/cleanup_gitlab.yml @@ -26,7 +26,7 @@ - name: Set dynamic run tags including 'gitlab' when: not config_file_status | default(false) | bool ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['provision']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['provision']) | unique }}" cacheable: true - name: Include input project directory diff --git a/gitlab/gitlab.yml b/gitlab/gitlab.yml index 8ef3378313..3034c6e23e 100644 --- a/gitlab/gitlab.yml +++ b/gitlab/gitlab.yml @@ -22,7 +22,7 @@ - name: Set dynamic run tags including 'gitlab' when: not config_file_status | default(false) | bool ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['gitlab'] + ['provision']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['gitlab'] + ['provision']) | unique }}" cacheable: true - name: Include input project directory diff --git a/gitlab/roles/hosted_gitlab/files/.gitlab-ci-deploy-child-template.yml b/gitlab/roles/hosted_gitlab/files/.gitlab-ci-deploy-child-template.yml index 6d33ad1f91..1cf170e550 100644 --- a/gitlab/roles/hosted_gitlab/files/.gitlab-ci-deploy-child-template.yml +++ b/gitlab/roles/hosted_gitlab/files/.gitlab-ci-deploy-child-template.yml @@ -759,7 +759,6 @@ validate: echo " ------------------------------------------------------------" printf " %-22s %s\n" "Error Code:" "${VALIDATE_ERR_CODE}" printf " %-22s %s\n" "Error Summary:" "${VALIDATE_ERR_SUMMARY}" - printf " %-22s %s\n" "Log File Path:" "${VALIDATE_LOG_PATH}" echo " ------------------------------------------------------------" # Extract test summary from result_detail if available @@ -769,6 +768,12 @@ validate: echo "${TEST_SUMMARY}" | jq '.' echo " ------------------------------------------------------------" fi + + # Display log file path after test summary with verbose message + printf " %-22s %s\n" "Log File Path:" "${VALIDATE_LOG_PATH}" + echo " ------------------------------------------------------------" + echo " For more detailed information, refer to the logs below" + echo " ------------------------------------------------------------" exit 1 ;; esac diff --git a/gitlab/roles/hosted_gitlab/files/.gitlab-ci.yml b/gitlab/roles/hosted_gitlab/files/.gitlab-ci.yml index a907c3c187..6c484a5523 100644 --- a/gitlab/roles/hosted_gitlab/files/.gitlab-ci.yml +++ b/gitlab/roles/hosted_gitlab/files/.gitlab-ci.yml @@ -24,13 +24,9 @@ # Click exactly one to run that pipeline independently. # API trigger : Set PIPELINE_TYPE to "build", "deploy", or "cleanup". # -# Constraint: no two child pipelines run in the same parent execution. -# Serial execution: all trigger jobs share a single resource_group (pipeline) -# so that only ONE pipeline of any type (build, deploy, or cleanup) runs at a -# time. If a new commit triggers a pipeline while a previous one is still -# running, the new pipeline will wait (queued) until the running one completes. -# This prevents status mismatches, race conditions, and configuration -# corruption from concurrent access to the shared backend. +# Note: Multiple pipelines can now run concurrently as resource_group has been removed. +# This allows parallel execution of build, deploy, and cleanup pipelines. +# Be aware of potential race conditions when accessing shared resources concurrently. # --------------------------------------------------------------------------- workflow: @@ -49,7 +45,6 @@ stages: # --------------------------------------------------------------------------- build_pipeline: stage: pipeline_selection - resource_group: pipeline trigger: include: .gitlab-ci-build.yml strategy: depend @@ -78,7 +73,6 @@ build_pipeline: # --------------------------------------------------------------------------- deploy_pipeline: stage: pipeline_selection - resource_group: pipeline trigger: include: .gitlab-ci-deploy.yml strategy: depend @@ -107,7 +101,6 @@ deploy_pipeline: # --------------------------------------------------------------------------- cleanup_pipeline: stage: pipeline_selection - resource_group: pipeline trigger: include: .gitlab-ci-cleanup.yml strategy: depend diff --git a/input/config/aarch64/rhel/10.0/slurm_custom.json b/input/config/aarch64/rhel/10.0/slurm_custom.json index 736c58e690..ade7d526ce 100644 --- a/input/config/aarch64/rhel/10.0/slurm_custom.json +++ b/input/config/aarch64/rhel/10.0/slurm_custom.json @@ -33,12 +33,7 @@ {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, {"package": "slurm-pam_slurm", "type": "rpm", "repo_name": "slurm_custom"}, {"package": "kernel-devel", "type": "rpm", "repo_name": "appstream"}, - {"package": "kernel-headers", "type": "rpm", "repo_name": "appstream"}, - { - "package": "nvhpc_2025_2511_Linux_aarch64_cuda_13.0", - "type": "tarball", - "url": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_aarch64_cuda_13.0.tar.gz" - } + {"package": "kernel-headers", "type": "rpm", "repo_name": "appstream"} ] }, diff --git a/input/config/x86_64/rhel/10.0/slurm_custom.json b/input/config/x86_64/rhel/10.0/slurm_custom.json index 15abda0c76..e2f13ecf68 100644 --- a/input/config/x86_64/rhel/10.0/slurm_custom.json +++ b/input/config/x86_64/rhel/10.0/slurm_custom.json @@ -34,12 +34,7 @@ {"package": "slurm-slurmd", "type": "rpm", "repo_name": "slurm_custom"}, {"package": "slurm-pam_slurm", "type": "rpm", "repo_name": "slurm_custom"}, {"package": "kernel-devel", "type": "rpm", "repo_name": "appstream"}, - {"package": "kernel-headers", "type": "rpm", "repo_name": "appstream"}, - { - "package": "nvhpc_2025_2511_Linux_x86_64_cuda_13.0", - "type": "tarball", - "url": "https://developer.download.nvidia.com/hpc-sdk/25.11/nvhpc_2025_2511_Linux_x86_64_cuda_13.0.tar.gz" - } + {"package": "kernel-headers", "type": "rpm", "repo_name": "appstream"} ] }, "login_node":{ diff --git a/input/omnia_config.yml b/input/omnia_config.yml index 19fcc4c38a..de54fddfd2 100644 --- a/input/omnia_config.yml +++ b/input/omnia_config.yml @@ -31,35 +31,42 @@ # Storage name corresponding to the VAST storage to be used by slurm cluster # This should match with exactly with a entry in storage_config.yml # The following directories will be mounted on the VAST storage: -# - /scratch -# - /tmp -# - /home -# - /apps -# - /projects +# - /scratch +# - /tmp +# - /home +# - /apps +# - /projects +# +# -> Centralized repository for HPC tools (UCX, OpenMPI, CUDA, benchmarks) that are +# bind-mounted to /hpc_tools on compute and login nodes. This storage must be +# accessible from OIM during provisioning to copy hpc_tools content to the cluster. +# -> Must match the 'name' field of the VAST storage entry(mounts) in storage_config.yml +# -> The VAST server must be reachable from OIM to enable hpc_tools population during +# cluster provisioning. Ensure network connectivity and mount permissions are configured. # skip_merge -# Variable indicates whether a specific configuration file path -# under config_sources should be used as-is without merging -# If skip_merge is set to true for a configuration source path, -# that configuration file will be applied directly -# without merging with defaults or existing configurations -# It accepts true and false values -# Default value is false +# Variable indicates whether a specific configuration file path +# under config_sources should be used as-is without merging +# If skip_merge is set to true for a configuration source path, +# that configuration file will be applied directly +# without merging with defaults or existing configurations +# It accepts true and false values +# Default value is false # node_discovery_mode -# Controls how hardware specifications are discovered for Slurm compute nodes -# Options: "heterogeneous" or "homogeneous" -# - heterogeneous: Discovers each node individually via iDRAC (1 call per node) -# Best for: Mixed hardware environments with different node configurations -# - homogeneous: Groups nodes by hardware type for optimized discovery -# Best for: Standardized hardware groups (grp0-grp100 in pxe_mapping_file.csv) +# Controls how hardware specifications are discovered for Slurm compute nodes +# Options: "heterogeneous" or "homogeneous" +# - heterogeneous: Discovers each node individually via iDRAC (1 call per node) +# Best for: Mixed hardware environments with different node configurations +# - homogeneous: Groups nodes by hardware type for optimized discovery +# Best for: Standardized hardware groups (grp0-grp100 in pxe_mapping_file.csv) # Performance: 0 iDRAC calls (with specs) or 1 call per group (without specs) -# Default value is heterogeneous +# Default value is heterogeneous # node_hardware_defaults -# Optional: Pre-define hardware specifications for homogeneous node groups -# Only used when node_discovery_mode is set to "homogeneous" -# Key: GROUP_NAME from pxe_mapping_file.csv (e.g., grp0, grp1, grp2, etc.) +# Optional: Pre-define hardware specifications for homogeneous node groups +# Only used when node_discovery_mode is set to "homogeneous" +# Key: GROUP_NAME from pxe_mapping_file.csv (e.g., grp0, grp1, grp2, etc.) # Value: Hardware specifications for all nodes in that group # - sockets: Number of CPU sockets per node (integer, minimum 1) # - cores_per_socket: Number of CPU cores per socket (integer, minimum 1) @@ -103,64 +110,37 @@ # oci # topology # burst_buffer -# Thes files will be written into the slurm_config directory with .conf suffix +# +# These files will be written into the slurm_config directory with .conf suffix +# config_sources: +# slurm: +# SlurmctldTimeout: 60 +# SlurmdTimeout: 150 +# NodeName: +# - NodeName: newnode1 +# CPUs: 16 +# RealMemory: 64000 +# - NodeName: newnode2 +# CPUs: 16 +# RealMemory: 64000 +# cgroup: +# CgroupPlugin: autodetect +# ConstrainCores: True +# ConstrainDevices: True +# ConstrainRAMSpace: True +# ConstrainSwapSpace: True +# +# OR +# +# config_sources: +# slurm: /opt/omnia/input/project_default/slurm.conf +# cgroup: /opt/omnia/input/project_default/cgroup.conf +# slurmdbd: /opt/omnia/input/project_default/slurmdbd.conf slurm_cluster: - cluster_name: slurm_cluster - # nfs_storage_name: References the NFS storage defined in storage_config.yml for Slurm controller data nfs_storage_name: nfs_slurm - - # vast_storage_name: References the VAST high-performance NFS storage defined in storage_config.yml - # Purpose: Centralized repository for HPC tools (UCX, OpenMPI, CUDA, benchmarks) that are - # bind-mounted to /hpc_tools on compute and login nodes. This storage must be - # accessible from OIM during provisioning to copy hpc_tools content to the cluster. - # Configuration: Must match the 'name' field of the VAST storage entry in storage_config.yml - # Note: The VAST server must be reachable from OIM to enable hpc_tools population during - # cluster provisioning. Ensure network connectivity and mount permissions are configured. vast_storage_name: vast_storage - # skip_merge: true - - # Uncomment to enable homogeneous discovery mode - # node_discovery_mode: "homogeneous" - - # Uncomment to provide hardware specs for homogeneous groups - # node_hardware_defaults: - # grp1: - # sockets: 2 - # cores_per_socket: 64 - # threads_per_core: 2 - # real_memory: 512000 - # gres: "gpu:4" - # grp2: - # sockets: 2 - # cores_per_socket: 32 - # threads_per_core: 2 - # real_memory: 256000 - - # config_sources: - # slurm: - # SlurmctldTimeout: 60 - # SlurmdTimeout: 150 - # NodeName: - # - NodeName: newnode1 - # CPUs: 16 - # RealMemory: 64000 - # - NodeName: newnode2 - # CPUs: 16 - # RealMemory: 64000 - # cgroup: - # CgroupPlugin: autodetect - # ConstrainCores: True - # ConstrainDevices: True - # ConstrainRAMSpace: True - # ConstrainSwapSpace: True - - # OR - - # config_sources: - # slurm: /opt/omnia/input/project_default/slurm.conf - # cgroup: /opt/omnia/input/project_default/cgroup.conf - # slurmdbd: /opt/omnia/input/project_default/slurmdbd.conf # ----------------------------SERVICE K8S------------------------------------------------------ # For service k8s cluster below parameters are required,(List) diff --git a/input_validation/ansible.cfg b/input_validation/ansible.cfg index 183d086b85..f5adeaf305 100644 --- a/input_validation/ansible.cfg +++ b/input_validation/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/input_validation/roles/validate_input/tasks/main.yml b/input_validation/roles/validate_input/tasks/main.yml index cb852a74e9..a4e80fb6e2 100644 --- a/input_validation/roles/validate_input/tasks/main.yml +++ b/input_validation/roles/validate_input/tasks/main.yml @@ -14,7 +14,7 @@ --- - name: Initialize list of tags ansible.builtin.set_fact: - omnia_run_tags: "{{ ansible_run_tags | default([]) }}" + omnia_run_tags: "{{ ansible_run_tags | default([]) | list }}" when: omnia_run_tags is not defined - name: Set validation messages diff --git a/input_validation/roles/validate_subscription/tasks/configure_rhel_os_urls.yml b/input_validation/roles/validate_subscription/tasks/configure_rhel_os_urls.yml index ba2220204b..d4a83e6d81 100644 --- a/input_validation/roles/validate_subscription/tasks/configure_rhel_os_urls.yml +++ b/input_validation/roles/validate_subscription/tasks/configure_rhel_os_urls.yml @@ -191,9 +191,13 @@ {%- endfor -%} {{ result }} - - name: Identify non-matching aarch64 override repos + - name: Create name mapping for aarch64 dynamic repos ansible.builtin.set_fact: aarch64_dynamic_names: "{{ sub_rhel_aarch64_urls | map(attribute='name') | list }}" + when: "'aarch64' in archs" + + - name: Identify non-matching aarch64 override repos + ansible.builtin.set_fact: additional_aarch64_repos: >- {{ sub_aarch64_override_config | rejectattr('name', 'in', aarch64_dynamic_names) | list @@ -248,7 +252,7 @@ Expected: {{ required_repos | join(', ') }}. Found: {{ present_repos | join(', ') }} vars: - present_repos: "{{ vars['rhel_url_' ~ arch_item] | map(attribute='name') | list }}" + present_repos: "{{ lookup('vars', 'rhel_url_' ~ arch_item) | map(attribute='name') | list }}" when: present_repos is not superset(required_repos) loop: "{{ archs }}" loop_control: diff --git a/input_validation/validate_config.yml b/input_validation/validate_config.yml index e30491fb82..dc9dfa3913 100644 --- a/input_validation/validate_config.yml +++ b/input_validation/validate_config.yml @@ -36,7 +36,7 @@ - name: Create oim group when: - not oim_group_status | default(false) | bool - - "'local_repo' in (omnia_run_tags | default(ansible_run_tags) | default([])) or 'all' in (ansible_run_tags | default([]))" + - "'local_repo' in (omnia_run_tags | default(ansible_run_tags | default([]) | list)) or 'all' in (ansible_run_tags | default([]) | list)" ansible.builtin.import_playbook: ../utils/create_container_group.yml vars: oim_group: true @@ -51,7 +51,7 @@ - always tasks: - name: Run subscription validation tasks - when: "'local_repo' in (omnia_run_tags | default(ansible_run_tags) | default([])) or 'all' in (ansible_run_tags | default([]))" + when: "'local_repo' in (omnia_run_tags | default(ansible_run_tags | default([]) | list)) or 'all' in (ansible_run_tags | default([]) | list)" block: - name: Include metadata vars ansible.builtin.include_vars: "/opt/omnia/.data/oim_metadata.yml" diff --git a/local_repo/ansible.cfg b/local_repo/ansible.cfg index 60bb2a3005..57097c487c 100644 --- a/local_repo/ansible.cfg +++ b/local_repo/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = roles/parse_and_download/library:../common/library/modules module_utils = ../common/library/module_utils diff --git a/local_repo/local_repo.yml b/local_repo/local_repo.yml index b9400ab89b..d4bb1d488d 100644 --- a/local_repo/local_repo.yml +++ b/local_repo/local_repo.yml @@ -26,7 +26,7 @@ - name: Set dynamic run tags including 'local_repo' ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['local_repo']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['local_repo']) | unique }}" cacheable: true - name: Include metadata vars diff --git a/local_repo/roles/validation/tasks/validate_software_config_json.yml b/local_repo/roles/validation/tasks/validate_software_config_json.yml index 190904eb95..6e734957f1 100644 --- a/local_repo/roles/validation/tasks/validate_software_config_json.yml +++ b/local_repo/roles/validation/tasks/validate_software_config_json.yml @@ -32,16 +32,19 @@ ansible.builtin.set_fact: service_k8s_support: "{{ software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | list | length > 0 }}" software_names: "{{ software_config.softwares | map(attribute='name') | select('defined') | list }}" + +- name: Build software JSON file list + ansible.builtin.set_fact: software_json_list: "{{ software_names | map('regex_replace', '$', '.json') | list }}" - name: Get k8s archs ansible.builtin.set_fact: - service_k8s_arch: "{{ (software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | first).get('arch', default_archs) }}" + service_k8s_arch: "{{ (software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | first).arch | default(['x86_64']) }}" when: service_k8s_support - name: Get k8s archs ansible.builtin.set_fact: - k8s_arch: "{{ (software_config.softwares | selectattr('name', 'equalto', 'k8s') | first).get('arch', default_archs) }}" + k8s_arch: "{{ (software_config.softwares | selectattr('name', 'equalto', 'k8s') | first).arch | default(['x86_64']) }}" when: k8s_support - name: Validation for version property for softwares mentioned in software_config.json @@ -50,7 +53,7 @@ ansible.builtin.assert: that: - item.name not in specific_softwares or (item.version is defined and item.version != "") - loop: "{{ software_config.softwares + software_config.amdgpu + software_config.bcm_roce | default([]) }}" + loop: "{{ software_config.softwares + (software_config.amdgpu | default([])) + (software_config.bcm_roce | default([])) }}" when: item.name is defined loop_control: loop_var: item @@ -61,7 +64,7 @@ ansible.builtin.fail: msg: "{{ item.msg }}" loop: "{{ version_result.results }}" - when: item.evaluated_to is false + when: item.msg is defined and item.msg == 'Assertion failed' rescue: - name: Versions were not defined for softwares diff --git a/log_collector/roles/log_collector/tasks/bundle.yml b/log_collector/roles/log_collector/tasks/bundle.yml index 8d2757d729..21d67574e1 100644 --- a/log_collector/roles/log_collector/tasks/bundle.yml +++ b/log_collector/roles/log_collector/tasks/bundle.yml @@ -22,7 +22,7 @@ - name: Override collection mode to curated_support when tag is active ansible.builtin.set_fact: collection_mode: "curated_support" - when: "'curated_support' in ansible_run_tags" + when: "'curated_support' in (ansible_run_tags | list)" - name: Set ISO-8601 warning timestamp for this run ansible.builtin.set_fact: diff --git a/omnia.sh b/omnia.sh index 353aa9b5ca..9bc5856605 100755 --- a/omnia.sh +++ b/omnia.sh @@ -30,6 +30,7 @@ GREEN='\033[0;32m' BLUE='\033[0;34m' NC='\033[0m' # No Color YELLOW='\033[0;33m' +WHITE='\033[0;37m' # Function to get version from git tag get_version_from_git_tag() { @@ -1657,6 +1658,123 @@ phase2_approval() { return 0 } +# ═══════════════════════════════════════════════════════════════════════════ +# validate_backup_disk_space: Pre-upgrade disk space validation +# Ensures sufficient space exists before backup creation to prevent partial +# backups due to disk full conditions. +# ═══════════════════════════════════════════════════════════════════════════ +validate_backup_disk_space() { + local backup_base="$1" + local safety_multiplier=2 # Require 2× the estimated backup size + + echo "[INFO] [ORCHESTRATOR] Validating disk space for backup..." + + if ! podman ps --format '{{.Names}}' | grep -qw "omnia_core"; then + echo "[ERROR] [ORCHESTRATOR] Cannot validate disk space: omnia_core container not running" + return 1 + fi + + # Calculate size of data to be backed up (in KB) + local input_size=0 + local openchami_size=0 + local metadata_size=0 + + # Get input directory size + input_size=$(podman exec -u root omnia_core bash -c " + if [ -d '$CONTAINER_INPUT_DIR' ]; then + du -sk '$CONTAINER_INPUT_DIR' 2>/dev/null | cut -f1 + else + echo 0 + fi + " 2>/dev/null || echo 0) + + # Get OpenCHAMI directory size + openchami_size=$(podman exec -u root omnia_core bash -c " + if [ -d '/opt/omnia/openchami' ]; then + du -sk '/opt/omnia/openchami' 2>/dev/null | cut -f1 + else + echo 0 + fi + " 2>/dev/null || echo 0) + + # Get metadata file size (small, but include for completeness) + metadata_size=$(podman exec -u root omnia_core bash -c " + if [ -f '$CONTAINER_METADATA_FILE' ]; then + du -sk '$CONTAINER_METADATA_FILE' 2>/dev/null | cut -f1 + else + echo 0 + fi + " 2>/dev/null || echo 0) + + # Ensure values are numeric + input_size=${input_size:-0} + openchami_size=${openchami_size:-0} + metadata_size=${metadata_size:-0} + + # Calculate total estimated backup size + local total_backup_size_kb=$((input_size + openchami_size + metadata_size)) + + # Add buffer for quadlet files from host (~100KB typical) + total_backup_size_kb=$((total_backup_size_kb + 100)) + + # Calculate required space with safety multiplier + local required_space_kb=$((total_backup_size_kb * safety_multiplier)) + + # Convert to human-readable for display + local total_backup_size_mb=$((total_backup_size_kb / 1024)) + local required_space_mb=$((required_space_kb / 1024)) + + echo "[INFO] [ORCHESTRATOR] Estimated backup size: ${total_backup_size_mb}MB" + echo "[INFO] [ORCHESTRATOR] Required space (${safety_multiplier}× safety margin): ${required_space_mb}MB" + + # Get available space on backup destination filesystem + # The backup path is inside the container, which maps to the omnia share + local backup_parent_dir + backup_parent_dir=$(dirname "$backup_base") + + local available_space_kb + available_space_kb=$(podman exec -u root omnia_core bash -c " + # Ensure parent directory exists for df check + mkdir -p '$backup_parent_dir' 2>/dev/null || true + df -k '$backup_parent_dir' 2>/dev/null | tail -1 | awk '{print \$4}' + " 2>/dev/null) + + if [ -z "$available_space_kb" ] || ! [[ "$available_space_kb" =~ ^[0-9]+$ ]]; then + echo "[WARN] [ORCHESTRATOR] Could not determine available disk space; proceeding with backup" + return 0 + fi + + local available_space_mb=$((available_space_kb / 1024)) + echo "[INFO] [ORCHESTRATOR] Available space on backup filesystem: ${available_space_mb}MB" + + # Check if sufficient space is available + if [ "$available_space_kb" -lt "$required_space_kb" ]; then + echo "" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo -e "${RED} INSUFFICIENT DISK SPACE FOR BACKUP${NC}" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo "" + echo -e "${RED}ERROR: Not enough disk space to safely create upgrade backup.${NC}" + echo "" + echo -e "${YELLOW}Disk Space Summary:${NC}" + echo -e "${YELLOW} - Estimated backup size: ${total_backup_size_mb}MB${NC}" + echo -e "${YELLOW} - Required space (${safety_multiplier}×): ${required_space_mb}MB${NC}" + echo -e "${YELLOW} - Available space: ${available_space_mb}MB${NC}" + echo -e "${YELLOW} - Shortfall: $((required_space_mb - available_space_mb))MB${NC}" + echo "" + echo -e "${YELLOW}Backup destination: $backup_base${NC}" + echo "" + echo -e "${GREEN}Required Action:${NC}" + echo -e "${GREEN} 1. Free up at least $((required_space_mb - available_space_mb))MB on the Omnia share${NC}" + echo -e "${GREEN} 2. Re-run 'omnia.sh --upgrade' after freeing space${NC}" + echo "" + return 1 + fi + + echo "[INFO] [ORCHESTRATOR] Disk space validation passed" + return 0 +} + backup_openchami_data() { local backup_base="$1" @@ -1702,6 +1820,17 @@ backup_openchami_data() { echo "[INFO] [ORCHESTRATOR] Quadlet .container files backed up" fi + # Backup quadlet .network files from host (if they exist) + # These define Podman networks that enable DNS resolution between containers + if ls /etc/containers/systemd/*.network >/dev/null 2>&1; then + podman exec -u root omnia_core mkdir -p "${backup_base%/}/openchami/quadlets" 2>/dev/null || true + for nfile in /etc/containers/systemd/*.network; do + podman cp "$nfile" \ + "omnia_core:${backup_base%/}/openchami/quadlets/$(basename "$nfile")" >/dev/null 2>&1 || true + done + echo "[INFO] [ORCHESTRATOR] Quadlet .network files backed up" + fi + echo "[INFO] [ORCHESTRATOR] OpenCHAMI data backup completed: ${backup_base}/openchami/" return 0 } @@ -1725,13 +1854,17 @@ phase3_backup_creation() { set -e rm -rf '${backup_base%/}/input' '${backup_base%/}/metadata' '${backup_base%/}/configs' mkdir -p '${backup_base%/}/input' '${backup_base%/}/metadata' '${backup_base%/}/configs' + chmod 0700 '${backup_base%/}' '${backup_base%/}/input' '${backup_base%/}/metadata' '${backup_base%/}/configs' if [ -f '$CONTAINER_INPUT_DIR/default.yml' ]; then cp -a '$CONTAINER_INPUT_DIR/default.yml' '${backup_base%/}/input/' + chmod 0600 '${backup_base%/}/input/default.yml' fi if [ -d '$CONTAINER_INPUT_DIR/project_default' ]; then cp -a '$CONTAINER_INPUT_DIR/project_default' '${backup_base%/}/input/' + chmod -R 0600 '${backup_base%/}/input/project_default'/* + find '${backup_base%/}/input/project_default' -type d -exec chmod 0700 {} \; fi if [ ! -f '$CONTAINER_METADATA_FILE' ]; then @@ -1739,6 +1872,7 @@ phase3_backup_creation() { exit 1 fi cp -a '$CONTAINER_METADATA_FILE' '${backup_base%/}/metadata/oim_metadata.yml' + chmod 0600 '${backup_base%/}/metadata/oim_metadata.yml' "; then echo "[ERROR] [ORCHESTRATOR] Backup failed; cleaning up partial backup" podman exec -u root omnia_core bash -c "rm -rf '${backup_base%/}/input' '${backup_base%/}/metadata' '${backup_base%/}/configs'" >/dev/null 2>&1 || true @@ -1751,6 +1885,7 @@ phase3_backup_creation() { podman exec -u root omnia_core bash -c "rm -rf '${backup_base%/}/input' '${backup_base%/}/metadata' '${backup_base%/}/configs'" >/dev/null 2>&1 || true return 1 fi + podman exec -u root omnia_core chmod 0600 "${backup_base%/}/configs/omnia_core.container" 2>/dev/null || true fi echo "[INFO] [ORCHESTRATOR] Backup created at: $backup_base" @@ -2104,6 +2239,12 @@ upgrade_omnia_core() { exit 1 fi + # Validate disk space before backup creation + if ! validate_backup_disk_space "$backup_base"; then + echo "[ERROR] [ORCHESTRATOR] Upgrade aborted: Insufficient disk space for backup" + exit 1 + fi + if ! phase3_backup_creation "$backup_base"; then echo "[ERROR] [ORCHESTRATOR] Upgrade failed in Phase 3" exit 1 @@ -2302,6 +2443,94 @@ rollback_omnia_core() { echo -e "${RED}ERROR: Omnia core container is not running.${NC}" exit 1 fi + + # ═══════════════════════════════════════════════════════════════════════════ + # SAFETY CHECK: Prevent core container rollback if upgrade.yml was run but + # rollback.yml has not completed successfully inside the container. + # This prevents inconsistent state where core is 2.1 but other components are 2.2. + # ═══════════════════════════════════════════════════════════════════════════ + local upgrade_manifest_path="/opt/omnia/.data/upgrade_manifest.yml" + local rollback_manifest_path="/opt/omnia/.data/rollback_manifest.yml" + + # Check if upgrade_manifest.yml exists (indicates upgrade process was started) + if podman exec -u root omnia_core test -f "$upgrade_manifest_path" 2>/dev/null; then + echo "[INFO] [ROLLBACK] Checking upgrade state before proceeding..." + + # Read component statuses from upgrade_manifest.yml + local component_statuses + component_statuses=$(podman exec -u root omnia_core grep -A20 'component_status:' "$upgrade_manifest_path" 2>/dev/null | grep -E '^\s+\w+:' | head -8) + + # Check if any component has been upgraded (status is not "pending") + local has_upgraded_components=false + if echo "$component_statuses" | grep -qvE ':\s*"?pending"?\s*$'; then + has_upgraded_components=true + fi + + if [ "$has_upgraded_components" = true ]; then + echo "[INFO] [ROLLBACK] Detected upgraded components. Checking rollback.yml completion status..." + + # Components have been upgraded - check if rollback.yml completed successfully + if podman exec -u root omnia_core test -f "$rollback_manifest_path" 2>/dev/null; then + local rollback_status + rollback_status=$(podman exec -u root omnia_core grep '^rollback_status:' "$rollback_manifest_path" 2>/dev/null | cut -d':' -f2 | tr -d ' \t\n\r"') + + if [ "$rollback_status" != "completed" ]; then + echo "" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo -e "${RED} CORE CONTAINER ROLLBACK BLOCKED${NC}" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo "" + echo -e "${RED}ERROR: Cannot rollback core container at this time.${NC}" + echo "" + echo -e "${YELLOW}Reason: upgrade.yml has upgraded components, but rollback.yml has not${NC}" + echo -e "${YELLOW} completed successfully inside the container.${NC}" + echo "" + echo -e "${YELLOW}Current rollback status: ${rollback_status:-'unknown'}${NC}" + echo "" + echo -e "${YELLOW}Rolling back the core container now would leave your cluster in an${NC}" + echo -e "${YELLOW}inconsistent state where:${NC}" + echo -e "${YELLOW} - Core container: 2.1 (rolled back)${NC}" + echo -e "${YELLOW} - Other components: 2.2 (not rolled back)${NC}" + echo "" + echo -e "${GREEN}Required Action:${NC}" + echo -e "${GREEN} 1. First run rollback.yml inside the container to rollback all components${NC}" + echo -e "${GREEN} 2. Wait for rollback.yml to complete successfully${NC}" + echo -e "${GREEN} 3. Then run 'omnia.sh --rollback' to rollback the core container${NC}" + echo "" + exit 1 + fi + echo "[INFO] [ROLLBACK] Rollback playbook completed successfully. Proceeding with core container rollback." + else + # Rollback manifest doesn't exist but components were upgraded + echo "" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo -e "${RED} CORE CONTAINER ROLLBACK BLOCKED${NC}" + echo -e "${RED}═══════════════════════════════════════════════════════════════════════════${NC}" + echo "" + echo -e "${RED}ERROR: Cannot rollback core container at this time.${NC}" + echo "" + echo -e "${YELLOW}Reason: upgrade.yml has upgraded components, but rollback.yml has not${NC}" + echo -e "${YELLOW} been executed inside the container.${NC}" + echo "" + echo -e "${YELLOW}Rolling back the core container now would leave your cluster in an${NC}" + echo -e "${YELLOW}inconsistent state where:${NC}" + echo -e "${YELLOW} - Core container: 2.1 (rolled back)${NC}" + echo -e "${YELLOW} - Other components: 2.2 (not rolled back)${NC}" + echo "" + echo -e "${GREEN}Required Action:${NC}" + echo -e "${GREEN} 1. First run rollback.yml inside the container to rollback all components${NC}" + echo -e "${GREEN} 2. Wait for rollback.yml to complete successfully${NC}" + echo -e "${GREEN} 3. Then run 'omnia.sh --rollback' to rollback the core container${NC}" + echo "" + exit 1 + fi + else + echo "[INFO] [ROLLBACK] No components upgraded yet. Core container rollback is safe to proceed." + fi + else + echo -e "${WHITE}[INFO] [ROLLBACK] No upgrade manifest found. Core container rollback is safe to proceed.${NC}" + fi + # ═══════════════════════════════════════════════════════════════════════════ # Create lock file to prevent concurrent rollbacks local lock_file="/tmp/omnia_rollback.lock" @@ -2408,6 +2637,14 @@ rollback_omnia_core() { rm -f "$upgrade_guard_lock_path" >/dev/null 2>&1 || true echo "[INFO] [ROLLBACK] Cleared upgrade guard lock: $upgrade_guard_lock_path" + # Remove upgrade_backup_dir and previous_omnia_version from metadata + # These are upgrade-only fields that should not persist after rollback + podman exec -u root omnia_core bash -c " + sed -i '/^upgrade_backup_dir:/d' '$CONTAINER_METADATA_FILE' 2>/dev/null || true + sed -i '/^previous_omnia_version:/d' '$CONTAINER_METADATA_FILE' 2>/dev/null || true + " 2>/dev/null || true + echo "[INFO] [ROLLBACK] Cleaned upgrade_backup_dir and previous_omnia_version from metadata" + # Fetch config from restored metadata (populates omnia_path, domain_name, etc.) fetch_config @@ -2545,6 +2782,14 @@ rollback_omnia_core() { rm -f "$upgrade_guard_lock_path" >/dev/null 2>&1 || true echo "[INFO] [ROLLBACK] Cleared upgrade guard lock: $upgrade_guard_lock_path" + # Remove upgrade_backup_dir and previous_omnia_version from metadata + # These are upgrade-only fields that should not persist after rollback + podman exec -u root omnia_core bash -c " + sed -i '/^upgrade_backup_dir:/d' '$CONTAINER_METADATA_FILE' 2>/dev/null || true + sed -i '/^previous_omnia_version:/d' '$CONTAINER_METADATA_FILE' 2>/dev/null || true + " 2>/dev/null || true + echo "[INFO] [ROLLBACK] Cleaned upgrade_backup_dir and previous_omnia_version from metadata" + # Fetch config from restored metadata (populates omnia_path, domain_name, etc.) fetch_config diff --git a/prepare_oim/ansible.cfg b/prepare_oim/ansible.cfg index e3d0666533..84969280c3 100644 --- a/prepare_oim/ansible.cfg +++ b/prepare_oim/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/prepare_oim/prepare_oim.yml b/prepare_oim/prepare_oim.yml index 51f9dc1f0c..4a9c969499 100644 --- a/prepare_oim/prepare_oim.yml +++ b/prepare_oim/prepare_oim.yml @@ -31,7 +31,7 @@ omnia_run_tags: >- {{ ( - ansible_run_tags | default([]) + + ansible_run_tags | default([]) | list + ['prepare_oim', 'local_repo', 'discovery', 'provision'] ) | unique }} diff --git a/prepare_oim/roles/deploy_containers/auth/vars/main.yml b/prepare_oim/roles/deploy_containers/auth/vars/main.yml index 49c72cbc13..01ceb2007a 100644 --- a/prepare_oim/roles/deploy_containers/auth/vars/main.yml +++ b/prepare_oim/roles/deploy_containers/auth/vars/main.yml @@ -23,7 +23,7 @@ openldap_ports: - 636 wait_time: 10 auth_service_image_name: omnia_auth -auth_service_image_tag: "1.0" +auth_service_image_tag: "1.1" auth_service_registry: "docker.io/dellhpcomniaaisolution" auth_service_container_name: omnia_auth auth_service_image_pull_fail_msg: diff --git a/prepare_oim/roles/prepare_oim_validation/tasks/check_k8s_support.yml b/prepare_oim/roles/prepare_oim_validation/tasks/check_k8s_support.yml index b3b4c76fb9..f9c1e701bd 100644 --- a/prepare_oim/roles/prepare_oim_validation/tasks/check_k8s_support.yml +++ b/prepare_oim/roles/prepare_oim_validation/tasks/check_k8s_support.yml @@ -29,7 +29,7 @@ - name: Extract service k8s version ansible.builtin.set_fact: k8s_versions: "{{ software_config.softwares | selectattr('name', 'in', ['compute_k8s', 'service_k8s']) | map(attribute='version') | list | unique }}" # noqa: yaml[line-length] - k8s_arch: "{{ (software_config.softwares | selectattr('name', 'in', ['compute_k8s', 'service_k8s']) | first).get('arch', default_archs) }}" + k8s_arch: "{{ (software_config.softwares | selectattr('name', 'in', ['compute_k8s', 'service_k8s']) | first).arch | default(['x86_64']) }}" - name: Set k8s_support_check to false if any k8s version is not in supported_k8s_versions ansible.builtin.set_fact: diff --git a/provision/ansible.cfg b/provision/ansible.cfg index 3d1500dd3b..b65edbf7ab 100644 --- a/provision/ansible.cfg +++ b/provision/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = library:../common/library/modules module_utils = ../common/library/module_utils diff --git a/provision/provision.yml b/provision/provision.yml index 5aac96f3dc..e476c50835 100644 --- a/provision/provision.yml +++ b/provision/provision.yml @@ -62,7 +62,7 @@ omnia_run_tags: >- {{ ( - ansible_run_tags | default([]) + + ansible_run_tags | default([]) | list + ['provision', 'slurm', 'slurm_custom', 'security', 'csi_driver_powerscale', 'ldms', 'telemetry'] + ( ['service_k8s'] diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_aarch64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_aarch64.yaml.j2 index cead7f3bf6..5a5b73da5e 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_aarch64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_aarch64.yaml.j2 @@ -131,6 +131,12 @@ content: | {{ lookup('template', 'templates/hpc_tools/install_ucx.sh.j2') | indent(12) }} + - path: /usr/local/bin/setup_doca_mpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_doca_mpi_env.sh.j2') | indent(12) }} + {% if dns_enabled | default(false) | bool %} - path: /etc/resolv.conf owner: root:root @@ -182,7 +188,8 @@ permissions: '{{ file_mode_755 }}' content: | {{ lookup('template', 'templates/hpc_tools/setup_nvhpc_sdk.sh.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} + +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -203,7 +210,7 @@ - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -228,7 +235,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for login+compiler node @@ -278,6 +285,7 @@ - echo "===== OpenMPI Configuration =====" - echo "OpenMPI version specified in software_config.json (available for manual compilation)" - echo "Default stack - DOCA OpenMPI 4.1.9a1 (system default)" + - bash /usr/local/bin/setup_doca_mpi_env.sh || echo "DOCA MPI environment setup failed (non-critical)" {% endif %} {% if ldms_support %} @@ -381,4 +389,4 @@ # NVIDIA HPC SDK: Script deployed to /usr/local/bin/setup_nvhpc_sdk.sh # User must run manually after cloud-init completes - echo "Cloud-Init has completed successfully." - - echo "To install NVIDIA HPC SDK, run: /usr/local/bin/setup_nvhpc_sdk.sh --install" \ No newline at end of file + - echo "To install NVIDIA HPC SDK, run: /usr/local/bin/setup_nvhpc_sdk.sh --install" diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_x86_64.yaml.j2 index 3fba092202..7cedbbbc00 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_compiler_node_x86_64.yaml.j2 @@ -129,6 +129,13 @@ permissions: '{{ file_mode_755 }}' content: | {{ lookup('template', 'templates/hpc_tools/install_ucx.sh.j2') | indent(12) }} + + - path: /usr/local/bin/setup_doca_mpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_doca_mpi_env.sh.j2') | indent(12) }} + {% if dns_enabled | default(false) | bool %} - path: /etc/resolv.conf @@ -182,7 +189,7 @@ content: | {{ lookup('template', 'templates/hpc_tools/setup_nvhpc_sdk.sh.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -203,7 +210,7 @@ - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -228,7 +235,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for login+compiler node @@ -279,6 +286,8 @@ - echo "===== OpenMPI Configuration =====" - echo "OpenMPI version specified in software_config.json (available for manual compilation)" - echo "Default stack - DOCA OpenMPI 4.1.9a1 (system default)" + - bash /usr/local/bin/setup_doca_mpi_env.sh || echo "DOCA MPI environment setup failed (non-critical)" + {% endif %} {% if ldms_support %} @@ -386,4 +395,4 @@ # User must run manually after cloud-init completes - echo "Run /usr/local/bin/setup_nvhpc_sdk.sh --install to install NVIDIA HPC SDK" - echo "Cloud-Init has completed successfully." - \ No newline at end of file + diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_aarch64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_aarch64.yaml.j2 index df8389b3e1..5410ac2d5a 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_aarch64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_aarch64.yaml.j2 @@ -145,7 +145,7 @@ permissions: '0644' content: | {{ lookup('template', 'templates/nodes/apptainer_mirror.conf.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -166,7 +166,7 @@ - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -191,7 +191,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for login node diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_x86_64.yaml.j2 index af74a044c9..93cac94165 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-login_node_x86_64.yaml.j2 @@ -144,7 +144,7 @@ permissions: '0644' content: | {{ lookup('template', 'templates/nodes/apptainer_mirror.conf.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -165,7 +165,7 @@ - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -190,7 +190,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for login node diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_first_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_first_x86_64.yaml.j2 index 8bbaa7ca74..d86341fbd2 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_first_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_first_x86_64.yaml.j2 @@ -178,8 +178,8 @@ location = "gcr.io" [[registry.mirror]] location = "{{ pulp_mirror }}" -{% if user_registry | default([]) | length > 0 %} -{% for registry in user_registry %} +{% if user_registry | default([], true) | length > 0 %} +{% for registry in user_registry | default([], true) %} [[registry]] prefix = "{{ registry.host }}" @@ -348,7 +348,7 @@ - "chronyc sources" - "chronyc -a makestep" {# Mount-specific runcmd entries #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -370,7 +370,7 @@ {% endif %} {% endif %} {% endraw %} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # K8s NFS mount entries @@ -445,7 +445,7 @@ [ -n "$search_line" ] && echo "$search_line" > "$tmpfile" # Add your new nameserver entries - {% for ns in dns %} + {% for ns in dns | default([], true) %} echo "nameserver {{ ns }}" >> "$tmpfile" {% endfor %} @@ -480,7 +480,7 @@ echo "Installing Necessary Python pip packages" python3 -m ensurepip - PACKAGES=({% for pkg in k8s_pip_packages %}"{{ pkg }}"{% if not loop.last %} {% endif %}{% endfor %}) + PACKAGES=({% for pkg in k8s_pip_packages | default([], true) %}"{{ pkg }}"{% if not loop.last %} {% endif %}{% endfor %}) for pkg in "${PACKAGES[@]}"; do echo "Installing $pkg from offline repo..." @@ -630,7 +630,7 @@ kubectl -n kube-system get configmap coredns -o yaml > "$cfg" # Patch: append nameservers after /etc/resolv.conf using Jinja list "dns" - sed -i 's|/etc/resolv.conf|/etc/resolv.conf{% for ns in dns %} {{ ns }}{% endfor %}|' "$cfg" + sed -i 's|/etc/resolv.conf|/etc/resolv.conf{% for ns in dns | default([], true) %} {{ ns }}{% endfor %}|' "$cfg" {% if dns_enabled | default(false) | bool %} # Forward cluster-internal DNS domain to OIM CoreDNS diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_x86_64.yaml.j2 index f381046222..37ef9f69d2 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_control_plane_x86_64.yaml.j2 @@ -149,8 +149,8 @@ location = "gcr.io" [[registry.mirror]] location = "{{ pulp_mirror }}" -{% if user_registry | default([]) | length > 0 %} -{% for registry in user_registry %} +{% if user_registry | default([], true) | length > 0 %} +{% for registry in user_registry | default([], true) %} [[registry]] prefix = "{{ registry.host }}" @@ -248,7 +248,7 @@ # Optional: Set up bash completion /usr/local/bin/helm completion bash > /etc/bash_completion.d/helm.sh chmod 0755 /etc/bash_completion.d/helm.sh -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -262,7 +262,7 @@ - "chronyc sources" - "chronyc -a makestep" {# Mount-specific runcmd entries #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -284,7 +284,7 @@ {% endif %} {% endif %} {% endraw %} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # K8s NFS mount entries @@ -360,7 +360,7 @@ [ -n "$search_line" ] && echo "$search_line" > "$tmpfile" # Add your new nameserver entries - {% for ns in dns %} + {% for ns in dns | default([], true) %} echo "nameserver {{ ns }}" >> "$tmpfile" {% endfor %} @@ -394,7 +394,7 @@ echo "Installing Necessary Python pip packages" python3 -m ensurepip - PACKAGES=({% for pkg in k8s_pip_packages %}"{{ pkg }}"{% if not loop.last %} {% endif %}{% endfor %}) + PACKAGES=({% for pkg in k8s_pip_packages | default([], true) %}"{{ pkg }}"{% if not loop.last %} {% endif %}{% endfor %}) for pkg in "${PACKAGES[@]}"; do echo "Installing $pkg from offline repo..." diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_node_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_node_x86_64.yaml.j2 index 1683736916..843be05a37 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_node_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-service_kube_node_x86_64.yaml.j2 @@ -137,8 +137,8 @@ location = "gcr.io" [[registry.mirror]] location = "{{ pulp_mirror }}" -{% if user_registry | default([]) | length > 0 %} -{% for registry in user_registry %} +{% if user_registry | default([], true) | length > 0 %} +{% for registry in user_registry | default([], true) %} [[registry]] prefix = "{{ registry.host }}" @@ -147,7 +147,7 @@ location = "{{ pulp_mirror }}" {% endfor %} {% endif %} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -161,7 +161,7 @@ - "chronyc sources" - "chronyc -a makestep" {# Mount-specific runcmd entries #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -183,7 +183,7 @@ {% endif %} {% endif %} {% endraw %} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # K8s NFS mount entries @@ -246,7 +246,7 @@ [ -n "$search_line" ] && echo "$search_line" > "$tmpfile" # Add your new nameserver entries - {% for ns in dns %} + {% for ns in dns | default([], true) %} echo "nameserver {{ ns }}" >> "$tmpfile" {% endfor %} diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64.yaml.j2 index 8196f0383d..e442c2b5f8 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_control_node_x86_64.yaml.j2 @@ -77,7 +77,7 @@ IdentityFile {{ client_mount_path }}/slurm/ssh/oim_rsa IdentitiesOnly yes {% if cloud_init_groups_dict[functional_group_name].powervault_scripts is defined %} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -297,7 +297,7 @@ - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -322,7 +322,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # Ensure Slurm NFS root is mounted at client_mount_path (e.g. /share_omnia) diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_aarch64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_aarch64.yaml.j2 index 61f7909f0d..2f7f52c930 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_aarch64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_aarch64.yaml.j2 @@ -385,14 +385,21 @@ permissions: '{{ file_mode_755 }}' content: | {{ lookup('template', 'templates/hpc_tools/configure_ucx_openmpi_env.sh.j2') | indent(12) }} - + + - path: /usr/local/bin/setup_doca_mpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_doca_mpi_env.sh.j2') | indent(12) }} + # NVIDIA HPC SDK setup script (run manually: /usr/local/bin/setup_nvhpc_sdk.sh) - path: /usr/local/bin/setup_nvhpc_sdk.sh owner: root:root permissions: '{{ file_mode_755 }}' content: | {{ lookup('template', 'templates/hpc_tools/setup_nvhpc_sdk.sh.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} + +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -409,8 +416,12 @@ # DOCA and IB configuration - now ready before vendor_data mounts - bash /usr/local/bin/doca-install.sh || true - bash /usr/local/bin/configure-ib-network.sh +{% if hostvars['localhost']['openmpi_support'] %} + - bash /usr/local/bin/setup_doca_mpi_env.sh || echo "DOCA MPI environment setup failed (non-critical)" +{% endif %} + {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -435,7 +446,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for compute node diff --git a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64.yaml.j2 b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64.yaml.j2 index df62d8d7d4..427703257c 100644 --- a/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64.yaml.j2 +++ b/provision/roles/configure_ochami/templates/cloud_init/ci-group-slurm_node_x86_64.yaml.j2 @@ -390,13 +390,21 @@ content: | {{ lookup('template', 'templates/hpc_tools/configure_ucx_openmpi_env.sh.j2') | indent(12) }} + - path: /usr/local/bin/setup_doca_mpi_env.sh + owner: root:root + permissions: '{{ file_mode_755 }}' + content: | + {{ lookup('template', 'templates/hpc_tools/setup_doca_mpi_env.sh.j2') | indent(12) }} + + # NVIDIA HPC SDK setup script (run manually: /usr/local/bin/setup_nvhpc_sdk.sh) - path: /usr/local/bin/setup_nvhpc_sdk.sh owner: root:root permissions: '{{ file_mode_755 }}' content: | {{ lookup('template', 'templates/hpc_tools/setup_nvhpc_sdk.sh.j2') | indent(12) }} -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} + +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - path: /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh permissions: '{{ file_mode_755 }}' content: | @@ -414,8 +422,12 @@ # DOCA and IB configuration - now ready before vendor_data mounts - bash /usr/local/bin/doca-install.sh || echo "DOCA install failed (non-critical)" - bash /usr/local/bin/configure-ib-network.sh || echo "IB network configuration failed (non-critical)" +{% if hostvars['localhost']['openmpi_support'] %} + - bash /usr/local/bin/setup_doca_mpi_env.sh || echo "DOCA MPI environment setup failed (non-critical)" +{% endif %} + {# Mount-specific runcmd entries - moved after DOCA to ensure RDMA is available #} -{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined %} +{%- if cloud_init_groups_dict[functional_group_name].runcmd is defined and cloud_init_groups_dict[functional_group_name].runcmd is not none %} {% for cmd in cloud_init_groups_dict[functional_group_name].runcmd %} - {{ cmd }} {% endfor %} @@ -440,7 +452,7 @@ {% set fg_swap = cloud_init_groups_dict.get(functional_group_name, {}).get('swap', {}) %} {% include 'configure_swap.yaml.j2' %} - mount -av -{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([]) %} +{% for pv_entry in cloud_init_groups_dict[functional_group_name].powervault_scripts | default([], true) %} - bash /usr/local/bin/setup_iscsi_storage_{{ pv_entry.name }}.sh {% endfor %} # VAST storage: create subdirectory structure for compute node diff --git a/provision/roles/configure_ochami/templates/doca-ofed/configure-ib-network.sh.j2 b/provision/roles/configure_ochami/templates/doca-ofed/configure-ib-network.sh.j2 index 0bc535918e..9ecc30d17f 100644 --- a/provision/roles/configure_ochami/templates/doca-ofed/configure-ib-network.sh.j2 +++ b/provision/roles/configure_ochami/templates/doca-ofed/configure-ib-network.sh.j2 @@ -86,10 +86,6 @@ else exit 1 fi -echo "INFO: Successfully parsed slot-based format" - echo "INFO: Extracted slot number: $SLOT_NUMBER" - echo "INFO: Extracted port number: $PORT_NUMBER" - # Check if IB hardware is present if ! ls /sys/class/infiniband/ >/dev/null 2>&1; then echo "ERROR: No IB hardware found in /sys/class/infiniband/" @@ -117,40 +113,57 @@ for mlx_device in /sys/class/infiniband/mlx5_*; do fi done -# Simple slot-to-device mapping function -find_device_by_slot() { - local target_slot="$1" - - echo "DEBUG: Starting slot-based device search for slot '$target_slot'" >&2 - - for mlx_device in /sys/class/infiniband/mlx5_*; do - [ -e "$mlx_device" ] || continue - device_name=$(basename "$mlx_device") - - # Get PCI address and extract slot number - pci_address=$(basename "$(readlink -f "/sys/class/infiniband/$device_name/device" 2>/dev/null)") - if [ -n "$pci_address" ]; then - # Extract slot from PCI address: 0000:17:00.0 → "17" - pci_slot=$(echo "$pci_address" | cut -d: -f2 | sed 's/^0*//') - target_clean=$(echo "$target_slot" | sed 's/^0*//') - - echo "DEBUG: Checking device $device_name: PCI $pci_address → slot $pci_slot (target: $target_clean)" >&2 - - if [[ "$pci_slot" == "$target_clean" ]]; then - echo "SUCCESS: Found matching device! Slot $target_clean matches PCI slot $pci_slot for device $device_name" >&2 - echo "$device_name" - return 0 - else - echo "DEBUG: Slot mismatch - device $device_name has PCI slot $pci_slot, looking for slot $target_clean" >&2 - fi - else - echo "DEBUG: Could not get PCI address for device $device_name" >&2 +# Always verify mlx5 devices are InfiniBand-capable using ibstat +# This prevents Ethernet-only Mellanox NICs from being configured as IB devices +if command -v ibstat >/dev/null 2>&1; then + echo "INFO: Verifying mlx5 devices are InfiniBand-capable using ibstat" + + IB_DEVICES=() + current_ca="" + + while IFS= read -r line; do + if [[ "$line" =~ ^CA\ \'(mlx5_[0-9]+)\' ]]; then + current_ca="${BASH_REMATCH[1]}" + echo "DEBUG: Found mlx5 device: $current_ca" + elif [[ "$line" =~ Link\ layer:\ InfiniBand ]] && [ -n "$current_ca" ]; then + IB_DEVICES+=("$current_ca") + echo "DEBUG: Device $current_ca has InfiniBand link layer - adding to list" + current_ca="" + elif [[ "$line" =~ Link\ layer:\ (.+) ]] && [ -n "$current_ca" ]; then + link_layer="${BASH_REMATCH[1]}" + echo "DEBUG: Device $current_ca has '$link_layer' link layer - skipping" + current_ca="" + elif [[ "$line" =~ ^CA\ \' ]] && [ -n "$current_ca" ]; then + echo "DEBUG: Device $current_ca does not have InfiniBand link layer - skipping" + current_ca="" fi + done < <(ibstat 2>/dev/null) + + FILTERED_COUNT=0 + for device in "${IB_DEVICES[@]}"; do + FILTERED_COUNT=$((FILTERED_COUNT + 1)) done - - echo "ERROR: No device found matching slot '$target_slot'" >&2 - return 1 -} + + if [ "$FILTERED_COUNT" -gt 0 ]; then + if [ "$MLX5_DEVICE_COUNT" -ne "$FILTERED_COUNT" ]; then + echo "INFO: Filtered $MLX5_DEVICE_COUNT mlx5 devices down to $FILTERED_COUNT InfiniBand-capable devices" + fi + MLX5_DEVICE_COUNT="$FILTERED_COUNT" + + if [ "$FILTERED_COUNT" -eq 1 ]; then + echo "INFO: Only one InfiniBand device found - using single-device mode" + SINGLE_IB_DEVICE="${IB_DEVICES[0]}" + fi + else + echo "ERROR: ibstat filtering found no InfiniBand-capable mlx5 devices" + echo "ERROR: All found mlx5 devices are Ethernet-only (RoCE) or not InfiniBand-capable" + echo "ERROR: Please ensure at least one Mellanox device has InfiniBand link layer" + exit 1 + fi +else + echo "WARNING: ibstat command not found. Cannot verify devices are InfiniBand-capable" + echo "WARNING: Proceeding with all mlx5 devices - may include Ethernet-only NICs" +fi # === DEVICE COUNT ANALYSIS AND SELECTION LOGIC === echo "INFO: DEVICE ANALYSIS: Analyzing mlx5 device count for configuration strategy" @@ -159,69 +172,99 @@ if [ "$MLX5_DEVICE_COUNT" -eq 0 ]; then echo "ERROR: DEVICE ANALYSIS: No mlx5 devices found on this system" echo "ERROR: DEVICE ANALYSIS: Please check hardware and driver installation" exit 1 - + elif [ "$MLX5_DEVICE_COUNT" -eq 1 ]; then echo "INFO: SINGLE-DEVICE MODE: Only one mlx5 device available - no slot-based mapping needed" - echo "INFO: SINGLE-DEVICE MODE: Using available device regardless of slot number in PXE mapping" + echo "INFO: SINGLE-DEVICE MODE: Using available device (slot number from PXE mapping ignored)" echo "INFO: SINGLE-DEVICE MODE: This ensures robustness for single-device deployments" - - MLX5_DEVICE=$(ls /sys/class/infiniband/ | grep mlx5 | head -1) + + if [ -n "${SINGLE_IB_DEVICE:-}" ]; then + MLX5_DEVICE="$SINGLE_IB_DEVICE" + echo "INFO: SINGLE-DEVICE MODE: Using filtered InfiniBand device: $MLX5_DEVICE" + else + MLX5_DEVICE=$(ls /sys/class/infiniband/ | grep mlx5 | head -1) + echo "INFO: SINGLE-DEVICE MODE: Using first available mlx5 device: $MLX5_DEVICE" + fi if [ -z "$MLX5_DEVICE" ]; then echo "ERROR: DEVICE ANALYSIS: Failed to detect mlx5 device despite count showing 1" exit 1 fi - + echo "SUCCESS: SINGLE-DEVICE MODE: Selected device '$MLX5_DEVICE' (only available device)" - + elif [ "$MLX5_DEVICE_COUNT" -gt 1 ]; then - echo "INFO: MULTI-DEVICE MODE: Found $MLX5_DEVICE_COUNT active mlx5 devices - using slot-based mapping" - echo "INFO: MULTI-DEVICE MODE: Slot-based mapping required for precise device selection" - - if [ -z "$SLOT_NUMBER" ]; then - echo "ERROR: MULTI-DEVICE MODE: Multiple devices found but no slot number specified in PXE mapping" - echo "ERROR: MULTI-DEVICE MODE: PXE mapping contains: '$IB_NIC_NAME'" - echo "ERROR: MULTI-DEVICE MODE: Expected format: 'InfiniBand.PCIe.Slot.X-Y' where X is the slot number" - echo "ERROR: MULTI-DEVICE MODE: Please update PXE mapping file with correct slot numbers" - echo "ERROR: MULTI-DEVICE MODE: Available mlx5 devices with their PCI slots:" + echo "INFO: MULTI-DEVICE MODE: Found $MLX5_DEVICE_COUNT active mlx5 devices" + echo "INFO: MULTI-DEVICE MODE: Checking all devices for port $PORT_NUMBER with GUID validation" + + # Array to store devices that have the specified port with valid GUID + MATCHING_DEVICES=() + + # Use filtered device list if available, otherwise check all devices + search_devices=() + if [ -n "${IB_DEVICES[*]:-}" ]; then + for device in "${IB_DEVICES[@]}"; do + search_devices+=("/sys/class/infiniband/$device") + done + else for mlx_device in /sys/class/infiniband/mlx5_*; do - [ -e "$mlx_device" ] || continue - device_name=$(basename "$mlx_device") - pci_address=$(basename "$(readlink -f "/sys/class/infiniband/$device_name/device" 2>/dev/null)") - if [ -n "$pci_address" ]; then - pci_slot=$(echo "$pci_address" | cut -d: -f2 | sed 's/^0*//') - echo " - $device_name: PCI $pci_address (slot $pci_slot)" - else - echo " - $device_name: PCI information not available" - fi + [ -e "$mlx_device" ] && search_devices+=("$mlx_device") done - exit 1 fi - - echo "INFO: MULTI-DEVICE MODE: Looking for device matching slot '$SLOT_NUMBER'" - MLX5_DEVICE=$(find_device_by_slot "$SLOT_NUMBER") - - if [ -z "$MLX5_DEVICE" ]; then - echo "ERROR: MULTI-DEVICE MODE: Found $MLX5_DEVICE_COUNT active mlx5 devices but none match slot '$SLOT_NUMBER'" - echo "ERROR: MULTI-DEVICE MODE: Slot '$SLOT_NUMBER' from PXE mapping doesn't match any hardware PCI slot" - echo "ERROR: MULTI-DEVICE MODE: Available mlx5 devices with their PCI slots:" - for mlx_device in /sys/class/infiniband/mlx5_*; do + + for mlx_device in "${search_devices[@]}"; do + [ -e "$mlx_device" ] || continue + device_name=$(basename "$mlx_device") + + # Check if port exists on this device + PORT_PATH="/sys/class/infiniband/${device_name}/ports/${PORT_NUMBER}" + if [ ! -d "$PORT_PATH" ]; then + echo "DEBUG: Device $device_name - Port $PORT_NUMBER does not exist" + continue + fi + + # Check if GUID exists for this port + GUID_PATH="${PORT_PATH}/gids/0" + if [ ! -f "$GUID_PATH" ]; then + echo "DEBUG: Device $device_name - Port $PORT_NUMBER exists but GUID not found" + continue + fi + + # Device has both port and GUID + MATCHING_DEVICES+=("$device_name") + echo "DEBUG: Device $device_name - Port $PORT_NUMBER with GUID found" + done + + # Analyze matching results + MATCHING_COUNT=0 + for device in "${MATCHING_DEVICES[@]}"; do + MATCHING_COUNT=$((MATCHING_COUNT + 1)) + done + + if [ "$MATCHING_COUNT" -eq 0 ]; then + echo "ERROR: MULTI-DEVICE MODE: Port $PORT_NUMBER not found on any device (or no GUID available)" + echo "ERROR: MULTI-DEVICE MODE: Available devices and their ports:" + for mlx_device in "${search_devices[@]}"; do [ -e "$mlx_device" ] || continue device_name=$(basename "$mlx_device") - pci_address=$(basename "$(readlink -f "/sys/class/infiniband/$device_name/device" 2>/dev/null)") - if [ -n "$pci_address" ]; then - pci_slot=$(echo "$pci_address" | cut -d: -f2 | sed 's/^0*//') - echo " - $device_name: PCI $pci_address (slot $pci_slot)" + echo " - $device_name:" + if [ -d "/sys/class/infiniband/${device_name}/ports" ]; then + ls /sys/class/infiniband/${device_name}/ports/ 2>/dev/null | sed 's/^/ Port: /' else - echo " - $device_name: PCI information not available" + echo " No ports directory found" fi done - echo "ERROR: MULTI-DEVICE MODE: Please update PXE mapping file with correct PCI slot numbers" - echo "ERROR: MULTI-DEVICE MODE: Use format: 'InfiniBand.PCIe.Slot.-'" + exit 1 + elif [ "$MATCHING_COUNT" -gt 1 ]; then + echo "ERROR: MULTI-DEVICE MODE: Port $PORT_NUMBER found on multiple devices" + echo "ERROR: MULTI-DEVICE MODE: Matching devices: ${MATCHING_DEVICES[*]}" + echo "ERROR: MULTI-DEVICE MODE: Cannot determine which device to use" + echo "ERROR: MULTI-DEVICE MODE: Please update PXE mapping to specify device uniquely" exit 1 fi - - echo "SUCCESS: MULTI-DEVICE MODE: Slot '$SLOT_NUMBER' matches device '$MLX5_DEVICE'" - echo "SUCCESS: MULTI-DEVICE MODE: Slot-based device selection completed successfully" + + # Use the single matching device + MLX5_DEVICE="${MATCHING_DEVICES[0]}" + echo "SUCCESS: MULTI-DEVICE MODE: Selected device '$MLX5_DEVICE' (only device with port $PORT_NUMBER and valid GUID)" fi echo "INFO: FINAL DEVICE SELECTION: Using mlx5 device '$MLX5_DEVICE'" @@ -284,11 +327,11 @@ done for iface in $(ip link show | grep -E "^[0-9]+: ib" | awk -F: '{print $2}'); do echo "DEBUG: Checking interface $iface for GUID match" - + # Get the full address from the interface and extract the last 8 octets full_addr=$(ip link show "$iface" | grep "link/infiniband" | sed 's/.*link\/infiniband //' | sed 's/ brd.*//') echo "DEBUG: Interface $iface full address: $full_addr" - + # Extract the last 8 octets (fields 13-20) and format with colons for comparison iface_octets=$(echo "$full_addr" | cut -d: -f13-20 | python3 -c " import sys @@ -298,7 +341,7 @@ if len(parts) >= 8: print(formatted) ") echo "DEBUG: Interface $iface octets: $iface_octets (target: $GUID_OCTETS)" - + if [ "$iface_octets" = "$GUID_OCTETS" ]; then echo "SUCCESS: GUID MATCH FOUND! Interface $iface matches hardware GUID" IB_INTERFACE="$iface" @@ -331,33 +374,33 @@ echo "SUCCESS: INTERFACE SELECTION: Found IB interface $IB_INTERFACE matching ha if command -v nmcli >/dev/null 2>&1; then echo "INFO: IP CONFIGURATION: Using NetworkManager to configure IB interface" echo "DEBUG: IP CONFIGURATION: Target IP $IB_IP/$NETMASK_BITS on interface $IB_INTERFACE" - + echo "DEBUG: IP CONFIGURATION: Removing existing NetworkManager connection for $IB_INTERFACE" nmcli con delete "$IB_INTERFACE" &>/dev/null || true - + echo "DEBUG: IP CONFIGURATION: Creating new NetworkManager connection for $IB_INTERFACE" nmcli con add type infiniband ifname "$IB_INTERFACE" con-name "$IB_INTERFACE" - + echo "DEBUG: IP CONFIGURATION: Setting IP address $IB_IP/$NETMASK_BITS on $IB_INTERFACE" nmcli con modify "$IB_INTERFACE" ipv4.method manual ipv4.addresses "$IB_IP/$NETMASK_BITS" - + echo "DEBUG: IP CONFIGURATION: Bringing up NetworkManager connection for $IB_INTERFACE" nmcli con up "$IB_INTERFACE" - + echo "SUCCESS: IP CONFIGURATION: NetworkManager successfully configured $IB_INTERFACE with IP $IB_IP/$NETMASK_BITS" else echo "INFO: IP CONFIGURATION: Using iproute2 to configure IB interface (NetworkManager not available)" echo "DEBUG: IP CONFIGURATION: Target IP $IB_IP/$NETMASK_BITS on interface $IB_INTERFACE" - + echo "DEBUG: IP CONFIGURATION: Flushing existing IP addresses from $IB_INTERFACE" ip addr flush dev "$IB_INTERFACE" - + echo "DEBUG: IP CONFIGURATION: Adding IP address $IB_IP/$NETMASK_BITS to $IB_INTERFACE" ip addr add "$IB_IP/$NETMASK_BITS" dev "$IB_INTERFACE" - + echo "DEBUG: IP CONFIGURATION: Bringing up interface $IB_INTERFACE" ip link set "$IB_INTERFACE" up - + echo "SUCCESS: IP CONFIGURATION: iproute2 successfully configured $IB_INTERFACE with IP $IB_IP/$NETMASK_BITS" fi @@ -366,13 +409,13 @@ echo "SUCCESS: FINAL IP ASSIGNMENT: Successfully assigned $IB_IP/$NETMASK_BITS t # Configure DNS for InfiniBand network if [ -n "$IB_IP" ]; then echo "INFO: DNS CONFIGURATION: Configuring DNS for InfiniBand interface" - + # Add VAST DNS servers (completely safe - handles empty arrays) {% for dns_server in hostvars['localhost']['ib_network_dns'] %} echo "DEBUG: DNS CONFIGURATION: Adding DNS server {{ dns_server }}" echo "nameserver {{ dns_server }}" >> /etc/resolv.conf {% endfor %} - + echo "SUCCESS: DNS CONFIGURATION: DNS configuration completed for IB network" else echo "INFO: DNS CONFIGURATION: No DNS configuration needed (IB IP is empty)" @@ -381,5 +424,4 @@ fi echo "=== IB NETWORK CONFIGURATION COMPLETED SUCCESSFULLY ===" echo "SUMMARY: IB interface $IB_INTERFACE configured with IP $IB_IP/$NETMASK_BITS" echo "SUMMARY: Device used: $MLX5_DEVICE, Port: $PORT_NUMBER" -echo "SUMMARY: Configuration method: $([ "$MLX5_DEVICE_COUNT" -eq 1 ] && echo "Single-device mode (no slot mapping needed)" || echo "Multi-device mode (slot-based mapping)")" - +echo "SUMMARY: Configuration method: $([ "$MLX5_DEVICE_COUNT" -eq 1 ] && echo "Single-device mode (no slot mapping needed)" || echo "Multi-device mode (port-based mapping)")" diff --git a/provision/roles/configure_ochami/templates/hpc_tools/install_dcgm.sh.j2 b/provision/roles/configure_ochami/templates/hpc_tools/install_dcgm.sh.j2 index 158e089805..a1e768d9bf 100644 --- a/provision/roles/configure_ochami/templates/hpc_tools/install_dcgm.sh.j2 +++ b/provision/roles/configure_ochami/templates/hpc_tools/install_dcgm.sh.j2 @@ -31,18 +31,12 @@ echo "=====================================================" # Detect CUDA major version for DCGM package selection echo "[INFO] Detecting CUDA version for DCGM package compatibility..." # Try to get CUDA version from nvidia-smi -CUDA_VERSION=$(nvidia-smi | grep "CUDA Version" | awk '{print $9}' | cut -d'.' -f1) +CUDA_VERSION=$(nvidia-smi | sed -nE 's/.*CUDA( UMD)? Version: *([0-9]+).*/\2/p') -# Fallback: Try to get CUDA version from nvcc if available if [ -z "$CUDA_VERSION" ]; then - if command -v nvcc &>/dev/null; then - CUDA_VERSION=$(nvcc --version | grep "release" | awk '{print $5}' | cut -d',' -f1 | cut -d'.' -f1) - echo "[INFO] CUDA version detected from nvcc: $CUDA_VERSION" - else - echo "[ERROR] Could not detect CUDA version from nvidia-smi or nvcc." - echo "[ERROR] CUDA toolkit is required for DCGM package version detection. Skipping DCGM setup." + echo "[ERROR] Could not detect CUDA version from nvidia-smi" + echo "[ERROR] CUDA driver is required for DCGM package version detection. Skipping DCGM setup." exit 1 - fi else echo "[INFO] CUDA major version detected from nvidia-smi: $CUDA_VERSION" fi diff --git a/provision/roles/configure_ochami/templates/hpc_tools/setup_doca_mpi_env.sh.j2 b/provision/roles/configure_ochami/templates/hpc_tools/setup_doca_mpi_env.sh.j2 new file mode 100644 index 0000000000..41462e866e --- /dev/null +++ b/provision/roles/configure_ochami/templates/hpc_tools/setup_doca_mpi_env.sh.j2 @@ -0,0 +1,60 @@ +#!/bin/bash +LOGFILE="/var/log/setup_doca_mpi_env.log" +exec > >(tee -a "$LOGFILE") 2>&1 + +echo "===== Setting up DOCA MPI Environment =====" +echo "Timestamp: $(date '+%Y-%m-%d %H:%M:%S')" + +# DOCA MPI installation path +DOCA_MPI_PATH="/usr/mpi/gcc/openmpi-4.1.9a1" +PROFILE_DIR="/etc/profile.d" + +# Check if DOCA MPI is installed +if [ ! -d "$DOCA_MPI_PATH" ]; then + echo "[ERROR] DOCA MPI not found at $DOCA_MPI_PATH" + echo "[INFO] DOCA MPI installation may have failed" + exit 1 +fi + +echo "[INFO] DOCA MPI found at $DOCA_MPI_PATH" + +# Create DOCA MPI environment profile +cat > "$PROFILE_DIR/doca_mpi.sh" <<'ENVEOF' +#!/bin/bash +# DOCA MPI and UCX Environment Setup +# Automatically configured for DOCA OpenMPI 4.1.9a1 + +# DOCA OpenMPI environment +export PATH=/usr/mpi/gcc/openmpi-4.1.9a1/bin:$PATH +export LD_LIBRARY_PATH=/usr/mpi/gcc/openmpi-4.1.9a1/lib64:$LD_LIBRARY_PATH +export MANPATH=/usr/mpi/gcc/openmpi-4.1.9a1/share/man:$MANPATH +export MPI_ROOT=/usr/mpi/gcc/openmpi-4.1.9a1 + +# DOCA UCX environment (included with DOCA-OFED) +export UCX_HOME=/usr/mpi/gcc/openmpi-4.1.9a1 +export UCX_LIB_DIR=/usr/mpi/gcc/openmpi-4.1.9a1/lib64 +ENVEOF + +chmod 644 "$PROFILE_DIR/doca_mpi.sh" +echo "[SUCCESS] DOCA MPI environment configured in $PROFILE_DIR/doca_mpi.sh" + +# Source the environment immediately for current session +source "$PROFILE_DIR/doca_mpi.sh" + +# Verify installation +if command -v mpirun &> /dev/null; then + MPI_VERSION=$(mpirun --version | head -1) + echo "[SUCCESS] DOCA MPI environment verified: $MPI_VERSION" +else + echo "[ERROR] mpirun not found after environment setup" + exit 1 +fi + +if command -v mpicc &> /dev/null; then + echo "[SUCCESS] mpicc compiler available" +else + echo "[WARN] mpicc compiler not found" +fi + +echo "[INFO] DOCA MPI environment setup completed successfully" +echo "===== DOCA MPI Environment Setup Complete =====" diff --git a/provision/roles/mount_config/tasks/process_single_powervault.yml b/provision/roles/mount_config/tasks/process_single_powervault.yml index 9d83e1b5b7..e611696156 100644 --- a/provision/roles/mount_config/tasks/process_single_powervault.yml +++ b/provision/roles/mount_config/tasks/process_single_powervault.yml @@ -30,7 +30,7 @@ cloud_init_groups_dict: >- {{ cloud_init_groups_dict | combine({ item: (cloud_init_groups_dict[item] | default({}) | combine({ - 'powervault_scripts': (cloud_init_groups_dict[item].powervault_scripts | default([])) + [{ + 'powervault_scripts': (cloud_init_groups_dict[item].powervault_scripts | default([], true)) + [{ 'name': pv_item.name, 'content': pv_rendered_script }] diff --git a/provision/roles/provision_validations/tasks/validate_telemetry_config.yml b/provision/roles/provision_validations/tasks/validate_telemetry_config.yml index 9deada8961..a8e7a4d09d 100644 --- a/provision/roles/provision_validations/tasks/validate_telemetry_config.yml +++ b/provision/roles/provision_validations/tasks/validate_telemetry_config.yml @@ -28,7 +28,7 @@ - name: Get k8s cluster details ansible.builtin.set_fact: service_cluster_info: >- - {{ vars[k8s_cluster_name] + {{ lookup('vars', k8s_cluster_name) | selectattr('deployment', 'equalto', true) | list | first }} diff --git a/provision/roles/slurm_config/tasks/build_slurm_conf.yml b/provision/roles/slurm_config/tasks/build_slurm_conf.yml index d930f64418..beeb14f4c8 100644 --- a/provision/roles/slurm_config/tasks/build_slurm_conf.yml +++ b/provision/roles/slurm_config/tasks/build_slurm_conf.yml @@ -17,7 +17,7 @@ apply_config: "{{ apply_config | default({}) | combine({'slurm': (apply_config['slurm'] | combine({'NodeName': (apply_config['slurm'].NodeName | default([])) + (node_params | default([]))}))}) }}" - when: node_params is defined and node_params + when: node_params is defined and (node_params | length > 0) no_log: "{{ _no_log }}" - name: Append login nodes to NodeName list @@ -26,7 +26,7 @@ | combine({'slurm': (apply_config['slurm'] | combine({'NodeName': (apply_config['slurm'].NodeName | default([])) + [{'NodeName': item}]}))}) }}" loop: "{{ login_list }}" - when: login_list is defined and login_list + when: login_list is defined and (login_list | length > 0) no_log: "{{ _no_log }}" - name: Append compiler login nodes to NodeName list @@ -35,7 +35,7 @@ | combine({'slurm': (apply_config['slurm'] | combine({'NodeName': (apply_config['slurm'].NodeName | default([])) + [{'NodeName': item}]}))}) }}" loop: "{{ compiler_login_list }}" - when: compiler_login_list is defined and compiler_login_list + when: compiler_login_list is defined and (compiler_login_list | length > 0) no_log: "{{ _no_log }}" - name: Append Partition @@ -43,11 +43,11 @@ apply_config: "{{ apply_config | default({}) | combine({'slurm': (apply_config['slurm'] | combine({'PartitionName': (apply_config['slurm'].PartitionName | default([])) + [partition_params]}))}) }}" - when: node_params is defined and node_params + when: node_params is defined and (node_params | length > 0) no_log: "{{ _no_log }}" - name: Add dbd parameters to slurm conf ansible.builtin.set_fact: apply_config: "{{ apply_config | default({}) | combine({'slurm': (apply_config['slurm'] | combine(dbd_slurm_conf))}) }}" - when: dbd_list is defined and dbd_list + when: dbd_list is defined and (dbd_list | length > 0) no_log: "{{ _no_log }}" diff --git a/provision/roles/slurm_config/tasks/check_ctld_running.yml b/provision/roles/slurm_config/tasks/check_ctld_running.yml index a8bacada0f..a6380573ad 100644 --- a/provision/roles/slurm_config/tasks/check_ctld_running.yml +++ b/provision/roles/slurm_config/tasks/check_ctld_running.yml @@ -81,7 +81,7 @@ register: scontrol_reconfig delegate_to: "{{ ctld }}" when: - - ctld_state[ctld] is true + - ctld_state[ctld] | bool - name: Undrain if any nodes are drain ansible.builtin.command: @@ -94,7 +94,7 @@ register: scontrol_node_resume delegate_to: "{{ ctld }}" when: - - ctld_state[ctld] is true + - ctld_state[ctld] | bool rescue: - name: Fail if slurmctld is not running on any host diff --git a/provision/roles/slurm_config/tasks/confs.yml b/provision/roles/slurm_config/tasks/confs.yml index 2378682b7d..7b188c3fe3 100644 --- a/provision/roles/slurm_config/tasks/confs.yml +++ b/provision/roles/slurm_config/tasks/confs.yml @@ -148,13 +148,13 @@ apply_config: "{{ apply_config | default({}) | combine({'slurmdbd': (apply_config['slurmdbd'] | combine({'DbdHost': ctld_list[0], 'StorageHost': ctld_list[0]}))}) }}" - when: ctld_list + when: ctld_list | length > 0 no_log: "{{ _no_log }}" - name: Check .conf files existence ansible.builtin.stat: path: "{{ slurm_config_path }}/{{ item.0 }}/etc/slurm/{{ item.1 }}.conf" - when: ctld_list + when: ctld_list | length > 0 loop: "{{ ctld_list | product(conf_files | default([])) }}" register: ctld_conf_files @@ -169,7 +169,7 @@ no_log: "{{ _no_log }}" when: - configs_input is defined - - configs_input + - configs_input | length > 0 - item.value is string - item.key in conf_files @@ -189,7 +189,7 @@ no_log: "{{ _no_log }}" when: - configs_input is defined - - configs_input + - configs_input | length > 0 - item.value is mapping - name: Create lists for conf_merge @@ -367,7 +367,7 @@ register: ctld_conf_files no_log: "{{ _no_log }}" when: - - item.ini_lines + - item.ini_lines | length > 0 - name: Add extra confs which are not handled ansible.builtin.include_tasks: handle_extra_confs.yml @@ -384,7 +384,7 @@ - name: Check if cluster running ansible.builtin.include_tasks: check_ctld_running.yml when: - - ctld_list + - ctld_list | length > 0 - ctld_conf_files is changed loop: "{{ ctld_list }}" loop_control: diff --git a/provision/roles/slurm_config/tasks/create_slurm_dir.yml b/provision/roles/slurm_config/tasks/create_slurm_dir.yml index 7ae0ae88af..0864bd2b6a 100644 --- a/provision/roles/slurm_config/tasks/create_slurm_dir.yml +++ b/provision/roles/slurm_config/tasks/create_slurm_dir.yml @@ -85,11 +85,11 @@ ansible.builtin.file: path: "{{ slurm_config_path }}/{{ slurm_item }}" state: absent - loop: "{{ (ctld_list | default([]) - + cmpt_list | default([]) - + login_list | default([]) - + compiler_login_list | default([]) - + dbd_list | default([]) + loop: "{{ ((ctld_list | default([])) + + (cmpt_list | default([])) + + (login_list | default([])) + + (compiler_login_list | default([])) + + (dbd_list | default([])) + ['munge.key']) | flatten }}" loop_control: loop_var: slurm_item @@ -180,7 +180,7 @@ owner: "{{ root_user }}" group: "{{ root_group }}" mode: "{{ conf_file_mode }}" - when: ctld_list + when: ctld_list | length > 0 loop: "{{ ctld_list }}" - name: Generate slurmd opts for Configless @@ -194,7 +194,7 @@ owner: "{{ root_user }}" group: "{{ root_group }}" mode: "{{ common_mode }}" - when: cmpt_list + when: cmpt_list | length > 0 loop: "{{ cmpt_list | product(['logout_user.sh']) }}" - name: Get the slurm NFS path diff --git a/provision/roles/slurm_config/tasks/main.yml b/provision/roles/slurm_config/tasks/main.yml index f300c5da5d..f3398cbfea 100644 --- a/provision/roles/slurm_config/tasks/main.yml +++ b/provision/roles/slurm_config/tasks/main.yml @@ -32,9 +32,15 @@ ansible.builtin.include_tasks: read_slurm_hostnames.yml when: slurm_support +- name: Backup slurm conf if upgrade + ansible.builtin.include_tasks: upgrade_conf_db_backup.yml + when: + - slurm_support + - (hostvars['localhost']['upgrade_mode'] | default(false) | bool) + # This does not consider hierarchy of slurm nodes - name: Entering the slurm configuration only if slurm in nodes.yaml ansible.builtin.include_tasks: create_slurm_dir.yml when: - slurm_support - - ctld_list or (cmpt_list or login_list or compiler_login_list) + - (ctld_list | length > 0) or (cmpt_list | length > 0) or (login_list | length > 0) or (compiler_login_list | length > 0) diff --git a/provision/roles/slurm_config/tasks/upgrade_conf_db_backup.yml b/provision/roles/slurm_config/tasks/upgrade_conf_db_backup.yml new file mode 100644 index 0000000000..be9de46bac --- /dev/null +++ b/provision/roles/slurm_config/tasks/upgrade_conf_db_backup.yml @@ -0,0 +1,78 @@ +# Copyright 2026 Dell Inc. or its subsidiaries. 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: Read upgrade_manifest + ansible.builtin.include_vars: + file: "/opt/omnia/.data/upgrade_manifest.yml" + name: upgrade_manifest + register: upgrade_manifest_result + ignore_errors: true + +- name: Fail if upgrade_manifest is not found + ansible.builtin.fail: + msg: "Slurm backup: Reading of upgrade_manifest.yml failed: {{ upgrade_manifest_result.msg }}" + when: upgrade_manifest_result is not defined or upgrade_manifest_result is failed + +- name: Include variable file omnia_config.yml + ansible.builtin.include_vars: + file: "{{ input_project_dir }}/omnia_config.yml" + name: upgrade_omnia_config + +- name: Include storage vars + ansible.builtin.include_vars: + file: "{{ input_project_dir }}/storage_config.yml" + name: upgrade_storage_config + +- name: Set nfs storage name + ansible.builtin.set_fact: + up_nfs_storage_name: "{{ upgrade_omnia_config.slurm_cluster[0].nfs_storage_name }}" + +- name: Read the slurm mount point + ansible.builtin.set_fact: + up_slurm_nfs_mounted_path: "{{ (upgrade_storage_config.mounts | selectattr('name', 'equalto', up_nfs_storage_name) | first).mount_point }}" + +- name: Set path for slurm backup + ansible.builtin.set_fact: + up_slurm_backup_path: "{{ up_slurm_nfs_mounted_path }}/slurm_backups/preupgrade_{{ upgrade_manifest.source_version }}_backup" + +- name: Create backup directory structure + ansible.builtin.file: + path: "{{ up_slurm_backup_path }}/{{ item }}" + state: directory + owner: root + group: root + mode: '0755' + loop: + - "etc/slurm" + - "var/lib/mysql/slurm_acct_db" + +- name: Backup slurm etc/slurm and var/lib/mysql/slurm_acct_db directories + ansible.builtin.copy: + src: "{{ up_slurm_nfs_mounted_path }}/slurm/{{ ctld_list[0] }}/{{ item }}/" + dest: "{{ up_slurm_backup_path }}/{{ item }}/" + remote_src: true + mode: preserve + register: conf_backup_result + loop: + - "etc/slurm" + - "var/lib/mysql/slurm_acct_db" + ignore_errors: true + +- name: Backup completed for slurm + ansible.builtin.pause: + seconds: 2 + prompt: | + Slurm confs and db backup completed before upgrade of slurm. + Backup location: {{ up_slurm_backup_path }} + when: conf_backup_result is success diff --git a/provision/roles/telemetry/files/nersc-ldms-aggr/make_host_map.dell.py b/provision/roles/telemetry/files/nersc-ldms-aggr/make_host_map.dell.py index 4fadf264c4..c3f1151846 100644 --- a/provision/roles/telemetry/files/nersc-ldms-aggr/make_host_map.dell.py +++ b/provision/roles/telemetry/files/nersc-ldms-aggr/make_host_map.dell.py @@ -23,7 +23,7 @@ def load_config(config_path): """Load the json config file given a file path.""" if not os.path.exists(config_path): return {} - with open(config_path, 'r') as f: + with open(config_path, 'r', encoding='utf-8') as f: return json.load(f) diff --git a/provision/roles/telemetry/files/nersc-ldms-aggr/mkmanifest.py b/provision/roles/telemetry/files/nersc-ldms-aggr/mkmanifest.py index 91f842f5ce..febf274d73 100644 --- a/provision/roles/telemetry/files/nersc-ldms-aggr/mkmanifest.py +++ b/provision/roles/telemetry/files/nersc-ldms-aggr/mkmanifest.py @@ -63,7 +63,7 @@ def load_yaml_file(path, required=True): else: logging.warning(f"Optional YAML file missing: {path}") return None - with open(path, 'r') as fh: + with open(path, 'r', encoding='utf-8') as fh: return yaml.safe_load(fh) def load_json_file(path, required=True): @@ -75,7 +75,7 @@ def load_json_file(path, required=True): else: logging.warning(f"Optional JSON file missing: {path}") return None - with open(path, 'r') as fh: + with open(path, 'r', encoding='utf-8') as fh: return json.load(fh) def harvest_cluster_info(cluster_file): @@ -303,7 +303,7 @@ def update_manifest(manifest, aggs, store_stateful_replicas, replicas_exporter, def write_yaml_file(path, data, description=None): """Write YAML data to file.""" try: - with open(path, 'w') as fh: + with open(path, 'w', encoding='utf-8') as fh: yaml.dump(data, fh, indent=2) if description: logging.info(f"Wrote {description} to {path}") diff --git a/provision/roles/telemetry/templates/telemetry/idrac_telemetry/idrac_telemetry_statefulset.yaml.j2 b/provision/roles/telemetry/templates/telemetry/idrac_telemetry/idrac_telemetry_statefulset.yaml.j2 index b0c3dd8b3c..7d56e91d56 100644 --- a/provision/roles/telemetry/templates/telemetry/idrac_telemetry/idrac_telemetry_statefulset.yaml.j2 +++ b/provision/roles/telemetry/templates/telemetry/idrac_telemetry/idrac_telemetry_statefulset.yaml.j2 @@ -72,7 +72,7 @@ spec: - ip: "127.0.0.1" hostnames: - "mysqldb" - terminationGracePeriodSeconds: 10 + terminationGracePeriodSeconds: 120 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready diff --git a/provision/roles/telemetry/vars/main.yml b/provision/roles/telemetry/vars/main.yml index 6c8653f998..55f0ac6534 100644 --- a/provision/roles/telemetry/vars/main.yml +++ b/provision/roles/telemetry/vars/main.yml @@ -667,7 +667,7 @@ vector: # Dynamic pattern based on ome_identifier from telemetry_config.yml # Example: if ome_identifier="ome", pattern="^ome\\..*$" (matches ome.inventory, ome.health, etc.) # Example: if ome_identifier="OME-637-2-100.100.5.8", pattern matches OME-637-2-100.100.5.8.* topics - kafka_topics_pattern: "^{{ telemetry_bridges.vector_ome.ome_identifier | default('ome') | regex_escape }}\\..*$" + kafka_topics_pattern: "^{{ telemetry_config.telemetry_bridges.vector_ome.ome_identifier | default('ome') | regex_escape }}\\..*$" consumer_group: "vector-ome-group" kafka_user: "vector-ome-user" # Dedicated KafkaUser for OME health_port: 8688 diff --git a/rollback/ansible.cfg b/rollback/ansible.cfg index 1e6688a5cf..c7116f280a 100644 --- a/rollback/ansible.cfg +++ b/rollback/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 roles_path = roles:../upgrade/roles:../utils/roles library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/rollback/playbooks/rollback_slurm.yml b/rollback/playbooks/rollback_slurm.yml index 47dd616671..c25e43383c 100644 --- a/rollback/playbooks/rollback_slurm.yml +++ b/rollback/playbooks/rollback_slurm.yml @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. --- + +# ============================================================================ +# Play 1: Pre-flight — manifest gating, BuildStream terminal gate +# ============================================================================ - name: Rollback Slurm feature updates hosts: localhost connection: local @@ -36,72 +40,95 @@ - name: Read rollback_manifest.yml ansible.builtin.include_vars: file: "{{ rollback_manifest_path }}" - name: rollback_manifest + name: manifest - - name: Skip if slurm already rolled back - ansible.builtin.meta: end_play - when: - - rollback_manifest.component_status[component_name] | default('pending') == 'completed' + - name: Read software_config.json + ansible.builtin.include_vars: + file: "{{ manifest.backup_dir }}/input/project_default/software_config.json" + name: software_config - - name: "Mark as skipped — BuildStream terminal gate active (C-24)" - ansible.builtin.copy: - content: >- - {{ rollback_manifest | combine({ - 'component_status': rollback_manifest.component_status | combine({ - component_name: 'skipped' - }) - }) | to_nice_yaml }} - dest: "{{ rollback_manifest_path }}" - mode: '0644' - when: - - hostvars['localhost']['build_stream_terminal'] | default(false) | bool + - name: Determine slurm_skip status + ansible.builtin.set_fact: + slurm_skip: >- + {{ + (manifest.component_status[component_name] | default('pending') == 'completed') + or (software_config.softwares | selectattr('name', 'equalto', 'slurm_custom') | list | length == 0) + }} - - name: "Skip — BuildStream terminal gate active (C-24)" - ansible.builtin.meta: end_play + - name: "Handle BuildStream terminal gate (C-24)" when: - hostvars['localhost']['build_stream_terminal'] | default(false) | bool + - manifest.component_status.build_stream | default('pending') == 'completed' + block: + - name: "Mark as skipped — BuildStream terminal gate active" + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + component_name: 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ rollback_manifest_path }}" + mode: '0644' + when: not slurm_skip + + - name: "Set slurm_skip — BuildStream terminal gate active" + ansible.builtin.set_fact: + slurm_skip: true - - name: Set slurm rollback status to in-progress - ansible.builtin.copy: - content: >- - {{ rollback_manifest | combine({ - 'component_status': rollback_manifest.component_status | combine({ - component_name: 'in-progress' - }) - }) | to_nice_yaml }} - dest: "{{ rollback_manifest_path }}" - mode: '0644' + - name: "Skip — BuildStream terminal gate active" + ansible.builtin.meta: end_play - - name: "Display rollback status in-progress — {{ component_name }}" - ansible.builtin.debug: - msg: "[ROLLBACK] Component '{{ component_name }}' — status changed to: in-progress" + - name: Block when slurm is already completed + when: not slurm_skip + block: + - name: Set slurm rollback status to in-progress + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + component_name: 'in-progress' + }) + }) | to_nice_yaml }} + dest: "{{ rollback_manifest_path }}" + mode: '0644' + + - name: "Display rollback status in-progress — {{ component_name }}" + ansible.builtin.debug: + msg: "[ROLLBACK] Component '{{ component_name }}' — status changed to: in-progress" - - name: Check for existing reboot state file - ansible.builtin.stat: - path: /opt/omnia/.data/slurm_rollback_reboot_state.yml - register: _reboot_state_stat + - name: Check for existing reboot state file + ansible.builtin.stat: + path: /opt/omnia/.data/slurm_rollback_reboot_state.yml + register: _reboot_state_stat - - name: Load reboot state from previous run - ansible.builtin.include_vars: - file: /opt/omnia/.data/slurm_rollback_reboot_state.yml - name: _reboot_state - when: _reboot_state_stat.stat.exists | default(false) + - name: Load reboot state from previous run + ansible.builtin.include_vars: + file: /opt/omnia/.data/slurm_rollback_reboot_state.yml + name: _reboot_state + when: _reboot_state_stat.stat.exists | default(false) - - name: Set previously successful reboot list - ansible.builtin.set_fact: - slurm_previously_rebooted: "{{ _reboot_state.successfully_rebooted | default([]) }}" - when: _reboot_state_stat.stat.exists | default(false) + - name: Set previously successful reboot list + ansible.builtin.set_fact: + slurm_previously_rebooted: "{{ _reboot_state.successfully_rebooted | default([], true) }}" + when: _reboot_state_stat.stat.exists | default(false) - - name: Initialize previously rebooted list (no prior state) - ansible.builtin.set_fact: - slurm_previously_rebooted: [] - when: not (_reboot_state_stat.stat.exists | default(false)) + - name: Initialize previously rebooted list (no prior state) + ansible.builtin.set_fact: + slurm_previously_rebooted: [] + when: not (_reboot_state_stat.stat.exists | default(false)) +# ============================================================================ +# Create OIM host group (needed for cloud-init/BSS update on OIM) +# ============================================================================ - name: Create OIM host group for cloud-init/BSS update ansible.builtin.import_playbook: ../../utils/create_container_group.yml vars: oim_group: true +# ============================================================================ +# Play 2: Update cloud-init and BSS from backup openchami_data +# ============================================================================ - name: Rollback cloud-init and BSS for slurm functional groups hosts: oim connection: ssh @@ -111,8 +138,7 @@ tasks: - name: Skip if slurm upgrade not needed ansible.builtin.meta: end_play - when: - - hostvars['localhost']['slurm_skip'] | default(false) | bool + when: hostvars['localhost']['slurm_skip'] | default(false) | bool - name: Read rollback_manifest.yml ansible.builtin.include_vars: @@ -132,6 +158,18 @@ ansible.builtin.debug: msg: "Slurm is not configured in software_config.json. Skipping Slurm rollback." + - name: Add skipped to rollback_manifest + ansible.builtin.copy: + content: >- + {{ rollback_manifest | combine({ + 'component_status': rollback_manifest.component_status | combine({ + 'slurm': 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ rollback_manifest_path }}" + mode: '0644' + delegate_to: localhost + - name: End play ansible.builtin.meta: end_play @@ -163,7 +201,7 @@ - name: End play if not slurm nodes in pxe_mapping ansible.builtin.meta: end_play - when: slurm_host_group_map | default({}) | length == 0 + when: slurm_host_group_map | default({}, true) | length == 0 - name: Get the backup directory ansible.builtin.set_fact: @@ -173,21 +211,17 @@ | replace('/opt', hostvars['localhost']['oim_shared_path']) }}/openchami/openchami_data/workdir - - name: SLURM ROLLBACK WARNING - ansible.builtin.debug: - msg: "{{ slurm_rollback_banner }}" - vars: - slurm_rollback_banner: - - "[ROLLBACK] SLURM CLUSTER — PRE-ROLLBACK NOTICE" - - "" - - "1. NODE REBOOT — All Slurm/login nodes will reboot." - - "2. NFS MOUNTS — Omnia 2.1 mount points are preserved. Do not modify during rollback." - - "3. ROLLBACK SCOPE — New NFS mounts(Ex: VAST) added during upgrade will NOT be retained on rollback." - - name: Pause to display warning ansible.builtin.pause: seconds: 10 - prompt: "SLURM ROLLBACK - Proceeding in 10 seconds..." + prompt: "{{ slurm_rollback_banner }}" + vars: + slurm_rollback_banner: | + [ROLLBACK] SLURM CLUSTER — PRE-ROLLBACK NOTICE + ============================================== + 1. NODE REBOOT — All Slurm/login nodes will reboot. + 2. NFS MOUNTS — Omnia 2.1 mount points are preserved. Do not modify during rollback. + 3. ROLLBACK SCOPE — New NFS mounts(Ex: VAST) added during upgrade will NOT be retained on rollback. - name: Read oim_metadata for oim_node_name (standalone fallback) ansible.builtin.include_vars: @@ -224,7 +258,7 @@ update_ci_defaults: true update_ci_common: true update_hostname: true - loop: "{{ slurm_host_group_map.values() | list }}" + loop: "{{ slurm_host_group_map.values() | list | unique }}" - name: Include slurm rollback role ansible.builtin.include_role: @@ -237,18 +271,18 @@ serial: 100% strategy: host_pinned vars: - reboot_timeout: 600 + reboot_timeout: 1200 ssh_timeout: 60 tasks: - name: Skip if slurm upgrade not needed ansible.builtin.meta: end_play - when: slurm_skip | default(false) | bool + when: hostvars['localhost']['slurm_skip'] | default(false) | bool - name: Initialize state ansible.builtin.set_fact: node_status: hostname: "{{ inventory_hostname }}" - reboot: false # TODO: rename as reboot_failed + reboot: false ssh: false sinfo: false unreachable: false @@ -272,7 +306,7 @@ when: ssh_check is failed - name: Skip reboot — node successfully rebooted in previous run - when: inventory_hostname in (hostvars['localhost']['slurm_previously_rebooted'] | default([])) + when: inventory_hostname in (hostvars['localhost']['slurm_previously_rebooted'] | default([], true)) block: - name: Mark node as previously completed ansible.builtin.set_fact: @@ -294,7 +328,7 @@ - name: Reboot node ansible.builtin.reboot: reboot_timeout: "{{ reboot_timeout }}" - test_command: "sinfo" + # test_command: "sinfo" register: reboot_result ignore_errors: true ignore_unreachable: true @@ -321,7 +355,21 @@ ansible.builtin.set_fact: node_status: "{{ node_status | combine({'ssh': (ssh_result is succeeded)}) }}" - # TODO: check if cloud-init status ?? + # ---- WAIT FOR CLOUD-INIT ---- + - name: Wait for cloud-init + ansible.builtin.command: + cmd: cloud-init status --wait + register: ci_wait + failed_when: false + changed_when: ci_wait.rc in [0, 2] + timeout: "{{ reboot_timeout }}" + ignore_errors: true + when: node_status.ssh + + - name: Print cloud-init status + ansible.builtin.debug: + var: ci_wait + when: node_status.ssh and ci_wait is defined # ---- CHECK SLURM ---- - name: Check slurm services @@ -349,7 +397,7 @@ tasks: - name: Skip if slurm rollback not needed ansible.builtin.meta: end_play - when: slurm_skip | default(false) | bool + when: hostvars['localhost']['slurm_skip'] | default(false) | bool - name: Set slurm nodes from inventory ansible.builtin.set_fact: @@ -365,9 +413,27 @@ ansible.builtin.debug: var: slurm_nodes - - name: End play if no slurm nodes found in inventory - ansible.builtin.meta: end_play + - name: Read rollback_manifest.yml + ansible.builtin.include_vars: + file: "{{ rollback_manifest_path }}" + name: rollback_manifest + + - name: Handle skipped case when: slurm_nodes | length == 0 + block: + - name: Add skipped to rollback_manifest + ansible.builtin.copy: + content: >- + {{ rollback_manifest | combine({ + 'component_status': rollback_manifest.component_status | combine({ + 'slurm': 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ rollback_manifest_path }}" + mode: '0644' + + - name: End play if no slurm nodes found in inventory + ansible.builtin.meta: end_play - name: Set filtered nodes ansible.builtin.set_fact: @@ -488,14 +554,17 @@ msg: "[ROLLBACK] Slurm rollback failed. Review the report above and re-run after remediation." - name: Generate and display success report - ansible.builtin.debug: - msg: | + ansible.builtin.pause: + seconds: 1 + prompt: | ============================================================ [ROLLBACK] SLURM ROLLBACK — ALL NODES VERIFIED SUCCESSFULLY ============================================================ + Verified: {{ success_nodes | length }} / {{ slurm_nodes | length }} nodes - Reboot complete | SSH active | Slurm (sinfo) responding on all nodes. - Cluster is ready for workload submission. + ✓ Reboot complete | SSH active | Slurm (sinfo) responding on all nodes + + Cluster is ready for workload submission! ============================================================ when: not slurm_rollback_failed @@ -505,11 +574,6 @@ state: absent when: not slurm_rollback_failed - - name: Read rollback_manifest.yml - ansible.builtin.include_vars: - file: "{{ rollback_manifest_path }}" - name: rollback_manifest - - name: Mark slurm rollback as completed ansible.builtin.copy: content: >- diff --git a/rollback/roles/rollback_buildstream/tasks/gitlab.yml b/rollback/roles/rollback_buildstream/tasks/gitlab.yml index 50af909a29..27a5b45337 100644 --- a/rollback/roles/rollback_buildstream/tasks/gitlab.yml +++ b/rollback/roles/rollback_buildstream/tasks/gitlab.yml @@ -146,7 +146,7 @@ | first).id | string }} when: - _action == 'revert_commits' - - _gl_project_search.json | default([]) | length > 0 + - _gl_project_search.json | default([], true) | length > 0 - name: "GitLab | Restore — Read upgrade commit SHA from metadata" ansible.builtin.set_fact: @@ -180,7 +180,7 @@ - _gl_upgrade_commit_sha | default('') == '' - _gl_latest_commits is defined - _gl_latest_commits.status | default(0) == 200 - - _gl_latest_commits.json | default([]) | selectattr('message', 'search', '\\[omnia-upgrade-2.1-to-2.2\\]') | list | length > 0 + - _gl_latest_commits.json | default([], true) | selectattr('message', 'search', '\\[omnia-upgrade-2.1-to-2.2\\]') | list | length > 0 - name: "GitLab | Restore — Skip if no upgrade commit SHA found" ansible.builtin.debug: @@ -207,7 +207,7 @@ - name: "GitLab | Restore — Analyze if already reverted" ansible.builtin.set_fact: _gl_already_reverted: >- - {{ _gl_revert_search.json | default([]) + {{ _gl_revert_search.json | default([], true) | rejectattr('id', 'equalto', _gl_upgrade_commit_sha) | selectattr('message', 'search', _gl_upgrade_commit_sha) | list | length > 0 }} diff --git a/rollback/roles/rollback_k8s/tasks/load_rollback_status.yml b/rollback/roles/rollback_k8s/tasks/load_rollback_status.yml index cbe19fb7b5..d0291d0102 100644 --- a/rollback/roles/rollback_k8s/tasks/load_rollback_status.yml +++ b/rollback/roles/rollback_k8s/tasks/load_rollback_status.yml @@ -133,7 +133,7 @@ | combine({ 'steps': ( rollback_status.nodes[item].steps - | default({}) + | default({}, true) | combine({ 'crio_restart': ( rollback_status.nodes[item].steps.crio_restart diff --git a/rollback/roles/rollback_openchami/tasks/restore_quadlets_and_configs.yml b/rollback/roles/rollback_openchami/tasks/restore_quadlets_and_configs.yml index 5259a56546..092c7b576e 100644 --- a/rollback/roles/rollback_openchami/tasks/restore_quadlets_and_configs.yml +++ b/rollback/roles/rollback_openchami/tasks/restore_quadlets_and_configs.yml @@ -54,7 +54,7 @@ rollback_oim_host_quadlets: >- {{ rollback_oim_host_backup_dir }}/{{ backup_quadlets_subpath }} - - name: List backed-up quadlet files + - name: List backed-up quadlet container files ansible.builtin.find: paths: "{{ rollback_oim_host_quadlets }}" patterns: "*.container" @@ -63,14 +63,43 @@ delegate_facts: true connection: ssh + - name: List backed-up quadlet network files + ansible.builtin.find: + paths: "{{ rollback_oim_host_quadlets }}" + patterns: "*.network" + register: rollback_network_files + delegate_to: oim + delegate_facts: true + connection: ssh + failed_when: false + - name: Display backed-up quadlet files found ansible.builtin.debug: verbosity: 1 msg: >- - Found {{ rollback_quadlet_files.files | length }} quadlet files in backup: - {{ rollback_quadlet_files.files | map(attribute='path') | map('basename') | list }} + Found {{ rollback_quadlet_files.files | length }} container files and + {{ rollback_network_files.files | default([]) | length }} network files in backup: + Containers: {{ rollback_quadlet_files.files | map(attribute='path') | map('basename') | list }} + Networks: {{ rollback_network_files.files | default([]) | map(attribute='path') | map('basename') | list }} + + # Restore network files FIRST - these must exist before containers can use them + - name: Restore each v2.1 network quadlet file to systemd quadlet directory + ansible.builtin.copy: + src: "{{ item.path }}" + dest: "{{ systemd_quadlet_dir }}/{{ item.path | basename }}" + remote_src: true + owner: root + group: root + mode: "{{ file_permissions_644 }}" + loop: "{{ rollback_network_files.files | default([]) }}" + loop_control: + label: "{{ item.path | basename }}" + delegate_to: oim + delegate_facts: true + connection: ssh + when: rollback_network_files.files | default([]) | length > 0 - - name: Restore each v2.1 quadlet file to systemd quadlet directory + - name: Restore each v2.1 container quadlet file to systemd quadlet directory ansible.builtin.copy: src: "{{ item.path }}" dest: "{{ systemd_quadlet_dir }}/{{ item.path | basename }}" @@ -216,7 +245,8 @@ ansible.builtin.debug: msg: - "{{ rollback_messages.restore.quadlets_success }}" - - "Quadlet files restored: {{ rollback_quadlet_files.files | length }}" + - "Container quadlet files restored: {{ rollback_quadlet_files.files | length }}" + - "Network quadlet files restored: {{ rollback_network_files.files | default([]) | length }}" - "v2.2-only quadlets removed: {{ rollback_v22_only_quadlets | join(', ') }}" - "openchami.target: restored from backup (references coresmd.service)" - "/etc/openchami: {{ 'restored from backup' if rollback_etc_openchami_backup_stat.stat.exists | default(false) else 'backup NOT found' }}" diff --git a/rollback/roles/rollback_openchami/tasks/rollback_status.yml b/rollback/roles/rollback_openchami/tasks/rollback_status.yml index 4ad672dc35..81e93963e2 100644 --- a/rollback/roles/rollback_openchami/tasks/rollback_status.yml +++ b/rollback/roles/rollback_openchami/tasks/rollback_status.yml @@ -14,10 +14,10 @@ --- # ============================================================================ -# rollback_status.yml — Report Rollback Result and Update Version Metadata +# rollback_status.yml — Report Rollback Result # ============================================================================ # Runs in the 'always' block of main.yml — executes regardless of success -# or failure. Updates version.yml to reflect v2.1 state on success. +# or failure. # ============================================================================ - name: Report rollback result @@ -27,21 +27,6 @@ msg: "{{ rollback_messages.status.failure }}" when: openchami_rollback_failed | default(false) | bool - # ── Update version.yml to reflect v2.1 state on success ───────────── - - name: Update version.yml with v2.1 metadata after successful rollback - ansible.builtin.copy: - content: | - # OpenCHAMI version metadata — updated by rollback_openchami role - openchami_version: "2.1.0.0" - omnia_version: "2.1.0.0" - rollback_timestamp: "{{ ansible_date_time.iso8601 }}" - rolled_back_from: "2.2.0.0" - rollback_backup_dir: "{{ rollback_backup_dir | default(rollback_backup_dir_default) }}" - dest: "/opt/omnia/.data/version.yml" - mode: "{{ file_permissions_644 }}" - when: - - not (openchami_rollback_failed | default(false) | bool) - - name: Report rollback success ansible.builtin.debug: msg: "{{ rollback_messages.status.success }}" diff --git a/rollback/roles/rollback_slurm/tasks/check_slurm_cluster.yml b/rollback/roles/rollback_slurm/tasks/check_slurm_cluster.yml index fa4277f87c..1003099f4f 100644 --- a/rollback/roles/rollback_slurm/tasks/check_slurm_cluster.yml +++ b/rollback/roles/rollback_slurm/tasks/check_slurm_cluster.yml @@ -17,10 +17,18 @@ slurm_ctld_host: >- {{ slurm_host_group_map | dict2items - | selectattr('value', 'equalto', 'slurm_control_node_x86_64') + | selectattr('value', 'match', '^slurm_control_node_') | map(attribute='key') | first }} +- name: Remove ctld tracking file + ansible.builtin.file: + path: "{{ slurm_nfs_mounted_path }}/ctld_track" + state: absent + when: + - slurm_ctld_host is defined + - slurm_ctld_host not in (hostvars['localhost']['slurm_previously_rebooted'] | default([], true)) + - name: Check for running jobs on slurm cluster ansible.builtin.shell: cmd: | @@ -39,18 +47,21 @@ when: running_jobs.unreachable | default(false) block: - name: Notify that OpenCHAMI changes are already applied - ansible.builtin.debug: - msg: "{{ ctld_unreachable_msg }}" - vars: - ctld_unreachable_msg: - - "ERROR: Slurm control node '{{ slurm_ctld_host }}' is unreachable." - - "" - - "NOTE: OpenCHAMI cloud-init and BSS changes have already been applied." - - " The cluster nodes are ready to be rebooted into the rollback image." - - "" - - "ACTION REQUIRED: Reboot the nodes using the iDRAC PXE boot playbook:" - - " ansible-playbook utils/set_pxe_boot.yml" - - "" + ansible.builtin.pause: + seconds: 1 + prompt: | + ================================================================ + ERROR: Slurm control node '{{ slurm_ctld_host }}' is unreachable. + ================================================================ + + NOTE: OpenCHAMI cloud-init and BSS changes have already been applied. + The cluster nodes are ready to be rebooted into the rollback image. + + ACTION REQUIRED: Reboot the nodes using the iDRAC PXE boot playbook: + ansible-playbook utils/set_pxe_boot.yml + + After nodes reboot, re-run the rollback playbook. + ================================================================ - name: Abort — control node unreachable, manual PXE reboot required ansible.builtin.fail: @@ -63,14 +74,15 @@ when: running_jobs.stdout | trim | int > 0 block: - name: Show rollback completion message - ansible.builtin.debug: - msg: "{{ slurm_rollback_message }}" - vars: - slurm_rollback_message: - - "Slurm rollback will be halted. as there are active jobs running." - - "Note: {{ running_jobs.stdout | trim }} running job(s) detected." - - "Please drain and stop jobs before proceeding with node reboot." - - "Then, rerun the rollback playbook to complete the process." + ansible.builtin.pause: + seconds: 1 + prompt: | + ================================================================ + Slurm rollback will be halted. as there are active jobs running. + Note: {{ running_jobs.stdout | trim }} running job(s) detected. + Please drain and stop jobs before proceeding with node reboot. + Then, rerun the rollback playbook to complete the process. + ================================================================ - name: Abort rollback if jobs are running ansible.builtin.fail: @@ -80,17 +92,14 @@ when: running_jobs.rc != 0 block: - name: Warn that slurmctld is not responding - ansible.builtin.debug: - msg: "{{ ctld_warn_msg }}" - vars: - ctld_warn_msg: - - "WARNING: Slurm controller '{{ slurm_ctld_host }}' is not responding to squeue." - - "Error: {{ running_jobs.stderr | default('(no error output)') }}" - - "Proceeding with rollback may be unsafe if the cluster is in an unknown state." - - - name: Ask user whether to proceed despite unresponsive controller ansible.builtin.pause: - prompt: > + prompt: | + ================================================================ + WARNING: Slurm controller '{{ slurm_ctld_host }}' is not responding to squeue. + Error: {{ running_jobs.stderr | default('(no error output)') }} + Proceeding with rollback may be unsafe if the cluster is in an unknown state. + ================================================================ + slurmctld on '{{ slurm_ctld_host }}' is not responding. Type 'yes/y' to proceed with rollback anyway, or press Enter to abort register: ctld_proceed_choice diff --git a/rollback/roles/rollback_slurm/tasks/slurm_backup.yml b/rollback/roles/rollback_slurm/tasks/slurm_backup.yml index a03897af6b..76dd522833 100644 --- a/rollback/roles/rollback_slurm/tasks/slurm_backup.yml +++ b/rollback/roles/rollback_slurm/tasks/slurm_backup.yml @@ -43,7 +43,7 @@ - name: Include oim_metadata.yml ansible.builtin.include_vars: - file: "{{ oim_metadata }}" + file: "{{ oim_metadata_path }}" name: oim_metadata - name: Set oim_shared_path fact @@ -51,11 +51,6 @@ oim_shared_path: "{{ oim_metadata.oim_shared_path | trim }}" slurm_nfs_mounted_path: "{{ slurm_nfs[0].client_share_path }}/slurm" -- name: Remove ctld tracking file - ansible.builtin.file: - path: "{{ slurm_nfs_mounted_path }}/ctld_track" - state: absent - - name: Read pxe_mapping_file from backup directory # TODO: pxe_mapping_file is an absolute path but assuming it's in project_default community.general.read_csv: diff --git a/rollback/roles/rollback_slurm/vars/main.yml b/rollback/roles/rollback_slurm/vars/main.yml index dc2e85ef49..9a5e1d78be 100644 --- a/rollback/roles/rollback_slurm/vars/main.yml +++ b/rollback/roles/rollback_slurm/vars/main.yml @@ -16,7 +16,7 @@ mounted_dir_perm: "0755" default_client_mount_options: "nosuid,rw,sync,hard,intr" slurm_nfs_fail_msg: "Failed to mount NFS share. Please check if the NFS server is reachable or NFS is configured properly." -oim_metadata: "/opt/omnia/.data/oim_metadata.yml" +oim_metadata_path: "/opt/omnia/.data/oim_metadata.yml" backup_slurm_nfs_contents: false # To create a copy of all slurm contents on the nfs share slurm_2_1_backup_dir_effective: "{{ slurm_2_1_backup_dir | default('/opt/omnia/backups/upgrade/version_2.1.0.0') }}" slurm_2_1_backup_subdir: "slurm_21_nfs_backups" diff --git a/rollback/rollback.yml b/rollback/rollback.yml index e0bde802a3..ef7da98d57 100644 --- a/rollback/rollback.yml +++ b/rollback/rollback.yml @@ -181,8 +181,8 @@ ansible.builtin.set_fact: requested_tags: >- {{ all_rollback_components - if (ansible_run_tags is not defined or 'all' in ansible_run_tags) - else ansible_run_tags }} + if (ansible_run_tags is not defined or 'all' in (ansible_run_tags | list)) + else ansible_run_tags | list }} # ─── Initialize rollback_manifest.yml using oim_metadata as source-of-truth ─── - name: Initialize rollback_manifest.yml (first invocation) @@ -333,24 +333,34 @@ ansible.builtin.set_fact: rollback_manifest: "{{ raw_rollback_manifest.content | b64decode | from_yaml }}" - # Build cleaned component_status: preserve 'skipped' for BuildStream-gated - # components; mark everything else as 'completed'. - - name: Build cleaned component_status (preserve failed; mark pending as completed) + # ── Identify tags skipped by BuildStream terminal gate ── + - name: Identify BuildStream-skipped components (rollback) + ansible.builtin.set_fact: + bs_skipped_tags: "{{ bs_rollback_skipped | default([], true) }}" + + - name: Resolve requested tags for finalize + ansible.builtin.set_fact: + finalize_requested_tags: >- + {{ all_rollback_components + if (ansible_run_tags is not defined or 'all' in ansible_run_tags) + else ansible_run_tags | intersect(all_rollback_components) }} + + # Build cleaned component_status: only update components that were + # actually requested via --tags; leave unrequested components as-is. + - name: Build cleaned component_status (only update requested tags) ansible.builtin.set_fact: cleaned_component_status: >- {%- set result = {} -%} {%- for key, val in rollback_manifest.component_status.items() -%} - {%- if val in ['completed', 'skipped', 'failed'] -%} - {%- set _ = result.update({key: val}) -%} + {%- if key in bs_skipped_tags and val == 'pending' -%} + {%- set _ = result.update({key: 'skipped'}) -%} + {%- elif key in finalize_requested_tags -%} + {%- set _ = result.update({key: val if val in ['completed', 'skipped'] else 'completed'}) -%} {%- else -%} - {%- set _ = result.update({key: 'completed'}) -%} + {%- set _ = result.update({key: val}) -%} {%- endif -%} {%- endfor -%} - {{ result | to_json }} - - - name: Coerce cleaned_component_status to a real dict - ansible.builtin.set_fact: - cleaned_component_status: "{{ cleaned_component_status | from_json }}" + {{ result }} - name: Determine rollback_status (failed if any failed, partial if pending, else completed) ansible.builtin.set_fact: diff --git a/telemetry/ansible.cfg b/telemetry/ansible.cfg index ef1156baf9..4b6f270146 100644 --- a/telemetry/ansible.cfg +++ b/telemetry/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/telemetry/roles/telemetry_disable/tasks/main.yml b/telemetry/roles/telemetry_disable/tasks/main.yml index ef0122c36f..79bbc62bb4 100644 --- a/telemetry/roles/telemetry_disable/tasks/main.yml +++ b/telemetry/roles/telemetry_disable/tasks/main.yml @@ -19,7 +19,7 @@ - name: Fail if no tags provided ansible.builtin.fail: msg: "{{ tags_required_msg }}" - when: ansible_run_tags | default(['all']) | length == 1 and 'all' in ansible_run_tags | default(['all']) + when: ansible_run_tags | default(['all']) | list | length == 1 and 'all' in (ansible_run_tags | default(['all']) | list) - name: Load telemetry configuration ansible.builtin.include_vars: diff --git a/telemetry/roles/telemetry_enable/tasks/main.yml b/telemetry/roles/telemetry_enable/tasks/main.yml index 2897085dee..0914a08bc2 100644 --- a/telemetry/roles/telemetry_enable/tasks/main.yml +++ b/telemetry/roles/telemetry_enable/tasks/main.yml @@ -19,7 +19,7 @@ - name: Fail if no tags provided ansible.builtin.fail: msg: "{{ tags_required_msg }}" - when: ansible_run_tags | default(['all']) | length == 1 and 'all' in ansible_run_tags | default(['all']) + when: ansible_run_tags | default(['all']) | list | length == 1 and 'all' in (ansible_run_tags | default(['all']) | list) - name: Load telemetry configuration ansible.builtin.include_vars: diff --git a/telemetry/telemetry.yml b/telemetry/telemetry.yml index d535c475ce..1aeb03a2fe 100644 --- a/telemetry/telemetry.yml +++ b/telemetry/telemetry.yml @@ -19,7 +19,7 @@ tasks: - name: Set dynamic run tags including 'telemetry' ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['telemetry']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['telemetry']) | unique }}" cacheable: true - name: Invoke validate_config.yml to perform L1 and L2 validations diff --git a/upgrade/ansible.cfg b/upgrade/ansible.cfg index 5a6d4bcf28..ff4775869e 100644 --- a/upgrade/ansible.cfg +++ b/upgrade/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 roles_path = roles:../utils/roles:../prepare_oim/roles library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/upgrade/playbooks/upgrade_k8s.yml b/upgrade/playbooks/upgrade_k8s.yml index 7aa8a962ad..d5cb163dda 100644 --- a/upgrade/playbooks/upgrade_k8s.yml +++ b/upgrade/playbooks/upgrade_k8s.yml @@ -1421,7 +1421,7 @@ multi_hop: current_hop: "{{ upgrade_status.multi_hop.current_hop | default(0) }}" hops: >- - {{ (upgrade_status.multi_hop.hops | default([])) + {{ (upgrade_status.multi_hop.hops | default([], true)) | map('combine', {'status': 'completed', 'completed_at': now(utc=true).strftime('%Y-%m-%dT%H:%M:%SZ')}) | list }} diff --git a/upgrade/playbooks/upgrade_oim.yml b/upgrade/playbooks/upgrade_oim.yml index a9006ccba1..9d23f656a3 100644 --- a/upgrade/playbooks/upgrade_oim.yml +++ b/upgrade/playbooks/upgrade_oim.yml @@ -86,40 +86,6 @@ upgrade_needed={{ upgrade_needed | default(true) }}, failed={{ openchami_upgrade_failed | default(false) }} - # Only update version tracking when an upgrade actually took place. - # Skipped when OpenCHAMI was not deployed or was already at target. - - name: Read current version.yml (if exists) - ansible.builtin.slurp: - src: "/opt/omnia/.data/version.yml" - register: raw_version_yml - failed_when: false - when: - - openchami_deployed | default(false) | bool - - upgrade_needed | default(true) | bool - - - name: Parse current version.yml - ansible.builtin.set_fact: - current_version_data: "{{ raw_version_yml.content | b64decode | from_yaml }}" - when: - - openchami_deployed | default(false) | bool - - upgrade_needed | default(true) | bool - - raw_version_yml is defined - - raw_version_yml.content is defined - - - name: Update version.yml with OpenCHAMI target version - ansible.builtin.copy: - content: >- - {{ (current_version_data | default({})) | combine({ - 'openchami_version': manifest.target_version | default('2.2.0.0'), - 'openchami_previous_version': manifest.source_version | default('2.1.0.0'), - 'openchami_upgrade_timestamp': lookup('pipe', 'date -u +%Y-%m-%dT%H:%M:%SZ') - }) | to_nice_yaml }} - dest: "/opt/omnia/.data/version.yml" - mode: '0644' - when: - - openchami_deployed | default(false) | bool - - upgrade_needed | default(true) | bool - rescue: # Re-read the manifest file to capture any intermediate writes # (e.g., the in-progress status set earlier in this play). diff --git a/upgrade/playbooks/upgrade_provision.yml b/upgrade/playbooks/upgrade_provision.yml index 9358d2bf07..f55f377e34 100644 --- a/upgrade/playbooks/upgrade_provision.yml +++ b/upgrade/playbooks/upgrade_provision.yml @@ -118,7 +118,7 @@ msg: "[UPGRADE] Component '{{ component_name }}' — status changed to: in-progress" when: proceed_provision | bool -# ── Telemetry backups ── +# ── Telemetry backups (only when service_k8s is configured) ── - name: "Telemetry Backups" hosts: localhost connection: ssh @@ -126,15 +126,42 @@ vars: input_project_dir: "{{ input_project_dir | default('/opt/omnia/input/project_default') }}" tasks: + - name: "Skip telemetry backups — provision not proceeding" + ansible.builtin.meta: end_play + when: not (hostvars['localhost']['proceed_provision'] | default(false) | bool) + + - name: "Load software_config.json to check for service_k8s" + ansible.builtin.slurp: + path: "{{ input_project_dir }}/software_config.json" + register: _prov_sw_config_slurp + failed_when: false + + - name: "Parse software_config.json" + ansible.builtin.set_fact: + prov_software_config: "{{ _prov_sw_config_slurp.content | b64decode | from_json }}" + when: _prov_sw_config_slurp is not failed + + - name: "Check if service_k8s is configured" + ansible.builtin.set_fact: + k8s_configured: "{{ (prov_software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | list | length) > 0 }}" + when: prov_software_config is defined + + - name: "Skip telemetry backups — service_k8s not configured" + ansible.builtin.debug: + msg: "Skipping telemetry backups — service_k8s not present in software_config.json" + when: not (k8s_configured | default(false) | bool) + - name: Include required input to resolve kube_vip ansible.builtin.include_role: name: ../roles/upgrade_telemetry tasks_from: include_required_input.yml + when: k8s_configured | default(false) | bool - name: Backup telemetry scripts before provisioning target version ansible.builtin.include_role: name: ../roles/upgrade_telemetry tasks_from: backup_telemetry.yml + when: k8s_configured | default(false) | bool # ── Run provision playbook ── - name: Run provision (upgrade) diff --git a/upgrade/playbooks/upgrade_slurm.yml b/upgrade/playbooks/upgrade_slurm.yml index c1163e5bbd..05ab2b069a 100644 --- a/upgrade/playbooks/upgrade_slurm.yml +++ b/upgrade/playbooks/upgrade_slurm.yml @@ -42,86 +42,82 @@ file: "{{ manifest_path }}" name: manifest - - name: Initialize slurm_skip - ansible.builtin.set_fact: - slurm_skip: false - - - name: Set slurm_skip when already completed - ansible.builtin.set_fact: - slurm_skip: true - when: - - manifest.component_status[component_name] | default('pending') == 'completed' + - name: Read software_config.json + ansible.builtin.include_vars: + file: "{{ hostvars['localhost']['input_project_dir'] }}/software_config.json" + name: software_config - - name: Set slurm upgrade directory + - name: Determine slurm_skip status ansible.builtin.set_fact: - slurm_2_1_backup_dir: "{{ manifest.backup_dir }}" + slurm_skip: >- + {{ + (manifest.component_status[component_name] | default('pending') == 'completed') + or (software_config.softwares | selectattr('name', 'equalto', 'slurm_custom') | list | length == 0) + }} - - name: "Mark as skipped — BuildStream terminal gate active (C-24)" - ansible.builtin.copy: - content: >- - {{ manifest | combine({ - 'component_status': manifest.component_status | combine({ - component_name: 'skipped' - }) - }) | to_nice_yaml }} - dest: "{{ manifest_path }}" - mode: '0644' + - name: "Handle BuildStream terminal gate (C-24)" when: - - not slurm_skip - hostvars['localhost']['build_stream_terminal'] | default(false) | bool - manifest.component_status.build_stream | default('pending') == 'completed' + block: + - name: "Mark as skipped — BuildStream terminal gate active" + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + component_name: 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ manifest_path }}" + mode: '0644' + when: not slurm_skip + + - name: "Set slurm_skip — BuildStream terminal gate active" + ansible.builtin.set_fact: + slurm_skip: true - - name: "Set slurm_skip — BuildStream terminal gate active (C-24)" - ansible.builtin.set_fact: - slurm_skip: true - when: - - hostvars['localhost']['build_stream_terminal'] | default(false) | bool - - manifest.component_status.build_stream | default('pending') == 'completed' + - name: "Skip — BuildStream terminal gate active" + ansible.builtin.meta: end_play - - name: Set slurm upgrade status to in-progress - ansible.builtin.copy: - content: >- - {{ manifest | combine({ - 'component_status': manifest.component_status | combine({ - component_name: 'in-progress' - }) - }) | to_nice_yaml }} - dest: "{{ manifest_path }}" - mode: '0644' + - name: Block when slurm is already completed when: not slurm_skip + block: + - name: Set slurm upgrade status to in-progress + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + component_name: 'in-progress' + }) + }) | to_nice_yaml }} + dest: "{{ manifest_path }}" + mode: '0644' + + - name: "Display upgrade status in-progress — {{ component_name }}" + ansible.builtin.debug: + msg: "[UPGRADE] Component '{{ component_name }}' — status changed to: in-progress" - - name: "Display upgrade status in-progress — {{ component_name }}" - ansible.builtin.debug: - msg: "[UPGRADE] Component '{{ component_name }}' — status changed to: in-progress" - when: not slurm_skip + - name: Check for existing reboot state file + ansible.builtin.stat: + path: /opt/omnia/.data/slurm_upgrade_reboot_state.yml + register: _reboot_state_stat - - name: Check for existing reboot state file - ansible.builtin.stat: - path: /opt/omnia/.data/slurm_upgrade_reboot_state.yml - register: _reboot_state_stat - when: not slurm_skip + - name: Load reboot state from previous run + ansible.builtin.include_vars: + file: /opt/omnia/.data/slurm_upgrade_reboot_state.yml + name: _reboot_state + when: + - _reboot_state_stat.stat.exists | default(false) - - name: Load reboot state from previous run - ansible.builtin.include_vars: - file: /opt/omnia/.data/slurm_upgrade_reboot_state.yml - name: _reboot_state - when: - - not slurm_skip - - _reboot_state_stat.stat.exists | default(false) - - - name: Set previously successful reboot list - ansible.builtin.set_fact: - slurm_previously_rebooted: "{{ _reboot_state.successfully_rebooted | default([]) }}" - when: - - not slurm_skip - - _reboot_state_stat.stat.exists | default(false) + - name: Set previously successful reboot list + ansible.builtin.set_fact: + slurm_previously_rebooted: "{{ _reboot_state.successfully_rebooted | default([], true) }}" + when: _reboot_state_stat.stat.exists | default(false) - - name: Initialize previously rebooted list (no prior state) - ansible.builtin.set_fact: - slurm_previously_rebooted: [] - when: - - not slurm_skip - - not (_reboot_state_stat.stat.exists | default(false)) + - name: Initialize previously rebooted list (no prior state) + ansible.builtin.set_fact: + slurm_previously_rebooted: [] + when: not (_reboot_state_stat.stat.exists | default(false)) # ============================================================================ # Create OIM host group (needed for cloud-init/BSS update on OIM) @@ -132,12 +128,12 @@ oim_group: true # ============================================================================ -# Play 2: Update cloud-init and BSS for slurm_control_node_x86_64 on OIM +# Play 2: Update cloud-init and BSS for slurm on OIM # ============================================================================ # During upgrade_provision.yml, the provision flow runs with upgrade_mode=true. # Templates are re-rendered (BSS YAML, cloud-init group YAML) but ochami CLI # delete/set commands are skipped. This play applies those skipped operations -# for the slurm_control_node_x86_64 functional group using the +# for the slurm functional groups using the # update_cloud_init_bss utility role. # ============================================================================ - name: Update cloud-init and BSS for slurm functional groups @@ -145,6 +141,7 @@ connection: ssh gather_facts: false vars: + manifest_path: /opt/omnia/.data/upgrade_manifest.yml openchami_work_dir: "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/workdir" tasks: - name: Skip if slurm upgrade not needed @@ -165,6 +162,23 @@ ansible.builtin.debug: msg: "Slurm is not configured in software_config.json. Skipping Slurm upgrade." + - name: Read upgrade_manifest.yml + ansible.builtin.include_vars: + file: "{{ manifest_path }}" + name: manifest + + - name: Add skipped to upgrade_manifest + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + 'slurm': 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ manifest_path }}" + mode: '0644' + delegate_to: localhost + - name: End play ansible.builtin.meta: end_play @@ -196,26 +210,22 @@ - name: End play if not slurm nodes in pxe_mapping ansible.builtin.meta: end_play - when: slurm_host_group_map | default({}) | length == 0 + when: slurm_host_group_map | default({}, true) | length == 0 - name: SLURM UPGRADE WARNING - ansible.builtin.debug: - msg: "{{ slurm_upgrade_banner }}" - vars: - slurm_upgrade_banner: - - "[UPGRADE] SLURM CLUSTER — PRE-UPGRADE NOTICE" - - "" - - "1. NODE REBOOT — All Slurm/login nodes will reboot. Ensure no critical jobs are running." - - "2. PXE MAPPING — Do not modify Slurm node entries until upgrade completes." - - "3. NFS MOUNTS — Omnia 2.1 mount points are preserved. Do not modify during upgrade." - - "4. VAST STORAGE — Vast storage is not supported during upgrade. Please remove it from omnia_config.yml." - - "5. ROLLBACK SCOPE — New NFS mounts added during upgrade will NOT be retained on rollback." - - "6. POST-UPGRADE — Rollback is NOT recommended once all nodes boot with cloud-init complete." - - - name: Pause to display warning ansible.builtin.pause: seconds: 10 - prompt: "SLURM UPGRADE - Proceeding in 10 seconds..." + prompt: "{{ slurm_upgrade_banner }}" + vars: + slurm_upgrade_banner: | + [UPGRADE] SLURM CLUSTER — PRE-UPGRADE NOTICE + ============================================ + 1. NODE REBOOT — All Slurm/login nodes will reboot. Ensure no critical jobs are running. + 2. PXE MAPPING — Do not modify Slurm node entries until upgrade completes. + 3. NFS MOUNTS — Omnia 2.1 mount points are preserved. Do not modify during upgrade. + 4. VAST STORAGE — Vast storage is not supported during upgrade. Please remove it from omnia_config.yml. + 5. ROLLBACK SCOPE — New NFS mounts added during upgrade will NOT be retained on rollback. + 6. POST-UPGRADE — Rollback is NOT recommended once all nodes boot with cloud-init complete. - name: Read oim_metadata for oim_node_name (standalone fallback) ansible.builtin.include_vars: @@ -257,7 +267,7 @@ update_ci_defaults: true update_ci_common: true update_hostname: true - loop: "{{ slurm_host_group_map.values() | list }}" + loop: "{{ slurm_host_group_map.values() | list | unique }}" - name: Reboot Slurm nodes and validate services hosts: slurm_*, login_* @@ -265,18 +275,18 @@ serial: 100% strategy: host_pinned vars: - reboot_timeout: 600 + reboot_timeout: 1200 ssh_timeout: 60 tasks: - name: Skip if slurm upgrade not needed ansible.builtin.meta: end_play - when: slurm_skip | default(false) | bool + when: hostvars['localhost']['slurm_skip'] | default(false) | bool - name: Initialize state ansible.builtin.set_fact: node_status: hostname: "{{ inventory_hostname }}" - reboot: false # TODO: rename as reboot_failed + reboot: false ssh: false sinfo: false unreachable: false @@ -300,7 +310,7 @@ when: ssh_check is failed - name: Skip reboot — node successfully rebooted in previous run - when: inventory_hostname in (hostvars['localhost']['slurm_previously_rebooted'] | default([])) + when: inventory_hostname in (hostvars['localhost']['slurm_previously_rebooted'] | default([], true)) block: - name: Mark node as previously completed ansible.builtin.set_fact: @@ -322,7 +332,7 @@ - name: Reboot node ansible.builtin.reboot: reboot_timeout: "{{ reboot_timeout }}" - test_command: "sinfo" + # test_command: "sinfo" register: reboot_result ignore_errors: true ignore_unreachable: true @@ -349,9 +359,26 @@ ansible.builtin.set_fact: node_status: "{{ node_status | combine({'ssh': (ssh_result is succeeded)}) }}" + # ---- WAIT FOR CLOUD-INIT ---- + - name: Wait for cloud-init + ansible.builtin.command: + cmd: cloud-init status --wait + register: ci_wait + failed_when: false + changed_when: ci_wait.rc in [0, 2] + timeout: "{{ reboot_timeout }}" + ignore_errors: true + when: node_status.ssh + + - name: Print cloud-init status + ansible.builtin.debug: + var: ci_wait + when: node_status.ssh and ci_wait is defined + # ---- CHECK SLURM ---- - name: Check slurm services - ansible.builtin.command: sinfo + ansible.builtin.command: + cmd: sinfo register: svc changed_when: false failed_when: false @@ -416,7 +443,7 @@ tasks: - name: Skip if slurm upgrade not needed ansible.builtin.meta: end_play - when: slurm_skip | default(false) | bool + when: hostvars['localhost']['slurm_skip'] | default(false) | bool - name: Set slurm nodes from inventory ansible.builtin.set_fact: @@ -432,9 +459,27 @@ ansible.builtin.debug: var: slurm_nodes - - name: End play if no slurm nodes found in inventory - ansible.builtin.meta: end_play + - name: Include omnia_config + ansible.builtin.include_vars: + file: "{{ manifest_path }}" + name: manifest + + - name: Handle skipped case when: slurm_nodes | length == 0 + block: + - name: Add skipped to upgrade_manifest + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + 'slurm': 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ manifest_path }}" + mode: '0644' + + - name: End play if no slurm nodes found in inventory + ansible.builtin.meta: end_play - name: Set filtered nodes ansible.builtin.set_fact: @@ -602,29 +647,28 @@ msg: "[UPGRADE] Slurm upgrade failed. Review the report above and re-run after remediation." - name: Generate and display success report - ansible.builtin.debug: - msg: | + ansible.builtin.pause: + seconds: 1 + prompt: | ======================================================================= [UPGRADE] SLURM UPGRADE — ALL NODES VERIFIED SUCCESSFULLY ======================================================================= + Verified: {{ success_nodes | length }} / {{ slurm_nodes | length }} nodes - Reboot complete | SSH active | Slurm (sinfo) responding on all nodes. - Controller: slurmctld UP | sinfo OK - {{ ctld_results | default([]) | map(attribute='sinfo_node_count') | map('int') | sum }} node(s) visible from controller. - Cluster is ready for workload submission. + ✓ Reboot complete | SSH active | Slurm (sinfo) responding on all nodes + + Controller Status: + ✓ slurmctld UP | sinfo OK + ✓ {{ ctld_results | default([]) | map(attribute='sinfo_node_count') | map('int') | sum }} node(s) visible from controller + + Cluster is ready for workload submission! ======================================================================= - when: not slurm_upgrade_failed - name: Remove reboot flag after successful verification ansible.builtin.file: path: /opt/omnia/.data/slurm_upgrade_reboot_state.yml state: absent - - name: Include omnia_config - ansible.builtin.include_vars: - file: "{{ manifest_path }}" - name: manifest - - name: Mark slurm upgrade as completed ansible.builtin.copy: content: >- diff --git a/upgrade/playbooks/upgrade_telemetry.yml b/upgrade/playbooks/upgrade_telemetry.yml index 5fcb99f410..fd21e71f78 100644 --- a/upgrade/playbooks/upgrade_telemetry.yml +++ b/upgrade/playbooks/upgrade_telemetry.yml @@ -30,11 +30,12 @@ ansible.builtin.set_fact: manifest: "{{ raw_manifest.content | b64decode | from_yaml }}" - - name: Skip if telemetry already upgraded + - name: Skip if telemetry already upgraded or skipped ansible.builtin.meta: end_play when: - - manifest.component_status[component_name] | default('pending') == 'completed' + - manifest.component_status[component_name] | default('pending') in ['completed', 'skipped'] + # ── BuildStream terminal gate (C-24) ── - name: "Mark as skipped — BuildStream terminal gate active (C-24)" ansible.builtin.copy: content: >- @@ -55,6 +56,57 @@ - hostvars['localhost']['build_stream_terminal'] | default(false) | bool - manifest.component_status.build_stream | default('pending') == 'completed' + # ── Pre-check: Skip telemetry upgrade if service_k8s is not in software_config.json ── + - name: "Load software_config.json for service_k8s check" + ansible.builtin.slurp: + path: "{{ input_project_dir }}/software_config.json" + register: _sw_config_slurp + failed_when: false + + - name: "Parse software_config.json" + ansible.builtin.set_fact: + _software_config: "{{ _sw_config_slurp.content | b64decode | from_json }}" + when: _sw_config_slurp is not failed + + - name: "Check if service_k8s is configured in software_config.json" + ansible.builtin.set_fact: + telemetry_upgrade_enabled: "{{ _software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | list | length > 0 }}" + when: _software_config is defined + + - name: "Set telemetry_upgrade_enabled to false if software_config not loaded" + ansible.builtin.set_fact: + telemetry_upgrade_enabled: false + when: _software_config is not defined + + - name: "Mark as skipped — service_k8s not configured" + ansible.builtin.copy: + content: >- + {{ manifest | combine({ + 'component_status': manifest.component_status | combine({ + component_name: 'skipped' + }) + }) | to_nice_yaml }} + dest: "{{ manifest_path }}" + mode: '0644' + when: not (telemetry_upgrade_enabled | default(false) | bool) + + - name: "Display skip message — service_k8s not configured" + ansible.builtin.debug: + msg: "{{ banner_telemetry_not_configured }}" + vars: + banner_telemetry_not_configured: + - "========================================================================" + - "[UPGRADE] Component 'telemetry' — SKIPPED" + - "========================================================================" + - "Reason: service_k8s is not present in software_config.json softwares list." + - "K8s cluster was not provisioned, skipping telemetry upgrade." + - "========================================================================" + when: not (telemetry_upgrade_enabled | default(false) | bool) + + - name: "Skip — service_k8s not configured" + ansible.builtin.meta: end_play + when: not (telemetry_upgrade_enabled | default(false) | bool) + - name: Set telemetry upgrade status to in-progress ansible.builtin.copy: content: >- diff --git a/upgrade/roles/import_input_parameters/scripts/transform_software_config.py b/upgrade/roles/import_input_parameters/scripts/transform_software_config.py index 4073e89f3a..9a314e7614 100644 --- a/upgrade/roles/import_input_parameters/scripts/transform_software_config.py +++ b/upgrade/roles/import_input_parameters/scripts/transform_software_config.py @@ -26,7 +26,7 @@ "csi_driver_powerscale": "v2.16.0" } -with open(backup_file, 'r') as f: +with open(backup_file, 'r', encoding='utf-8') as f: backup = json.load(f) # Start with a copy of the backup (preserves user's configuration exactly) @@ -50,13 +50,16 @@ # If additional_packages exists as a TOP-LEVEL key in backup, append "os" if not present # This is the array like: "additional_packages": [{"name": "..."}, ...] if 'additional_packages' in result and isinstance(result['additional_packages'], list): - existing_names = {item.get('name') for item in result['additional_packages'] if isinstance(item, dict) and 'name' in item} + existing_names = { + item.get('name') for item in result['additional_packages'] + if isinstance(item, dict) and 'name' in item + } if 'os' not in existing_names: result['additional_packages'].append({"name": "os"}) print("Added {'name': 'os'} to additional_packages array", file=sys.stderr) # Write the result with compact formatting (no extra whitespace in arrays) -with open(target_file, 'w') as f: +with open(target_file, 'w', encoding='utf-8') as f: json.dump(result, f, indent=4, separators=(',', ': ')) f.write('\n') diff --git a/upgrade/roles/import_input_parameters/tasks/restore_input_files.yml b/upgrade/roles/import_input_parameters/tasks/restore_input_files.yml index 3dd6d45206..8ece1546e8 100644 --- a/upgrade/roles/import_input_parameters/tasks/restore_input_files.yml +++ b/upgrade/roles/import_input_parameters/tasks/restore_input_files.yml @@ -15,7 +15,7 @@ - name: Validate restore_input_files is defined ansible.builtin.set_fact: - restore_input_files_effective: "{{ restore_input_files | default([]) }}" + restore_input_files_effective: "{{ restore_input_files | default([], true) }}" - name: Restore input files from backup (overwrite target) ansible.builtin.include_tasks: restore_single_input_file.yml diff --git a/upgrade/roles/import_input_parameters/tasks/restore_omnia_config_credentials.yml b/upgrade/roles/import_input_parameters/tasks/restore_omnia_config_credentials.yml index a78f0de5d3..089011e96f 100644 --- a/upgrade/roles/import_input_parameters/tasks/restore_omnia_config_credentials.yml +++ b/upgrade/roles/import_input_parameters/tasks/restore_omnia_config_credentials.yml @@ -142,6 +142,10 @@ ome_password: "{{ credentials_dict.ome_password | default('') }}" ufm_username: "{{ credentials_dict.ufm_username | default('') }}" ufm_password: "{{ credentials_dict.ufm_password | default('') }}" + vast_username: "{{ credentials_dict.vast_username | default('') }}" + vast_password: "{{ credentials_dict.vast_password | default('') }}" + postgres_user: "{{ credentials_dict.postgres_user | default('') }}" + postgres_password: "{{ credentials_dict.postgres_password | default('') }}" no_log: true - name: Write updated content using template @@ -191,7 +195,7 @@ not backup_omnia_config_credentials_key_stat.stat.exists and (backup_omnia_config_credentials_content.stdout is not defined or '$ANSIBLE_VAULT;' not in backup_omnia_config_credentials_content.stdout) and - "'INFO: Both omnia_config_credentials.yml and .omnia_config_credentials_key' not in (upgrade_warnings | join(' '))" + 'INFO: Both omnia_config_credentials.yml and .omnia_config_credentials_key' not in (upgrade_warnings | join(' ')) ansible.builtin.set_fact: upgrade_warnings: > {{ upgrade_warnings + [msg_omnia_config_credentials_info_missing] }} diff --git a/upgrade/roles/import_input_parameters/tasks/restore_user_registry_credential.yml b/upgrade/roles/import_input_parameters/tasks/restore_user_registry_credential.yml index 16e31a4d63..e5d303a38b 100644 --- a/upgrade/roles/import_input_parameters/tasks/restore_user_registry_credential.yml +++ b/upgrade/roles/import_input_parameters/tasks/restore_user_registry_credential.yml @@ -84,7 +84,7 @@ not backup_local_repo_credentials_key_stat.stat.exists and (backup_user_registry_content.stdout is not defined or '$ANSIBLE_VAULT;' not in backup_user_registry_content.stdout) and - "'INFO: Both user_registry_credential.yml and .local_repo_credentials_key' not in (upgrade_warnings | join(' '))" + 'INFO: Both user_registry_credential.yml and .local_repo_credentials_key' not in (upgrade_warnings | join(' ')) ansible.builtin.set_fact: upgrade_warnings: >- {{ upgrade_warnings + [ diff --git a/upgrade/roles/import_input_parameters/tasks/transform_build_stream_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_build_stream_config.yml index 9eca462839..58fdcf1d5e 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_build_stream_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_build_stream_config.yml @@ -64,7 +64,7 @@ - name: Validate build_stream_host_ip format if provided ansible.builtin.assert: that: - - build_stream_host_ip == "" or build_stream_host_ip | ansible.utils.ipaddr + - build_stream_host_ip == "" or (build_stream_host_ip | ansible.utils.ipaddr | bool) fail_msg: "build_stream_host_ip '{{ build_stream_host_ip }}' is not a valid IP address" success_msg: "build_stream_host_ip is valid" when: build_stream_host_ip != "" @@ -72,7 +72,7 @@ - name: Validate build_stream_aarch64_ip format if provided ansible.builtin.assert: that: - - build_stream_aarch64_ip == "" or build_stream_aarch64_ip | ansible.utils.ipaddr + - build_stream_aarch64_ip == "" or (build_stream_aarch64_ip | ansible.utils.ipaddr | bool) fail_msg: "build_stream_aarch64_ip '{{ build_stream_aarch64_ip }}' is not a valid IP address" success_msg: "build_stream_aarch64_ip is valid" when: build_stream_aarch64_ip != "" diff --git a/upgrade/roles/import_input_parameters/tasks/transform_gitlab_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_gitlab_config.yml index 90a04368e1..609f3c0509 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_gitlab_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_gitlab_config.yml @@ -62,7 +62,7 @@ - name: Validate gitlab_host IP format if provided ansible.builtin.assert: that: - - gitlab_host == "" or gitlab_host | ansible.utils.ipaddr + - gitlab_host == "" or (gitlab_host | ansible.utils.ipaddr | bool) fail_msg: "gitlab_host '{{ gitlab_host }}' is not a valid IP address" success_msg: "gitlab_host is valid" when: gitlab_host != "" @@ -85,7 +85,7 @@ - name: Validate gitlab_default_branch format ansible.builtin.assert: that: - - gitlab_default_branch | regex_search('^[a-zA-Z0-9/_-]+$') + - gitlab_default_branch | regex_search('^[a-zA-Z0-9/_-]+$') is not none fail_msg: "gitlab_default_branch '{{ gitlab_default_branch }}' contains invalid characters" success_msg: "gitlab_default_branch is valid" diff --git a/upgrade/roles/import_input_parameters/tasks/transform_high_availability_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_high_availability_config.yml index 192dfef630..b9a276f5b4 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_high_availability_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_high_availability_config.yml @@ -49,7 +49,7 @@ ( [backup_ha_config.service_k8s_cluster_ha] if (backup_ha_config.service_k8s_cluster_ha is mapping) - else (backup_ha_config.service_k8s_cluster_ha | default([])) + else (backup_ha_config.service_k8s_cluster_ha | default([], true)) ) }} @@ -57,7 +57,7 @@ ansible.builtin.set_fact: ha_entries_missing_vip: >- {{ - (ha_service_k8s_cluster_ha | default([])) + (ha_service_k8s_cluster_ha | default([], true)) | select('mapping') | selectattr('virtual_ip_address', 'undefined') | map(attribute='cluster_name') @@ -68,7 +68,7 @@ ansible.builtin.set_fact: ha_entries_empty_vip: >- {{ - (ha_service_k8s_cluster_ha | default([])) + (ha_service_k8s_cluster_ha | default([], true)) | select('mapping') | selectattr('virtual_ip_address', 'defined') | selectattr('virtual_ip_address', 'match', '^\\s*$') @@ -80,9 +80,9 @@ ansible.builtin.fail: msg: "{{ msg_ha_virtual_ip_missing }}" when: - - (ha_service_k8s_cluster_ha | default([]) | length) == 0 - or ((ha_entries_missing_vip | default([]) | length) > 0) - or ((ha_entries_empty_vip | default([]) | length) > 0) + - (ha_service_k8s_cluster_ha | default([], true) | length) == 0 + or ((ha_entries_missing_vip | default([], true) | length) > 0) + or ((ha_entries_empty_vip | default([], true) | length) > 0) - name: Write high_availability_config.yml in Omnia 2.2 format ansible.builtin.template: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_local_repo_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_local_repo_config.yml index d220caf0ad..7abc073a01 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_local_repo_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_local_repo_config.yml @@ -52,7 +52,7 @@ else ( ( - (backup_local_repo_config.omnia_registry | default([])) + (backup_local_repo_config.omnia_registry | default([], true)) | select('string') | map('regex_replace', '^(.*)$', '{"host": "\\1", "cert_path": "", "key_path": ""}') | map('from_json') @@ -67,37 +67,37 @@ local_repo_user_repo_url_x86_64: "{{ backup_local_repo_config.user_repo_url_x86_64 | default(backup_local_repo_config.user_repo | - default([])) + default([], true), true) }}" - local_repo_user_repo_url_aarch64: "{{ backup_local_repo_config.user_repo_url_aarch64 | default([]) }}" + local_repo_user_repo_url_aarch64: "{{ backup_local_repo_config.user_repo_url_aarch64 | default([], true) }}" local_repo_rhel_os_url_x86_64: "{{ backup_local_repo_config.rhel_os_url_x86_64 | default(backup_local_repo_config.rhel_os_url | - default([])) + default([], true), true) }}" - local_repo_rhel_os_url_aarch64: "{{ backup_local_repo_config.rhel_os_url_aarch64 | default([]) }}" + local_repo_rhel_os_url_aarch64: "{{ backup_local_repo_config.rhel_os_url_aarch64 | default([], true) }}" local_repo_omnia_repo_url_rhel_x86_64: "{{ backup_local_repo_config.omnia_repo_url_rhel_x86_64 | default(backup_local_repo_config.omnia_repo_url_rhel | - default([])) + default([], true), true) }}" local_repo_omnia_repo_url_rhel_aarch64: "{{ backup_local_repo_config.omnia_repo_url_rhel_aarch64 | default(backup_local_repo_config.omnia_repo_url_rhel | - default([])) + default([], true), true) }}" local_repo_additional_repos_x86_64: "{{ backup_local_repo_config.additional_repos_x86_64 | default(backup_local_repo_config.additional_repos | - default([])) + default([], true), true) }}" - local_repo_additional_repos_aarch64: "{{ backup_local_repo_config.additional_repos_aarch64 | default([]) }}" + local_repo_additional_repos_aarch64: "{{ backup_local_repo_config.additional_repos_aarch64 | default([], true) }}" - name: Strip x86_64_ prefix from user_repo_url_x86_64 names ansible.builtin.set_fact: local_repo_user_repo_url_x86_64: >- {%- set result = [] -%} - {%- for repo in (local_repo_user_repo_url_x86_64 | default([])) -%} + {%- for repo in (local_repo_user_repo_url_x86_64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^x86_64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -107,7 +107,7 @@ ansible.builtin.set_fact: local_repo_user_repo_url_aarch64: >- {%- set result = [] -%} - {%- for repo in (local_repo_user_repo_url_aarch64 | default([])) -%} + {%- for repo in (local_repo_user_repo_url_aarch64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^aarch64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -117,7 +117,7 @@ ansible.builtin.set_fact: local_repo_rhel_os_url_x86_64: >- {%- set result = [] -%} - {%- for repo in (local_repo_rhel_os_url_x86_64 | default([])) -%} + {%- for repo in (local_repo_rhel_os_url_x86_64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^x86_64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -127,7 +127,7 @@ ansible.builtin.set_fact: local_repo_rhel_os_url_aarch64: >- {%- set result = [] -%} - {%- for repo in (local_repo_rhel_os_url_aarch64 | default([])) -%} + {%- for repo in (local_repo_rhel_os_url_aarch64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^aarch64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -137,7 +137,7 @@ ansible.builtin.set_fact: local_repo_additional_repos_x86_64: >- {%- set result = [] -%} - {%- for repo in (local_repo_additional_repos_x86_64 | default([])) -%} + {%- for repo in (local_repo_additional_repos_x86_64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^x86_64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -147,7 +147,7 @@ ansible.builtin.set_fact: local_repo_additional_repos_aarch64: >- {%- set result = [] -%} - {%- for repo in (local_repo_additional_repos_aarch64 | default([])) -%} + {%- for repo in (local_repo_additional_repos_aarch64 | default([], true)) -%} {%- set clean_name = repo.name | default('') | regex_replace('^aarch64_', '') -%} {%- set _ = result.append(repo | combine({'name': clean_name})) -%} {%- endfor -%} @@ -156,12 +156,12 @@ - name: Fail if omnia_repo_url_rhel_x86_64 is missing ansible.builtin.fail: msg: "{{ msg_omnia_repo_url_rhel_x86_64_missing }}" - when: (local_repo_omnia_repo_url_rhel_x86_64 | default([]) | length) == 0 + when: (local_repo_omnia_repo_url_rhel_x86_64 | default([], true) | length) == 0 - name: Fail if omnia_repo_url_rhel_aarch64 is missing ansible.builtin.fail: msg: "{{ msg_omnia_repo_url_rhel_aarch64_missing }}" - when: (local_repo_omnia_repo_url_rhel_aarch64 | default([]) | length) == 0 + when: (local_repo_omnia_repo_url_rhel_aarch64 | default([], true) | length) == 0 - name: Write local_repo_config.yml in Omnia 2.2 format ansible.builtin.template: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_network_spec.yml b/upgrade/roles/import_input_parameters/tasks/transform_network_spec.yml index 0867e1c405..8b0dc7d46f 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_network_spec.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_network_spec.yml @@ -50,7 +50,7 @@ if (backup_network_spec is mapping and backup_network_spec.admin_network is defined) else ( - (backup_network_spec.Networks | default([]) + (backup_network_spec.Networks | default([], true) | select('mapping') | selectattr('admin_network', 'defined') | map(attribute='admin_network') @@ -65,7 +65,7 @@ if (backup_network_spec is mapping and backup_network_spec.ib_network is defined) else ( - (backup_network_spec.Networks | default([]) + (backup_network_spec.Networks | default([], true) | select('mapping') | selectattr('ib_network', 'defined') | map(attribute='ib_network') diff --git a/upgrade/roles/import_input_parameters/tasks/transform_omnia_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_omnia_config.yml index 1fa196cc1e..b495b8b6e9 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_omnia_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_omnia_config.yml @@ -44,8 +44,8 @@ - name: Normalize omnia_config.yml values ansible.builtin.set_fact: - omnia_slurm_cluster_raw: "{{ backup_omnia_config.slurm_cluster | default([]) }}" - omnia_service_k8s_cluster_raw: "{{ backup_omnia_config.service_k8s_cluster | default([]) }}" + omnia_slurm_cluster_raw: "{{ backup_omnia_config.slurm_cluster | default([], true) }}" + omnia_service_k8s_cluster_raw: "{{ backup_omnia_config.service_k8s_cluster | default([], true) }}" - name: Ensure slurm_cluster and service_k8s_cluster are lists ansible.builtin.set_fact: @@ -65,12 +65,12 @@ - name: Fail if slurm_cluster is missing ansible.builtin.fail: msg: "{{ msg_slurm_cluster_missing }}" - when: (omnia_slurm_cluster | default([]) | length) == 0 + when: (omnia_slurm_cluster | default([], true) | length) == 0 - name: Fail if service_k8s_cluster is missing ansible.builtin.fail: msg: "{{ msg_service_k8s_cluster_missing }}" - when: (omnia_service_k8s_cluster | default([]) | length) == 0 + when: (omnia_service_k8s_cluster | default([], true) | length) == 0 - name: Write omnia_config.yml in Omnia 2.2 format ansible.builtin.template: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_powerscale_values.yml b/upgrade/roles/import_input_parameters/tasks/transform_powerscale_values.yml index ac2477aecf..d1aeb4e253 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_powerscale_values.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_powerscale_values.yml @@ -121,19 +121,46 @@ | select('ne', '') | first | default('') }} + - name: Fetch PowerScale secret_path from backup omnia_config + ansible.builtin.set_fact: + powerscale_secret_path: >- + {{ backup_omnia_config.service_k8s_cluster + | selectattr('csi_powerscale_driver_secret_file_path', 'defined') + | map(attribute='csi_powerscale_driver_secret_file_path') + | select('ne', '') + | first | default('') }} + - name: Display PowerScale values_path from backup omnia_config ansible.builtin.debug: msg: "PowerScale values_path from backup omnia_config: {{ powerscale_values_path }}" + - name: Display PowerScale secret_path from backup omnia_config + ansible.builtin.debug: + msg: "PowerScale secret_path from backup omnia_config: {{ powerscale_secret_path }}" + - name: Extract values file name from backup omnia_config powerscale_values_path ansible.builtin.set_fact: powerscale_values_filename: "{{ powerscale_values_path | basename | default('values.yaml') }}" when: powerscale_values_path | length > 0 + - name: Extract secret file name from backup omnia_config powerscale_secret_path + ansible.builtin.set_fact: + powerscale_secret_filename: "{{ powerscale_secret_path | basename | default('secret.yaml') }}" + when: powerscale_secret_path | length > 0 + + - name: Set default secret filename if path not configured + ansible.builtin.set_fact: + powerscale_secret_filename: "secret.yaml" + when: powerscale_secret_path | default('') | length == 0 + - name: Display extracted PowerScale values file name ansible.builtin.debug: msg: "PowerScale values file name from backup omnia_config: {{ powerscale_values_filename }}" + - name: Display extracted PowerScale secret file name + ansible.builtin.debug: + msg: "PowerScale secret file name from backup omnia_config: {{ powerscale_secret_filename }}" + - name: Build dynamic GitHub URL for target version values.yaml ansible.builtin.set_fact: powerscale_target_values_url: "{{ powerscale_values_github_url_template | replace('{version}', powerscale_v22_version | regex_replace('^v', '')) }}" @@ -170,12 +197,17 @@ msg: "{{ merge_values_result.stderr_lines | default([]) }}" when: merge_values_result.stderr_lines | default([]) | length > 0 - - name: Copy secret.yaml from v2.1 backup + - name: Check if v2.1 secret file exists in backup + ansible.builtin.stat: + path: "{{ backup_location }}/{{ powerscale_secret_filename }}" + register: v21_secret_stat + + - name: Copy secret file from v2.1 backup ansible.builtin.copy: - src: "{{ backup_location }}/secret.yaml" - dest: "{{ input_project_dir }}/secret.yaml" + src: "{{ backup_location }}/{{ powerscale_secret_filename }}" + dest: "{{ input_project_dir }}/{{ powerscale_secret_filename }}" mode: "0600" - when: v21_values_stat.stat.exists + when: v21_secret_stat.stat.exists - name: Display PowerScale values.yaml transformation summary ansible.builtin.debug: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_pxe_mapping_file.yml b/upgrade/roles/import_input_parameters/tasks/transform_pxe_mapping_file.yml index c23d8b0692..a467e62aa6 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_pxe_mapping_file.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_pxe_mapping_file.yml @@ -47,7 +47,7 @@ - name: Fail if no valid rows found in pxe_mapping_file ansible.builtin.fail: msg: "{{ msg_pxe_mapping_file_empty }}" - when: (pxe_mapping_rows | default([]) | length) == 0 + when: (pxe_mapping_rows | default([], true) | length) == 0 - name: Write pxe_mapping_file in Omnia 2.2 format with IB fields ansible.builtin.template: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_storage_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_storage_config.yml index a9b12b424e..4097f4d472 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_storage_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_storage_config.yml @@ -59,13 +59,13 @@ ansible.builtin.set_fact: slurm_nfs_client_params: "{{ (backup_storage_config.nfs_client_params | selectattr('nfs_name', 'equalto', slurm_nfs_storage_name) | first | default({})) }}" k8s_nfs_client_params: "{{ (backup_storage_config.nfs_client_params | selectattr('nfs_name', 'equalto', k8s_nfs_storage_name) | first | default({})) }}" - storage_nfs_client_params: "{{ backup_storage_config.nfs_client_params | default([]) }}" - storage_powervault_config: "{{ backup_storage_config.powervault_config | default({}) }}" + storage_nfs_client_params: "{{ backup_storage_config.nfs_client_params | default([], true) }}" + storage_powervault_config: "{{ backup_storage_config.powervault_config | default({}, true) }}" - name: Fail if nfs_client_params is missing ansible.builtin.fail: msg: "{{ msg_nfs_client_params_missing }}" - when: (storage_nfs_client_params | default([]) | length) == 0 + when: (storage_nfs_client_params | default([], true) | length) == 0 - name: Fail if any NFS client entry is missing required keys ansible.builtin.fail: diff --git a/upgrade/roles/import_input_parameters/tasks/transform_telemetry_config.yml b/upgrade/roles/import_input_parameters/tasks/transform_telemetry_config.yml index c112961faf..d86b476e39 100644 --- a/upgrade/roles/import_input_parameters/tasks/transform_telemetry_config.yml +++ b/upgrade/roles/import_input_parameters/tasks/transform_telemetry_config.yml @@ -46,19 +46,19 @@ ansible.builtin.set_fact: backup_telemetry_victoria_config: >- {{ backup_telemetry_config.victoria_metrics_configurations - | default(backup_telemetry_config.victoria_configurations | default({})) }} + | default(backup_telemetry_config.victoria_configurations | default({}, true)) }} backup_telemetry_kafka_config: >- - {{ backup_telemetry_config.kafka_configurations | default({}) }} + {{ backup_telemetry_config.kafka_configurations | default({}, true) }} backup_telemetry_victoria_logs_config: >- - {{ backup_telemetry_config.victoria_logs_configurations | default({}) }} + {{ backup_telemetry_config.victoria_logs_configurations | default({}, true) }} backup_telemetry_powerscale_config: >- - {{ backup_telemetry_config.powerscale_configurations | default({}) }} + {{ backup_telemetry_config.powerscale_configurations | default({}, true) }} backup_telemetry_sources: >- - {{ backup_telemetry_config.telemetry_sources | default({}) }} + {{ backup_telemetry_config.telemetry_sources | default({}, true) }} backup_telemetry_sinks: >- - {{ backup_telemetry_config.telemetry_sinks | default({}) }} + {{ backup_telemetry_config.telemetry_sinks | default({}, true) }} backup_telemetry_ldms_config: >- - {{ backup_telemetry_config.ldms_configurations | default({}) }} + {{ backup_telemetry_config.ldms_configurations | default({}, true) }} - name: Extract iDRAC telemetry support from backup (2.1 or 2.2 format) ansible.builtin.set_fact: @@ -66,7 +66,7 @@ {{ backup_telemetry_config.idrac_telemetry_support | default( - (backup_telemetry_sources.idrac | default({})).metrics_enabled + (backup_telemetry_sources.idrac | default({}, true)).metrics_enabled | default(telemetry_default_idrac_support) ) }} @@ -84,7 +84,7 @@ ansible.builtin.set_fact: telemetry_idrac_collection_targets: >- {{ - (backup_telemetry_sources.idrac | default({})).collection_targets + (backup_telemetry_sources.idrac | default({}, true)).collection_targets | default( telemetry_telemetry_collection_type.split(',') | map('trim') @@ -96,47 +96,47 @@ - name: Normalize VictoriaMetrics sink values from backup ansible.builtin.set_fact: telemetry_victoria_persistence_size: >- - {{ (backup_telemetry_sinks.victoria_metrics | default({})).persistence_size + {{ (backup_telemetry_sinks.victoria_metrics | default({}, true)).persistence_size | default(backup_telemetry_victoria_config.persistence_size | default(telemetry_default_victoria_persistence_size)) }} telemetry_victoria_retention_period: >- - {{ (backup_telemetry_sinks.victoria_metrics | default({})).retention_period + {{ (backup_telemetry_sinks.victoria_metrics | default({}, true)).retention_period | default(backup_telemetry_victoria_config.retention_period | default(telemetry_default_victoria_retention_period)) }} telemetry_additional_metric_remote_write_endpoints: >- - {{ (backup_telemetry_sinks.victoria_metrics | default({})).additional_metric_remote_write_endpoints - | default([]) }} + {{ (backup_telemetry_sinks.victoria_metrics | default({}, true)).additional_metric_remote_write_endpoints + | default([], true) }} - name: Normalize VictoriaLogs sink values from backup ansible.builtin.set_fact: telemetry_victoria_logs_storage_size: >- - {{ (backup_telemetry_sinks.victoria_logs | default({})).storage_size + {{ (backup_telemetry_sinks.victoria_logs | default({}, true)).storage_size | default(backup_telemetry_victoria_logs_config.storage_size | default(telemetry_default_victoria_logs_storage_size)) }} telemetry_victoria_logs_retention_period: >- - {{ (backup_telemetry_sinks.victoria_logs | default({})).retention_period + {{ (backup_telemetry_sinks.victoria_logs | default({}, true)).retention_period | default(backup_telemetry_victoria_logs_config.retention_period | default(telemetry_default_victoria_logs_retention_period)) }} telemetry_additional_log_write_endpoints: >- - {{ (backup_telemetry_sinks.victoria_logs | default({})).additional_log_write_endpoints - | default([]) }} + {{ (backup_telemetry_sinks.victoria_logs | default({}, true)).additional_log_write_endpoints + | default([], true) }} - name: Normalize Kafka sink values from backup ansible.builtin.set_fact: telemetry_kafka_persistence_size: >- - {{ (backup_telemetry_sinks.kafka | default({})).persistence_size + {{ (backup_telemetry_sinks.kafka | default({}, true)).persistence_size | default(backup_telemetry_kafka_config.persistence_size | default(telemetry_default_kafka_persistence_size)) }} telemetry_kafka_log_retention_hours: >- - {{ (backup_telemetry_sinks.kafka | default({})).log_retention_hours + {{ (backup_telemetry_sinks.kafka | default({}, true)).log_retention_hours | default(backup_telemetry_kafka_config.log_retention_hours | default(telemetry_default_kafka_log_retention_hours)) }} telemetry_kafka_log_retention_bytes: >- - {{ (backup_telemetry_sinks.kafka | default({})).log_retention_bytes + {{ (backup_telemetry_sinks.kafka | default({}, true)).log_retention_bytes | default(backup_telemetry_kafka_config.log_retention_bytes | default(telemetry_default_kafka_log_retention_bytes)) }} telemetry_kafka_log_segment_bytes: >- - {{ (backup_telemetry_sinks.kafka | default({})).log_segment_bytes + {{ (backup_telemetry_sinks.kafka | default({}, true)).log_segment_bytes | default(backup_telemetry_kafka_config.log_segment_bytes | default(telemetry_default_kafka_log_segment_bytes)) }} @@ -144,7 +144,7 @@ ansible.builtin.set_fact: telemetry_kafka_topic_partitions_raw: >- {{ - (backup_telemetry_sinks.kafka | default({})).topic_partitions + (backup_telemetry_sinks.kafka | default({}, true)).topic_partitions | default(backup_telemetry_kafka_config.topic_partitions | default(telemetry_default_kafka_topic_partitions)) }} @@ -204,7 +204,7 @@ ansible.builtin.set_fact: ldms_present_in_software_config: >- {{ - (backup_software_config.softwares | default([])) + (backup_software_config.softwares | default([], true)) | selectattr('name', 'defined') | selectattr('name', 'equalto', 'ldms') | list @@ -220,46 +220,46 @@ - name: Normalize LDMS source metrics_enabled from backup ansible.builtin.set_fact: telemetry_ldms_metrics_enabled: >- - {{ (backup_telemetry_sources.ldms | default({})).metrics_enabled + {{ (backup_telemetry_sources.ldms | default({}, true)).metrics_enabled | default(true if ldms_present_in_software_config | bool else telemetry_default_ldms_metrics_enabled) }} - name: Normalize DCGM and PowerScale source values from backup ansible.builtin.set_fact: telemetry_dcgm_support: >- - {{ (backup_telemetry_sources.dcgm | default({})).metrics_enabled + {{ (backup_telemetry_sources.dcgm | default({}, true)).metrics_enabled | default(backup_telemetry_config.dcgm_support | default(telemetry_default_dcgm_support)) }} telemetry_powerscale_metrics_enabled: >- - {{ (backup_telemetry_sources.powerscale | default({})).metrics_enabled + {{ (backup_telemetry_sources.powerscale | default({}, true)).metrics_enabled | default(backup_telemetry_powerscale_config.powerscale_telemetry_support | default(telemetry_default_powerscale_support)) }} telemetry_powerscale_logs_enabled: >- - {{ (backup_telemetry_sources.powerscale | default({})).logs_enabled + {{ (backup_telemetry_sources.powerscale | default({}, true)).logs_enabled | default(backup_telemetry_powerscale_config.powerscale_log_enabled | default(telemetry_default_powerscale_log_enabled)) }} - name: Normalize OME source values from backup (new in 2.2) ansible.builtin.set_fact: telemetry_ome_metrics_enabled: >- - {{ (backup_telemetry_sources.ome | default({})).metrics_enabled + {{ (backup_telemetry_sources.ome | default({}, true)).metrics_enabled | default(telemetry_default_ome_metrics_enabled) }} telemetry_ome_logs_enabled: >- - {{ (backup_telemetry_sources.ome | default({})).logs_enabled + {{ (backup_telemetry_sources.ome | default({}, true)).logs_enabled | default(telemetry_default_ome_logs_enabled) }} - name: Normalize UFM source values from backup (new in 2.2) ansible.builtin.set_fact: telemetry_ufm_metrics_enabled: >- - {{ (backup_telemetry_sources.ufm | default({})).metrics_enabled + {{ (backup_telemetry_sources.ufm | default({}, true)).metrics_enabled | default(telemetry_default_ufm_metrics_enabled) }} telemetry_ufm_logs_enabled: >- - {{ (backup_telemetry_sources.ufm | default({})).logs_enabled + {{ (backup_telemetry_sources.ufm | default({}, true)).logs_enabled | default(telemetry_default_ufm_logs_enabled) }} - name: Normalize UFM configuration values from backup (new in 2.2) ansible.builtin.set_fact: backup_telemetry_ufm_config: >- - {{ backup_telemetry_config.ufm_configuration | default({}) }} + {{ backup_telemetry_config.ufm_configuration | default({}, true) }} - name: Extract UFM configuration fields ansible.builtin.set_fact: @@ -288,16 +288,16 @@ - name: Normalize VAST source values from backup (new in 2.2) ansible.builtin.set_fact: telemetry_vast_metrics_enabled: >- - {{ (backup_telemetry_sources.vast | default({})).metrics_enabled + {{ (backup_telemetry_sources.vast | default({}, true)).metrics_enabled | default(telemetry_default_vast_metrics_enabled) }} telemetry_vast_logs_enabled: >- - {{ (backup_telemetry_sources.vast | default({})).logs_enabled + {{ (backup_telemetry_sources.vast | default({}, true)).logs_enabled | default(telemetry_default_vast_logs_enabled) }} - name: Normalize VAST configuration values from backup (new in 2.2) ansible.builtin.set_fact: backup_telemetry_vast_config: >- - {{ backup_telemetry_config.vast_configuration | default({}) }} + {{ backup_telemetry_config.vast_configuration | default({}, true) }} - name: Extract VAST configuration fields ansible.builtin.set_fact: @@ -329,16 +329,16 @@ - name: Normalize bridge values from backup (2.2 format or defaults) ansible.builtin.set_fact: telemetry_vector_ldms_metrics_enabled: >- - {{ ((backup_telemetry_config.telemetry_bridges | default({})).vector_ldms | default({})).metrics_enabled + {{ ((backup_telemetry_config.telemetry_bridges | default({}, true)).vector_ldms | default({}, true)).metrics_enabled | default(telemetry_default_vector_ldms_metrics_enabled) }} telemetry_vector_ome_metrics_enabled: >- - {{ ((backup_telemetry_config.telemetry_bridges | default({})).vector_ome | default({})).metrics_enabled + {{ ((backup_telemetry_config.telemetry_bridges | default({}, true)).vector_ome | default({}, true)).metrics_enabled | default(telemetry_default_vector_ome_metrics_enabled) }} telemetry_vector_ome_logs_enabled: >- - {{ ((backup_telemetry_config.telemetry_bridges | default({})).vector_ome | default({})).logs_enabled + {{ ((backup_telemetry_config.telemetry_bridges | default({}, true)).vector_ome | default({}, true)).logs_enabled | default(telemetry_default_vector_ome_logs_enabled) }} telemetry_vector_ome_identifier: >- - {{ ((backup_telemetry_config.telemetry_bridges | default({})).vector_ome | default({})).ome_identifier + {{ ((backup_telemetry_config.telemetry_bridges | default({}, true)).vector_ome | default({}, true)).ome_identifier | default('ome') }} - name: Normalize PowerScale configuration values from backup diff --git a/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 b/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 index 1f4025b432..7daf9b941d 100644 --- a/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 +++ b/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 @@ -162,7 +162,7 @@ # user_registry: # - { host: "172.16.107.254:4000", cert_path: "/opt/omnia/domain.crt", key_path: "/opt/omnia/domain.key" } user_registry: -{% set _user_registry = local_repo_user_registry | default([]) %} +{% set _user_registry = local_repo_user_registry | default([], true) %} {% if (_user_registry | length) > 0 %} {% for _reg in _user_registry %} - { host: {{ (_reg.host | default('')) | to_json }}, cert_path: {{ (_reg.cert_path | default('')) | to_json }}, key_path: {{ (_reg.key_path | default('')) | to_json }} } @@ -171,14 +171,14 @@ user_registry: # user_repo_url_x86_64: # - { url: "", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "slurm_custom" } user_repo_url_x86_64: -{% set _user_repo_url_x86_64 = local_repo_user_repo_url_x86_64 | default([]) %} +{% set _user_repo_url_x86_64 = local_repo_user_repo_url_x86_64 | default([], true) %} {% if (_user_repo_url_x86_64 | length) > 0 %} {% for _repo in _user_repo_url_x86_64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }} } {% endfor %} {% endif %} user_repo_url_aarch64: -{% set _user_repo_url_aarch64 = local_repo_user_repo_url_aarch64 | default([]) %} +{% set _user_repo_url_aarch64 = local_repo_user_repo_url_aarch64 | default([], true) %} {% if (_user_repo_url_aarch64 | length) > 0 %} {% for _repo in _user_repo_url_aarch64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }} } @@ -190,14 +190,14 @@ user_repo_url_aarch64: # - { url: "http://BaseOS.com/BaseOS/x86_64/os/", gpgkey: "http://BaseOS.com/BaseOS/x86_64/os/RPM-GPG-KEY", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "baseos"} # - { url: "http://AppStream.com/AppStream/x86_64/os/", gpgkey: "http://AppStream.com/AppStream/x86_64/os/RPM-GPG-KEY", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "appstream" } rhel_os_url_x86_64: -{% set _rhel_os_url_x86_64 = local_repo_rhel_os_url_x86_64 | default([]) %} +{% set _rhel_os_url_x86_64 = local_repo_rhel_os_url_x86_64 | default([], true) %} {% if (_rhel_os_url_x86_64 | length) > 0 %} {% for _repo in _rhel_os_url_x86_64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }} } {% endfor %} {% endif %} rhel_os_url_aarch64: -{% set _rhel_os_url_aarch64 = local_repo_rhel_os_url_aarch64 | default([]) %} +{% set _rhel_os_url_aarch64 = local_repo_rhel_os_url_aarch64 | default([], true) %} {% if (_rhel_os_url_aarch64 | length) > 0 %} {% for _repo in _rhel_os_url_aarch64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }} } @@ -227,14 +227,14 @@ omnia_repo_url_rhel_aarch64: # - { url: "https://rpm.grafana.com/", gpgkey: "", name: "grafana" } # - { url: "https://repo.example.com/x86_64/", gpgkey: "", name: "custom-repo", sslcacert: "/path/ca.crt", sslclientkey: "/path/client.key", sslclientcert: "/path/client.crt" } additional_repos_x86_64: -{% set _additional_repos_x86_64 = local_repo_additional_repos_x86_64 | default([]) %} +{% set _additional_repos_x86_64 = local_repo_additional_repos_x86_64 | default([], true) %} {% if (_additional_repos_x86_64 | length) > 0 %} {% for _repo in _additional_repos_x86_64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }} } {% endfor %} {% endif %} additional_repos_aarch64: -{% set _additional_repos_aarch64 = local_repo_additional_repos_aarch64 | default([]) %} +{% set _additional_repos_aarch64 = local_repo_additional_repos_aarch64 | default([], true) %} {% if (_additional_repos_aarch64 | length) > 0 %} {% for _repo in _additional_repos_aarch64 %} - { url: {{ (_repo.url | default('')) | to_json }}, gpgkey: {{ (_repo.gpgkey | default('')) | to_json }}, name: {{ (_repo.name | default('')) | to_json }}, sslcacert: {{ (_repo.sslcacert | default('')) | to_json }}, sslclientkey: {{ (_repo.sslclientkey | default('')) | to_json }}, sslclientcert: {{ (_repo.sslclientcert | default('')) | to_json }} } diff --git a/upgrade/roles/import_input_parameters/templates/network_spec.j2 b/upgrade/roles/import_input_parameters/templates/network_spec.j2 index 864fd39014..b46c12f90b 100644 --- a/upgrade/roles/import_input_parameters/templates/network_spec.j2 +++ b/upgrade/roles/import_input_parameters/templates/network_spec.j2 @@ -70,11 +70,11 @@ Networks: primary_oim_admin_ip: "{{ admin_network.primary_oim_admin_ip | default('') }}" primary_oim_bmc_ip: "{{ admin_network.primary_oim_bmc_ip | default('') }}" dynamic_range: "{{ admin_network.dynamic_range | default('') }}" - dns: {{ admin_network.dns | default([]) }} - ntp_servers: {{ admin_network.ntp_servers | default([]) }} - additional_subnets: {{ admin_network.additional_subnets | default([]) }} + dns: {{ admin_network.dns | default([], true) }} + ntp_servers: {{ admin_network.ntp_servers | default([], true) }} + additional_subnets: {{ admin_network.additional_subnets | default([], true) }} - ib_network: subnet: "{{ ib_network.subnet | default('') }}" netmask_bits: "{{ ib_network.netmask_bits | default(admin_network_netmask_bits | default(network_default_netmask_bits)) }}" - dns: {{ ib_network.dns | default([]) }} + dns: {{ ib_network.dns | default([], true) }} diff --git a/upgrade/roles/import_input_parameters/templates/omnia_config.j2 b/upgrade/roles/import_input_parameters/templates/omnia_config.j2 index 91ba9622a1..0c86f50913 100644 --- a/upgrade/roles/import_input_parameters/templates/omnia_config.j2 +++ b/upgrade/roles/import_input_parameters/templates/omnia_config.j2 @@ -118,7 +118,7 @@ # Thes files will be written into the slurm_config directory with .conf suffix slurm_cluster: -{% set _slurm_cluster = omnia_slurm_cluster | default([]) %} +{% set _slurm_cluster = omnia_slurm_cluster | default([], true) %} {% if (_slurm_cluster | length) > 0 %} {% for _cluster in _slurm_cluster %} - cluster_name: {{ _cluster.cluster_name | default('') }} @@ -242,7 +242,7 @@ slurm_cluster: service_k8s_cluster: -{% set _service_k8s_cluster = omnia_service_k8s_cluster | default([]) %} +{% set _service_k8s_cluster = omnia_service_k8s_cluster | default([], true) %} {% if (_service_k8s_cluster | length) > 0 %} {% for _cluster in _service_k8s_cluster %} - cluster_name: {{ _cluster.cluster_name | default('') }} diff --git a/upgrade/roles/import_input_parameters/templates/omnia_config_credentials.yml.j2 b/upgrade/roles/import_input_parameters/templates/omnia_config_credentials.yml.j2 index 9ca40114aa..80699f1cc2 100644 --- a/upgrade/roles/import_input_parameters/templates/omnia_config_credentials.yml.j2 +++ b/upgrade/roles/import_input_parameters/templates/omnia_config_credentials.yml.j2 @@ -58,3 +58,7 @@ ome_password: "{{ ome_password | default('') }}" # UFM telemetry credentials ufm_username: "{{ ufm_username | default('') }}" ufm_password: "{{ ufm_password | default('') }}" + +# VAST telemetry credentials +vast_username: "{{ vast_username | default('') }}" +vast_password: "{{ vast_password | default('') }}" diff --git a/upgrade/roles/import_input_parameters/templates/storage_config.j2 b/upgrade/roles/import_input_parameters/templates/storage_config.j2 index 2220ffd560..1a0a0c617d 100644 --- a/upgrade/roles/import_input_parameters/templates/storage_config.j2 +++ b/upgrade/roles/import_input_parameters/templates/storage_config.j2 @@ -189,12 +189,12 @@ mount_params: # # This mounts the whole powervault volume with to /mnt/slurm # # followed by bind creation of dir under /mnt/slurm # # node_key is the key in cloud-init so that its unique per host -{% set pv = storage_powervault_config | default({}) %} +{% set pv = storage_powervault_config | default({}, true) %} {% if pv %} powervault_config: - name: powervault_slurm_ctld ip: - {% for _ip in pv.ip | default([]) %} + {% for _ip in pv.ip | default([], true) %} - {{ _ip }} {% endfor %} port: {{ pv.port | default('') }} diff --git a/upgrade/roles/import_input_parameters/templates/telemetry_config.j2 b/upgrade/roles/import_input_parameters/templates/telemetry_config.j2 index 80971b74ff..132bf50872 100644 --- a/upgrade/roles/import_input_parameters/templates/telemetry_config.j2 +++ b/upgrade/roles/import_input_parameters/templates/telemetry_config.j2 @@ -295,7 +295,7 @@ telemetry_sinks: # additional_metric_remote_write_endpoints: # - url: https://external-metrics-server:8480/insert/0/prometheus/api/v1/write # tls_insecure_skip_verify: false - additional_metric_remote_write_endpoints: {{ telemetry_additional_metric_remote_write_endpoints | default([]) | to_json }} + additional_metric_remote_write_endpoints: {{ telemetry_additional_metric_remote_write_endpoints | default([], true) | to_json }} # -------------------------------------------------------------------------- # victoria_logs — Centralized log storage and querying @@ -322,7 +322,7 @@ telemetry_sinks: # additional_log_write_endpoints: # - url: https://external-logs-server:9481/internal/insert # tls_insecure_skip_verify: false - additional_log_write_endpoints: {{ telemetry_additional_log_write_endpoints | default([]) | to_json }} + additional_log_write_endpoints: {{ telemetry_additional_log_write_endpoints | default([], true) | to_json }} # -------------------------------------------------------------------------- # Kafka — Distributed streaming platform @@ -391,7 +391,7 @@ ldms_configurations: {% if telemetry_ldms_sampler_configurations is none %} null {% else %} -{% for _plugin in (telemetry_ldms_sampler_configurations | default([])) %} +{% for _plugin in (telemetry_ldms_sampler_configurations | default([], true)) %} - plugin_name: {{ _plugin.plugin_name | default('') }} config_parameters: {{ _plugin.config_parameters | default('') | to_json }} activation_parameters: {{ _plugin.activation_parameters | default('interval=30000000') | to_json }} diff --git a/upgrade/roles/import_input_parameters/vars/main.yml b/upgrade/roles/import_input_parameters/vars/main.yml index 3bac72ac30..4423147336 100644 --- a/upgrade/roles/import_input_parameters/vars/main.yml +++ b/upgrade/roles/import_input_parameters/vars/main.yml @@ -353,13 +353,13 @@ msg_powerscale_v22_version_missing: | Please check the software_config.json file. msg_powerscale_values_transform_summary: | PowerScale CSI driver values.yaml transformed: {{ powerscale_v21_version }} to {{ powerscale_v22_version }}. - Backup preserved at: {{ backup_location }}/values.yaml - Target: {{ input_project_dir }}/values.yaml + Backup preserved at: {{ backup_location }}/{{ powerscale_values_filename | default('values.yaml') }} + Target: {{ input_project_dir }}/{{ powerscale_values_filename | default('values.yaml') }} Changes: - Downloaded {{ powerscale_v22_version }} values.yaml template from GitHub - Preserved v2.1 settings: isiPath, isiAccessZone, controllerCount, custom configurations - Updated to {{ powerscale_v22_version }} structure with new parameters - Secret file copied: {{ input_project_dir }}/secret.yaml + Secret file copied: {{ input_project_dir }}/{{ powerscale_secret_filename | default('secret.yaml') }} # PowerScale GitHub URL template for values.yaml powerscale_values_github_url_template: "https://raw.githubusercontent.com/dell/helm-charts/csi-isilon-{version}/charts/csi-isilon/values.yaml" diff --git a/upgrade/roles/prep_local_repo/tasks/create_staging.yml b/upgrade/roles/prep_local_repo/tasks/create_staging.yml index 8ef5856b26..581452dd9e 100644 --- a/upgrade/roles/prep_local_repo/tasks/create_staging.yml +++ b/upgrade/roles/prep_local_repo/tasks/create_staging.yml @@ -45,7 +45,7 @@ current_software_config: "{{ current_software_config }}" architectures: "{{ upgrade_active_architectures }}" target_omnia_version: "{{ upgrade_target_version }}" - calculated_hop_chains: "{{ calculated_hop_chains | default([]) }}" + calculated_hop_chains: "{{ calculated_hop_chains | default([], true) }}" register: _staging_result - name: "Staging — Display staging summary" diff --git a/upgrade/roles/prep_local_repo/tasks/sync_local_repo.yml b/upgrade/roles/prep_local_repo/tasks/sync_local_repo.yml index 675a33c8e2..eecea9920e 100644 --- a/upgrade/roles/prep_local_repo/tasks/sync_local_repo.yml +++ b/upgrade/roles/prep_local_repo/tasks/sync_local_repo.yml @@ -30,7 +30,7 @@ # Initialise sub_final_repo_urls (normally set by validate_subscription role) - name: "Sync — Initialise subscription repo URLs" ansible.builtin.set_fact: - sub_final_repo_urls: "{{ sub_final_repo_urls | default({}) }}" + sub_final_repo_urls: "{{ sub_final_repo_urls | default({}, true) }}" # Get actual Pulp URL from pulp status command (same as pulp_validation role) - name: "Sync — Get Pulp status" diff --git a/upgrade/roles/upgrade_build_stream/tasks/gitlab_config_upgrade.yml b/upgrade/roles/upgrade_build_stream/tasks/gitlab_config_upgrade.yml index 5a4676b2e1..e7a5dbfb1d 100644 --- a/upgrade/roles/upgrade_build_stream/tasks/gitlab_config_upgrade.yml +++ b/upgrade/roles/upgrade_build_stream/tasks/gitlab_config_upgrade.yml @@ -140,7 +140,7 @@ ACTION REQUIRED: Wait for all pipelines to complete or cancel them before re-running. ============================================================ - when: _active_pipeline_list | default([]) | length > 0 + when: _active_pipeline_list | default([], true) | length > 0 # ══════════════════════════════════════════════════════════════════ # GL-TAG: Create pre-upgrade tag for rollback safety diff --git a/upgrade/roles/upgrade_cluster/vars/main.yml b/upgrade/roles/upgrade_cluster/vars/main.yml index 6e141b6538..4f287a7dfa 100644 --- a/upgrade/roles/upgrade_cluster/vars/main.yml +++ b/upgrade/roles/upgrade_cluster/vars/main.yml @@ -14,5 +14,5 @@ --- storage_config_path: "/opt/omnia/input/project_default/storage_config.yml" storage_content: "{{ lookup('file', storage_config_path, errors='ignore') | default('') }}" -storage_yaml: "{{ storage_content | from_yaml | default({}) }}" -nfs_params: "{{ storage_yaml.nfs_client_params | default([]) }}" +storage_yaml: "{{ storage_content | from_yaml | default({}, true) }}" +nfs_params: "{{ storage_yaml.nfs_client_params | default([], true) }}" diff --git a/upgrade/roles/upgrade_k8s/tasks/execute_single_hop.yml b/upgrade/roles/upgrade_k8s/tasks/execute_single_hop.yml index 70c98c3e44..cc95b84133 100644 --- a/upgrade/roles/upgrade_k8s/tasks/execute_single_hop.yml +++ b/upgrade/roles/upgrade_k8s/tasks/execute_single_hop.yml @@ -46,7 +46,7 @@ - name: "Hop — Check if hop already completed" ansible.builtin.set_fact: _hop_completed: >- - {{ (upgrade_status.multi_hop.hops | default([])) + {{ (upgrade_status.multi_hop.hops | default([], true)) | selectattr('to', 'equalto', _current_hop.to_version) | selectattr('status', 'equalto', 'completed') | list | length > 0 }} @@ -147,7 +147,7 @@ multi_hop: current_hop: "{{ _hop_idx }}" hops: >- - {{ (upgrade_status.multi_hop.hops | default([])) + {{ (upgrade_status.multi_hop.hops | default([], true)) | rejectattr('to', 'equalto', _current_hop.to_version) | list + [{ @@ -415,12 +415,13 @@ status: in_progress started_at: "{{ now(utc=true).strftime('%Y-%m-%dT%H:%M:%SZ') }}" when: + - groups_cp | default([]) | length > 0 - upgrade_status.upgrade.status != 'completed' - upgrade_status.bss_update.service_kube_control_plane.status | default('pending') != 'completed' - name: "Hop — Update cloud-init and BSS for service_kube_control_plane_x86_64" when: - - ha_config_data.service_k8s_cluster_ha | length > 1 + - groups_cp | default([]) | length > 0 - upgrade_status.upgrade.status != 'completed' - upgrade_status.bss_update.service_kube_control_plane.status | default('pending') != 'completed' ansible.builtin.shell: @@ -447,11 +448,26 @@ status: completed completed_at: "{{ now(utc=true).strftime('%Y-%m-%dT%H:%M:%SZ') }}" when: + - groups_cp | default([]) | length > 0 - upgrade_status.upgrade.status != 'completed' - bss_cp_additional_result is defined - bss_cp_additional_result is not skipped - bss_cp_additional_result.rc == 0 + - name: "Hop — Set BSS status to completed for service_kube_control_plane (no additional CPs)" + ansible.builtin.include_tasks: update_node_step.yml + vars: + status_update: + bss_update: + service_kube_control_plane: + status: completed + completed_at: "{{ now(utc=true).strftime('%Y-%m-%dT%H:%M:%SZ') }}" + note: "Skipped - no additional control planes to update" + when: + - groups_cp | default([]) | length == 0 + - upgrade_status.upgrade.status != 'completed' + - upgrade_status.bss_update.service_kube_control_plane.status | default('pending') != 'completed' + - name: "Hop — Control plane upgrades complete" ansible.builtin.debug: msg: "{{ cp_complete_banner }}" @@ -768,7 +784,7 @@ multi_hop: current_hop: "{{ _hop_idx }}" hops: >- - {{ (upgrade_status.multi_hop.hops | default([])) + {{ (upgrade_status.multi_hop.hops | default([], true)) | rejectattr('to', 'equalto', _current_hop.to_version) | list + [{ diff --git a/upgrade/roles/upgrade_k8s/tasks/load_version_vars.yml b/upgrade/roles/upgrade_k8s/tasks/load_version_vars.yml index d930690682..33b51ae6b6 100644 --- a/upgrade/roles/upgrade_k8s/tasks/load_version_vars.yml +++ b/upgrade/roles/upgrade_k8s/tasks/load_version_vars.yml @@ -126,8 +126,3 @@ | selectattr('type', 'equalto', 'tarball') | selectattr('package', 'search', 'helm') | map(attribute='package') | join }} - -# ── Set OIM host ─────────────────────────────────────────────────── -- name: Set oim_host to NFS server IP - ansible.builtin.set_fact: - oim_host: "{{ k8s_nfs_server_ip }}" diff --git a/upgrade/roles/upgrade_k8s/tasks/powerscale_prepare_upgrade.yml b/upgrade/roles/upgrade_k8s/tasks/powerscale_prepare_upgrade.yml index cac3e9165c..14e367b9cf 100644 --- a/upgrade/roles/upgrade_k8s/tasks/powerscale_prepare_upgrade.yml +++ b/upgrade/roles/upgrade_k8s/tasks/powerscale_prepare_upgrade.yml @@ -46,7 +46,7 @@ msg: "{{ msg_powerscale_controller_pods_missing }}" when: > powerscale_controller_pods.rc != 0 or - (powerscale_controllers['items'] | default([])) | length == 0 + (powerscale_controllers['items'] | default([], true)) | length == 0 - name: Check PowerScale node daemonset delegate_to: "{{ kube_vip }}" diff --git a/upgrade/roles/upgrade_k8s/tasks/preflight_checks_pulp.yml b/upgrade/roles/upgrade_k8s/tasks/preflight_checks_pulp.yml index b0d33c4c00..0f1f5184bd 100644 --- a/upgrade/roles/upgrade_k8s/tasks/preflight_checks_pulp.yml +++ b/upgrade/roles/upgrade_k8s/tasks/preflight_checks_pulp.yml @@ -66,13 +66,15 @@ - name: Verify required tags exist for each image ansible.builtin.fail: - msg: "Required image {{ item.item.name }}:{{ item.item.tag }} not found in Pulp registry. Available tags: {{ item.json.tags | default([]) | join(', ') }}" + msg: >- + Required image {{ item.item.name }}:{{ item.item.tag }} not found in Pulp registry. + Available tags: {{ item.json.tags | default([], true) | join(', ') }} loop: "{{ image_checks.results }}" loop_control: label: "{{ item.item.name }}:{{ item.item.tag }}" when: - item.status == 200 - - item.item.tag not in (item.json.tags | default([])) + - item.item.tag not in (item.json.tags | default([], true)) - name: Warn if image check failed ansible.builtin.debug: diff --git a/upgrade/roles/upgrade_k8s/tasks/preflight_checks_storage.yml b/upgrade/roles/upgrade_k8s/tasks/preflight_checks_storage.yml index 4d2572fa7e..7cc2b8f319 100644 --- a/upgrade/roles/upgrade_k8s/tasks/preflight_checks_storage.yml +++ b/upgrade/roles/upgrade_k8s/tasks/preflight_checks_storage.yml @@ -20,6 +20,7 @@ # 1. No PersistentVolumes in Failed state # 2. No PersistentVolumeClaims in Lost state # 3. NFS storage mount is accessible on kube_vip +# 4. All control planes (first + additional) have .cluster_initialized marker # ── Check 1: PersistentVolumes must not be in Failed state ───────── - name: "Preflight storage — Check for PersistentVolumes in Failed state" @@ -74,29 +75,63 @@ when: not (preflight_nfs_stat.stat.exists | default(false)) # ── Check 4: All control planes must have .cluster_initialized marker ── +- name: "Preflight storage — Build list of all control plane nodes" + ansible.builtin.set_fact: + all_control_plane_nodes: "{{ (groups['k8s_control_plane_first'] | default([])) + (groups['k8s_control_plane'] | default([])) }}" + - name: "Preflight storage — Check .cluster_initialized marker on all control planes" ansible.builtin.stat: path: "/etc/kubernetes/.cluster_initialized" delegate_to: "{{ item }}" register: preflight_cluster_init_check - loop: "{{ groups[group_cp] | default([]) }}" + loop: "{{ all_control_plane_nodes }}" loop_control: label: "{{ item }}" + when: all_control_plane_nodes | length > 0 -- name: "Preflight storage — Fail if any control plane is missing .cluster_initialized" - ansible.builtin.fail: - msg: | - Control plane node {{ item.item }} is missing /etc/kubernetes/.cluster_initialized marker file. - This indicates that the node's cloud-init provisioning did not complete successfully. +- name: "Preflight storage — Collect nodes missing .cluster_initialized" + ansible.builtin.set_fact: + missing_cluster_init_nodes: >- + {{ preflight_cluster_init_check.results + | selectattr('stat.exists', 'defined') + | rejectattr('stat.exists') + | map(attribute='item') + | list }} + when: preflight_cluster_init_check.results is defined - Please check the cloud-init logs on {{ item.item }}: - ssh {{ item.item }} cat /var/log/cloud-init-output.log +- name: "Preflight storage — Display missing nodes warning" + ansible.builtin.debug: + msg: + - "" + - "╔════════════════════════════════════════════════════════════════════════════════╗" + - "║ PREFLIGHT CHECK FAILED: Missing .cluster_initialized marker ║" + - "╚════════════════════════════════════════════════════════════════════════════════╝" + - "" + - "The following control plane node(s) are missing /etc/kubernetes/.cluster_initialized:" + - " {{ missing_cluster_init_nodes | join(', ') }}" + - "" + - "This indicates that cloud-init provisioning did not complete successfully." + - "" + - "── Troubleshooting Steps ──────────────────────────────────────────────────────" + - "" + - "Check cloud-init logs on the affected node(s):" + - "{% for node in missing_cluster_init_nodes %} ssh {{ node }}{% endfor %}" + - "{% for node in missing_cluster_init_nodes %} cat /var/log/cloud-init-output.log{% endfor %}" + - "" + - "── Action Required ────────────────────────────────────────────────────────────" + - "" + - "Fix the provisioning issues on the affected nodes before retrying the upgrade." + - "" + when: + - missing_cluster_init_nodes is defined + - missing_cluster_init_nodes | length > 0 - The node must be successfully provisioned before upgrade can proceed. - loop: "{{ preflight_cluster_init_check.results }}" - loop_control: - label: "{{ item.item }}" - when: not (item.stat.exists | default(false)) +- name: "Preflight storage — Fail if any control plane is missing .cluster_initialized" + ansible.builtin.fail: + msg: "Control plane nodes missing .cluster_initialized marker: {{ missing_cluster_init_nodes | join(', ') }}" + when: + - missing_cluster_init_nodes is defined + - missing_cluster_init_nodes | length > 0 - name: "Preflight storage — All storage checks passed" ansible.builtin.debug: diff --git a/upgrade/roles/upgrade_k8s/tasks/step_drain.yml b/upgrade/roles/upgrade_k8s/tasks/step_drain.yml index a15514c1d8..daa994ae7d 100644 --- a/upgrade/roles/upgrade_k8s/tasks/step_drain.yml +++ b/upgrade/roles/upgrade_k8s/tasks/step_drain.yml @@ -59,7 +59,7 @@ | combine({ item.namespace ~ '/' ~ item.name: ( - item.matchLabels | default({}) + item.matchLabels | default({}, true) | dictsort | map('join', '=') | join(',') diff --git a/upgrade/roles/upgrade_openchami/tasks/backup_openchami.yml b/upgrade/roles/upgrade_openchami/tasks/backup_openchami.yml index e646f78066..e3b33530c4 100644 --- a/upgrade/roles/upgrade_openchami/tasks/backup_openchami.yml +++ b/upgrade/roles/upgrade_openchami/tasks/backup_openchami.yml @@ -297,13 +297,19 @@ - name: Create backup inventory manifest ansible.builtin.copy: content: | - # OpenCHAMI Pre-Upgrade Backup Manifest + # OpenCHAMI Backup Manifest backup_timestamp: "{{ ansible_date_time.iso8601 }}" - source_version: "{{ backup_manifest.source_version | default('unknown') }}" - target_version: "{{ backup_manifest.target_version | default('unknown') }}" upgrade_id: "{{ backup_manifest.upgrade_id | default('unknown') }}" backup_dir: "{{ openchami_backup_dir }}" + source_rpms: + openchami: "{{ current_openchami_rpm | default('not installed') }}" + ochami_cli: "{{ current_ochami_rpm | default('not installed') }}" + + target_rpms: + openchami: "{{ openchami_rpm_name }}" + ochami_cli: "{{ ochami_client_rpm_name }}" + postgresql_backup: file: "openchami/postgresql_backup/openchami.sql" database: "{{ postgres_db_name }}" diff --git a/upgrade/roles/upgrade_openchami/tasks/post_upgrade_health_check.yml b/upgrade/roles/upgrade_openchami/tasks/post_upgrade_health_check.yml index 28a20e21d1..df8aae5793 100644 --- a/upgrade/roles/upgrade_openchami/tasks/post_upgrade_health_check.yml +++ b/upgrade/roles/upgrade_openchami/tasks/post_upgrade_health_check.yml @@ -220,7 +220,7 @@ set -o pipefail ochami smd --cacert {{ ca_cert_path | default('/root_ca/root_ca.crt') }} \ component get 2>&1 | head -20 || echo "ochami_unavailable" - environment: "{{ ci_reload_ochami_env | default({}) }}" + environment: "{{ ci_reload_ochami_env | default({}, true) }}" register: ochami_smd_check changed_when: false failed_when: false @@ -267,7 +267,7 @@ ansible.builtin.shell: | set -o pipefail /usr/bin/ochami bss boot params get -F yaml 2>&1 | grep -c 'cloud-init' || echo "0" - environment: "{{ ci_reload_ochami_env | default({}) }}" + environment: "{{ ci_reload_ochami_env | default({}, true) }}" register: bss_ci_ds_check changed_when: false failed_when: false @@ -303,7 +303,7 @@ ansible.builtin.shell: | set -o pipefail /usr/bin/ochami cloud-init service status 2>&1 - environment: "{{ ci_reload_ochami_env | default({}) }}" + environment: "{{ ci_reload_ochami_env | default({}, true) }}" register: ci_http_health changed_when: false failed_when: false @@ -328,7 +328,7 @@ ansible.builtin.shell: | set -o pipefail /usr/bin/ochami cloud-init group get 2>&1 || echo "ci_unavailable" - environment: "{{ ci_reload_ochami_env | default({}) }}" + environment: "{{ ci_reload_ochami_env | default({}, true) }}" register: ci_group_list changed_when: false failed_when: false @@ -354,7 +354,7 @@ ansible.builtin.shell: | set -o pipefail /usr/bin/ochami cloud-init node get 2>&1 || echo "ci_node_unavailable" - environment: "{{ ci_reload_ochami_env | default({}) }}" + environment: "{{ ci_reload_ochami_env | default({}, true) }}" register: ci_node_list changed_when: false failed_when: false diff --git a/upgrade/roles/upgrade_openchami/tasks/pre_upgrade_health_check.yml b/upgrade/roles/upgrade_openchami/tasks/pre_upgrade_health_check.yml index e131c383aa..293bc49b3e 100644 --- a/upgrade/roles/upgrade_openchami/tasks/pre_upgrade_health_check.yml +++ b/upgrade/roles/upgrade_openchami/tasks/pre_upgrade_health_check.yml @@ -95,29 +95,41 @@ # --- Pre-upgrade health verification --- - name: Pre-upgrade health check block: - # ── Verify current OpenCHAMI version from version.yml ───────── - - name: Check if version.yml exists - ansible.builtin.stat: - path: "/opt/omnia/.data/version.yml" - register: version_yml_stat + # ── Find source (2.1) OpenCHAMI and ochami CLI RPM filenames from backup ───── + # The live workdir already contains the 2.2 target RPMs by the time + # the upgrade playbook runs. The original 2.1 RPMs are preserved in the + # backup directory created by omnia.sh --upgrade. + - name: Find source openchami RPM filename from backup + ansible.builtin.shell: | + set -o pipefail + backup_dir="{{ openchami_backup_dir | default(openchami_backup_dir_default) }}" + RPM=$(ls -1 "${backup_dir}/openchami/openchami_data/workdir/openchami"*.rpm 2>/dev/null | head -1) + if [ -n "$RPM" ]; then basename "$RPM"; else echo "not found"; fi + register: source_openchami_rpm_result + changed_when: false + failed_when: false - - name: Read current OpenCHAMI version from version.yml - ansible.builtin.slurp: - src: "/opt/omnia/.data/version.yml" - register: version_yml_raw - when: version_yml_stat.stat.exists | default(false) + - name: Find source ochami CLI RPM filename from backup + ansible.builtin.shell: | + set -o pipefail + backup_dir="{{ openchami_backup_dir | default(openchami_backup_dir_default) }}" + RPM=$(ls -1 "${backup_dir}/openchami/openchami_data/workdir/ochami"*.rpm 2>/dev/null | head -1) + if [ -n "$RPM" ]; then basename "$RPM"; else echo "not found"; fi + register: source_ochami_rpm_result + changed_when: false + failed_when: false - - name: Parse version.yml and display current version + - name: Set current RPM filename facts ansible.builtin.set_fact: - current_openchami_version: "{{ (version_yml_raw.content | b64decode | from_yaml).openchami_version | default('unknown') }}" - when: - - version_yml_stat.stat.exists | default(false) - - version_yml_raw.content is defined + current_openchami_rpm: "{{ source_openchami_rpm_result.stdout | default('not found') | trim }}" + current_ochami_rpm: "{{ source_ochami_rpm_result.stdout | default('not found') | trim }}" - - name: Display current OpenCHAMI version + - name: Display current installed RPM filenames ansible.builtin.debug: verbosity: 1 - msg: "Current OpenCHAMI version: {{ current_openchami_version | default('not recorded') }}" + msg: + - "Source openchami RPM: {{ current_openchami_rpm }}" + - "Source ochami CLI RPM: {{ current_ochami_rpm }}" # ── Verify no active provisioning jobs ──────────────────────── - name: Check for running discovery processes @@ -276,7 +288,8 @@ and 's3_unreachable' not in pre_s3_check.stdout | default('s3_unreachable')) else 'not configured (non-fatal)' }} - "Node count: {{ pre_upgrade_node_count }}{{ ' (prepare_oim-only)' if (pre_upgrade_node_count | int) == 0 else '' }}" - - "Version: {{ current_openchami_version | default('not recorded') }}" + - "OpenCHAMI RPM: {{ current_openchami_rpm | default('not installed') }}" + - "ochami CLI RPM: {{ current_ochami_rpm | default('not installed') }}" - "════════════════════════════════════════════" rescue: diff --git a/upgrade/roles/upgrade_openchami/tasks/upgrade_status.yml b/upgrade/roles/upgrade_openchami/tasks/upgrade_status.yml index 906672bd43..9beadc2572 100644 --- a/upgrade/roles/upgrade_openchami/tasks/upgrade_status.yml +++ b/upgrade/roles/upgrade_openchami/tasks/upgrade_status.yml @@ -23,36 +23,9 @@ {{ upgrade_messages.troubleshooting.container_upgrade_diagnosis }} when: openchami_upgrade_failed | default(false) | bool - # ── Update version.yml with new metadata on success ────────────── - - name: Update version.yml with new OpenCHAMI version metadata - ansible.builtin.copy: - content: | - # OpenCHAMI version metadata — updated by upgrade_openchami role - openchami_version: "{{ backup_manifest.target_version | default('2.2.0.0') }}" - omnia_version: "{{ backup_manifest.target_version | default('2.2.0.0') }}" - upgrade_timestamp: "{{ ansible_date_time.iso8601 }}" - upgraded_from: "{{ backup_manifest.source_version | default('2.1.0.0') }}" - component_versions: - smd: "{{ openchami_smd_tag }}" - bss: "{{ openchami_bss_tag }}" - cloud_init: "{{ openchami_cloud_init_tag }}" - local_ca: "{{ openchami_local_ca_tag }}" - opaal: "{{ openchami_opaal_tag }}" - coresmd: "{{ openchami_coresmd_tag }}" - postgres: "{{ postgres_tag }}" - hydra: "{{ hydra_tag }}" - haproxy: "{{ haproxy_tag }}" - registry: "{{ registry_tag }}" - minio: "{{ minio_release_tag }}" - dest: "/opt/omnia/.data/version.yml" - mode: "{{ file_permissions_644 }}" - when: - - not (openchami_upgrade_failed | default(false) | bool) - - openchami_deployed | default(false) | bool - - name: Report upgrade success ansible.builtin.debug: - msg: "OpenCHAMI upgrade completed successfully. version.yml updated." + msg: "OpenCHAMI upgrade completed successfully." when: - not (openchami_upgrade_failed | default(false) | bool) - openchami_deployed | default(false) | bool diff --git a/upgrade/roles/upgrade_slurm/tasks/check_slurm_cluster.yml b/upgrade/roles/upgrade_slurm/tasks/check_slurm_cluster.yml index 917b2ed648..f79fab053e 100644 --- a/upgrade/roles/upgrade_slurm/tasks/check_slurm_cluster.yml +++ b/upgrade/roles/upgrade_slurm/tasks/check_slurm_cluster.yml @@ -21,6 +21,14 @@ | map(attribute='key') | first }} +- name: Remove ctld tracking file + ansible.builtin.file: + path: "{{ slurm_nfs_mounted_path }}/ctld_track" + state: absent + when: + - slurm_ctld_host is defined + - slurm_ctld_host not in (hostvars['localhost']['slurm_previously_rebooted'] | default([], true)) + - name: Check for running jobs on slurm cluster ansible.builtin.shell: cmd: | @@ -74,7 +82,7 @@ ansible.builtin.shell: cmd: | set -o pipefail - sinfo -h -N -o "%n" -t idle + sinfo -h -N -o "%n %t" | awk '$2 == "idle" {print $1}' register: sinfo_idle_nodes changed_when: false failed_when: false @@ -122,29 +130,32 @@ delegate_to: "{{ slurm_ctld_host }}" - name: Show non-idle node details and remediation steps - ansible.builtin.debug: - msg: "{{ non_idle_report }}" + ansible.builtin.pause: + prompt: "{{ non_idle_report }}" + seconds: 5 vars: - non_idle_report: - - "Pre-upgrade node state check FAILED." - - "{{ slurm_non_idle_nodes | length }} compute node(s) are NOT in idle state." - - "" - - "Non-idle nodes:" - - "{{ slurm_non_idle_nodes | join(', ') }}" - - "" - - "Current state (node / state / reason):" - - "{{ sinfo_non_idle_detail.stdout_lines | default(['(unable to retrieve)']) }}" - - "" - - "All slurm_node_* compute nodes must be idle before upgrade can proceed." - - "" - - "Remediation — run the following on '{{ slurm_ctld_host }}':" - - " 1. Cancel running jobs on affected nodes:" - - " scancel --nodelist={{ slurm_non_idle_nodes | join(',') }}" - - " 2. Drain nodes to prevent new job scheduling:" - - " scontrol update NodeName={{ slurm_non_idle_nodes | join(',') }} State=drain Reason='upgrade'" - - " 3. Wait for nodes to reach idle/drained state:" - - " watch -n5 'sinfo -N -o \"%n %T\" --nodes={{ slurm_non_idle_nodes | join(',') }}'" - - " 4. Re-run the upgrade playbook once all nodes are idle." + non_idle_report: | + ------------------------------------------------ + Pre-upgrade node state check FAILED. + ------------------------------------------------ + {{ slurm_non_idle_nodes | length }} compute node(s) are NOT in idle state. + ------------------------------------------------ + Non-idle nodes: + {{ slurm_non_idle_nodes | join(', ') }} + ------------------------------------------------ + Current state (node / state / reason): + {{ sinfo_non_idle_detail.stdout_lines | default(['(unable to retrieve)']) }} + ------------------------------------------------ + All slurm_node_* compute nodes must be idle before upgrade can proceed. + ------------------------------------------------ + Remediation — run the following on '{{ slurm_ctld_host }}': + 1. Cancel running jobs on affected nodes: + scancel --nodelist={{ slurm_non_idle_nodes | join(',') }} + 2. Drain nodes to prevent new job scheduling: + scontrol update NodeName={{ slurm_non_idle_nodes | join(',') }} State=drain Reason='upgrade' + 3. Wait for nodes to reach idle/drained state: + watch -n5 'sinfo -N -o "%n %T" --nodes={{ slurm_non_idle_nodes | join(',') }}' + 4. Re-run the upgrade playbook once all nodes are idle. - name: Abort upgrade — compute nodes not in idle state ansible.builtin.fail: diff --git a/upgrade/roles/upgrade_slurm/tasks/nfs_client.yml b/upgrade/roles/upgrade_slurm/tasks/nfs_client.yml index e3adbf03fd..cb688b9e77 100644 --- a/upgrade/roles/upgrade_slurm/tasks/nfs_client.yml +++ b/upgrade/roles/upgrade_slurm/tasks/nfs_client.yml @@ -15,7 +15,7 @@ ## Mount an entry on the OIM node. - name: Resolve mount_params profile if specified ansible.builtin.set_fact: - resolved_mount_profile: "{{ storage_config.mount_params[item.mount_params] | default({}) }}" + resolved_mount_profile: "{{ storage_config.mount_params[item.mount_params] | default({}, true) }}" when: item.mount_params is defined and item.mount_params in storage_config.mount_params - name: Initialize client mount path (new schema) diff --git a/upgrade/roles/upgrade_slurm/tasks/slurm_backup.yml b/upgrade/roles/upgrade_slurm/tasks/slurm_backup.yml index bcba44ee24..5fd7141039 100644 --- a/upgrade/roles/upgrade_slurm/tasks/slurm_backup.yml +++ b/upgrade/roles/upgrade_slurm/tasks/slurm_backup.yml @@ -48,7 +48,7 @@ - name: Include oim_metadata.yml ansible.builtin.include_vars: - file: "{{ oim_metadata }}" + file: "{{ oim_metadata_path }}" name: oim_metadata - name: Set oim_shared_path fact @@ -56,11 +56,6 @@ oim_shared_path: "{{ oim_metadata.oim_shared_path | trim }}" slurm_nfs_mounted_path: "{{ slurm_nfs[0].mount_point }}/slurm" -- name: Remove ctld tracking file - ansible.builtin.file: - path: "{{ slurm_nfs_mounted_path }}/ctld_track" - state: absent - - name: Read pxe_mapping_file from backup directory # TODO: pxe_mapping_file is an absolute path but assuming it's in project_default community.general.read_csv: @@ -137,31 +132,3 @@ ansible.builtin.fail: msg: "SLURM: MySQL datadir not found in nfs" when: not is_mysql_datadir - -- name: Create backup directory - when: backup_slurm_nfs_contents - block: - - name: Create backup directory structure - ansible.builtin.file: - path: "{{ slurm_nfs_mounted_path }}/slurm_21_nfs_backups/{{ item }}" - state: directory - owner: root - group: root - mode: '0755' - loop: - - "etc/slurm" - - "var/lib/mysql" - - - name: Backup etc/slurm directory - ansible.builtin.copy: - src: "{{ ctld_dir_nfs }}/etc/slurm/" - dest: "{{ slurm_nfs_mounted_path }}/slurm_21_nfs_backups/etc/slurm" - remote_src: true - mode: preserve - - - name: Backup var/lib/mysql directory - ansible.builtin.copy: - src: "{{ ctld_dir_nfs }}/var/lib/mysql/" - dest: "{{ slurm_nfs_mounted_path }}/slurm_21_nfs_backups/var/lib/mysql" - remote_src: true - mode: preserve diff --git a/upgrade/roles/upgrade_slurm/vars/main.yml b/upgrade/roles/upgrade_slurm/vars/main.yml index 56cda11a95..1086db92fd 100644 --- a/upgrade/roles/upgrade_slurm/vars/main.yml +++ b/upgrade/roles/upgrade_slurm/vars/main.yml @@ -16,7 +16,7 @@ mounted_dir_perm: "0755" default_client_mount_options: "nosuid,rw,sync,hard,intr" slurm_nfs_fail_msg: "Failed to mount NFS share. Please check if the NFS server is reachable or NFS is configured properly." -oim_metadata: "/opt/omnia/.data/oim_metadata.yml" +oim_metadata_path: "/opt/omnia/.data/oim_metadata.yml" backup_slurm_nfs_contents: true # To create a copy of all slurm contents on the nfs share input_project_dir: "{{ hostvars['localhost']['input_project_dir'] | default('/opt/omnia/input/project_default') }}" oim_nfs_fail_msg: "Failed to mount NFS on oim" diff --git a/upgrade/roles/upgrade_telemetry/tasks/include_required_input.yml b/upgrade/roles/upgrade_telemetry/tasks/include_required_input.yml index b90b2c69fb..ea699200b8 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/include_required_input.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/include_required_input.yml @@ -60,6 +60,7 @@ when: - omnia_config is defined - omnia_config.service_k8s_cluster is defined + - omnia_config.service_k8s_cluster | length > 0 tags: always - name: Set k8s_client_mount_path @@ -70,13 +71,22 @@ | first).mount_point }} when: - storage_config is defined + - storage_config.mounts is defined - k8s_nfs_storage_name is defined + - storage_config.mounts | selectattr('name', 'equalto', k8s_nfs_storage_name) | list | length > 0 tags: always + # ── Load high_availability_config.yml ── +- name: Check if high_availability_config.yml exists + ansible.builtin.stat: + path: "{{ input_project_dir }}/high_availability_config.yml" + register: ha_config_stat + - name: Read high_availability_config.yml for kube_vip ansible.builtin.include_vars: file: "{{ input_project_dir }}/high_availability_config.yml" name: ha_config + when: ha_config_stat.stat.exists - name: Debug high_availability_config.yml content ansible.builtin.debug: @@ -90,6 +100,7 @@ kube_vip: "{{ ha_config.service_k8s_cluster_ha[0].virtual_ip_address | default('') }}" cacheable: true when: + - ha_config is defined - ha_config.service_k8s_cluster_ha is defined - ha_config.service_k8s_cluster_ha | length > 0 @@ -112,10 +123,10 @@ ansible.builtin.set_fact: victoria_in_targets: >- {{ - telemetry_config.telemetry_sources.idrac.collection_targets | default([]) | select('search', 'victoria_metrics') | list | length > 0 - or telemetry_config.telemetry_sources.powerscale.collection_targets | default([]) | select('search', 'victoria_metrics') | list | length > 0 - or telemetry_config.telemetry_sources.vast.collection_targets | default([]) | select('search', 'victoria_metrics') | list | length > 0 - or telemetry_config.telemetry_sources.ufm.collection_targets | default([]) | select('search', 'victoria_metrics') | list | length > 0 + telemetry_config.telemetry_sources.idrac.collection_targets | default([], true) | select('search', 'victoria_metrics') | list | length > 0 + or telemetry_config.telemetry_sources.powerscale.collection_targets | default([], true) | select('search', 'victoria_metrics') | list | length > 0 + or telemetry_config.telemetry_sources.vast.collection_targets | default([], true) | select('search', 'victoria_metrics') | list | length > 0 + or telemetry_config.telemetry_sources.ufm.collection_targets | default([], true) | select('search', 'victoria_metrics') | list | length > 0 }} when: - telemetry_config is defined @@ -138,16 +149,31 @@ - name: Parse software_config.json ansible.builtin.set_fact: - software_config: "{{ software_config_slurp.content | b64decode | from_yaml }}" + software_config: "{{ software_config_slurp.content | b64decode | from_json }}" when: software_config_slurp is not failed tags: always +- name: Check if service_k8s exists in software_config.json + ansible.builtin.set_fact: + service_k8s_exists: "{{ (software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | list | length) > 0 }}" + when: + - software_config is defined + - software_config.softwares is defined + tags: always + +- name: Set service_k8s_exists to false if software_config not loaded + ansible.builtin.set_fact: + service_k8s_exists: false + when: software_config is not defined + tags: always + - name: Set architecture from software_config.json (from service_k8s arch) ansible.builtin.set_fact: architecture: "{{ (software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | map(attribute='arch') | first | first) }}" when: - software_config is defined - software_config.softwares is defined + - service_k8s_exists | default(false) | bool tags: always - name: Set os_version from software_config.json @@ -164,6 +190,7 @@ when: - software_config is defined - software_config.softwares is defined + - service_k8s_exists | default(false) | bool tags: always # ── Load service_k8s JSON for victoria operator package name ── @@ -172,12 +199,19 @@ src: "{{ input_project_dir }}/config/{{ architecture }}/rhel/{{ os_version }}/service_k8s_v{{ k8s_version }}.json" register: service_k8s_slurp failed_when: false + when: + - service_k8s_exists | default(false) | bool + - architecture is defined + - os_version is defined + - k8s_version is defined tags: always - name: Parse service_k8s JSON ansible.builtin.set_fact: - service_k8s_config: "{{ service_k8s_slurp.content | b64decode | from_yaml }}" - when: service_k8s_slurp is not failed + service_k8s_config: "{{ service_k8s_slurp.content | b64decode | from_json }}" + when: + - service_k8s_slurp is not failed + - service_k8s_slurp is not skipped tags: always - name: Extract victoria operator package name from service_k8s JSON diff --git a/upgrade/roles/upgrade_telemetry/tasks/main.yml b/upgrade/roles/upgrade_telemetry/tasks/main.yml index ee5fd1d282..68c087306c 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/main.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/main.yml @@ -54,9 +54,21 @@ # ── Phase 3: Execute telemetry.sh to redeploy telemetry stack ── - name: Phase 3 - Execute telemetry.sh to redeploy telemetry stack ansible.builtin.include_tasks: execute_telemetry_sh.yml + when: + - k8s_client_mount_path is defined + - kube_vip is defined + - kube_vip | length > 0 + +- name: Skip telemetry.sh (k8s not configured) + ansible.builtin.debug: + msg: "Skipping telemetry.sh execution — service_k8s not configured (Slurm-only deployment)." + when: k8s_client_mount_path is not defined or kube_vip is not defined # ── Phase 4: Verify all telemetry pods and set upgrade status ── - name: Phase 4 - Verify all telemetry pods and set upgrade status + when: + - kube_vip is defined + - kube_vip | length > 0 block: - name: Get all telemetry pods status ansible.builtin.shell: diff --git a/upgrade/roles/upgrade_telemetry/tasks/migrate_statefulset.yml b/upgrade/roles/upgrade_telemetry/tasks/migrate_statefulset.yml index 847ad36af4..e99d7bf80c 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/migrate_statefulset.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/migrate_statefulset.yml @@ -168,3 +168,43 @@ when: orphaned_pods.stdout_lines | default([]) | length > 0 delegate_to: "{{ kube_vip }}" connection: ssh + + # ── Cleanup old pre-operator services and deployments ── + # The operator creates new services with different names (e.g. vminsert-victoria-cluster), + # so the old standalone services become stale and waste LoadBalancer IPs. + - name: Find old pre-operator services + ansible.builtin.shell: | + set -o pipefail + kubectl -n {{ telemetry_namespace }} get svc --no-headers 2>/dev/null \ + | awk '{print $1}' \ + | grep -xE 'vminsert|vmselect|vmstorage|vmagent' || true + register: old_services + changed_when: false + failed_when: false + delegate_to: "{{ kube_vip }}" + connection: ssh + + - name: Delete old pre-operator services + ansible.builtin.command: + cmd: kubectl -n {{ telemetry_namespace }} delete svc {{ item }} --timeout=30s + loop: "{{ old_services.stdout_lines | default([]) | select() | list }}" + changed_when: true + failed_when: false + when: old_services.stdout_lines | default([]) | select() | list | length > 0 + delegate_to: "{{ kube_vip }}" + connection: ssh + + - name: Delete old vmagent deployment (replaced by operator-managed VMAgent) + ansible.builtin.shell: | + kubectl -n {{ telemetry_namespace }} get deployment {{ old_vmagent_deployment }} --no-headers 2>/dev/null && \ + kubectl -n {{ telemetry_namespace }} delete deployment {{ old_vmagent_deployment }} --timeout=60s || true + changed_when: true + failed_when: false + delegate_to: "{{ kube_vip }}" + connection: ssh + + - name: Display old resource cleanup summary + ansible.builtin.debug: + msg: + - "Old services deleted: {{ old_services.stdout_lines | default([]) | select() | list }}" + - "Old vmagent deployment cleanup attempted: {{ old_vmagent_deployment }}" diff --git a/upgrade/roles/upgrade_telemetry/tasks/patch_idrac_termination_grace_period.yml b/upgrade/roles/upgrade_telemetry/tasks/patch_idrac_termination_grace_period.yml index 6116afb37f..76755b45b9 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/patch_idrac_termination_grace_period.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/patch_idrac_termination_grace_period.yml @@ -48,7 +48,7 @@ msg: "idrac-telemetry current replica count: {{ idrac_replica_count.stdout }}" when: idrac_sts_check.rc == 0 -- name: Patch terminationGracePeriodSeconds to 120s for graceful MySQL shutdown +- name: Patch terminationGracePeriodSeconds for graceful MySQL shutdown ansible.builtin.command: cmd: > kubectl patch statefulset idrac-telemetry -n {{ telemetry_namespace }} diff --git a/upgrade/roles/upgrade_telemetry/tasks/upgrade_operator.yml b/upgrade/roles/upgrade_telemetry/tasks/upgrade_operator.yml index 4fa40ba520..40cd32336a 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/upgrade_operator.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/upgrade_operator.yml @@ -16,15 +16,29 @@ # Install / upgrade VictoriaMetrics operator via Helm # ============================================================================ +- name: Remove finalizers from VictoriaMetrics CRDs (prevents delete hang) + ansible.builtin.shell: | + set -o pipefail + for crd in $(kubectl get crd 2>/dev/null | grep victoriametrics | awk '{print $1}'); do + kubectl patch crd "$crd" --type=merge -p '{"metadata":{"finalizers":[]}}' 2>/dev/null || true + done + changed_when: false + failed_when: false + delegate_to: "{{ kube_vip }}" + connection: ssh + - name: Delete existing VictoriaMetrics CRDs (to fix Helm ownership issues) ansible.builtin.shell: | set -o pipefail - kubectl get crd | grep victoriametrics | awk '{print $1}' | xargs kubectl delete crd 2>/dev/null || true + for crd in $(kubectl get crd 2>/dev/null | grep victoriametrics | awk '{print $1}'); do + timeout 30 kubectl delete crd "$crd" --timeout=30s 2>/dev/null || true + done register: crd_delete_result changed_when: true failed_when: false delegate_to: "{{ kube_vip }}" connection: ssh + timeout: 120 - name: Install VictoriaMetrics operator from tarball ansible.builtin.command: diff --git a/upgrade/upgrade.yml b/upgrade/upgrade.yml index d0f0d40041..7d15568575 100644 --- a/upgrade/upgrade.yml +++ b/upgrade/upgrade.yml @@ -66,7 +66,7 @@ provision: [oim, build_image] k8s: [oim, provision, local_repo, build_image] telemetry: [oim, k8s] - slurm: [provision, local_repo] + slurm: [oim, local_repo, build_image, provision] tasks: # ═══════════════════════════════════════════════════════════════ # PHASE 1: READ-ONLY GUARDS (no state mutation allowed here) @@ -245,8 +245,8 @@ ansible.builtin.set_fact: requested_tags: >- {{ all_components - if (ansible_run_tags is not defined or 'all' in ansible_run_tags) - else ansible_run_tags }} + if (ansible_run_tags is not defined or 'all' in (ansible_run_tags | list)) + else ansible_run_tags | list }} - name: Validate tag dependency order ansible.builtin.fail: @@ -257,8 +257,11 @@ when: - item in tag_dependencies - tag_dependencies[item] | difference(requested_tags) | length > 0 - - tag_dependencies[item] | reject('in', (manifest.component_status | default({})) | dict2items | selectattr('value', 'equalto', 'completed') | - map(attribute='key') | list ) | list | length > 0 + - >- + tag_dependencies[item] | reject('in', + (manifest.component_status | default({}, true)) + | dict2items | selectattr('value', 'in', ['completed', 'skipped']) + | map(attribute='key') | list) | list | length > 0 - name: Report already-upgraded components (will be skipped) ansible.builtin.debug: @@ -312,7 +315,7 @@ omnia_run_tags: >- {{ ( - ansible_run_tags | default([]) + + ansible_run_tags | default([]) | list + ['build_stream', 'gitlab'] ) | unique }} @@ -357,6 +360,34 @@ GitLab pipeline manually post-upgrade. when: build_stream_terminal | bool +# ────────────────────────────────────────────────────────────────────── +# Detect K8s and Slurm configuration — check if services are enabled +# ────────────────────────────────────────────────────────────────────── +- name: Detect K8s and Slurm configuration + hosts: localhost + connection: local + gather_facts: false + tags: always + tasks: + - name: Read software_config.json + ansible.builtin.slurp: + src: "{{ input_project_dir }}/software_config.json" + register: _software_config_slurp + + - name: Parse software_config.json + ansible.builtin.set_fact: + _software_config: "{{ _software_config_slurp.content | b64decode | from_json }}" + + - name: Check if service_k8s is configured + ansible.builtin.set_fact: + k8s_upgrade_enabled: "{{ _software_config.softwares | selectattr('name', 'equalto', 'service_k8s') | list | length > 0 }}" + cacheable: true + + - name: Check if slurm_custom is configured + ansible.builtin.set_fact: + slurm_upgrade_enabled: "{{ _software_config.softwares | selectattr('name', 'equalto', 'slurm_custom') | list | length > 0 }}" + cacheable: true + # ────────────────────────────────────────────────────────────────────── # Operator Approval — shows upgrade plan and waits for confirmation. # Tracks approval_status in upgrade_manifest.yml so re-runs skip it. @@ -466,35 +497,75 @@ the new Omnia 2.2 package set 5. provision → Refresh Cloud-Init data and BSS boot configurations to point at 2.2 images - 6. k8s → Roll the Kubernetes cluster to the new - Omnia-supported version (control plane + nodes) + 6. k8s → {% if k8s_upgrade_enabled | default(false) %}Roll the Kubernetes cluster to the new + Omnia-supported version (control plane + nodes){% else %}SKIPPED (not configured in software_config.json){% endif %} + 7. telemetry → Upgrade the Omnia telemetry stack for kafka, victoria metrics, and other components - 8. slurm → Upgrade the Slurm controller, slurm nodes + 8. slurm → {% if slurm_upgrade_enabled | default(false) %}Upgrade the Slurm controller, slurm nodes + {% else %}SKIPPED (not configured in software_config.json){% endif %} ── Impact & Risk ──────────────────────────────────────────── • Running Omnia services will be modified and briefly restarted. • Do NOT reboot the OIM during the upgrade • Compute workloads should be drained or completed beforehand. - ── Pre-flight Checklist ───────────────────────────────────── - [ ] prepare_upgrade.yml completed without errors - [ ] Kubernetes cluster healthy (no failing pods, all PVCs + ── Pre-flight Checklist (REQUIRED) ────────────────────────── + BEFORE proceeding, verify ALL of the following: + + • prepare_upgrade.yml completed without errors + {% if k8s_upgrade_enabled | default(false) %}• Kubernetes cluster healthy (no failing pods, all PVCs bound, LoadBalancer services have external IPs) - [ ] Slurm cluster healthy (no failing jobs, all nodes ready) - [ ] Stable internet connectivity verified on the OIM - [ ] Maintenance window is active and stakeholders notified - [ ] Sufficient disk space available for new images & packages + {% endif %}{% if slurm_upgrade_enabled | default(false) %}• Slurm cluster healthy (no failing jobs, all nodes ready) + {% endif %}• Stable internet connectivity verified on the OIM + • Maintenance window is active and stakeholders notified + • Sufficient disk space available for new images & packages ────────────────────────────────────────────────────────────── - Press ENTER to PROCEED with the Omnia upgrade - Press Ctrl+C, A to ABORT and exit safely + CONFIRMATION REQUIRED: + Type 'yes' to confirm all pre-flight checks are complete + and PROCEED with the Omnia upgrade. + + Type anything else or press Ctrl+C to ABORT. ══════════════════════════════════════════════════════════════ + register: operator_confirmation when: - not (skip_approval | default(false) | bool) - approval_manifest.approval_status | default('pending') != 'approved' - not (build_stream_terminal | default(false) | bool) + - name: Validate operator confirmation + when: + - not (skip_approval | default(false) | bool) + - approval_manifest.approval_status | default('pending') != 'approved' + - not (build_stream_terminal | default(false) | bool) + - operator_confirmation.user_input | default('') | lower != 'yes' + block: + - name: Display abort message + ansible.builtin.pause: + seconds: 1 + prompt: |2 + ══════════════════════════════════════════════════════════════ + UPGRADE ABORTED — CONFIRMATION REQUIRED + ══════════════════════════════════════════════════════════════ + + You did not type 'yes' to confirm that all pre-flight checks + have been completed. + + To proceed with the upgrade, you MUST explicitly confirm by + typing 'yes' when prompted. + + Please re-run the upgrade playbook and type 'yes' at the + confirmation prompt: + + ansible-playbook upgrade/upgrade.yml + + ══════════════════════════════════════════════════════════════ + + - name: Fail the playbook + ansible.builtin.fail: + msg: "Upgrade aborted: operator did not confirm pre-flight checks" + - name: Update approval_status to approved in manifest ansible.builtin.copy: content: >- @@ -532,7 +603,7 @@ omnia_run_tags: >- {{ ( - ansible_run_tags | default([]) + + ansible_run_tags | default([]) | list + ['prepare_oim', 'local_repo', 'ufm_telemetry', 'vast_telemetry', 'ldms', 'idrac_telemetry'] ) | unique }} @@ -631,8 +702,8 @@ ansible.builtin.set_fact: finalize_requested_tags: >- {{ all_components - if (ansible_run_tags is not defined or 'all' in ansible_run_tags) - else ansible_run_tags | intersect(all_components) }} + if (ansible_run_tags is not defined or 'all' in (ansible_run_tags | list)) + else ansible_run_tags | list | intersect(all_components) }} - name: Build cleaned component_status (only update requested tags) ansible.builtin.set_fact: diff --git a/utils/ansible.cfg b/utils/ansible.cfg index c2472ef518..2aec0b37f9 100644 --- a/utils/ansible.cfg +++ b/utils/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../common/library/modules module_utils = ../common/library/module_utils diff --git a/utils/credential_utility/ansible.cfg b/utils/credential_utility/ansible.cfg index 3b339cbaf5..505802ff42 100644 --- a/utils/credential_utility/ansible.cfg +++ b/utils/credential_utility/ansible.cfg @@ -5,6 +5,7 @@ host_key_checking = false forks = 5 timeout = 180 executable = /bin/bash +interpreter_python = /usr/bin/python3 library = ../../common/library/modules module_utils = ../../common/library/module_utils diff --git a/utils/credential_utility/roles/create_config/templates/omnia_credential.j2 b/utils/credential_utility/roles/create_config/templates/omnia_credential.j2 index d9ffd938b4..f1ae1091f6 100644 --- a/utils/credential_utility/roles/create_config/templates/omnia_credential.j2 +++ b/utils/credential_utility/roles/create_config/templates/omnia_credential.j2 @@ -58,3 +58,7 @@ ome_password: "" # UFM telemetry credentials ufm_username: "" ufm_password: "" + +# VAST telemetry credentials +vast_username: "" +vast_password: "" diff --git a/utils/credential_utility/roles/update_config/tasks/credential_status.yml b/utils/credential_utility/roles/update_config/tasks/credential_status.yml index af2568f4df..d56e6b761e 100644 --- a/utils/credential_utility/roles/update_config/tasks/credential_status.yml +++ b/utils/credential_utility/roles/update_config/tasks/credential_status.yml @@ -34,18 +34,18 @@ ( ((field.file is not defined or field.file != credential_files[1].file_path) and - (vars[field.username] is not defined or - vars[field.username] == "" or - (vars[field.username] | length == 0)) and + (lookup('vars', field.username, default='') is not defined or + lookup('vars', field.username, default='') == "" or + (lookup('vars', field.username, default='') | length == 0)) and (mandatory_credentials_status or conditional_mandatory_credentials_status or optional_credentials_status)) or ((field.file is defined and field.file == credential_files[1].file_path) and - (vars['build_stream_auth_username'] is not defined or - vars['build_stream_auth_username'] == "" or - (vars['build_stream_auth_username'] | length == 0))) + (lookup('vars', 'build_stream_auth_username', default='') is not defined or + lookup('vars', 'build_stream_auth_username', default='') == "" or + (lookup('vars', 'build_stream_auth_username', default='') | length == 0))) ) }} @@ -62,9 +62,9 @@ ( ((field.file is not defined or field.file != credential_files[1].file_path) and - (vars[field.password] is not defined or - vars[field.password] == "" or - (vars[field.password] | length == 0)) and + (lookup('vars', field.password, default='') is not defined or + lookup('vars', field.password, default='') == "" or + (lookup('vars', field.password, default='') | length == 0)) and ( (mandatory_credentials_status | default(false) | bool or conditional_mandatory_credentials_status | @@ -72,15 +72,15 @@ or (optional_credentials_status | default(false) | bool and field.username is defined and - ((vars[field.username] is defined and - vars[field.username] != "") or + ((lookup('vars', field.username, default='') is defined and + lookup('vars', field.username, default='') != "") or (username_status | default(false) | bool))))) or ((field.file is defined and field.file == credential_files[1].file_path) and - (vars['build_stream_auth_password_hash'] is not defined or - vars['build_stream_auth_password_hash'] == "" or - (vars['build_stream_auth_password_hash'] | length == 0))) + (lookup('vars', 'build_stream_auth_password_hash', default='') is not defined or + lookup('vars', 'build_stream_auth_password_hash', default='') == "" or + (lookup('vars', 'build_stream_auth_password_hash', default='') | length == 0))) ) }} @@ -94,8 +94,8 @@ - field.username is defined - optional_credentials_status | default(false) | bool - username_status | default(false) | bool - - vars[field.username] is not defined or - vars[field.username] == "" + - lookup('vars', field.username, default='') is not defined or + lookup('vars', field.username, default='') == "" # Reset credential status after processing - name: Reset credentials status diff --git a/utils/credential_utility/roles/update_config/tasks/update_bs_credential_file.yml b/utils/credential_utility/roles/update_config/tasks/update_bs_credential_file.yml index b01cdfb9fd..898f7189a3 100644 --- a/utils/credential_utility/roles/update_config/tasks/update_bs_credential_file.yml +++ b/utils/credential_utility/roles/update_config/tasks/update_bs_credential_file.yml @@ -27,7 +27,7 @@ - name: Use existing username when username not updated ansible.builtin.set_fact: - build_stream_auth_username: "{{ vars['build_stream_auth_username'] | default('') }}" + build_stream_auth_username: "{{ lookup('vars', 'build_stream_auth_username', default='') }}" no_log: true when: not username_status | default(false) @@ -43,7 +43,7 @@ - name: Use existing password when password not updated ansible.builtin.set_fact: - build_stream_auth_password: "{{ vars['build_stream_auth_password'] | default('') }}" + build_stream_auth_password: "{{ lookup('vars', 'build_stream_auth_password', default='') }}" no_log: true when: not password_status | default(false) @@ -76,7 +76,7 @@ - name: Use existing password hash when password not updated ansible.builtin.set_fact: - build_stream_auth_password_hash: "{{ vars['build_stream_auth_password_hash'] | default('') }}" + build_stream_auth_password_hash: "{{ lookup('vars', 'build_stream_auth_password_hash', default='') }}" no_log: true when: not password_status | default(false) or password_hash is not defined or password_hash is not succeeded diff --git a/utils/credential_utility/roles/update_config/vars/main.yml b/utils/credential_utility/roles/update_config/vars/main.yml index c035b0ec06..76ca81a79d 100644 --- a/utils/credential_utility/roles/update_config/vars/main.yml +++ b/utils/credential_utility/roles/update_config/vars/main.yml @@ -100,8 +100,12 @@ omnia_credentials: idrac_telemetry: mandatory: - { username: bmc_username, password: bmc_password } - - { username: mysqldb_user, password: mysqldb_password } - - { password: mysqldb_root_password } + conditional_mandatory: + - username: mysqldb_user + password: mysqldb_password + condition: "{{ idrac_telemetry_support | default(false) | bool }}" + - password: mysqldb_root_password + condition: "{{ idrac_telemetry_support | default(false) | bool }}" csi_driver_powerscale: conditional_mandatory: - username: csi_username diff --git a/utils/credential_utility/roles/validation/tasks/main.yml b/utils/credential_utility/roles/validation/tasks/main.yml index 63929bcaf3..223126008d 100644 --- a/utils/credential_utility/roles/validation/tasks/main.yml +++ b/utils/credential_utility/roles/validation/tasks/main.yml @@ -15,7 +15,7 @@ - name: Initialize list of tags ansible.builtin.set_fact: - omnia_run_tags: "{{ ansible_run_tags | default([]) }}" + omnia_run_tags: "{{ ansible_run_tags | default([]) | list }}" when: omnia_run_tags is not defined - name: Load build_stream_config.yml to check if enabled diff --git a/utils/credential_utility/roles/validation/tasks/pre_requisite.yml b/utils/credential_utility/roles/validation/tasks/pre_requisite.yml index 572dd5f79a..af1418305d 100644 --- a/utils/credential_utility/roles/validation/tasks/pre_requisite.yml +++ b/utils/credential_utility/roles/validation/tasks/pre_requisite.yml @@ -44,11 +44,27 @@ - name: Set run tags for telemetry ansible.builtin.set_fact: - omnia_run_tags: "{{ (omnia_run_tags | default([])) + (result.telemetry_status_list | default([])) | unique }}" + omnia_run_tags: "{{ ((omnia_run_tags | default([])) + (result.telemetry_status_list | default([]))) | unique }}" when: - not result.skipped | default(false) - result.telemetry_status_list | length > 0 +- name: Derive iDRAC telemetry support flag from telemetry_config.yml + when: "'idrac_telemetry' in (omnia_run_tags | default([]))" + block: + - name: Load telemetry_config.yml for iDRAC support flag + ansible.builtin.include_vars: + file: "{{ telemetry_config_path }}" + name: _telemetry_config + failed_when: false + + - name: Set idrac_telemetry_support flag + ansible.builtin.set_fact: + idrac_telemetry_support: >- + {{ ((_telemetry_config.telemetry_sources | default({})).idrac | default({})).metrics_enabled + | default(_telemetry_config.idrac_telemetry_support | default(false)) | bool }} + when: _telemetry_config is defined + - name: Derive UFM telemetry support flag from telemetry_config.yml when: "'ufm_telemetry' in (omnia_run_tags | default([]))" block: diff --git a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_k8s.yml b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_k8s.yml index 279d053830..c6905ea917 100644 --- a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_k8s.yml +++ b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_k8s.yml @@ -18,9 +18,9 @@ ansible.builtin.include_vars: file: "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config.yml" -- name: Set k8s NFS storage name +- name: Get k8s NFS storage names from all clusters ansible.builtin.set_fact: - k8s_nfs_storage_name: "{{ service_k8s_cluster[0].nfs_storage_name }}" + k8s_nfs_storage_names: "{{ service_k8s_cluster | map(attribute='nfs_storage_name') | list | default([]) }}" when: - service_k8s_cluster is defined - service_k8s_cluster | length > 0 @@ -28,64 +28,73 @@ - name: Fail if k8s cluster not configured ansible.builtin.fail: msg: "K8s cluster not configured in omnia_config.yml. Please configure service_k8s_cluster first." - when: k8s_nfs_storage_name is not defined + when: k8s_nfs_storage_names is not defined or k8s_nfs_storage_names | length == 0 -- name: Check if k8s mount exists in storage_config +- name: Find all k8s storage mounts ansible.builtin.set_fact: - k8s_mount_found: >- - {{ mounts | selectattr('name', 'equalto', k8s_nfs_storage_name) | list | length > 0 }} + k8s_storage_mounts: "{{ mounts | selectattr('name', 'in', k8s_nfs_storage_names) | list }}" -- name: Skip k8s cleanup if mount not configured +- name: Skip k8s cleanup if no mounts found ansible.builtin.debug: msg: > - K8s NFS mount '{{ k8s_nfs_storage_name }}' not found in storage_config.yml. + K8s NFS mounts {{ k8s_nfs_storage_names }} not found in storage_config.yml. Skipping k8s cleanup. If you want to clean k8s directories, please configure - the mount for '{{ k8s_nfs_storage_name }}' in storage_config.yml. - when: not k8s_mount_found - -- name: Set k8s base path from detected mount - ansible.builtin.set_fact: - k8s_base_path: "{{ (mounts | selectattr('name', 'equalto', k8s_nfs_storage_name) | first).mount_point }}" - when: k8s_mount_found + the mounts in storage_config.yml. + when: k8s_storage_mounts | length == 0 - name: K8s cleanup tasks - when: k8s_mount_found + when: k8s_storage_mounts | length > 0 block: - - name: Display detected k8s base path - ansible.builtin.debug: - msg: "K8s cleanup using mount: {{ k8s_base_path }} (storage name: {{ k8s_nfs_storage_name }})" + - name: Build cleanup paths for all storage mounts + ansible.builtin.set_fact: + all_k8s_base_paths: [] + + - name: Build cleanup paths for each storage mount + ansible.builtin.set_fact: + all_k8s_base_paths: "{{ all_k8s_base_paths + [item.mount_point] }}" + loop: "{{ k8s_storage_mounts }}" + loop_control: + label: "{{ item.name }}" - - name: Build k8s cleanup paths from variable list + - name: Build k8s cleanup paths from variable list for all mounts ansible.builtin.set_fact: - k8s_static_cleanup_paths: [] + all_k8s_static_cleanup_paths: [] - - name: Build cleanup paths using loop + - name: Build cleanup paths using loop for all mounts ansible.builtin.set_fact: - k8s_static_cleanup_paths: "{{ k8s_static_cleanup_paths + [k8s_base_path + '/' + item] }}" - loop: "{{ k8s_cleanup_directories }}" + all_k8s_static_cleanup_paths: "{{ all_k8s_static_cleanup_paths + [path_item[0] + '/' + path_item[1]] }}" + loop: "{{ all_k8s_base_paths | product(k8s_cleanup_directories) | list }}" + loop_control: + loop_var: path_item - name: Check if static k8s directories exist ansible.builtin.stat: path: "{{ item }}" register: k8s_static_dirs_stat - loop: "{{ k8s_static_cleanup_paths }}" + loop: "{{ all_k8s_static_cleanup_paths }}" - - name: Find node IP directories when enabled + - name: Find node IP directories when enabled for all mounts when: k8s_cleanup_node_ips | default(false) block: - - name: Find all directories in k8s base path + - name: Find all directories in all k8s base paths ansible.builtin.find: - paths: "{{ k8s_base_path }}" + paths: "{{ item }}" file_type: directory register: k8s_all_dirs + loop: "{{ all_k8s_base_paths }}" - - name: Filter IP-named directories using basename + - name: Combine all found directories + ansible.builtin.set_fact: + k8s_all_found_dirs: "{{ k8s_all_dirs.results | map(attribute='files') | list | flatten }}" + + - name: Filter IP-named directories using basename for all mounts ansible.builtin.set_fact: k8s_ip_dirs: >- - {{ k8s_all_dirs.files - | selectattr('path', 'match', k8s_base_path + '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+') + {{ k8s_all_found_dirs + | selectattr('path', 'match', item + '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+') | map(attribute='path') | list }} + loop: "{{ all_k8s_base_paths }}" - name: Set empty IP dirs list when disabled ansible.builtin.set_fact: @@ -112,29 +121,40 @@ - name: Display k8s cleanup information ansible.builtin.debug: msg: | - WARNING: This will delete K8s-related directories from NFS share: - Base path: {{ k8s_base_path }} + WARNING: This will delete K8s-related directories from NFS shares: + {% for mount in k8s_storage_mounts %} + Storage: {{ mount.name }} ({{ mount.mount_point }}) {% for item in k8s_static_dirs_stat.results %} - {% if item.stat.exists %} + {% if item.stat.exists and item.item.startswith(mount.mount_point) %} - {{ item.item }} ({{ item.item | basename }}) {% endif %} {% endfor %} {% if k8s_cleanup_node_ips | default(false) %} Node IP directories: {% for item in k8s_ip_dirs %} + {% if item.startswith(mount.mount_point) %} - {{ item }} ({{ item | basename }}) + {% endif %} {% else %} - No IP directories found {% endfor %} {% else %} Node IP directories: Skipped (k8s_cleanup_node_ips: false) {% endif %} + {% endfor %} + + CRITICAL WARNING: Deleting NFS shared data will affect ALL nodes! + - Ensure K8s services are stopped on all nodes + - Ensure nodes are not accessing these directories + - This may cause stale file handles on running nodes + - Only proceed if you understand the impact on your cluster + This action is destructive and cannot be undone. when: k8s_cleanup_needed | default(false) - name: Prompt for k8s cleanup confirmation ansible.builtin.pause: - prompt: "This will delete K8s-related directories. Type {{ k8s_cleanup_confirm_token }} to continue" + prompt: "I understand this will delete NFS data affecting all nodes. Type {{ k8s_cleanup_confirm_token }} to continue" register: k8s_cleanup_confirm - name: Fail if cleanup not confirmed @@ -142,57 +162,27 @@ msg: "K8s cleanup aborted" when: k8s_cleanup_confirm.user_input | lower != k8s_cleanup_confirm_token | lower - - name: Delete static k8s directories - ansible.builtin.file: - path: "{{ item.item }}" - state: absent - register: k8s_static_cleanup_result - when: - - k8s_cleanup_needed | default(false) - - item.stat.exists - loop: "{{ k8s_static_dirs_stat.results }}" - - - name: Delete node IP directories + - name: Delete all k8s directories ansible.builtin.file: path: "{{ item }}" state: absent - register: k8s_ip_cleanup_result - when: - - k8s_cleanup_needed | default(false) - - k8s_cleanup_node_ips | default(false) - loop: "{{ k8s_ip_dirs }}" + register: k8s_cleanup_result + when: k8s_cleanup_needed | default(false) + loop: "{{ k8s_all_cleanup_paths }}" - name: Display k8s cleanup completion message ansible.builtin.debug: msg: | K8s-related cleanup completed. - Base path: {{ k8s_base_path }} - {% if k8s_static_cleanup_result.results is defined %} - Static directories: - {% for item in k8s_static_cleanup_result.results %} - {% if item is defined and item.changed %} - ✅ Deleted: {{ item.item }} - {% elif item is defined and not item.changed %} - ℹ️ Already absent: {{ item.item }} - {% endif %} + {% for mount in k8s_storage_mounts %} + Storage: {{ mount.name }} ({{ mount.mount_point }}) + {% set mount_deleted = k8s_cleanup_result.results | selectattr('item', 'search', '^' + mount.mount_point) | selectattr('changed') | list %} + {% if mount_deleted %} + {% for item in mount_deleted %} + -> Deleted: {{ item.item }} {% endfor %} {% else %} - Static directories: None deleted - {% endif %} - {% if k8s_cleanup_node_ips | default(false) %} - {% if k8s_ip_cleanup_result.results is defined %} - Node IP directories: - {% for item in k8s_ip_cleanup_result.results %} - {% if item is defined and item.changed %} - ✅ Deleted: {{ item.item }} - {% elif item is defined and not item.changed %} - ℹ️ Already absent: {{ item.item }} + -> No directories deleted from this storage {% endif %} {% endfor %} - {% else %} - Node IP directories: None deleted - {% endif %} - {% else %} - Node IP directories: Skipped - {% endif %} when: k8s_cleanup_needed | default(false) diff --git a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_omnia_postgres.yml b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_omnia_postgres.yml index 8faaf7dd37..6a76f45bed 100644 --- a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_omnia_postgres.yml +++ b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_omnia_postgres.yml @@ -16,10 +16,72 @@ ansible.builtin.set_fact: postgres_backup: "{{ postgres_backup | default(true) }}" +- name: Set postgres_user from hostvars or default to admin + ansible.builtin.set_fact: + postgres_user: "{{ hostvars['localhost']['postgres_user'] | default('admin') }}" + - name: Display cleanup mode ansible.builtin.debug: msg: "{{ postgres_cleanup_mode_msg }}" +- name: Mark all image_groups as CLEANED before stopping Postgres + block: + - name: Check if omnia_postgres container is running + containers.podman.podman_container_info: + name: "{{ postgres_container_name }}" + register: pg_pre_check + failed_when: false + + - name: Check if image_groups table exists in build_stream_db + ansible.builtin.command: + cmd: >- + podman exec {{ postgres_container_name }} + psql -U {{ postgres_user }} -d build_stream_db -tAc + "SELECT EXISTS (SELECT 1 FROM pg_tables WHERE tablename = 'image_groups');" + register: image_groups_table_check + changed_when: false + failed_when: false + when: + - pg_pre_check.containers | default([]) | length > 0 + - pg_pre_check.containers[0].State.Running | default(false) + + - name: Count non-CLEANED image_groups records + ansible.builtin.command: + cmd: >- + podman exec {{ postgres_container_name }} + psql -U {{ postgres_user }} -d build_stream_db -tAc + "SELECT COUNT(*) FROM image_groups WHERE status != 'CLEANED';" + register: non_cleaned_count + changed_when: false + failed_when: false + when: + - image_groups_table_check is not skipped + - image_groups_table_check.stdout | default('') | trim == 't' + + - name: Update all non-CLEANED image_groups to CLEANED + ansible.builtin.command: + cmd: >- + podman exec {{ postgres_container_name }} + psql -U {{ postgres_user }} -d build_stream_db -c + "UPDATE image_groups SET status = 'CLEANED', updated_at = NOW() + WHERE status != 'CLEANED';" + register: image_groups_update + changed_when: image_groups_update.rc == 0 + when: + - non_cleaned_count is not skipped + - (non_cleaned_count.stdout | default('0') | trim | int) > 0 + + - name: Display image_groups cleanup result + ansible.builtin.debug: + msg: "{{ image_groups_cleaned_msg }}" + when: + - image_groups_update is not skipped + - image_groups_update.rc | default(1) == 0 + rescue: + - name: Log image_groups cleanup failure + ansible.builtin.debug: + msg: "{{ image_groups_cleanup_failure_msg }}" + - name: Reload systemd daemon ansible.builtin.systemd: daemon_reload: true diff --git a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_slurm.yml b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_slurm.yml index c208965329..4cc76a93b8 100644 --- a/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_slurm.yml +++ b/utils/roles/oim_cleanup/oim_container_cleanup/tasks/cleanup_slurm.yml @@ -14,25 +14,101 @@ --- -- name: Check if slurm mount exists in storage_config +- name: Read omnia_config for slurm cluster configuration + ansible.builtin.include_vars: + file: "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config.yml" + +- name: Fail if slurm cluster not configured + ansible.builtin.fail: + msg: "Slurm cluster not configured in omnia_config.yml. Please configure slurm_cluster first." + when: slurm_cluster is not defined or slurm_cluster | length == 0 + +- name: Build cleanup storage list for each cluster + ansible.builtin.set_fact: + cleanup_storage_list: [] + +- name: Determine storage mounts to clean for each cluster + ansible.builtin.set_fact: + cleanup_storage_list: >- + {{ cleanup_storage_list + [ + { + 'cluster_name': cluster_item.cluster_name, + 'nfs_storage': cluster_item.nfs_storage_name, + 'vast_storage': cluster_item.vast_storage_name | default(cluster_item.nfs_storage_name), + 'nfs_mount_point': (mounts | selectattr('name', 'equalto', cluster_item.nfs_storage_name) + | first | default({})).mount_point, + 'vast_mount_point': (mounts | selectattr('name', 'equalto', + cluster_item.vast_storage_name | default(cluster_item.nfs_storage_name)) + | first | default({})).mount_point, + 'has_separate_vast': cluster_item.vast_storage_name is defined + and cluster_item.vast_storage_name + and cluster_item.vast_storage_name != cluster_item.nfs_storage_name + } + ] }} + loop: "{{ slurm_cluster }}" + loop_control: + loop_var: cluster_item + +- name: Build unique storage mount entries for cleanup ansible.builtin.set_fact: - slurm_mount_found: >- - {{ mounts | selectattr('name', 'equalto', 'nfs_slurm') | list | length > 0 }} + unique_storage_mounts: [] -- name: Skip slurm cleanup if mount not configured +- name: Collect unique storage mounts with directory types + ansible.builtin.set_fact: + unique_storage_mounts: >- + {{ unique_storage_mounts + [ + { + 'mount_point': item.nfs_mount_point, + 'storage_name': item.nfs_storage, + 'dir_type': 'nfs', + 'directories': ['slurm', 'ctld_track', 'openldap', 'slurm_backups'] + + (['apps', 'scratch', 'projects', 'slurm/hpc_tools'] + if not item.has_separate_vast else []) + } + ] if item.nfs_mount_point not in unique_storage_mounts + | map(attribute='mount_point') | list else unique_storage_mounts }} + loop: "{{ cleanup_storage_list }}" + loop_control: + label: "{{ item.cluster_name }}" + +- name: Add separate VAST storage mounts + ansible.builtin.set_fact: + unique_storage_mounts: >- + {{ unique_storage_mounts + [ + { + 'mount_point': item.vast_mount_point, + 'storage_name': item.vast_storage, + 'dir_type': 'vast', + 'directories': ['apps', 'scratch', 'projects', 'slurm/hpc_tools'] + } + ] if item.has_separate_vast and item.vast_mount_point not in unique_storage_mounts | map(attribute='mount_point') | list else unique_storage_mounts }} + loop: "{{ cleanup_storage_list }}" + loop_control: + label: "{{ item.cluster_name }}" + +- name: Skip slurm cleanup if no mounts found ansible.builtin.debug: msg: > - Slurm NFS mount 'nfs_slurm' not found in storage_config.yml. + Slurm storage mounts not found in storage_config.yml. Skipping slurm cleanup. If you want to clean slurm directories, please configure - the mount for 'nfs_slurm' in storage_config.yml. - when: not slurm_mount_found + the storage mounts in storage_config.yml. + when: unique_storage_mounts | length == 0 - name: Slurm cleanup tasks - when: slurm_mount_found + when: unique_storage_mounts | length > 0 block: - - name: Set slurm cleanup paths + - name: Build all cleanup paths + ansible.builtin.set_fact: + all_cleanup_paths: [] + + - name: Build cleanup paths for each storage mount ansible.builtin.set_fact: - slurm_cleanup_path: "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/slurm" + all_cleanup_paths: >- + {{ all_cleanup_paths + (storage_item.directories | map('regex_replace', '^', storage_item.mount_point + '/') | list) }} + loop: "{{ unique_storage_mounts }}" + loop_control: + loop_var: storage_item + label: "{{ storage_item.storage_name }}" - name: Check if any slurm-related directories exist ansible.builtin.stat: @@ -40,10 +116,7 @@ register: slurm_dirs_stat failed_when: false ignore_errors: true - loop: - - "{{ slurm_cleanup_path }}" - - "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/ctld_track" - - "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/openldap" + loop: "{{ all_cleanup_paths }}" - name: Set cleanup needed flag ansible.builtin.set_fact: @@ -57,185 +130,31 @@ - name: Display slurm cleanup information ansible.builtin.debug: msg: | - WARNING: This will delete Slurm-related directories from NFS share: - - {{ slurm_cleanup_path }} (Slurm configuration) - - {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/ctld_track (Controller tracking) - - {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/openldap (OpenLDAP) - PRESERVED: {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/slurm_backups (Backups) - This action is destructive and cannot be easily undone. + WARNING: This will delete Slurm-related directories from NFS shares: + {% for storage in unique_storage_mounts %} + Storage: {{ storage.storage_name }} ({{ storage.mount_point }}) + Type: {{ storage.dir_type | upper }} + {% for dir in storage.directories %} + - {{ storage.mount_point }}/{{ dir }}{% if dir == 'slurm_backups' %} (PRESERVED - will not be deleted){% endif %} + {% endfor %} + {% endfor %} + + CRITICAL WARNING: Deleting NFS shared data will affect ALL nodes! + - Ensure Slurm services are stopped on all compute nodes + - Ensure compute nodes are not accessing these directories + - This may cause stale file handles on running nodes + - Only proceed if you understand the impact on your cluster + + Note: slurm_backups directories will be preserved. + If you need Slurm configuration backup, use the separate utility: + ansible-playbook utils/slurm_config_util.yml --tags config_backup + + This action is destructive and cannot be undone. when: cleanup_needed | default(false) - - name: Prompt for pre-cleanup backup - ansible.builtin.pause: - prompt: "Before cleanup, take a Slurm config backup? (y/n)" - register: pre_cleanup_backup - - - name: Set pre-cleanup backup choice - ansible.builtin.set_fact: - pre_cleanup_backup_choice: "{{ pre_cleanup_backup.user_input | default('') | trim | lower }}" - - - name: Fail if pre-cleanup backup choice is empty - ansible.builtin.fail: - msg: "No input provided for pre-cleanup backup prompt. Slurm cleanup aborted." - when: pre_cleanup_backup_choice | length == 0 - - - name: Validate pre-cleanup backup choice - ansible.builtin.fail: - msg: "Invalid input '{{ pre_cleanup_backup.user_input | default('') }}'. Enter 'y' or 'n'." - when: pre_cleanup_backup_choice not in ['y', 'yes', 'n', 'no'] - - - name: Normalize backup choice to boolean - ansible.builtin.set_fact: - backup_choice_bool: "{{ pre_cleanup_backup_choice in ['y', 'yes'] }}" - - - name: Set slurm backup variables - ansible.builtin.set_fact: - share_path: "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}" - slurm_share_dir_name: slurm - slurm_backups_dir_name: slurm_backups - when: backup_choice_bool | default(false) - - - name: Read omnia_config for slurm_cluster - ansible.builtin.include_vars: - file: "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config.yml" - when: backup_choice_bool | default(false) - - - name: Set slurm cluster facts - ansible.builtin.set_fact: - nfs_storage_name: "{{ slurm_cluster[0].nfs_storage_name }}" - when: - - backup_choice_bool | default(false) - - slurm_cluster is defined - - slurm_cluster | length > 0 - - - name: Check if nodes.yaml exists - ansible.builtin.stat: - path: "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/workdir/nodes/nodes.yaml" - register: nodes_yaml_stat - when: backup_choice_bool | default(false) - - - name: Warn if nodes.yaml not found and skip backup - ansible.builtin.debug: - msg: > - WARNING: nodes.yaml not found at - {{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/workdir/nodes/nodes.yaml. - Skipping backup and proceeding with cleanup only. - when: - - backup_choice_bool | default(false) - - not nodes_yaml_stat.stat.exists - - - name: Set backup skipped flag - ansible.builtin.set_fact: - backup_skipped: true - when: - - backup_choice_bool | default(false) - - not nodes_yaml_stat.stat.exists - - - name: Slurp nodes.yaml - ansible.builtin.slurp: - src: "{{ hostvars['localhost']['oim_shared_path'] }}/omnia/openchami/workdir/nodes/nodes.yaml" - register: slurped_yaml - when: - - backup_choice_bool | default(false) - - nodes_yaml_stat.stat.exists - - - name: Parse nodes.yaml - ansible.builtin.set_fact: - node_yaml: "{{ slurped_yaml.content | b64decode | from_yaml }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Get node IP mapping - ansible.builtin.set_fact: - tmp_ip_name_map: "{{ node_yaml.nodes | items2dict(key_name='name', value_name='interfaces') }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Create IP name map - ansible.builtin.set_fact: - ip_name_map: "{{ ip_name_map | default({}) | combine({item.key: item.value[0]['ip_addrs'][0]['ip_addr']}) }}" - loop: "{{ tmp_ip_name_map | dict2items }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Get node group mapping - ansible.builtin.set_fact: - name_group_map: "{{ node_yaml.nodes | items2dict(key_name='name', value_name='group') }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Group functional groups - ansible.builtin.set_fact: - tmp_grouped_nodes: "{{ name_group_map | dict2items | groupby('value') }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Reorganize groups - ansible.builtin.set_fact: - grouped_nodes: "{{ grouped_nodes | default({}) | combine({item[0]: ((item[1] | items2dict).keys() | list)}) }}" - loop: "{{ tmp_grouped_nodes }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Set ctld_list - ansible.builtin.set_fact: - ctld_list: "{{ grouped_nodes | dict2items - | selectattr('key', 'match', '^' ~ 'slurm_control_node_') - | map(attribute='value') | list | flatten }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Set controller IP - ansible.builtin.set_fact: - controller_ip: "{{ ip_name_map[ctld_list | first] }}" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - ctld_list is defined - - ctld_list | length > 0 - - - name: Add slurm controller as dynamic host - ansible.builtin.add_host: - name: slurm_controller - ansible_host: "{{ controller_ip }}" - ansible_user: root - ansible_port: 22 - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - controller_ip is defined - - - name: Run slurm config backup before cleanup - ansible.builtin.include_role: - name: slurm_config_backup - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Display backup completion message - ansible.builtin.debug: - msg: "Slurm configuration backup completed. You can restore using: ansible-playbook utils/slurm_config_util.yml --tags config_rollback" - when: - - backup_choice_bool | default(false) - - backup_skipped is not defined - - - name: Display backup skipped message - ansible.builtin.debug: - msg: "Slurm configuration backup was skipped due to missing nodes.yaml. Cleanup will proceed without backup." - when: - - backup_choice_bool | default(false) - - backup_skipped is defined - - name: Prompt for slurm cleanup confirmation ansible.builtin.pause: - prompt: "This will delete Slurm-related directories (slurm, ctld_track, openldap). Type {{ slurm_cleanup_confirm_token }} to continue" + prompt: "I understand this will delete NFS data affecting all nodes. Type {{ slurm_cleanup_confirm_token }} to continue" register: cleanup_confirm - name: Fail if cleanup not confirmed @@ -243,74 +162,41 @@ msg: "Slurm cleanup aborted" when: cleanup_confirm.user_input | lower != slurm_cleanup_confirm_token | lower - - name: Delete slurm configuration directory + - name: Delete slurm directories (excluding slurm_backups) ansible.builtin.file: - path: "{{ slurm_cleanup_path }}" + path: "{{ item.item }}" state: absent register: slurm_cleanup_result ignore_errors: true when: - cleanup_needed | default(false) - - slurm_dirs_stat.results[0].stat is defined - - slurm_dirs_stat.results[0].stat.exists - - - name: Set related directories to clean - ansible.builtin.set_fact: - related_dirs: - - "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/ctld_track" - - "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/openldap" - when: cleanup_needed | default(false) - - - name: Delete ctld_track directory - ansible.builtin.file: - path: "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/ctld_track" - state: absent - register: ctld_track_cleanup_result - ignore_errors: true - when: - - cleanup_needed | default(false) - - slurm_dirs_stat.results[1].stat is defined - - slurm_dirs_stat.results[1].stat.exists - - - name: Delete openldap directory - ansible.builtin.file: - path: "{{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/openldap" - state: absent - register: openldap_cleanup_result - ignore_errors: true - when: - - cleanup_needed | default(false) - - slurm_dirs_stat.results[2].stat is defined - - slurm_dirs_stat.results[2].stat.exists + - item.stat is defined + - item.stat.exists + - not item.item | regex_search('slurm_backups$') + loop: "{{ slurm_dirs_stat.results }}" + loop_control: + label: "{{ item.item }}" - name: Display slurm cleanup completion message ansible.builtin.debug: msg: | Slurm-related cleanup completed. - {% if slurm_cleanup_result is defined and slurm_cleanup_result.changed %} - -> Slurm configuration directory deleted: {{ slurm_cleanup_path }} - {% elif slurm_cleanup_result is defined %} - -> Slurm configuration directory already absent: {{ slurm_cleanup_path }} - {% endif %} - {% if ctld_track_cleanup_result is defined and ctld_track_cleanup_result.changed %} - -> Controller tracking directory deleted: {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/ctld_track - {% elif ctld_track_cleanup_result is defined %} - -> Controller tracking directory already absent - {% endif %} - {% if openldap_cleanup_result is defined and openldap_cleanup_result.changed %} - -> OpenLDAP directory deleted: {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/openldap - {% elif openldap_cleanup_result is defined %} - -> OpenLDAP directory already absent - {% endif %} - -> Slurm backups preserved at: {{ (mounts | selectattr('name', 'equalto', 'nfs_slurm') | first).mount_point }}/slurm_backups - {% if backup_choice_bool | default(false) %} - {% if backup_skipped is defined %} - -> Backup was skipped due to missing nodes.yaml. - {% else %} - -> Backup was created using slurm_config_backup role. - To restore, use: ansible-playbook utils/slurm_config_util.yml --tags config_rollback - {% endif %} - {% else %} - -> No backup was created. This action cannot be undone. + {% for storage in unique_storage_mounts %} + Storage: {{ storage.storage_name }} ({{ storage.mount_point }}) + Type: {{ storage.dir_type | upper }} + {% for dir in storage.directories %} + {% set full_path = storage.mount_point + '/' + dir %} + {% set dir_deleted = slurm_cleanup_result.results | selectattr('item', 'equalto', full_path) + | selectattr('changed') | list %} + {% set dir_exists = slurm_cleanup_result.results | selectattr('item', 'equalto', full_path) + | selectattr('stat', 'defined') | selectattr('stat.exists') | list %} + {% if dir == 'slurm_backups' %} + -> Preserved: {{ full_path }} + {% elif dir_deleted %} + -> Deleted: {{ full_path }} + {% elif dir_exists %} + -> Already absent: {{ full_path }} {% endif %} + {% endfor %} + {% endfor %} when: cleanup_needed | default(false) diff --git a/utils/roles/oim_cleanup/oim_container_cleanup/vars/main.yml b/utils/roles/oim_cleanup/oim_container_cleanup/vars/main.yml index 75bc2e3e5d..28dd327351 100644 --- a/utils/roles/oim_cleanup/oim_container_cleanup/vars/main.yml +++ b/utils/roles/oim_cleanup/oim_container_cleanup/vars/main.yml @@ -182,6 +182,16 @@ postgres_cleanup_directory: - "{{ omnia_nfs_share }}/postgres" postgres_container_name: omnia_postgres + +# Usage: cleanup_omnia_postgres.yml (image_groups DB update) +image_groups_cleaned_msg: >- + BuildStream image_groups: All records updated to CLEANED status. + S3 images were already removed during OpenCHAMI cleanup. + Database is now consistent for backup. +image_groups_cleanup_failure_msg: >- + WARNING: Failed to update image_groups status to CLEANED in build_stream_db. + If postgres_backup is enabled, the backed-up database may contain stale image_groups records. + This does not affect the cleanup process. Proceeding with Postgres container removal. postgres_cleanup_mode_msg: "Postgres cleanup mode: {{ 'PRESERVE data (postgres_backup=true)' if postgres_backup | bool else 'DELETE data (postgres_backup=false)' }}" postgres_preserved_msg: "PRESERVED: Postgres data directories retained (postgres_backup=true): {{ postgres_cleanup_directory }}" @@ -196,21 +206,23 @@ oim_cleanup_note: | [Post-Cleanup Actions Required] 1. Reboot the OIM node after running oim_cleanup.yml. - 2. The playbook now removes Slurm-related directories from NFS share: + 2. The playbook removes Slurm-related directories from NFS shares: - slurm (Slurm configuration) - ctld_track (Controller tracking) - openldap (OpenLDAP) + - apps (Applications) + - projects (Projects) + - scratch (Scratch space) - PRESERVED: slurm_backups (Backup directory) - - Slurm configuration backup is offered before cleanup (recommended to accept). + - Supports multi-storage: Cleans directories from all Slurm storage mounts configured in omnia_config.yml + - For Slurm configuration backup, use the separate utility: ansible-playbook utils/slurm_config_util.yml --tags config_backup - To skip slurm cleanup, run: ansible-playbook utils/oim_cleanup.yml --skip-tags slurm - - Backup uses existing slurm_config_backup role (same as slurm_config_util.yml) - - To restore slurm configs from backup, use: ansible-playbook utils/slurm_config_util.yml --tags config_rollback - 3. The playbook now removes K8s-related directories from NFS share: + 3. The playbook removes K8s-related directories from NFS shares: - ssh, calico, metallb, helm, packages, telemetry, karavi-observability, csi-driver-powerscale, nfs-client-provisioner - Node IP directories (when k8s_cleanup_node_ips: true) - - PRESERVED: slurm, ctld_track, openldap, slurm_backups (Slurm directories) - Directory list is configurable via k8s_cleanup_directories variable in vars/main.yml + - Supports multi-storage: Cleans directories from all K8s storage mounts configured in omnia_config.yml - To skip k8s cleanup, run: ansible-playbook utils/oim_cleanup.yml --skip-tags k8s - No backup is created for k8s directories (directory deletion only) diff --git a/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml b/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml index de03349b77..889a6f7208 100644 --- a/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml +++ b/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml @@ -18,6 +18,53 @@ register: include_metadata no_log: true +- name: Include omnia_config_credentials.yml for postgres_user + block: + - name: Check if credentials file exists + ansible.builtin.stat: + path: "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config_credentials.yml" + register: credentials_file_status + + - name: Load credentials if file exists + when: credentials_file_status.stat.exists + block: + - name: Check if credentials file is encrypted + ansible.builtin.command: head -1 "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config_credentials.yml" + changed_when: false + register: credentials_file_content + no_log: true + + - name: Decrypt credentials if encrypted + ansible.builtin.command: >- + ansible-vault decrypt "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config_credentials.yml" + --vault-password-file "{{ hostvars['localhost']['input_project_dir'] }}/.omnia_config_credentials_key" + changed_when: false + when: "'$ANSIBLE_VAULT' in credentials_file_content.stdout" + no_log: true + + - name: Include credentials + ansible.builtin.include_vars: "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config_credentials.yml" + no_log: true + + - name: Set postgres_user as a fact for all hosts + ansible.builtin.set_fact: + postgres_user: "{{ postgres_user | default('admin') }}" + delegate_to: localhost + delegate_facts: true + + - name: Re-encrypt credentials if it was encrypted + ansible.builtin.command: >- + ansible-vault encrypt "{{ hostvars['localhost']['input_project_dir'] }}/omnia_config_credentials.yml" + --vault-password-file "{{ hostvars['localhost']['input_project_dir'] }}/.omnia_config_credentials_key" + changed_when: false + when: "'$ANSIBLE_VAULT' in credentials_file_content.stdout" + no_log: true + rescue: + - name: Set default postgres_user if credentials not available + ansible.builtin.set_fact: + postgres_user: "admin" + no_log: true + - name: Load software_config.json as software_config block: - name: Load software_config.json as user_config diff --git a/utils/set_pxe_boot.yml b/utils/set_pxe_boot.yml index fba614a5da..bad598b0e7 100644 --- a/utils/set_pxe_boot.yml +++ b/utils/set_pxe_boot.yml @@ -39,7 +39,7 @@ - name: Set dynamic run tags including 'provision' when: not config_file_status | default(false) | bool ansible.builtin.set_fact: - omnia_run_tags: "{{ (ansible_run_tags | default([]) + ['provision']) | unique }}" + omnia_run_tags: "{{ (ansible_run_tags | default([]) | list + ['provision']) | unique }}" cacheable: true - name: Invoke get_config_credentials.yml