From 8d9003b59dd67c12a44106376e0e29817faced51 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Tue, 5 Mar 2024 19:17:21 -0500 Subject: [PATCH 01/10] Add initial service-now data setup shell script --- .gitignore | 2 + .../instance-setup/sn-instance-setup.sh | 239 ++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100755 escalation-sn/instance-setup/sn-instance-setup.sh diff --git a/.gitignore b/.gitignore index 787a1dd..80db48f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .idea .vscode */target/* +temp +**/clear-data.sh \ No newline at end of file diff --git a/escalation-sn/instance-setup/sn-instance-setup.sh b/escalation-sn/instance-setup/sn-instance-setup.sh new file mode 100755 index 0000000..b3d0988 --- /dev/null +++ b/escalation-sn/instance-setup/sn-instance-setup.sh @@ -0,0 +1,239 @@ +#!/bin/bash + +# DOUBLE CHECK FOLLOWING VALUES WITH YOUR OWN INSTANCE +export ADMIN_ROLE_SYS_ID="\"2831a114c611228501d4ea6c309d626d\"" +export APPROVER_USER_ROLE_SYS_ID="\"debab85bff02110053ccffffffffffb6\"" + +# SERVICE NOW URLs +export SN_USER_URL=${SN_SERVER}/api/now/table/sys_user?sysparm_input_display_value=true&sysparm_display_value=true +export SN_ASSIGN_USER_ROLE_URL="${SN_SERVER}/api/now/table/sys_user_has_role" +export SN_CREATE_GROUP_URL="${SN_SERVER}/api/now/table/sys_user_group" +export SN_ASSIGN_GROUP_ROLE_URL="${SN_SERVER}/api/now/table/sys_group_has_role" +export SN_ASSIGN_USR_TO_GRP_URL="${SN_SERVER}/api/now/table/sys_user_grmember" +export SN_CHANGE_REQUEST_URL="${SN_SERVER}/api/now/table/change_request" + +# CREATE REQUESTER USER +export CREATE_REQ_USER_PAYLOAD="{ \ + \"user_name\": \"requester\", \ + \"first_name\": \"requester\", \ + \"last_name\": \"user\", \ + \"email\": \"requester@example.com\", \ + \"user_password\": \"${DEFAULT_PWD}\", \ + \"password_needs_reset\": \"false\", \ + \"active\": \"true\", \ + \"locked_out\": \"false\", \ + \"web_service_access_only\": \"false\", \ + \"internal_integration_user\": \"false\", \ + \"roles\": \"admin\" \ +}" + +export NEW_REQ_USER_SYS_ID=`curl -s \ +--variable %SN_USER_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %CREATE_REQ_USER_PAYLOAD \ +--variable %DEFAULT_PWD \ +--expand-url {{SN_USER_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{CREATE_REQ_USER_PAYLOAD}} | jq '.result.sys_id'` + +echo "*** Requester User Sys Id: ${NEW_REQ_USER_SYS_ID}" + +# ASSIGN REQUESTER USER WITH ADMIN ROLE +export ASSIGN_USER_ROLE_PAYLOAD="{ + \"role\": ${ADMIN_ROLE_SYS_ID}, \ + \"user\": ${NEW_REQ_USER_SYS_ID} \ +}" + +export NEW_USER_ROLE_ASSOC_SYS_ID=`curl -s \ +--variable %SN_ASSIGN_USER_ROLE_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %ASSIGN_USER_ROLE_PAYLOAD \ +--expand-url {{SN_ASSIGN_USER_ROLE_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{ASSIGN_USER_ROLE_PAYLOAD}} | jq '.result.sys_id'` + +echo "*** Requester User associated to Admin role with Sys Id: ${NEW_USER_ROLE_ASSOC_SYS_ID}" + +# CREATE APPROVER USER +export CREATE_APPRV_USER_PAYLOAD="{ \ + \"user_name\": \"manager\", \ + \"first_name\": \"manager\", \ + \"last_name\": \"user\", \ + \"email\": \"manager@example.com\", \ + \"user_password\": \"${DEFAULT_PWD}\", \ + \"password_needs_reset\": \"false\", \ + \"active\": \"true\", \ + \"locked_out\": \"false\", \ + \"web_service_access_only\": \"false\", \ + \"internal_integration_user\": \"false\", \ + \"roles\": \"admin\" \ +}" + +export NEW_APPRV_USER_SYS_ID=$(curl -s \ +--variable %SN_USER_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %CREATE_APPRV_USER_PAYLOAD \ +--expand-url {{SN_USER_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{CREATE_APPRV_USER_PAYLOAD}} | jq '.result.sys_id') + +echo "*** Approver User Sys Id: ${NEW_APPRV_USER_SYS_ID}" + +# CREATE APPROVER GROUP +export CREATE_GROUP_PAYLOAD="{ + \"name\": \"Approvers\", + \"exclude_manager\": \"false\", + \"manager\": ${NEW_APPRV_USER_SYS_ID}, + \"email\": \"chgapprovers@example.com\", + \"include_members\": \"false\", + \"roles\": \"itil,approver_user\" +}" + +export NEW_APPRV_GRP_SYS_ID=$(curl -s \ +--variable %SN_CREATE_GROUP_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %CREATE_GROUP_PAYLOAD \ +--expand-url {{SN_CREATE_GROUP_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{CREATE_GROUP_PAYLOAD}} | jq '.result.sys_id') + +echo "*** Approver Group Sys Id: ${NEW_APPRV_GRP_SYS_ID}" + +# ADD approver_user ROLE TO APPROVER GROUP +export ASSIGN_GRP_ROLE_PAYLOAD="{ + \"role\": ${APPROVER_USER_ROLE_SYS_ID}, \ + \"group\": ${NEW_APPRV_GRP_SYS_ID} \ +}" + +export NEW_GRP_ROLE_ASSOC_SYS_ID=$(curl -s \ +--variable %SN_ASSIGN_GROUP_ROLE_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %ASSIGN_GRP_ROLE_PAYLOAD \ +--expand-url {{SN_ASSIGN_GROUP_ROLE_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{ASSIGN_GRP_ROLE_PAYLOAD}} | jq '.result.sys_id') + +echo "*** Associate approver_user role to approver user Sys Id: ${NEW_GRP_ROLE_ASSOC_SYS_ID}" + +# ASSOCIATE APPROVER USER AND APPROVER GROUP +export ASSIGN_APPRV_USR_TO_APPRV_GRP_PAYLOAD="{ + \"user\": ${NEW_APPRV_USER_SYS_ID}, \ + \"group\": ${NEW_APPRV_GRP_SYS_ID} \ +}" + +export NEW_ASSIGN_GRP_TO_USR_SYS_ID=$(curl -s \ +--variable %SN_ASSIGN_USR_TO_GRP_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %ASSIGN_APPRV_USR_TO_APPRV_GRP_PAYLOAD \ +--expand-url {{SN_ASSIGN_USR_TO_GRP_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{ASSIGN_APPRV_USR_TO_APPRV_GRP_PAYLOAD}} | jq '.result.sys_id') + +echo "*** Assigned approver user to approver group with Sys Id: ${NEW_ASSIGN_GRP_TO_USR_SYS_ID}" + +# CREATE A CHANGE REQUEST +export CREATE_CHG_REQ_PAYLOAD="{ + \"description\": \"Requester requesting an item\", + \"short_description\": \"Requester requesting an item in short\", + \"comments\": \"Requester requesting an item in comments\", + \"state\": \"new\", + \"assigned_to\": ${NEW_APPRV_USER_SYS_ID}, + \"additional_assignee_list\": ${NEW_APPRV_USER_SYS_ID}, + \"assignment_group\": ${NEW_APPRV_GRP_SYS_ID} +}" + +export NEW_CHG_REQ_SYS_ID=$(curl -s \ +--variable %SN_CHANGE_REQUEST_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %CREATE_CHG_REQ_PAYLOAD \ +--expand-url {{SN_CHANGE_REQUEST_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{CREATE_CHG_REQ_PAYLOAD}} | jq '.result.sys_id') + +echo "*** New Change Request Sys Id: ${NEW_CHG_REQ_SYS_ID}" + +# TRIGGER THE CHANGE REQUEST FOR APPROVAL +export TEMP=`echo ${NEW_CHG_REQ_SYS_ID} | tr -d "\""` +export TRIGGER_CHG_REQ_URL=${SN_CHANGE_REQUEST_URL}/${TEMP} + +export TRIGGER_CHG_REQ_PAYLOAD="{ + \"state\": \"-4\", + \"approval\": \"requested\" +}" + +export TRIGGER_CHG_REQ_SYS_ID=$(curl -s -X PUT \ +--variable %TRIGGER_CHG_REQ_URL \ +--variable %CONTENT_TYPE \ +--variable %AUTH_HEADER \ +--variable %TRIGGER_CHG_REQ_PAYLOAD \ +--expand-url {{TRIGGER_CHG_REQ_URL}} \ +--expand-header {{CONTENT_TYPE}} \ +--expand-header {{AUTH_HEADER}} \ +--expand-data {{TRIGGER_CHG_REQ_PAYLOAD}} | jq '.result.sys_id') +echo "*** Triggered change request with Sys Id: ${TRIGGER_CHG_REQ_SYS_ID}" + +# OUTPUT DELETE DATA SCRIPT +export CLEAR_DATA=clear-data.sh +rm -f $CLEAR_DATA +echo "export SN_SERVER='${SN_SERVER}'" >> $CLEAR_DATA +echo "export AUTH_HEADER=\"${AUTH_HEADER}\"" >> $CLEAR_DATA +echo "export ACCEPT='Accept: application/json'" >> $CLEAR_DATA + +export ACCEPT='Accept: application/json' + +echo "# Delete Change Request" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_CHG_REQ_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/change_request/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + +echo "# Delete approver_user role to approver group" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_GRP_ROLE_ASSOC_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/sys_group_has_role/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + +echo "# Delete approver user association with approver group" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_ASSIGN_GRP_TO_USR_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/sys_user_grmember/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + +echo "# Delete Approver Group" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_APPRV_GRP_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/sys_user_group/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + +echo "# Delete Approver User" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_APPRV_USER_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/sys_user/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + +echo "# Delete Requester User" >> $CLEAR_DATA +export DELETE_SYS_ID=`echo ${NEW_REQ_USER_SYS_ID} | tr -d "\""` +echo "curl \"${SN_SERVER}/api/now/table/sys_user/${DELETE_SYS_ID}\" \ +--request DELETE \ +--header '${ACCEPT}' \ +--header '${AUTH_HEADER}' " >> $CLEAR_DATA + From 162e84d468316720e2c07650aaa099832c3a084c Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Thu, 7 Mar 2024 16:01:46 -0500 Subject: [PATCH 02/10] Add ServiceNow initial setup readme and a few tweaks to the script --- .../instance-setup/setup-script/readme.md | 47 +++++++++++++++++++ .../{ => setup-script}/sn-instance-setup.sh | 3 +- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 escalation-sn/instance-setup/setup-script/readme.md rename escalation-sn/instance-setup/{ => setup-script}/sn-instance-setup.sh (98%) diff --git a/escalation-sn/instance-setup/setup-script/readme.md b/escalation-sn/instance-setup/setup-script/readme.md new file mode 100644 index 0000000..8b599ce --- /dev/null +++ b/escalation-sn/instance-setup/setup-script/readme.md @@ -0,0 +1,47 @@ +Setup ServiceNow Instance with an automation script. + +## Prerequisite +* An available ServiceNow instance with admin credentials. +* The script has been developed against ServiceNow Washington DC version of the instance. + +## Shell Script Variables +* In a shell terminal set the following variables before invoking the script. +```shell +export SN_SERVER='https://.service-now.com' +export AUTH_HEADER="Authorization: Basic " +export DEFAULT_PWD='' +export CONTENT_TYPE='Content-Type: application/json' +``` + +## Execute ServiceNow Instance Setup Script +* Ensure that the provided `sn-instance-setup.sh` script on your developer machine has been granted execute permission. +* In a terminal window ensure your environment variables set earlier are available/visible. +* Execute the script. +```shell +./sn-instance-setup.sh +``` +* Successful completion of the script should show messages like following, however the id values will be different for you. +```text +*** Requester User Sys Id: "a879ca9197b0c2102425b39fe153af6d" +*** Requester User associated to Admin role with Sys Id: "20794e5197b0c2102425b39fe153af59" +*** Approver User Sys Id: "7879ca9197b0c2102425b39fe153af74" +*** Approver Group Sys Id: "f4794e9197b0c2102425b39fe153af3f" +*** Associate approver_user role to approver user Sys Id: "cd794e9197b0c2102425b39fe153af46" +*** Assigned approver user to approver group with Sys Id: "c9794e9197b0c2102425b39fe153af69" +*** New Change Request Sys Id: "89794e9197b0c2102425b39fe153af4b" +*** Triggered change request with Sys Id: "89794e9197b0c2102425b39fe153af4b" +``` + +## Verify the script execution results on ServiceNow instance +Login to the ServiceNow instance and verify the `requester` user, `approver` user, `approver` group and a `change request` are created. + +## Cleaning up +* The instance setup script execution also generates a `clear-data.sh` script, which you can use to clear the data created by instance setup script. +* Clean up the data generated by executing the clear data script, just ensure that the script has been given execute permission. +```shell +./clear-data.sh +``` + +## Issues? +* In case if you see empty or null values in the generated id's, most likely the curl commands to ServiceNow may have failed. Be sure to check the environment variables related to ServiceNow instance url and Auth header are still valid. +* You can also remove the `-s` switch corresponding to silent execution, from the `curl` command execution in the script and see what is the exact error. diff --git a/escalation-sn/instance-setup/sn-instance-setup.sh b/escalation-sn/instance-setup/setup-script/sn-instance-setup.sh similarity index 98% rename from escalation-sn/instance-setup/sn-instance-setup.sh rename to escalation-sn/instance-setup/setup-script/sn-instance-setup.sh index b3d0988..f6e4ee2 100755 --- a/escalation-sn/instance-setup/sn-instance-setup.sh +++ b/escalation-sn/instance-setup/setup-script/sn-instance-setup.sh @@ -5,7 +5,7 @@ export ADMIN_ROLE_SYS_ID="\"2831a114c611228501d4ea6c309d626d\"" export APPROVER_USER_ROLE_SYS_ID="\"debab85bff02110053ccffffffffffb6\"" # SERVICE NOW URLs -export SN_USER_URL=${SN_SERVER}/api/now/table/sys_user?sysparm_input_display_value=true&sysparm_display_value=true +export SN_USER_URL="${SN_SERVER}/api/now/table/sys_user?sysparm_input_display_value=true&sysparm_display_value=true" export SN_ASSIGN_USER_ROLE_URL="${SN_SERVER}/api/now/table/sys_user_has_role" export SN_CREATE_GROUP_URL="${SN_SERVER}/api/now/table/sys_user_group" export SN_ASSIGN_GROUP_ROLE_URL="${SN_SERVER}/api/now/table/sys_group_has_role" @@ -32,7 +32,6 @@ export NEW_REQ_USER_SYS_ID=`curl -s \ --variable %CONTENT_TYPE \ --variable %AUTH_HEADER \ --variable %CREATE_REQ_USER_PAYLOAD \ ---variable %DEFAULT_PWD \ --expand-url {{SN_USER_URL}} \ --expand-header {{CONTENT_TYPE}} \ --expand-header {{AUTH_HEADER}} \ From 787c762741d487e0c0fd56a521a524b3c1dca426 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Fri, 8 Mar 2024 11:47:20 -0500 Subject: [PATCH 03/10] Add ServiceNow manual setup readme --- .../manual-self-guided/readme.md | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 escalation-sn/instance-setup/manual-self-guided/readme.md diff --git a/escalation-sn/instance-setup/manual-self-guided/readme.md b/escalation-sn/instance-setup/manual-self-guided/readme.md new file mode 100644 index 0000000..56f2f8c --- /dev/null +++ b/escalation-sn/instance-setup/manual-self-guided/readme.md @@ -0,0 +1,252 @@ +Setup ServiceNow Instance with a self-guided manual approach. + +## Prerequisite +* An available ServiceNow instance with admin credentials. +* The script has been developed against ServiceNow Washington DC version of the instance. + +## Set General ServiceNow Data and URL Environment Variables +* In a shell terminal set the following environment variables. +```shell +export SN_SERVER='https://.service-now.com' +export AUTH_HEADER="Authorization: Basic " +export DEFAULT_PWD='' +export CONTENT_TYPE='Content-Type: application/json' + +# DOUBLE CHECK FOLLOWING VALUES WITH YOUR OWN INSTANCE +export ADMIN_ROLE_SYS_ID="\"2831a114c611228501d4ea6c309d626d\"" +export APPROVER_USER_ROLE_SYS_ID="\"debab85bff02110053ccffffffffffb6\"" + +# SERVICE NOW URLs +export SN_USER_URL="${SN_SERVER}/api/now/table/sys_user?sysparm_input_display_value=true&sysparm_display_value=true" +export SN_ASSIGN_USER_ROLE_URL="${SN_SERVER}/api/now/table/sys_user_has_role" +export SN_CREATE_GROUP_URL="${SN_SERVER}/api/now/table/sys_user_group" +export SN_ASSIGN_GROUP_ROLE_URL="${SN_SERVER}/api/now/table/sys_group_has_role" +export SN_ASSIGN_USR_TO_GRP_URL="${SN_SERVER}/api/now/table/sys_user_grmember" +export SN_CHANGE_REQUEST_URL="${SN_SERVER}/api/now/table/change_request" +``` + +## Setup ServiceNow Instance + +### CREATE REQUESTER USER +```shell +export CREATE_REQ_USER_PAYLOAD="{ \ + \"user_name\": \"requester\", \ + \"first_name\": \"requester\", \ + \"last_name\": \"user\", \ + \"email\": \"requester@example.com\", \ + \"user_password\": \"${DEFAULT_PWD}\", \ + \"password_needs_reset\": \"false\", \ + \"active\": \"true\", \ + \"locked_out\": \"false\", \ + \"web_service_access_only\": \"false\", \ + \"internal_integration_user\": \"false\", \ + \"roles\": \"admin\" \ +}" + +export NEW_REQ_USER_SYS_ID=$(curl -s \ +--location ${SN_USER_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${CREATE_REQ_USER_PAYLOAD} | jq '.result.sys_id') + +echo "*** REQUESTER USER Sys Id: ${NEW_REQ_USER_SYS_ID}" +``` + +### ASSIGN REQUESTER USER WITH ADMIN ROLE +```shell +export ASSIGN_USER_ROLE_PAYLOAD="{ + \"role\": ${ADMIN_ROLE_SYS_ID}, \ + \"user\": ${NEW_REQ_USER_SYS_ID} \ +}" + +export NEW_USER_ROLE_ASSOC_SYS_ID=$(curl -s \ +--location ${SN_ASSIGN_USER_ROLE_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${ASSIGN_USER_ROLE_PAYLOAD} | jq '.result.sys_id') + +echo "*** REQUESTER USER associated to Admin role with Sys Id: ${NEW_USER_ROLE_ASSOC_SYS_ID}" +``` + +### CREATE APPROVER USER +```shell +export CREATE_APPRV_USER_PAYLOAD="{ \ + \"user_name\": \"manager\", \ + \"first_name\": \"manager\", \ + \"last_name\": \"user\", \ + \"email\": \"manager@example.com\", \ + \"user_password\": \"${DEFAULT_PWD}\", \ + \"password_needs_reset\": \"false\", \ + \"active\": \"true\", \ + \"locked_out\": \"false\", \ + \"web_service_access_only\": \"false\", \ + \"internal_integration_user\": \"false\", \ + \"roles\": \"admin\" \ +}" + +export NEW_APPRV_USER_SYS_ID=$(curl -s \ +--location ${SN_USER_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${CREATE_APPRV_USER_PAYLOAD} | jq '.result.sys_id') + +echo "*** APPROVER USER Sys Id: ${NEW_APPRV_USER_SYS_ID}" +``` + +### CREATE APPROVER GROUP +```shell +export CREATE_GROUP_PAYLOAD="{ + \"name\": \"Approvers\", + \"exclude_manager\": \"false\", + \"manager\": ${NEW_APPRV_USER_SYS_ID}, + \"email\": \"chgapprovers@example.com\", + \"include_members\": \"false\", + \"roles\": \"itil,approver_user\" +}" + +export NEW_APPRV_GRP_SYS_ID=$(curl -s \ +--location ${SN_CREATE_GROUP_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${CREATE_GROUP_PAYLOAD} | jq '.result.sys_id') + +echo "*** APPROVER GROUP Sys Id: ${NEW_APPRV_GRP_SYS_ID}" +``` + +### ADD approver_user ROLE TO APPROVER GROUP +```shell +export ASSIGN_GRP_ROLE_PAYLOAD="{ + \"role\": ${APPROVER_USER_ROLE_SYS_ID}, \ + \"group\": ${NEW_APPRV_GRP_SYS_ID} \ +}" + +export NEW_GRP_ROLE_ASSOC_SYS_ID=$(curl -s \ +--location ${SN_ASSIGN_GROUP_ROLE_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${ASSIGN_GRP_ROLE_PAYLOAD} | jq '.result.sys_id') + +echo "*** Associate approver_user role to approver user Sys Id: ${NEW_GRP_ROLE_ASSOC_SYS_ID}" +``` + +### ASSOCIATE APPROVER USER AND APPROVER GROUP +```shell +export ASSIGN_APPRV_USR_TO_APPRV_GRP_PAYLOAD="{ + \"user\": ${NEW_APPRV_USER_SYS_ID}, \ + \"group\": ${NEW_APPRV_GRP_SYS_ID} \ +}" + +export NEW_ASSIGN_GRP_TO_USR_SYS_ID=$(curl -s \ +--location ${SN_ASSIGN_USR_TO_GRP_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${ASSIGN_APPRV_USR_TO_APPRV_GRP_PAYLOAD} | jq '.result.sys_id') + +echo "*** Assigned approver user to APPROVER GROUP with Sys Id: ${NEW_ASSIGN_GRP_TO_USR_SYS_ID}" +``` + +### CREATE A CHANGE REQUEST +```shell +export CREATE_CHG_REQ_PAYLOAD="{ + \"description\": \"REQUESTER requesting an item\", + \"short_description\": \"REQUESTER requesting an item in short\", + \"comments\": \"REQUESTER requesting an item in comments\", + \"state\": \"new\", + \"assigned_to\": ${NEW_APPRV_USER_SYS_ID}, + \"additional_assignee_list\": ${NEW_APPRV_USER_SYS_ID}, + \"assignment_group\": ${NEW_APPRV_GRP_SYS_ID} +}" + +export NEW_CHG_REQ_SYS_ID=$(curl -s \ +--location ${SN_CHANGE_REQUEST_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${CREATE_CHG_REQ_PAYLOAD} | jq '.result.sys_id') + +echo "*** New Change Request Sys Id: ${NEW_CHG_REQ_SYS_ID}" +``` + +### TRIGGER THE CHANGE REQUEST FOR APPROVAL +```shell +export TEMP=`echo ${NEW_CHG_REQ_SYS_ID} | tr -d "\""` +export TRIGGER_CHG_REQ_URL=${SN_CHANGE_REQUEST_URL}/${TEMP} + +export TRIGGER_CHG_REQ_PAYLOAD="{ + \"state\": \"-4\", + \"approval\": \"requested\" +}" + +export TRIGGER_CHG_REQ_SYS_ID=$(curl -s -X PUT \ +--location ${TRIGGER_CHG_REQ_URL} \ +--header ${CONTENT_TYPE} \ +--header ${AUTH_HEADER} \ +--data-raw ${TRIGGER_CHG_REQ_PAYLOAD} | jq '.result.sys_id') +echo "*** Triggered change request with Sys Id: ${TRIGGER_CHG_REQ_SYS_ID}" +``` + +### Verify the script execution results on ServiceNow instance +Login to the ServiceNow instance and verify the `requester` user, `approver` user, `approver` group and a `change request` are created. + +## Cleaning up + +### SETUP ENVIRONMENT VARIABLES +```shell +export SN_SERVER='https://.service-now.com' +export AUTH_HEADER="Authorization: Basic " +export ACCEPT='Accept: application/json' +``` + +### DELETE CHANGE REQUEST +```shell +export DELETE_SYS_ID=`echo ${NEW_CHG_REQ_SYS_ID} | tr -d "\""` + +curl "${SN_SERVER}/api/now/table/change_request/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` + +### DELETE approver_user ROLE TO APPROVER GROUP +```shell +export DELETE_SYS_ID=`echo ${NEW_GRP_ROLE_ASSOC_SYS_ID} | tr -d "\""` +curl "${SN_SERVER}/api/now/table/sys_group_has_role/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` + +### DELETE APPROVER USER ASSOCIATION WITH APPROVER GROUP +```shell +export DELETE_SYS_ID=`echo ${NEW_ASSIGN_GRP_TO_USR_SYS_ID} | tr -d "\""` +curl "${SN_SERVER}/api/now/table/sys_user_grmember/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` + +### DELETE APPROVER GROUP +```shell +export DELETE_SYS_ID=`echo ${NEW_APPRV_GRP_SYS_ID} | tr -d "\""` +curl "${SN_SERVER}/api/now/table/sys_user_group/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` + +### DELETE APPROVER USER +```shell +export DELETE_SYS_ID=`echo ${NEW_APPRV_USER_SYS_ID} | tr -d "\""` +curl "${SN_SERVER}/api/now/table/sys_user/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` + +### DELETE REQUESTER USER +```shell +export DELETE_SYS_ID=`echo ${NEW_REQ_USER_SYS_ID} | tr -d "\""` +curl "${SN_SERVER}/api/now/table/sys_user/${DELETE_SYS_ID}" \ +--request DELETE \ +--header ${ACCEPT} \ +--header ${AUTH_HEADER} +``` \ No newline at end of file From 7f7e5d2fedca84175b2c8ea7d51e463c17089fec Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Mon, 11 Mar 2024 17:12:19 -0400 Subject: [PATCH 04/10] Begin with create servicenow change request workflow step --- escalation-sn/pom.xml | 199 ++++++++++++++++++ .../src/main/resources/application.properties | 33 +++ .../resources/serviceNowEscalation.sw.yaml | 38 ++++ .../servicenow-escalation-schema.json | 43 ++++ .../src/main/resources/specs/servicenow.yaml | 65 ++++++ 5 files changed, 378 insertions(+) create mode 100644 escalation-sn/pom.xml create mode 100644 escalation-sn/src/main/resources/application.properties create mode 100644 escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml create mode 100644 escalation-sn/src/main/resources/servicenow-escalation-schema.json create mode 100644 escalation-sn/src/main/resources/specs/servicenow.yaml diff --git a/escalation-sn/pom.xml b/escalation-sn/pom.xml new file mode 100644 index 0000000..7ce3d3d --- /dev/null +++ b/escalation-sn/pom.xml @@ -0,0 +1,199 @@ + + + 4.0.0 + dev.parodos + servicenow-escalation + 1.0.0-SNAPSHOT + + kogito-bom + org.kie.kogito + 1.43.0.Final + + 3.10.1 + 11 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 2.16.10.Final + true + 3.0.0-M7 + 0.0.8 + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + ${kogito.bom.group-id} + ${kogito.bom.artifact-id} + ${kogito.bom.version} + pom + import + + + ${quarkus.platform.group-id} + quarkus-kogito-bom + ${quarkus.platform.version} + pom + import + + + io.quarkiverse.embedded.postgresql + quarkus-embedded-postgresql + ${version.io.quarkiverse.embedded.postgresql} + + + + + + + org.kie.kogito + kogito-quarkus-serverless-workflow + + + org.kie.kogito + kogito-quarkus-serverless-workflow-devui + + + org.kie.kogito + kogito-addons-quarkus-process-management + + + org.kie.kogito + kogito-addons-quarkus-source-files + + + + io.quarkiverse.embedded.postgresql + quarkus-embedded-postgresql + + + io.quarkus + quarkus-jdbc-postgresql + + + io.quarkus + quarkus-agroal + + + org.kie.kogito + kogito-addons-quarkus-persistence-jdbc + + + + + org.kie.kogito + kogito-addons-quarkus-jobs-service-embedded + + + + + org.kie.kogito + kogito-addons-quarkus-data-index-inmemory + + + + org.eclipse.angus + angus-mail + 2.0.1 + + + + io.quarkus + quarkus-smallrye-openapi + + + io.quarkus + quarkus-resteasy-jackson + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-junit5 + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + native + + + native + + + + false + native + + + + \ No newline at end of file diff --git a/escalation-sn/src/main/resources/application.properties b/escalation-sn/src/main/resources/application.properties new file mode 100644 index 0000000..4064ece --- /dev/null +++ b/escalation-sn/src/main/resources/application.properties @@ -0,0 +1,33 @@ +# Application properties +# The number of seconds to wait before triggering the escalation request, after the change request has been created +timeout_seconds=${ESCALATION_TIMEOUT_SECONDS:60} +# The polling periodicity of the change request state checker, according to ISO 8601 duration format +polling_periodicity=${POLLING_PERIODICITY:PT6S} + +# SERVICE NOW INSTANCE +quarkus.rest-client.servicenow_yaml.url=${SN_SERVER} +quarkus.openapi-generator.servicenow_yaml.auth.basicAuth.username=${SERVICENOW_USERNAME} +quarkus.openapi-generator.servicenow_yaml.auth.basicAuth.password=${SERVICENOW_PASSWORD} + +#Quarkus +quarkus.http.host=0.0.0.0 +# This is to enable debugging of HTTP request +quarkus.log.category.\"org.apache.http\".level=DEBUG + +# Added +quarkus.http.port=8080 + +kogito.service.url=http://localhost:${quarkus.http.port} + +quarkus.kogito.devservices.enabled=false +quarkus.devservices.enabled=false + +quarkus.swagger-ui.always-include=true +quarkus.kogito.data-index.graphql.ui.always-include=true + +# Kogito runtime persistence configurations +kogito.persistence.type=jdbc +kogito.persistence.proto.marshaller=false +kogito.persistence.query.timeout.millis=10000 +quarkus.datasource.db-kind=postgresql +quarkus.flyway.migrate-at-start=true diff --git a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml new file mode 100644 index 0000000..2d7c19f --- /dev/null +++ b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml @@ -0,0 +1,38 @@ +specVersion: "0.8" +id: servicenow-escalation +name: ServiceNow Change Request escalation +annotations: + - "workflow-type/infrastructure" +version: 0.0.1 +timeouts: + workflowExecTimeout: PT24H +start: CreateChangeRequest +dataInputSchema: servicenow-escalation-schema.json +functions: + # - name: sendNotification + # operation: 'specs/mailtrap.yaml#sendNotification' + - name: createChangeRequest + operation: specs/servicenow.yaml#createChangeRequest + # - name: getChangeRequest + # operation: specs/servicenow.yaml#getChangeRequest + - name: logInfo + type: custom + operation: "sysout:INFO" + +states: + - name: CreateChangeRequest + type: operation + actions: + - functionRef: + refName: createChangeRequest + arguments: + description: ".description" + short_description: ".short_description" + comments: ".comments" + state: ".state" + assigned_to: ".assigned_to" + additional_assignee_list: ".additional_assignee_list" + assignment_group: ".assignment_group" + actionDataFilter: + toStateData: .createdChangeRequest + end: true \ No newline at end of file diff --git a/escalation-sn/src/main/resources/servicenow-escalation-schema.json b/escalation-sn/src/main/resources/servicenow-escalation-schema.json new file mode 100644 index 0000000..a35a382 --- /dev/null +++ b/escalation-sn/src/main/resources/servicenow-escalation-schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Change request description" + }, + "short_description": { + "type": "string", + "description": "Change request short_description" + }, + "comments": { + "type": "string", + "description": "Change request comments" + }, + "state": { + "type": "string", + "description": "Change request state" + }, + "assigned_to": { + "type": "string", + "description": "Change request assigned_to" + }, + "additional_assignee_list": { + "type": "string", + "description": "Change request additional_assignee_list" + }, + "assignment_group": { + "type": "string", + "description": "Change request assignment_group" + } + }, + "required": [ + "description", + "short_description", + "comments", + "state", + "assigned_to", + "additional_assignee_list", + "assignment_group" + ] +} \ No newline at end of file diff --git a/escalation-sn/src/main/resources/specs/servicenow.yaml b/escalation-sn/src/main/resources/specs/servicenow.yaml new file mode 100644 index 0000000..ceb40c5 --- /dev/null +++ b/escalation-sn/src/main/resources/specs/servicenow.yaml @@ -0,0 +1,65 @@ +openapi: 3.0.3 +info: + title: Table API + description: Allows you to perform create, read, update and delete (CRUD) operations on existing tables + version: latest +externalDocs: + url: https://docs.servicenow.com/?context=CSHelp:REST-Table-API +servers: +- url: https://dev143716.service-now.com/ +paths: + /api/now/table/change_request: + post: + description: "Create a record" + operationId: createChangeRequest + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateChangeRequest' + responses: + "200": + description: ok + content: + application/json: + schema: + $ref: '#/components/schemas/CreateChangeRequestResponse' + security: + - basicAuth: [ ] + +components: + schemas: + CreateChangeRequest: + type: object + properties: + description: + type: string + short_description: + type: string + comments: + type: string + state: + type: string + assigned_to: + type: string + additional_assignee_list: + type: string + assignment_group: + type: string + CreateChangeRequestResponse: + type: object + properties: + result: + type: object + properties: + sys_id: + type: string + state: + type: string + number: + type: string + securitySchemes: + basicAuth: + type: http + description: You can access this resource via basic auth. + scheme: basic \ No newline at end of file From f2cdd0acf82bb76c581d678a2c1a7c2f04d43a20 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Tue, 12 Mar 2024 14:42:03 -0400 Subject: [PATCH 05/10] Add timeout, status check and notify to manager workflow steps --- .../resources/serviceNowEscalation.sw.yaml | 54 +++++++++++++++++-- .../src/main/resources/specs/servicenow.yaml | 30 +++++++++++ 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml index 2d7c19f..8a3f83d 100644 --- a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml +++ b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml @@ -9,16 +9,13 @@ timeouts: start: CreateChangeRequest dataInputSchema: servicenow-escalation-schema.json functions: - # - name: sendNotification - # operation: 'specs/mailtrap.yaml#sendNotification' - name: createChangeRequest operation: specs/servicenow.yaml#createChangeRequest - # - name: getChangeRequest - # operation: specs/servicenow.yaml#getChangeRequest + - name: getChangeRequest + operation: specs/servicenow.yaml#getChangeRequest - name: logInfo type: custom operation: "sysout:INFO" - states: - name: CreateChangeRequest type: operation @@ -35,4 +32,51 @@ states: assignment_group: ".assignment_group" actionDataFilter: toStateData: .createdChangeRequest + transition: GetChangeRequest + - name: GetChangeRequest + type: operation + actions: + - name: "SleepBeforeChecking" + functionRef: + refName: "logInfo" + arguments: + message: "\"Sleeping before checking the change request \\(.createdChangeRequest.result)\"" + sleep: + after: PT30S + - name: "getChangeRequest" + functionRef: + refName: getChangeRequest + arguments: + sys_id: ".createdChangeRequest.result.sys_id" + actionDataFilter: + toStateData: .readChangeRequest + transition: IsApproved + - name: IsApproved + type: switch + dataConditions: + - condition: (.readChangeRequest.result.state == "-5") + transition: + nextState: RemindManagerToApprove + - condition: (.readChangeRequest.result.state != "-5") + transition: + nextState: ThankAndTerminate + defaultCondition: + transition: GetChangeRequest + - name: RemindManagerToApprove + type: operation + actions: + - name: "RemindManagerToApprove" + functionRef: + refName: "logInfo" + arguments: + message: "\"Manager, please approve this change request \\(.createdChangeRequest.result.number)\"" + transition: GetChangeRequest + - name: ThankAndTerminate + type: operation + actions: + - name: "ThankAndTerminate" + functionRef: + refName: "logInfo" + arguments: + message: "\"Thanks Manager for approving this change request \\(.createdChangeRequest.result.number)\"" end: true \ No newline at end of file diff --git a/escalation-sn/src/main/resources/specs/servicenow.yaml b/escalation-sn/src/main/resources/specs/servicenow.yaml index ceb40c5..d4171aa 100644 --- a/escalation-sn/src/main/resources/specs/servicenow.yaml +++ b/escalation-sn/src/main/resources/specs/servicenow.yaml @@ -26,6 +26,24 @@ paths: $ref: '#/components/schemas/CreateChangeRequestResponse' security: - basicAuth: [ ] + /api/now/table/change_request/{sys_id}: + get: + description: "Retrieve a record" + operationId: getChangeRequest + parameters: + - name: "sys_id" + in: "path" + required: true + schema: {} + responses: + "200": + description: "ok" + content: + application/json: + schema: + $ref: '#/components/schemas/GetChangeRequestResponse' + security: + - basicAuth: [ ] components: schemas: @@ -58,6 +76,18 @@ components: type: string number: type: string + GetChangeRequestResponse: + type: object + properties: + result: + type: object + properties: + sys_id: + type: string + state: + type: string + number: + type: string securitySchemes: basicAuth: type: http From 61d93a8bbc5b5b4f3ed31a7fd9bf6cd218029a45 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Thu, 14 Mar 2024 13:44:30 -0400 Subject: [PATCH 06/10] Add integration with janus-idp notifications service --- .../resources/serviceNowEscalation.sw.yaml | 22 +- .../main/resources/specs/notifications.yaml | 254 ++++++++++++++++++ 2 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 escalation-sn/src/main/resources/specs/notifications.yaml diff --git a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml index 8a3f83d..ea23d30 100644 --- a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml +++ b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml @@ -13,6 +13,8 @@ functions: operation: specs/servicenow.yaml#createChangeRequest - name: getChangeRequest operation: specs/servicenow.yaml#getChangeRequest + - name: createNotification + operation: specs/notifications.yaml#createNotification - name: logInfo type: custom operation: "sysout:INFO" @@ -67,16 +69,28 @@ states: actions: - name: "RemindManagerToApprove" functionRef: - refName: "logInfo" + refName: "createNotification" arguments: - message: "\"Manager, please approve this change request \\(.createdChangeRequest.result.number)\"" + title: " \"Please approve: \" + (.createdChangeRequest.result.number) " + message: "\"Manager, please approve this change request: \\(.createdChangeRequest.result.number)\"" + origin: "Serverless Workflow Example" + targetUsers: "[\"default/manager\"]" + actions: [] + topic: "Approval Request" + targetGroups: [] transition: GetChangeRequest - name: ThankAndTerminate type: operation actions: - name: "ThankAndTerminate" functionRef: - refName: "logInfo" + refName: "createNotification" arguments: - message: "\"Thanks Manager for approving this change request \\(.createdChangeRequest.result.number)\"" + title: " \"Thanks for approving: \" + (.createdChangeRequest.result.number) " + message: "\"Manager, thanks a ton for approving this change request: \\(.createdChangeRequest.result.number)\"" + origin: "Serverless Workflow Example" + targetUsers: "[\"default/manager\"]" + actions: [] + topic: "Approval Request" + targetGroups: [] end: true \ No newline at end of file diff --git a/escalation-sn/src/main/resources/specs/notifications.yaml b/escalation-sn/src/main/resources/specs/notifications.yaml new file mode 100644 index 0000000..4ad93c8 --- /dev/null +++ b/escalation-sn/src/main/resources/specs/notifications.yaml @@ -0,0 +1,254 @@ +openapi: 3.0.3 +info: + title: Notifications Plugin - OpenAPI Specs + description: |- + Notifications Plugin - OpenAPI Specs + version: 1.0.0 +tags: + - name: notifications + description: notifications plugin +servers: + - url: http://localhost:7007/api/notifications +paths: + /notifications: + post: + tags: + - notifications + summary: Create notification + description: Create notification + operationId: createNotification + requestBody: + description: Create a new notification + content: + application/json: + schema: + $ref: '#/components/schemas/CreateBody' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + properties: + messageId: + type: string + example: bc9f19de-8b7b-49a8-9262-c5036a1ed35e + required: ['messageId'] + get: + tags: + - notifications + summary: Gets notifications + description: Gets notifications + operationId: getNotifications + parameters: + - name: pageSize + in: query + description: Page size of the result + required: false + schema: + type: integer + minimum: 0 + - name: pageNumber + in: query + description: Page number of the result + required: false + schema: + type: integer + minimum: 0 + - name: orderBy + in: query + description: order by field. e.g. created, origin. + required: false + schema: + type: string + enum: + - title + - message + - created + - topic + - origin + - name: orderByDirec + in: query + description: order ascending or descending + required: false + schema: + type: string + enum: + - asc + - desc + - name: containsText + in: query + description: Filter notifications whose either title or message contains the provided string + required: false + schema: + type: string + - name: createdAfter + in: query + description: Only notifications created after this timestamp will be included + required: false + schema: + type: string + format: date-time + - name: messageScope + in: query + description: retrieve either logged-in user messages, system messages or both + required: false + schema: + type: string + enum: + - all + - user + - system + - name: read + in: query + description: Notifications read or not + required: false + schema: + type: boolean + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Notifications' + /notifications/count: + get: + tags: + - notifications + summary: Get notifications count + description: Gets notifications count + operationId: getNotificationsCount + parameters: + - name: containsText + in: query + description: Filter notifications whose either title or message contains the provided string + required: false + schema: + type: string + - name: createdAfter + in: query + description: Only notifications created after this timestamp will be included + required: false + schema: + type: string + format: date-time + - name: messageScope + in: query + description: retrieve either logged-in user messages, system messages or both + required: false + schema: + type: string + enum: + - all + - user + - system + - name: read + in: query + description: Notifications read or not + required: false + schema: + type: boolean + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + properties: + count: + type: number + required: ['count'] + /notifications/read: + put: + tags: + - notifications + summary: Set notification as read/unread + description: Set notification as read/unread + operationId: setRead + parameters: + - name: messageId + in: query + description: The message ID + required: true + schema: + type: string + - name: read + in: query + description: read/unread + required: true + schema: + type: boolean + responses: + '200': + description: Successful operation +components: + schemas: + Notifications: + type: array + items: + $ref: '#/components/schemas/Notification' + Notification: + properties: + id: + type: string + created: + type: string + format: date-time + readByUser: + type: boolean + isSystem: + type: boolean + origin: + type: string + title: + type: string + message: + type: string + topic: + type: string + actions: + type: array + items: + $ref: '#/components/schemas/Action' + required: [id, created, readByUser, isSystem, origin, title, actions] + Action: + properties: + id: + type: string + title: + type: string + url: + type: string + required: [id, title, url] + CreateBody: + properties: + origin: + type: string + title: + type: string + message: + type: string + actions: + type: array + items: + type: object + properties: + title: + type: string + url: + type: string + required: [title, url] + topic: + type: string + targetUsers: + type: array + items: + type: string + targetGroups: + type: array + items: + type: string + required: [origin, title] From 376022ab35a5c99e1990c6819c17aca9c63147bf Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Thu, 14 Mar 2024 15:01:07 -0400 Subject: [PATCH 07/10] Add readme files --- escalation-sn/README.md | 134 +++++++++++++++++++++++++ escalation-sn/instance-setup/readme.md | 4 + 2 files changed, 138 insertions(+) create mode 100644 escalation-sn/README.md create mode 100644 escalation-sn/instance-setup/readme.md diff --git a/escalation-sn/README.md b/escalation-sn/README.md new file mode 100644 index 0000000..c03f490 --- /dev/null +++ b/escalation-sn/README.md @@ -0,0 +1,134 @@ +An escalation workflow integrated with ServiceNow using [SonataFlow](https://sonataflow.org/serverlessworkflow/latest/index.html). + +## Prerequisite +* An available ServiceNow instance with admin credentials. +* Prerequisite data being available on ServiceNow instance with setup instructions [found here](instance-setup/readme.md) +* Janus-idp notifications service is deployed and functionally running with instructions [found here](https://github.com/janus-idp/backstage-plugins/tree/main/plugins/notifications-backend). + +### Specifics about Notifications service +* Add the `manager` user in `notifications-backend/users.yaml` and your file could look something like this +```yaml +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: guest +spec: + profile: + displayName: Guest User + memberOf: [] +--- +apiVersion: backstage.io/v1alpha1 +kind: User +metadata: + name: manager +spec: + profile: + displayName: Manager Approver User + memberOf: [] +``` +* Restart the notifications service +```shell +yarn start:backstage +``` + +* Be sure the create notification call from the command line works successfully. +```shell +curl -X POST http://localhost:7007/api/notifications/notifications -H "Content-Type: application/json" -d '{"title": "My message title", "message": "I have nothing to say", "origin": "my-origin", "targetUsers": ["default/manager"]}' | jq '.' +``` + +* An example response could look like this +```yaml +{ + "messageId": "942b0aa0-79d4-46a7-a973-47573fa19543" +} +``` + +## Workflow Application configuration +Application properties can be initialized from environment variables before running the application: + +| Environment variable | Description | Mandatory | +|-----------------------|-------------|-----------| +| `SN_SERVER` | The ServiceNow server URL | ✅ | +| `SERVICENOW_USERNAME` | The ServiceNow server username | ✅ | +| `SERVICENOW_PASSWORD` | The ServiceNow server password | ✅ | + +## How to run + +### Start the workflow application +```bash +mvn clean quarkus:dev +``` + +### Trigger/start the workflow +* Example of POST to trigger the flow (see input schema in [servicenow-escalation-schema.json](./src/main/resources/servicenow-escalation-schema.json)): +```bash +# This is a request sent to the workflow instance +curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow-escalation -d '{ + "description": "", + "short_description": "", + "comments": "", + "state": "new", + "assigned_to": " e.g. 950597b6973002102425b39fe153af41", + "additional_assignee_list": " e.g. 950597b6973002102425b39fe153af41", + "assignment_group": " e.g. e50597b6973002102425b39fe153afb2" +}' | jq '.' +``` +* You should see a response similar to the following +```json +{ + "id": "99203918-3e8c-46a6-ba43-9a025172f8c2", + "workflowdata": { + "description": "Requester requesting an item", + "short_description": "Requester requesting an item in short", + "comments": "Requester requesting an item in comments", + "state": "new", + "assigned_to": "950597b6973002102425b39fe153af41", + "additional_assignee_list": "950597b6973002102425b39fe153af41", + "assignment_group": "e50597b6973002102425b39fe153afb2", + "createdChangeRequest": { + "result": { + "sys_id": "6dfa4ff7973002102425b39fe153afed", + "state": "-5", + "number": "CHG0030045" + } + } + } +} +``` +* Wait for a minute or two before proceeding to the next step, to view notifications created by the workflow, to remind the approver to approve the created change request. + * In the current implementation this reminder is generated every `30s` by the workflow. + +* After this wait, login to notifications service's postgres database console. + +* You will see `reminder` notification(s) created by `Notifications service` as shown in the following example. +```text + id | message +--------------------------------------+--------------------------------------------------------------------- + 8a3c945d-9009-4188-a28e-17ceee853a99 | Manager, please approve this change request: CHG0030045 +``` + +### End the workflow by updating the change request + +* Update the Change Request state on ServiceNow instance to help terminate the workflow +```bash +# This is a request sent to the ServiceNow instance +curl --location --request PUT 'https:///api/now/table/change_request/' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic ' \ +--data '{ + "state": "-4", + "approval": "requested" +}' +``` + +* You will see a `thank you` notification created by `Notifications service` as shown in the following example. +Note: this may appear after a few seconds, as the workflow needs to wait for completion of the timeout event of `30s`, before this notification is created. +```text + id | message +--------------------------------------+--------------------------------------------------------------------- + 3e9cd0a6-c4c8-4ea1-973a-dbb063279397 | Manager, thanks a ton for approving this change request: CHG0030045 +``` + +Tips: +* Visit [Workflow Instances](http://localhost:8080/q/dev/org.kie.kogito.kogito-quarkus-serverless-workflow-devui/workflowInstances) +* Visit (Data Index Query Service)[http://localhost:8080/q/graphql-ui/] \ No newline at end of file diff --git a/escalation-sn/instance-setup/readme.md b/escalation-sn/instance-setup/readme.md new file mode 100644 index 0000000..53e314d --- /dev/null +++ b/escalation-sn/instance-setup/readme.md @@ -0,0 +1,4 @@ +Setup your ServiceNow instance using one of the following + +* [Automated approach](setup-script/readme.md) +* [Manual approach](manual-self-guided/readme.md) \ No newline at end of file From b823583c0cdcabb115490477f3a18a99313c6e99 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Fri, 15 Mar 2024 15:51:52 -0400 Subject: [PATCH 08/10] Address the review comments - pass 1 --- escalation-sn/README.md | 5 +- .../readme.md | 0 .../sn-instance-setup.sh | 0 escalation-sn/instance-setup/readme.md | 2 +- escalation-sn/pom.xml | 87 +----- .../main/resources/application-dev.properties | 7 + .../src/main/resources/application.properties | 9 - .../servicenow-escalation-schema.json | 2 +- .../resources/serviceNowEscalation.sw.yaml | 18 +- .../main/resources/specs/notifications.yaml | 254 ------------------ 10 files changed, 31 insertions(+), 353 deletions(-) rename escalation-sn/instance-setup/{setup-script => automated-script}/readme.md (100%) rename escalation-sn/instance-setup/{setup-script => automated-script}/sn-instance-setup.sh (100%) create mode 100644 escalation-sn/src/main/resources/application-dev.properties rename escalation-sn/src/main/resources/{ => schemas}/servicenow-escalation-schema.json (94%) delete mode 100644 escalation-sn/src/main/resources/specs/notifications.yaml diff --git a/escalation-sn/README.md b/escalation-sn/README.md index c03f490..fca1377 100644 --- a/escalation-sn/README.md +++ b/escalation-sn/README.md @@ -70,7 +70,8 @@ curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow "state": "new", "assigned_to": " e.g. 950597b6973002102425b39fe153af41", "additional_assignee_list": " e.g. 950597b6973002102425b39fe153af41", - "assignment_group": " e.g. e50597b6973002102425b39fe153afb2" + "assignment_group": " e.g. e50597b6973002102425b39fe153afb2", + "sn_url": "https://" }' | jq '.' ``` * You should see a response similar to the following @@ -126,7 +127,7 @@ Note: this may appear after a few seconds, as the workflow needs to wait for com ```text id | message --------------------------------------+--------------------------------------------------------------------- - 3e9cd0a6-c4c8-4ea1-973a-dbb063279397 | Manager, thanks a ton for approving this change request: CHG0030045 + 3e9cd0a6-c4c8-4ea1-973a-dbb063279397 | Manager, thanks a ton for approving the change request: CHG0030045 ``` Tips: diff --git a/escalation-sn/instance-setup/setup-script/readme.md b/escalation-sn/instance-setup/automated-script/readme.md similarity index 100% rename from escalation-sn/instance-setup/setup-script/readme.md rename to escalation-sn/instance-setup/automated-script/readme.md diff --git a/escalation-sn/instance-setup/setup-script/sn-instance-setup.sh b/escalation-sn/instance-setup/automated-script/sn-instance-setup.sh similarity index 100% rename from escalation-sn/instance-setup/setup-script/sn-instance-setup.sh rename to escalation-sn/instance-setup/automated-script/sn-instance-setup.sh diff --git a/escalation-sn/instance-setup/readme.md b/escalation-sn/instance-setup/readme.md index 53e314d..e746961 100644 --- a/escalation-sn/instance-setup/readme.md +++ b/escalation-sn/instance-setup/readme.md @@ -1,4 +1,4 @@ Setup your ServiceNow instance using one of the following -* [Automated approach](setup-script/readme.md) +* [Automated approach](automated-script/readme.md) * [Manual approach](manual-self-guided/readme.md) \ No newline at end of file diff --git a/escalation-sn/pom.xml b/escalation-sn/pom.xml index 7ce3d3d..91c8f1e 100644 --- a/escalation-sn/pom.xml +++ b/escalation-sn/pom.xml @@ -6,39 +6,21 @@ 4.0.0 dev.parodos servicenow-escalation + + dev.parodos + swf-parent + 1.0.0-SNAPSHOT + ../swf-parent + 1.0.0-SNAPSHOT - kogito-bom - org.kie.kogito 1.43.0.Final - 3.10.1 - 11 - UTF-8 - UTF-8 - quarkus-bom - io.quarkus.platform 2.16.10.Final - true - 3.0.0-M7 0.0.8 - - ${quarkus.platform.group-id} - ${quarkus.platform.artifact-id} - ${quarkus.platform.version} - pom - import - - - ${kogito.bom.group-id} - ${kogito.bom.artifact-id} - ${kogito.bom.version} - pom - import - ${quarkus.platform.group-id} quarkus-kogito-bom @@ -125,63 +107,6 @@ test - - - - ${quarkus.platform.group-id} - quarkus-maven-plugin - ${quarkus.platform.version} - true - - - - build - generate-code - generate-code-tests - - - - - - maven-compiler-plugin - ${compiler-plugin.version} - - - -parameters - - - - - maven-surefire-plugin - ${surefire-plugin.version} - - - org.jboss.logmanager.LogManager - ${maven.home} - - - - - maven-failsafe-plugin - ${surefire-plugin.version} - - - - integration-test - verify - - - - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager - ${maven.home} - - - - - - - native diff --git a/escalation-sn/src/main/resources/application-dev.properties b/escalation-sn/src/main/resources/application-dev.properties new file mode 100644 index 0000000..bf057e5 --- /dev/null +++ b/escalation-sn/src/main/resources/application-dev.properties @@ -0,0 +1,7 @@ +#Quarkus +quarkus.http.host=0.0.0.0 +# This is to enable debugging of HTTP request +quarkus.log.category.\"org.apache.http\".level=DEBUG + +# Added +quarkus.http.port=8080 \ No newline at end of file diff --git a/escalation-sn/src/main/resources/application.properties b/escalation-sn/src/main/resources/application.properties index 4064ece..40ac36d 100644 --- a/escalation-sn/src/main/resources/application.properties +++ b/escalation-sn/src/main/resources/application.properties @@ -9,16 +9,7 @@ quarkus.rest-client.servicenow_yaml.url=${SN_SERVER} quarkus.openapi-generator.servicenow_yaml.auth.basicAuth.username=${SERVICENOW_USERNAME} quarkus.openapi-generator.servicenow_yaml.auth.basicAuth.password=${SERVICENOW_PASSWORD} -#Quarkus -quarkus.http.host=0.0.0.0 -# This is to enable debugging of HTTP request -quarkus.log.category.\"org.apache.http\".level=DEBUG - -# Added -quarkus.http.port=8080 - kogito.service.url=http://localhost:${quarkus.http.port} - quarkus.kogito.devservices.enabled=false quarkus.devservices.enabled=false diff --git a/escalation-sn/src/main/resources/servicenow-escalation-schema.json b/escalation-sn/src/main/resources/schemas/servicenow-escalation-schema.json similarity index 94% rename from escalation-sn/src/main/resources/servicenow-escalation-schema.json rename to escalation-sn/src/main/resources/schemas/servicenow-escalation-schema.json index a35a382..8015726 100644 --- a/escalation-sn/src/main/resources/servicenow-escalation-schema.json +++ b/escalation-sn/src/main/resources/schemas/servicenow-escalation-schema.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "description": { diff --git a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml index ea23d30..efe853e 100644 --- a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml +++ b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml @@ -7,14 +7,18 @@ version: 0.0.1 timeouts: workflowExecTimeout: PT24H start: CreateChangeRequest -dataInputSchema: servicenow-escalation-schema.json +extensions: + - extensionid: workflow-uri-definitions + definitions: + notifications: "https://raw.githubusercontent.com/janus-idp/backstage-plugins/%40janus-idp/plugin-notifications-backend%401.0.3/plugins/notifications-backend/src/openapi.yaml" +dataInputSchema: schemas/servicenow-escalation-schema.json functions: - name: createChangeRequest operation: specs/servicenow.yaml#createChangeRequest - name: getChangeRequest operation: specs/servicenow.yaml#getChangeRequest - name: createNotification - operation: specs/notifications.yaml#createNotification + operation: notifications#createNotification - name: logInfo type: custom operation: "sysout:INFO" @@ -75,9 +79,11 @@ states: message: "\"Manager, please approve this change request: \\(.createdChangeRequest.result.number)\"" origin: "Serverless Workflow Example" targetUsers: "[\"default/manager\"]" - actions: [] topic: "Approval Request" targetGroups: [] + actions: + - title: "Approve" + url: " (.sn_url) + \"/nav_to.do?uri=change_request.do?sys_id=\" + (.createdChangeRequest.result.sys_id) " transition: GetChangeRequest - name: ThankAndTerminate type: operation @@ -87,10 +93,12 @@ states: refName: "createNotification" arguments: title: " \"Thanks for approving: \" + (.createdChangeRequest.result.number) " - message: "\"Manager, thanks a ton for approving this change request: \\(.createdChangeRequest.result.number)\"" + message: "\"Manager, thanks a ton for approving the change request: \\(.createdChangeRequest.result.number)\"" origin: "Serverless Workflow Example" targetUsers: "[\"default/manager\"]" - actions: [] topic: "Approval Request" targetGroups: [] + actions: + - title: "Approved Change Request" + url: " (.sn_url) + \"/nav_to.do?uri=change_request.do?sys_id=\" + (.createdChangeRequest.result.sys_id) " end: true \ No newline at end of file diff --git a/escalation-sn/src/main/resources/specs/notifications.yaml b/escalation-sn/src/main/resources/specs/notifications.yaml deleted file mode 100644 index 4ad93c8..0000000 --- a/escalation-sn/src/main/resources/specs/notifications.yaml +++ /dev/null @@ -1,254 +0,0 @@ -openapi: 3.0.3 -info: - title: Notifications Plugin - OpenAPI Specs - description: |- - Notifications Plugin - OpenAPI Specs - version: 1.0.0 -tags: - - name: notifications - description: notifications plugin -servers: - - url: http://localhost:7007/api/notifications -paths: - /notifications: - post: - tags: - - notifications - summary: Create notification - description: Create notification - operationId: createNotification - requestBody: - description: Create a new notification - content: - application/json: - schema: - $ref: '#/components/schemas/CreateBody' - responses: - '200': - description: Successful operation - content: - application/json: - schema: - type: object - properties: - messageId: - type: string - example: bc9f19de-8b7b-49a8-9262-c5036a1ed35e - required: ['messageId'] - get: - tags: - - notifications - summary: Gets notifications - description: Gets notifications - operationId: getNotifications - parameters: - - name: pageSize - in: query - description: Page size of the result - required: false - schema: - type: integer - minimum: 0 - - name: pageNumber - in: query - description: Page number of the result - required: false - schema: - type: integer - minimum: 0 - - name: orderBy - in: query - description: order by field. e.g. created, origin. - required: false - schema: - type: string - enum: - - title - - message - - created - - topic - - origin - - name: orderByDirec - in: query - description: order ascending or descending - required: false - schema: - type: string - enum: - - asc - - desc - - name: containsText - in: query - description: Filter notifications whose either title or message contains the provided string - required: false - schema: - type: string - - name: createdAfter - in: query - description: Only notifications created after this timestamp will be included - required: false - schema: - type: string - format: date-time - - name: messageScope - in: query - description: retrieve either logged-in user messages, system messages or both - required: false - schema: - type: string - enum: - - all - - user - - system - - name: read - in: query - description: Notifications read or not - required: false - schema: - type: boolean - responses: - '200': - description: Successful operation - content: - application/json: - schema: - $ref: '#/components/schemas/Notifications' - /notifications/count: - get: - tags: - - notifications - summary: Get notifications count - description: Gets notifications count - operationId: getNotificationsCount - parameters: - - name: containsText - in: query - description: Filter notifications whose either title or message contains the provided string - required: false - schema: - type: string - - name: createdAfter - in: query - description: Only notifications created after this timestamp will be included - required: false - schema: - type: string - format: date-time - - name: messageScope - in: query - description: retrieve either logged-in user messages, system messages or both - required: false - schema: - type: string - enum: - - all - - user - - system - - name: read - in: query - description: Notifications read or not - required: false - schema: - type: boolean - responses: - '200': - description: Successful operation - content: - application/json: - schema: - type: object - properties: - count: - type: number - required: ['count'] - /notifications/read: - put: - tags: - - notifications - summary: Set notification as read/unread - description: Set notification as read/unread - operationId: setRead - parameters: - - name: messageId - in: query - description: The message ID - required: true - schema: - type: string - - name: read - in: query - description: read/unread - required: true - schema: - type: boolean - responses: - '200': - description: Successful operation -components: - schemas: - Notifications: - type: array - items: - $ref: '#/components/schemas/Notification' - Notification: - properties: - id: - type: string - created: - type: string - format: date-time - readByUser: - type: boolean - isSystem: - type: boolean - origin: - type: string - title: - type: string - message: - type: string - topic: - type: string - actions: - type: array - items: - $ref: '#/components/schemas/Action' - required: [id, created, readByUser, isSystem, origin, title, actions] - Action: - properties: - id: - type: string - title: - type: string - url: - type: string - required: [id, title, url] - CreateBody: - properties: - origin: - type: string - title: - type: string - message: - type: string - actions: - type: array - items: - type: object - properties: - title: - type: string - url: - type: string - required: [title, url] - topic: - type: string - targetUsers: - type: array - items: - type: string - targetGroups: - type: array - items: - type: string - required: [origin, title] From 9696ba83549163b53cbd27348cf5ddf591759227 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Fri, 15 Mar 2024 17:34:05 -0400 Subject: [PATCH 09/10] Address the review comments - add parent pom with related changes --- escalation-sn/pom.xml | 17 ++++++++--------- swf-parent/pom.xml | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/escalation-sn/pom.xml b/escalation-sn/pom.xml index 91c8f1e..4274ab9 100644 --- a/escalation-sn/pom.xml +++ b/escalation-sn/pom.xml @@ -4,7 +4,6 @@ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 4.0.0 - dev.parodos servicenow-escalation dev.parodos @@ -14,24 +13,23 @@ 1.0.0-SNAPSHOT - 1.43.0.Final - - 2.16.10.Final - 0.0.8 + 0.1.3 ${quarkus.platform.group-id} - quarkus-kogito-bom + ${quarkus.platform.artifact-id} ${quarkus.platform.version} pom import - io.quarkiverse.embedded.postgresql - quarkus-embedded-postgresql - ${version.io.quarkiverse.embedded.postgresql} + ${kogito.bom.group-id} + ${kogito.bom.artifact-id} + ${kogito.bom.version} + pom + import @@ -57,6 +55,7 @@ io.quarkiverse.embedded.postgresql quarkus-embedded-postgresql + ${version.io.quarkiverse.embedded.postgresql} io.quarkus diff --git a/swf-parent/pom.xml b/swf-parent/pom.xml index 5aeaaf4..a215794 100644 --- a/swf-parent/pom.xml +++ b/swf-parent/pom.xml @@ -18,7 +18,7 @@ 3.2.9.Final org.kie.kogito kogito-bom - 999-SNAPSHOT + 2.44.0.Alpha true 3.0.0-M7 From 0f268bc4d4e4a56d2943303b3cc9da05a70e1579 Mon Sep 17 00:00:00 2001 From: Kamlesh Panchal Date: Sat, 16 Mar 2024 19:16:07 -0400 Subject: [PATCH 10/10] Further refine workflow and update readme --- escalation-sn/README.md | 48 ++++++++++++------- .../resources/serviceNowEscalation.sw.yaml | 8 +++- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/escalation-sn/README.md b/escalation-sn/README.md index fca1377..bdf80ed 100644 --- a/escalation-sn/README.md +++ b/escalation-sn/README.md @@ -63,7 +63,7 @@ mvn clean quarkus:dev * Example of POST to trigger the flow (see input schema in [servicenow-escalation-schema.json](./src/main/resources/servicenow-escalation-schema.json)): ```bash # This is a request sent to the workflow instance -curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow-escalation -d '{ +CREATE_CR_RESP=$(curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow-escalation -d '{ "description": "", "short_description": "", "comments": "", @@ -72,9 +72,10 @@ curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow "additional_assignee_list": " e.g. 950597b6973002102425b39fe153af41", "assignment_group": " e.g. e50597b6973002102425b39fe153afb2", "sn_url": "https://" -}' | jq '.' +}'); +echo $CREATE_CR_RESP | jq '.'; ``` -* You should see a response similar to the following +* You should see a response similar to the following, which provides newly create change request information. ```json { "id": "99203918-3e8c-46a6-ba43-9a025172f8c2", @@ -96,6 +97,26 @@ curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow } } ``` + +* From the response above extract the sys_id of the newly created change request. +```shell +CREATED_CR_SYS_ID=$( jq -r '.workflowdata.createdChangeRequest.result.sys_id' <<< "${CREATE_CR_RESP}" ); +echo "${CREATED_CR_SYS_ID}"; +``` + +* Trigger the newly created change request for approval by changing its state to `assessment` state. +```shell +TRIGGER_CR_CMD="curl --location --request PUT 'https://dev143716.service-now.com/api/now/table/change_request/${CREATED_CR_SYS_ID}' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic ' \ +--data '{ + \"state\": \"-4\", + \"approval\": \"requested\" +}'"; + +eval $TRIGGER_CR_CMD | jq '.'; +``` + * Wait for a minute or two before proceeding to the next step, to view notifications created by the workflow, to remind the approver to approve the created change request. * In the current implementation this reminder is generated every `30s` by the workflow. @@ -105,24 +126,15 @@ curl -XPOST -H "Content-Type: application/json" http://localhost:8080/servicenow ```text id | message --------------------------------------+--------------------------------------------------------------------- - 8a3c945d-9009-4188-a28e-17ceee853a99 | Manager, please approve this change request: CHG0030045 + 8a3c945d-9009-4188-a28e-17ceee853a99 | Manager, please approve the change request: CHG0030045 ``` -### End the workflow by updating the change request - -* Update the Change Request state on ServiceNow instance to help terminate the workflow -```bash -# This is a request sent to the ServiceNow instance -curl --location --request PUT 'https:///api/now/table/change_request/' \ ---header 'Content-Type: application/json' \ ---header 'Authorization: Basic ' \ ---data '{ - "state": "-4", - "approval": "requested" -}' -``` +### End the workflow by approving the change request -* You will see a `thank you` notification created by `Notifications service` as shown in the following example. +* Login to the ServiceNow instance UI with `manager` user and credentials. +* Click All -> My Approvals menu item, in the resulting list, click the change request that was created. +* In the change request detail screen, set the `State` to `Approved` and click `Update`. +* As the change request is approved, you will see a `thank you` notification created by `Notifications service` as shown in the following example. Note: this may appear after a few seconds, as the workflow needs to wait for completion of the timeout event of `30s`, before this notification is created. ```text id | message diff --git a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml index efe853e..cbecc4b 100644 --- a/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml +++ b/escalation-sn/src/main/resources/serviceNowEscalation.sw.yaml @@ -60,10 +60,16 @@ states: - name: IsApproved type: switch dataConditions: + # Change request state is new, wait for it to come to assessment phase - condition: (.readChangeRequest.result.state == "-5") + transition: + nextState: GetChangeRequest + # Change request is now in assessment phase + - condition: (.readChangeRequest.result.state == "-4") transition: nextState: RemindManagerToApprove - - condition: (.readChangeRequest.result.state != "-5") + # Change request is approved + - condition: (.readChangeRequest.result.state == "-3") transition: nextState: ThankAndTerminate defaultCondition: