From dc09e108935f5d020d2da99668324a69d812d3d4 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Fri, 26 May 2023 14:23:22 -0400 Subject: [PATCH 1/6] Create process.py Initial commit --- tools/snow_importer/process.py | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tools/snow_importer/process.py diff --git a/tools/snow_importer/process.py b/tools/snow_importer/process.py new file mode 100644 index 0000000..97008c5 --- /dev/null +++ b/tools/snow_importer/process.py @@ -0,0 +1,80 @@ +# read the servicenow CMDB table (should we make it configurable?) +# for each entry create a yaml and upload it + +import os +import requests +import yaml +import json + +# Set your Cortex API Token as Environment Variable COTEX_API_TOKEN +c_token = os.getenv('CORTEX_API_TOKEN') +# ServiceNow token 64-bit encoded username:password for basic auth +s_token = os.getenv('SNOW_API_TOKEN') +# Update the URLs where different +c_url = "https://api.getcortexapp.com/" +s_url = "https://dev93537.service-now.com/" + +# We are going to query the CMDB_appl table but will store it as a variable since this is likely to vary from instance to instance +s_table = 'cmdb_ci_appl' + +# The full servicenow URL to send the request - note that we are only retrieving the sys_id, name, and owned_by fields (edit as needed) +service_url= s_url + 'api/now/table/' + s_table + '?sysparm_fields=sys_id%2Cname%2Cowned_by' +# The headers +headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Basic ' + s_token} +#Let's get all the records from ServiceNow +response = requests.get(service_url,headers=headers) +print(response.text) +j_response = json.loads(response.text) +services = j_response['result'] +for s in services: + #let's see if we have an owner + info = {} + owners = [] + links = [] + if (s['owned_by'] != ""): + u_sys_id = s['owned_by']['value'] + #print(u_sys_id) + #we need the email of the user so we can assign it to the user + user_url = s_url + '/api/now/table/sys_user?sysparm_query=sys_id%3D' + u_sys_id + '&sysparm_fields=email' + u_headers = headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Basic ' + s_token} + u_resp = requests.get(user_url,headers=u_headers) + j_resp = json.loads(u_resp.text) + print(j_resp) + user_email = j_resp['result'][0]['email'] + owners.append({'type': 'email', 'email': user_email}) + info['x-cortex-owners'] = owners + else: + print('no owner found, so will not add ownership to service in Cortex') + service_name = s['name'] + info['title'] = service_name + #let's convert the name to a tag + s_tag = service_name.replace(' ','-').lower() + print(s_tag) + info['x-cortex-tag'] = s_tag + links.append({'name': 'ServiceNow','type':'ServiceNow Link','url': s_url + 'nav_to.do?uri=cmdb_ci_appl.do?sys_id=' + s['sys_id']}) + info['x-cortex-link'] = links + + #Let's make sure the service doesn't already exist + gs_url = c_url + "api/v1/catalog/" + s_tag + "/openapi?yaml=true" + c_headers = { + 'Accept': '*/*', + 'Authorization': 'Bearer ' + c_token + } + s_response = requests.get(gs_url, headers=c_headers) + print(s_response.status_code) + #If we get 404, means not found so let's add it + if s_response.status_code == 404: + #code to add service + print("Service not found in Cortex, uploading now...") + u_url = c_url + 'api/v1/open-api' + u_headers = {'Content-Type': 'application/openapi;charset=UTF-8', 'Authorization': 'Bearer ' + c_token } + data= yaml.dump({'openapi': '3.0.1', 'info': info}) + u_response = requests.post(u_url, headers=u_headers, data=data) + if (u_response.status_code == 200): + print('Succesfully uploaded service') + #print(u_response.text) + + elif s_response.status_code == 200: + print('service found! Will not update it') + #TODO code to update service + #let's get the service yaml and update only the fields that could have changed (owner?) From e28e83019bc0589be64003372d442f1b19323692 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Fri, 26 May 2023 14:32:22 -0400 Subject: [PATCH 2/6] Create README.MD --- tools/snow_importer/README.MD | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tools/snow_importer/README.MD diff --git a/tools/snow_importer/README.MD b/tools/snow_importer/README.MD new file mode 100644 index 0000000..8e98718 --- /dev/null +++ b/tools/snow_importer/README.MD @@ -0,0 +1,25 @@ +## ServiceNow Importer + +ServiceNow Importer is a script to help you import items from your CMDB to Cortex as Services. + +## API tokens + +The script reads the tokens from environment variables. + +For the Cortex API Token, assign it to a `CORTEX_API_TOKEN` environment variable. To obtain the API Token, go to `Settings` > `API Keys`. Note that only Administrators have access to get API keys. + +For the ServiceNow Token, assing it to the `SNOW_API_TOKEN` environment variable. The script uses `Basic` authentication so you will need to Base64 encode your `username`:`password`. +You can use a tool like this [one](https://www.debugbear.com/basic-auth-header-generator) to do the encoding. + +### Configuraiton + +The script by default reads in all records from the `cmdb_appl` table but is set as a variable(`s_table`) so you can change this if the records you wish to import are stored in a different table. +If you wish to only update a subset of the records, add the nescessary `sysparm_query` to the `service-url` variable. + +### Ownership + +The script reads in the `owned by` field to get the user that owns the item. It retrieves the user'a email from ServiceNow and sets it as the owner in Cortex. + +### Links + +The script will add a link to the corresponding ServiceNow Item From bfd2852193e459d2d1a07d1a565901255ce65306 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Fri, 26 May 2023 14:40:31 -0400 Subject: [PATCH 3/6] Update README.MD --- tools/snow_importer/README.MD | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/snow_importer/README.MD b/tools/snow_importer/README.MD index 8e98718..2945c71 100644 --- a/tools/snow_importer/README.MD +++ b/tools/snow_importer/README.MD @@ -23,3 +23,7 @@ The script reads in the `owned by` field to get the user that owns the item. It ### Links The script will add a link to the corresponding ServiceNow Item + +### Custom Data + +The script will add the ServiceNow sys_id as custom data to the service in Cortex From 81587caa8940bcaa0e4b50ddbb78b485c57d42c0 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Fri, 26 May 2023 14:41:20 -0400 Subject: [PATCH 4/6] Update process.py Updated to add custom data with ServiceNow sys_id --- tools/snow_importer/process.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/snow_importer/process.py b/tools/snow_importer/process.py index 97008c5..a3a88c2 100644 --- a/tools/snow_importer/process.py +++ b/tools/snow_importer/process.py @@ -72,6 +72,17 @@ u_response = requests.post(u_url, headers=u_headers, data=data) if (u_response.status_code == 200): print('Succesfully uploaded service') + #Let's add custom-data to store the servicenow sys_id + cd_headers = { + 'Authorization': 'Bearer ' + c_token, + 'Content-Type': 'application/json' + } + cd_url = c_url + 'api/v1/catalog/' + s_tag + '/custom-data' + json_body = { + "key":"ServiceNow sys_id", + "value": s['sys_id'] + } + cd_resp = requests.post(url=cd_url, json=json_body, headers=cd_headers) #print(u_response.text) elif s_response.status_code == 200: From b311d9157b4e070b52cf35977fde0a71c2a47359 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Fri, 26 May 2023 14:43:08 -0400 Subject: [PATCH 5/6] Update README.MD --- tools/snow_importer/README.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/snow_importer/README.MD b/tools/snow_importer/README.MD index 2945c71..1acee25 100644 --- a/tools/snow_importer/README.MD +++ b/tools/snow_importer/README.MD @@ -1,6 +1,6 @@ ## ServiceNow Importer -ServiceNow Importer is a script to help you import items from your CMDB to Cortex as Services. +ServiceNow Importer is a script to help you import items from your CMDB to Cortex as Services. The script could easily be modified to also import items from ServiceNow as Resources ## API tokens From c49d391db75ba1d2f233deed3f4ac5c9e6bc1337 Mon Sep 17 00:00:00 2001 From: cremerfc Date: Tue, 30 May 2023 09:35:09 -0400 Subject: [PATCH 6/6] Update process.py Added some more comments and optimizations --- tools/snow_importer/process.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/snow_importer/process.py b/tools/snow_importer/process.py index a3a88c2..60d1f20 100644 --- a/tools/snow_importer/process.py +++ b/tools/snow_importer/process.py @@ -17,7 +17,7 @@ # We are going to query the CMDB_appl table but will store it as a variable since this is likely to vary from instance to instance s_table = 'cmdb_ci_appl' -# The full servicenow URL to send the request - note that we are only retrieving the sys_id, name, and owned_by fields (edit as needed) +# The full servicenow URL to send the request - note that we are only retrieving the sys_id, name, and owned_by fields (edit as needed) - if we only want a subset of the records, consider adding service_url= s_url + 'api/now/table/' + s_table + '?sysparm_fields=sys_id%2Cname%2Cowned_by' # The headers headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Basic ' + s_token} @@ -34,7 +34,7 @@ if (s['owned_by'] != ""): u_sys_id = s['owned_by']['value'] #print(u_sys_id) - #we need the email of the user so we can assign it to the user + #we need the email of the user so we can assign it to the service in Cortex as an owner user_url = s_url + '/api/now/table/sys_user?sysparm_query=sys_id%3D' + u_sys_id + '&sysparm_fields=email' u_headers = headers = {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Basic ' + s_token} u_resp = requests.get(user_url,headers=u_headers) @@ -45,12 +45,12 @@ info['x-cortex-owners'] = owners else: print('no owner found, so will not add ownership to service in Cortex') - service_name = s['name'] - info['title'] = service_name + info['title'] = s['name'] #let's convert the name to a tag - s_tag = service_name.replace(' ','-').lower() + s_tag = s['name'].replace(' ','-').lower() print(s_tag) info['x-cortex-tag'] = s_tag + #Let's add at link that points to the service in ServiceNow links.append({'name': 'ServiceNow','type':'ServiceNow Link','url': s_url + 'nav_to.do?uri=cmdb_ci_appl.do?sys_id=' + s['sys_id']}) info['x-cortex-link'] = links