From ba7283d6a0a256afcaf84776a6f85ed9e533208b Mon Sep 17 00:00:00 2001 From: Laurent Date: Mon, 11 Oct 2021 15:09:01 -0700 Subject: [PATCH] #402: Fixing python script Adding code for modifying a CR as well --- incubating/service-now/lib/snow.py | 102 +++++++++++++++++++++-------- incubating/service-now/step.yaml | 44 +++++++++---- 2 files changed, 107 insertions(+), 39 deletions(-) diff --git a/incubating/service-now/lib/snow.py b/incubating/service-now/lib/snow.py index 37d1dc0ae..146ce71f9 100644 --- a/incubating/service-now/lib/snow.py +++ b/incubating/service-now/lib/snow.py @@ -24,7 +24,7 @@ def processCallbackResponse(response): print("Callback creation successful") -def processChangeRequestResponse(response): +def processCreateChangeRequestResponse(response): print("Processing answer from CR creation REST call") print("Change Request returned code %s" % (response.status_code)) @@ -45,7 +45,7 @@ def processChangeRequestResponse(response): if os.path.exists(env_file_path): env_file = open(env_file_path, "a") env_file.write(f"CR_NUMBER={CR_NUMBER}\n") - env_file.write(f"CR_SYS_ID={CR_SYSID}\n") + env_file.write(f"CR_SYSID={CR_SYSID}\n") env_file.write("CR_FULL_JSON=/codefresh/volume/servicenow-cr.json\n") env_file.close() @@ -56,11 +56,11 @@ def processChangeRequestResponse(response): # # Call SNow REST API to create a new Change Request # Fields required are pasted in the data -def createChangeRequest(user, password, baseUrl, title, data, description): +def createChangeRequest(user, password, baseUrl, data): if DEBUG: print("Entering createChangeRequest:") - print("Body: " + data) + print(f"Data: {data}") if (bool(data)): crBody=json.loads(data) @@ -82,49 +82,77 @@ def createChangeRequest(user, password, baseUrl, title, data, description): json = crBody, headers = {"content-type":"application/json"}, auth=(user, password)) - processChangeRequestResponse(response=resp) + processCreateChangeRequestResponse(response=resp) -def processCloseChangeRequestResponse(response): +def processModifyChangeRequestResponse(response, action): - print("Processing answer from CR closing REST call") + print("Processing answer from CR %s REST call" %(action)) print("Close Change Request returned code %s" % (response.status_code)) if (response.status_code != 200 and response.status_code != 201): - print("Close Change Request creation failed with code %s" % (response.status_code)) + print("%s Change Request creation failed with code %s" % (action, response.status_code)) print("Error: " + response.text) return response.status_code - print("Close Change Request creation successful") + print("%s Change Request creation successful" %(action)) data=response.json() # json.loads(response.text) FULL_JSON=json.dumps(data, indent=2) + if (action == "close" ): + jsonVar="CR_CLOSE_FULL_JSON" + jsonFileName="/codefresh/volume/servicenow-cr-close.json" + elif (action == "update" ): + jsonVar="CR_UPDATE_FULL_JSON" + jsonFileName="/codefresh/volume/servicenow-cr-update.json" + else: + print("ERROR: action unknonw. Should not be here. Error should have been caught earlier") if os.path.exists(env_file_path): env_file = open(env_file_path, "a") - env_file.write("CR_CLOSE_FULL_JSON=/codefresh/volume/servicenow-cr-close.json\n") + env_file.write(f"{jsonVar}=/codefresh/volume/servicenow-cr-close.json\n") env_file.close() json_file=open("/codefresh/volume/servicenow-cr-close.json", "w") json_file.write(FULL_JSON) json_file.close() - + # Call SNow REST API to close a CR # Fields required are pasted in the data -def closeChangeRequest(user, password, baseUrl, sysid, code): +def closeChangeRequest(user, password, baseUrl, sysid, code, notes, data): if DEBUG: print("Entering closeChangeRequest:") - print("Body: " + data) + print(f"DATA: {data}") if (bool(data)): crBody=json.loads(data) else: crBody= {} crBody["state"] = 3 crBody["close_code"] = code + crBody["close_notes"] = notes url="%s/now/table/change_request/%s" % (baseUrl, sysid) resp=requests.patch(url, json = crBody, headers = {"content-type":"application/json"}, auth=(user, password)) - processCloseChangeRequestResponse(response=resp) + processModifyChangeRequestResponse(response=resp, action="close") + +# Call SNow REST API to update a CR +# Fields required are pasted in the data +def updateChangeRequest(user, password, baseUrl, sysid, data): + if DEBUG: + print("Entering closeChangeRequest:") + print(f"DATA: {data}") + if (bool(data)): + crBody=json.loads(data) + else: + crBody= {} + print("WARNING: CR_DATA is empty. What are you updating exactly?") + + url="%s/now/table/change_request/%s" % (baseUrl, sysid) + resp=requests.patch(url, + json = crBody, + headers = {"content-type":"application/json"}, + auth=(user, password)) + processModifyChangeRequestResponse(response=resp, action="update") # Use rest API to call scripted REST API to start a flow that will wait for CR # to be approved or rejected, then callback Codefreh to approve/deny pipeline # @@ -153,26 +181,31 @@ def callback(user, password, baseUrl, number, cf_build_id, token): auth=(user, password)) processCallbackResponse(response=resp) +def checkSysid(sysid): + if DEBUG: + print("Entering checkSysid: ") + print(" CR_SYSID: %s" % (sysid)) + + if ( sysid == None ): + sys.exit("FATAL: CR_SYS_ID is not defined.") + + def main(): global DEBUG - ACTION = os.getenv('action', 'createCR').lower() + ACTION = os.getenv('CR_ACTION', 'createCR').lower() USER = os.getenv('SN_USER') PASSWORD = os.getenv('SN_PASSWORD') INSTANCE = os.getenv('SN_INSTANCE') - DATA = os.getenv('data') + DATA = os.getenv('CR_DATA') #DEBUG = True if os.getenv('debug', "false").lower == "true" else False if ACTION == "createcr": - TITLE = os.getenv('title', 'Change Request created by Codefresh') - DESCRIPTION = os.getenv('description', '') createChangeRequest(user=USER, password=PASSWORD, baseUrl=getBaseUrl(instance=INSTANCE), - title=TITLE, - data=DATA, - description=DESCRIPTION) + data=DATA) elif ACTION == "callback": callback(user=USER, password=PASSWORD, @@ -182,17 +215,34 @@ def main(): cf_build_id=os.getenv('CF_BUILD_ID') ) elif ACTION == "closecr": - CR_SYS_ID= os.getenv('CR_SYS_ID') - CODE= "successful" if os.getenv('closeCode') == "success" else "unsuccessful" + CR_SYSID= os.getenv('CR_SYSID') + CODE=os.getenv('CR_CLOSE_CODE') + NOTES=os.getenv('CR_CLOSE_NOTES') + + checkSysid(CR_SYSID) + closeChangeRequest( user=USER, password=PASSWORD, baseUrl=getBaseUrl(instance=INSTANCE), - number=os.getenv('CR_SYSID'), - code=CODE + sysid=os.getenv('CR_SYSID'), + code=CODE, + notes=NOTES, + data=DATA + ) + elif ACTION == "updatecr": + CR_SYSID= os.getenv('CR_SYSID') + checkSysid(CR_SYSID) + + updateChangeRequest( + user=USER, + password=PASSWORD, + baseUrl=getBaseUrl(instance=INSTANCE), + sysid=os.getenv('CR_SYSID'), + data=DATA ) else: - sys.exit(f"Unknown action: {ACTION}") + sys.exit(f"FATAL: Unknown action: {ACTION}. Allowed values are createCR, closeCR or updateCR.") if __name__ == "__main__": diff --git a/incubating/service-now/step.yaml b/incubating/service-now/step.yaml index e652ac37d..d48e07874 100644 --- a/incubating/service-now/step.yaml +++ b/incubating/service-now/step.yaml @@ -3,7 +3,7 @@ version: '1.0' metadata: name: laurent-cf/service-now version: 1.1.0 - isPublic: true + isPublic: false description: Integration with ServiceNow Change Management sources: - https://github.com/codefresh-io/steps/tree/master/incubating/service-now @@ -13,7 +13,7 @@ metadata: - email: laurent.rochette@codefresh.io categories: - utilities - official: true + official: false tags: [] icon: type: svg @@ -27,11 +27,11 @@ metadata: type: service-now stage: deploy arguments: - action: createCR + CR_ACTION: createCR SN_INSTANCE: https://instance.service-now.com SN_USER: ${{SN_USER}} SN_PASSWORD: ${{SN_PASSWORD}} - data: '{"short_description":"This is a Change Request created by Codefresh","description":"long description for Codefresh build ${{CF_BUILD_ID}}","justification":"because our app is awesome"}' + CR_DATA: '{"short_description":"This is a Change Request created by Codefresh","description":"long description for Codefresh build ${{CF_BUILD_ID}}","justification":"because our app is awesome"}' wait: stage: deploy title: Waiting for the Change Request to be approved @@ -45,12 +45,13 @@ metadata: type: service-now stage: cleaning arguments: - action: closeCR + CR_ACTION: closeCR SN_INSTANCE: https://instance.service-now.com SN_USER: ${{SN_USER}} SN_PASSWORD: ${{SN_PASSWORD}} - close_code: ${{workflow.status}} - data: '{"close_code":"success", "close_note":"Closed automatically by Codefresh build ${{CF_BUILD_ID}}"}' + CR_CLOSE_CODE: successful + CR_CLOSE_NOTES: "CR closed by Codefresh build ${{CF_BUILD_ID}}" + CR_DATA: '{"close_note":"Closed automatically by Codefresh build ${{CF_BUILD_ID}}"}' spec: arguments: |- @@ -98,9 +99,14 @@ spec: }, "CR_CLOSE_CODE": { "type": "string", - "description": "Close code for the closeCR action: successful or unsuccessful", + "description": "Close code for the closeCR action: successful, successful_issues or unsuccessful", "default": "successful" }, + "CR_CLOSE_NOTES": { + "type": "string", + "description": "Close notes for the closeCR action: successful, successful_issues or unsuccessful", + "default": "Closed by Codefresh" + }, "DEBUG": { "type": "string", "default": "false", @@ -117,12 +123,12 @@ spec: "patterns": [], "required": [ "CR_NUMBER", - "CR_SYS_ID" + "CR_SYSID" ], "properties": { - "CR_SYS_ID": { + "CR_SYSID": { "type": "string", - "description": "The sys_id of the CR created" + "description": "The sysid of the CR created" }, "CR_NUMBER": { "type": "string", @@ -132,7 +138,7 @@ spec: } stepsTemplate: |- [[ if .Arguments.CR_ACTION == "closeCR" ]] - createCR: + closeCR: name: Close a ServiceNow Change Request title: Use REST API to close the CR #image: 'quay.io/codefreshplugins/service-now:1.1.0' @@ -143,6 +149,18 @@ spec: - '[[ $key ]]=[[ $val ]]' [[- end ]] [[ end ]] + [[ if .Arguments.CR_ACTION == "updateCR" ]] + closeCR: + name: Update a ServiceNow Change Request + title: Use REST API to close the CR + #image: 'quay.io/codefreshplugins/service-now:1.1.0' + image: lrochette/service-now:1.1.0 + environment: + - CR_ACTION=updateCR + [[ range $key, $val := .Arguments ]] + - '[[ $key ]]=[[ $val ]]' + [[- end ]] + [[ end ]] [[ if .Arguments.CR_ACTION == "createCR" ]] createCR: name: Create a ServiceNow Change Request @@ -160,7 +178,7 @@ spec: commands: - | codefresh create annotation workflow ${{CF_BUILD_ID}} CR_NUMBER=${{CR_NUMBER}} - export createAnnotation_CF_OUTPUT_URL='[[.Arguments.SN_INSTANCE]]/nav_to.do?uri=/change_request.do?sys_id=${{CR_SYS_ID}}' + export createAnnotation_CF_OUTPUT_URL='[[.Arguments.SN_INSTANCE]]/nav_to.do?uri=/change_request.do?sys_id=${{CR_SYSID}}' # echo $createAnnotation_CF_OUTPUT_URL # cf_export createAnnotation_CF_OUTPUT_URL callback: