This blog post is a CheatSheet about how to loop an endpoint of an application running on IBM Cloud Code Engine with a bash automation.
1. Objectives
The following list contains the main objectives for the loop automation of an endpoint for an application running on IBM Cloud Code Engine.
- Invoke a REST endpoint.
- Loop the invocation to all entries in a CSV file.
- Create files to save values, one for a detailed error log and one for the endpoint invocation results.
These are the main values to save:- Response time for the endpoint invocation.
- Get a specific return value of the response in the JSON format.
- Save the detailed information about the container running on IBM Cloud Code Engine in case an error occurs.
- Use kubectl command and the IBM Cloud Code Engine CLI to log the detailed information.
2. Overall
The following list is an overall overview of all the steps implemented in the automation.
- 1. Connect to IBM Cloud Code Engine.
- 2. Initialization of the output files.
- 3. Loop the questions in the question input file.
- 3.1 Start a timer to log the time from the request to the response of the HTTP rest call.
- 3.2 Ensure that CSV file column headers are not used to invoke the endpoint.
- 3.3 Save the HTTP response to a file.
- 3.4 Define the JSON path of the return value you want to verify.
- 3.4a (optional) Show the extracted and raw content if needed for debugging.
- 3.6 In case the wrong value is found, inspect the error logs of Code Engine and log them to a file.
- 3.7 End timer and calculate the response time.
- 3.8 Create a date time-stamp for the log file.
- 3.9 Write the logging information to a file.
3. Input files
We use two input files:
- One for the environment variables as .env file.
- One for the invocation values of the REST endpoint as a CSV file.
3.1 CSV file
The input file contains the values we will loop by the invocation of the endpoint.
- The input file CSV format:
CE_HOST,QUESTION,API_CALL,API_KEY
my_endpoint.XXXX.us-east.codeengine.appdomain.cloud,MY QUESTION?,my_api_call,BASIC_AUTH_KEY
3.2 .env file
We have an environment file to define additional configurations.
export IBM_CLOUD_RESOURCE_GROUP=MY_RESOURCE_GROUP
export IBM_CLOUD_REGION=us-east
export IBM_CLOUD_API_KEY=
export CODEENGINE_PROJECT_NAME=MY_CODE_ENGINE_PROJECT
export CE_DOMAIN=.MY_DOMAIN.us-east.codeengine.appdomain.cloud
4. Source Code
This is the source code for the bash automation.
The bash file has following organizational structure:
- Variables
- Functions definition
- Execution
#!/bin/bash
# **********************************************************************************
# Variables
# **********************************************************************************
# IBM Cloud - variables
source ./.env
# Input variables
LOG_FILE=${1}
CSV_FILE=${2}
ERROR_LOG_FILE=${3}
CSV_ANSWER_FILE=${4}
# Local variables
j=0
CSV_HEADER=1
OUTPUT_CHECK=MY_VERIFICATION_VALUE
TMP_FILE=tmp.json
# **********************************************************************************
# Functions definition
# **********************************************************************************
function login_to_ibm_cloud () {
echo ""
echo "*********************"
echo "Log in to IBM Cloud"
echo "*********************"
echo ""
ibmcloud login --apikey $IBM_CLOUD_API_KEY
ibmcloud target -r $IBM_CLOUD_REGION
ibmcloud target -g $IBM_CLOUD_RESOURCE_GROUP
}
function connect_ce_project() {
echo "**********************************"
echo " Using following project: $CODEENGINE_PROJECT_NAME"
echo "**********************************"
# 1. Connect to IBM Cloud Code Engine project
ibmcloud ce project select -n $CODEENGINE_PROJECT_NAME
# 2. Get the kubecfg to connect to the related cluster
ibmcloud ce project select -n $CODEENGINE_PROJECT_NAME --kubecfg
# 3. Get the project namespace
CODEENGINE_PROJECT_NAMESPACE=$(ibmcloud ce project get --name $CODEENGINE_PROJECT_NAME --output json | grep "namespace" | awk '{print $2;}' | sed 's/"//g' | sed 's/,//g')
echo "Code Engine project namespace: $CODEENGINE_PROJECT_NAMESPACE"
# 4. List all running pods
kubectl get pods -n $CODEENGINE_PROJECT_NAMESPACE
}
# **** Kubernetes CLI ****
function kube_information(){
echo "************************************"
echo " Kubernetes info '$CODEENGINE_APP_NAME': pods, deployments and configmaps details "
echo "************************************"
kubectl get pods -n $CODEENGINE_PROJECT_NAMESPACE
kubectl get deployments -n $CODEENGINE_PROJECT_NAMESPACE
kubectl get configmaps -n $CODEENGINE_PROJECT_NAMESPACE
}
function kube_pod_log(){
echo "************************************"
echo " Kubernetes $CODEENGINE_APP_NAME: log"
echo "************************************"
# 1. Find the first pod for the application
FIND="$CODEENGINE_APP_NAME"
echo "Get pod: ${FIND}"
APP_POD=$(kubectl get pod -n $CODEENGINE_PROJECT_NAMESPACE | grep ${FIND} | awk '{print $1}')
echo "************************************"
echo "Show log for the pod: $APP_POD"
echo "************************************"
# 2. Show the logs for this pod
kubectl logs --since=10m $APP_POD
}
function ce_log () {
echo "************************************"
echo "Show log for the CE application: $CODEENGINE_APP_NAME"
echo "************************************"
ibmcloud ce application logs --application $CODEENGINE_APP_NAME --all-containers
}
#**********************************************************************************
# Execution
# *********************************************************************************
# 1. Connect to IBM Cloud Code Engine.
login_to_ibm_cloud
connect_ce_project
# 2. Init output files.
echo "Run,Endpoint,Question,API_call,Start_time,Duration,Response" > ${LOG_FILE}
echo "Run,Endpoint,Question,Answer" > ${CSV_ANSWER_FILE}
echo "Error file endpoint verification" > ${ERROR_LOG_FILE}
# 3. Loop the questions in the question input file
while IFS=',' read -r CE_HOST QUESTION API_CALL API_KEY;
do
# 3.1 Start a timer to log the time from the request to the response of the HTTP rest call.
start_time=$(date "+%s")
((j++))
RUN=$((j-1))
# 3.2 Ensure the CSV file HEADER is not used to invoke the endpoint.
if [[ $j -eq $CSV_HEADER ]]; then
echo "---------------------------"
echo "CSV Header:"
echo "${CE_HOST} ${QUESTION} ${API_CALL} ${API_KEY}"
echo ""
else
# 3.3 Save the HTTP response to a file.
curl -X POST -u "apikey:${API_KEY}" --header "Content-Type: application/json" --data "{ \"query\": \"text:${QUESTION}\" }" "https://${CE_HOST}/${API_CALL}" | jq '.' > ./${TMP_FILE}
# 3.4 Define the JSON path of the return value you want to verify.
JSON_EXTRACT='.my.path'
OUTPUT=$(cat ./${TMP_FILE} | --argjson j "$JSON_EXTRACT" -n "$j")
OUTPUT_RAW=$(cat ./${TMP_FILE})
# 3.4a (optional) Show the extracted and raw content if needed for debugging.
#echo "OUTPUT: ${OUTPUT}"
#echo "---------------------------"
#echo "OUTPUT_RAW:"
#cat ${OUTPUT_RAW}
# 3.5 Verify, if the right JSON contains the expected value.
if [ "${OUTPUT}" = "${OUTPUT_CHECK}" ]; then
VERIFY="valid response content"
ANSWER=$(cat ./${TMP_FILE} | jq -c '.results[0].text[0]')
echo "----------------------------"
echo "Answer:"
echo "${ANSWER}"
echo "----------------------------"
echo "${RUN},${CE_HOST},\"${QUESTION}\",${ANSWER}" >> ${CSV_ANSWER_FILE}
else
# 3.6 In case the wrong value is found, inspect the error logs of Code Engine and save the log information to a file.
VERIFY="invalid response content"
echo "----------------------------"
log_date=$(date +'%F %H:%M:%S')
echo "${log_date} Error" >> ${ERROR_LOG_FILE}
echo ""
echo "Run: ${RUN}" >> ${ERROR_LOG_FILE}
echo "Endpoint: ${CE_HOST}" >> ${ERROR_LOG_FILE}
echo "" >> ${ERROR_LOG_FILE}
echo "----- Command ----" >> ${ERROR_LOG_FILE}
echo "curl -X POST -u \"apikey:${API_KEY}\" --header \"Content-Type: application/json\" --data \"{ \"query\": \"text:${QUESTION}\" }\" \"https://${CE_HOST}/${API_CALL}\"" >> ${ERROR_LOG_FILE}
echo "----- Output ----" >> ${ERROR_LOG_FILE}
echo "" >> ${ERROR_LOG_FILE}
echo "${OUTPUT_RAW}" >> ${ERROR_LOG_FILE}
echo "" >> ${ERROR_LOG_FILE}
CODEENGINE_APP_NAME=${CE_HOST%${CE_DOMAIN}}
echo "CE APP: ${CODEENGINE_APP_NAME}"
echo "--- CE APP: ${CODEENGINE_APP_NAME} ---" >> ${ERROR_LOG_FILE}
echo "" >> ${ERROR_LOG_FILE}
#echo "all namespace kubectl information"
#echo ""
#kube_information >> ${ERROR_LOG_FILE}
#echo ""
echo "--- kubectl first pod information ---" >> ${ERROR_LOG_FILE}
kube_pod_log >> ${ERROR_LOG_FILE}
echo "--- CE app log ---" >> ${ERROR_LOG_FILE}
ce_log >> ${ERROR_LOG_FILE}
fi
# 3.7 End timer and calculate the response time.
end_time=$(date "+%s")
duration_time=$(( end_time - start_time))
# 3.8 Create a date time-stamp for the log file.
log_date=$(date +'%F %H:%M:%S')
echo "------------------------------------------------------------------------"
echo "${log_date} Run: ${RUN} Endpoint: ${CE_HOST}"
echo "Duration: ${duration_time} Response: ${VERIFY}"
echo "------------------------------------------------------------------------"
# 3.9 Write the logging information to a file.
echo "${RUN},${CE_HOST},${QUESTION},${API_CALL},${start_time},${duration_time},\"${VERIFY}\"" >> ${LOG_FILE}
fi
done < ${CSV_FILE}
rm $TMP_FILE
I hope this was useful for you and let’s see what’s next?
Greetings,
Thomas
#cheatsheet, #ibmcloud, #bash, #kubectl, #codeengine, #csv, #environmentvariables, #jq, #curl, #counting, #loop

helped me to save time. thanks
LikeLike