em-service-now 0.3 → 0.3.1

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.
@@ -2,17 +2,17 @@ require 'date'
2
2
  Gem::Specification.new do |spec|
3
3
 
4
4
  spec.name = %q{em-service-now}
5
- spec.version = '0.3'
5
+ spec.version = '0.3.1'
6
6
  spec.date = DateTime.now.strftime( "%Y-%m-%d" )
7
7
  spec.authors = ["Richard","","",""]
8
8
  spec.email = %q{ops@clue.co.za}
9
- spec.summary = %q{Tools for interfacing with service-now.com}
9
+ spec.summary = %q{Tool for interfacing with service-now.com}
10
10
  spec.homepage = %q{https://github.com/cluetechnologies/em-service-now}
11
11
  spec.description = %q{}
12
- spec.add_runtime_dependency 'eventmachine', '~> 1'
13
- spec.add_runtime_dependency 'em-http-request', '~> 1'
12
+ spec.add_runtime_dependency 'eventmachine'
13
+ spec.add_runtime_dependency 'em-http-request'
14
14
  spec.add_runtime_dependency 'json'
15
- spec.add_runtime_dependency 'yaml'
15
+ spec.add_runtime_dependency 'awesome_print'
16
16
  spec.files = [
17
17
 
18
18
  'em-service-now.gemspec',
@@ -3,20 +3,16 @@ require 'em-http-request'
3
3
  require 'json'
4
4
  require 'uri'
5
5
  require 'yaml'
6
+ require 'csv'
6
7
 
7
- class ServiceNowException < Exception
8
-
9
- end
10
-
11
- class ConfigException < Exception
8
+ module ServiceNow
12
9
 
13
- end unless defined?( ConfigException )
10
+ class RuntimeException < Exception; end
11
+ class ConfigException < Exception; end
14
12
 
15
- module ServiceNow
16
-
17
13
  def service_now_init( config, logger = nil )
18
14
 
19
- @config = {}
15
+ @config = {}
20
16
  @config = config unless config.nil?
21
17
 
22
18
  @logger = logger
@@ -33,8 +29,7 @@ module ServiceNow
33
29
 
34
30
  @service_now_running = false
35
31
 
36
-
37
- raise ::ConfigException.new(
32
+ raise ConfigException.new(
38
33
 
39
34
  "#{self.class} requires :url: and :username: and :password: configured."
40
35
 
@@ -50,32 +45,119 @@ module ServiceNow
50
45
  # Assumes already running inside an EM reactor
51
46
  # If not, call em_service_now
52
47
  #
53
- @inline = true
48
+ @service_now_inline = true
54
49
 
55
- get_cookies
50
+ sn_get_cookies
56
51
 
57
52
  end
58
53
 
54
+ def em_service_now( type, query, records_array = nil, &block )
55
+
56
+ @service_now_inline = false
59
57
 
58
+ EM::run do
59
+
60
+ service_now( type, query, records_array, &block )
61
+
62
+ end
63
+
64
+ end
60
65
 
61
- def em_service_now_query( query, &block )
66
+ def service_now( type, query, records_array = nil, &block )
67
+
68
+ @service_now_running = true
69
+
70
+ url = nil
71
+
72
+ table = query['table']
62
73
 
63
- @inline = false
74
+ case type
75
+
76
+ when :getRecords, :getKeys, :getCSV
77
+
78
+ return sn_query( type, query, &block )
79
+
80
+ when :insert
64
81
 
65
- EM::run do
82
+ url = "#{@url}/#{table}.do?JSON&sysparm_action=insertMultiple"
83
+ body = {
84
+
85
+ 'records' => records_array
86
+
87
+ }
66
88
 
67
- #
68
- # Pass the block straight through.
69
- #
70
- service_now_query( query, &block )
89
+ when :update
90
+
91
+ url = "#{@url}/#{table}.do?JSON"
92
+ url="#{url}&sysparm_action=update"
93
+ url = sn_append_query( url, query )
94
+ body = records_array[0]
95
+
96
+ else
97
+
98
+ raise ServiceNow::RuntimeException.new(
99
+
100
+ "no such query type '#{type}'"
101
+
102
+ )
103
+
104
+ end
105
+
106
+ json_body = JSON.dump(body)
107
+
108
+ @logger.debug "ServiceNow URL:#{url}" unless @logger.nil?
109
+
110
+ http = EventMachine::HttpRequest.new( url ).post(
111
+
112
+ sn_generate_POST_request( json_body )
113
+
114
+ )
115
+
116
+ http.errback do
117
+
118
+ sn_on_error( url, http, &block )
119
+
120
+ end
121
+
122
+ http.callback do
123
+
124
+ if http.response_header.status == 401
125
+
126
+ #
127
+ # Authentication failed
128
+ #
129
+ sn_login_and_retry( url, json_body, &block )
130
+
131
+ else
132
+
133
+ sn_on_success( url, http, &block )
134
+
135
+ end
71
136
 
72
137
  end
73
138
 
74
139
  end
75
140
 
76
- def on_error( url, http, &block )
141
+ private
142
+
143
+ #def em_sn_query( query, &block )
144
+ #
145
+ # @service_now_inline = false
146
+ #
147
+ # EM::run do
148
+ #
149
+ # #
150
+ # # Pass the block straight through.
151
+ # #
152
+ # sn_query( query, &block )
153
+ #
154
+ # end
155
+ #
156
+ #end
157
+
158
+ def sn_on_error( url, http, &block )
77
159
 
78
- EM::stop unless @inline
160
+ EM::stop unless @service_now_inline
79
161
 
80
162
  error = "transport or http error #{http.error}"
81
163
 
@@ -88,11 +170,11 @@ module ServiceNow
88
170
  end
89
171
 
90
172
 
91
- def on_success( url, http, &block )
173
+ def sn_on_success( url, http, &block )
92
174
 
93
- store_cookies( http )
175
+ sn_store_cookies( http )
94
176
 
95
- EM::stop unless @inline
177
+ EM::stop unless @service_now_inline
96
178
 
97
179
  unless http.response_header.status == 200
98
180
 
@@ -110,9 +192,9 @@ module ServiceNow
110
192
 
111
193
  end
112
194
 
113
- if /do\?CSV\&/.match( url )
195
+ if /do\?CSV/.match( url )
114
196
 
115
- parse_csv( http, &block )
197
+ sn_parse_csv( http, &block )
116
198
 
117
199
  @service_now_running = false
118
200
 
@@ -160,97 +242,7 @@ module ServiceNow
160
242
 
161
243
  end
162
244
 
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
245
+ def sn_get_cookies
254
246
 
255
247
  dir = Dir.getwd
256
248
  file = 'service_now.cookie'
@@ -298,7 +290,7 @@ module ServiceNow
298
290
 
299
291
  end
300
292
 
301
- def store_cookies( http )
293
+ def sn_store_cookies( http )
302
294
 
303
295
  #
304
296
  # Only store cookies if JSESSIONID is in [0]'th cookie
@@ -309,6 +301,9 @@ module ServiceNow
309
301
  #
310
302
  # Effectively making the session cookie only work once.
311
303
  #
304
+ # I.show http
305
+
306
+ return if http.response_header["SET_COOKIE"].nil?
312
307
 
313
308
  return unless /^JSESSIONID/.match( http.response_header["SET_COOKIE"][0] )
314
309
 
@@ -326,9 +321,7 @@ module ServiceNow
326
321
 
327
322
  end
328
323
 
329
- def parse_csv( http, &block )
330
-
331
- require 'csv'
324
+ def sn_parse_csv( http, &block )
332
325
 
333
326
  headings = nil
334
327
 
@@ -359,12 +352,22 @@ module ServiceNow
359
352
 
360
353
  end
361
354
 
362
- def append_csv_query( url, query )
355
+ def sn_append_csv_query( url, query )
363
356
 
364
- url = "#{url}&" unless query['where'].nil?
357
+ url = "#{url}&sysparm_query=" unless query['where'].nil?
365
358
 
366
359
  query['where'].each do |field, value|
367
360
 
361
+ if field == 'jvar_report_id'
362
+
363
+ #
364
+ # dont specify query if fetching
365
+ # a configured report
366
+ #
367
+ url.gsub!('sysparm_query=','')
368
+
369
+ end
370
+
368
371
  if /^\=/.match( value )
369
372
  url = "#{url}#{field}#{value[1..-1]}^"
370
373
 
@@ -384,7 +387,7 @@ module ServiceNow
384
387
 
385
388
  end
386
389
 
387
- def append_query( url, query )
390
+ def sn_append_query( url, query )
388
391
 
389
392
  url = "#{url}&sysparm_query=" unless query['where'].nil?
390
393
 
@@ -410,7 +413,7 @@ module ServiceNow
410
413
 
411
414
  end
412
415
 
413
- def generate_GET_request
416
+ def sn_generate_GET_request
414
417
 
415
418
  return \
416
419
  :connect_timeout => @connect_timeout,
@@ -434,7 +437,7 @@ module ServiceNow
434
437
 
435
438
  end
436
439
 
437
- def generate_POST_request( body )
440
+ def sn_generate_POST_request( body )
438
441
 
439
442
  return \
440
443
  :connect_timeout => @connect_timeout,
@@ -461,14 +464,14 @@ module ServiceNow
461
464
 
462
465
  end
463
466
 
464
- def service_now_query( type, query, &block )
467
+ def sn_query( type, query, &block )
465
468
 
466
469
  result = []
467
470
  error = nil
468
471
 
469
472
  table = query['table']
470
473
 
471
- if query['where'].nil? and type == :select
474
+ if query['where'].nil? and type == :getRecords
472
475
 
473
476
  @logger.warn( "WARNING! No 'where' clause! - Use :selectKeys on large dataset, SNOW might return only a subset of the result" )
474
477
 
@@ -479,17 +482,17 @@ module ServiceNow
479
482
  when :getKeys
480
483
 
481
484
  url = "#{@url}/#{table}.do?JSON&sysparm_action=getKeys"
482
- url = append_query( url, query )
485
+ url = sn_append_query( url, query )
483
486
 
484
487
  when :getRecords
485
488
 
486
489
  url = "#{@url}/#{table}.do?JSON&sysparm_action=getRecords"
487
- url = append_query( url, query )
490
+ url = sn_append_query( url, query )
488
491
 
489
492
  when :getCSV
490
493
 
491
494
  url = "#{@url}/#{table}.do?CSV"
492
- url = append_csv_query( url, query )
495
+ url = sn_append_csv_query( url, query )
493
496
 
494
497
  end
495
498
 
@@ -497,13 +500,13 @@ module ServiceNow
497
500
 
498
501
  http = EventMachine::HttpRequest.new( url ).get(
499
502
 
500
- generate_GET_request
503
+ sn_generate_GET_request
501
504
 
502
505
  )
503
506
 
504
507
  http.errback do
505
508
 
506
- on_error( url, http, &block )
509
+ sn_on_error( url, http, &block )
507
510
 
508
511
  end
509
512
 
@@ -514,11 +517,11 @@ module ServiceNow
514
517
  #
515
518
  # Authentication failed
516
519
  #
517
- login_and_retry( url, &block )
520
+ sn_login_and_retry( url, &block )
518
521
 
519
522
  else
520
523
 
521
- on_success( url, http, &block )
524
+ sn_on_success( url, http, &block )
522
525
 
523
526
  end
524
527
 
@@ -526,7 +529,7 @@ module ServiceNow
526
529
 
527
530
  end
528
531
 
529
- def login_and_retry( url, body = nil, &block )
532
+ def sn_login_and_retry( url, body = nil, &block )
530
533
 
531
534
  @logger.warn "#{self.class} creating new session"
532
535
 
@@ -542,7 +545,7 @@ module ServiceNow
542
545
 
543
546
  http = EventMachine::HttpRequest.new( url ).get(
544
547
 
545
- generate_GET_request
548
+ sn_generate_GET_request
546
549
 
547
550
  )
548
551
 
@@ -550,7 +553,7 @@ module ServiceNow
550
553
 
551
554
  http = EventMachine::HttpRequest.new( url ).post(
552
555
 
553
- generate_POST_request( body )
556
+ sn_generate_POST_request( body )
554
557
 
555
558
  )
556
559
 
@@ -558,16 +561,30 @@ module ServiceNow
558
561
 
559
562
  http.errback do
560
563
 
561
- on_error( url, http, &block )
564
+ sn_on_error( url, http, &block )
562
565
 
563
566
  end
564
567
 
565
568
  http.callback do
566
569
 
567
- on_success( url, http, &block )
570
+ sn_on_success( url, http, &block )
568
571
 
569
572
  end
570
573
 
571
574
  end
572
575
 
573
576
  end
577
+
578
+ #
579
+ # quick hack to show variable contents
580
+ #
581
+ class I
582
+
583
+ def self.show( var )
584
+
585
+ require 'awesome_print'
586
+ ap var
587
+
588
+ end
589
+
590
+ end unless defined?( I )
@@ -1,5 +1,5 @@
1
1
  module ServiceNow
2
2
 
3
- Version = VERSION = '0.3'
3
+ Version = VERSION = '0.3.1'
4
4
 
5
5
  end
@@ -39,7 +39,7 @@ describe ServiceNow do
39
39
 
40
40
  }.to raise_error(
41
41
 
42
- ConfigException,
42
+ ServiceNow::ConfigException,
43
43
 
44
44
  /requires :url: and :username: and :password: configured/
45
45
 
@@ -68,6 +68,22 @@ describe ServiceNow do
68
68
 
69
69
  end
70
70
 
71
+ it 'errors on invalid query type' do
72
+
73
+ expect {
74
+
75
+ subject.em_service_now( :noSuch, {} )
76
+
77
+ }.to raise_error(
78
+
79
+ ServiceNow::RuntimeException,
80
+
81
+ /no such query type/
82
+
83
+ )
84
+
85
+ end
86
+
71
87
  context 'can query/insert/update' do
72
88
 
73
89
  before :each do
@@ -147,6 +163,111 @@ describe ServiceNow do
147
163
 
148
164
  end
149
165
 
166
+ it 'supports getCSV with query' do
167
+
168
+ query = {
169
+
170
+ 'table' => 'table',
171
+ 'where' => {
172
+
173
+ 'column1' => 'value1',
174
+ 'column2' => 'value2'
175
+
176
+ }
177
+
178
+ }
179
+
180
+ @http_request.should_receive(
181
+
182
+ :get
183
+
184
+ ).with({
185
+
186
+ :connect_timeout => 60,
187
+ :timeout => 120,
188
+ :head => {
189
+
190
+ "Content-Type" => "application/json",
191
+ "cookie" => @cookies
192
+
193
+ },
194
+
195
+ }).and_return(
196
+
197
+ @http_request
198
+
199
+ )
200
+
201
+ EventMachine::HttpRequest.should_receive(
202
+
203
+ :new
204
+
205
+ ).with(
206
+
207
+ "#{@url}/table.do?CSV&sysparm_query=column1=value1%5Ecolumn2=value2"
208
+
209
+ ).and_return(
210
+
211
+ @http_request
212
+
213
+ )
214
+
215
+ subject.service_now( :getCSV, query )
216
+
217
+ end
218
+
219
+ it 'supports getCSV report' do
220
+
221
+ query = {
222
+
223
+ 'table' => 'sys_report_template',
224
+ 'where' => {
225
+
226
+ 'jvar_report_id' => '__REPORT_SYS_ID___'
227
+
228
+ }
229
+
230
+ }
231
+
232
+ @http_request.should_receive(
233
+
234
+ :get
235
+
236
+ ).with({
237
+
238
+ :connect_timeout => 60,
239
+ :timeout => 120,
240
+ :head => {
241
+
242
+ "Content-Type" => "application/json",
243
+ "cookie" => @cookies
244
+
245
+ },
246
+
247
+ }).and_return(
248
+
249
+ @http_request
250
+
251
+ )
252
+
253
+ EventMachine::HttpRequest.should_receive(
254
+
255
+ :new
256
+
257
+ ).with(
258
+
259
+ "#{@url}/sys_report_template.do?CSV&jvar_report_id=__REPORT_SYS_ID___"
260
+
261
+ ).and_return(
262
+
263
+ @http_request
264
+
265
+ )
266
+
267
+ subject.service_now( :getCSV, query )
268
+
269
+ end
270
+
150
271
  it 'supports special query things' do
151
272
 
152
273
  query = {
@@ -4,21 +4,20 @@ describe ServiceNow do
4
4
 
5
5
  subject {
6
6
 
7
- LOG.on
7
+ LOG.off
8
8
  subj = Object.extend( ServiceNow )
9
9
  subj.service_now_init( CONFIG['config'], LOG )
10
10
  subj
11
11
 
12
12
  }
13
13
 
14
- pending 'can get by CSV interface' do
14
+ it 'can get by CSV interface' do
15
15
 
16
16
  query = CONFIG['queries']['get_specific_report']
17
17
 
18
18
  result = []
19
19
  subject.em_service_now( :getCSV, query ) do |record, error|
20
20
 
21
-
22
21
  result << record unless record.nil?
23
22
 
24
23
  end
@@ -27,7 +26,24 @@ describe ServiceNow do
27
26
 
28
27
  end
29
28
 
30
- pending 'can get by JSON interface' do
29
+ it 'can getKeys by JSON interface' do
30
+
31
+ sys_id = nil
32
+
33
+ query = CONFIG['queries']['get_specific_company']
34
+ expectation = CONFIG['queries']['get_specific_company_sys_id']
35
+
36
+ subject.em_service_now( :getKeys, query ) do |record, status|
37
+
38
+ sys_id = record
39
+
40
+ end
41
+
42
+ sys_id.should == expectation
43
+
44
+ end
45
+
46
+ it 'can getRecords by JSON interface' do
31
47
 
32
48
  company = nil
33
49
 
@@ -44,7 +60,7 @@ describe ServiceNow do
44
60
 
45
61
  end
46
62
 
47
- pending 'errors on invalid table name' do
63
+ it 'errors on invalid table name' do
48
64
 
49
65
  result = nil
50
66
 
@@ -65,7 +81,7 @@ describe ServiceNow do
65
81
 
66
82
  end
67
83
 
68
- pending 'can create an incident' do
84
+ it 'can create an incident' do
69
85
 
70
86
  query = {
71
87
 
@@ -83,7 +99,7 @@ describe ServiceNow do
83
99
 
84
100
  end
85
101
 
86
- pending 'can update incidents by company, short_description and status' do
102
+ it 'can update incidents by company, short_description and status' do
87
103
 
88
104
  update_column = CONFIG['incident']['update']['column']
89
105
  update_value = CONFIG['incident']['update']['value']
@@ -121,7 +137,7 @@ describe ServiceNow do
121
137
  end
122
138
 
123
139
 
124
- pending 'can close incidents by company, short_description and status' do
140
+ it 'can close incidents by company, short_description and status' do
125
141
 
126
142
  query = {
127
143
 
@@ -18,6 +18,7 @@ queries:
18
18
  jvar_report_id: 5896e8a30c16a00087c61678d080f220
19
19
 
20
20
  get_specific_company_expectation: COMPANY NAME
21
+ get_specific_company_sys_id: 5fac1edc0a0a3c1e00ccdb50799bcec1
21
22
  get_specific_company:
22
23
  table: core_company
23
24
  where:
@@ -1,7 +1,11 @@
1
1
  require 'em-service-now'
2
+ # :stopdoc:
2
3
 
4
+ #
5
+ # service_now_init() takes a config Hash
6
+ # (this loads it)
7
+ #
3
8
  SPEC_CONFIG_FILE = "#{File.dirname( __FILE__ )}/spec_config.yml"
4
-
5
9
  CONFIG = YAML.load_file(
6
10
 
7
11
  SPEC_CONFIG_FILE
@@ -9,6 +13,10 @@ CONFIG = YAML.load_file(
9
13
  ) if File.file?( SPEC_CONFIG_FILE )
10
14
  CONFIG = {} unless defined?( CONFIG )
11
15
 
16
+ #
17
+ # service_now_init() takes a generic logger
18
+ # (this creates a fake one)
19
+ #
12
20
  class FakeLogger
13
21
 
14
22
  def initialize( parameter = :noisey )
@@ -41,3 +49,5 @@ class FakeLogger
41
49
  end
42
50
 
43
51
  LOG = FakeLogger.new
52
+
53
+ # :startdoc:
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-service-now
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- version: "0.3"
9
+ - 1
10
+ version: 0.3.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Richard
@@ -17,7 +18,7 @@ autorequire:
17
18
  bindir: bin
18
19
  cert_chain: []
19
20
 
20
- date: 2012-06-22 00:00:00 Z
21
+ date: 2012-06-23 00:00:00 Z
21
22
  dependencies:
22
23
  - !ruby/object:Gem::Dependency
23
24
  name: eventmachine
@@ -25,12 +26,12 @@ dependencies:
25
26
  requirement: &id001 !ruby/object:Gem::Requirement
26
27
  none: false
27
28
  requirements:
28
- - - ~>
29
+ - - ">="
29
30
  - !ruby/object:Gem::Version
30
- hash: 1
31
+ hash: 3
31
32
  segments:
32
- - 1
33
- version: "1"
33
+ - 0
34
+ version: "0"
34
35
  type: :runtime
35
36
  version_requirements: *id001
36
37
  - !ruby/object:Gem::Dependency
@@ -39,12 +40,12 @@ dependencies:
39
40
  requirement: &id002 !ruby/object:Gem::Requirement
40
41
  none: false
41
42
  requirements:
42
- - - ~>
43
+ - - ">="
43
44
  - !ruby/object:Gem::Version
44
- hash: 1
45
+ hash: 3
45
46
  segments:
46
- - 1
47
- version: "1"
47
+ - 0
48
+ version: "0"
48
49
  type: :runtime
49
50
  version_requirements: *id002
50
51
  - !ruby/object:Gem::Dependency
@@ -62,7 +63,7 @@ dependencies:
62
63
  type: :runtime
63
64
  version_requirements: *id003
64
65
  - !ruby/object:Gem::Dependency
65
- name: yaml
66
+ name: awesome_print
66
67
  prerelease: false
67
68
  requirement: &id004 !ruby/object:Gem::Requirement
68
69
  none: false
@@ -123,6 +124,6 @@ rubyforge_project:
123
124
  rubygems_version: 1.8.5
124
125
  signing_key:
125
126
  specification_version: 3
126
- summary: Tools for interfacing with service-now.com
127
+ summary: Tool for interfacing with service-now.com
127
128
  test_files: []
128
129