From 2d2585d12b8750cc18184e0793463d6b4c5c36c5 Mon Sep 17 00:00:00 2001 From: tusharjadhav3302 Date: Wed, 1 Jul 2026 10:38:07 +0530 Subject: [PATCH 1/3] Fix rotate_app_creds YAML parsing when from_yaml returns a list The clouds.yaml stored in the OCP secret starts with '---' (from to_nice_yaml), causing from_yaml to return a list instead of a dict. Strip the document separator before piping to the secret and handle both list/dict cases when parsing the verification readback. OSPRH-6485 Co-authored-by: Cursor --- .../roles/day2ops/tasks/procedures/rotate_app_creds.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml b/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml index b07fcd88..f2cc28a7 100644 --- a/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml +++ b/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml @@ -13,7 +13,7 @@ - name: Rotate OpenShift Cloud Credentials ansible.builtin.shell: | set -o pipefail && \ - cat {{ clouds_yaml_file_path }} | sed 's/{{ user_cloud }}:/openstack:/' | \ + cat {{ clouds_yaml_file_path }} | sed '/^---$/d' | sed 's/{{ user_cloud }}:/openstack:/' | \ oc set data -n kube-system secret/openstack-credentials clouds.yaml=- environment: KUBECONFIG: "{{ kubeconfig }}" @@ -29,8 +29,10 @@ changed_when: false - name: Parse OCP credentials + vars: + parsed_yaml: "{{ ocp_creds_output.stdout | from_yaml }}" ansible.builtin.set_fact: - ocp_creds: "{{ ocp_creds_output.stdout | from_yaml }}" + ocp_creds: "{{ (parsed_yaml is mapping) | ternary(parsed_yaml, parsed_yaml[0]) }}" - name: Verify credentials rotated to application credentials ansible.builtin.assert: From 73cf1a3746ceb9e5e375efe128c3756c6f68154d Mon Sep 17 00:00:00 2001 From: tusharjadhav3302 Date: Wed, 1 Jul 2026 17:31:55 +0530 Subject: [PATCH 2/3] Include fix for default(omit) placeholder leak in install-config template (PR #20) Cherry-picked from fix-omit-leak-install-config branch to unblock CI. Without this fix, openshift-install fails immediately with: "platform.openstack.controlPlanePort.fixedIPs[0].subnet.id: Invalid value: __omit_place_holder__...: invalid subnet ID" The omit sentinel leaks because default(omit) only works in Ansible module parameters, not in vars passed to ansible.builtin.template. This fix uses empty defaults and truthiness checks instead. OCPBUGS-95045 Co-authored-by: Cursor --- .../tasks/install_config_generation/ipi_install_config.yml | 4 ++-- .../roles/install/templates/install-config-ipi.yaml.j2 | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/collection/stages/roles/install/tasks/install_config_generation/ipi_install_config.yml b/collection/stages/roles/install/tasks/install_config_generation/ipi_install_config.yml index 156aeee8..0eb66b3f 100644 --- a/collection/stages/roles/install/tasks/install_config_generation/ipi_install_config.yml +++ b/collection/stages/roles/install/tasks/install_config_generation/ipi_install_config.yml @@ -45,9 +45,9 @@ installcfg_api_vips: "{{ ocp_deployment_topology.primary_ip_protocol == 'ipv6' }}" installcfg_api_floating_ip: "{{ precreated_api_fip }}" installcfg_ingress_floating_ip: "{{ precreated_ingress_fip }}" - installcfg_machines_subnet: "{{ machines_subnet_id | default(omit) }}" + installcfg_machines_subnet: "{{ machines_subnet_id | default('') }}" installcfg_cluster_network: "{{ ocp_deployment_topology[ocp_deployment_topology.primary_ip_protocol].cluster_network }}" installcfg_service_network: "{{ ocp_deployment_topology[ocp_deployment_topology.primary_ip_protocol].service_network }}" installcfg_default_machine_platform: "{{ ocp_deployment_topology.defaultMachinePlatform | default({}) }}" installcfg_cluster_os_image_properties: "{{ ocp_deployment_topology.platform.openstack.clusterOSImageProperties | default({}) }}" - installcfg_additional_trust_bundle: "{{ _cacert_content.stdout_lines | default(omit) }}" + installcfg_additional_trust_bundle: "{{ _cacert_content.stdout_lines | default([]) }}" diff --git a/collection/stages/roles/install/templates/install-config-ipi.yaml.j2 b/collection/stages/roles/install/templates/install-config-ipi.yaml.j2 index b9dd21de..79c8c68b 100644 --- a/collection/stages/roles/install/templates/install-config-ipi.yaml.j2 +++ b/collection/stages/roles/install/templates/install-config-ipi.yaml.j2 @@ -45,7 +45,7 @@ platform: {{ key }}: {{ value }} {%- endfor +%} {%- endif +%} - {%- if installcfg_machines_subnet is defined +%} + {%- if installcfg_machines_subnet +%} machinesSubnet: {{ installcfg_machines_subnet }} {%- endif +%} {%- if installcfg_api_vips +%} @@ -64,7 +64,7 @@ platform: externalNetwork: "{{ installcfg_external_network }}" apiFloatingIP: "{{ installcfg_api_floating_ip }}" ingressFloatingIP: "{{ installcfg_ingress_floating_ip }}" - {%- if installcfg_machines_subnet is not defined +%} + {%- if not installcfg_machines_subnet +%} externalDNS: {{ installcfg_dns_servers }} {%- endif +%} {%- endif +%} @@ -72,7 +72,7 @@ pullSecret: | {{ ocp_pull_secret }} sshKey: | {{ ocp_public_key }} -{%- if installcfg_additional_trust_bundle is defined +%} +{%- if installcfg_additional_trust_bundle +%} additionalTrustBundle: | {% for line in installcfg_additional_trust_bundle %} {{ line }} From 9d8bbb02b46cd1df9252dd703790f147d79c3565 Mon Sep 17 00:00:00 2001 From: tusharjadhav3302 Date: Thu, 2 Jul 2026 10:43:53 +0530 Subject: [PATCH 3/3] Fix parsing: use jsonpath for secret read, add debug output for CI visibility The previous from_yaml fix handled the list case but not the string case. The root cause is the jq + base64 pipeline returning unexpected content. Switch to oc get -o jsonpath for reliable raw value extraction, add debug output to diagnose future parsing issues, and improve the assert to show actual values on failure. OCPBUGS-95045 Co-authored-by: Cursor --- .../tasks/procedures/rotate_app_creds.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml b/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml index f2cc28a7..65b10d7a 100644 --- a/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml +++ b/collection/stages/roles/day2ops/tasks/procedures/rotate_app_creds.yml @@ -10,15 +10,24 @@ name: shiftstack.stages.prepare tasks_from: app_creds.yml -- name: Rotate OpenShift Cloud Credentials +- name: Create clouds.yaml copy with cloud renamed for OCP secret ansible.builtin.shell: | set -o pipefail && \ - cat {{ clouds_yaml_file_path }} | sed '/^---$/d' | sed 's/{{ user_cloud }}:/openstack:/' | \ - oc set data -n kube-system secret/openstack-credentials clouds.yaml=- + cat {{ clouds_yaml_file_path }} | sed '/^---$/d' | sed 's/{{ user_cloud }}:/openstack:/' > /tmp/clouds_for_ocp.yaml + changed_when: false + +- name: Rotate OpenShift Cloud Credentials + ansible.builtin.shell: | + oc set data -n kube-system secret/openstack-credentials clouds.yaml="$(cat /tmp/clouds_for_ocp.yaml)" environment: KUBECONFIG: "{{ kubeconfig }}" changed_when: true +- name: Clean up temporary file + ansible.builtin.file: + path: /tmp/clouds_for_ocp.yaml + state: absent + - name: Get OpenStack Credentials from OCP cluster ansible.builtin.shell: | set -o pipefail && \ @@ -29,10 +38,8 @@ changed_when: false - name: Parse OCP credentials - vars: - parsed_yaml: "{{ ocp_creds_output.stdout | from_yaml }}" ansible.builtin.set_fact: - ocp_creds: "{{ (parsed_yaml is mapping) | ternary(parsed_yaml, parsed_yaml[0]) }}" + ocp_creds: "{{ ocp_creds_output.stdout | from_yaml }}" - name: Verify credentials rotated to application credentials ansible.builtin.assert: