em-service-now 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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