Skip to content

Commit

Permalink
feat(RHTAPBUGS-959): add wait-for-ir script to enable parallel runs
Browse files Browse the repository at this point in the history
The new wait-for-ir script will wait for one or more
InternalRequests to complete. The IR(s) to wait for can
either be specified by a name or using a label selector.

The internal-request script was modified to use this new script
if used in sync mode (-s).

Signed-off-by: Martin Malina <[email protected]>
  • Loading branch information
mmalina committed Dec 14, 2023
1 parent e94a8ea commit 893349e
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 42 deletions.
59 changes: 17 additions & 42 deletions utils/internal-request
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
# InternalRequest resource. The value of the parameter is treated as a string,
# and it can be a valid JSON object or array. When passing complex parameter
# values, make sure to enclose them in quotes.
# -l label: Label value to use for selecting IRs to watch,
# e.g. the TaskRun UID. Optional.
# -s Sync: a flag that indicates whether the script has to finish to complete
# the tasks or exit immediately after creating the resource. Default is true.
# -t Timeout: Defaults to 600 seconds.
Expand All @@ -41,6 +43,8 @@
set -e

TIMEOUT=600
LABEL_KEY="release.appstudio.openshift.io/task-id"
LABEL_VALUE=""
SYNC=true
PARAMS=""

Expand All @@ -51,6 +55,8 @@ function usage {
echo " -p Params: can be specified multiple times. Each '-p' flag represents a"
echo " parameter that will be added to the 'parameters' field in the"
echo " InternalRequest resource."
echo " -l label: Label value to use for selecting IRs to watch,"
echo " e.g. the TaskRun UID. Optional."
echo " -s Sync: a flag that indicates whether the script has to finish to complete the tasks or exit immediately after creating the resource. Default is true."
echo " -t Timeout: Defaults to 600 seconds."
echo " -h Display this help message."
Expand All @@ -60,11 +66,12 @@ function usage {

# Parsing arguments
PARAMS=() # initialize PARAMS as an empty array
while getopts r:p:s:t:h flag
while getopts r:p:l:s:t:h flag
do
case "${flag}" in
r) REQUEST=${OPTARG};;
p) PARAMS+=("${OPTARG}");; # append each parameter to the PARAMS array
l) LABEL_VALUE=${OPTARG};;
s) SYNC=${OPTARG};;
t) TIMEOUT=${OPTARG};;
h) usage;;
Expand Down Expand Up @@ -109,6 +116,12 @@ PAYLOAD=$(jq -n \
}
}'
)
if [ -n $LABEL_VALUE ]; then
PAYLOAD=$(jq \
--arg label_key "$LABEL_KEY" \
--arg label_value "$LABEL_VALUE" \
'.metadata.labels += {($label_key): $label_value}' <<< $PAYLOAD)
fi

# Create InternalRequest using kubectl
RESOURCE=$(echo "$PAYLOAD" | kubectl create -f - -o json)
Expand All @@ -117,46 +130,8 @@ INTERNAL_REQUEST_NAME=$(echo "$RESOURCE" | jq -r '.metadata.name')
echo "InternalRequest '$INTERNAL_REQUEST_NAME' created."

if [ "$SYNC" = "true" ]; then
echo "Sync flag set to true. Waiting for the InternalRequest to be completed."

# Wait until status is set or timeout
END_TIME=$(date -ud "$TIMEOUT seconds" +%s)
while true; do
STATUS=$(kubectl get internalrequest "$INTERNAL_REQUEST_NAME" -o json | jq '.status')

if [ "$STATUS" != "null" ]; then
CONDITIONS=$(kubectl get internalrequest "$INTERNAL_REQUEST_NAME" -o json | jq '.status.conditions')
if [ "$(echo "$CONDITIONS" | jq 'length')" -eq 1 ]; then
CONDITION_REASON=$(echo "$CONDITIONS" | jq -r '.[0].reason')
if [ "$CONDITION_REASON" == "Running" ]; then
continue
else
case $CONDITION_REASON in
"Succeeded")
echo "InternalRequest succeeded"
EXIT_CODE=0
;;
"Failed")
echo "InternalRequest failed"
EXIT_CODE=21
;;
"Rejected")
echo "InternalRequest rejected"
EXIT_CODE=22
;;
esac
echo "Conditions:"
echo $CONDITIONS
exit $EXIT_CODE
fi
fi
fi

if [ "$(date +%s)" -gt "$END_TIME" ]; then
echo "Timeout while waiting for the InternalRequest to complete."
exit 1
fi
echo "Sync flag set to true. Waiting for the InternalRequest to be completed."

sleep 5
done
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
$SCRIPT_DIR/wait-for-ir -n $INTERNAL_REQUEST_NAME -t $TIMEOUT
fi
139 changes: 139 additions & 0 deletions utils/wait-for-ir
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/bin/bash

# This script waits for one or more InternalRequests to complete.
#
# The IRs to watch can be specified either by name or by a label selector.
#
# The script waits for the InternalRequests to reach a 'completed'
# status and will provide an exit code as follows:
# - All succeeded: exit code 0
# - At least one IR failed or rejected: exit code 21
# - Timeout reached: exit code 124
#
# Usage:
# ./wait-for-ir [-n name] [-l label] [-t timeout]
#
# Parameters:
# -n name: The name of the InternalRequest to watch.
# -l label: Label value to use for selecting IRs to watch,
# e.g. the TaskRun UID.
# -t Timeout: Defaults to 600 seconds.
# -h Display this help message.
#
# One of -n or -l has to be specified, but not both.
#
# Prerequisites:
# - kubectl: The Kubernetes command line tool must be installed and properly
# configured to communicate with your cluster.
# - jq: This script uses jq to parse JSON. It must be installed on the system
# running the script.
#
# Note: This script is intended to be used with a specific Kubernetes API
# that includes the 'InternalRequest' resource type.

set -e

NAME=""
LABEL_KEY="release.appstudio.openshift.io/task-id"
LABEL_VALUE=""
TIMEOUT=600

function usage {
echo "Usage: $0 [-n name] [-l label] [-t timeout]"
echo
echo " -n name: The name of the InternalRequest to watch."
echo " -l label: Label value to use for selecting IRs to watch,"
echo " e.g. the TaskRun UID."
echo " -t Timeout: Defaults to 600 seconds."
echo " -h Display this help message."
echo
echo " One of -n or -l has to be specified, but not both."
exit 1
}


function print_conditions {
IRS=$1
IRS_LENGTH=$(jq '. |length' <<< "$IRS")
echo Conditions:
for(( i=0; i<$IRS_LENGTH; i++)); do
echo -n " "$(jq -r ".[$i].metadata.name" <<< "$IRS")": "
jq -c ".[$i].status.conditions" <<< "$IRS"
done
}

# Parsing arguments
while getopts n:l:t:h flag
do
case "${flag}" in
n) NAME=${OPTARG};;
l) LABEL_VALUE=${OPTARG};;
t) TIMEOUT=${OPTARG};;
h) usage;;
*) usage;;
esac
done

# Check that name or label is set, but not both
if [[ -z "$NAME" && -z $LABEL_VALUE || -n $NAME && -n $LABEL_VALUE ]]
then
usage
fi

# Wait until status is set for all IRs or timeout is reached
END_TIME=$(date -ud "$TIMEOUT seconds" +%s)
SUCCESS=true
while true; do
echo Checking IR statuses...
if [ -n "$NAME" ]; then
# Wrap the single IR in a JSON array
IRS=$(kubectl get internalrequest "$NAME" -o json | jq -c '[.]' )
else
IRS=$(kubectl get internalrequest -l"${LABEL_KEY}=${LABEL_VALUE}" -o json | jq -c ".items" )
fi

IRS_LENGTH=$(jq '. |length' <<< "$IRS")
echo Found $IRS_LENGTH InternalRequests matching the name or label
echo Conditions:
DONE_COUNT=0
for(( i=0; i<$IRS_LENGTH; i++)); do
IR=$(jq -c ".[$i]" <<< "$IRS")
CONDITION_REASON=$(jq -r '.status.conditions[0].reason // ""' <<< "$IR")
echo -n " "$(jq -r ".metadata.name" <<< "$IR")": "
if [ -z $CONDITION_REASON ]; then
echo "no condition yet"
elif [ $CONDITION_REASON = "Running" ]; then
echo "running"
elif [ $CONDITION_REASON = "Succeeded" ]; then
echo "succeeded"
((++DONE_COUNT))
else
echo $CONDITION_REASON
((++DONE_COUNT))
SUCCESS=false
fi
done

if [ $DONE_COUNT -eq $IRS_LENGTH ]; then
echo All InternalRequests have been completed
if [ $SUCCESS = true ]; then
print_conditions "$IRS"
echo Result: success
exit 0
else
echo ERROR: At least one InternalRequest failed
print_conditions "$IRS"
echo Result: failure
exit 21
fi
fi

if [ "$(date +%s)" -gt "$END_TIME" ]; then
echo "ERROR: Timeout while waiting for the InternalRequests to complete"
print_conditions "$IRS"
echo result: timeout
exit 124
fi

sleep 5
done

0 comments on commit 893349e

Please sign in to comment.