Created
August 30, 2020 13:41
-
-
Save Here-Be-Dragons/3eb87af52e0d99ca240eab71ef7bd5a5 to your computer and use it in GitHub Desktop.
Launch AWX job with survey input from Environment Variables
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Kicks off a Job Template, and waits for it to finish. | |
function LogIt { | |
LEVEL=$1 | |
MESSAGE=$2 | |
if [ "$LEVEL" = "SUCCESS" ]; then | |
echo -e "[\033[32m✔\033[0m]\t\033[32m${LEVEL}:\033[0m ${MESSAGE}" | |
elif [ "$LEVEL" = "INFO" ]; then | |
echo -e "[•]\t${LEVEL}: ${MESSAGE}" | |
elif [ "$LEVEL" = "WARN" ]; then | |
echo -e "[\033[33;1m-\033[0m]\t\033[33;1m${LEVEL}:\033[0m ${MESSAGE}" | |
elif [ "$LEVEL" = "ERROR" ]; then | |
echo -e "[\033[31m✘\033[0m]\t\033[31m${LEVEL}:\033[0m ${MESSAGE}" | |
else | |
echo -e "[?]\t${LEVEL}: ${MESSAGE}" | |
fi | |
} | |
function GetAssemblyVersion { | |
if [ -z "${APP_VERSION}" ]; then | |
LogIt "INFO" "Parsing Build Number for Application Version." | |
if [[ "$BUILD_BUILDNUMBER" =~ ^(.*)-[0-9]+\.[0-9]+$ ]]; then | |
LogIt "SUCCESS" "Retrieved Build Number: ${BUILD_BUILDNUMBER}" | |
APP_VERSION=${BASH_REMATCH[1]} | |
LogIt "SUCCESS" "Parsed Application Version: ${APP_VERSION}" | |
elif [[ "$BUILD_BUILDNUMBER" =~ ^([0-9]+\.){2,3}[0-9]+$ ]]; then | |
LogIt "SUCCESS" "Build Number already in correct format, using as-is." | |
APP_VERSION=${BUILD_BUILDNUMBER} | |
LogIt "SUCCESS" "Parsed Application Version: ${APP_VERSION}" | |
else | |
LogIt "ERROR" "Unable to get Application Version from Build.BuildNumber variable." | |
LogIt "ERROR" "Verify \$Build.BuildNumber is of the format ##.##.##.##-##.##, where" | |
LogIt "ERROR" "## is any length number. The portion before the dash is used as App Version." | |
exit 1 | |
fi | |
else | |
LogIt "INFO" "Application Version provided by APP_VERSION variable: ${APP_VERSION}" | |
fi | |
} | |
function TestConnectivity { | |
LogIt "INFO" "Verifying connectivity to the AWX Server at ${ANSIBLEHOST}" | |
QRETURN=$(curl --silent --show-error -i -X GET \ | |
https://${ANSIBLEHOST}/api/v2/ping/) | |
if [ $? -ne 0 ]; then | |
LogIt "ERROR" "Connecting to Ansible Failed. Check Server Availability." | |
LogIt "INFO" "$QRETURN" | |
exit 1 | |
else | |
AWX_VERSION=$(grep '{"' <<< "${QRETURN}" | jq '.version') | |
LogIt "SUCCESS" "AWX connection succeeded." | |
LogIt "INFO" "AWX Version ${AWX_VERSION} running." | |
fi | |
} | |
function GetAnsibleJobNumber { | |
if [[ "$TEMPLATE_ID" =~ [0-9]+ ]]; then | |
LogIt "WARN" "Ansible AWX Job Template ID manually provided as \"${TEMPLATE_ID}\". Skipping Template ID discovery." | |
LogIt "WARN" "Template IDs usually vary between instances of Ansible AWX. It is much safer to specify" | |
LogIt "WARN" "\$ANSIBLEJOBNAME and let the script discover the Template ID dynamically." | |
else | |
if [ -z "${ANSIBLEJOBNAME}" ]; then | |
LogIt "ERROR" "Variable \"ANSIBLEJOBNAME\" is not set, cannot continue. Verify you pass the variable to this script and re-run." | |
exit 1 | |
fi | |
LogIt "INFO" "Locating Ansible Job Number using Job Name: \"${ANSIBLEJOBNAME}\"" | |
QRETURN=$(curl --silent --show-error -G \ | |
https://${ANSIBLEHOST}/api/v2/job_templates/ --data-urlencode "name=${ANSIBLEJOBNAME}" \ | |
-H "Authorization: Bearer ${ANSIBLEPAT}" \ | |
-H 'Content-Type: application/json' \ | |
-s) | |
echo "##[debug]${QRETURN}" | |
TEMPLATE_ID=$(jq '.results[0].id' <<< "${QRETURN}") | |
TEMPLATE_NAME=$(jq -r '.results[0].name' <<< "${QRETURN}") | |
if [ "$TEMPLATE_NAME" = "$ANSIBLEJOBNAME" ]; then | |
LogIt "INFO" "\"${ANSIBLEJOBNAME}\" matches return from Ansible: \"$TEMPLATE_NAME\"" | |
LogIt "SUCCESS" "Ansible Job Template name sanity check successful." | |
else | |
LogIt "INFO" "\"${ANSIBLEJOBNAME}\" DOES NOT match return from Ansible: \"$TEMPLATE_NAME\"" | |
LogIt "ERROR" "Ansible Job Template name sanity check FAILED. HALTING DEPLOYMENT." | |
LogIt "INFO" "Job ID returned: ${TEMPLATE_ID}" | |
LogIt "INFO" "${QRETURN}" | |
exit 1 | |
fi | |
if [[ "$TEMPLATE_ID" =~ [0-9]+ ]]; then | |
LogIt "SUCCESS" "Ansible AWX Job Template ID found: ${TEMPLATE_ID}" | |
else | |
LogIt "ERROR" "Unable to discover Ansible AWX Job Template ID. This is a fatal error, investigation required." | |
LogIt "INFO" "Template ID returned:" | |
echo ${QRETURN} | |
exit 1 | |
fi | |
fi | |
} | |
function GeneratePostData { | |
postData="{}" | |
LogIt "INFO" "Gathering Variable Requirements from Ansible AWX" | |
ansiblevars=$(curl --silent -X GET \ | |
https://${ANSIBLEHOST}/api/v2/job_templates/${TEMPLATE_ID}/survey_spec/ \ | |
-H "Authorization: Bearer ${ANSIBLEPAT}" \ | |
-H 'Content-Type: application/json' \ | |
-s) | |
if [[ "$ansiblevars" =~ "could not be found" ]]; then | |
LogIt "ERROR" "Gathering Variable Requirements from Ansible AWX Failed. This is a fatal error, investigation required." | |
LogIt "INFO" "Return from Ansible AWX:" | |
echo -e "${ansiblevars}" | |
exit 1 | |
fi | |
# If there's no survey, skip populating the JSON Payload. Else, get the values | |
# we need to continue. | |
if [ "$ansiblevars" = "{}" ]; then | |
LogIt "SUCCESS" "No variables needed, continuing without action." | |
else | |
ansiblevars=$(echo ${ansiblevars} | jq -r '.spec[].variable') | |
for i in ${ansiblevars}; do | |
if [ -z "$(eval echo \$${i})" ]; then | |
LogIt "ERROR" "Required variable \"$i\" is not set, cannot continue. Exiting, no job created." | |
exit 1 | |
fi | |
replacementval=$(eval echo \$${i}) | |
postData=$(echo ${postData} | jq --arg inp1 "$i" --arg inp2 "$replacementval" '.extra_vars += {( $inp1 ) : ( $inp2 )}') | |
done | |
LogIt "SUCCESS" "JSON Payload being sent to Ansible AWX:" | |
echo -e "${postData}" | |
fi | |
} | |
function ExecuteAnsibleJob { | |
LogIt "INFO" "Handing off execution of deploy to Ansible AWX" | |
QRETURN=$(curl --silent --show-error -X POST \ | |
https://${ANSIBLEHOST}/api/v2/job_templates/${TEMPLATE_ID}/launch/ \ | |
-H "Authorization: Bearer ${ANSIBLEPAT}" \ | |
-H 'Content-Type: application/json' \ | |
-d "${postData}" \ | |
-s) | |
if [ $? -ne 0 ]; then | |
LogIt "ERROR" "Attempt to start job failed. Failing request, investigation requred." | |
LogIt "INFO" "${QRETURN}" | |
exit 1 | |
fi | |
JOB_ID=$(jq '.id' <<< "${QRETURN}" ) | |
if [[ "$JOB_ID" =~ [0-9]+ ]]; then | |
LogIt "SUCCESS" "Ansible job created: ${JOB_ID}" | |
else | |
LogIt "ERROR" "Ansible job not created. Exiting, failed." | |
echo -e "\tJSON Payload:" | |
echo -e "\t${postData}" | |
echo -e "\tReturn:" | |
echo -e "\t${QRETURN}" | |
exit 1 | |
fi | |
} | |
function GetStdOut { | |
LogIt "INFO" "STDOUT:" | |
ANSIBLESTDOUT=$(curl --silent -X GET \ | |
"https://${ANSIBLEHOST}/api/v2/jobs/${JOB_ID}/stdout/?format=ansi" \ | |
-H "Authorization: Bearer ${ANSIBLEPAT}" \ | |
-H 'Content-Type: application/json') | |
echo -e "${ANSIBLESTDOUT}" | |
if [[ "$ANSIBLESTDOUT" =~ "no hosts matched" ]]; then | |
LogIt "ERROR" "Job execution did not match any hosts, invalid job execution." | |
LogIt "ERROR" "Validate \"hosts:\" line matches inventory values" | |
exit 1 | |
fi | |
} | |
function AwaitJobCompletion { | |
LogIt "INFO" "Waiting for job to complete." | |
FINISHED=null | |
STATUS='"pending"' | |
while [ "$FINISHED" = 'null' ]; do | |
LogIt "INFO" "Current Status: ${STATUS}. Sleeping for 5 seconds. 💤" | |
sleep 5 | |
QRESULT=$(curl --silent -X GET \ | |
https://${ANSIBLEHOST}/api/v2/jobs/${JOB_ID}/ \ | |
-H "Authorization: Bearer ${ANSIBLEPAT}" \ | |
-H 'Content-Type: application/json') | |
STATUS=$(jq '.status' <<< ${QRESULT}) | |
FINISHED=$(jq '.finished' <<< ${QRESULT}) | |
FAILED=$(jq '.failed' <<< ${QRESULT}) | |
done | |
if [ "$FAILED" = 'false' ]; then | |
LogIt "SUCCESS" "Ansible Job ${JOB_ID} reports success. Job URL:" | |
echo -e "\thttps://${ANSIBLEHOST}/#/jobs/playbook/${JOB_ID}" | |
GetStdOut | |
elif [ "$FAILED" = 'true' ]; then | |
LogIt "ERROR" "Ansible Job ${JOB_ID} reports ${STATUS}. Check the following URL for more details." | |
echo -e "\thttps://${ANSIBLEHOST}/#/jobs/playbook/${JOB_ID}" | |
GetStdOut | |
exit 1 | |
else | |
LogIt "ERROR" "An unexpected return value was recieved. Please investigate." | |
echo -e "\thttps://${ANSIBLEHOST}/#/jobs/playbook/${JOB_ID}" | |
echo -e "${QRESULT}" | |
fi | |
} | |
# Release starts here | |
GetAssemblyVersion | |
LogIt "INFO" "Configured settings:" | |
LogIt "INFO" "ANSIBLEHOST: ${ANSIBLEHOST}" | |
LogIt "INFO" "TEMPLATE_ID (Discovered if missing): ${TEMPLATE_ID}" | |
LogIt "INFO" "ANSIBLEJOBNAME: ${ANSIBLEJOBNAME}" | |
TestConnectivity | |
GetAnsibleJobNumber | |
GeneratePostData | |
ExecuteAnsibleJob | |
AwaitJobCompletion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment