halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
| 3 | # Copyright 2024 Nordix Foundation. |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | # you may not use this file except in compliance with the License. |
| 7 | # You may obtain a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | # See the License for the specific language governing permissions and |
| 15 | # limitations under the License. |
| 16 | # |
| 17 | |
| 18 | set -o errexit # Exit on most errors |
| 19 | set -o nounset # Disallow expansion of unset variables |
| 20 | set -o pipefail # Use last non-zero exit code in a pipeline |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 21 | set -o xtrace # Trace logging |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 22 | |
| 23 | ############################################################################################################################# |
| 24 | ################################################ F U N C T I O N S ########################################################## |
| 25 | ############################################################################################################################# |
| 26 | |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 27 | JENKINS_JOB_URL="https://jenkins.nordix.org/job/onap-cps-performance-test-k6" |
| 28 | |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 29 | latestRecordedBuild="" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 30 | formattedTimestampOfLatestRecordedBuild="" |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 31 | |
| 32 | # Get last completed build number |
| 33 | # The number has not been plotted on the graphs yet |
| 34 | getLastCompletedBuildNumber() { |
| 35 | curl -s "${JENKINS_JOB_URL}/lastCompletedBuild/buildNumber" |
| 36 | } |
| 37 | |
| 38 | # Get the last recorded build number from local workspace of the jenkins |
| 39 | # The number has already been plotted on the graphs |
| 40 | getLastRecordedBuildNumber() { |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 41 | local file_name="data/1.csv" |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 42 | if [ -f "$file_name" ]; then |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 43 | tail -n 1 "$file_name" | cut -d, -f1 |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 44 | else |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 45 | echo 0 |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 46 | fi |
| 47 | } |
| 48 | |
| 49 | # Get all builds numbers |
| 50 | getAllBuildNumbers() { |
| 51 | curl -s "${JENKINS_JOB_URL}/api/json?tree=allBuilds\[id\]" | jq -r '.allBuilds[].id' | sort -n |
| 52 | } |
| 53 | |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 54 | # Extract CSV results from the console text of k6 performance job |
| 55 | getSummaryCsv() { |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 56 | buildToRead=$1 |
| 57 | consoleURL="${JENKINS_JOB_URL}/${buildToRead}/consoleText" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 58 | # Extract summary CSV from Jenkins console output |
| 59 | curl -s "$consoleURL" | sed -n '/-- BEGIN CSV REPORT/, /-- END CSV REPORT/p' | grep "^[1-9].*,.*,.*,.*,.*$" || true |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | # Get and record the latest k6-job-results with the build number for all tests |
| 63 | getAndRecordPerformanceJobResultForBuild() { |
| 64 | buildNumber="$1" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 65 | getSummaryCsv "$buildNumber" > summary.csv |
| 66 | if [ -s summary.csv ]; then |
| 67 | # Store the test cases, names, and units |
| 68 | cut -d, -f1,2,3 summary.csv > test-cases.csv |
| 69 | # Process each row in the CSV, storing the limit and actual value for this build |
| 70 | while IFS=, read -r test_case test_name units limit actual; do |
| 71 | echo "$buildNumber,$limit,$actual" >> "data/$test_case.csv" |
| 72 | done < summary.csv |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 73 | else |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 74 | # No CSV data for this build, so record zeroes for this build in each existing data file |
| 75 | for dataFile in data/*.csv; do |
| 76 | echo "$buildNumber,0,0" >> "$dataFile" |
| 77 | done |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 78 | fi |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 79 | recordLatestRecordedBuild "$buildNumber" |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | # Format the date and time of the latest build |
| 83 | recordLatestRecordedBuild() { |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 84 | local latestBuildToRecord="$1" |
| 85 | local timestampOfLatestRecordedBuild |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 86 | timestampOfLatestRecordedBuild=$(curl -s "${JENKINS_JOB_URL}/${latestBuildToRecord}/api/json?tree=timestamp" | jq -r '.timestamp') |
| 87 | formattedTimestampOfLatestRecordedBuild=$(date -d "@$((timestampOfLatestRecordedBuild / 1000))" "+%B %e, %Y at %H:%M") |
| 88 | latestRecordedBuild=$latestBuildToRecord |
| 89 | } |
| 90 | |
| 91 | # Plot the image (graph) in png format |
| 92 | buildPlotImage() { |
| 93 | dataFile="$1" |
| 94 | chartFileName="$2" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 95 | units="$3" |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 96 | |
danielhanrahan | ea51278 | 2024-08-01 11:14:13 +0100 | [diff] [blame^] | 97 | y_max=$(findMaxPlotRange "$dataFile") |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 98 | |
| 99 | # Create a temporary Gnuplot script |
| 100 | cat <<EOT >gnuplot_script.gp |
| 101 | set datafile separator "," |
| 102 | set terminal pngcairo size 1500,600 |
| 103 | set output "${chartFileName}" |
| 104 | set xlabel "Build" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 105 | set ylabel "${units}" |
danielhanrahan | ea51278 | 2024-08-01 11:14:13 +0100 | [diff] [blame^] | 106 | set yrange [0 : ${y_max} < *] |
halil.cakal | 7ae8934 | 2024-06-14 17:28:29 +0100 | [diff] [blame] | 107 | set xtics rotate |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 108 | plot '$dataFile' using 1:3:xtic(sprintf("%d", column(1))) with linespoints title "measured", \ |
| 109 | '$dataFile' using 1:2 with lines linestyle 2 title "limit" |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 110 | EOT |
| 111 | |
| 112 | # Run the temporary Gnuplot script |
| 113 | gnuplot gnuplot_script.gp |
| 114 | |
| 115 | # Remove the temporary Gnuplot script |
| 116 | rm gnuplot_script.gp |
| 117 | } |
| 118 | |
danielhanrahan | ea51278 | 2024-08-01 11:14:13 +0100 | [diff] [blame^] | 119 | # Set upper limit of the graphs to 20% bigger than largest value to have more space above the plot |
| 120 | findMaxPlotRange() { |
| 121 | dataFile="$1" |
| 122 | awk -F, '{ |
| 123 | if ($2 > max) max = $2; |
| 124 | if ($3 > max) max = $3; |
| 125 | } END { |
| 126 | print max * 1.2; |
| 127 | }' "$dataFile" |
| 128 | } |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 129 | ############################################################################################################################# |
| 130 | ################################################ M A I N #################################################################### |
| 131 | ############################################################################################################################# |
| 132 | |
| 133 | # Install dependencies |
| 134 | sudo apt-get install -y bc gnuplot jq |
| 135 | |
| 136 | # Download data from CPS performance Jenkins job |
| 137 | cd "$WORKSPACE" |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 138 | if [ ! -d data ]; then |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 139 | # If workspace is empty, pull data from all previous performance job runs |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 140 | mkdir -p data |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 141 | for buildNumber in $(getAllBuildNumbers); do |
| 142 | getAndRecordPerformanceJobResultForBuild "$buildNumber" |
| 143 | done |
| 144 | else |
| 145 | # Append new data from latest jobs run |
| 146 | lastCompletedBuildNumber=$(getLastCompletedBuildNumber) |
| 147 | lastRecordedBuildNumber=$(getLastRecordedBuildNumber) |
| 148 | # Check if last completed build number is greater than last recorded build number |
| 149 | if [ "$lastCompletedBuildNumber" -gt "$lastRecordedBuildNumber" ]; then |
| 150 | for ((i = lastRecordedBuildNumber + 1; i <= lastCompletedBuildNumber; i++)); do |
| 151 | # Process the new builds which hasn't been recorded yet |
| 152 | getAndRecordPerformanceJobResultForBuild "$i" |
| 153 | done |
| 154 | else |
| 155 | echo "No new builds to process." |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 156 | exit |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 157 | fi |
| 158 | fi |
| 159 | |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 160 | reportTitle="k6 tests performance review" |
| 161 | outputFile="k6TestsPerformanceReview.html" |
| 162 | cat <<EOT >"$outputFile" |
| 163 | <!DOCTYPE html> |
| 164 | <html> |
| 165 | <head> |
| 166 | <title>$reportTitle</title> |
| 167 | </head> |
| 168 | <body> |
| 169 | <h1 style="text-align: center;">$reportTitle</h1> |
| 170 | <h4>Last updated for performance job build no. $latestRecordedBuild on $formattedTimestampOfLatestRecordedBuild</h4> |
| 171 | <table align="center"> |
| 172 | EOT |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 173 | |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 174 | # Loop through the tests to generate the HTML rows which consists of the plot-image |
| 175 | while IFS=, read -r test_case test_name units; do |
| 176 | dataFile="data/$test_case.csv" |
| 177 | # Limit the plots to last 100 builds for each test |
| 178 | tail -n 100 "$dataFile" > file.tmp && mv file.tmp "$dataFile" |
| 179 | # Plot image files in png format |
| 180 | buildPlotImage "$dataFile" "data/$test_case.png" "$units" |
| 181 | # Output to HTML |
| 182 | cat <<EOF >>"$outputFile" |
| 183 | <tr> |
| 184 | <td align="center" style="padding: 10px;"> |
| 185 | <figcaption>$test_case. $test_name ($units)</figcaption> |
| 186 | <img src="data/$test_case.png" width="750" height="300"> |
| 187 | </td> |
| 188 | </tr> |
| 189 | EOF |
| 190 | done < test-cases.csv |
halil.cakal | 25ff8e8 | 2024-05-31 11:18:54 +0100 | [diff] [blame] | 191 | |
danielhanrahan | 913c6ea | 2024-06-28 18:14:14 +0100 | [diff] [blame] | 192 | # Close the HTML file |
| 193 | cat <<EOT >>"$outputFile" |
| 194 | </table> |
| 195 | <p>The plots are generated from the output of the Nordix Jenkins job: |
| 196 | <a href="https://jenkins.nordix.org/job/onap-cps-performance-test-k6/">onap-cps-performance-test-k6</a>.</p> |
| 197 | <p>The k6 performance tests run are described in the |
| 198 | <a href="https://wiki.onap.org/display/DW/CPS-391Spike%3A+Define+and+Agree+NCMP+REST+Interface#CPS391Spike:DefineandAgreeNCMPRESTInterface-Characteristics">NCMP REST Interface Characteristics</a> documentation.</p> |
| 199 | </body> |
| 200 | </html> |
| 201 | EOT |