Skip to content

Commit

Permalink
v1.2.1
Browse files Browse the repository at this point in the history
Rundeck 5.x support and xml deprecated on API usage
  • Loading branch information
Daryes authored Jun 15, 2024
1 parent dda550c commit e3f5137
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 66 deletions.
18 changes: 14 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
Change history
======

v1.2.1 (2024/06/15)
------

- new requirement : the package/command "jq" is now required.
- Module dependencies-wait_job: Rundeck 5.x support by switching the expected api output from xml to json.
- Module dependencies-wait_job: updated the minimum Rundeck API version to 47 which might hamper the support of older Rundeck version.
- Module dependencies-wait_file : rewording of some messages.


v1.2.0 (2023/11/12)
------

- dependencies-wait_file : new module able to wait for a file presence.
- Better wording of the plugin descriptions
- wait_job: updated the minimum API version from 11 to 14
- wait_job: able to managed the disappearance of a running job with an optional dependency over it
- Module dependencies-wait_file : new module able to wait for a file presence.
- Better wording of the readme and plugin descriptions
- Module dependencies-wait_job: updated the minimum Rundeck API version from 11 to 14
- Module dependencies-wait_job: able to manage the disappearance of a running job while waiting on it with an optional dependency


v1.1.1 (2021/05/16)
Expand All @@ -21,6 +30,7 @@ v1.1.0 (2021/04/04)

- updated the minimum Rundeck API to 11
- changed the api token to support a file based location
- switched to semver versionning

v1.0.10 (2019/06/06)
------
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ together or to other ressources in a global flow.

Support Rundeck 3.x and more

[Changelog](CHANGELOG.md)



## Available modules

Expand All @@ -31,15 +34,15 @@ of the current flow. Even if the day change, as Rundeck does not support a proce
The dependencies zip archive must be placed in the `/var/rundeck/lib/rundeck/libext/` directory.
Either the zip file as is, or a symlink to the zip file elsewhere.

If upgrading, the remaining file for the previous version must be removed.
If upgrading, the file from the previous version must be removed.

An alternate option is by using the UI under the system menu (the cog icon) => plugins.
You can then upload a plugin to Rundeck.


## System requirements

The curl and findutils packages must be installed.
The curl, jq and findutils packages must be installed.

This command must return a message with `<message>API Version not specified</message>` :
`curl https://<rundeck_url>/api/`
Expand Down
4 changes: 2 additions & 2 deletions contents/dep_wait_common.include
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ REF_TMP_DIR=${RD_TMP_DIR:-/tmp/rundeck}
[ ! -d "${REF_TMP_DIR}" ] && REF_TMP_DIR=${RD_PLUGIN_TMPDIR} # use the plugin tmp as a fallback


VAL_OK=";ok;success;succeeded;"
VAL_KO=";ko;error;failed;aborted;timedout;timeout"
JOB_STATUS_OK_LST=";ok;success;succeeded;"
JOB_STATUS_KO_LST=";ko;error;failed;aborted;timedout;timeout"


### Functions
Expand Down
9 changes: 5 additions & 4 deletions contents/dep_wait_file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -266,21 +266,22 @@ if [ $TARGET_FILE_RECEIVED -eq 1 ] && \
echo "NOTICE: received flag has no content while its size is not 0."

else
echo "Processing hash found in $TARGET_FLAG_FILENAME ..."
echo "$TARGET_FLAG_FILENAME has a hash definition - processing ..."
sFlagBin=${HASH_CMD[${nFlagLen}]}
if [ "$sFlagBin" != "" ]; then
echo "Related binary detected : $sFlagBin"
echo "=> hash binary detected : $sFlagBin"
echo "=> hash value detected : $sFlagContent"
sFileHash=$( $SSH_CMD $sFlagBin "$TARGET_DIRECTORY/$TARGET_FILENAME" 2>&1 )
if [ $? -ne 0 ]; then echoerr "Error: could not validate the file $TARGET_DIRECTORY/$TARGET_FILENAME $SSH_TEXT_INFO"; echo "$sFileHash"; exit 1; fi

sFileHash=$( echo "$sFileHash" | cut -d ' ' -f1 )
if [ "$sFileHash" != "$sFlagContent" ]; then
echoerr "Error: the hash in the flag file doesn't match with the received file"
echoerr " calculated hash with $sFlagBin : $sFileHash"
echoerr " hash in the flag file : $sFlagContent"
echoerr " hash in the flag file : $sFlagContent"
exit 1
fi
echo "Target file hash is valid: $sFlagContent"
echo "Target file hash is valid => success"

else
echoerr "Warning: no command available for a $nFlagLen characters hash $SSH_TEXT_INFO"
Expand Down
97 changes: 44 additions & 53 deletions contents/dep_wait_job.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,22 +69,23 @@ Worth mentionning :


# -----------------------------------------------------------------------------
# ref: https://docs.rundeck.com/docs/api/rundeck-api-versions.html
CURL_API_VERSION_MIN=47

# curl command
# args: anything from: curl https://rundeck/api/<arg1> <arg2> <arg3> ...
_curlCmd() {
CURL_API_ROOT="${RD_JOB_SERVERURL%/}/api"
# curl v7.55.0+ is required for using "@-"
echo "X-Rundeck-Auth-Token: $RD_TOKEN" | curl --retry 3 --user-agent "dependencies-wait_job/curl" --get -H @- --silent ${CURL_API_ROOT}/"$@" 2>&1
}
# ref: https://docs.rundeck.com/docs/api/rundeck-api-versions.html
CURL_API_VERSION_MIN=14

# check the Rundeck API access to all projects
# input: n/a
# output: error code
rdProjects_VerifyAccess() {
sData=$( _curlCmd ${CURL_API_VERSION_MIN}/projects )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true' || ! echo "$sData" | grep -i -q "projects count="; then echoerr "Error: cannot contact rundeck through the API nor access the project list"; echoerr "$sData"; exit 1; fi
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true' || ! echo "$sData" | grep -i -q '"name":' ; then echoerr "Error: cannot contact rundeck through the API nor access the project list"; echoerr "$sData"; exit 1; fi
}


Expand All @@ -95,60 +96,52 @@ rdProjects_getList() {
sData=$( _curlCmd ${CURL_API_VERSION_MIN}/projects )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true'; then echoerr "Error: projects list - bad API query"; echoerr "$sData"; exit 1; fi

sData=$( echo "$sData" | grep -Po "<name>\K.*?(?=</name>)" )
sData=$( echo "$sData" | jq -r ".[].name" )

echo "$sData" | grep -v '^#'
return 0 # grep will return rc=1 if there is no data
echo "$sData" | jq -r ".[].name"
}


# get the job list from a project
# input: "project name"
# output: list of jobs names
# output: list of jobs id
rdProject_getJobList() {
TARGET_PROJECT=$1

CURL_API_VERSION=17
CURL_API_VERSION=${CURL_API_VERSION_MIN}
sData=$( _curlCmd ${CURL_API_VERSION}/project/${TARGET_PROJECT}/jobs )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true'; then echoerr "Error: job list - bad API query"; echoerr "$sData"; exit 1; fi

# tranform the xml data in single line, then add \n between job blocs
echo echo "$sData" | tr '\n' ' ' | sed 's#>[ \t]*<#><#g' | sed 's#</job><job#</job>\n<job#g'
echo "$sData" | jq -r '.[].id'
}


# find a job GID from his project, group and job names
# input: TARGET_PROJECT_NAME, TARGET_GROUP_NAME, TARGET_JOB_NAME
# output: job id
rdJob_GetIdFromName() {
CURL_API_VERSION=17
CURL_API_VERSION=${CURL_API_VERSION_MIN}
sData=$( _curlCmd ${CURL_API_VERSION}/project/${TARGET_PROJECT_NAME}/jobs --data-urlencode groupPathExact="$TARGET_GROUP_NAME" --data-urlencode jobExactFilter="$TARGET_JOB_NAME" )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true' || ! echo "$sData"|grep -i -q "<jobs count="; then echoerr "Error: rdJob_GetIdFromName - bad API query"; echoerr "API message: $sData"; exit 1; fi
if echo "$sData"|grep -i -q "<jobs count='0'"; then echoerr "Error: rdJob_GetIdFromName - target job '$TARGET_JOB_NAME' in group '$TARGET_GROUP_NAME' wasn't found"; exit 1; fi
if ! echo "$sData"|grep -i -q "<jobs count='1'>"; then echoerr "Error: rdJob_GetIdFromName - more than a single job was returned "; exit 1; fi
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true' ; then echoerr "Error: rdJob_GetIdFromName - bad API query"; echoerr "API message: $sData"; exit 1; fi

nJobCount=$( echo "$sData" | jq ". |length" )
if [ $nJobCount -eq 0 ] ; then echoerr "Error: rdJob_GetIdFromName - target job '$TARGET_JOB_NAME' in group '$TARGET_GROUP_NAME' was not found"; echoerr "$sData"; exit 1; fi
if [ $nJobCount -gt 1 ]; then echoerr "Error: rdJob_GetIdFromName - more than a single job was returned "; echoerr "$sData"; exit 1; fi

# on purpose to have a progress status message
echoerr "Notice: JOB definition for '${TARGET_JOB_NAME}' found - extracting id ..."

# expected format: <job id='a4997c82-86b9-42fb-8bfd-ff57fad90202' href='http://...' ...>
echo "$sData" | grep -oP -i "job id='\K.*?(?=')"
echo "$sData" | jq -r '.[].id'
}

# the execution/running api list all currently running job, without any filter option
# input: TARGET_PROJECT_NAME, TARGET_JOB_ID
# output: 0 or 1 depending if the job is running or not
rdJob_IsRunning() {
sData=$( _curlCmd ${CURL_API_VERSION_MIN}/project/${TARGET_PROJECT_NAME}/executions/running )
sData=$( _curlCmd ${CURL_API_VERSION_MIN}/project/${TARGET_PROJECT_NAME}/executions/running --data-urlencode jobIdFilter="$TARGET_JOB_ID" )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true'; then echoerr "Error: rdJob_IsRunning - bad API query"; echoerr "API message: $sData"; exit 1; fi

# look for the requested job id
sData=$( echo "$sData" | grep "$TARGET_JOB_ID" | head -1 )

if [ -z "$sData" ]; then
echo 0
else
echo 1
fi
echo "$sData" | jq ".paging.total"
}


Expand All @@ -159,8 +152,7 @@ rdJob_GetLastExecData() {
sData=$( _curlCmd ${CURL_API_VERSION_MIN}/job/${TARGET_JOB_ID}/executions --data-urlencode max=1 )
if [ $? -ne 0 ] || echo "$sData" |grep -i 'error"*:true'; then echoerr "Error: rdJob_GetLastExecData - bad API query"; echoerr "API message: $sData"; exit 1; fi

echo "$sData" | grep -v '^#'
return 0 # grep will return rc=1 if there is no data
echo "$sData"
}


Expand All @@ -175,17 +167,21 @@ rdJob_GetLastExecValue() {
valueRet=""

case $1 in
-count)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".paging.total" )
;;

-exec_id)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | grep -oP -i "execution id='\K.*?(?=')" )
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".executions[].id" )
;;

-exec_url)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | grep -oP -i "<execution id=.* href='\K.*?(?=')" )
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".executions[].href" )
;;

-time_start)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | grep -oP -i "date-started unixtime='\K.*?(?=')" )
if [ ! -z "$valueRet" ]; then
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq ".executions[].\"date-started\".unixtime" )
if [ ! -z "$valueRet" ] || [ "$valueRet" == "null" ]; then
#cli only: valueRet=$( date -d "$valueRet" "+%s" )
valueRet=$(( $valueRet / 1000 )) # api unix time is in ms
else
Expand All @@ -194,8 +190,8 @@ valueRet=""
;;

-time_end)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | grep -oP -i "date-ended unixtime='\K.*?(?=')" )
if [ ! -z "$valueRet" ]; then
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq ".executions[].\"date-ended\".unixtime" )
if [ ! -z "$valueRet" ] || [ "$valueRet" == "null" ]; then
#cli only: valueRet=$( date -d "$valueRet" "+%s" )
valueRet=$(( $valueRet / 1000 )) # api unix time is in ms
else
Expand All @@ -204,26 +200,20 @@ valueRet=""
;;

-status|-state)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | grep -oP -i "<execution id=.* status='\K.*?(?=')" )
if [ -z "$valueRet" ]; then valueRet="unknown"; fi
if echo "$VAL_OK"|grep -q "$valueRet"; then valueRet="success"; fi
if echo "$VAL_KO"|grep -q "$valueRet"; then valueRet="error"; fi
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".executions[].status" )
if [ -z "$valueRet" ] || [ "$valueRet" == "null" ]; then valueRet="unknown"; fi
if echo "$JOB_STATUS_OK_LST"|grep -q "$valueRet"; then valueRet="success"; fi
if echo "$JOB_STATUS_KO_LST"|grep -q "$valueRet"; then valueRet="error"; fi
;;

-nodes_success)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | tr '\n' '\a' | grep -oP -i "<successfulNodes>\K.*?(?=</successfulNodes>)" | tr '\a' '\n' )
if [ ! -z "$valueRet" ]; then
# remove '<node name=' then the chars ' \ / > then whitespaces around then empty lines
valueRet=$( echo "$valueRet" | sed "s/ *<node name=//;s#[\\'/>]##g;s/^ *//;s/ *$//;/^$/d" )
fi
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".executions[].failedNodes[]? // null" )
if [ -z "$valueRet" ] || [ "$valueRet" == "null" ]; then valueRet=""; fi
;;

-nodes_fail)
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | tr '\n' '\a' | grep -oP -i "<failedNodes>\K.*?(?=</failedNodes>)" | tr '\a' '\n' )
if [ ! -z "$valueRet" ]; then
# remove '<node name=' then the chars ' \ / > then whitespaces around then empty lines
valueRet=$( echo "$valueRet" | sed "s/ *<node name=//;s#[\\'/>]##g;s/^ *//;s/ *$//;/^$/d" )
fi
valueRet=$( echo "$TARGET_JOB_LASTEXEC_DATA" | jq -r ".executions[].failedNodes[]? // null" )
if [ -z "$valueRet" ] || [ "$valueRet" == "null" ]; then valueRet=""; fi
;;

*)
Expand All @@ -247,8 +237,9 @@ source ${PLUGIN_INCLUDE_FILE}
if [ $? -ne 0 ]; then echo "Error: the function file '$PLUGIN_INCLUDE_FILE' was not found"; exit 1; fi


# curl presence verification
# requirements verification
if ! command -v curl >/dev/null 2>&1; then echoerr "Error: the command 'curl' was not found in the path"; exit 1; fi
if ! command -v jq >/dev/null 2>&1; then echoerr "Error: the command 'jq' was not found in the path"; exit 1; fi

# parameters access validation
if [ $# -eq 0 ]; then usageSyntax; exit 1; fi
Expand All @@ -274,7 +265,7 @@ while [ $# -gt 0 ]; do

-state)
TARGET_JOB_EXPECTED_STATUS=$( echo "$2" | tr '[:upper:]' '[:lower:]' )
if ! echo "$VAL_OK;$VAL_KO" | grep -q "$TARGET_JOB_EXPECTED_STATUS"; then echoerr "Error: unexpected value '$2' for -state"; exit 1; fi
if ! echo "$JOB_STATUS_OK_LST;$JOB_STATUS_KO_LST" | grep -q "$TARGET_JOB_EXPECTED_STATUS"; then echoerr "Error: unexpected value '$2' for -state"; exit 1; fi
shift
;;

Expand Down Expand Up @@ -421,7 +412,7 @@ while [ $nCount -lt ${DEP_WAIT_TIMEOUT} ]; do
if [ "$TARGET_JOB_ISRUNNING" == "0" ]; then
# retrieve last execution information, if available
TARGET_JOB_LASTEXEC_DATA=$( rdJob_GetLastExecData ) || exit 1
if [ ! -z "$TARGET_JOB_LASTEXEC_DATA" ]; then
if [ ! -z "$TARGET_JOB_LASTEXEC_DATA" ] && [ $( rdJob_GetLastExecValue -count ) -gt 0 ]; then
TARGET_JOB_LASTEXEC_STATUS=$( rdJob_GetLastExecValue -status ) || exit 1
TARGET_JOB_LASTEXEC_TIME_START=$( rdJob_GetLastExecValue -time_start ) || exit 1
TARGET_JOB_LASTEXEC_TIME_END=$( rdJob_GetLastExecValue -time_end ) || exit 1
Expand All @@ -435,12 +426,12 @@ while [ $nCount -lt ${DEP_WAIT_TIMEOUT} ]; do

case "$TARGET_JOB_EXPECTED_STATUS" in
success|ok)
SEARCH_STATUS="$VAL_OK"
SEARCH_STATUS="$JOB_STATUS_OK_LST"
TARGET_JOB_STATUS_NODES=$( rdJob_GetLastExecValue -nodes_success ) || exit 1
;;

error|failed|ko)
SEARCH_STATUS="$VAL_KO"
SEARCH_STATUS="$JOB_STATUS_KO_LST"
TARGET_JOB_STATUS_NODES=$( rdJob_GetLastExecValue -nodes_fail ) || exit 1
;;
esac
Expand Down Expand Up @@ -500,7 +491,7 @@ while [ $nCount -lt ${DEP_WAIT_TIMEOUT} ]; do
fi
fi
fi

nCount=$(( $nCount + $SLEEP_DURATION_SEC ))
timeFlow_stillWaiting $nCount
if ! timeFlow_limitReach $TIME_FLOW_DAILY_END; then break; fi
Expand Down
2 changes: 1 addition & 1 deletion plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# ref: https://github.com/rundeck/rundeck/tree/main/core/src/main/java/com/dtolabs/rundeck/core/plugins/metadata/
# ref: https://github.com/rundeck/rundeck/blob/main/rundeckapp/grails-app/taglib/rundeck/PluginTagLib.groovy
name: dependencies
version: 1.2.0
version: 1.2.1
rundeckPluginVersion: 1.2
targetHostCompatibility: unix
date: Wed Aug 17 19:37:26 CEST 2017
Expand Down

0 comments on commit e3f5137

Please sign in to comment.