Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjusted cleanup logic to make sure that databases are always cleaned up properly #71

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 104 additions & 89 deletions cloudant-change-listener/run
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#!/bin/bash

# Ensure that jq tool is installed
if ! command -v jq &>/dev/null; then
echo "FAILED - 'jq' tool is not installed"
exit 1
fi

# Ensure that latest versions of used IBM Cloud ClI is installed
ibmcloud update --force

# Ensure that latest versions of used IBM Cloud CLI plugins are installed
# Ensure that latest versions of used IBM Cloud CLI plugins are installed
echo "Install necessary ibmcloud cli plugins ..."
ibmcloud plugin install cloudant -f
ibmcloud plugin install code-engine -f
Expand All @@ -21,87 +27,97 @@ function clean() {

ibmcloud ce configmap delete --name cloudant-change-listener-job-config --force
ibmcloud ce secret delete --name cloudant-change-listener-credentials --force

ibmcloud ce project delete --name ce-sample-cloudant-change-listener-project --force --hard --no-wait
ibmcloud iam service-id-delete ce-sample-cloudant-change-listener-api-credentials --force
ibmcloud resource service-key-delete cloudant-creds-ce-project --force
ibmcloud resource service-instance-delete CE-Cloudant-SampleDB --force
) > /dev/null 2>&1

# Iterate over all service instances that are called 'CE-Cloudant-SampleDB' and delete them
cloudant_dbs=$(ibmcloud resource search 'name:CE-Cloudant-SampleDB' --output JSON | jq -r '.items')
if [[ $cloudant_dbs == '[]' ]]; then
echo "No Cloudant instances that needs to get cleaned up!"
else
# Encoding each line as base64 helps to iterate over JSON objects within a bash script
for cloudant_db in $(echo "${cloudant_dbs}" | jq -r '.[] | @base64'); do
# Use this inner function to decode the base64 encoded JSON object and extract property values
# from the Cloudant instance, such as name, or crn
_jqCloudantDb() {
echo ${cloudant_db} | base64 --decode | jq -r ${1}
}
ibmcloud resource service-instance-delete $(_jqCloudantDb '.crn') --force
done
fi

) >/dev/null 2>&1
}

clean

# In case this script has been executed with `./run clean`, we stop right after the cleanup
[[ "$1" == "clean" ]] && exit 0

# Ensure that jq tool is installed
if ! command -v jq &> /dev/null ; then
echo "FAILED - 'jq' tool is not installed"
exit 1
fi


# echo "Create a new Cloudant instance ..."
# ibmcloud resource service-instance-create CE-Cloudant-SampleDB cloudantnosqldb standard eu-de -p '{"legacyCredentials":"false"}'
ibmcloud resource service-instance-create CE-Cloudant-SampleDB cloudantnosqldb standard eu-de -p '{"legacyCredentials":"false"}'

echo "Wait for the Cloudant instance to get properly initialized ..."
COUNTER=0

while ! ibmcloud resource service-instance CE-Cloudant-SampleDB | grep "active" ; do
while ! ibmcloud resource service-instance CE-Cloudant-SampleDB | grep "active"; do
sleep 5
# wait max 3 min to get a cloudant DB instance
COUNTER=$((COUNTER+1))
if (( COUNTER > 36 )); then
# wait max 3 min to get a cloudant DB instance
COUNTER=$((COUNTER + 1))
if ((COUNTER > 36)); then
echo "FAILED - Cloudant DB instance cannot be created"
exit 1
fi
done

# Obtain the created Cloudant instance
cloudant_instances=$(ibmcloud resource service-instance CE-Cloudant-SampleDB --output JSON)
cloudant_instance_name=$(echo $cloudant_instances|jq -r '.[0]|.name')
cloudant_instance_guid=$(echo $cloudant_instances|jq -r '.[0]|.guid')
cloudant_instance_name=$(echo $cloudant_instances | jq -r '.[0]|.name')
cloudant_instance_guid=$(echo $cloudant_instances | jq -r '.[0]|.guid')

if [ -z "$cloudant_instances" ]; then
if [ -z "$cloudant_instances" ]; then
echo "FAILED - Cloudant DB instances info cannot be retrieved"
exit 1
fi

echo "Obtain the service URL of the newly created Cloudant instance '$cloudant_instance_name' (id: $cloudant_instance_guid) ..."
cloudant_url=$(ibmcloud cloudant url --resource-id $cloudant_instance_guid --output JSON)
echo "$cloudant_url"
if [ -z "$cloudant_url" ]; then
if [ -z "$cloudant_url" ]; then
echo "FAILED - Cloudant DB URL cannot be retrieved"
exit 1
fi

echo "Creating the database 'sample-db' within Cloudant instance '$cloudant_instance_name' ..."
echo "using cloudant API https://cloud.ibm.com/apidocs/cloudant#putdatabase"
iam_access_token=$(ibmcloud iam oauth-tokens --output JSON|jq -r '.iam_token')
if [ -z "$iam_access_token" ]; then
iam_access_token=$(ibmcloud iam oauth-tokens --output JSON | jq -r '.iam_token')
if [ -z "$iam_access_token" ]; then
echo "FAILED - The IAM access token of the current CLI session could not be obtained"
exit 1
fi
curl -H "Authorization: $iam_access_token" -X PUT "$cloudant_url/sample-db"
if [ $? != 0 ]; then
echo "FAILED - The creation of the Cloudant database failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of the Cloudant database failed"
exit 1
fi

echo "Creating Code Engine project 'ce-sample-cloudant-change-listener-project' ..."
ibmcloud ce proj create --name ce-sample-cloudant-change-listener-project
if [ $? != 0 ]; then
echo "FAILED - The creation of a Code Engine project failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of a Code Engine project failed"
exit 1
fi

ce_project_guid=$(ibmcloud ce proj current --output json|jq -r '.guid')
if [ -z "$ce_project_guid" ]; then
ce_project_guid=$(ibmcloud ce proj current --output json | jq -r '.guid')
if [ -z "$ce_project_guid" ]; then
echo "FAILED - obtaining the project GUID failed"
exit 1
fi
ce_project_region=$(ibmcloud ce proj current --output json|jq -r '.region_id')
if [ -z "$ce_project_region" ]; then
ce_project_region=$(ibmcloud ce proj current --output json | jq -r '.region_id')
if [ -z "$ce_project_region" ]; then
echo "FAILED - Obtaining the project region failed"
exit 1
fi
Expand All @@ -117,14 +133,13 @@ ce_fn_endpoint="null"
ce_fn_endpoint_internal="null"

COUNTER=0
while [ "$ce_fn_endpoint" == "null" ]
do
while [ "$ce_fn_endpoint" == "null" ]; do
ce_fn_endpoint=$(ibmcloud ce fn get --name cloudant-change-listener-function -o json | jq -r '.endpoint')
ce_fn_endpoint_internal=$(ibmcloud ce fn get --name cloudant-change-listener-function -o json | jq -r '.endpoint_internal')
sleep 2
# wait max 3 min to get a cloudant DB instance
COUNTER=$((COUNTER+1))
if (( COUNTER > 90 )); then
# wait max 3 min to get a cloudant DB instance
COUNTER=$((COUNTER + 1))
if ((COUNTER > 90)); then
echo "FAILED - The creation of a Code Engine function failed"
exit 1
fi
Expand All @@ -135,25 +150,25 @@ echo "Creating a config map to store the event state"
ibmcloud ce configmap create \
--name cloudant-change-listener-job-config \
--from-literal DB_LAST_SEQ=now
if [ $? != 0 ]; then
echo "FAILED - The creation of the Code Engine configmap failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of the Code Engine configmap failed"
exit 1
fi

# See Code Engine docs: Managing user access (https://cloud.ibm.com/docs/codeengine?topic=codeengine-iam#service)
echo "Creating an IAM ServiceID that contains a policy to access the Code Engine project '${ce_project_guid}' ..."
ibmcloud iam service-id-create ce-sample-cloudant-change-listener-api-credentials --description "Service ID to operate towards the Code Engine project ${ce_project_guid}"
if [ $? != 0 ]; then
echo "FAILED - The creation of the IAM serviceID failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of the IAM serviceID failed"
exit 1
fi
ibmcloud iam service-policy-create ce-sample-cloudant-change-listener-api-credentials --roles Writer --service-name codeengine --service-instance ${ce_project_guid}
if [ $? != 0 ]; then
echo "FAILED - The creation of the IAM serviceID policy failed"
exit 1
fi
ce_api_key=$(ibmcloud iam service-api-key-create codeengine-api-key ce-sample-cloudant-change-listener-api-credentials --description "API key for serviceID ce-${ce_project_guid}-api-credentials for Code Engine project ${ce_project_guid}" --output JSON|jq -r '.apikey')
if [ -z "$ce_api_key" ]; then
if [ $? != 0 ]; then
echo "FAILED - The creation of the IAM serviceID policy failed"
exit 1
fi
ce_api_key=$(ibmcloud iam service-api-key-create codeengine-api-key ce-sample-cloudant-change-listener-api-credentials --description "API key for serviceID ce-${ce_project_guid}-api-credentials for Code Engine project ${ce_project_guid}" --output JSON | jq -r '.apikey')
if [ -z "$ce_api_key" ]; then
echo "FAILED - The creation of the IAM serviceID APIKey failed"
exit 1
fi
Expand All @@ -162,10 +177,10 @@ echo "Creating a secret that stores a serviceID APIKey to enable the job storing
ibmcloud ce secret create \
--name cloudant-change-listener-credentials \
--from-literal CE_API_KEY=$ce_api_key
if [ $? != 0 ]; then
echo "FAILED - The creation of the Code Engine secret failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of the Code Engine secret failed"
exit 1
fi

echo "Creating the Code Engine daemon job 'cloudant-change-listener-job' ..."
ibmcloud ce job create \
Expand All @@ -178,52 +193,52 @@ ibmcloud ce job create \
--env CE_REGION=$ce_project_region \
--env-from-configmap cloudant-change-listener-job-config \
--env-from-secret cloudant-change-listener-credentials
if [ $? != 0 ]; then
echo "FAILED - The creation of a Code Engine job failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The creation of a Code Engine job failed"
exit 1
fi

echo "Creating the service credential on the Cloudant database to be able to bind the job and the function ..."
ibmcloud resource service-key-create cloudant-creds-ce-project Reader --instance-id $cloudant_instance_guid
if [ $? != 0 ]; then
echo "FAILED - The creation of the service credential on the Cloudant DB failed"
exit 1
fi
ibmcloud resource service-key-create cloudant-creds-ce-project Reader --instance-id $cloudant_instance_guid
if [ $? != 0 ]; then
echo "FAILED - The creation of the service credential on the Cloudant DB failed"
exit 1
fi

echo "Binding the Cloudant credentials to the Code Engine function to enable that the function code can access the DB via Env vars ..."
ibmcloud ce fn bind \
--name cloudant-change-listener-function \
--service-instance-id $cloudant_instance_guid \
--service-credential cloudant-creds-ce-project
if [ $? != 0 ]; then
echo "FAILED - The binding of a service binding of the Cloudant DB to the CE function failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - The binding of a service binding of the Cloudant DB to the CE function failed"
exit 1
fi

echo "Binding the Cloudant credentials to the Code Engine job ..."
ibmcloud ce job bind \
--name cloudant-change-listener-job \
--service-instance-id $cloudant_instance_guid \
--service-credential cloudant-creds-ce-project
if [ $? != 0 ]; then
echo "FAILED - the binding of a service binding of the Cloudant DB to the CE job failed"
exit 1
fi
if [ $? != 0 ]; then
echo "FAILED - the binding of a service binding of the Cloudant DB to the CE job failed"
exit 1
fi

echo "Starting the daemon job ..."
job_run_name=$(ibmcloud ce jobrun submit --job cloudant-change-listener-job --output json|jq -r '.metadata|.name')
if [ -z "$job_run_name" ]; then
job_run_name=$(ibmcloud ce jobrun submit --job cloudant-change-listener-job --output json | jq -r '.metadata|.name')
if [ -z "$job_run_name" ]; then
echo "FAILED - The submission of the Code Engine daemon job failed"
exit 1
fi

echo "Check whether the job started properly ..."
COUNTER=0
while ! ibmcloud ce jobrun get -n ${job_run_name} | grep "1/1" | grep "Running" ; do
while ! ibmcloud ce jobrun get -n ${job_run_name} | grep "1/1" | grep "Running"; do
sleep 2
COUNTER=$((COUNTER+1))
if (( COUNTER > 90 )); then
echo $( ibmcloud ce jobrun get -n ${job_run_name} )
COUNTER=$((COUNTER + 1))
if ((COUNTER > 90)); then
echo $(ibmcloud ce jobrun get -n ${job_run_name})
echo "FAILED - The job could not be started"
exit 1
fi
Expand All @@ -242,30 +257,30 @@ curl -H "Authorization: $iam_access_token" -X POST "$cloudant_url/sample-db" -H
echo "Verify job receives the Cloudant event by fetching the job run logs ..."

COUNTER=0
while true; do
while true; do
echo "Waiting on job to detect change"
sleep 5
foundDetectedChange=$(ibmcloud ce jobrun logs -n ${job_run_name} | grep "Detected 1 change(s) in the DB")
foundCalledFunction=$(ibmcloud ce jobrun logs -n ${job_run_name} | grep "Successfully called CE function")

if [[ $foundDetectedChange && $foundCalledFunction ]]; then
if [[ $foundDetectedChange && $foundCalledFunction ]]; then
echo ""
echo "That was a success :)"
break;
fi
COUNTER=$((COUNTER+1))
if (( COUNTER > 20 )); then
if [[ ! $foundDetectedChange ]]; then
break
fi
COUNTER=$((COUNTER + 1))
if ((COUNTER > 20)); then
if [[ ! $foundDetectedChange ]]; then
echo "Testing of the sample failed because the change was not detected"
fi
if [[ ! $foundCalledFunction ]]; then
if [[ ! $foundCalledFunction ]]; then
echo "Testing of the sample failed because the ce function was not called "
fi
# Clean up
clean
exit 1;
exit 1
fi
done;
done

# Clean up
clean