Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
cdc944e
Merge pull request #4605 from abhishek-sa1/pub/q2_ansible
abhishek-sa1 May 30, 2026
ef32c83
Merge pull request #4609 from dell/pub/q2_upgrade
abhishek-sa1 May 30, 2026
48dc462
Merge pull request #4616 from dell/pub/q2_upgrade
abhishek-sa1 Jun 1, 2026
923c43b
Add catalog generator documentation.
Venu-p1 Jun 1, 2026
39bae76
Merge pull request #4626 from dell/pub/q2_upgrade
abhishek-sa1 Jun 1, 2026
7e300f3
Merge branch 'q2_ansible_sync' into q2_upgrade_sync
abhishek-sa1 Jun 2, 2026
8f29320
Merge pull request #72 from abhishek-sa1/q2_upgrade_sync
abhishek-sa1 Jun 2, 2026
990220d
ansible 2.20 fixes
abhishek-sa1 Jun 2, 2026
f9e0d8c
lint update
abhishek-sa1 Jun 2, 2026
d38fe7c
Merge pull request #4646 from abhishek-sa1/q2_ansible_sync
abhishek-sa1 Jun 3, 2026
5082514
Merge pull request #4654 from dell/pub/q2_upgrade
abhishek-sa1 Jun 3, 2026
0b20c0c
ib ip port matching enhanced logic
Nagachandan-P Jun 3, 2026
bd60099
Update software_utils.py
abhishek-sa1 Jun 3, 2026
e0c2d97
Merge pull request #4662 from abhishek-sa1/pub/q2_ansible
snarthan Jun 3, 2026
38ecac9
Merge pull request #4658 from dell/pub/q2_ansible
abhishek-sa1 Jun 4, 2026
40f2605
Merge pull request #4621 from Venu-p1/dev/catalog-gen-readme
abhishek-sa1 Jun 4, 2026
51f8e71
Update configure-ib-network.sh.j2
Nagachandan-P Jun 4, 2026
c22280f
Merge pull request #4659 from Nagachandan-P/pub/q2_upgrade
snarthan Jun 4, 2026
47b6149
Fix for upgarde is failing in localrepo when omnia_config_credential.…
pullan1 Jun 4, 2026
bff9ad2
Fixing ansible 2.20 issues in upgrade and rollback flow (#4673)
abhishek-sa1 Jun 4, 2026
765f0ce
Slurm ansible 2.20 fix
abhishek-sa1 Jun 4, 2026
7f4e422
Merge pull request #4674 from pullan1/pub/q2_upgrade
snarthan Jun 4, 2026
8b5bf18
Simplify ID format to use package name only (version stripped) instea…
Venu-p1 Jun 4, 2026
4b3405b
Fix the incorrect pipeline status in Gitlab (#4676)
Rajeshkumar-s2 Jun 4, 2026
629e9de
ansible 2.20 fix
abhishek-sa1 Jun 4, 2026
6bc4318
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
abhishek-sa1 Jun 4, 2026
a1f8d7a
Merge pull request #4675 from abhishek-sa1/pub/q2_upgrade
abhishek-sa1 Jun 4, 2026
e544179
omnia.sh ssh fix and openchami upgrade optimization (#4679)
mithileshreddy04 Jun 4, 2026
99a070e
Oim_metadata stale variable from provision, hence renaming
jagadeeshnv Jun 4, 2026
d66d4fb
Oim cleanup slurm entry gate
jagadeeshnv Jun 4, 2026
640a841
Merge pull request #4680 from jagadeeshnv/pub/q2_upgrade
jagadeeshnv Jun 4, 2026
9f6c844
Kubernetes Upgrade/Rollback Improvements and Kubelet Configuration Co…
Katakam-Rakesh Jun 4, 2026
08f3f26
fix(openchami): use coresmd rule-level subnet keys for multi-subnet P…
sujit-jadhav Jun 5, 2026
b4f8d25
Rollback summary formatting fixes (#4683)
mithileshreddy04 Jun 5, 2026
9051775
Update check_slurm_cluster.yml
Nagachandan-P Jun 5, 2026
b10ed1d
Update omnia.sh (#4684)
mithileshreddy04 Jun 5, 2026
c679902
fix(dns): propagate dns_enabled to OIM and configure resolv.conf for …
sujit-jadhav Jun 4, 2026
0bdd71b
fix(dns): namespace include_vars to prevent variable collision with m…
Jun 5, 2026
cb4089e
Revert "fix(dns): namespace include_vars to prevent variable collisio…
Jun 5, 2026
1bd3332
Revert "fix(dns): propagate dns_enabled to OIM and configure resolv.c…
Jun 5, 2026
5472535
Update regctl path in build image flow and update input validation lo…
abhishek-sa1 Jun 5, 2026
4d227ac
VAST support retained after pre upgrade
jagadeeshnv Jun 5, 2026
ded516d
Update cleanup_stale_volume_attachments.yml
Katakam-Rakesh Jun 5, 2026
3f89828
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
Katakam-Rakesh Jun 5, 2026
e323bcb
Merge pull request #4686 from Nagachandan-P/pub/q2_upgrade
jagadeeshnv Jun 5, 2026
f99b9bf
Merge pull request #4687 from jagadeeshnv/pub/q2_upgrade
jagadeeshnv Jun 5, 2026
8726c69
Merge pull request #4688 from Katakam-Rakesh/pub/q2_upgrade
Katakam-Rakesh Jun 5, 2026
392839f
Input file upgrade template fixes
mithileshreddy04 Jun 5, 2026
6fb344b
fix(dns): propagate dns_enabled to OIM and configure resolv.conf for …
sujit-jadhav Jun 5, 2026
71c1384
Update omnia_config.j2
mithileshreddy04 Jun 5, 2026
68a1183
Merge pull request #4689 from mithileshreddy04/pub/q2_upgrade_transfo…
Katakam-Rakesh Jun 5, 2026
a498c7d
Update slurm_backup.yml
jagadeeshnv Jun 5, 2026
7898915
Update main.yml
jagadeeshnv Jun 5, 2026
126d961
Merge pull request #4693 from jagadeeshnv/pub/q2_upgrade
Katakam-Rakesh Jun 5, 2026
c240b49
Remove duplicate NFS cleanup prompt and duplicate credential utility …
Venu-p1 Jun 5, 2026
69ceb7c
kernel version update support (#4692)
abhishek-sa1 Jun 6, 2026
0cbfd24
Enhance K8s upgrade/rollback with validation and cleanup improvements…
Katakam-Rakesh Jun 6, 2026
3ad89bf
Update get_powerscale_telemetry_dependencies.yml (#4696)
balajikumaran-c-s Jun 6, 2026
1f1f881
Fix DNF5 compatibility issues in local_repo RPM downloads (#4695)
balajikumaran-c-s Jun 6, 2026
06b96a8
kernel version update check (#4697)
abhishek-sa1 Jun 6, 2026
2341847
Fix: Cloud-Init runcmd YAML parsing errors on aarch64 templates (#4699)
balajikumaran-c-s Jun 8, 2026
3f73926
Fix: Multiple Ansible 2.14+ compatibility issues after upgrade (#4698)
balajikumaran-c-s Jun 8, 2026
64b0a76
fix(openchami): resolve missing service units in multi-subnet deploym…
sujit-jadhav Jun 8, 2026
71b899f
localrepo checkmarx fixes (#4703)
pullan1 Jun 8, 2026
c24c64e
Update etcd-disk-setup.sh.j2
Katakam-Rakesh Jun 8, 2026
7210917
Update etcd-fstab-update.sh.j2
Katakam-Rakesh Jun 8, 2026
690ee6b
Backup permission issue fix and recheck for rollback openchami
mithileshreddy04 Jun 8, 2026
88deba9
input validation for ldms and vector (#4704)
Kratika-P Jun 8, 2026
10a9b96
kernel 10.2 fix
abhishek-sa1 Jun 8, 2026
97724c5
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
abhishek-sa1 Jun 8, 2026
5e7348f
checkmarx fixes (#4706)
pullan1 Jun 8, 2026
71e6592
remove duplicate kernel check
abhishek-sa1 Jun 8, 2026
0797f45
Update validate_image.yml
abhishek-sa1 Jun 8, 2026
31bbead
Update ci-group-service_kube_control_plane_first_x86_64.yaml.j2
Katakam-Rakesh Jun 8, 2026
bcc60ca
Update ci-group-service_kube_control_plane_x86_64.yaml.j2
Katakam-Rakesh Jun 8, 2026
6874303
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
Katakam-Rakesh Jun 8, 2026
33dc6a8
Updating default storage size for idrac telemetry containers (#4702)
priti-parate Jun 8, 2026
b4c70f5
fix: prevent telemetry pods from getting stuck in ContainerCreating s…
balajikumaran-c-s Jun 8, 2026
a77e94f
Update install_cuda_driver.sh.j2
Katakam-Rakesh Jun 8, 2026
609bc6d
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
Katakam-Rakesh Jun 8, 2026
d20165a
Update version for cuda aarch
jagadeeshnv Jun 8, 2026
3c0e0c7
Cuda for aarch version install_cuda_driver.sh.j2
jagadeeshnv Jun 8, 2026
51362ab
Update install_cuda_driver.sh.j2
jagadeeshnv Jun 8, 2026
c845c83
Update update_kcm_arguments.yml
Katakam-Rakesh Jun 8, 2026
87d8ccd
vast metrics relabeling fix (#4712)
pullan1 Jun 8, 2026
8f42123
Merge pull request #4710 from Katakam-Rakesh/pub/q2_upgrade
snarthan Jun 8, 2026
1d1515d
Update validate_image.yml
abhishek-sa1 Jun 8, 2026
958493c
Kernel 10.2 provisioning support (#4707)
abhishek-sa1 Jun 8, 2026
26b5cdc
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
abhishek-sa1 Jun 8, 2026
61acdb6
local repo fix
abhishek-sa1 Jun 8, 2026
cce6b6b
Merge pull request #4705 from mithileshreddy04/pub/rollback_permissio…
Katakam-Rakesh Jun 8, 2026
8a3da7f
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
abhishek-sa1 Jun 8, 2026
631c5d8
pip fix
abhishek-sa1 Jun 8, 2026
a2322be
pip3 package installation fix post python3.13 upgrade (#4713)
abhishek-sa1 Jun 8, 2026
5de6d24
multi-ib ib ip supported
Nagachandan-P Jun 9, 2026
708d9fa
fix(discovery): prompt for OME credentials when not available (OMN01D…
sujit-jadhav Jun 9, 2026
2df7643
Merge branch 'dell:pub/q2_upgrade' into pub/q2_upgrade
abhishek-sa1 Jun 9, 2026
05de523
pulp fix
abhishek-sa1 Jun 9, 2026
b5dd8b4
Update configure-ib-network.sh.j2
Nagachandan-P Jun 9, 2026
8c2bb92
Merge pull request #4714 from Nagachandan-P/pub/q2_upgrade
snarthan Jun 9, 2026
16ad488
Merge pull request #4715 from dell/fix/OMN01D-2517-discovery-credenti…
snarthan Jun 9, 2026
54fd1e0
disable warning and failures in ansible.cfg
abhishek-sa1 Jun 9, 2026
c55f984
Merge pull request #4716 from abhishek-sa1/pub/q2_upgrade
snarthan Jun 9, 2026
803d269
Update reload_cloud_init_data.yml
mithileshreddy04 Jun 9, 2026
e62cb87
Merge pull request #4718 from mithileshreddy04/pub/q2_openchami_upgrade
Katakam-Rakesh Jun 9, 2026
380d152
fix(provision): fix invalid YAML in cloud-init template when dns_enab…
sujit-jadhav Jun 9, 2026
7966c5c
updating the comments (#4722)
Kratika-P Jun 9, 2026
03fda46
postgres backup idempotency fix (#4721)
mithileshreddy04 Jun 9, 2026
eb2497a
Fixed reading of build_stream_terminal
jagadeeshnv Jun 9, 2026
5987bed
Merge branch 'pub/q2_upgrade' into pub/q2_upgrade
jagadeeshnv Jun 9, 2026
8547467
Update main.yml
jagadeeshnv Jun 9, 2026
20dcf6a
Merge pull request #4711 from jagadeeshnv/pub/q2_upgrade
jagadeeshnv Jun 10, 2026
92f14aa
Ansible 2.20 fixes (#4717)
pullan1 Jun 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ansible-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- pub/q2_dev
- pub/telemetry
- pub/q2_upgrade
- pub/q2_ansible

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ on:
- pub/q2_dev
- pub/telemetry
- pub/q2_upgrade
- pub/q2_ansible

jobs:
build:
Expand Down
5 changes: 3 additions & 2 deletions ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ forks = 5
timeout = 180
executable = /bin/bash
display_skipped_hosts = false
library = discovery/library:common/library/modules
#inventory = /opt/omnia/omnia_inventory/cluster_layout
deprecation_warnings = false
show_task_path_on_failure = false
library = common/library/modules
module_utils = common/library/module_utils

[persistent_connection]
Expand Down
3 changes: 3 additions & 0 deletions build_image_aarch64/ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ host_key_checking = false
forks = 5
timeout = 180
executable = /bin/bash
interpreter_python = /usr/bin/python3
deprecation_warnings = false
show_task_path_on_failure = false
library = ../common/library/modules
module_utils = ../common/library/module_utils

Expand Down
2 changes: 1 addition & 1 deletion build_image_aarch64/build_image_aarch64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

- name: Verify the aarch64 base osimage in registry
ansible.builtin.command:
cmd: "regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
delegate_to: "{{ aarch64_build_host }}"
connection: ssh
changed_when: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@

- name: Verify aarch64 compute osimages in registry
ansible.builtin.command:
cmd: "regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
delegate_to: "{{ aarch64_build_host }}"
connection: ssh
changed_when: false
Expand Down
3 changes: 3 additions & 0 deletions build_image_x86_64/ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ host_key_checking = false
forks = 5
timeout = 180
executable = /bin/bash
interpreter_python = /usr/bin/python3
deprecation_warnings = false
show_task_path_on_failure = false
library = ../common/library/modules
module_utils = ../common/library/module_utils

Expand Down
2 changes: 1 addition & 1 deletion build_image_x86_64/build_image_x86_64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@

- name: Verify the x86_64 base osimage in registry
ansible.builtin.command:
cmd: "regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
changed_when: false
register: verify_base_osimage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@

- name: Verify x86_64 compute osimages in registry
ansible.builtin.command:
cmd: "regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
cmd: "/usr/local/bin/regctl repo ls {{ oim_node_name }}.{{ domain_name }}:5000"
changed_when: false
register: verify_compute_osimages

Expand Down
106 changes: 106 additions & 0 deletions build_stream/core/catalog/CATALOG_GENERATOR.md
Original file line number Diff line number Diff line change
@@ -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 <path>`: Write a human-readable table report to the given file
- `--pxe-mapping <path>`: Path to PXE mapping CSV file for information display
- `--catalog <path>`: Path to catalog file for information display

**What it does:**
1. Compares `software_config.json` (softwares list and versions)
2. Walks `config/<arch>/<os>/<ver>/*.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
84 changes: 84 additions & 0 deletions build_stream/core/catalog/tests/test_generate_catalog_id.py
Original file line number Diff line number Diff line change
@@ -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()
50 changes: 28 additions & 22 deletions build_stream/generate_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion build_stream/requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion build_stream/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions common/library/module_utils/discovery/standard_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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)
Loading
Loading