Skip to content

Commit f4d8917

Browse files
committed
[shiftstack] Use GitHub for shiftstack-qa clone and fix false-positive test results
shiftstack-qa moved code review to GitHub PRs (shiftstack/ shiftstack-qa#2). The role default still clones from GerritHub, which is no longer maintained. - Change cifmw_shiftstack_qa_repo default to GitHub - Rename cifmw_shiftstack_qa_gerrithub_change to cifmw_shiftstack_qa_change_ref Also fix a false-positive bug in exec_command_in_pod.yml where oc rsh could return rc=0 before the inner command finished, causing the test to report PASS when the playbook actually failed. Observed in tp!2297 build d078ccbd - the shiftstack test ran for only 145s (vs typical 1.5-2h), OCP was never installed, yet the job reported SUCCESS. The fix runs the inner command detached via nohup and polls a marker file for the exit code. This survives connection drops. Uses kubernetes.core.k8s_exec and k8s_cp modules for setup tasks; the poll step uses oc exec for resilience to transient network errors. Process-crash detection via kill -0 inside the pod catches OOM without polling for 8h. Diagnostic output fetched in rescue/always blocks restores stderr visibility lost by the async approach. Configurable via cifmw_shiftstack_exec_retries (default 5760) and cifmw_shiftstack_exec_delay (default 5s) for an 8h timeout. Related-Issue: #OSPRH-30385 Assisted-By: Claude Code Signed-off-by: Itay Matza <imatza@redhat.com>
1 parent e269481 commit f4d8917

4 files changed

Lines changed: 130 additions & 17 deletions

File tree

roles/shiftstack/README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ Role for triggering Openshift on Openstack QA automation (installation and tests
1414
* `cifmw_shiftstack_client_pvc_manifest`: (*string*) The file name for the shiftstackclient pvc manifest. Defaults to `"{{ cifmw_shiftstack_client_pod_name }}_pvc.yml"`.
1515
* `cifmw_shiftstack_cluster_name`: (*string*) The Openshift cluster name. Defaults to `ostest`.
1616
* `cifmw_shiftstack_hypervisor`: (*string*) The hypervisor where RHOSO is deployed. Defaults to `"{{ hostvars[hostvars['controller-0']['cifmw_hypervisor_host'] | default ('')]['ansible_host'] | default('') }}"`.
17+
* `cifmw_shiftstack_exec_delay`: (*integer*) Seconds between polling attempts when waiting for a command to complete in the pod. Defaults to `5`.
18+
* `cifmw_shiftstack_exec_retries`: (*integer*) Maximum polling attempts when waiting for a command to complete in the pod. With the default delay of 5s, 5760 retries gives an 8-hour timeout. Defaults to `5760`.
1719
* `cifmw_shiftstack_exclude_artifacts_regex`: (*string*) Regex that will be passed on `oc rsync` command as `--exclude` param, so the role does not gather the artifacts matching it.
1820
* `cifmw_shiftstack_installation_dir`: (*string*) Directory to place installation files. Defaults to `"{{ cifmw_shiftstack_shiftstackclient_artifacts_dir }}/installation"`.
1921
* `cifmw_shiftstack_manifests_dir`: (*string*) Directory name for the role generated Openshift manifests. Defaults to `"{{ cifmw_shiftstack_basedir }}/manifests"`.
2022
* `cifmw_shiftstack_project_name`: (*string*) The Openstack project name. Defaults to `shiftstack`.
2123
* `cifmw_shiftstack_proxy`: (*string*) The proxy url that should be used to reach the underlying OCP. Defaults to omit.
22-
* `cifmw_shiftstack_qa_gerrithub_change`: (*string*) The gerrithub change to fetch from the `cifmw_shiftstack_qa_repo` repository (i.e. 'refs/changes/29/1188429/50)'. Defaults to ''.
23-
* `cifmw_shiftstack_qa_repo`: (*string*) The repository containing the Openshift on Openstack QA automation. Defaults to `https://review.gerrithub.io/shiftstack/shiftstack-qa`.
24+
* `cifmw_shiftstack_qa_change_ref`: (*string*) A git ref to fetch and checkout from the `cifmw_shiftstack_qa_repo` repository. Supports GitHub PR refs (e.g. `refs/pull/5/head`) and GerritHub change refs (e.g. `refs/changes/29/1188429/50`). Defaults to `''`.
25+
* `cifmw_shiftstack_qa_repo`: (*string*) The repository containing the Openshift on Openstack QA automation. Defaults to `https://github.com/shiftstack/shiftstack-qa`.
2426
* `cifmw_shiftstack_run_playbook`: (*string*) The playbook to be run from the `cifmw_shiftstack_qa_repo` repository. Defaults to `ocp_testing.yaml`.
2527
* `cifmw_shiftstack_sc`: (*string*) The storage class to be used for PVC for the shiftstackclient pod. Defaults to `local-storage`.
2628
* `cifmw_shiftstack_shiftstackclient_artifacts_dir`: (*string*) The artifacts directory path for the shiftstackclient pod. Defaults to `/home/cloud-admin/artifacts`.
@@ -40,7 +42,7 @@ cifmw_run_test_role: shiftstack
4042
cifmw_run_test_shiftstack_testconfig:
4143
- 4.17_ovnkubernetes_ipi.yaml
4244
- 4.17_ovnkubernetes_upi.yaml
43-
cifmw_shiftstack_qa_gerrithub_change: refs/changes/29/1188429/50 #optional
45+
cifmw_shiftstack_qa_change_ref: refs/pull/5/head #optional
4446
45-
$ ansible-playbook deploy-edpm.yml --extra-vars "cifmw_run_tests=true cifmw_run_test_role=shiftstack cifmw_test_operator_stages=[] cifmw_openshift_kubeconfig={{ ansible_user_dir }}/.kube/config cifmw_run_test_shiftstack_testconfig=4.15_ovnkubernetes_ipi_va1.yaml cifmw_shiftstack_qa_gerrithub_change=refs/changes/29/1188429/50"
47+
$ ansible-playbook deploy-edpm.yml --extra-vars "cifmw_run_tests=true cifmw_run_test_role=shiftstack cifmw_test_operator_stages=[] cifmw_openshift_kubeconfig={{ ansible_user_dir }}/.kube/config cifmw_run_test_shiftstack_testconfig=4.15_ovnkubernetes_ipi_va1.yaml cifmw_shiftstack_qa_change_ref=refs/pull/5/head"
4648
```

roles/shiftstack/defaults/main.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ cifmw_shiftstack_client_pod_name: "shiftstackclient-{{ cifmw_shiftstack_project_
2828
cifmw_shiftstack_client_pod_namespace: "openstack"
2929
cifmw_shiftstack_client_pvc_manifest: "{{ cifmw_shiftstack_client_pod_name }}_pvc.yml"
3030
cifmw_shiftstack_cluster_name: "ostest"
31+
cifmw_shiftstack_exec_delay: 5
32+
cifmw_shiftstack_exec_retries: 5760
3133
cifmw_shiftstack_exclude_artifacts_regex: "openshift-install"
3234
cifmw_shiftstack_hypervisor: "{{ hostvars[hostvars['controller-0']['cifmw_hypervisor_host'] | default ('')]['ansible_host'] | default('') }}"
3335
cifmw_shiftstack_installation_dir: "{{ cifmw_shiftstack_basedir }}/installation"
3436
cifmw_shiftstack_manifests_dir: "{{ cifmw_shiftstack_basedir }}/manifests"
3537
cifmw_shiftstack_project_name: "shiftstack"
36-
cifmw_shiftstack_qa_gerrithub_change: ""
37-
cifmw_shiftstack_qa_repo: "https://review.gerrithub.io/shiftstack/shiftstack-qa"
38+
cifmw_shiftstack_qa_change_ref: ""
39+
cifmw_shiftstack_qa_repo: "https://github.com/shiftstack/shiftstack-qa"
3840
cifmw_shiftstack_run_playbook: "ocp_testing.yaml"
3941
cifmw_shiftstack_sc: "local-storage"
4042
cifmw_shiftstack_shiftstackclient_artifacts_dir: "/home/cloud-admin/artifacts"

roles/shiftstack/tasks/exec_command_in_pod.yml

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,130 @@
1616

1717
- name: Command execution block
1818
block:
19-
- name: Execute in the pod the command '{{ command }}'
19+
- name: Kill any previous background command and clear markers
20+
kubernetes.core.k8s_exec:
21+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
22+
namespace: "{{ namespace }}"
23+
pod: "{{ pod_name }}"
24+
command: >-
25+
bash -c 'if [ -f /tmp/cifmw_cmd_pid ]; then
26+
kill $(cat /tmp/cifmw_cmd_pid) 2>/dev/null;
27+
wait $(cat /tmp/cifmw_cmd_pid) 2>/dev/null; fi;
28+
rm -f /tmp/cifmw_cmd_rc /tmp/cifmw_cmd_pid
29+
/tmp/cifmw_cmd_script.sh /tmp/cifmw_cmd_output.log'
30+
changed_when: false
31+
failed_when: false
32+
33+
- name: Copy the command script into the pod
34+
kubernetes.core.k8s_cp:
35+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
36+
namespace: "{{ namespace }}"
37+
pod: "{{ pod_name }}"
38+
remote_path: /tmp/cifmw_cmd_script.sh
39+
content: |
40+
#!/bin/bash
41+
{{ command }}
42+
state: to_pod
43+
44+
- name: Execute '{{ command }}' detached in the pod
45+
kubernetes.core.k8s_exec:
46+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
47+
namespace: "{{ namespace }}"
48+
pod: "{{ pod_name }}"
49+
command: >-
50+
bash -c 'nohup bash -c "bash /tmp/cifmw_cmd_script.sh;
51+
echo \$? > /tmp/cifmw_cmd_rc"
52+
> /tmp/cifmw_cmd_output.log 2>&1 &
53+
echo $! > /tmp/cifmw_cmd_pid && cat /tmp/cifmw_cmd_pid'
54+
register: pod_command_result
55+
56+
- name: Wait for the command to complete in the pod
2057
environment:
2158
PATH: "{{ cifmw_path }}"
2259
KUBECONFIG: "{{ cifmw_openshift_kubeconfig }}"
2360
ansible.builtin.command:
24-
cmd: "oc rsh -n {{ namespace }} {{ pod_name }} bash -c '{{ command }}'"
25-
register: pod_command_result
61+
cmd: >-
62+
oc exec -n {{ namespace }} {{ pod_name }} --
63+
bash -c 'if cat /tmp/cifmw_cmd_rc 2>/dev/null; then exit 0;
64+
elif [ -f /tmp/cifmw_cmd_pid ] && kill -0 $(cat /tmp/cifmw_cmd_pid) 2>/dev/null; then exit 1;
65+
else exit 2; fi'
66+
register: pod_exit_code
67+
changed_when: false
68+
failed_when: false
69+
until: pod_exit_code.rc == 0 or pod_exit_code.rc == 2
70+
retries: "{{ cifmw_shiftstack_exec_retries }}"
71+
delay: "{{ cifmw_shiftstack_exec_delay }}"
72+
73+
- name: Fail if the background process died without writing the marker
74+
ansible.builtin.fail:
75+
msg: >-
76+
The background process in pod {{ pod_name }} exited without writing a result.
77+
The command may have been killed by OOM or a signal.
78+
when: pod_exit_code.rc == 2
79+
80+
- name: Fail if polling timed out
81+
ansible.builtin.fail:
82+
msg: >-
83+
Timed out waiting for "{{ command }}" to complete
84+
in pod {{ pod_name }} after {{ cifmw_shiftstack_exec_retries }} attempts.
85+
when: pod_exit_code.rc != 0 and pod_exit_code.rc != 2
86+
87+
- name: Fail if the command failed inside the pod
88+
ansible.builtin.fail:
89+
msg: >-
90+
"{{ command }}" failed inside the pod with
91+
exit code {{ pod_exit_code.stdout | trim }}.
92+
when:
93+
- pod_exit_code.rc == 0
94+
- (pod_exit_code.stdout | default('') | trim) != '0'
2695

2796
rescue:
28-
- name: Fail when the command module fails
97+
- name: Kill background process on failure
98+
kubernetes.core.k8s_exec:
99+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
100+
namespace: "{{ namespace }}"
101+
pod: "{{ pod_name }}"
102+
command: >-
103+
bash -c 'if [ -f /tmp/cifmw_cmd_pid ]; then
104+
kill $(cat /tmp/cifmw_cmd_pid) 2>/dev/null; fi'
105+
failed_when: false
106+
changed_when: false
107+
108+
- name: Retrieve command output from pod
109+
kubernetes.core.k8s_exec:
110+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
111+
namespace: "{{ namespace }}"
112+
pod: "{{ pod_name }}"
113+
command: >-
114+
bash -c 'tail -c 8192 /tmp/cifmw_cmd_output.log 2>/dev/null
115+
|| echo "(output not available)"'
116+
register: pod_output_log
117+
failed_when: false
118+
changed_when: false
119+
120+
- name: Fail with diagnostic information
29121
ansible.builtin.fail:
30-
msg: '"{{ command }}" command execution failed with exit code "{{ pod_command_result.rc }}" and error: "{{ pod_command_result.stderr }}".'
122+
msg: >-
123+
"{{ command }}" failed.
124+
pod exit code: {{ pod_exit_code.stdout | default('N/A') | trim }},
125+
output (last 8KB): {{ pod_output_log.stdout | default('(not retrieved)') }}
31126
32127
always:
33128
- name: Command execution log saving block
34129
when: log_file_name | default(false)
35130
block:
131+
- name: Retrieve command output for log
132+
kubernetes.core.k8s_exec:
133+
kubeconfig: "{{ cifmw_openshift_kubeconfig }}"
134+
namespace: "{{ namespace }}"
135+
pod: "{{ pod_name }}"
136+
command: >-
137+
bash -c 'tail -c 16384 /tmp/cifmw_cmd_output.log 2>/dev/null
138+
|| echo "(output not available)"'
139+
register: pod_output_for_log
140+
failed_when: false
141+
changed_when: false
142+
36143
- name: Get current date and time
37144
ansible.builtin.command:
38145
cmd: date +"%Y_%m_%d-%H_%M_%S"
@@ -44,7 +151,9 @@
44151
namespace: "{{ namespace }}"
45152
pod_name: "{{ pod_name }}"
46153
command: "{{ command }}"
47-
pod_command_result: "{{ pod_command_result }}"
154+
pod_command_result: "{{ pod_command_result | default('N/A') }}"
155+
pod_exit_code: "{{ pod_exit_code | default('N/A') }}"
156+
pod_output: "{{ pod_output_for_log.stdout | default('N/A') }}"
48157
ansible.builtin.copy:
49158
content: "{{ command_info | to_nice_yaml }}"
50159
dest: "{{ cifmw_shiftstack_ansible_command_logs_dir }}/{{ current_date.stdout }}.{{ log_file_name }}"

roles/shiftstack/tasks/test_shiftstack.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323
log_file_name: "clone_shiftstack_qa_repo.log"
2424
ansible.builtin.include_tasks: exec_command_in_pod.yml
2525

26-
- name: Fetch the gerrithub change '{{ cifmw_shiftstack_qa_gerrithub_change }}'
26+
- name: Fetch the change ref '{{ cifmw_shiftstack_qa_change_ref }}'
2727
vars:
2828
namespace: "{{ cifmw_shiftstack_client_pod_namespace }}"
2929
pod_name: "{{ cifmw_shiftstack_client_pod_name }}"
3030
command: >-
3131
cd shiftstack-qa &&
32-
git fetch {{ cifmw_shiftstack_qa_repo }} {{ cifmw_shiftstack_qa_gerrithub_change }} &&
32+
git fetch {{ cifmw_shiftstack_qa_repo }} {{ cifmw_shiftstack_qa_change_ref }} &&
3333
git checkout FETCH_HEAD
34-
log_file_name: "fetch_shiftstack_qa_gerrithub_change.log"
34+
log_file_name: "fetch_shiftstack_qa_change_ref.log"
3535
when:
36-
- cifmw_shiftstack_qa_gerrithub_change is defined
37-
- cifmw_shiftstack_qa_gerrithub_change != ''
36+
- cifmw_shiftstack_qa_change_ref is defined
37+
- cifmw_shiftstack_qa_change_ref != ''
3838
ansible.builtin.include_tasks: exec_command_in_pod.yml
3939

4040
- name: Install the ansible collections

0 commit comments

Comments
 (0)