spectre-core 1.9.0 → 1.12.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/spectre/curl.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative '../spectre'
2
+
1
3
  require 'open3'
2
4
  require 'ostruct'
3
5
 
@@ -21,17 +23,17 @@ module Spectre::Curl
21
23
  end
22
24
 
23
25
  def header name, value
24
- @__req['headers'] = [] if not @__req['headers']
26
+ @__req['headers'] = [] unless @__req['headers']
25
27
  @__req['headers'].append [name, value.to_s.strip]
26
28
  end
27
29
 
28
30
  def param name, value
29
- @__req['query'] = [] if not @__req['query']
31
+ @__req['query'] = [] unless @__req['query']
30
32
  @__req['query'].append [name, value.to_s.strip]
31
33
  end
32
34
 
33
35
  def content_type media_type
34
- @__req['headers'] = [] if not @__req['headers']
36
+ @__req['headers'] = [] unless @__req['headers']
35
37
  @__req['headers'].append ['Content-Type', media_type]
36
38
  end
37
39
 
@@ -111,7 +113,7 @@ module Spectre::Curl
111
113
  end
112
114
 
113
115
  def json
114
- return nil if not @res[:body]
116
+ return nil unless @res[:body]
115
117
 
116
118
  if @data == nil
117
119
  begin
@@ -161,28 +163,31 @@ module Spectre::Curl
161
163
 
162
164
  if @@http_cfg.key? name
163
165
  req.merge! @@http_cfg[name]
164
- raise "No `base_url' set for HTTP client '#{name}'. Check your HTTP config in your environment." if !req['base_url']
166
+ raise "No `base_url' set for HTTP client '#{name}'. Check your HTTP config in your environment." unless req['base_url']
165
167
  else
166
168
  req['base_url'] = name
167
169
  end
168
170
 
169
- SpectreHttpRequest.new(req).instance_eval(&block) if block_given?
171
+ SpectreHttpRequest.new(req)._evaluate(&block) if block_given?
170
172
 
171
173
  invoke(req)
172
174
  end
173
175
 
174
176
  def curl_request
175
177
  raise 'No request has been invoked yet' unless @@request
178
+
176
179
  @@request
177
180
  end
178
181
 
179
182
  def curl_response
180
183
  raise 'There is no response. No request has been invoked yet.' unless @@response
184
+
181
185
  @@response
182
186
  end
183
187
 
184
188
  def register mod
185
189
  raise 'Module must not be nil' unless mod
190
+
186
191
  @@modules << mod
187
192
  end
188
193
 
@@ -192,7 +197,8 @@ module Spectre::Curl
192
197
  return str unless str or str.empty?
193
198
 
194
199
  begin
195
- json = JSON.parse str
200
+ json = JSON.parse(str)
201
+ json.obfuscate!(@@secure_keys) unless @@debug
196
202
 
197
203
  if pretty
198
204
  str = JSON.pretty_generate(json)
@@ -206,6 +212,25 @@ module Spectre::Curl
206
212
  str
207
213
  end
208
214
 
215
+ def secure? key
216
+ @@secure_keys.any? { |x| key.to_s.downcase.include? x.downcase }
217
+ end
218
+
219
+ def header_to_s headers
220
+ s = ''
221
+
222
+ return s unless headers
223
+
224
+ headers.each do |header|
225
+ key = header[0].to_s
226
+ value = header[1].to_s
227
+ value = '*****' if secure?(key) and not @@debug
228
+ s += "#{key.ljust(30, '.')}: #{value}\n"
229
+ end
230
+
231
+ s
232
+ end
233
+
209
234
  def invoke req
210
235
  cmd = [@@curl_path]
211
236
 
@@ -217,12 +242,12 @@ module Spectre::Curl
217
242
 
218
243
  uri = req['base_url']
219
244
 
220
- if not uri.match /http(?:s)?:\/\//
245
+ unless uri.match /http(?:s)?:\/\//
221
246
  uri = scheme + '://' + uri
222
247
  end
223
248
 
224
249
  if req['path']
225
- uri += '/' if !uri.end_with? '/'
250
+ uri += '/' unless uri.end_with? '/'
226
251
  uri += req['path']
227
252
  end
228
253
 
@@ -230,11 +255,11 @@ module Spectre::Curl
230
255
  uri += '?'
231
256
  uri += req['query']
232
257
  .map { |x| x.join '='}
233
- .join '&'
258
+ .join('&')
234
259
  end
235
260
 
236
- cmd.append '"' + uri + '"'
237
- cmd.append '-X', req['method'] unless req['method'] == 'GET' or (req['body'] and req['method'] == 'POST')
261
+ cmd.append('"' + uri + '"')
262
+ cmd.append('-X', req['method']) unless req['method'] == 'GET' or (req['body'] and req['method'] == 'POST')
238
263
 
239
264
  # Call all registered modules
240
265
  @@modules.each do |mod|
@@ -243,43 +268,42 @@ module Spectre::Curl
243
268
 
244
269
  # Add headers to curl command
245
270
  req['headers'].each do |header|
246
- cmd.append '-H', '"' + header.join(':') + '"'
271
+ cmd.append('-H', '"' + header.join(':') + '"')
247
272
  end if req['headers']
248
273
 
249
274
  # Add request body
250
275
  if req['body'] != nil and not req['body'].empty?
251
276
  req_body = try_format_json(req['body']).gsub(/"/, '\\"')
252
- cmd.append '-d', '"' + req_body + '"'
277
+ cmd.append('-d', '"' + req_body + '"')
253
278
  elsif ['POST', 'PUT', 'PATCH'].include? req['method'].upcase
254
- cmd.append '-d', '"\n"'
279
+ cmd.append('-d', '"\n"')
255
280
  end
256
281
 
257
282
  # Add certificate path if one if given
258
283
  if req['cert']
259
284
  raise "Certificate '#{req['cert']}' does not exist" unless File.exists? req['cert']
260
- cmd.append '--cacert', req['cert']
285
+
286
+ cmd.append('--cacert', req['cert'])
261
287
  elsif req['use_ssl'] or uri.start_with? 'https'
262
- cmd.append '-k'
288
+ cmd.append('-k')
263
289
  end
264
290
 
265
- cmd.append '-i'
266
- cmd.append '-v'
291
+ cmd.append('-i')
292
+ cmd.append('-v')
267
293
 
268
- @@request = OpenStruct.new req
294
+ @@request = OpenStruct.new(req)
269
295
 
270
- sys_cmd = cmd.join ' '
296
+ sys_cmd = cmd.join(' ')
271
297
 
272
- @@logger.debug sys_cmd
298
+ @@logger.debug(sys_cmd)
273
299
 
274
300
  req_id = SecureRandom.uuid()[0..5]
275
301
 
276
302
  req_log = "[>] #{req_id} #{req['method']} #{uri}\n"
277
- req['headers'].each do |header|
278
- req_log += "#{header[0].to_s.ljust(30, '.')}: #{header[1].to_s}\n"
279
- end if req['headers']
280
- req_log += req['body'] if req['body'] != nil and not req['body'].empty?
303
+ req_log += header_to_s(req['headers'])
304
+ req_log += try_format_json(req['body'], pretty: true)
281
305
 
282
- @@logger.info req_log
306
+ @@logger.info(req_log)
283
307
 
284
308
  start_time = Time.now
285
309
 
@@ -295,9 +319,9 @@ module Spectre::Curl
295
319
 
296
320
  # debug_log.lines.each { |x| @@logger.debug x unless x.empty? }
297
321
 
298
- raise "Unable to request #{uri}. Please check if this service is reachable." unless output
322
+ raise "Unable to request #{uri}. Please check if this URL is correctly configured and reachable." unless output
299
323
 
300
- @@logger.debug "[<] #{req_id} stdout:\n#{output}"
324
+ @@logger.debug("[<] #{req_id} stdout:\n#{output}")
301
325
 
302
326
  header, body = output.split /\r?\n\r?\n/
303
327
 
@@ -323,7 +347,7 @@ module Spectre::Curl
323
347
  code: match[:code].to_i,
324
348
  message: match[:message],
325
349
  headers: Hash[res_headers],
326
- body: body
350
+ body: body,
327
351
  }
328
352
 
329
353
  # Call all registered modules
@@ -342,7 +366,7 @@ module Spectre::Curl
342
366
 
343
367
  @@logger.info res_log
344
368
 
345
- @@response = SpectreHttpResponse.new res
369
+ @@response = SpectreHttpResponse.new(res)
346
370
 
347
371
  raise "Response did not indicate success: #{@@response.code} #{@@response.message}" if req['ensure_success'] and not @@response.success?
348
372
 
@@ -351,7 +375,12 @@ module Spectre::Curl
351
375
  end
352
376
 
353
377
  Spectre.register do |config|
354
- @@logger = ::Logger.new config['log_file'], progname: 'spectre/curl'
378
+ @@debug = config['debug']
379
+
380
+ @@logger = ::Logger.new(config['log_file'], progname: 'spectre/curl')
381
+ @@logger.level = @@debug ? Logger::DEBUG : Logger::INFO
382
+
383
+ @@secure_keys = config['secure_keys'] || []
355
384
 
356
385
  @@curl_path = config['curl_path'] || 'curl'
357
386
 
@@ -365,4 +394,4 @@ module Spectre::Curl
365
394
  end
366
395
 
367
396
  Spectre.delegate :curl, :curl_response, :curl_request, to: self
368
- end
397
+ end
@@ -1,3 +1,5 @@
1
+ require_relative '../spectre'
2
+
1
3
  module Spectre
2
4
  module Diagnostic
3
5
  module Stopwatch
@@ -21,9 +23,17 @@ module Spectre
21
23
  def duration
22
24
  @@end_time - @@start_time
23
25
  end
26
+
27
+ def started_at
28
+ @@start_time
29
+ end
30
+
31
+ def finished_at
32
+ @@end_time
33
+ end
24
34
  end
25
35
 
26
- Spectre.delegate :start_watch, :stop_watch, :duration, :measure, to: Stopwatch
36
+ Spectre.delegate :start_watch, :stop_watch, :duration, :measure, to: self
27
37
  end
28
38
  end
29
- end
39
+ end
@@ -1,9 +1,13 @@
1
+ require_relative '../spectre'
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  def to_recursive_ostruct(hash)
4
- OpenStruct.new(hash.each_with_object({}) do |(key, val), memo|
5
- memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
6
- end)
6
+ OpenStruct.new(
7
+ hash.each_with_object({}) do |(key, val), memo|
8
+ memo[key] = val.is_a?(Hash) ? to_recursive_ostruct(val) : val
9
+ end
10
+ )
7
11
  end
8
12
 
9
13
  module Spectre
@@ -21,6 +25,6 @@ module Spectre
21
25
  @@environment.freeze
22
26
  end
23
27
 
24
- Spectre.delegate :env, to: Environment
28
+ Spectre.delegate :env, to: self
25
29
  end
26
- end
30
+ end
@@ -1,7 +1,10 @@
1
+ require_relative '../spectre'
2
+
1
3
  require 'securerandom'
2
4
  require 'json'
3
5
  require 'date'
4
6
  require 'ostruct'
7
+ require 'jsonpath'
5
8
 
6
9
  class ::String
7
10
  def as_json
@@ -12,15 +15,8 @@ class ::String
12
15
  DateTime.parse(self)
13
16
  end
14
17
 
15
- def content with: nil
16
- fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
17
- file_content = File.read(self)
18
-
19
- if with
20
- file_content.with(with)
21
- else
22
- file_content
23
- end
18
+ def as_timestamp
19
+ DateTime.parse(self).to_time.to_i
24
20
  end
25
21
 
26
22
  def with mapping
@@ -29,46 +25,109 @@ class ::String
29
25
  new_string = self
30
26
 
31
27
  mapping.each do |key, value|
32
- new_string = new_string.gsub '#{' + key.to_s + '}', value.to_s
28
+ new_string = new_string.gsub('#{' + key.to_s + '}', value.to_s)
33
29
  end
34
30
 
35
31
  new_string
36
32
  end
37
33
 
38
- def exists?
39
- File.exists? self
34
+ def trim size = 50
35
+ if (self.length + 3) > size
36
+ return self[0..size-4] + '...'
37
+ end
38
+
39
+ self
40
40
  end
41
41
 
42
- def remove!
43
- fail "'#{self}' is not a file path, or the file does not exist." if !File.exists? self
42
+ def pick path
43
+ raise ArgumentError.new("`path' must not be nil or empty") if path.nil? or path.empty?
44
44
 
45
- File.delete self
45
+ begin
46
+ JsonPath.on(self, path)
47
+ rescue MultiJson::ParseError
48
+ # do nothing and return nil
49
+ end
46
50
  end
47
51
 
48
- def trim count = 50
49
- if (self.length + 3) > count
50
- return self[0..count-4] + '...'
52
+ # File helpers
53
+
54
+ def content with: nil
55
+ fail "'#{self}' is not a file path, or the file does not exist." unless File.exists? self
56
+
57
+ file_content = File.read(self)
58
+
59
+ if with
60
+ file_content.with(with)
61
+ else
62
+ file_content
51
63
  end
64
+ end
52
65
 
53
- self
66
+ def file_size
67
+ fail "'#{self}' is not a file path, or the file does not exist." unless File.exists? self
68
+
69
+ File.size(self)
54
70
  end
55
- end
56
71
 
72
+ def exists?
73
+ File.exists? self
74
+ end
75
+
76
+ def remove!
77
+ fail "'#{self}' is not a file path, or the file does not exist." unless File.exists? self
78
+
79
+ File.delete self
80
+ end
81
+ end
57
82
 
58
83
  class ::OpenStruct
59
84
  def to_json *args, **kwargs
60
85
  self.to_h.inject({}) { |memo, (k,v)| memo[k] = v.is_a?(OpenStruct) ? v.to_h : v; memo }.to_json(*args, **kwargs)
61
86
  end
62
- end
63
87
 
88
+ def pick path
89
+ raise ArgumentError.new("`path' must not be nil or empty") if path.nil? or path.empty?
90
+
91
+ JsonPath.on(self, path)
92
+ end
93
+
94
+ def default_to! defaults
95
+ defaults.each_key do |key|
96
+ unless self[key] != nil
97
+ self[key] = defaults[key]
98
+ end
99
+ end
100
+ end
101
+
102
+ alias :defaults_to! :default_to!
103
+ end
64
104
 
65
105
  class ::Hash
66
106
  def symbolize_keys
67
107
  self.inject({}) { |memo, (k,v)| memo[k.to_sym] = v; memo }
68
108
  end
109
+
110
+ def default_to! defaults
111
+ defaults.each_key do |key|
112
+ unless self[key] != nil
113
+ self[key] = defaults[key]
114
+ end
115
+ end
116
+ end
117
+
118
+ alias :defaults_to! :default_to!
69
119
  end
70
120
 
121
+ class ::Array
122
+ def last_element
123
+ self[-1]
124
+ end
125
+ end
71
126
 
72
127
  def uuid length = 5
73
128
  SecureRandom.uuid().gsub('-', '')[0..length-1]
74
- end
129
+ end
130
+
131
+ def now
132
+ Time.now
133
+ end
@@ -1,7 +1,9 @@
1
+ require_relative '../http'
2
+
1
3
  module Spectre::Http
2
4
  class SpectreHttpRequest
3
5
  def basic_auth username, password
4
- @__req['basic_auth'] = {} if not @__req.key? 'basic_auth'
6
+ @__req['basic_auth'] = {} unless @__req.key? 'basic_auth'
5
7
 
6
8
  @__req['basic_auth']['username'] = username
7
9
  @__req['basic_auth']['password'] = password
@@ -11,8 +13,9 @@ module Spectre::Http
11
13
  end
12
14
 
13
15
  module BasicAuth
14
- def self.on_req http, net_req, req
16
+ def self.on_req _http, net_req, req
15
17
  return unless req.key? 'basic_auth' and req['auth'] == 'basic_auth'
18
+
16
19
  basic_auth_cfg = req['basic_auth']
17
20
  net_req.basic_auth(basic_auth_cfg['username'], basic_auth_cfg['password'])
18
21
  end
@@ -1,98 +1,101 @@
1
- class HttpRequest
2
- def keystone url, username, password, project, domain, cert
3
- @__req['keystone'] = {} if not @__req.key? 'keystone'
4
-
5
- @__req['keystone']['url'] = url
6
- @__req['keystone']['username'] = username
7
- @__req['keystone']['password'] = password
8
- @__req['keystone']['project'] = project
9
- @__req['keystone']['domain'] = domain
10
- @__req['keystone']['cert'] = cert
11
-
12
- @__req.config['auth'] = 'keystone'
1
+ require_relative '../http'
2
+
3
+ module Spectre::Http
4
+ class SpectreHttpRequest
5
+ def keystone url, username, password, project, domain, cert=nil
6
+ @__req['keystone'] = {} unless @__req.key? 'keystone'
7
+
8
+ @__req['keystone']['url'] = url
9
+ @__req['keystone']['username'] = username
10
+ @__req['keystone']['password'] = password
11
+ @__req['keystone']['project'] = project
12
+ @__req['keystone']['domain'] = domain
13
+ @__req['keystone']['cert'] = cert
14
+
15
+ @__req['auth'] = 'keystone'
16
+ end
13
17
  end
14
- end
15
18
 
19
+ module Keystone
20
+ @@cache = {}
16
21
 
17
- module Spectre::Http::Keystone
18
- @@cache = {}
22
+ def self.on_req _http, net_req, req
23
+ return unless req.key? 'keystone' and req['auth'] == 'keystone'
19
24
 
20
- def self.on_req http, net_req, req
21
- return unless req.key? 'keystone' and req['auth'] == 'keystone'
25
+ keystone_cfg = req['keystone']
22
26
 
23
- keystone_cfg = req['keystone']
27
+ if @@cache.key? keystone_cfg
28
+ token = @@cache[keystone_cfg]
29
+ else
30
+ token, _ = authenticate(
31
+ keystone_cfg['url'],
32
+ keystone_cfg['username'],
33
+ keystone_cfg['password'],
34
+ keystone_cfg['project'],
35
+ keystone_cfg['domain'],
36
+ keystone_cfg['cert'],
37
+ )
24
38
 
25
- if @@cache.key? keystone_cfg
26
- token = @@cache[keystone_cfg]
27
- else
28
- token, _ = authenticate(
29
- keystone_cfg['url'],
30
- keystone_cfg['username'],
31
- keystone_cfg['password'],
32
- keystone_cfg['project'],
33
- keystone_cfg['domain'],
34
- keystone_cfg['cert'],
35
- )
39
+ @@cache[keystone_cfg] = token
40
+ end
36
41
 
37
- @@cache[keystone_cfg] = token
42
+ net_req['X-Auth-Token'] = token
38
43
  end
39
44
 
40
- net_req['X-Auth-Token'] = token
41
- end
42
-
43
- private
44
-
45
- def self.authenticate keystone_url, username, password, project, domain, cert
46
- auth_data = {
47
- auth: {
48
- identity: {
49
- methods: ['password'],
50
- password: {
51
- user: {
52
- name: username,
53
- password: password,
54
- domain: {
55
- name: domain,
45
+ private
46
+
47
+ def self.authenticate keystone_url, username, password, project, domain, cert
48
+ auth_data = {
49
+ auth: {
50
+ identity: {
51
+ methods: ['password'],
52
+ password: {
53
+ user: {
54
+ name: username,
55
+ password: password,
56
+ domain: {
57
+ name: domain,
58
+ },
56
59
  },
57
60
  },
58
61
  },
59
- },
60
- scope: {
61
- project: {
62
- name: project,
63
- domain: {
64
- name: domain,
62
+ scope: {
63
+ project: {
64
+ name: project,
65
+ domain: {
66
+ name: domain,
67
+ },
65
68
  },
66
69
  },
67
70
  },
68
- },
69
- }
71
+ }
70
72
 
71
- keystone_url = keystone_url + '/' if !keystone_url.end_with? '/'
73
+ keystone_url = keystone_url + '/' unless keystone_url.end_with? '/'
72
74
 
73
- base_uri = URI(keystone_url)
74
- uri = URI.join(base_uri, 'auth/tokens?nocatalog=true')
75
+ base_uri = URI(keystone_url)
76
+ uri = URI.join(base_uri, 'auth/tokens?nocatalog=true')
75
77
 
76
- http = Net::HTTP.new(base_uri.host, base_uri.port)
78
+ http = Net::HTTP.new(base_uri.host, base_uri.port)
77
79
 
78
- if cert
79
- http.use_ssl = true
80
- http.ca_file = cert
81
- end
80
+ if cert
81
+ http.use_ssl = true
82
+ http.ca_file = cert
83
+ end
82
84
 
83
- req = Net::HTTP::Post.new(uri)
84
- req.body = JSON.pretty_generate(auth_data)
85
- req.content_type = 'application/json'
85
+ req = Net::HTTP::Post.new(uri)
86
+ req.body = JSON.pretty_generate(auth_data)
87
+ req.content_type = 'application/json'
86
88
 
87
- res = http.request(req)
89
+ res = http.request(req)
88
90
 
89
- raise "error while authenticating: #{res.code} #{res.message}\n#{res.body}" if res.code != '201'
91
+ raise "error while authenticating: #{res.code} #{res.message}\n#{res.body}" if res.code != '201'
90
92
 
91
- [
92
- res['X-Subject-Token'],
93
- JSON.parse(res.body),
94
- ]
95
- end
93
+ [
94
+ res['X-Subject-Token'],
95
+ JSON.parse(res.body),
96
+ ]
97
+ end
96
98
 
97
- Spectre::Http.register(self)
99
+ Spectre::Http.register(self)
100
+ end
98
101
  end