CheatSheet: How to loop an endpoint of an application running on “IBM Cloud Code Engine” with a bash automation

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.

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

One thought on “CheatSheet: How to loop an endpoint of an application running on “IBM Cloud Code Engine” with a bash automation

Add yours

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at WordPress.com.

Up ↑