Skip to content

Commit b9eb505

Browse files
dkaras-splunkawownysz-splunk
authored andcommitted
feat: upgrade tests (#344)
TA-> TA Upgrade implementation ADDON-73792 This pull request introduces a new feature to our CI/CD pipeline, focusing on automating upgrade testing for Technology Add-ons (TA). The goal is to streamline the release process by incorporating scalable and user-friendly solutions capable of executing upgrade scenarios Key Features: Automated Upgrade Testing: Introduces jobs for upgrade testing within the GitHub CI/CD pipeline. Flexible Version Testing: Allows users to provide multiple TA versions on which upgrade tests should be executed. In this repo, ta_upgrade_version parameter is responsible for passing the info about versions being tested. Also, both GitHub and Splunkbase releases are supported, depending on the format of the version string provided: vX.X.X - for GitHub releases X.X.X - for Splunkbase releases additionally, latest can be passed to use the latest version from GitHub example run - https://github.com/splunk/splunk-add-on-for-amazon-web-services/actions/runs/12045945177 Part of splunk/ta-automation-app-of-apps#27 splunk/ta-automation-k8s-manifests#102 splunk/wfe-test-runner-action#35 --------- Co-authored-by: Adam Wownysz <[email protected]>
1 parent 5a2bfdb commit b9eb505

File tree

1 file changed

+289
-5
lines changed

1 file changed

+289
-5
lines changed

.github/workflows/reusable-build-test-release.yml

Lines changed: 289 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ on:
4646
type: string
4747
default: >-
4848
["ubuntu:14.04", "ubuntu:16.04","ubuntu:18.04","ubuntu:22.04", "ubuntu:24.04", "redhat:8.4", "redhat:8.5", "redhat:8.6", "redhat:8.8"]
49+
upgrade-tests-ta-versions:
50+
required: false
51+
description: "List with TA versions (in 'X.X.X' format) that should be used as starting points for upgrade tests. If not provided,
52+
the latest TA version will be used. Example: ['7.6.0', '7.7.0']"
53+
type: string
54+
default: >-
55+
["latest"]
4956
secrets:
5057
GH_TOKEN_ADMIN:
5158
description: Github admin token
@@ -120,6 +127,7 @@ jobs:
120127
execute-ucc-modinput-labeled: ${{ steps.configure-tests-on-labels.outputs.execute_ucc_modinput_functional_labeled }}
121128
execute-scripted_inputs-labeled: ${{ steps.configure-tests-on-labels.outputs.execute_scripted_inputs_labeled }}
122129
execute-requirement-labeled: ${{ steps.configure-tests-on-labels.outputs.execute_requirement_test_labeled }}
130+
execute-upgrade-labeled: ${{ steps.configure-tests-on-labels.outputs.execute_upgrade_test_labeled }}
123131
s3_bucket_k8s: ${{ steps.k8s-environment.outputs.s3_bucket }}
124132
argo_server_domain_k8s: ${{ steps.k8s-environment.outputs.argo_server_domain }}
125133
argo_token_secret_id_k8s: ${{ steps.k8s-environment.outputs.argo_token_secret_id }}
@@ -148,7 +156,7 @@ jobs:
148156
run: |
149157
set +e
150158
declare -A EXECUTE_LABELED
151-
TESTSET=("execute_knowledge" "execute_ui" "execute_modinput_functional" "execute_ucc_modinput_functional" "execute_scripted_inputs" "execute_requirement_test")
159+
TESTSET=("execute_knowledge" "execute_ui" "execute_modinput_functional" "execute_ucc_modinput_functional" "execute_scripted_inputs" "execute_requirement_test" "execute_upgrade")
152160
for test_type in "${TESTSET[@]}"; do
153161
EXECUTE_LABELED["$test_type"]="false"
154162
done
@@ -164,7 +172,10 @@ jobs:
164172
done
165173
elif ${{ github.base_ref == 'main' }} || ${{ contains(github.event.pull_request.labels.*.name, 'execute_all_tests') }}; then
166174
for test_type in "${TESTSET[@]}"; do
167-
EXECUTE_LABELED["$test_type"]="true"
175+
# Exclude upgrade tests on PRs to main
176+
if [[ "$test_type" != "execute_upgrade" ]]; then
177+
EXECUTE_LABELED["$test_type"]="true"
178+
fi
168179
done
169180
else
170181
for test_type in "${TESTSET[@]}"; do
@@ -178,19 +189,28 @@ jobs:
178189
if ${{ github.ref_name == 'main' }} || ${{ github.ref_name == 'develop' }} ||
179190
${{ startsWith(github.ref_name, 'release/') && inputs.execute-tests-on-push-to-release == 'true' }} ; then
180191
for test_type in "${TESTSET[@]}"; do
181-
EXECUTE_LABELED["$test_type"]="true"
192+
# Exclude upgrade tests on push to main
193+
if [[ "$test_type" != "execute_upgrade" ]]; then
194+
EXECUTE_LABELED["$test_type"]="true"
195+
fi
182196
done
183197
fi
184198
;;
185199
"schedule")
186200
for test_type in "${TESTSET[@]}"; do
187-
EXECUTE_LABELED["$test_type"]="true"
201+
# Exclude upgrade tests in scheduled runs
202+
if [[ "$test_type" != "execute_upgrade" ]]; then
203+
EXECUTE_LABELED["$test_type"]="true"
204+
fi
188205
done
189206
;;
190207
"workflow_dispatch")
191208
if ${{ inputs.custom-version != '' }} ; then
192209
for test_type in "${TESTSET[@]}"; do
193-
EXECUTE_LABELED["$test_type"]="true"
210+
# Exclude upgrade tests in custom releases
211+
if [[ "$test_type" != "execute_upgrade" ]]; then
212+
EXECUTE_LABELED["$test_type"]="true"
213+
fi
194214
done
195215
fi
196216
;;
@@ -345,6 +365,7 @@ jobs:
345365
requirement_test: ${{ steps.testset.outputs.requirement_test }}
346366
scripted_inputs: ${{ steps.testset.outputs.scripted_inputs }}
347367
ucc_modinput_functional: ${{ steps.testset.outputs.ucc_modinput_functional }}
368+
upgrade: ${{ steps.testset.outputs.upgrade }}
348369
steps:
349370
- uses: actions/checkout@v4
350371
- id: testset
@@ -2545,6 +2566,269 @@ jobs:
25452566
with:
25462567
name: |
25472568
summary-ucc_modinput*
2569+
2570+
run-upgrade-tests:
2571+
if: ${{ !cancelled() && needs.build.result == 'success' && needs.test-inventory.outputs.upgrade == 'true' }}
2572+
needs:
2573+
- build
2574+
- test-inventory
2575+
- setup
2576+
- meta
2577+
- setup-workflow
2578+
runs-on: ubuntu-latest
2579+
strategy:
2580+
fail-fast: false
2581+
matrix:
2582+
splunk: ${{ fromJson(needs.meta.outputs.matrix_supportedSplunk) }}
2583+
vendor-version: ${{ fromJson(needs.meta.outputs.matrix_supportedModinputFunctionalVendors) }}
2584+
ta-version-from-upgrade: ${{ fromJson(inputs.upgrade-tests-ta-versions) }}
2585+
container:
2586+
image: ghcr.io/splunk/workflow-engine-base:4.1.0
2587+
env:
2588+
ARGO_SERVER: ${{ needs.setup.outputs.argo-server }}
2589+
ARGO_HTTP1: ${{ needs.setup.outputs.argo-http1 }}
2590+
ARGO_SECURE: ${{ needs.setup.outputs.argo-secure }}
2591+
ARGO_BASE_HREF: ${{ needs.setup.outputs.argo-href }}
2592+
ARGO_NAMESPACE: ${{ needs.setup.outputs.argo-namespace }}
2593+
SPLUNK_VERSION_BASE: ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }}
2594+
TEST_TYPE: "upgrade"
2595+
TEST_ARGS: ""
2596+
permissions:
2597+
actions: read
2598+
deployments: read
2599+
contents: read
2600+
packages: read
2601+
statuses: read
2602+
checks: write
2603+
steps:
2604+
- uses: actions/checkout@v4
2605+
with:
2606+
submodules: recursive
2607+
- name: configure git # This step configures git to omit "dubious git ownership error" in later test-reporter stage
2608+
id: configure-git
2609+
run: |
2610+
git --version
2611+
git_path="$(pwd)"
2612+
echo "$git_path"
2613+
git config --global --add safe.directory "$git_path"
2614+
- name: capture start time
2615+
id: capture-start-time
2616+
run: |
2617+
echo "start_time=$(date +%s)" >> "$GITHUB_OUTPUT"
2618+
- name: Configure AWS credentials
2619+
uses: aws-actions/configure-aws-credentials@v4
2620+
with:
2621+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
2622+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
2623+
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
2624+
- name: Read secrets from AWS Secrets Manager into environment variables
2625+
id: get-argo-token
2626+
run: |
2627+
ARGO_TOKEN=$(aws secretsmanager get-secret-value --secret-id "${{ needs.setup-workflow.outputs.argo_token_secret_id_k8s }}" | jq -r '.SecretString')
2628+
echo "argo-token=$ARGO_TOKEN" >> "$GITHUB_OUTPUT"
2629+
- name: create job name
2630+
id: create-job-name
2631+
shell: bash
2632+
run: |
2633+
RANDOM_STRING=$(head -3 /dev/urandom | tr -cd '[:lower:]' | cut -c -4)
2634+
JOB_NAME=${{ needs.setup.outputs.job-name }}-${RANDOM_STRING}
2635+
JOB_NAME=${JOB_NAME//TEST-TYPE/${{ env.TEST_TYPE }}}
2636+
JOB_NAME=${JOB_NAME//[_.]/-}
2637+
JOB_NAME=$(echo "$JOB_NAME" | tr '[:upper:]' '[:lower:]')
2638+
echo "job-name=$JOB_NAME" >> "$GITHUB_OUTPUT"
2639+
- name: run-tests
2640+
id: run-tests
2641+
timeout-minutes: 340
2642+
continue-on-error: true
2643+
env:
2644+
ARGO_TOKEN: ${{ steps.get-argo-token.outputs.argo-token }}
2645+
uses: splunk/wfe-test-runner-action@feat/ADDON-73868-add-inputs-for-upgrade-tests # TODO: add correct branch name
2646+
with:
2647+
splunk: ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }}
2648+
test-type: ${{ env.TEST_TYPE }}
2649+
test-args: ${{ env.TEST_ARGS }}
2650+
job-name: ${{ steps.create-job-name.outputs.job-name }}
2651+
labels: ${{ needs.setup.outputs.labels }}
2652+
workflow-tmpl-name: ${{ needs.setup.outputs.argo-workflow-tmpl-name }}
2653+
workflow-template-ns: ${{ needs.setup.outputs.argo-namespace }}
2654+
addon-url: ${{ needs.setup.outputs.addon-upload-path }}
2655+
addon-name: ${{ needs.setup.outputs.addon-name }}
2656+
vendor-version: ${{ matrix.vendor-version.image }}
2657+
sc4s-version: "No"
2658+
k8s-manifests-branch: ${{ needs.setup.outputs.k8s-manifests-branch }}
2659+
ta-upgrade-version: ${{ matrix.ta-version-from-upgrade }}
2660+
- name: Read secrets from AWS Secrets Manager again into environment variables in case credential rotation
2661+
id: update-argo-token
2662+
if: ${{ !cancelled() }}
2663+
run: |
2664+
ARGO_TOKEN=$(aws secretsmanager get-secret-value --secret-id "${{ needs.setup-workflow.outputs.argo_token_secret_id_k8s }}" | jq -r '.SecretString')
2665+
echo "argo-token=$ARGO_TOKEN" >> "$GITHUB_OUTPUT"
2666+
- name: calculate timeout
2667+
id: calculate-timeout
2668+
run: |
2669+
start_time=${{ steps.capture-start-time.outputs.start_time }}
2670+
current_time=$(date +%s)
2671+
remaining_time_minutes=$(( 350-((current_time-start_time)/60) ))
2672+
echo "remaining_time_minutes=$remaining_time_minutes" >> "$GITHUB_OUTPUT"
2673+
- name: Check if pod was deleted
2674+
id: is-pod-deleted
2675+
timeout-minutes: ${{ fromJson(steps.calculate-timeout.outputs.remaining_time_minutes) }}
2676+
if: ${{ !cancelled() }}
2677+
shell: bash
2678+
env:
2679+
ARGO_TOKEN: ${{ steps.update-argo-token.outputs.argo-token }}
2680+
run: |
2681+
set -o xtrace
2682+
if argo watch ${{ steps.run-tests.outputs.workflow-name }} -n workflows | grep "pod deleted"; then
2683+
echo "retry-workflow=true" >> "$GITHUB_OUTPUT"
2684+
fi
2685+
- name: Cancel workflow
2686+
env:
2687+
ARGO_TOKEN: ${{ steps.get-argo-token.outputs.argo-token }}
2688+
if: ${{ cancelled() || steps.is-pod-deleted.outcome != 'success' }}
2689+
run: |
2690+
cancel_response=$(argo submit -v -o json --from wftmpl/${{ needs.setup.outputs.argo-cancel-workflow-tmpl-name }} -l workflows.argoproj.io/workflow-template=${{ needs.setup.outputs.argo-cancel-workflow-tmpl-name }} --argo-base-href '' -p workflow-to-cancel=${{ steps.run-tests.outputs.workflow-name }})
2691+
cancel_workflow_name=$( echo "$cancel_response" |jq -r '.metadata.name' )
2692+
cancel_logs=$(argo logs --follow "$cancel_workflow_name" -n workflows)
2693+
if echo "$cancel_logs" | grep -q "workflow ${{ steps.run-tests.outputs.workflow-name }} stopped"; then
2694+
echo "Workflow ${{ steps.run-tests.outputs.workflow-name }} stopped"
2695+
else
2696+
echo "Workflow ${{ steps.run-tests.outputs.workflow-name }} didn't stop"
2697+
exit 1
2698+
fi
2699+
- name: Retrying workflow
2700+
id: retry-wf
2701+
shell: bash
2702+
env:
2703+
ARGO_TOKEN: ${{ steps.update-argo-token.outputs.argo-token }}
2704+
if: ${{ !cancelled() }}
2705+
run: |
2706+
set -o xtrace
2707+
set +e
2708+
if [[ "${{ steps.is-pod-deleted.outputs.retry-workflow }}" == "true" ]]
2709+
then
2710+
WORKFLOW_NAME=$(argo resubmit -v -o json -n workflows "${{ steps.run-tests.outputs.workflow-name }}" | jq -r .metadata.name)
2711+
echo "workflow-name=$WORKFLOW_NAME" >> "$GITHUB_OUTPUT"
2712+
argo logs --follow "${WORKFLOW_NAME}" -n workflows || echo "... there was an error fetching logs, the workflow is still in progress. please wait for the workflow to complete ..."
2713+
else
2714+
echo "No retry required"
2715+
argo wait "${{ steps.run-tests.outputs.workflow-name }}" -n workflows
2716+
argo watch "${{ steps.run-tests.outputs.workflow-name }}" -n workflows | grep "test-addon"
2717+
fi
2718+
- name: check if workflow completed
2719+
env:
2720+
ARGO_TOKEN: ${{ steps.update-argo-token.outputs.argo-token }}
2721+
if: ${{ !cancelled() }}
2722+
shell: bash
2723+
run: |
2724+
set +e
2725+
# shellcheck disable=SC2157
2726+
if [ -z "${{ steps.retry-wf.outputs.workflow-name }}" ]; then
2727+
WORKFLOW_NAME=${{ steps.run-tests.outputs.workflow-name }}
2728+
else
2729+
WORKFLOW_NAME="${{ steps.retry-wf.outputs.workflow-name }}"
2730+
fi
2731+
ARGO_STATUS=$(argo get "${WORKFLOW_NAME}" -n workflows -o json | jq -r '.status.phase')
2732+
echo "Status of workflow:" "$ARGO_STATUS"
2733+
while [ "$ARGO_STATUS" == "Running" ] || [ "$ARGO_STATUS" == "Pending" ]
2734+
do
2735+
echo "... argo Workflow ${WORKFLOW_NAME} is running, waiting for it to complete."
2736+
argo wait "${WORKFLOW_NAME}" -n workflows || true
2737+
ARGO_STATUS=$(argo get "${WORKFLOW_NAME}" -n workflows -o json | jq -r '.status.phase')
2738+
done
2739+
- name: pull artifacts from s3 bucket
2740+
if: ${{ !cancelled() }}
2741+
run: |
2742+
echo "pulling artifacts"
2743+
aws s3 cp s3://${{ needs.setup.outputs.s3-bucket }}/artifacts-${{ steps.create-job-name.outputs.job-name }}/${{ steps.create-job-name.outputs.job-name }}.tgz ${{ needs.setup.outputs.directory-path }}/
2744+
tar -xf ${{ needs.setup.outputs.directory-path }}/${{ steps.create-job-name.outputs.job-name }}.tgz -C ${{ needs.setup.outputs.directory-path }}
2745+
- name: pull logs from s3 bucket
2746+
if: ${{ !cancelled() }}
2747+
run: |
2748+
# shellcheck disable=SC2157
2749+
if [ -z "${{ steps.retry-wf.outputs.workflow-name }}" ]; then
2750+
WORKFLOW_NAME=${{ steps.run-tests.outputs.workflow-name }}
2751+
else
2752+
WORKFLOW_NAME="${{ steps.retry-wf.outputs.workflow-name }}"
2753+
fi
2754+
echo "pulling logs"
2755+
mkdir -p ${{ needs.setup.outputs.directory-path }}/argo-logs
2756+
aws s3 cp s3://${{ needs.setup.outputs.s3-bucket }}/${WORKFLOW_NAME}/ ${{ needs.setup.outputs.directory-path }}/argo-logs/ --recursive
2757+
- uses: actions/upload-artifact@v4
2758+
if: ${{ !cancelled() }}
2759+
with:
2760+
name: archive splunk ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }} ${{ env.TEST_TYPE }} ${{ matrix.vendor-version.image }} ${{ matrix.ta-version-from-upgrade }} tests artifacts
2761+
path: |
2762+
${{ needs.setup.outputs.directory-path }}/test-results
2763+
- uses: actions/upload-artifact@v4
2764+
if: ${{ !cancelled() }}
2765+
with:
2766+
name: archive splunk ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }} ${{ env.TEST_TYPE }} ${{ matrix.vendor-version.image }} ${{ matrix.ta-version-from-upgrade }} tests logs
2767+
path: |
2768+
${{ needs.setup.outputs.directory-path }}/argo-logs
2769+
- name: Test Report
2770+
id: test_report
2771+
uses: dorny/[email protected]
2772+
if: ${{ !cancelled() }}
2773+
with:
2774+
name: splunk ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }} ${{ env.TEST_TYPE }} ${{ matrix.vendor-version.image }} test report
2775+
path: "${{ needs.setup.outputs.directory-path }}/test-results/*.xml"
2776+
reporter: java-junit
2777+
- name: Parse JUnit XML
2778+
if: ${{ !cancelled() }}
2779+
run: |
2780+
apt-get install -y libxml2-utils
2781+
junit_xml_path="${{ needs.setup.outputs.directory-path }}/test-results"
2782+
junit_xml_file=$(find "$junit_xml_path" -name "*.xml" -type f 2>/dev/null | head -n 1)
2783+
if [ -n "$junit_xml_file" ]; then
2784+
total_tests=$(xmllint --xpath "count(//testcase)" "$junit_xml_file")
2785+
failures=$(xmllint --xpath "count(//testcase[failure])" "$junit_xml_file")
2786+
errors=$(xmllint --xpath "count(//testcase[error])" "$junit_xml_file")
2787+
skipped=$(xmllint --xpath "count(//testcase[skipped])" "$junit_xml_file")
2788+
passed=$((total_tests - failures - errors - skipped))
2789+
echo "splunk ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }} ${{ matrix.ta-version-from-upgrade }} ${{ matrix.vendor-version.image }} |$total_tests |$passed |$failures |$errors | $skipped |${{steps.test_report.outputs.url_html}}" > job_summary.txt
2790+
else
2791+
echo "no XML File found, exiting"
2792+
exit 1
2793+
fi
2794+
- name: Upload-artifact-for-github-summary
2795+
uses: actions/upload-artifact@v4
2796+
if: ${{ !cancelled() }}
2797+
with:
2798+
name: summary-${{ env.TEST_TYPE }}-${{ matrix.splunk.version }}-${{ secrets.OTHER_TA_REQUIRED_CONFIGS }}-${{ matrix.vendor-version.image }}-${{ matrix.ta-version-from-upgrade }}-artifact
2799+
path: job_summary.txt
2800+
- name: pull diag from s3 bucket
2801+
if: ${{ failure() && steps.test_report.outputs.conclusion == 'failure' }}
2802+
run: |
2803+
echo "pulling diag"
2804+
aws s3 cp s3://${{ needs.setup.outputs.s3-bucket }}/diag-${{ steps.create-job-name.outputs.job-name }}/diag-${{ steps.create-job-name.outputs.job-name }}.tgz ${{ needs.setup.outputs.directory-path }}/
2805+
- uses: actions/upload-artifact@v4
2806+
if: ${{ failure() && steps.test_report.outputs.conclusion == 'failure' }}
2807+
with:
2808+
name: archive splunk ${{ matrix.splunk.version }}${{ secrets.OTHER_TA_REQUIRED_CONFIGS }} ${{ env.TEST_TYPE }} ${{ matrix.vendor-version.image }} tests diag
2809+
path: |
2810+
${{ needs.setup.outputs.directory-path }}/diag*
2811+
2812+
upgrade-tests-report:
2813+
needs: run-upgrade-tests
2814+
runs-on: ubuntu-latest
2815+
if: ${{ !cancelled() && needs.run-upgrade-tests.result != 'skipped' }}
2816+
steps:
2817+
- name: Download all summaries
2818+
uses: actions/download-artifact@v4
2819+
with:
2820+
pattern: summary-upgrade*
2821+
- name: Combine summaries into a table
2822+
run: |
2823+
echo "| Job | Total Tests | Passed Tests | Failed Tests | Errored Tests | Skipped Tests | Report Link" >> "$GITHUB_STEP_SUMMARY"
2824+
echo "| ---------- | ----------- | ------ | ------ | ------ | ------- | ------ |" >> "$GITHUB_STEP_SUMMARY"
2825+
for file in summary-upgrade*/job_summary.txt; do
2826+
cat "$file" >> "$GITHUB_STEP_SUMMARY"
2827+
done
2828+
- uses: geekyeggo/delete-artifact@v5
2829+
with:
2830+
name: |
2831+
summary-upgrade*
25482832
25492833
run-scripted-input-tests-full-matrix:
25502834
if: ${{ !cancelled() && needs.build.result == 'success' && needs.test-inventory.outputs.scripted_inputs == 'true' && needs.setup-workflow.outputs.execute-scripted_inputs-labeled == 'true' }}

0 commit comments

Comments
 (0)