em-service-now 0.3

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.
@@ -0,0 +1,28 @@
1
+ require 'date'
2
+ Gem::Specification.new do |spec|
3
+
4
+ spec.name = %q{em-service-now}
5
+ spec.version = '0.3'
6
+ spec.date = DateTime.now.strftime( "%Y-%m-%d" )
7
+ spec.authors = ["Richard","","",""]
8
+ spec.email = %q{ops@clue.co.za}
9
+ spec.summary = %q{Tools for interfacing with service-now.com}
10
+ spec.homepage = %q{https://github.com/cluetechnologies/em-service-now}
11
+ spec.description = %q{}
12
+ spec.add_runtime_dependency 'eventmachine', '~> 1'
13
+ spec.add_runtime_dependency 'em-http-request', '~> 1'
14
+ spec.add_runtime_dependency 'json'
15
+ spec.add_runtime_dependency 'yaml'
16
+ spec.files = [
17
+
18
+ 'em-service-now.gemspec',
19
+ 'lib/em-service-now.rb',
20
+ 'lib/version.rb',
21
+ 'spec/spec_helper.rb',
22
+ 'spec/spec_config.yml.tmpl',
23
+ 'spec/functional_spec.rb',
24
+ 'spec/em-service-now_spec.rb'
25
+
26
+ ]
27
+
28
+ end
@@ -0,0 +1,573 @@
1
+ require 'eventmachine'
2
+ require 'em-http-request'
3
+ require 'json'
4
+ require 'uri'
5
+ require 'yaml'
6
+
7
+ class ServiceNowException < Exception
8
+
9
+ end
10
+
11
+ class ConfigException < Exception
12
+
13
+ end unless defined?( ConfigException )
14
+
15
+ module ServiceNow
16
+
17
+ def service_now_init( config, logger = nil )
18
+
19
+ @config = {}
20
+ @config = config unless config.nil?
21
+
22
+ @logger = logger
23
+
24
+ @connect_timeout = 60
25
+ @connect_timeout = @config[:connect_timeout] unless @config[:connect_timeout].nil?
26
+
27
+ @timeout = 120
28
+ @timeout = @config[:timeout] unless @config[:timeout].nil?
29
+
30
+ @username = @config[:username]
31
+ @password = @config[:password]
32
+ @url = @config[:url]
33
+
34
+ @service_now_running = false
35
+
36
+
37
+ raise ::ConfigException.new(
38
+
39
+ "#{self.class} requires :url: and :username: and :password: configured."
40
+
41
+ ) if (
42
+
43
+ @username.nil? or @username == '' or
44
+ @password.nil? or @password == '' or
45
+ @url.nil? or @url == ''
46
+
47
+ )
48
+
49
+ #
50
+ # Assumes already running inside an EM reactor
51
+ # If not, call em_service_now
52
+ #
53
+ @inline = true
54
+
55
+ get_cookies
56
+
57
+ end
58
+
59
+
60
+
61
+ def em_service_now_query( query, &block )
62
+
63
+ @inline = false
64
+
65
+ EM::run do
66
+
67
+ #
68
+ # Pass the block straight through.
69
+ #
70
+ service_now_query( query, &block )
71
+
72
+ end
73
+
74
+ end
75
+
76
+ def on_error( url, http, &block )
77
+
78
+ EM::stop unless @inline
79
+
80
+ error = "transport or http error #{http.error}"
81
+
82
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
83
+
84
+ yield nil, error if block
85
+
86
+ @service_now_running = false
87
+
88
+ end
89
+
90
+
91
+ def on_success( url, http, &block )
92
+
93
+ store_cookies( http )
94
+
95
+ EM::stop unless @inline
96
+
97
+ unless http.response_header.status == 200
98
+
99
+ error = "Response #{http.response_header.status} from #{url}"
100
+
101
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
102
+
103
+ end
104
+
105
+ if error != nil or http.response == ""
106
+
107
+ error = "Empty JSON response from #{url}"
108
+
109
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
110
+
111
+ end
112
+
113
+ if /do\?CSV\&/.match( url )
114
+
115
+ parse_csv( http, &block )
116
+
117
+ @service_now_running = false
118
+
119
+ return
120
+
121
+ end
122
+
123
+ unless error != nil or records = JSON.parse( http.response )
124
+
125
+ error = "Malformed JSON response from #{url}"
126
+
127
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
128
+
129
+ end
130
+
131
+ if error.nil? and records.has_key?('error')
132
+
133
+ #
134
+ # SNOW returns a 200 'successs' and puts the error in the JSON
135
+ #
136
+ error = "#{records['error']}from #{url}"
137
+
138
+ @logger.error "#{self.class} ERROR:#{error}" unless @logger.nil?
139
+
140
+ end
141
+
142
+ if error.nil? and records.has_key?('records')
143
+
144
+ records['records'].each do |record|
145
+
146
+ #
147
+ # Have records, yield them each
148
+ #
149
+ yield record, nil if block
150
+
151
+ end
152
+
153
+ else
154
+
155
+ yield nil, error if block
156
+
157
+ end
158
+
159
+ @service_now_running = false
160
+
161
+ end
162
+
163
+ def em_service_now( type, query, records_array = nil, &block )
164
+
165
+ @inline = false
166
+
167
+ EM::run do
168
+
169
+ service_now( type, query, records_array, &block )
170
+
171
+ end
172
+
173
+ end
174
+
175
+
176
+ def service_now( type, query, records_array = nil, &block )
177
+
178
+ @service_now_running = true
179
+
180
+ url = nil
181
+
182
+ table = query['table']
183
+
184
+ case type
185
+
186
+ when :getRecords, :getKeys, :getCSV
187
+
188
+ return service_now_query( type, query, &block )
189
+
190
+ when :insert
191
+
192
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=insertMultiple"
193
+ body = {
194
+
195
+ 'records' => records_array
196
+
197
+ }
198
+
199
+ when :update
200
+
201
+ url = "#{@url}/#{table}.do?JSON"
202
+ url="#{url}&sysparm_action=update"
203
+ url = append_query( url, query )
204
+ body = records_array[0]
205
+
206
+ else
207
+
208
+ raise ServiceNowException.new(
209
+
210
+ "no such query type '#{type}'"
211
+
212
+ )
213
+
214
+ end
215
+
216
+ json_body = JSON.dump(body)
217
+
218
+ @logger.debug "ServiceNow URL:#{url}" unless @logger.nil?
219
+
220
+ http = EventMachine::HttpRequest.new( url ).post(
221
+
222
+ generate_POST_request( json_body )
223
+
224
+ )
225
+
226
+ http.errback do
227
+
228
+ on_error( url, http, &block )
229
+
230
+ end
231
+
232
+ http.callback do
233
+
234
+ if http.response_header.status == 401
235
+
236
+ #
237
+ # Authentication failed
238
+ #
239
+ login_and_retry( url, json_body, &block )
240
+
241
+ else
242
+
243
+ on_success( url, http, &block )
244
+
245
+ end
246
+
247
+ end
248
+
249
+ end
250
+
251
+ private
252
+
253
+ def get_cookies
254
+
255
+ dir = Dir.getwd
256
+ file = 'service_now.cookie'
257
+
258
+ #
259
+ # Assemble cookie file location
260
+ #
261
+
262
+ begin
263
+
264
+ unless DAEMON_ROOT.nil?
265
+
266
+ dir = "#{DAEMON_ROOT}/log"
267
+
268
+ unless File.directory?( "#{DAEMON_ROOT}/log" )
269
+
270
+ dir = DAEMON_ROOT
271
+
272
+ end
273
+
274
+ end
275
+
276
+ unless DAEMON_NAME.nil?
277
+
278
+ file = "service_now.#{DAEMON_NAME}.cookie"
279
+
280
+ end
281
+
282
+ rescue; end
283
+
284
+ @cookiefile = "#{dir}/#{file}"
285
+
286
+ #
287
+ # Load the cookies from file
288
+ #
289
+ if File.file?( @cookiefile )
290
+
291
+ begin
292
+
293
+ @cookies = YAML.load_file( @cookiefile )
294
+
295
+ rescue; end
296
+
297
+ end
298
+
299
+ end
300
+
301
+ def store_cookies( http )
302
+
303
+ #
304
+ # Only store cookies if JSESSIONID is in [0]'th cookie
305
+ #
306
+ # ie. At the creation of the SNOWside session. All subsequently
307
+ # received cookie arrays do not contain the JSESSIONID in
308
+ # reply, so it would be overwritten in the cookie file,
309
+ #
310
+ # Effectively making the session cookie only work once.
311
+ #
312
+
313
+ return unless /^JSESSIONID/.match( http.response_header["SET_COOKIE"][0] )
314
+
315
+ begin
316
+
317
+ File.open( @cookiefile, 'w' ) do |f|
318
+
319
+ YAML::dump( http.response_header["SET_COOKIE"], f )
320
+
321
+ end
322
+
323
+ rescue
324
+
325
+ end
326
+
327
+ end
328
+
329
+ def parse_csv( http, &block )
330
+
331
+ require 'csv'
332
+
333
+ headings = nil
334
+
335
+ begin
336
+
337
+ CSV.parse( http.response ).each do |row|
338
+
339
+ if headings.nil? then
340
+
341
+ headings = row
342
+ next
343
+
344
+ else
345
+
346
+ record = Hash[*headings.zip( row ).flatten]
347
+
348
+ yield record, nil if block
349
+
350
+ end
351
+
352
+ end
353
+
354
+ rescue Exception => e
355
+
356
+ yield nil, e.to_s if block
357
+
358
+ end
359
+
360
+ end
361
+
362
+ def append_csv_query( url, query )
363
+
364
+ url = "#{url}&" unless query['where'].nil?
365
+
366
+ query['where'].each do |field, value|
367
+
368
+ if /^\=/.match( value )
369
+ url = "#{url}#{field}#{value[1..-1]}^"
370
+
371
+ else
372
+
373
+ url = "#{url}#{field}=#{value}^"
374
+
375
+ end
376
+
377
+ end unless query['where'].nil?
378
+
379
+ url.gsub!( /\^$/, '' )
380
+ url = URI.escape( url )
381
+ url = url.gsub( %r[,], '%2C' )
382
+
383
+ return url
384
+
385
+ end
386
+
387
+ def append_query( url, query )
388
+
389
+ url = "#{url}&sysparm_query=" unless query['where'].nil?
390
+
391
+ query['where'].each do |field, value|
392
+
393
+ if /^\=/.match( value )
394
+
395
+ url = "#{url}#{field}#{value[1..-1]}^"
396
+
397
+ else
398
+
399
+ url = "#{url}#{field}=#{value}^"
400
+
401
+ end
402
+
403
+ end unless query['where'].nil?
404
+
405
+ url.gsub!( /\^$/, '' )
406
+ url = URI.escape( url )
407
+ url = url.gsub( %r[,], '%2C' )
408
+
409
+ return url
410
+
411
+ end
412
+
413
+ def generate_GET_request
414
+
415
+ return \
416
+ :connect_timeout => @connect_timeout,
417
+ :timeout => @timeout,
418
+ :head => {
419
+
420
+ 'cookie' => @cookies,
421
+ 'Content-Type' => 'application/json'
422
+
423
+ } unless @cookies.nil?
424
+
425
+ return \
426
+ :connect_timeout => @connect_timeout,
427
+ :timeout => @timeout,
428
+ :head => {
429
+
430
+ 'Authorization' => [ @username, @password ],
431
+ 'Content-Type' => 'application/json'
432
+
433
+ }
434
+
435
+ end
436
+
437
+ def generate_POST_request( body )
438
+
439
+ return \
440
+ :connect_timeout => @connect_timeout,
441
+ :timeout => @timeout,
442
+ :head => {
443
+
444
+ 'cookie' => @cookies,
445
+ 'Content-Type' => 'application/json'
446
+
447
+ },
448
+ :body => body \
449
+ unless @cookies.nil?
450
+
451
+ return \
452
+ :connect_timeout => @connect_timeout,
453
+ :timeout => @timeout,
454
+ :head => {
455
+
456
+ 'Authorization' => [ @username, @password ],
457
+ 'Content-Type' => 'application/json'
458
+
459
+ },
460
+ :body => body
461
+
462
+ end
463
+
464
+ def service_now_query( type, query, &block )
465
+
466
+ result = []
467
+ error = nil
468
+
469
+ table = query['table']
470
+
471
+ if query['where'].nil? and type == :select
472
+
473
+ @logger.warn( "WARNING! No 'where' clause! - Use :selectKeys on large dataset, SNOW might return only a subset of the result" )
474
+
475
+ end
476
+
477
+ case type
478
+
479
+ when :getKeys
480
+
481
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=getKeys"
482
+ url = append_query( url, query )
483
+
484
+ when :getRecords
485
+
486
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=getRecords"
487
+ url = append_query( url, query )
488
+
489
+ when :getCSV
490
+
491
+ url = "#{@url}/#{table}.do?CSV"
492
+ url = append_csv_query( url, query )
493
+
494
+ end
495
+
496
+ @logger.debug "ServiceNow URL:#{url}" unless @logger.nil?
497
+
498
+ http = EventMachine::HttpRequest.new( url ).get(
499
+
500
+ generate_GET_request
501
+
502
+ )
503
+
504
+ http.errback do
505
+
506
+ on_error( url, http, &block )
507
+
508
+ end
509
+
510
+ http.callback do
511
+
512
+ if http.response_header.status == 401
513
+
514
+ #
515
+ # Authentication failed
516
+ #
517
+ login_and_retry( url, &block )
518
+
519
+ else
520
+
521
+ on_success( url, http, &block )
522
+
523
+ end
524
+
525
+ end
526
+
527
+ end
528
+
529
+ def login_and_retry( url, body = nil, &block )
530
+
531
+ @logger.warn "#{self.class} creating new session"
532
+
533
+ #
534
+ # Nil cookies will cause an authentication
535
+ # and the new cookies will be saved to file
536
+ # on the reply.
537
+ #
538
+
539
+ @cookies = nil
540
+
541
+ if body.nil?
542
+
543
+ http = EventMachine::HttpRequest.new( url ).get(
544
+
545
+ generate_GET_request
546
+
547
+ )
548
+
549
+ else
550
+
551
+ http = EventMachine::HttpRequest.new( url ).post(
552
+
553
+ generate_POST_request( body )
554
+
555
+ )
556
+
557
+ end
558
+
559
+ http.errback do
560
+
561
+ on_error( url, http, &block )
562
+
563
+ end
564
+
565
+ http.callback do
566
+
567
+ on_success( url, http, &block )
568
+
569
+ end
570
+
571
+ end
572
+
573
+ end
@@ -0,0 +1,5 @@
1
+ module ServiceNow
2
+
3
+ Version = VERSION = '0.3'
4
+
5
+ end
@@ -0,0 +1,366 @@
1
+ require 'spec_helper'
2
+
3
+ describe ServiceNow do
4
+
5
+ before :all do
6
+
7
+ LOG.off
8
+
9
+ @cookies = 'NONE'
10
+
11
+ @get_companies = {
12
+
13
+ 'table' => 'core_company',
14
+ 'where' => {
15
+
16
+ 'status' => 'Operational'
17
+
18
+ }
19
+
20
+ }
21
+
22
+ end
23
+
24
+ subject {
25
+
26
+ Object.extend( ServiceNow )
27
+
28
+ }
29
+
30
+ it 'requires configuration' do
31
+
32
+ config_copy = Hash.new
33
+ config_copy[:username] = CONFIG['config'][:username]
34
+ config_copy[:password] = CONFIG['config'][:password]
35
+
36
+ expect {
37
+
38
+ subject.service_now_init( config_copy, LOG )
39
+
40
+ }.to raise_error(
41
+
42
+ ConfigException,
43
+
44
+ /requires :url: and :username: and :password: configured/
45
+
46
+ )
47
+
48
+ end
49
+
50
+ it 'errors on transport errors' do
51
+
52
+ config_copy = Hash.new
53
+ config_copy[:username] = CONFIG['config'][:username]
54
+ config_copy[:password] = CONFIG['config'][:password]
55
+ config_copy[:url] = 'https://no.such.thing'
56
+
57
+ result = nil
58
+
59
+ subject.service_now_init( config_copy, LOG )
60
+
61
+ subject.em_service_now( :getKeys, @get_companies ) do |record, status|
62
+
63
+ result = status.inspect
64
+
65
+ end
66
+
67
+ result.should match /transport or http error/
68
+
69
+ end
70
+
71
+ context 'can query/insert/update' do
72
+
73
+ before :each do
74
+
75
+ subject.service_now_init( CONFIG['config'], LOG )
76
+
77
+ @url = CONFIG['config'][:url]
78
+
79
+ subject.instance_variable_set( :@cookies, @cookies )
80
+
81
+ @http_request = mock( 'EventMachine::HttpRequest' )
82
+
83
+ @http_request.should_receive(
84
+
85
+ :errback
86
+
87
+ )
88
+
89
+ @http_request.should_receive(
90
+
91
+ :callback
92
+
93
+ )
94
+
95
+ end
96
+
97
+ it 'supports getKeys' do
98
+
99
+ query = {
100
+
101
+ 'table' => 'table',
102
+ 'where' => {
103
+
104
+ 'column1' => 'value1',
105
+ 'column2' => 'value2'
106
+
107
+ }
108
+
109
+ }
110
+
111
+ @http_request.should_receive(
112
+
113
+ :get
114
+
115
+ ).with({
116
+
117
+ :connect_timeout => 60,
118
+ :timeout => 120,
119
+ :head => {
120
+
121
+ "Content-Type" => "application/json",
122
+ "cookie" => @cookies
123
+
124
+ },
125
+
126
+ }).and_return(
127
+
128
+ @http_request
129
+
130
+ )
131
+
132
+ EventMachine::HttpRequest.should_receive(
133
+
134
+ :new
135
+
136
+ ).with(
137
+
138
+ "#{@url}/table.do?JSON&sysparm_action=getKeys&sysparm_query=column1=value1%5Ecolumn2=value2"
139
+
140
+ ).and_return(
141
+
142
+ @http_request
143
+
144
+ )
145
+
146
+ subject.service_now( :getKeys, query )
147
+
148
+ end
149
+
150
+ it 'supports special query things' do
151
+
152
+ query = {
153
+
154
+ 'table' => 'table',
155
+ 'where' => {
156
+
157
+ 'field' => '=NOT IN1,2'
158
+
159
+ }
160
+
161
+ }
162
+
163
+ @http_request.should_receive(
164
+
165
+ :get
166
+
167
+ ).with({
168
+
169
+ :connect_timeout => 60,
170
+ :timeout => 120,
171
+ :head => {
172
+
173
+ "Content-Type" => "application/json",
174
+ "cookie" => @cookies
175
+
176
+ },
177
+
178
+ }).and_return(
179
+
180
+ @http_request
181
+
182
+ )
183
+
184
+ EventMachine::HttpRequest.should_receive(
185
+
186
+ :new
187
+
188
+ ).with(
189
+
190
+ "#{@url}/table.do?JSON&sysparm_action=getKeys&sysparm_query=fieldNOT%20IN1%2C2"
191
+
192
+ ).and_return(
193
+
194
+ @http_request
195
+
196
+ )
197
+
198
+ subject.service_now( :getKeys, query )
199
+
200
+ end
201
+
202
+ it 'can insert a record' do
203
+
204
+ query = {
205
+
206
+ 'table' => 'table'
207
+
208
+ }
209
+
210
+ records_array = [{
211
+
212
+ 'column1' => 'value1',
213
+ 'column2' => 'value2'
214
+
215
+ }]
216
+
217
+ body = '{"records":[{"column1":"value1","column2":"value2"}]}'
218
+
219
+ @http_request.should_receive(
220
+
221
+ :post
222
+
223
+ ).with({
224
+
225
+ :connect_timeout => 60,
226
+ :timeout => 120,
227
+ :head => {
228
+
229
+ "Content-Type" => "application/json",
230
+ "cookie" => @cookies
231
+
232
+ },
233
+ :body => body
234
+
235
+ }).and_return(
236
+
237
+ @http_request
238
+
239
+ )
240
+
241
+ EventMachine::HttpRequest.should_receive(
242
+
243
+ :new
244
+
245
+ ).with(
246
+
247
+ "#{@url}/table.do?JSON&sysparm_action=insertMultiple"
248
+
249
+ ).and_return(
250
+
251
+ @http_request
252
+
253
+ )
254
+
255
+ subject.service_now( :insert, query, records_array )
256
+
257
+ end
258
+
259
+ it 'can update a record' do
260
+
261
+ query = {
262
+
263
+ 'table' => 'core_company',
264
+ 'where' => {
265
+
266
+ 'sys_id' => '_____SYS___ID____'
267
+
268
+ }
269
+
270
+ }
271
+
272
+ record_array = [{
273
+
274
+ 'u_column_one' => 'one',
275
+ 'u_column_two' => 'two'
276
+
277
+ }]
278
+
279
+ body = '{"u_column_one":"one","u_column_two":"two"}'
280
+
281
+ @http_request.should_receive(
282
+
283
+ :post
284
+
285
+ ).with({
286
+
287
+ :connect_timeout => 60,
288
+ :timeout => 120,
289
+ :head => {
290
+
291
+ "Content-Type" => "application/json",
292
+ "cookie" => @cookies
293
+
294
+ },
295
+ :body => body
296
+
297
+ }).and_return(
298
+
299
+ @http_request
300
+
301
+ )
302
+
303
+ EventMachine::HttpRequest.should_receive(
304
+
305
+ :new
306
+
307
+ ).with(
308
+
309
+ "#{@url}/core_company.do?JSON&sysparm_action=update&sysparm_query=sys_id=_____SYS___ID____"
310
+
311
+ ).and_return(
312
+
313
+ @http_request
314
+
315
+ )
316
+
317
+ subject.service_now( :update, query, record_array )
318
+
319
+ end
320
+
321
+ it 'supports STARTSWITH' do
322
+
323
+ subject.service_now_init( CONFIG['config'], LOG )
324
+
325
+ result = []
326
+
327
+ EventMachine::HttpRequest.should_receive(
328
+
329
+ :new
330
+
331
+ ).with(
332
+
333
+ "#{@url}/core_company.do?JSON&sysparm_action=getKeys&sysparm_query=nameSTARTSWITHClue"
334
+
335
+ ).and_return(
336
+
337
+ @http_request
338
+
339
+ )
340
+
341
+ @http_request.should_receive(
342
+
343
+ :get
344
+
345
+ ).and_return(
346
+
347
+ @http_request
348
+
349
+ )
350
+
351
+ subject.service_now( :getKeys, {
352
+
353
+ 'table' => 'core_company',
354
+ 'where' => {
355
+
356
+ 'name' => '=STARTSWITHClue'
357
+
358
+ }
359
+
360
+ } )
361
+
362
+ end
363
+
364
+ end
365
+
366
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe ServiceNow do
4
+
5
+ subject {
6
+
7
+ LOG.on
8
+ subj = Object.extend( ServiceNow )
9
+ subj.service_now_init( CONFIG['config'], LOG )
10
+ subj
11
+
12
+ }
13
+
14
+ pending 'can get by CSV interface' do
15
+
16
+ query = CONFIG['queries']['get_specific_report']
17
+
18
+ result = []
19
+ subject.em_service_now( :getCSV, query ) do |record, error|
20
+
21
+
22
+ result << record unless record.nil?
23
+
24
+ end
25
+
26
+ result.length.should > 1
27
+
28
+ end
29
+
30
+ pending 'can get by JSON interface' do
31
+
32
+ company = nil
33
+
34
+ query = CONFIG['queries']['get_specific_company']
35
+ expectation = CONFIG['queries']['get_specific_company_expectation']
36
+
37
+ subject.em_service_now( :getRecords, query ) do |record, status|
38
+
39
+ company = record
40
+
41
+ end
42
+
43
+ company['name'].should == expectation
44
+
45
+ end
46
+
47
+ pending 'errors on invalid table name' do
48
+
49
+ result = nil
50
+
51
+ subject.em_service_now( :getKeys, {
52
+
53
+ 'table' => 'nosuchtable',
54
+ 'where' => {
55
+ 'u_no_such_column' => 'MIA'
56
+ }
57
+
58
+ } ) do |record, error|
59
+
60
+ result = error
61
+
62
+ end
63
+
64
+ result.should match /Empty JSON response from/
65
+
66
+ end
67
+
68
+ pending 'can create an incident' do
69
+
70
+ query = {
71
+
72
+ 'table' => 'incident'
73
+
74
+ }
75
+
76
+ records = [
77
+
78
+ CONFIG['incident']['create']
79
+
80
+ ]
81
+
82
+ subject.em_service_now( :insert, query, records )
83
+
84
+ end
85
+
86
+ pending 'can update incidents by company, short_description and status' do
87
+
88
+ update_column = CONFIG['incident']['update']['column']
89
+ update_value = CONFIG['incident']['update']['value']
90
+
91
+ query = {
92
+
93
+ 'table' => 'incident',
94
+
95
+ 'where' => {
96
+
97
+ 'company' => CONFIG['incident']['create']['company'],
98
+ 'state' => '=NOT IN6,7',
99
+ 'short_description' => CONFIG['incident']['create']['short_description']
100
+
101
+ }
102
+
103
+ }
104
+
105
+ records = [{
106
+
107
+ update_column => update_value
108
+
109
+ }]
110
+
111
+ result = nil
112
+
113
+ subject.em_service_now( :update, query, records ) do |record, error|
114
+
115
+ result = record
116
+
117
+ end
118
+
119
+ result[ update_column ].should == update_value
120
+
121
+ end
122
+
123
+
124
+ pending 'can close incidents by company, short_description and status' do
125
+
126
+ query = {
127
+
128
+ 'table' => 'incident',
129
+
130
+ 'where' => {
131
+
132
+ 'company' => CONFIG['incident']['create']['company'],
133
+ 'state' => '=NOT IN6,7',
134
+ 'short_description' => CONFIG['incident']['create']['short_description']
135
+
136
+ }
137
+
138
+ }
139
+
140
+ records = [{
141
+
142
+ 'u_next_step' => 'Set to Resolved'
143
+
144
+ }]
145
+
146
+ subject.em_service_now( :update, query, records ) do |record, error|
147
+
148
+ raise error.inspect unless error.nil?
149
+
150
+ end
151
+
152
+ end
153
+
154
+ end
@@ -0,0 +1,40 @@
1
+ config:
2
+
3
+ :username: username@domain.com
4
+ :password: password
5
+ :url: https://yourDEVinstance.service-now.com
6
+
7
+ queries:
8
+
9
+ get_specific_report:
10
+ #
11
+ # fetches a configured snow report
12
+ #
13
+ table: sys_report_template
14
+ #
15
+ # Should refer to configured report's sys_id
16
+ #
17
+ where:
18
+ jvar_report_id: 5896e8a30c16a00087c61678d080f220
19
+
20
+ get_specific_company_expectation: COMPANY NAME
21
+ get_specific_company:
22
+ table: core_company
23
+ where:
24
+ name: COMPANY NAME
25
+
26
+
27
+ incident:
28
+
29
+ create:
30
+ company: 5fac1edc0a0a3c1e00ccdb50799bcec1
31
+ assignment_group: d625dccec0a8016700a222a0f7900d06
32
+ category: Lab
33
+ subcategory: Software
34
+ short_description: puppet error name
35
+ description: Description Text
36
+
37
+ update:
38
+ column: u_event_count
39
+ value: '40'
40
+
@@ -0,0 +1,43 @@
1
+ require 'em-service-now'
2
+
3
+ SPEC_CONFIG_FILE = "#{File.dirname( __FILE__ )}/spec_config.yml"
4
+
5
+ CONFIG = YAML.load_file(
6
+
7
+ SPEC_CONFIG_FILE
8
+
9
+ ) if File.file?( SPEC_CONFIG_FILE )
10
+ CONFIG = {} unless defined?( CONFIG )
11
+
12
+ class FakeLogger
13
+
14
+ def initialize( parameter = :noisey )
15
+ @parameter = parameter
16
+ end
17
+
18
+ def on
19
+ @parameter = :noisey
20
+ end
21
+
22
+ def off
23
+ @parameter = :silent
24
+ end
25
+
26
+ def method_missing( symbol, *args, &block )
27
+ puts "LOG.#{symbol}: #{args}" unless @parameter == :silent
28
+ end
29
+
30
+ #
31
+ # rspec won't match unless for these unless they'r defined
32
+ #
33
+ def info( msg )
34
+ puts "LOG.info: [#{msg}]" unless @parameter == :silent
35
+ end
36
+
37
+ def warn( msg )
38
+ puts "LOG.warn: [#{msg}]" unless @parameter == :silent
39
+ end
40
+
41
+ end
42
+
43
+ LOG = FakeLogger.new
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-service-now
3
+ version: !ruby/object:Gem::Version
4
+ hash: 13
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ version: "0.3"
10
+ platform: ruby
11
+ authors:
12
+ - Richard
13
+ - ""
14
+ - ""
15
+ - ""
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2012-06-22 00:00:00 Z
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: eventmachine
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 1
31
+ segments:
32
+ - 1
33
+ version: "1"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: em-http-request
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ hash: 1
45
+ segments:
46
+ - 1
47
+ version: "1"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: json
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :runtime
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: yaml
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ type: :runtime
77
+ version_requirements: *id004
78
+ description: ""
79
+ email: ops@clue.co.za
80
+ executables: []
81
+
82
+ extensions: []
83
+
84
+ extra_rdoc_files: []
85
+
86
+ files:
87
+ - em-service-now.gemspec
88
+ - lib/em-service-now.rb
89
+ - lib/version.rb
90
+ - spec/spec_helper.rb
91
+ - spec/spec_config.yml.tmpl
92
+ - spec/functional_spec.rb
93
+ - spec/em-service-now_spec.rb
94
+ homepage: https://github.com/cluetechnologies/em-service-now
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.5
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Tools for interfacing with service-now.com
127
+ test_files: []
128
+