From 112ec6b0b4664f83ff13d795db0c2f951f25307e Mon Sep 17 00:00:00 2001 From: sauragar Date: Thu, 22 Jan 2026 19:44:36 +0530 Subject: [PATCH 1/2] Add stackviz integration for tempest test results This commit adds automatic stackviz HTML report generation for tempest test results in the test_operator role. Changes: - Add generate-stackviz.yml task file to handle stackviz generation - Integrate stackviz generation into run-test-operator-job.yml - Add cifmw_test_operator_generate_stackviz config variable - Add STACKVIZ_INTEGRATION.md documentation The integration automatically: 1. Finds tempest_results.subunit.gz in collected logs 2. Decompresses the subunit file 3. Runs stackviz-export to generate interactive HTML 4. Stores output in /stackviz/html/ Users can disable this feature by setting: cifmw_test_operator_generate_stackviz: false Signed-off-by: Saurabh Agarwal Co-Authored-By: Claude Sonnet 4.5 --- roles/test_operator/defaults/main.yml | 1 + .../tasks/STACKVIZ_INTEGRATION.md | 120 ++++++++++++++ .../test_operator/tasks/generate-stackviz.yml | 154 ++++++++++++++++++ .../tasks/run-test-operator-job.yml | 3 + 4 files changed, 278 insertions(+) create mode 100644 roles/test_operator/tasks/STACKVIZ_INTEGRATION.md create mode 100644 roles/test_operator/tasks/generate-stackviz.yml diff --git a/roles/test_operator/defaults/main.yml b/roles/test_operator/defaults/main.yml index ecfdc3b4fb..87efa14886 100644 --- a/roles/test_operator/defaults/main.yml +++ b/roles/test_operator/defaults/main.yml @@ -42,6 +42,7 @@ cifmw_test_operator_storage_class: "{{ cifmw_test_operator_storage_class_prefix cifmw_test_operator_delete_logs_pod: false cifmw_test_operator_privileged: true cifmw_test_operator_selinux_level: "s0:c478,c978" +cifmw_test_operator_generate_stackviz: true cifmw_test_operator_crs_path: "{{ cifmw_basedir }}/artifacts/test-operator-crs" cifmw_test_operator_log_pod_definition: apiVersion: v1 diff --git a/roles/test_operator/tasks/STACKVIZ_INTEGRATION.md b/roles/test_operator/tasks/STACKVIZ_INTEGRATION.md new file mode 100644 index 0000000000..48cfe282ed --- /dev/null +++ b/roles/test_operator/tasks/STACKVIZ_INTEGRATION.md @@ -0,0 +1,120 @@ +# Stackviz Integration for Tempest Results + +## Overview +This integration automatically generates HTML visualization reports from Tempest test results using Stackviz. The reports are generated automatically after each Tempest run when using the test_operator role. + +## Files Modified/Created + +### New Files +- `tasks/generate-stackviz.yml` - Main task file that handles stackviz HTML generation + +### Modified Files +- `tasks/run-test-operator-job.yml` - Added include statement to call stackviz generation after log collection +- `defaults/main.yml` - Added `cifmw_test_operator_generate_stackviz` configuration variable + +## How It Works + +1. **After tempest completes**, logs are collected from the test-operator PVCs +2. **The script searches** for `tempest_results.subunit.gz` in the artifacts directory +3. **Decompresses** the gzipped subunit file +4. **Runs stackviz-export** to convert subunit data to interactive HTML +5. **Stores the HTML report** in `/stackviz/html/index.html` + +## Configuration + +### Enable/Disable Stackviz Generation +```yaml +# In your scenario file or playbook variables +cifmw_test_operator_generate_stackviz: true # Default: true +``` + +Set to `false` to disable stackviz generation. + +## Output Location + +After a successful tempest run, the stackviz HTML report will be available at: +``` +~/ci-framework-data/tests/test_operator/stackviz/html/index.html +``` + +You can open this file directly in a web browser: +```bash +firefox ~/ci-framework-data/tests/test_operator/stackviz/html/index.html +``` + +Or via file:// URL in your browser. + +## Dependencies + +The role will automatically install required dependencies: +- `python3-pip` (system package) +- `stackviz` (Python package via pip) + +## Integration with CI/CD Artifacts + +To publish the stackviz HTML to your CI/CD system, you can add a task after the test_operator role runs: + +### Example: Publishing to Jenkins/Zuul Artifacts +```yaml +- name: Upload stackviz HTML to artifacts storage + ansible.builtin.copy: + src: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz/" + dest: "{{ zuul.executor.log_root }}/stackviz/" + remote_src: true + when: stackviz_html_path is defined +``` + +### Example: Publishing to S3/Swift +```yaml +- name: Upload stackviz to object storage + amazon.aws.s3_sync: + bucket: "{{ ci_artifacts_bucket }}" + file_root: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz/html" + key_prefix: "tempest-results/{{ zuul.build }}/stackviz" + when: stackviz_html_path is defined +``` + +## Troubleshooting + +### Subunit file not found +If you see the warning "No tempest_results.subunit.gz file found", check: +1. Tempest actually ran and completed +2. Logs were successfully collected from the PVCs +3. The expected file path: `{{ cifmw_test_operator_artifacts_basedir }}/**/tempest_results.subunit.gz` + +### Stackviz export failed +Check the ansible output for the error message. Common issues: +- Corrupted subunit file +- Incompatible stackviz version +- Insufficient disk space + +### Installation failures +If stackviz installation fails: +```bash +# Manually install stackviz +sudo pip3 install stackviz + +# Or use a specific version +sudo pip3 install stackviz==0.28 +``` + +## Example Usage + +```yaml +- name: Run tempest tests with stackviz + hosts: controller + vars: + cifmw_test_operator_generate_stackviz: true + cifmw_test_operator_artifacts_basedir: "/home/zuul/tempest-artifacts" + roles: + - test_operator +``` + +## Future Enhancements + +Potential improvements for this integration: +1. Add support for comparing multiple test runs +2. Integration with ReportPortal for centralized test reporting +3. Automatic upload to centralized artifact storage +4. Email notifications with stackviz report links +5. Support for other test frameworks (tobiko, etc.) diff --git a/roles/test_operator/tasks/generate-stackviz.yml b/roles/test_operator/tasks/generate-stackviz.yml new file mode 100644 index 0000000000..7a5b2d739a --- /dev/null +++ b/roles/test_operator/tasks/generate-stackviz.yml @@ -0,0 +1,154 @@ +--- +# Copyright Red Hat, Inc. +# 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. + +- name: Generate stackviz HTML from tempest results + when: + - not cifmw_test_operator_dry_run | bool + - cifmw_test_operator_generate_stackviz | default(true) | bool + - run_test_fw == 'tempest' + block: + - name: Find tempest_results.subunit.gz file in collected logs + ansible.builtin.find: + paths: "{{ cifmw_test_operator_artifacts_basedir }}" + patterns: "tempest_results.subunit.gz" + file_type: file + recurse: true + register: subunit_files + + - name: Process stackviz generation + when: subunit_files.matched > 0 + block: + - name: Set subunit file path + ansible.builtin.set_fact: + tempest_subunit_gz: "{{ subunit_files.files[0].path }}" + + - name: Display subunit file location + ansible.builtin.debug: + msg: "Found tempest subunit file at: {{ tempest_subunit_gz }}" + + - name: Create stackviz output directory + ansible.builtin.file: + path: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz" + state: directory + mode: "0755" + + - name: Check if stackviz is installed + ansible.builtin.command: which stackviz-export + register: stackviz_check + failed_when: false + changed_when: false + + - name: Install stackviz + when: stackviz_check.rc != 0 + block: + - name: Ensure pip is available + ansible.builtin.package: + name: python3-pip + state: present + become: true + + - name: Install stackviz via pip + ansible.builtin.pip: + name: stackviz + state: present + executable: pip3 + become: true + + - name: Decompress subunit file + ansible.builtin.command: + cmd: > + gunzip -c {{ tempest_subunit_gz }} + chdir: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz" + register: decompressed_subunit + changed_when: false + + - name: Write decompressed subunit to file + ansible.builtin.copy: + content: "{{ decompressed_subunit.stdout }}" + dest: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz/tempest_results.subunit" + mode: "0644" + + - name: Check if decompressed subunit file exists + ansible.builtin.stat: + path: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz/tempest_results.subunit" + register: subunit_file + + - name: Generate stackviz HTML from subunit file + when: subunit_file.stat.exists + block: + - name: Run stackviz-export + ansible.builtin.command: + cmd: > + stackviz-export + {{ cifmw_test_operator_artifacts_basedir }}/stackviz/tempest_results.subunit + {{ cifmw_test_operator_artifacts_basedir }}/stackviz/html + chdir: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz" + register: stackviz_export + failed_when: false + + - name: Display stackviz export status + ansible.builtin.debug: + msg: | + Stackviz export completed with return code: {{ stackviz_export.rc }} + {% if stackviz_export.rc == 0 %} + HTML report available at: {{ cifmw_test_operator_artifacts_basedir }}/stackviz/html/index.html + {% else %} + Stackviz export failed. Check logs for details. + Output: {{ stackviz_export.stdout }} + Error: {{ stackviz_export.stderr }} + {% endif %} + + - name: Set stackviz HTML path fact + when: stackviz_export.rc == 0 + ansible.builtin.set_fact: + stackviz_html_path: "{{ cifmw_test_operator_artifacts_basedir }}/stackviz/html/index.html" + + - name: Verify stackviz HTML was generated + when: stackviz_export.rc == 0 + ansible.builtin.stat: + path: "{{ stackviz_html_path }}" + register: stackviz_html + + - name: Display success message + when: + - stackviz_export.rc == 0 + - stackviz_html.stat.exists + ansible.builtin.debug: + msg: | + ======================================== + Stackviz HTML Report Generated Successfully! + ======================================== + Location: {{ stackviz_html_path }} + + To view the report, open the following file in your browser: + file://{{ stackviz_html_path }} + ======================================== + + - name: Warn if decompressed subunit file was not created + when: not subunit_file.stat.exists + ansible.builtin.debug: + msg: | + WARNING: Decompressed subunit file was not created. + This may indicate an issue with decompressing {{ tempest_subunit_gz }}. + Skipping stackviz generation. + + - name: Warn if no subunit file found + when: subunit_files.matched == 0 + ansible.builtin.debug: + msg: | + WARNING: No tempest_results.subunit.gz file found in tempest logs. + Stackviz HTML generation skipped. + Expected location: {{ cifmw_test_operator_artifacts_basedir }}/**/tempest_results.subunit.gz diff --git a/roles/test_operator/tasks/run-test-operator-job.yml b/roles/test_operator/tasks/run-test-operator-job.yml index 66e8adaec9..77e67811f9 100644 --- a/roles/test_operator/tasks/run-test-operator-job.yml +++ b/roles/test_operator/tasks/run-test-operator-job.yml @@ -79,6 +79,9 @@ - not testpod_timed_out ansible.builtin.include_tasks: collect-logs.yaml + - name: Generate stackviz HTML report from tempest results + ansible.builtin.include_tasks: generate-stackviz.yml + - name: Get list of all pods kubernetes.core.k8s_info: kubeconfig: "{{ cifmw_openshift_kubeconfig }}" From 91fb448d349c8907c826a136bd01cde01f643770 Mon Sep 17 00:00:00 2001 From: sauragar Date: Thu, 29 Jan 2026 19:44:50 +0530 Subject: [PATCH 2/2] Address review feedback for stackviz integration - Remove unnecessary stackviz installation check (pip is idempotent) - Update success message to reference artifacts path instead of local file URL for Zuul CI context Co-Authored-By: Claude Sonnet 4.5 --- .../test_operator/tasks/generate-stackviz.yml | 38 +++++++------------ 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/roles/test_operator/tasks/generate-stackviz.yml b/roles/test_operator/tasks/generate-stackviz.yml index 7a5b2d739a..0bc784d58b 100644 --- a/roles/test_operator/tasks/generate-stackviz.yml +++ b/roles/test_operator/tasks/generate-stackviz.yml @@ -45,27 +45,18 @@ state: directory mode: "0755" - - name: Check if stackviz is installed - ansible.builtin.command: which stackviz-export - register: stackviz_check - failed_when: false - changed_when: false - - - name: Install stackviz - when: stackviz_check.rc != 0 - block: - - name: Ensure pip is available - ansible.builtin.package: - name: python3-pip - state: present - become: true - - - name: Install stackviz via pip - ansible.builtin.pip: - name: stackviz - state: present - executable: pip3 - become: true + - name: Ensure pip is available + ansible.builtin.package: + name: python3-pip + state: present + become: true + + - name: Install stackviz via pip + ansible.builtin.pip: + name: stackviz + state: present + executable: pip3 + become: true - name: Decompress subunit file ansible.builtin.command: @@ -131,10 +122,7 @@ ======================================== Stackviz HTML Report Generated Successfully! ======================================== - Location: {{ stackviz_html_path }} - - To view the report, open the following file in your browser: - file://{{ stackviz_html_path }} + Report available in artifacts: stackviz/html/index.html ======================================== - name: Warn if decompressed subunit file was not created