Skip to content

Commit cedfc1b

Browse files
osp_verification: purge bogus Machines and harden LB suite cleanup
Purge bogus-* leftovers before openstack_test, enable nightly LB guest cleanup including lb-sg-*, and fix serial OTE skip exits plus empty late sourceRanges junit. Serial OTE: ignore run-test non-zero only when the resolver confirms skip/pass; empty/unknown/failed outcomes keep the suite failed. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 1c9e88e commit cedfc1b

11 files changed

Lines changed: 160 additions & 18 deletions

‎collection/stages/roles/lb_tests/tasks/cleanup_lb_test_leftovers.yml‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,23 @@
6767
OS_CLOUD: "{{ user_cloud }}"
6868
changed_when: false
6969
failed_when: false
70+
71+
# Orphan lb-sg-* Neutron SGs left on node ports trip ProviderSpec SG matching
72+
# when lb_tests runs before openstack_test (seen on 4.21 warm re-runs).
73+
- name: Best-effort remove orphan lb-sg-* security group attachments and SGs
74+
ansible.builtin.shell: |
75+
set -o pipefail
76+
openstack security group list -f value -c ID -c Name 2>/dev/null | while read -r sg_id sg_name; do
77+
case "$sg_name" in
78+
lb-sg-*)
79+
for port_id in $(openstack port list --security-group "$sg_id" -f value -c ID 2>/dev/null); do
80+
openstack port unset --security-group "$sg_id" "$port_id" 2>/dev/null || true
81+
done
82+
openstack security group delete "$sg_id" 2>/dev/null || true
83+
;;
84+
esac
85+
done
86+
environment:
87+
OS_CLOUD: "{{ user_cloud }}"
88+
changed_when: false
89+
failed_when: false

‎collection/stages/roles/lb_tests/tasks/main.yml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,7 @@
101101
openstack_test_ote_run_serial: true
102102
openstack_testsuite_name: openstack_tests_lb_ovn
103103
openstack_reset_result_dir: no # As we want to keep the logs generated in the previous step
104+
105+
- name: Best-effort cleanup after LB tests (before openstack_test)
106+
ansible.builtin.include_tasks: cleanup_lb_test_leftovers.yml
107+
when: lb_tests_guest_cleanup | bool

‎collection/stages/roles/openstack_test/files/ote_resolve_results.py‎

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
or in ginkgo summary lines (``SUCCESS!`` / ``FAIL!``).
1111
1212
Usage:
13-
ote_resolve_results.py count <log> passed|failed|skipped
13+
ote_resolve_results.py count <log> passed|failed|skipped|unknown
1414
ote_resolve_results.py junit <log> <junit_xml_path>
1515
"""
1616

@@ -23,26 +23,47 @@
2323
from typing import Any
2424

2525

26+
def _is_ote_shaped(entry: Any) -> bool:
27+
return isinstance(entry, dict) and "result" in entry
28+
29+
2630
def _load_outer_results(raw: str) -> list[dict[str, Any]]:
2731
raw = raw.strip()
2832
if not raw:
2933
return []
3034

31-
# Skip leading klog / noise before the JSON array/object.
32-
start_candidates = [i for i, ch in enumerate(raw) if ch in "[{"]
33-
for start in start_candidates:
34-
chunk = raw[start:]
35+
# Scan top-level JSON values. Skip empty lists / non-OTE-shaped JSON
36+
# (e.g. bare ``[]`` from ginkgo text like ``map[]``) so we reach the real
37+
# result array(s) at the end of the log. Advance past each decoded value
38+
# to avoid re-parsing nested JSON inside ``output`` fields. Serial
39+
# run-test appends multiple arrays — collect all OTE-shaped entries.
40+
results: list[dict[str, Any]] = []
41+
decoder = json.JSONDecoder()
42+
i = 0
43+
n = len(raw)
44+
while i < n:
45+
while i < n and raw[i] not in "[{":
46+
i += 1
47+
if i >= n:
48+
break
3549
try:
36-
data, _ = json.JSONDecoder().raw_decode(chunk)
50+
data, end = decoder.raw_decode(raw[i:])
3751
except json.JSONDecodeError:
52+
i += 1
3853
continue
54+
i = i + end
3955
if isinstance(data, list):
40-
return [r for r in data if isinstance(r, dict)]
41-
if isinstance(data, dict):
42-
return [data]
56+
ote = [r for r in data if _is_ote_shaped(r)]
57+
if ote:
58+
results.extend(ote)
59+
continue
60+
if _is_ote_shaped(data):
61+
results.append(data)
62+
63+
if results:
64+
return results
4365

4466
# NDJSON fallback
45-
results: list[dict[str, Any]] = []
4667
for line in raw.splitlines():
4768
line = line.strip()
4869
if not line or not line.startswith("{"):
@@ -51,7 +72,7 @@ def _load_outer_results(raw: str) -> list[dict[str, Any]]:
5172
obj = json.loads(line)
5273
except json.JSONDecodeError:
5374
continue
54-
if isinstance(obj, dict):
75+
if _is_ote_shaped(obj):
5576
results.append(obj)
5677
return results
5778

@@ -206,7 +227,7 @@ def main(argv: list[str]) -> int:
206227
cmd = argv[1]
207228
if cmd == "count":
208229
if len(argv) != 4:
209-
print("usage: count <log> passed|failed|skipped", file=sys.stderr)
230+
print("usage: count <log> passed|failed|skipped|unknown", file=sys.stderr)
210231
return 2
211232
print(cmd_count(argv[2], argv[3]))
212233
return 0
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
# Best-effort purge of leftover bogus-* MachineSets/Machines before openstack_test.
3+
# Pairs with openstack-test bz_2073398 cleanup; suite-level hygiene if that It left
4+
# stuck objects that poison later Machine / MachineSet / ProviderSpec specs.
5+
- name: List bogus MachineSets in openshift-machine-api
6+
ansible.builtin.shell: |
7+
set -o pipefail
8+
oc get machineset -n openshift-machine-api -o name 2>/dev/null \
9+
| grep -E 'bogus-' || true
10+
environment:
11+
KUBECONFIG: "{{ kubeconfig }}"
12+
register: bogus_machinesets_cmd
13+
changed_when: false
14+
failed_when: false
15+
16+
- name: List bogus Machines in openshift-machine-api
17+
ansible.builtin.shell: |
18+
set -o pipefail
19+
oc get machine -n openshift-machine-api -o name 2>/dev/null \
20+
| grep -E 'bogus-' || true
21+
environment:
22+
KUBECONFIG: "{{ kubeconfig }}"
23+
register: bogus_machines_cmd
24+
changed_when: false
25+
failed_when: false
26+
27+
- name: Delete leftover bogus MachineSets
28+
ansible.builtin.command:
29+
argv:
30+
- oc
31+
- delete
32+
- "{{ item }}"
33+
- -n
34+
- openshift-machine-api
35+
- --wait=false
36+
environment:
37+
KUBECONFIG: "{{ kubeconfig }}"
38+
loop: "{{ bogus_machinesets_cmd.stdout_lines | default([]) }}"
39+
loop_control:
40+
label: "{{ item }}"
41+
register: bogus_ms_delete
42+
changed_when: bogus_ms_delete.rc == 0
43+
failed_when: false
44+
when: bogus_machinesets_cmd.stdout_lines | default([]) | length > 0
45+
46+
- name: Delete leftover bogus Machines
47+
ansible.builtin.command:
48+
argv:
49+
- oc
50+
- delete
51+
- "{{ item }}"
52+
- -n
53+
- openshift-machine-api
54+
- --wait=false
55+
environment:
56+
KUBECONFIG: "{{ kubeconfig }}"
57+
loop: "{{ bogus_machines_cmd.stdout_lines | default([]) }}"
58+
loop_control:
59+
label: "{{ item }}"
60+
register: bogus_machine_delete
61+
changed_when: bogus_machine_delete.rc == 0
62+
failed_when: false
63+
when: bogus_machines_cmd.stdout_lines | default([]) | length > 0
64+
65+
- name: Short wait after bogus Machine purge
66+
ansible.builtin.pause:
67+
seconds: 15
68+
when: >-
69+
(bogus_machinesets_cmd.stdout_lines | default([]) | length > 0)
70+
or (bogus_machines_cmd.stdout_lines | default([]) | length > 0)

‎collection/stages/roles/openstack_test/tasks/main.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
delegate_to: "{{ hypervisor }}"
3333
remote_user: root
3434

35+
- name: Best-effort purge leftover bogus Machines before openstack-test
36+
ansible.builtin.include_tasks: cleanup_bogus_machines.yml
37+
3538
- name: Include Openstack-Test tasks
3639
ansible.builtin.include_tasks: run_openstack_test.yml
3740

‎collection/stages/roles/openstack_test/tasks/run_openstack_test.yml‎

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,37 @@
188188
ansible.builtin.shell: |
189189
set -o pipefail
190190
: > {{ openstack_test_log_path }}
191-
run_exit=0
191+
suite_exit=0
192192
py_exit=0
193+
resolve="{{ openstack_test_ote_resolve_script }}"
193194
while IFS= read -r test || [[ -n "$test" ]]; do
194195
[[ -z "${test// }" ]] && continue
195-
if ! {{ openstack_test_executable }} run-test --output=json "$test" \
196-
>> {{ openstack_test_log_path }} 2>&1; then
197-
run_exit=1
196+
tmp=$(mktemp)
197+
rc=0
198+
{{ openstack_test_executable }} run-test --output=json "$test" \
199+
> "$tmp" 2>&1 || rc=$?
200+
cat "$tmp" >> {{ openstack_test_log_path }}
201+
# Skip-only (and pass) often exit non-zero from run-test; ignore that
202+
# only when the resolver confirms skipped/passed. Empty, unknown, or
203+
# failed outcomes keep the non-zero exit as a suite failure.
204+
if [ "$rc" -ne 0 ]; then
205+
failed=$(python3 "$resolve" count "$tmp" failed || echo 1)
206+
skipped=$(python3 "$resolve" count "$tmp" skipped || echo 0)
207+
passed=$(python3 "$resolve" count "$tmp" passed || echo 0)
208+
unknown=$(python3 "$resolve" count "$tmp" unknown || echo 0)
209+
total=$((failed + skipped + passed + unknown))
210+
if [ "$total" -eq 0 ] || [ "$failed" -gt 0 ] || [ "$unknown" -gt 0 ]; then
211+
suite_exit=1
212+
fi
198213
fi
214+
rm -f "$tmp"
199215
done < {{ tests_to_run_path }}
200-
python3 "{{ openstack_test_ote_resolve_script }}" junit \
216+
python3 "$resolve" junit \
201217
"{{ openstack_test_log_path }}" "{{ openstack_test_junit_path }}" || py_exit=$?
202-
if [ "$run_exit" -ne 0 ] || [ "$py_exit" -ne 0 ]; then
218+
failed_count=$(python3 "$resolve" count \
219+
"{{ openstack_test_log_path }}" failed || echo 0)
220+
if [ "$suite_exit" -ne 0 ] || [ "$py_exit" -ne 0 ] \
221+
|| [ "${failed_count:-0}" -gt 0 ]; then
203222
exit 1
204223
fi
205224
exit 0

‎jobs_definitions/osp_verification_4.21_nightly.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
openshift_release: "4.21"
1414
openshift_build_name: "" # Empty resolves to latest nightly via 4.21.0-0.nightly/latest
1515
installation_type: ipi
16+
lb_tests_guest_cleanup: true
1617
stages:
1718
- prepare
1819
- install

‎jobs_definitions/osp_verification_4.22_nightly.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
openshift_release: "4.22"
1414
openshift_build_name: "" # Empty resolves to latest nightly via 4.22.0-0.nightly/latest
1515
installation_type: ipi
16+
lb_tests_guest_cleanup: true
1617
stages:
1718
- prepare
1819
- install

‎jobs_definitions/osp_verification_4.23_nightly.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
openshift_release: "4.23"
1414
openshift_build_name: "" # Empty resolves to latest nightly via 4.23.0-0.nightly/latest
1515
installation_type: ipi
16+
lb_tests_guest_cleanup: true
1617
stages:
1718
- prepare
1819
- install

‎jobs_definitions/osp_verification_5.0_nightly.yaml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
openshift_release: "5.0"
1717
openshift_build_name: "" # Empty resolves to latest nightly via 5.0.0-0.nightly/latest
1818
installation_type: ipi
19+
lb_tests_guest_cleanup: true
1920
stages:
2021
- prepare
2122
- install

0 commit comments

Comments
 (0)