From ee2b08e2faca16f43f913b36156aa0a2852ccd46 Mon Sep 17 00:00:00 2001 From: pullan1 Date: Mon, 15 Jun 2026 14:18:19 +0530 Subject: [PATCH 1/9] support rhel_subscription_repo_config_ precedence logic(rhel eus) Signed-off-by: pullan1 --- .../schema/local_repo_config.json | 166 +----------------- input/local_repo_config.yml | 32 ++-- .../tasks/configure_rhel_os_urls.yml | 40 +++-- 3 files changed, 44 insertions(+), 194 deletions(-) diff --git a/common/library/module_utils/input_validation/schema/local_repo_config.json b/common/library/module_utils/input_validation/schema/local_repo_config.json index 587851d0b3..a89c648105 100644 --- a/common/library/module_utils/input_validation/schema/local_repo_config.json +++ b/common/library/module_utils/input_validation/schema/local_repo_config.json @@ -1190,91 +1190,10 @@ }, "required": [ "url", - "gpgkey", "name" - ], - "allOf": [ - { - "if": { - "required": [ - "sslcacert" - ], - "properties": { - "sslcacert": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslclientkey", - "sslclientcert" - ], - "properties": { - "sslclientkey": { - "minLength": 1 - }, - "sslclientcert": { - "minLength": 1 - } - } - } - }, - { - "if": { - "required": [ - "sslclientkey" - ], - "properties": { - "sslclientkey": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslcacert", - "sslclientcert" - ], - "properties": { - "sslcacert": { - "minLength": 1 - }, - "sslclientcert": { - "minLength": 1 - } - } - } - }, - { - "if": { - "required": [ - "sslclientcert" - ], - "properties": { - "sslclientcert": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslcacert", - "sslclientkey" - ], - "properties": { - "sslcacert": { - "minLength": 1 - }, - "sslclientkey": { - "minLength": 1 - } - } - } - } ] }, - "description": "Optional configuration for overriding policy and caching settings for RHEL subscription-based repositories on x86_64 architecture." + "description": "Optional configuration for overriding policy and caching settings for RHEL subscription-based repositories on x86_64 architecture. Only url and name are required. Certificates are auto-populated from subscription defaults if not provided." }, "rhel_subscription_repo_config_aarch64": { "type": [ @@ -1329,91 +1248,10 @@ }, "required": [ "url", - "gpgkey", "name" - ], - "allOf": [ - { - "if": { - "required": [ - "sslcacert" - ], - "properties": { - "sslcacert": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslclientkey", - "sslclientcert" - ], - "properties": { - "sslclientkey": { - "minLength": 1 - }, - "sslclientcert": { - "minLength": 1 - } - } - } - }, - { - "if": { - "required": [ - "sslclientkey" - ], - "properties": { - "sslclientkey": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslcacert", - "sslclientcert" - ], - "properties": { - "sslcacert": { - "minLength": 1 - }, - "sslclientcert": { - "minLength": 1 - } - } - } - }, - { - "if": { - "required": [ - "sslclientcert" - ], - "properties": { - "sslclientcert": { - "minLength": 1 - } - } - }, - "then": { - "required": [ - "sslcacert", - "sslclientkey" - ], - "properties": { - "sslcacert": { - "minLength": 1 - }, - "sslclientkey": { - "minLength": 1 - } - } - } - } ] }, - "description": "Optional configuration for overriding policy and caching settings for RHEL subscription-based repositories on aarch64 architecture." + "description": "Optional configuration for overriding policy and caching settings for RHEL subscription-based repositories on aarch64 architecture. Only url and name are required. Certificates are auto-populated from subscription defaults if not provided." } }, "required": [ diff --git a/input/local_repo_config.yml b/input/local_repo_config.yml index 52f32d4cb3..24dc5847c3 100644 --- a/input/local_repo_config.yml +++ b/input/local_repo_config.yml @@ -84,26 +84,26 @@ # # 6. rhel_subscription_repo_config_x86_64 #------------------------------------------- -# Optional configuration for overriding policy and caching settings for RHEL -# subscription-based repositories on x86_64 architecture. -# When subscription is enabled, this config takes precedence over dynamically -# generated URLs for matching repositories and adds any additional repositories. +# Optional configuration for overriding RHEL subscription-based repositories +# on x86_64 architecture. +# When subscription is enabled, user-provided repos with names matching base repos +# (baseos, appstream, codeready-builder) will have their URL overridden. +# Non-matching repositories are added as additional repos. # Fields: # url : Base URL of the repository (REQUIRED) -# gpgkey : GPG key URL (REQUIRED, can be empty to disable gpgcheck) # name : Repository name for matching (REQUIRED) +# Use 'baseos', 'appstream', or 'codeready-builder' to override base repo URLs +# gpgkey : GPG key URL (OPTIONAL, defaults to empty to disable gpgcheck) # policy : Repository sync policy. Allowed values: always, partial (OPTIONAL) # If not provided, uses repo_config from software_config.json # caching : Enable or disable local caching. Allowed values: true, false (OPTIONAL) # If not provided, defaults to true -# sslcacert : Path to SSL CA certificate (optional) -# sslclientkey: Path to SSL client key (optional) -# sslclientcert: Path to SSL client certificate (optional) # Notes: -# - Do not use Jinja variables in this configuration. -# - Omit SSL fields entirely if SSL is not in use. -# - Matching is done by repository name (e.g., appstream) -# - Non-matching repositories are added as additional repos +# - Only 'url' and 'name' are required fields +# - SSL certificates are ALWAYS auto-populated from RHEL subscription defaults +# - User cannot override SSL certificates (sslcacert, sslclientkey, sslclientcert) +# - Matching is done by repository name (e.g., baseos, appstream, codeready-builder) +# - Non-matching repositories are added as additional repos with subscription certs # # 7. rhel_subscription_repo_config_aarch64 #-------------------------------------------- @@ -176,8 +176,12 @@ rhel_os_url_x86_64: rhel_os_url_aarch64: # Example: # rhel_subscription_repo_config_x86_64: -# - { url: "https://example.com/appstream", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "appstream", policy: "always", caching: true } -# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/supplementary/os/", gpgkey: "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "supplementary", policy: "always", caching: false } +# # Override baseos with EUS URL (only url and name required, certs auto-populated) +# - { url: "https://cdn.redhat.com/content/eus/rhel10/10.0/x86_64/baseos/os/", name: "baseos" } +# # Override appstream with custom URL and policy +# - { url: "https://cdn.redhat.com/content/eus/rhel10/10.0/x86_64/appstream/os/", name: "appstream", policy: "always" } +# # Add supplementary repo (non-base repo, certs auto-populated) +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/supplementary/os/", name: "supplementary", policy: "always", caching: false } rhel_subscription_repo_config_x86_64: rhel_subscription_repo_config_aarch64: # Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. 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 d4a83e6d81..114942ec65 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 @@ -133,18 +133,22 @@ ansible.builtin.set_fact: x86_64_dynamic_names: "{{ sub_rhel_x86_64_urls | map(attribute='name') | list }}" - - name: Apply x86_64 overrides to matching repos + - name: Apply x86_64 overrides to matching repos (only URL overridden, certs always from defaults) ansible.builtin.set_fact: sub_rhel_x86_64_urls: >- {%- set result = [] -%} {%- for repo in sub_rhel_x86_64_urls -%} {%- set override = (sub_x86_64_override_config | selectattr('name', 'equalto', repo.name) | first | default({})) -%} - {%- set updated_repo = repo | combine({ - 'policy': override.policy | default(repo.policy), - 'caching': override.caching | default(repo.caching), - 'url': override.url | default(repo.url), - 'gpgkey': override.gpgkey | default(repo.gpgkey) - }) -%} + {%- if override -%} + {%- set updated_repo = repo | combine({ + 'url': override.url | default(repo.url), + 'gpgkey': override.gpgkey | default(repo.gpgkey), + 'policy': override.policy | default(repo.policy), + 'caching': override.caching | default(repo.caching) + }) -%} + {%- else -%} + {%- set updated_repo = repo -%} + {%- endif -%} {%- set _ = result.append(updated_repo) -%} {%- endfor -%} {{ result }} @@ -156,7 +160,7 @@ sub_x86_64_override_config | rejectattr('name', 'in', x86_64_dynamic_names) | list }} - - name: Add non-matching x86_64 override repos as additional + - name: Add non-matching x86_64 override repos as additional (certs always from defaults) ansible.builtin.set_fact: sub_rhel_x86_64_urls: >- {%- set result = sub_rhel_x86_64_urls -%} @@ -175,18 +179,22 @@ {%- endfor -%} {{ result }} - - name: Apply aarch64 overrides to matching repos + - name: Apply aarch64 overrides to matching repos (only URL overridden, certs always from defaults) ansible.builtin.set_fact: sub_rhel_aarch64_urls: >- {%- set result = [] -%} {%- for repo in sub_rhel_aarch64_urls -%} {%- set override = (sub_aarch64_override_config | selectattr('name', 'equalto', repo.name) | first | default({})) -%} - {%- set updated_repo = repo | combine({ - 'policy': override.policy | default(repo.policy), - 'caching': override.caching | default(repo.caching), - 'url': override.url | default(repo.url), - 'gpgkey': override.gpgkey | default(repo.gpgkey) - }) -%} + {%- if override -%} + {%- set updated_repo = repo | combine({ + 'url': override.url | default(repo.url), + 'gpgkey': override.gpgkey | default(repo.gpgkey), + 'policy': override.policy | default(repo.policy), + 'caching': override.caching | default(repo.caching) + }) -%} + {%- else -%} + {%- set updated_repo = repo -%} + {%- endif -%} {%- set _ = result.append(updated_repo) -%} {%- endfor -%} {{ result }} @@ -204,7 +212,7 @@ }} when: "'aarch64' in archs" - - name: Add non-matching aarch64 override repos as additional + - name: Add non-matching aarch64 override repos as additional (certs always from defaults) ansible.builtin.set_fact: sub_rhel_aarch64_urls: >- {%- set result = sub_rhel_aarch64_urls -%} From ffc3bf1c8f2ac7ac040548ef2c7455aa4f969a3c Mon Sep 17 00:00:00 2001 From: Rajeshkumar-s2 Date: Tue, 16 Jun 2026 11:51:32 +0530 Subject: [PATCH 2/9] Merge pull request #4757 from Rajeshkumar-s2/pub/q2_upgrade Fix the source artifacts path of software_config.json --- build_stream/orchestrator/upload/use_cases/upload_files.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build_stream/orchestrator/upload/use_cases/upload_files.py b/build_stream/orchestrator/upload/use_cases/upload_files.py index 75554b46e5..6ddd9d86df 100644 --- a/build_stream/orchestrator/upload/use_cases/upload_files.py +++ b/build_stream/orchestrator/upload/use_cases/upload_files.py @@ -225,7 +225,6 @@ def _validate_all_files(self, files: List[tuple]): """Validate all files before processing (fail-fast). Args: - files: List of (filename, content) tuples. Raises: InvalidFilenameError: If any filename is invalid. @@ -600,7 +599,7 @@ def _copy_software_config_from_artifacts(self, job_id: str) -> None: try: config = load_config() artifacts_base = Path(config.file_store.base_path) - source = artifacts_base / job_id / "software_config.json" + source = artifacts_base / job_id / "input" / "software_config.json" if not source.exists(): log_secure_info( From 6475c06a3f2cef22d6bc84c6d4e10f19718c8031 Mon Sep 17 00:00:00 2001 From: pullan1 Date: Tue, 16 Jun 2026 12:27:36 +0530 Subject: [PATCH 3/9] Modifed to take rhel eus baseurls as default with subscription enabled Signed-off-by: pullan1 --- input/local_repo_config.yml | 6 ++-- .../tasks/check_rhel_subscription.yml | 28 ++++++++++++---- .../templates/local_repo_config.j2 | 32 +++++++++++-------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/input/local_repo_config.yml b/input/local_repo_config.yml index 24dc5847c3..571c2947dd 100644 --- a/input/local_repo_config.yml +++ b/input/local_repo_config.yml @@ -176,10 +176,10 @@ rhel_os_url_x86_64: rhel_os_url_aarch64: # Example: # rhel_subscription_repo_config_x86_64: -# # Override baseos with EUS URL (only url and name required, certs auto-populated) -# - { url: "https://cdn.redhat.com/content/eus/rhel10/10.0/x86_64/baseos/os/", name: "baseos" } +# # Override baseos with standard URL (only url and name required, certs auto-populated) +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/baseos/os/", name: "baseos" } # # Override appstream with custom URL and policy -# - { url: "https://cdn.redhat.com/content/eus/rhel10/10.0/x86_64/appstream/os/", name: "appstream", policy: "always" } +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/appstream/os/", name: "appstream", policy: "always" } # # Add supplementary repo (non-base repo, certs auto-populated) # - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/supplementary/os/", name: "supplementary", policy: "always", caching: false } rhel_subscription_repo_config_x86_64: diff --git a/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml b/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml index 09ad929f51..5b32ab6ac9 100644 --- a/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml +++ b/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml @@ -123,23 +123,37 @@ changed_when: true failed_when: false - - name: Extract only RHEL baseurls (appstream, baseos, codeready-builder) + - name: Extract EUS baseurls (appstream, baseos, codeready-builder) ansible.builtin.shell: | set -o pipefail - awk -v ver="{{ rhel_version }}" ' + awk ' /^\[/ {section=$0} - /^baseurl/ && section ~ /(rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-rpms)/ { - gsub(/\$releasever/, ver, $3) + /^baseurl/ && section ~ /(rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-eus-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-eus-rpms)/ { + gsub(/\$releasever/, "{{ hostvars['localhost']['cluster_os_version'] }}", $3) print $3 } ' {{ redhat_repo_file }} - register: repo_baseurls + register: eus_baseurls changed_when: false + failed_when: false + - name: Extract standard baseurls if EUS not found + ansible.builtin.shell: | + set -o pipefail + awk ' + /^\[/ {section=$0} + /^baseurl/ && section ~ /(rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-rpms)/ { + gsub(/\$releasever/, "{{ hostvars['localhost']['cluster_os_version'] }}", $3) + print $3 + } + ' {{ redhat_repo_file }} + register: standard_baseurls + changed_when: false + when: eus_baseurls.stdout_lines | default([]) | length == 0 - - name: Set fact repo baseurls with trailing slash + - name: Set fact repo baseurls (EUS preferred, fallback to standard) ansible.builtin.set_fact: - repo_baseurls: "{{ repo_baseurls.stdout_lines + repo_baseurls: "{{ (eus_baseurls.stdout_lines if (eus_baseurls.stdout_lines | default([]) | length > 0) else standard_baseurls.stdout_lines | default([])) | map('regex_replace', '([^/])$', '\\1/') | list }}" 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 d7752615b8..e94c06db8a 100644 --- a/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 +++ b/upgrade/roles/import_input_parameters/templates/local_repo_config.j2 @@ -84,26 +84,26 @@ # # 6. rhel_subscription_repo_config_x86_64 #------------------------------------------- -# Optional configuration for overriding policy and caching settings for RHEL -# subscription-based repositories on x86_64 architecture. -# When subscription is enabled, this config takes precedence over dynamically -# generated URLs for matching repositories and adds any additional repositories. +# Optional configuration for overriding RHEL subscription-based repositories +# on x86_64 architecture. +# When subscription is enabled, user-provided repos with names matching base repos +# (baseos, appstream, codeready-builder) will have their URL overridden. +# Non-matching repositories are added as additional repos. # Fields: # url : Base URL of the repository (REQUIRED) -# gpgkey : GPG key URL (REQUIRED, can be empty to disable gpgcheck) # name : Repository name for matching (REQUIRED) +# Use 'baseos', 'appstream', or 'codeready-builder' to override base repo URLs +# gpgkey : GPG key URL (OPTIONAL, defaults to empty to disable gpgcheck) # policy : Repository sync policy. Allowed values: always, partial (OPTIONAL) # If not provided, uses repo_config from software_config.json # caching : Enable or disable local caching. Allowed values: true, false (OPTIONAL) # If not provided, defaults to true -# sslcacert : Path to SSL CA certificate (optional) -# sslclientkey: Path to SSL client key (optional) -# sslclientcert: Path to SSL client certificate (optional) # Notes: -# - Do not use Jinja variables in this configuration. -# - Omit SSL fields entirely if SSL is not in use. -# - Matching is done by repository name (e.g., appstream) -# - Non-matching repositories are added as additional repos +# - Only 'url' and 'name' are required fields +# - SSL certificates are ALWAYS auto-populated from RHEL subscription defaults +# - User cannot override SSL certificates (sslcacert, sslclientkey, sslclientcert) +# - Matching is done by repository name (e.g., baseos, appstream, codeready-builder) +# - Non-matching repositories are added as additional repos with subscription certs # # 7. rhel_subscription_repo_config_aarch64 #-------------------------------------------- @@ -206,8 +206,12 @@ rhel_os_url_aarch64: {% endif %} # Example: # rhel_subscription_repo_config_x86_64: -# - { url: "https://example.com/appstream", gpgkey: "", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "appstream", policy: "always", caching: true } -# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/supplementary/os/", gpgkey: "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release", sslcacert: "", sslclientkey: "", sslclientcert: "", name: "supplementary", policy: "always", caching: false } +# # Override baseos with standard URL (only url and name required, certs auto-populated) +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/baseos/os/", name: "baseos" } +# # Override appstream with custom URL and policy +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/appstream/os/", name: "appstream", policy: "always" } +# # Add supplementary repo (non-base repo, certs auto-populated) +# - { url: "https://cdn.redhat.com/content/dist/rhel10/10.0/x86_64/supplementary/os/", name: "supplementary", policy: "always", caching: false } rhel_subscription_repo_config_x86_64: rhel_subscription_repo_config_aarch64: # Making incorrect changes to this variable can cause omnia failure. Please edit cautiously. From afca6795806d6bd87be7ec6b8cea09fc196717df Mon Sep 17 00:00:00 2001 From: pullan1 Date: Tue, 16 Jun 2026 12:42:27 +0530 Subject: [PATCH 4/9] ansible lint fix Signed-off-by: pullan1 --- .ansible/.lock | 0 .../tasks/check_rhel_subscription.yml | 16 +++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 .ansible/.lock diff --git a/.ansible/.lock b/.ansible/.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml b/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml index 5b32ab6ac9..6a89fd2c56 100644 --- a/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml +++ b/input_validation/roles/validate_subscription/tasks/check_rhel_subscription.yml @@ -124,11 +124,13 @@ failed_when: false - name: Extract EUS baseurls (appstream, baseos, codeready-builder) + vars: + eus_pattern: "rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-eus-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-eus-rpms" ansible.builtin.shell: | set -o pipefail awk ' /^\[/ {section=$0} - /^baseurl/ && section ~ /(rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-eus-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-eus-rpms)/ { + /^baseurl/ && section ~ /({{ eus_pattern }})/ { gsub(/\$releasever/, "{{ hostvars['localhost']['cluster_os_version'] }}", $3) print $3 } @@ -138,11 +140,13 @@ failed_when: false - name: Extract standard baseurls if EUS not found + vars: + std_pattern: "rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-rpms" ansible.builtin.shell: | set -o pipefail awk ' /^\[/ {section=$0} - /^baseurl/ && section ~ /(rhel-{{ rhel_version }}-for-x86_64-(appstream|baseos)-rpms|codeready-builder-for-rhel-{{ rhel_version }}-x86_64-rpms)/ { + /^baseurl/ && section ~ /({{ std_pattern }})/ { gsub(/\$releasever/, "{{ hostvars['localhost']['cluster_os_version'] }}", $3) print $3 } @@ -153,9 +157,11 @@ - name: Set fact repo baseurls (EUS preferred, fallback to standard) ansible.builtin.set_fact: - repo_baseurls: "{{ (eus_baseurls.stdout_lines if (eus_baseurls.stdout_lines | default([]) | length > 0) else standard_baseurls.stdout_lines | default([])) - | map('regex_replace', '([^/])$', '\\1/') - | list }}" + repo_baseurls: >- + {{ (eus_baseurls.stdout_lines if (eus_baseurls.stdout_lines | default([]) | length > 0) + else standard_baseurls.stdout_lines | default([])) + | map('regex_replace', '([^/])$', '\1/') + | list }} - name: Show extracted baseurls ansible.builtin.debug: From 602057435b7e1fa2a4962bdeebd7018baf3abc81 Mon Sep 17 00:00:00 2001 From: Abhishek S A Date: Tue, 16 Jun 2026 14:28:33 +0530 Subject: [PATCH 5/9] skip approval update Signed-off-by: Abhishek S A --- local_repo/pulp_cleanup.yml | 8 ++++---- .../upgrade_telemetry/tasks/detect_victoria_state.yml | 4 +++- utils/delete_migrated_pulp_rpm_repos.yml | 5 +++-- .../oim_container_cleanup/tasks/cleanup_k8s.yml | 5 ++++- .../oim_container_cleanup/tasks/cleanup_slurm.yml | 5 ++++- .../oim_cleanup/pre_requisite/tasks/pre_requisite.yml | 5 ++++- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/local_repo/pulp_cleanup.yml b/local_repo/pulp_cleanup.yml index 04e4fda5ae..a43f934b91 100644 --- a/local_repo/pulp_cleanup.yml +++ b/local_repo/pulp_cleanup.yml @@ -98,7 +98,7 @@ - name: Set force skip confirmation flag ansible.builtin.set_fact: - force_skip_confirmation: "{{ force | default(false) | bool }}" + force_skip_confirmation: "{{ force | default(false) | bool or skip_approval | default(false) | bool }}" - name: Get user confirmation ansible.builtin.pause: @@ -109,7 +109,7 @@ Type 'yes' to continue or 'no' to abort echo: true register: user_input - when: not force_skip_confirmation + when: not force_skip_confirmation | bool - name: Set user confirmed flag ansible.builtin.set_fact: @@ -119,13 +119,13 @@ ansible.builtin.debug: msg: "Cleanup cancelled by user. Exiting." when: - - not force_skip_confirmation + - not force_skip_confirmation | bool - not user_confirmed - name: Abort if not confirmed ansible.builtin.meta: end_play when: - - not force_skip_confirmation + - not force_skip_confirmation | bool - not user_confirmed tasks: diff --git a/upgrade/roles/upgrade_telemetry/tasks/detect_victoria_state.yml b/upgrade/roles/upgrade_telemetry/tasks/detect_victoria_state.yml index 33f71fbd5d..a12681a6b9 100644 --- a/upgrade/roles/upgrade_telemetry/tasks/detect_victoria_state.yml +++ b/upgrade/roles/upgrade_telemetry/tasks/detect_victoria_state.yml @@ -187,7 +187,9 @@ {{ victoria_unhealthy_pods | length }} unhealthy Victoria pod(s) found. They will be deleted and re-created during upgrade. Press ENTER to continue or Ctrl+C to abort. - when: victoria_unhealthy_pods | length > 0 + when: + - not (skip_approval | default(false) | bool) + - victoria_unhealthy_pods | length > 0 - name: Delete unhealthy Victoria pods ansible.builtin.command: diff --git a/utils/delete_migrated_pulp_rpm_repos.yml b/utils/delete_migrated_pulp_rpm_repos.yml index e88f477c39..119aa5900a 100644 --- a/utils/delete_migrated_pulp_rpm_repos.yml +++ b/utils/delete_migrated_pulp_rpm_repos.yml @@ -38,6 +38,7 @@ # # # Skip user confirmation prompt: # ansible-playbook delete_migrated_pulp_rpm_repos.yml -e "repo_format=old" -e "force=true" +# ansible-playbook delete_migrated_pulp_rpm_repos.yml -e "repo_format=old" -e "skip_approval=true" - name: Delete Migrated Pulp RPM Repositories by Format hosts: localhost @@ -121,13 +122,13 @@ This action cannot be undone. Type 'yes' to continue or press Ctrl+C to abort register: user_input - when: not (force | default(false)) | bool + when: not (force | default(false) | bool or skip_approval | default(false) | bool) - name: Abort if not confirmed ansible.builtin.fail: msg: "Deletion cancelled by user" when: - - not (force | default(false)) | bool + - not (force | default(false) | bool or skip_approval | default(false) | bool) - user_input.user_input | default('') | lower != 'yes' tasks: 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 c6905ea917..6f0da6b43e 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 @@ -156,11 +156,14 @@ ansible.builtin.pause: prompt: "I understand this will delete NFS data affecting all nodes. Type {{ k8s_cleanup_confirm_token }} to continue" register: k8s_cleanup_confirm + when: not (skip_approval | default(false) | bool) - name: Fail if cleanup not confirmed ansible.builtin.fail: msg: "K8s cleanup aborted" - when: k8s_cleanup_confirm.user_input | lower != k8s_cleanup_confirm_token | lower + when: + - not (skip_approval | default(false) | bool) + - k8s_cleanup_confirm.user_input | lower != k8s_cleanup_confirm_token | lower - name: Delete all k8s directories ansible.builtin.file: 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 4cc76a93b8..649b0cebb3 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 @@ -156,11 +156,14 @@ ansible.builtin.pause: prompt: "I understand this will delete NFS data affecting all nodes. Type {{ slurm_cleanup_confirm_token }} to continue" register: cleanup_confirm + when: not (skip_approval | default(false) | bool) - name: Fail if cleanup not confirmed ansible.builtin.fail: msg: "Slurm cleanup aborted" - when: cleanup_confirm.user_input | lower != slurm_cleanup_confirm_token | lower + when: + - not (skip_approval | default(false) | bool) + - cleanup_confirm.user_input | lower != slurm_cleanup_confirm_token | lower - name: Delete slurm directories (excluding slurm_backups) ansible.builtin.file: 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 889a6f7208..0766c17bb0 100644 --- a/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml +++ b/utils/roles/oim_cleanup/pre_requisite/tasks/pre_requisite.yml @@ -110,6 +110,7 @@ prompt: "{{ postgres_credentials_backup_msg }}" seconds: "{{ wait_delay }}" when: + - not (skip_approval | default(false) | bool) - postgres_backup | bool - enable_build_stream @@ -117,5 +118,7 @@ ansible.builtin.pause: prompt: "{{ build_stream_cleanup_warning }}" seconds: "{{ build_stream_pause_seconds }}" - when: enable_build_stream | default(false) | bool + when: + - not (skip_approval | default(false) | bool) + - enable_build_stream | default(false) | bool tags: always From e3b51d9907a24133aec94476a44e257ad5bef86a Mon Sep 17 00:00:00 2001 From: Katakam-Rakesh Date: Tue, 16 Jun 2026 09:19:47 +0000 Subject: [PATCH 6/9] resume upgrade after initial pod status check Signed-off-by: Katakam-Rakesh --- upgrade/playbooks/upgrade_k8s.yml | 228 +++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 20 deletions(-) diff --git a/upgrade/playbooks/upgrade_k8s.yml b/upgrade/playbooks/upgrade_k8s.yml index a85da33da7..1fff8e4d22 100644 --- a/upgrade/playbooks/upgrade_k8s.yml +++ b/upgrade/playbooks/upgrade_k8s.yml @@ -637,6 +637,7 @@ group_cp: "service_kube_control_plane_x86_64" group_worker: "service_kube_node_x86_64" kube_vip: "{{ hostvars['localhost']['kube_vip'] }}" + input_project_dir: "/opt/omnia/input/project_default" tasks: - name: "Skip all tasks — service_k8s not configured, already completed, or resuming post-validation" ansible.builtin.meta: end_play @@ -649,8 +650,119 @@ ansible.builtin.include_vars: file: "{{ playbook_dir }}/../roles/upgrade_k8s/vars/main.yml" + # Check if we're resuming an in-progress/failed upgrade - skip full validation if so + - name: "Check for existing upgrade status file" + block: + - name: "Use cached storage_config" + ansible.builtin.set_fact: + storage_config: "{{ hostvars['localhost']['cached_storage_config'] }}" + + - name: "Use cached omnia_config" + ansible.builtin.set_fact: + omnia_config: "{{ hostvars['localhost']['cached_omnia_config'] }}" + + - name: "Set k8s_nfs_storage_name" + ansible.builtin.set_fact: + k8s_nfs_storage_name: "{{ omnia_config.service_k8s_cluster[0].nfs_storage_name }}" + + - name: "Set status_file path" + ansible.builtin.set_fact: + status_file: >- + {{ (storage_config.mounts + | selectattr('name', 'equalto', k8s_nfs_storage_name) + | first).mount_point }}/upgrade/upgrade_status.yml + + - name: "Check if upgrade status file exists" + ansible.builtin.stat: + path: "{{ status_file }}" + delegate_to: "{{ kube_vip }}" + register: validation_status_file_stat + + - name: "Read existing status file" + ansible.builtin.slurp: + src: "{{ status_file }}" + delegate_to: "{{ kube_vip }}" + register: validation_status_slurp + when: validation_status_file_stat.stat.exists | default(false) + + - name: "Parse existing status" + ansible.builtin.set_fact: + validation_existing_status: "{{ validation_status_slurp.content | b64decode | from_yaml | default({}, true) }}" + when: validation_status_file_stat.stat.exists | default(false) + + - name: "Set default for validation_existing_status if not defined" + ansible.builtin.set_fact: + validation_existing_status: {} + when: not (validation_status_file_stat.stat.exists | default(false)) + + - name: "Check if upgrade is in progress or failed (resuming)" + ansible.builtin.set_fact: + upgrade_resuming_early: >- + {{ validation_status_file_stat.stat.exists | default(false) and + (validation_existing_status.upgrade.status | default('')) in ['in_progress', 'failed'] }} + + - name: "Display resuming message and skip full validation" + ansible.builtin.debug: + msg: + - "════════════════════════════════════════════════════════════════════════════════" + - "[UPGRADE] Resuming previous upgrade - skipping pre-upgrade validation" + - "════════════════════════════════════════════════════════════════════════════════" + - "Upgrade status: {{ validation_existing_status.upgrade.status | default('unknown') }}" + - "Nodes may be drained or pods restarting - full validation not appropriate" + - "Loading node groups from existing upgrade_status.yml instead" + - "════════════════════════════════════════════════════════════════════════════════" + when: upgrade_resuming_early | default(false) + + - name: "Load node groups from status file when resuming" + when: upgrade_resuming_early | default(false) + block: + - name: "Extract node groups from upgrade status" + ansible.builtin.set_fact: + groups_cp_first: >- + {{ validation_existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'control_plane_first') + | map(attribute='key') | list }} + groups_cp: >- + {{ validation_existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'control_plane') + | map(attribute='key') | list }} + groups_worker: >- + {{ validation_existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'worker') + | map(attribute='key') | list }} + + - name: "Build node IPs from upgrade status" + ansible.builtin.set_fact: + node_ips: >- + {{ dict(validation_existing_status.nodes | dict2items + | map(attribute='key') + | zip(validation_existing_status.nodes | dict2items + | map(attribute='value.ip'))) }} + + - name: "Set all upgrade nodes" + ansible.builtin.set_fact: + all_upgrade_nodes: "{{ groups_cp_first + groups_cp + groups_worker }}" + + - name: "Load nodes.yaml for parsed_nodes" + ansible.builtin.slurp: + src: "{{ nodes_yaml_path }}" + register: nodes_slurp_resume_early + + - name: "Parse nodes.yaml" + ansible.builtin.set_fact: + parsed_nodes: "{{ nodes_slurp_resume_early.content | b64decode | from_yaml }}" + + - name: "Mark cluster validation as completed (skipped for resume)" + ansible.builtin.set_fact: + cluster_validation_completed: true + + - name: "Set upgrade_resuming flag for subsequent plays" + ansible.builtin.set_fact: + upgrade_resuming: true + - name: "Validate cluster nodes against nodes.yaml" ansible.builtin.include_tasks: "{{ playbook_dir }}/../roles/upgrade_k8s/tasks/validate_cluster_nodes.yml" + when: not (upgrade_resuming_early | default(false)) - name: "Cache validated node groups for subsequent plays" ansible.builtin.set_fact: @@ -711,17 +823,6 @@ parsed_nodes: "{{ hostvars['localhost']['validated_parsed_nodes'] }}" when: hostvars['localhost']['cluster_validation_completed'] | default(false) - - name: "Run cluster validation if not already done" - when: not (hostvars['localhost']['cluster_validation_completed'] | default(false)) - block: - - name: "Load upgrade role variables for validation" - ansible.builtin.include_vars: - file: "{{ playbook_dir }}/../roles/upgrade_k8s/vars/main.yml" - - - name: "Run cluster node validation" - ansible.builtin.include_tasks: - file: "{{ playbook_dir }}/../roles/upgrade_k8s/tasks/validate_cluster_nodes.yml" - - name: Load variables from file ansible.builtin.include_vars: file: /tmp/k8s_vars.yml @@ -744,6 +845,77 @@ existing_status: "{{ existing_status_slurp.content | b64decode | from_yaml | default({}, true) }}" when: status_file_stat.stat.exists | default(false) + - name: Check if upgrade is in progress or failed (resuming) + ansible.builtin.set_fact: + upgrade_resuming: "{{ status_file_stat.stat.exists | default(false) and (existing_status.upgrade.status | default('')) in ['in_progress', 'failed'] }}" + + - name: "Load node groups from existing upgrade status (resuming upgrade)" + when: + - upgrade_resuming | default(false) + - not (hostvars['localhost']['cluster_validation_completed'] | default(false)) + block: + - name: "Display resuming upgrade message" + ansible.builtin.debug: + msg: + - "========================================================================" + - "[UPGRADE] Resuming previous upgrade" + - "========================================================================" + - "Upgrade status: {{ existing_status.upgrade.status | default('unknown') }}" + - "Skipping node/pod health validation (nodes may be drained or pods restarting)" + - "Loading node groups from existing upgrade_status.yml" + - "========================================================================" + + - name: "Extract node groups from upgrade status" + ansible.builtin.set_fact: + groups_cp_first: >- + {{ existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'control_plane_first') + | map(attribute='key') | list }} + groups_cp: >- + {{ existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'control_plane') + | map(attribute='key') | list }} + groups_worker: >- + {{ existing_status.nodes | dict2items + | selectattr('value.role', 'equalto', 'worker') + | map(attribute='key') | list }} + + - name: "Build node IPs from upgrade status" + ansible.builtin.set_fact: + node_ips: >- + {{ existing_status.nodes | dict2items + | items2dict(key_name='key', value_name='value.ip') }} + + - name: "Set all upgrade nodes" + ansible.builtin.set_fact: + all_upgrade_nodes: "{{ groups_cp_first + groups_cp + groups_worker }}" + + - name: "Load nodes.yaml for parsed_nodes" + ansible.builtin.slurp: + src: "{{ nodes_yaml_path }}" + register: nodes_slurp_resume + + - name: "Parse nodes.yaml" + ansible.builtin.set_fact: + parsed_nodes: "{{ nodes_slurp_resume.content | b64decode | from_yaml }}" + + - name: "Mark validation as completed (skipped for resume)" + ansible.builtin.set_fact: + cluster_validation_completed: true + + - name: "Run cluster validation if not already done and not resuming" + when: + - not (hostvars['localhost']['cluster_validation_completed'] | default(false)) + - not (upgrade_resuming | default(false)) + block: + - name: "Load upgrade role variables for validation" + ansible.builtin.include_vars: + file: "{{ playbook_dir }}/../roles/upgrade_k8s/vars/main.yml" + + - name: "Run cluster node validation" + ansible.builtin.include_tasks: + file: "{{ playbook_dir }}/../roles/upgrade_k8s/tasks/validate_cluster_nodes.yml" + # Steps are stored as dictionary for reliable YAML handling # Execution order: setup_repos -> kubeadm_install -> kubeadm_upgrade_apply/node -> # drain -> kubelet_install -> crio_install -> kubelet_restart -> uncordon -> validation -> etcd_health_check @@ -938,8 +1110,14 @@ node_ips: "{{ hostvars['localhost']['validated_node_ips'] }}" when: hostvars['localhost']['cluster_validation_completed'] | default(false) - - name: "Run cluster validation if not already done" - when: not (hostvars['localhost']['cluster_validation_completed'] | default(false)) + - name: "Use upgrade_resuming flag from previous play" + ansible.builtin.set_fact: + upgrade_resuming: "{{ hostvars['localhost']['upgrade_resuming'] | default(false) }}" + + - name: "Run cluster validation if not already done and not resuming" + when: + - not (hostvars['localhost']['cluster_validation_completed'] | default(false)) + - not (upgrade_resuming | default(false)) block: - name: "Load upgrade role variables for validation" ansible.builtin.include_vars: @@ -1504,20 +1682,30 @@ all_upgrade_nodes: "{{ hostvars['localhost']['validated_all_upgrade_nodes'] }}" when: hostvars['localhost']['cluster_validation_completed'] | default(false) - - name: "Run cluster validation if not already done" + # Note: Post-validation does NOT run validate_cluster_nodes.yml + # That file contains pre-upgrade checks (all-namespace pod health) which are not appropriate here. + # Post-validation only runs post_validation.yml which checks core K8s components. + + - name: "Load all_upgrade_nodes from previous play or status file" when: not (hostvars['localhost']['cluster_validation_completed'] | default(false)) block: - - name: "Load upgrade role variables for validation" + - name: "Load upgrade role variables" ansible.builtin.include_vars: file: "{{ playbook_dir }}/../roles/upgrade_k8s/vars/main.yml" - - name: "Run cluster node validation" - ansible.builtin.include_tasks: - file: "{{ playbook_dir }}/../roles/upgrade_k8s/tasks/validate_cluster_nodes.yml" + - name: "Read status file for node list" + ansible.builtin.slurp: + src: "{{ status_file }}" + delegate_to: "{{ kube_vip }}" + register: status_for_nodes - - name: "Set all_upgrade_nodes from validation" + - name: "Parse status file for nodes" ansible.builtin.set_fact: - all_upgrade_nodes: "{{ groups_cp_first + groups_cp + groups_worker }}" + status_nodes: "{{ (status_for_nodes.content | b64decode | from_yaml).nodes | default({}) }}" + + - name: "Build all_upgrade_nodes from status file" + ansible.builtin.set_fact: + all_upgrade_nodes: "{{ status_nodes.keys() | list }}" - name: Get k8s_from_version from status file ansible.builtin.slurp: From ca8112980c8c6178fb6c5ff9b23737a8664da2cb Mon Sep 17 00:00:00 2001 From: Katakam Rakesh Naga Sai <125246792+Katakam-Rakesh@users.noreply.github.com> Date: Tue, 16 Jun 2026 15:00:07 +0530 Subject: [PATCH 7/9] Update upgrade_k8s.yml Signed-off-by: Katakam Rakesh Naga Sai <125246792+Katakam-Rakesh@users.noreply.github.com> --- upgrade/playbooks/upgrade_k8s.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/upgrade/playbooks/upgrade_k8s.yml b/upgrade/playbooks/upgrade_k8s.yml index 1fff8e4d22..2a57eb69b7 100644 --- a/upgrade/playbooks/upgrade_k8s.yml +++ b/upgrade/playbooks/upgrade_k8s.yml @@ -637,7 +637,6 @@ group_cp: "service_kube_control_plane_x86_64" group_worker: "service_kube_node_x86_64" kube_vip: "{{ hostvars['localhost']['kube_vip'] }}" - input_project_dir: "/opt/omnia/input/project_default" tasks: - name: "Skip all tasks — service_k8s not configured, already completed, or resuming post-validation" ansible.builtin.meta: end_play From 6eade06ccf2bba6adb8475caf26471ecfbf8eb25 Mon Sep 17 00:00:00 2001 From: Rajeshkumar-s2 Date: Tue, 16 Jun 2026 16:44:14 +0530 Subject: [PATCH 8/9] Add service_kube_control_plane_first to images DB (#4760) --- .../orchestrator/catalog/use_cases/parse_catalog.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build_stream/orchestrator/catalog/use_cases/parse_catalog.py b/build_stream/orchestrator/catalog/use_cases/parse_catalog.py index 495ec6c91f..240d7484df 100644 --- a/build_stream/orchestrator/catalog/use_cases/parse_catalog.py +++ b/build_stream/orchestrator/catalog/use_cases/parse_catalog.py @@ -362,6 +362,13 @@ def _extract_catalog_metadata( role_images[role_name] = f"{role_name}.img" roles.sort() + # Add synthetic service_kube_control_plane_first_x86_64 role if base role exists + # This ensures Image records are created for the _first variant during build-image completion + if "service_kube_control_plane_x86_64" in roles and "service_kube_control_plane_first_x86_64" not in roles: + roles.append("service_kube_control_plane_first_x86_64") + role_images["service_kube_control_plane_first_x86_64"] = "service_kube_control_plane_first_x86_64.img" + roles.sort() + return { "image_group_id": str(image_group_id), "roles": roles, From a277fdb93e3fa21cf92b3b2e0943d86cf5538f77 Mon Sep 17 00:00:00 2001 From: Abhishek S A Date: Wed, 17 Jun 2026 11:16:53 +0530 Subject: [PATCH 9/9] Delete .ansible/.lock Signed-off-by: Abhishek S A Signed-off-by: Abhishek S A --- .ansible/.lock | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .ansible/.lock diff --git a/.ansible/.lock b/.ansible/.lock deleted file mode 100644 index e69de29bb2..0000000000