floe-servicenow 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop_local.yml +5 -0
- data/.whitesource +3 -0
- data/CHANGELOG.md +24 -0
- data/LICENSE.txt +202 -0
- data/README.md +185 -0
- data/Rakefile +12 -0
- data/docs/cmdb.md +343 -0
- data/docs/incident.md +270 -0
- data/docs/oauth.md +98 -0
- data/docs/service_catalog.md +423 -0
- data/docs/table.md +320 -0
- data/examples/cmdb.asl +90 -0
- data/examples/create_server_ci.asl +43 -0
- data/examples/incident.asl +53 -0
- data/examples/oauth.asl +67 -0
- data/examples/service_catalog.asl +77 -0
- data/examples/table.asl +138 -0
- data/exe/floe-servicenow +9 -0
- data/lib/floe/service_now.rb +1 -0
- data/lib/floe/servicenow/cmdb.rb +282 -0
- data/lib/floe/servicenow/incident.rb +128 -0
- data/lib/floe/servicenow/methods.rb +73 -0
- data/lib/floe/servicenow/oauth.rb +39 -0
- data/lib/floe/servicenow/runner.rb +73 -0
- data/lib/floe/servicenow/service_catalog.rb +446 -0
- data/lib/floe/servicenow/table.rb +217 -0
- data/lib/floe/servicenow/version.rb +7 -0
- data/lib/floe/servicenow.rb +35 -0
- metadata +130 -0
data/examples/table.asl
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Comment": "ServiceNow Table API Examples - Demonstrates all CRUD operations",
|
|
3
|
+
"StartAt": "ListTables",
|
|
4
|
+
"States": {
|
|
5
|
+
"ListTables": {
|
|
6
|
+
"Type": "Task",
|
|
7
|
+
"Resource": "servicenow://table/list_tables",
|
|
8
|
+
"Credentials": {
|
|
9
|
+
"username.$": "$$.Credentials.username",
|
|
10
|
+
"password.$": "$$.Credentials.password"
|
|
11
|
+
},
|
|
12
|
+
"Parameters": {
|
|
13
|
+
"instance_id.$": "$.instance_id",
|
|
14
|
+
"query": "nameSTARTSWITHcmdb",
|
|
15
|
+
"limit": 5,
|
|
16
|
+
"fields": "name,label"
|
|
17
|
+
},
|
|
18
|
+
"ResultPath": "$.tables",
|
|
19
|
+
"Next": "QueryRecords"
|
|
20
|
+
},
|
|
21
|
+
"QueryRecords": {
|
|
22
|
+
"Type": "Task",
|
|
23
|
+
"Resource": "servicenow://table/query_records",
|
|
24
|
+
"Credentials": {
|
|
25
|
+
"username.$": "$$.Credentials.username",
|
|
26
|
+
"password.$": "$$.Credentials.password"
|
|
27
|
+
},
|
|
28
|
+
"Parameters": {
|
|
29
|
+
"instance_id.$": "$.instance_id",
|
|
30
|
+
"table_name": "incident",
|
|
31
|
+
"query": "active=true^priority=1",
|
|
32
|
+
"limit": 10,
|
|
33
|
+
"fields": "sys_id,number,short_description,state,priority",
|
|
34
|
+
"display_value": "true"
|
|
35
|
+
},
|
|
36
|
+
"ResultPath": "$.incidents",
|
|
37
|
+
"Next": "GetRecord"
|
|
38
|
+
},
|
|
39
|
+
"GetRecord": {
|
|
40
|
+
"Type": "Task",
|
|
41
|
+
"Resource": "servicenow://table/get_record",
|
|
42
|
+
"Credentials": {
|
|
43
|
+
"username.$": "$$.Credentials.username",
|
|
44
|
+
"password.$": "$$.Credentials.password"
|
|
45
|
+
},
|
|
46
|
+
"Parameters": {
|
|
47
|
+
"instance_id.$": "$.instance_id",
|
|
48
|
+
"table_name": "incident",
|
|
49
|
+
"sys_id.$": "$.incidents.result[0].sys_id",
|
|
50
|
+
"fields": "number,short_description,state,priority,assigned_to",
|
|
51
|
+
"display_value": "all"
|
|
52
|
+
},
|
|
53
|
+
"ResultPath": "$.incident_detail",
|
|
54
|
+
"Next": "CreateRecord"
|
|
55
|
+
},
|
|
56
|
+
"CreateRecord": {
|
|
57
|
+
"Type": "Task",
|
|
58
|
+
"Resource": "servicenow://table/create_record",
|
|
59
|
+
"Credentials": {
|
|
60
|
+
"username.$": "$$.Credentials.username",
|
|
61
|
+
"password.$": "$$.Credentials.password"
|
|
62
|
+
},
|
|
63
|
+
"Parameters": {
|
|
64
|
+
"instance_id.$": "$.instance_id",
|
|
65
|
+
"table_name": "incident",
|
|
66
|
+
"data": {
|
|
67
|
+
"short_description": "Test incident created by workflow",
|
|
68
|
+
"urgency": "3",
|
|
69
|
+
"impact": "3",
|
|
70
|
+
"category": "Software",
|
|
71
|
+
"subcategory": "Email"
|
|
72
|
+
},
|
|
73
|
+
"display_value": "true"
|
|
74
|
+
},
|
|
75
|
+
"ResultPath": "$.new_incident",
|
|
76
|
+
"Next": "PatchRecord"
|
|
77
|
+
},
|
|
78
|
+
"PatchRecord": {
|
|
79
|
+
"Type": "Task",
|
|
80
|
+
"Resource": "servicenow://table/patch_record",
|
|
81
|
+
"Credentials": {
|
|
82
|
+
"username.$": "$$.Credentials.username",
|
|
83
|
+
"password.$": "$$.Credentials.password"
|
|
84
|
+
},
|
|
85
|
+
"Parameters": {
|
|
86
|
+
"instance_id.$": "$.instance_id",
|
|
87
|
+
"table_name": "incident",
|
|
88
|
+
"sys_id.$": "$.new_incident.result.sys_id",
|
|
89
|
+
"data": {
|
|
90
|
+
"state": "2",
|
|
91
|
+
"work_notes": "Updated by workflow - investigating issue"
|
|
92
|
+
},
|
|
93
|
+
"display_value": "true"
|
|
94
|
+
},
|
|
95
|
+
"ResultPath": "$.patched_incident",
|
|
96
|
+
"Next": "UpdateRecord"
|
|
97
|
+
},
|
|
98
|
+
"UpdateRecord": {
|
|
99
|
+
"Type": "Task",
|
|
100
|
+
"Resource": "servicenow://table/update_record",
|
|
101
|
+
"Credentials": {
|
|
102
|
+
"username.$": "$$.Credentials.username",
|
|
103
|
+
"password.$": "$$.Credentials.password"
|
|
104
|
+
},
|
|
105
|
+
"Parameters": {
|
|
106
|
+
"instance_id.$": "$.instance_id",
|
|
107
|
+
"table_name": "incident",
|
|
108
|
+
"sys_id.$": "$.new_incident.result.sys_id",
|
|
109
|
+
"data": {
|
|
110
|
+
"short_description": "Test incident - UPDATED",
|
|
111
|
+
"urgency": "3",
|
|
112
|
+
"impact": "3"
|
|
113
|
+
},
|
|
114
|
+
"display_value": "true"
|
|
115
|
+
},
|
|
116
|
+
"ResultPath": "$.updated_incident",
|
|
117
|
+
"Next": "DeleteRecord"
|
|
118
|
+
},
|
|
119
|
+
"DeleteRecord": {
|
|
120
|
+
"Type": "Task",
|
|
121
|
+
"Resource": "servicenow://table/delete_record",
|
|
122
|
+
"Credentials": {
|
|
123
|
+
"username.$": "$$.Credentials.username",
|
|
124
|
+
"password.$": "$$.Credentials.password"
|
|
125
|
+
},
|
|
126
|
+
"Parameters": {
|
|
127
|
+
"instance_id.$": "$.instance_id",
|
|
128
|
+
"table_name": "incident",
|
|
129
|
+
"sys_id.$": "$.new_incident.result.sys_id"
|
|
130
|
+
},
|
|
131
|
+
"ResultPath": "$.delete_result",
|
|
132
|
+
"Next": "Success"
|
|
133
|
+
},
|
|
134
|
+
"Success": {
|
|
135
|
+
"Type": "Succeed"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
data/exe/floe-servicenow
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "floe/servicenow"
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Floe
|
|
6
|
+
module ServiceNow
|
|
7
|
+
class Cmdb < Floe::ServiceNow::Methods
|
|
8
|
+
# Get a Configuration Item (CI) by sys_id
|
|
9
|
+
def self.get_ci(params, secrets, _context)
|
|
10
|
+
error = verify_credentials(secrets)
|
|
11
|
+
error ||= verify_get_ci_params(params)
|
|
12
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
13
|
+
|
|
14
|
+
table = params["table"] || "cmdb_ci"
|
|
15
|
+
sys_id = params["sys_id"]
|
|
16
|
+
|
|
17
|
+
http_params = build_http_params(
|
|
18
|
+
"GET",
|
|
19
|
+
"/api/now/table/#{table}/#{sys_id}",
|
|
20
|
+
params,
|
|
21
|
+
secrets
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
http_request(http_params, {}, {})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Query Configuration Items with optional filters
|
|
28
|
+
def self.query_cis(params, secrets, _context)
|
|
29
|
+
error = verify_credentials(secrets)
|
|
30
|
+
error ||= verify_query_cis_params(params)
|
|
31
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
32
|
+
|
|
33
|
+
instance_id = params["instance_id"]
|
|
34
|
+
table = params["table"] || "cmdb_ci"
|
|
35
|
+
username = secrets["username"]
|
|
36
|
+
password = secrets["password"]
|
|
37
|
+
|
|
38
|
+
require "base64"
|
|
39
|
+
authorization = "Basic #{::Base64.urlsafe_encode64("#{username}:#{password}")}"
|
|
40
|
+
|
|
41
|
+
headers = {
|
|
42
|
+
"Authorization" => authorization,
|
|
43
|
+
"Content-Type" => "application/json",
|
|
44
|
+
"Accept" => "application/json"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
query_params = {}
|
|
48
|
+
query_params["sysparm_query"] = params["query"] if params["query"]
|
|
49
|
+
query_params["sysparm_limit"] = params["limit"] if params["limit"]
|
|
50
|
+
query_params["sysparm_offset"] = params["offset"] if params["offset"]
|
|
51
|
+
query_params["sysparm_fields"] = params["fields"] if params["fields"]
|
|
52
|
+
|
|
53
|
+
http_params = {
|
|
54
|
+
"Method" => params["method"],
|
|
55
|
+
"Url" => "https://#{instance_id}.service-now.com/api/now/table/#{table}",
|
|
56
|
+
"Options" => {"Encoding" => "JSON"},
|
|
57
|
+
"Headers" => headers,
|
|
58
|
+
"QueryParameters" => query_params
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
http_request(http_params, {}, {})
|
|
63
|
+
rescue => err
|
|
64
|
+
ServiceNow.error!({}, :cause => err.to_s)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Create a new Configuration Item
|
|
69
|
+
def self.create_ci(params, secrets, _context)
|
|
70
|
+
error = verify_credentials(secrets)
|
|
71
|
+
error ||= verify_create_ci_params(params)
|
|
72
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
73
|
+
|
|
74
|
+
table = params["table"] || "cmdb_ci"
|
|
75
|
+
|
|
76
|
+
http_params = build_http_params(
|
|
77
|
+
"POST",
|
|
78
|
+
"/api/now/table/#{table}",
|
|
79
|
+
params,
|
|
80
|
+
secrets,
|
|
81
|
+
:body => params.except("instance_id", "table")
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
http_request(http_params, {}, {})
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Update an existing Configuration Item
|
|
88
|
+
def self.update_ci(params, secrets, _context)
|
|
89
|
+
error = verify_credentials(secrets)
|
|
90
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
91
|
+
|
|
92
|
+
error = verify_update_ci_params(params)
|
|
93
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
94
|
+
|
|
95
|
+
table = params["table"] || "cmdb_ci"
|
|
96
|
+
sys_id = params["sys_id"]
|
|
97
|
+
|
|
98
|
+
http_params = build_http_params(
|
|
99
|
+
"PATCH",
|
|
100
|
+
"/api/now/table/#{table}/#{sys_id}",
|
|
101
|
+
params,
|
|
102
|
+
secrets,
|
|
103
|
+
:body => params.except("sys_id", "instance_id", "table")
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
http_request(http_params, {}, {})
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Delete a Configuration Item
|
|
110
|
+
def self.delete_ci(params, secrets, _context)
|
|
111
|
+
error = verify_credentials(secrets)
|
|
112
|
+
error ||= verify_delete_ci_params(params)
|
|
113
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
114
|
+
|
|
115
|
+
table = params["table"] || "cmdb_ci"
|
|
116
|
+
sys_id = params["sys_id"]
|
|
117
|
+
|
|
118
|
+
http_params = build_http_params(
|
|
119
|
+
"DELETE",
|
|
120
|
+
"/api/now/table/#{table}/#{sys_id}",
|
|
121
|
+
params,
|
|
122
|
+
secrets
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
http_request(http_params, {}, {})
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Get CI relationships
|
|
129
|
+
def self.get_ci_relationships(params, secrets, _context)
|
|
130
|
+
error = verify_credentials(secrets)
|
|
131
|
+
error ||= verify_get_ci_relationships_params(params)
|
|
132
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
133
|
+
|
|
134
|
+
sys_id = params["sys_id"]
|
|
135
|
+
|
|
136
|
+
# Get CI instance
|
|
137
|
+
query_params = {
|
|
138
|
+
"sysparm_display_value" => "true",
|
|
139
|
+
"sysparm_exclude_reference_link" => "true"
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
http_params = build_http_params(
|
|
143
|
+
"GET",
|
|
144
|
+
"/api/now/cmdb/instance/cmdb_ci/#{sys_id}",
|
|
145
|
+
params,
|
|
146
|
+
secrets,
|
|
147
|
+
:query => query_params
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
ci_response = http_request(http_params, {}, {})
|
|
151
|
+
return ci_response unless ci_response["success"]
|
|
152
|
+
|
|
153
|
+
# Get relationships
|
|
154
|
+
rel_query_params = {
|
|
155
|
+
"sysparm_query" => "parent=#{sys_id}^ORchild=#{sys_id}",
|
|
156
|
+
"sysparm_display_value" => "true"
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
rel_http_params = build_http_params(
|
|
160
|
+
"GET",
|
|
161
|
+
"/api/now/table/cmdb_rel_ci",
|
|
162
|
+
params,
|
|
163
|
+
secrets,
|
|
164
|
+
:query => rel_query_params
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
rel_response = http_request(rel_http_params, {}, {})
|
|
168
|
+
return rel_response unless rel_response["success"]
|
|
169
|
+
|
|
170
|
+
# Merge results
|
|
171
|
+
ci_data = ci_response["output"]["result"]
|
|
172
|
+
rel_data = rel_response["output"]["result"]
|
|
173
|
+
output = ci_data.merge("relationships" => rel_data)
|
|
174
|
+
|
|
175
|
+
ServiceNow.success!({}, :output => output)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Create a CI relationship
|
|
179
|
+
def self.create_ci_relationship(params, secrets, _context)
|
|
180
|
+
error = verify_credentials(secrets)
|
|
181
|
+
error ||= verify_create_ci_relationship_params(params)
|
|
182
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
183
|
+
|
|
184
|
+
body = {
|
|
185
|
+
"parent" => params["parent_sys_id"],
|
|
186
|
+
"child" => params["child_sys_id"],
|
|
187
|
+
"type" => params["relationship_type"],
|
|
188
|
+
"connection_strength" => params["connection_strength"] || "1"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
http_params = build_http_params(
|
|
192
|
+
"POST",
|
|
193
|
+
"/api/now/table/cmdb_rel_ci",
|
|
194
|
+
params,
|
|
195
|
+
secrets,
|
|
196
|
+
:body => body
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
http_request(http_params, {}, {})
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Get CI classes (types)
|
|
203
|
+
def self.get_ci_classes(params, secrets, _context)
|
|
204
|
+
error = verify_credentials(secrets)
|
|
205
|
+
error ||= verify_instance_id(params)
|
|
206
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
207
|
+
|
|
208
|
+
query_params = {
|
|
209
|
+
"sysparm_query" => "nameSTARTSWITHcmdb_ci",
|
|
210
|
+
"sysparm_fields" => "name,label,super_class"
|
|
211
|
+
}
|
|
212
|
+
query_params["sysparm_limit"] = params["limit"] if params["limit"]
|
|
213
|
+
|
|
214
|
+
http_params = build_http_params(
|
|
215
|
+
"GET",
|
|
216
|
+
"/api/now/table/sys_db_object",
|
|
217
|
+
params,
|
|
218
|
+
secrets,
|
|
219
|
+
:query => query_params
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
http_request(http_params, {}, {})
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Verify parameters for get_ci
|
|
226
|
+
private_class_method def self.verify_get_ci_params(params)
|
|
227
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
228
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
229
|
+
|
|
230
|
+
nil
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Verify parameters for query_cis
|
|
234
|
+
private_class_method def self.verify_query_cis_params(params)
|
|
235
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
236
|
+
|
|
237
|
+
nil
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Verify parameters for create_ci
|
|
241
|
+
private_class_method def self.verify_create_ci_params(params)
|
|
242
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
243
|
+
|
|
244
|
+
nil
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Verify parameters for update_ci
|
|
248
|
+
private_class_method def self.verify_update_ci_params(params)
|
|
249
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
250
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
251
|
+
|
|
252
|
+
nil
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Verify parameters for delete_ci
|
|
256
|
+
private_class_method def self.verify_delete_ci_params(params)
|
|
257
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
258
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
259
|
+
|
|
260
|
+
nil
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Verify parameters for get_ci_relationships
|
|
264
|
+
private_class_method def self.verify_get_ci_relationships_params(params)
|
|
265
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
266
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
267
|
+
|
|
268
|
+
nil
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Verify parameters for create_ci_relationship
|
|
272
|
+
private_class_method def self.verify_create_ci_relationship_params(params)
|
|
273
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
274
|
+
return "Missing Parameter: parent_sys_id" if params["parent_sys_id"].nil?
|
|
275
|
+
return "Missing Parameter: child_sys_id" if params["child_sys_id"].nil?
|
|
276
|
+
return "Missing Parameter: relationship_type" if params["relationship_type"].nil?
|
|
277
|
+
|
|
278
|
+
nil
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Floe
|
|
6
|
+
module ServiceNow
|
|
7
|
+
class Incident < Floe::ServiceNow::Methods
|
|
8
|
+
# Create a new incident in ServiceNow
|
|
9
|
+
def self.create_incident(params, secrets, _context)
|
|
10
|
+
error = verify_credentials(secrets)
|
|
11
|
+
error ||= verify_create_params(params)
|
|
12
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
13
|
+
|
|
14
|
+
http_params = build_http_params(
|
|
15
|
+
"POST",
|
|
16
|
+
"/api/now/table/incident",
|
|
17
|
+
params,
|
|
18
|
+
secrets,
|
|
19
|
+
:body => params.except("instance_id")
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
http_request(http_params, {}, {})
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get an incident by sys_id
|
|
26
|
+
def self.get_incident(params, secrets, _context)
|
|
27
|
+
error = verify_credentials(secrets)
|
|
28
|
+
error ||= verify_get_params(params)
|
|
29
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
30
|
+
|
|
31
|
+
sys_id = params["sys_id"]
|
|
32
|
+
|
|
33
|
+
http_params = build_http_params(
|
|
34
|
+
"GET",
|
|
35
|
+
"/api/now/table/incident/#{sys_id}",
|
|
36
|
+
params,
|
|
37
|
+
secrets
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
http_request(http_params, {}, {})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Update an existing incident
|
|
44
|
+
def self.update_incident(params, secrets, _context)
|
|
45
|
+
error = verify_credentials(secrets)
|
|
46
|
+
error ||= verify_update_params(params)
|
|
47
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
48
|
+
|
|
49
|
+
sys_id = params["sys_id"]
|
|
50
|
+
|
|
51
|
+
http_params = build_http_params(
|
|
52
|
+
"PATCH",
|
|
53
|
+
"/api/now/table/incident/#{sys_id}",
|
|
54
|
+
params,
|
|
55
|
+
secrets,
|
|
56
|
+
:body => params.except("sys_id", "instance_id")
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
http_request(http_params, {}, {})
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.resolve_incident(params, secrets, context)
|
|
63
|
+
params['attributes'] ||= {}
|
|
64
|
+
params['attributes']['state'] = '6' # state enum 6 is resolved
|
|
65
|
+
params['attributes']['resolution_code'] = params.delete('close_code') if params['close_code']
|
|
66
|
+
params['attributes']['resolution_notes'] = params.delete('close_notes') if params['close_notes']
|
|
67
|
+
|
|
68
|
+
update_incident(params, secrets, context)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.close_incident(params, secrets, context)
|
|
72
|
+
params['attributes'] ||= {}
|
|
73
|
+
params['attributes']['state'] = '7' # state enum 7 is closed
|
|
74
|
+
params['attributes']['resolution_code'] = params.delete('close_code') if params['close_code']
|
|
75
|
+
params['attributes']['resolution_notes'] = params.delete('close_notes') if params['close_notes']
|
|
76
|
+
|
|
77
|
+
update_incident(params, secrets, context)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Query incidents with optional filters
|
|
81
|
+
def self.query_incidents(params, secrets, _context)
|
|
82
|
+
error = verify_credentials(secrets)
|
|
83
|
+
error ||= verify_instance_id(params)
|
|
84
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
85
|
+
|
|
86
|
+
query_params = {}
|
|
87
|
+
query_params["sysparm_query"] = params["query"] if params["query"]
|
|
88
|
+
query_params["sysparm_limit"] = params["limit"] if params["limit"]
|
|
89
|
+
query_params["sysparm_offset"] = params["offset"] if params["offset"]
|
|
90
|
+
query_params["sysparm_fields"] = params["fields"] if params["fields"]
|
|
91
|
+
|
|
92
|
+
http_params = build_http_params(
|
|
93
|
+
"GET",
|
|
94
|
+
"/api/now/table/incident",
|
|
95
|
+
params,
|
|
96
|
+
secrets,
|
|
97
|
+
:query => query_params
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
http_request(http_params, {}, {})
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Verify parameters for create_incident
|
|
104
|
+
private_class_method def self.verify_create_params(params)
|
|
105
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
106
|
+
return "Missing Parameter: short_description" if params["short_description"].nil?
|
|
107
|
+
|
|
108
|
+
nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Verify parameters for get_incident
|
|
112
|
+
private_class_method def self.verify_get_params(params)
|
|
113
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
114
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
115
|
+
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Verify parameters for update_incident
|
|
120
|
+
private_class_method def self.verify_update_params(params)
|
|
121
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
122
|
+
return "Missing Parameter: sys_id" if params["sys_id"].nil?
|
|
123
|
+
|
|
124
|
+
nil
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Floe
|
|
4
|
+
module ServiceNow
|
|
5
|
+
class Methods < Floe::BuiltinRunner::Methods
|
|
6
|
+
private_class_method def self.verify_credentials(secrets)
|
|
7
|
+
return "Missing Credentials" if secrets.nil?
|
|
8
|
+
|
|
9
|
+
# Allow either username/password OR access_token
|
|
10
|
+
has_basic_auth = secrets["username"] && secrets["password"]
|
|
11
|
+
has_oauth = secrets["access_token"]
|
|
12
|
+
|
|
13
|
+
return "Missing Credentials: Provide either (username and password) or access_token" unless has_basic_auth || has_oauth
|
|
14
|
+
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private_class_method def self.verify_instance_id(params)
|
|
19
|
+
return "Missing Parameter: instance_id" if params["instance_id"].nil?
|
|
20
|
+
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private_class_method def self.verify_required_param(params, param_name)
|
|
25
|
+
return "Missing Parameter: #{param_name}" if params[param_name].nil?
|
|
26
|
+
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private_class_method def self.build_http_params(method, path, params, secrets, options = {})
|
|
31
|
+
instance_id = params["instance_id"]
|
|
32
|
+
|
|
33
|
+
# Build authorization header - support both Basic Auth and OAuth
|
|
34
|
+
if secrets["access_token"]
|
|
35
|
+
authorization = "Bearer #{secrets["access_token"]}"
|
|
36
|
+
elsif secrets["username"] && secrets["password"]
|
|
37
|
+
require "base64"
|
|
38
|
+
authorization = "Basic #{::Base64.urlsafe_encode64("#{secrets["username"]}:#{secrets["password"]}")}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
headers = {
|
|
42
|
+
"Content-Type" => "application/json",
|
|
43
|
+
"Accept" => "application/json"
|
|
44
|
+
}
|
|
45
|
+
headers["Authorization"] = authorization if authorization
|
|
46
|
+
|
|
47
|
+
http_params = {
|
|
48
|
+
"Method" => method,
|
|
49
|
+
"Url" => "https://#{instance_id}.service-now.com#{path}",
|
|
50
|
+
"Options" => {"Encoding" => "JSON"},
|
|
51
|
+
"Headers" => headers
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
http_params["QueryParameters"] = options[:query] if options[:query]
|
|
55
|
+
http_params["Body"] = options[:body] if options[:body]
|
|
56
|
+
|
|
57
|
+
http_params
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Wrapper around http() that returns only the Body wrapped in success response
|
|
61
|
+
private_class_method def self.http_request(http_params, secrets, context)
|
|
62
|
+
response = http(http_params, secrets, context)
|
|
63
|
+
|
|
64
|
+
# If there's an error at the top level, return it as-is
|
|
65
|
+
return response if response.key?("success") && !response["success"]
|
|
66
|
+
|
|
67
|
+
# Extract the Body and wrap in success response
|
|
68
|
+
body = response.dig("output", "Body") || response
|
|
69
|
+
ServiceNow.success!({}, :output => body)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Floe
|
|
6
|
+
module ServiceNow
|
|
7
|
+
class OAuth < Floe::ServiceNow::Methods
|
|
8
|
+
def self.token(params, secrets, context)
|
|
9
|
+
error = verify_instance_id(params)
|
|
10
|
+
return ServiceNow.error!({}, :cause => error) if error
|
|
11
|
+
|
|
12
|
+
instance_id = params["instance_id"]
|
|
13
|
+
|
|
14
|
+
headers = {
|
|
15
|
+
"ContentType" => "application/x-www-form-urlencoded",
|
|
16
|
+
"Accept" => "application/json"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
body_params = {}
|
|
20
|
+
body_params["grant_type"] = params["grant_type"] if params["grant_type"]
|
|
21
|
+
body_params["client_id"] = params["client_id"] if params["client_id"]
|
|
22
|
+
body_params["scope"] = params["scope"] if params["scope"]
|
|
23
|
+
body_params["username"] = secrets["username"] if secrets["username"]
|
|
24
|
+
body_params["password"] = secrets["password"] if secrets["password"]
|
|
25
|
+
body_params["client_secret"] = secrets["client_secret"] if secrets["client_secret"]
|
|
26
|
+
body_params["refresh_token"] = secrets["refresh_token"] if secrets["refresh_token"]
|
|
27
|
+
|
|
28
|
+
http_params = {
|
|
29
|
+
"Method" => "POST",
|
|
30
|
+
"Headers" => headers,
|
|
31
|
+
"Url" => "https://#{instance_id}.service-now.com/oauth_token.do",
|
|
32
|
+
"Body" => body_params
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
http_request(http_params, secrets, context)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|