Creating administration scripts for Cognos Analytics

Create administration scripts to manage deployments, shutdown or restart Cognos Analytics, and manage images.

Procedure

  1. Create the deployment.sh script to manage deployments.

    The deployment.sh script is a file with the following contents:

    #!/usr/bin/env bash
    # -----------------------------------------------------------------------------
    #      Licensed Materials - Property of IBM
    #
    #      IBM Cognos Products: ca
    #
    #      (C) Copyright IBM Corp. 2024
    #
    #      US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
    # -----------------------------------------------------------------------------
    set -e
    function usage {
      echo $0: usage: $0 [-h] -c command -d deployment -n namespace [-t tethered_namespace] -u user [[-p password][-a apikey]]
    }
    function help {
      usage
      echo "-h                    prints help to the console"
      echo "-c command            one of list, download, upload or delete"
      echo "-d deployment         deployment (not required for list)"
      echo "-n namespace          namespace or project"
      echo "-t tethered_namespace tethered namespace or project"
      echo "-a zenapikey          CP4D API key (if provided, password is ignored)"
      echo "-u user               CP4D user name"
      echo "-p password           CP4D user password"
      echo
      echo "Examples:"
      echo
      echo "./deployment.sh -c list -n cpd-instance -t cat1 -u admin -p ***"
      echo "./deployment.sh -c upload -n cpd-instance -t cat1 -u admin -p *** -d your_deployment.zip"
      echo "./deployment.sh -c download -n cpd-instance -t cat1 -u admin -p *** -d your_deployment.zip"
      echo "./deployment.sh -c delete -n cpd-instance -t cat1 -u admin -p *** -d your_deployment.zip"
      echo
      exit 0
    }
    zen_api_key=
    while getopts ":hc:d:n:t:a:u:p:" opt; do
       case ${opt} in
       h)
          help
          ;;
       c)
          deployment_cmd=$OPTARG
          ;;
       d)
          deployment=$OPTARG
          ;;
       n)
          namespace=$OPTARG
          ;;
       t)
          tethered_namespace=$OPTARG
          ;;
       a)
          zen_api_key=$OPTARG
          ;;
       u)
          user_name=$OPTARG
          ;;
       p)
          user_password=$OPTARG
          ;;
       \?)
          usage
          exit 0
          ;;
       esac
    done
    jq --version
    if [[ $? -ne 0 ]]
    then
      echo "jq is a requirement please install"
      exit 1
    fi
    if [ -z ${deployment_cmd} ]; then
      echo "A deployment command must be provided"
      help
    fi
    case ${deployment_cmd} in
      list|upload|download|delete)
        ;;
      *)
        echo "Unknown command: ${deployment_cmd}"
        help
    esac
    if [ -z ${namespace} ]; then
      echo "A namespace must be provided"
      help
    fi
    if [ -z ${tethered_namespace} ]; then
      tethered_namespace=${namespace}
      echo "A tethered namespace has not been provided, defaulting to ${tethered_namespace}"
    fi
    if [ -z ${user_name} ]; then
      echo "A user name must be provided"
      help
    fi
    if [ -z ${zen_api_key} ]; then
      if [ -z ${user_password} ]; then
        echo "A user password or api key must be provided"
        help
      fi
    else
      echo "zen apikey being used; ignoring password parameter."
      user_password=
    fi
    if [ "${deployment_cmd}" != "list" ]; then
      if [ -z $deployment ]; then
          echo "A deployment must be provided"
          help
      fi
    fi
    # Get CPD route and URLs
    cpd_route=$(oc get route -n ${namespace} | grep 'cpd.*ibm-nginx' | awk '{print $2}')
    cpd_url="https://"${cpd_route}
    echo "CP4D URL: ${cpd_url}"
    cpd_authurl=${cpd_url}/icp4d-api/v1/authorize
    deployments_url=${cpd_url}/cognosanalytics/${tethered_namespace}/artifacts/v1/deployments
    # Get CPD bearer token
    jwt_token=
    if [ -z ${zen_api_key} ]; then
      cpd_bearer="$( curl -s -k -X POST -H 'Content-Type: application/json'  -d "{ \"username\":\"${user_name}\", \"password\":\"${user_password}\" }" "${cpd_authurl}" | jq -r '. | .token' )"
      jwt_token="Authorization: Bearer ${cpd_bearer}"
    else
      jwt_token="Authorization: ZenApiKey "`echo -n ${user_name}:${zen_api_key} |base64`
    fi
    case ${deployment_cmd} in
      list)
        curl --silent "${deployments_url}" -H "${jwt_token}" -k | jq '.[]'
        echo
        ;;
      upload)
        if [ -r ${deployment} ]; then
          echo "Uploading ${deployment} ..."
          curl --silent -X POST -L "${deployments_url}" -H "${jwt_token}" -F "fileName=@${deployment}" -k
          echo
        else
          echo "Unable to read deployment: ${deployment}"
          exit 1
        fi
        ;;
      download)
        deployment_id=$(curl --silent "${deployments_url}" -H "${jwt_token}" -k | jq -r ".[] | select(.deploymentFileName == \"${deployment}\") | .id")
        echo "id: ${deployment_id}"
        if [ -z ${deployment_id} ]; then
          echo "Unable to find deployment ${deployment}"
          exit 1
        else
          echo "Downloading ${deployment} ..."
          wget -O ${deployment} --header="${jwt_token}" --no-check-certificate -nc --no-use-server-timestamps "${deployments_url}/${deployment_id}"
        fi
        ;;
      delete)
        deployment_id=$(curl --silent "${deployments_url}" -H "${jwt_token}" -k | jq -r ".[] | select(.deploymentFileName == \"${deployment}\") | .id")
        echo "id: ${deployment_id}"
        if [ -z ${deployment_id} ]; then
          echo "Unable to find deployment ${deployment}"
          exit 1
        else
          echo "Deleting ${deployment} ..."
          curl --request DELETE "${deployments_url}/${deployment_id}" -H "${jwt_token}" -k
        fi
        ;;
    esac
  2. Create the shutdown.sh script to shut down or restart Cognos Analytics.

    The shutdown.sh script is a file with the following contents:

    #!/usr/bin/env bash
    #
    # -----------------------------------------------------------------------------
    #         Licensed Materials - Property of IBM
    #
    #         IBM Cognos Products: ca
    #
    #         (C) Copyright IBM Corp. 2022, 2023
    #
    #         US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule
    # -----------------------------------------------------------------------------
    #
    #
    ​
    set -e
    #set -x
    ​
    restart_flag="false"
    shutdown_flag="true"
    check_status=""
    ​
    function usage {
        echo $0: usage: $0 [-h] -t tethered_namespace [-r]
    }
    ​
    function help {
        usage
        echo "-h                    prints help to the console"
        echo "-t tethered_namespace tethered namespace to shutdown/restart (required)"
        echo "-r                    restart (default: shutdown)"
        echo ""
        exit 0
    }
    ​
    while getopts ":ht:r" opt; do
         case ${opt} in
         h)
            help
            ;;
         t)
            tethered_namespace=$OPTARG
            ;;
         r)
            restart_flag="true"
            shutdown_flag="false"
            ;;
         \?)
            usage
            exit 0
            ;;
         esac
    done
    ​
    if [ -z ${tethered_namespace} ]; then
      echo "A tethered namespace must be provided"
      help
    fi
    ​
    cr_name=$(oc -n ${tethered_namespace} get caserviceinstance --no-headers -o custom-columns=NAME:.metadata.name)
    if [ -z ${cr_name} ]; then
      echo "Unable to find the CR for Cognos Analytics in this tethered namespace."
      exit 1
    fi
    ​
    # Patch shutdown option into CR
    if [ "${restart_flag}" == "true" ]; then
      echo "Restarting ${cr_name} ..."
      oc patch caserviceinstance ${cr_name} --type merge -p "{\"spec\":{\"shutdown\":\"false\"}}" -n ${tethered_namespace}
      check_status="Completed"
    fi
    if [ "${shutdown_flag}" == "true" ]; then
      echo "Shutting down ${cr_name} ..."
      oc patch caserviceinstance ${cr_name} --type merge -p "{\"spec\":{\"shutdown\":\"true\"}}" -n ${tethered_namespace}
      check_status="shutdown"
    fi
    ​
    sleep 10
    ​
    # Checking status of ca shutdown action
    for i in {1..240};do
        caStatus=$(oc get caserviceinstance ${cr_name} -o jsonpath="{.status.caStatus}" -n ${tethered_namespace})
    ​
        if [[ ${caStatus} == ${check_status} ]];then
            echo "${check_status} Successfully"
            break
        elif [[ ${caStatus} == "Failed" ]];then
            echo "${caStatus}!"
            exit 1
        fi
        echo "Status: ${caStatus}"
        sleep 30
    done
  3. Create the image.sh script to manage images.

    The image.sh script is a file with the following contents:

    #!/usr/bin/env bash
    # -----------------------------------------------------------------------------
    #      Licensed Materials - Property of IBM
    #
    #      IBM Cognos Products: ca
    #
    #      (C) Copyright IBM Corp. 2024
    #
    #      US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
    # -----------------------------------------------------------------------------
    
    set -e
    #set -x
    
    isRelativeReturnValue=false
    
    function usage {
      echo $0: usage: $0 [-h] -c command -i image -n namespace [-t tethered_namespace] -u user -p password
    }
    function help {
      usage
      echo "-h                    prints help to the console"
      echo "-c command            one of list, download, upload or delete"
      echo "-i image              image (not required for list, link or verify)"
      echo "-d subdir             destination subdir (optional)"
      echo "-s subdir             source subdir (not required for list or verify)"
      echo "-n namespace          namespace or project"
      echo "-t tethered_namespace tethered namespace or project"
      echo "-u user               CP4D user name"
      echo "-p password           CP4D user password"
      echo
      echo "Examples:"
      echo
      echo "./image.sh -c list -n cpd-instance -t cat1 -u admin -p ***"
      echo "./image.sh -c upload -n cpd-instance -t cat1 -u admin -p *** -i image.jpg -d subdir"
      echo "./image.sh -c download -n cpd-instance -t cat1 -u admin -p *** -i image.jpg"
      echo "./image.sh -c delete -n cpd-instance -t cat1 -u admin -p *** -i image.jpg"
      echo "./image.sh -c add_link -n cpd-instance -t cat1 -u admin -p *** -s src_path -d dest_path"
      echo "./image.sh -c delete_link -n cpd-instance -t cat1 -u admin -p *** -s src_path -d dest_path"
      echo "./image.sh -c list_link -n cpd-instance -t cat1 -u admin -p ***"
      echo
      exit 1
    }
    
    function isRelative() {
        path="$1"
        if [[ "${path}" == *".."* ]]; then
            isRelativeReturnValue=false
        else
            isRelativeReturnValue=true
        fi
    }
    
    function checkStatus () {
      # Checking status of ca reconcile action
      check_status="Completed"
      cr_name=$(oc -n ${tethered_namespace} get caserviceinstance --no-headers -o custom-columns=NAME:.metadata.name)
      for i in {1..240};do
          caStatus=$(oc get caserviceinstance ${cr_name} -o jsonpath="{.status.caStatus}" -n ${tethered_namespace})
    
          if [[ ${caStatus} == ${check_status} ]];then
            echo "ca ${check_status} Successfully"
            break
          elif [[ ${caStatus} == "Failed" ]];then
            echo "ca ${caStatus}!"
            exit 1
          fi
          echo "ca Status: ${caStatus}"
          sleep 30
      done
    }
    
    while getopts ":hc:i:d:s:n:t:u:p:" opt; do
       case ${opt} in
       h)
          help
          ;;
       c)
          image_cmd=$OPTARG
          ;;
       i)
          image=$OPTARG
          ;;
       d)
          dest_path=$OPTARG
          ;;
       s)
          src_path=$OPTARG
          ;;
       n)
          namespace=$OPTARG
          ;;
       t)
          tethered_namespace=$OPTARG
          ;;
       u)
          user_name=$OPTARG
          ;;
       p)
          user_password=$OPTARG
          ;;
       \?)
          usage
          exit 0
          ;;
       esac
    done
    
    which_jq=$(which jq)
    if [[ -z ${which_jq} ]]
    then
      echo "jq is a requirement please install"
      exit 1
    fi
    
    if [ -z ${image_cmd} ]; then
      echo "A image command must be provided"
      exit 1
    fi
    if [ -z "${dest_path}" ]; then
      dest_path="/"
    fi
    
    case ${image_cmd} in
      list|upload|download|delete|add_link|list_link|delete_link)
        ;;
    
      *)
        echo "Unknown command: ${image_cmd}"
        exit 1
    esac
    
    if [ -z ${namespace} ]; then
      echo "A namespace must be provided"
      exit 1
    fi
    
    if [ -z ${tethered_namespace} ]; then
      tethered_namespace=${namespace}
      echo "A tethered namespace has not been provided, defaulting to ${tethered_namespace}"
    fi
    
    if [ -z ${user_name} ]; then
      echo "A user name must be provided"
      exit 1
    fi
    
    if [ -z ${user_password} ]; then
      echo "A user password must be provided"
      exit 1
    fi
    
    if [ "${image_cmd}" != "list" ] && [ "${image_cmd}" != "add_link" ]  && [ "${image_cmd}" != "list_link" ]  && [ "${image_cmd}" != "delete_link" ]; then
      if [ -z $image ]; then
          echo "A image must be provided"
          exit 1
      fi
    fi
    
    if [[ "${src_path}" == *".."* ]]; then
      echo "Relative paths are not supported"
      echo "${src_path}"
      exit 1
    fi
    
    if [[ "${dest_path}" == *".."* ]]; then
      echo "Relative paths are not supported"
      echo "${dest_path}"
      exit 1
    fi
    
    # Get CPD route and URLs
    cpd_route=$(oc get route -n ${namespace} | grep 'cpd.*ibm-nginx' | awk '{print $2}')
    cpd_url="https://"${cpd_route}
    #echo "CP4D URL: ${cpd_url}"
    cpd_authurl=${cpd_url}/icp4d-api/v1/authorize
    images_url=${cpd_url}/cognosanalytics/${tethered_namespace}/artifacts/v1/images
    
    
    # Get CPD bearer token
    cpd_bearer="$( curl -s -k -X POST -H 'Content-Type: application/json'  -d "{ \"username\":\"${user_name}\", \"password\":\"${user_password}\" }" "${cpd_authurl}" | jq -r '. | .token' )"
    jwt_token="Authorization: Bearer ${cpd_bearer}"
    
    case ${image_cmd} in
      list)
        curl --silent "${images_url}" -H "${jwt_token}" -k | jq '.'
        ;;
    
      upload)
        if [ -f ${image} ]; then
          curl --silent -k -X POST "${images_url}" -H 'Accept: application/json' -H "${jwt_token}" -F "files=@${image}" -F "dirpath=${dest_path}"
        else
          echo "Unable to find image: ${image}"
          exit 1
        fi
        ;;
    
      download)
        image_id=$(curl --silent "${images_url}" -H "${jwt_token}" -k | jq -r ".[] | select(.imageFilePath == \"${image}\") | .id")
        echo "id: ${image_id}"
        if [ -z ${image_id} ]; then
          echo "Unable to find image ${image}"
          exit 1
        else
          echo "Downloading ${image} ..."
          wget --quiet -O $(basename ${image}) --header="${jwt_token}" --no-check-certificate -nc --no-use-server-timestamps "${images_url}/${image_id}"
        fi
        ;;
    
      delete)
        image_id=$(curl --silent "${images_url}" -H "${jwt_token}" -k | jq -r ".[] | select(.imageFilePath == \"${image}\") | .id")
        echo "id: ${image_id}"
        if [ -z ${image_id} ]; then
          echo "Unable to find image ${image}"
          exit 1
        else
          echo "Deleting ${image} ..."
          curl --silent --request DELETE "${images_url}/${image_id}" -H "${jwt_token}" -k
        fi
        ;;
    
      add_link)
        echo "Patching the CR to update the image soft links...."
        cr_name=$(oc -n ${tethered_namespace} get caserviceinstance --no-headers -o custom-columns=NAME:.metadata.name)
        if [[ -z ${cr_name} ]]; then
          echo "Unable to find CAServiceInstance CR for namespace: ${tethered_namespace}"
          exit 1
        fi
    
        imageLinks=$(oc get caserviceinstance ${cr_name} -o jsonpath='{.spec.imageLinks}' -n ${tethered_namespace})
        echo "Adding image link : ${src_path} -> ${dest_path} to the Custom Resource ${cr_name}..."
        link_data="${src_path}:${dest_path}"
        if [[ -z ${imageLinks} || ${imageLinks} == null || ${imageLinks} == "" ]];then
          oc patch caserviceinstance ${cr_name} --type merge -p "{\"spec\":{\"imageLinks\":[\"${link_data}\"]}}" -n ${tethered_namespace}
        else
          oc patch caserviceinstance ${cr_name} -n ${tethered_namespace} --type=json --patch "[{"op": "add", "path": "/spec/imageLinks/-", "value": \"${link_data}\"}]"
        fi
        checkStatus 
        sleep 20
        ;;
    
      delete_link)
        cr_name=$(oc -n ${tethered_namespace} get caserviceinstance --no-headers -o custom-columns=NAME:.metadata.name)
        if [[ -z ${cr_name} ]]; then
          echo "Unable to find CAServiceInstance CR for namespace: ${tethered_namespace}"
          exit 1
        fi
        imageLinks=$(oc get caserviceinstance ${cr_name} -o jsonpath='{.spec.imageLinks}' -n ${tethered_namespace} )
        if [[ -z ${imageLinks} || ${imageLinks} == null || ${imageLinks} == "" ]];then
          echo Can not find imageLinks specified in $cr_name
          exit 1
        fi
        imageLinks=$(oc get caserviceinstance ${cr_name} -o jsonpath='{.spec}' -n ${tethered_namespace} | jq '.imageLinks[]')
        link_data="${src_path}:${dest_path}"
        index=0
        while IFS= read -r value; do
          if [[ "${value}" == "\"${link_data}\"" ]]; then
            echo Index to be deleted is $index for "${link_data}"
            oc patch caserviceinstance ${cr_name} -n ${tethered_namespace} --type=json --patch "[{"op": "remove", "path": "/spec/imageLinks/${index}"}]" 
          fi
          index=$((index+1))
        done <<< ${imageLinks}
        # 
        imageLinks=$(oc get caserviceinstance ${cr_name} -o jsonpath='{.spec.imageLinks}' -n ${tethered_namespace})
        if [[ -z ${imageLinks} || ${imageLinks} == null || ${imageLinks} == "" || ${imageLinks} == "[]" ]]; then
            echo "The imageLinks field is empty - removing reference in the CA Instance -${cr_name}"
            oc patch caserviceinstance ${cr_name} -n ${tethered_namespace} --type=json --patch "[{"op": "remove", "path": "/spec/imageLinks"}]"
        fi
        checkStatus
        ;;
    
      list_link)
        cr_name=$(oc -n ${tethered_namespace} get caserviceinstance --no-headers -o custom-columns=NAME:.metadata.name)
        if [[ -z ${cr_name} ]]; then
          echo "Unable to find CAServiceInstance CR for namespace: ${tethered_namespace}"
          exit 1
        fi
    
        imageLinks=$(oc get caserviceinstance ${cr_name} -o jsonpath='{.spec.imageLinks}' -n ${tethered_namespace})
        echo ${imageLinks}
    esac