arborist-webservice 0.0.1.pre20180815100446 → 0.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1006dfaf9b120fa2720a2637603c4f75397cbe36d62f2039c35d4a1f8c39b56
4
- data.tar.gz: 46b34fd363f89a60bcfa7cdafceeec8d2a68c00e9e0b79d2c5126b9fc4b47137
3
+ metadata.gz: 3d364d3021e618267b924682c39b011d365aa486c56a37c13842a23d71e4b4c6
4
+ data.tar.gz: b6028b714764befd0d89372432d6936037eaa0b5bd54d10f735c537903fbeb38
5
5
  SHA512:
6
- metadata.gz: 3d5b067c522b37beb004f549c98fba58ba7e64806a79baa05be708344ef9cc6801d982ec083bedfacbed75f6e30eb5fa4ef09ebf0b744f88272d032f1ea2dc9a
7
- data.tar.gz: 49457c9714ce9c128be66eb3e04a9f7bc280ebbf4c0359e2d3719e73415eb21ce62189eb07ff68e095f876f5b8b2dadf996b46dedf230d3084baa0aa4bf5d299
6
+ metadata.gz: f7b5ff725bd2e08a5737e5c2d0ceb8dfdff21aec1d30633cf08fa0c310ca82c01f1524c3bdb2ce472843ca002536311cbf1eca65d1e087bd2487ecfb156741ee
7
+ data.tar.gz: 1c023a87365bc5551a3ccb3f054e5c15a671f8bff6df0e66e88b8f83232d08524d0f4f07a94a791c19a033b67d8ff71eef437ecf730a4dbebefc08773472fcf4
@@ -0,0 +1,2 @@
1
+ �@9�]�TElMoˡ�|�g����c��R�����P����ڙ���u�k�j�U~���w�Ӿݘ��-�������!��B��u+����~mVG?�Fѯ�Q��ud�@� :0�R��L.����'�z���mrAs�(�]�`���r0 �o'M���ލ��\��Ð�Zp@9C�ͷ�3�bW8����_��~�ަ���#%����/:� �|��Z�������vs<���4��)A�P���WOE��@j$�[xs�2W
2
+ �� /0$����JY\�-2
Binary file
data/ChangeLog CHANGED
@@ -1,12 +1,55 @@
1
+ 2018-08-30 Michael Granger <ged@FaerieMUD.org>
2
+
3
+ * History.md, arborist-webservice.gemspec:
4
+ Update history and the gemspec
5
+ [65c19b823a1b] [tip]
6
+
7
+ * README.md, lib/arborist/monitor/webservice.rb,
8
+ lib/arborist/node/webservice.rb,
9
+ lib/arborist/webservice/constants.rb,
10
+ spec/arborist/monitor/webservice_spec.rb,
11
+ spec/arborist/node/webservice_spec.rb, spec/spec_helper.rb:
12
+ Finish up tests, flesh out settings and config for less-common
13
+ cases.
14
+ [53ff11b5ccf6]
15
+
16
+ 2018-08-29 Michael Granger <ged@FaerieMUD.org>
17
+
18
+ * lib/arborist/monitor/webservice.rb,
19
+ spec/arborist/monitor/webservice_spec.rb:
20
+ Rename 'HTML' monitor callback to 'HTTP'
21
+ [c970fb9b5ccf] [github/master]
22
+
1
23
  2018-08-15 Michael Granger <ged@FaerieMUD.org>
2
24
 
25
+ * README.md, Rakefile, arborist-webservice.gemspec:
26
+ Fix some documentation issues.
27
+ [1e226b9d9561]
28
+
29
+ * .hgignore:
30
+ Ignore built gems
31
+ [a580ef4ff61b]
32
+
33
+ * Rakefile, arborist-webservice.gemspec:
34
+ Update dependencies.
35
+ [c08c1e0bbb70]
36
+
37
+ * .gems, .hgignore, ChangeLog, Manifest.txt, Rakefile, arborist-
38
+ webservice.gemspec, lib/arborist/monitor/webservice.rb,
39
+ lib/arborist/webservice.rb, lib/arborist/webservice/connection.rb,
40
+ lib/arborist/webservice/constants.rb,
41
+ spec/arborist/monitor/webservice_spec.rb,
42
+ spec/arborist/node/webservice_spec.rb:
43
+ Switch to Typhoeus for batched parallel requests
44
+ [59e390021ccd]
45
+
3
46
  * .gems, Rakefile, lib/arborist/monitor/webservice.rb,
4
47
  lib/arborist/node/webservice.rb, lib/arborist/webservice.rb,
5
48
  lib/arborist/webservice/connection.rb,
6
49
  lib/arborist/webservice/constants.rb,
7
50
  lib/arborist/webservice/monkeypatches.rb:
8
51
  Checkpoint commit before switching to Typhoeus
9
- [d2e9ed791434] [tip]
52
+ [d2e9ed791434]
10
53
 
11
54
  2018-08-01 Mahlon E. Smith <mahlon@martini.nu>
12
55
 
@@ -18,7 +61,7 @@
18
61
 
19
62
  * README.md:
20
63
  Fix incorrect URLs in the README
21
- [7bdc40158b25] [github/master]
64
+ [7bdc40158b25]
22
65
 
23
66
  * .gems, .pryrc, .ruby-gemset, .ruby-version, .rvm.gems, .rvmrc,
24
67
  ChangeLog, History.md, LICENSE.txt, Manifest.txt, README.md,
data/History.md CHANGED
@@ -1,4 +1,4 @@
1
- ## v0.0.1 [YYYY-MM-DD] Michael Granger <ged@FaerieMUD.org>
1
+ ## v0.0.1 [2018-08-30] Michael Granger <ged@FaerieMUD.org>
2
2
 
3
3
  Initial release.
4
4
 
data/README.md CHANGED
@@ -30,7 +30,7 @@ The simplest example is an unauthenticated REST service running on port 80:
30
30
  end
31
31
 
32
32
  This adds a `webservice` child node to the containing host with an identifier of
33
- `frontend-17-api-example-com-webservice`.
33
+ `example-webserver-api-vi`.
34
34
 
35
35
  The simplest monitor setup to monitor that service might look something like:
36
36
 
@@ -38,9 +38,9 @@ The simplest monitor setup to monitor that service might look something like:
38
38
  #encoding: utf-8
39
39
 
40
40
  require 'arborist/monitor/webservice'
41
- Arborist::Monitor::Webservice::REST.default
41
+ Arborist::Monitor::Webservice::HTTP.default
42
42
 
43
- This would check that an OPTIONS HTTP request to `http://api.example.com/v1/heartbeat` responds with a 2xx status code.
43
+ This would check that an HEAD HTTP request to `http://api.example.com/v1/heartbeat` responds with a 2xx status code.
44
44
 
45
45
 
46
46
  ## Prerequisites
@@ -69,7 +69,7 @@ and generate the API documentation.
69
69
 
70
70
  ## License
71
71
 
72
- Copyright (c) 2016, Michael Granger
72
+ Copyright (c) 2016-2018, Michael Granger
73
73
  All rights reserved.
74
74
 
75
75
  Redistribution and use in source and binary forms, with or without
data/Rakefile CHANGED
@@ -29,13 +29,13 @@ hoespec = Hoe.spec 'arborist-webservice' do |spec|
29
29
 
30
30
  spec.developer 'Michael Granger', 'ged@FaerieMUD.org'
31
31
 
32
- spec.dependency 'arborist', '~> 0'
33
- spec.dependency 'loggability', '~> 0.11'
32
+ spec.dependency 'arborist', '~> 0.2'
33
+ spec.dependency 'loggability', '~> 0.14'
34
34
  spec.dependency 'typhoeus', '~> 1.3'
35
35
 
36
- spec.dependency 'hoe-deveiate', '~> 0.3', :developer
36
+ spec.dependency 'hoe-deveiate', '~> 0.10', :developer
37
37
  spec.dependency 'simplecov', '~> 0.7', :developer
38
- spec.dependency 'rdoc-generator-fivefish', '~> 0.1', :developer
38
+ spec.dependency 'rdoc-generator-fivefish', '~> 0.4', :developer
39
39
 
40
40
  spec.hg_sign_tags = true if spec.respond_to?( :hg_sign_tags= )
41
41
  spec.check_history_on_release = true if spec.respond_to?( :check_history_on_release= )
@@ -69,11 +69,11 @@ if File.directory?( '.hg' )
69
69
 
70
70
  Rake::Task[ 'docs' ].clear
71
71
  RDoc::Task.new( 'docs' ) do |rdoc|
72
- rdoc.main = "README.rdoc"
72
+ rdoc.main = "README.md"
73
73
  rdoc.markup = 'markdown'
74
- rdoc.rdoc_files.include( "*.rdoc", "ChangeLog", "lib/**/*.rb" )
74
+ rdoc.rdoc_files.include( "*.rdoc", "*.md", "ChangeLog", "lib/**/*.rb" )
75
75
  rdoc.generator = :fivefish
76
- rdoc.title = 'Webservice Node Type for Arborist'
76
+ rdoc.title = 'Webservice Node Type and Monitor for Arborist'
77
77
  rdoc.rdoc_dir = 'doc'
78
78
  end
79
79
  end
@@ -34,12 +34,20 @@ module Arborist::Monitor::Webservice
34
34
  Integer( val )
35
35
  end
36
36
 
37
+ ##
38
+ # Whether or not to enable SSL peer certificate verification by default. The
39
+ # value is either `1` to enable it by default, or `0` to disable it by default.
40
+ # The config of each invidual webservice node can override this.
41
+ setting :ssl_verifypeer, default: 1 do |val|
42
+ Integer( val ).nonzero? ? 1 : 0
43
+ end
44
+
37
45
  end
38
46
 
39
47
 
40
48
 
41
- # Arborist HTML web service monitor logic
42
- class HTML
49
+ # Arborist HTTP web service monitor logic
50
+ class HTTP
43
51
  extend Loggability
44
52
  include Arborist::Webservice::Constants
45
53
 
@@ -53,7 +61,7 @@ module Arborist::Monitor::Webservice
53
61
  }
54
62
 
55
63
  # The array of node properites used by this monitor
56
- NODE_PROPERTIES = %i[ uri http_method body body_mimetype ].freeze
64
+ NODE_PROPERTIES = %i[ uri http_method body body_mimetype config ].freeze
57
65
 
58
66
 
59
67
  ### Return an array of attributes to fetch from nodes for this monitor.
@@ -68,7 +76,7 @@ module Arborist::Monitor::Webservice
68
76
  end
69
77
 
70
78
 
71
- ### Create a new HTML webservice monitor with the specified +options+. Valid options are:
79
+ ### Create a new HTTP webservice monitor with the specified +options+. Valid options are:
72
80
  ###
73
81
  ### +:timeout+
74
82
  ### Set the number of seconds to wait for a connection for each node.
@@ -103,7 +111,8 @@ module Arborist::Monitor::Webservice
103
111
  request = self.request_for_node( node )
104
112
  request.on_complete do |response|
105
113
  self.log.debug "Handling response for %s" % [ identifier ]
106
- results[ identifier ] = self.make_response_results( response )
114
+ results[ identifier ] =
115
+ self.make_response_results( response, node['expected_status'] )
107
116
  end
108
117
  hydra.queue( request )
109
118
  end
@@ -116,9 +125,11 @@ module Arborist::Monitor::Webservice
116
125
 
117
126
  ### Return a request object built to test the specified webservice +node+.
118
127
  def request_for_node( node_data )
128
+ http_version = convert_http_version( node_data['http_version'] || DEFAULT_HTTP_VERSION )
129
+
119
130
  options = {
120
131
  method: node_data['http_method'] || DEFAULT_HTTP_METHOD,
121
- http_version: node_data['http_version'] || DEFAULT_HTTP_VERSION,
132
+ http_version: http_version,
122
133
  headers: self.make_headers_hash( node_data ),
123
134
  body: node_data['body'],
124
135
  timeout: self.timeout,
@@ -129,6 +140,7 @@ module Arborist::Monitor::Webservice
129
140
  options.merge!( ssl_opts )
130
141
  end
131
142
 
143
+ self.log.debug "Node options for %p are: %p" % [ node_data['uri'], options ]
132
144
  return Typhoeus::Request.new( node_data['uri'], options )
133
145
  end
134
146
 
@@ -137,10 +149,15 @@ module Arborist::Monitor::Webservice
137
149
  def make_ssl_options( uri, node_data )
138
150
  return nil unless uri.start_with?( 'https:' )
139
151
 
140
- ssl_attributes = SSL_ATTRIBUTES.each_with_object({}) do |(key, ssl_key), opts|
141
- opts[ ssl_key ] = node_data[ key.to_s ] if node_data.key?( key.to_s )
152
+ self.log.debug "Extracting valid SSL options from the node's config: %p" %
153
+ [ node_data['config'] ]
154
+ ssl_attributes = SSL_ATTRIBUTES.each_with_object({}) do |(key, desc), opts|
155
+ opts[ key ] = node_data[ 'config' ][ key.to_s ] if
156
+ node_data['config']&.key?( key.to_s )
142
157
  end
143
158
 
159
+ ssl_attributes[ :ssl_verifypeer ] ||= Arborist::Monitor::Webservice.ssl_verifypeer
160
+
144
161
  return ssl_attributes
145
162
  end
146
163
 
@@ -167,17 +184,18 @@ module Arborist::Monitor::Webservice
167
184
 
168
185
 
169
186
  ### Return a Hash of results appropriate for the specified +response+.
170
- def make_response_results( response )
171
- if response.success?
187
+ def make_response_results( response, expected_status=200 )
188
+ if response.code == expected_status
172
189
  return { webservice: self.success_results(response) }
173
190
  elsif response.timed_out?
174
191
  self.log.error "Request timed out."
175
192
  return { error: 'Request timed out.' }
176
193
  elsif response.code == 0
177
- self.log.error "Non-HTTP response: %s." % [ response.return_code ]
178
- return { error: response.return_code }
194
+ self.log.error( response.return_message )
195
+ return { error: response.return_message }
179
196
  else
180
- self.log.error "Got a %03d %s response." % [ response.code, response.status_message ]
197
+ self.log.error "Got an unexpected %03d %s response; expected %03d." %
198
+ [ response.code, response.status_message, expected_status ]
181
199
  return {
182
200
  error: "%03d %s" % [ response.code, response.status_message ]
183
201
  }
@@ -189,6 +207,7 @@ module Arborist::Monitor::Webservice
189
207
  ### responses.
190
208
  def success_results( response )
191
209
  return {
210
+ http_version: response.http_version,
192
211
  status: response.code,
193
212
  status_message: response.status_message,
194
213
  headers: response.headers_hash,
@@ -203,11 +222,31 @@ module Arborist::Monitor::Webservice
203
222
  }
204
223
  end
205
224
 
206
- end # class HTML
225
+
226
+ #######
227
+ private
228
+ #######
229
+
230
+ ### Convert a version string like `1.1` into the Symbol Typhoeus/Ethon expect
231
+ ### (e.g., `:httpv1_1`)
232
+ def convert_http_version( version_string )
233
+ return case version_string
234
+ when '1.0'
235
+ :httpv1_0
236
+ when '1.1'
237
+ :httpv1_1
238
+ when '2.0'
239
+ :httpv2_0
240
+ else
241
+ version_string.to_sym
242
+ end
243
+ end
244
+
245
+ end # class HTTP
207
246
 
208
247
 
209
248
  # Arborist REST webservice monitor logic
210
- class REST < Arborist::Monitor::Webservice::HTML
249
+ class REST < Arborist::Monitor::Webservice::HTTP
211
250
  end # class REST
212
251
 
213
252
  end # class Arborist::Monitor::Webservice
@@ -25,14 +25,11 @@ class Arborist::Node::Webservice < Arborist::Node::Service
25
25
 
26
26
  ### Create a new Webservice node.
27
27
  def initialize( identifier, host, uri, attributes={}, &block )
28
- @uri = uri
29
- uri_obj = URI( uri )
30
-
31
- attributes[:app_protocol] ||= uri_obj.scheme
32
- attributes[:port] ||= uri_obj.port
28
+ attributes[:uri] = URI( uri )
33
29
  attributes[:protocol] = 'tcp'
34
30
  attributes[:app_protocol] = 'http'
35
31
  attributes[:http_method] ||= DEFAULT_HTTP_METHOD
32
+ attributes[:http_version] ||= DEFAULT_HTTP_VERSION
36
33
  attributes[:http_headers] ||= {}
37
34
  attributes[:expected_status] ||= DEFAULT_EXPECTED_STATUS
38
35
  attributes[:body] ||= ''
@@ -47,14 +44,14 @@ class Arborist::Node::Webservice < Arborist::Node::Service
47
44
  public
48
45
  ######
49
46
 
50
- ##
51
- # The URI of an endpoint that can be used to monitor the webservice
52
- dsl_accessor :uri
53
-
54
47
  ##
55
48
  # The http_method used by the service
56
49
  dsl_accessor :http_method
57
50
 
51
+ ##
52
+ # The http version used by the service
53
+ dsl_accessor :http_version
54
+
58
55
  ##
59
56
  # The expected_status used by the service
60
57
  dsl_accessor :expected_status
@@ -73,6 +70,20 @@ class Arborist::Node::Webservice < Arborist::Node::Service
73
70
  end
74
71
 
75
72
 
73
+ ### Get/set the URI of the service.
74
+ def uri( new_uri=nil )
75
+ if new_uri
76
+ @uri = URI( new_uri )
77
+ @uri.host ||= self.addresses.first.to_s
78
+
79
+ self.app_protocol( @uri.scheme )
80
+ self.port( @uri.port )
81
+ end
82
+
83
+ return @uri.to_s
84
+ end
85
+
86
+
76
87
  ### Set node +attributes+ from a Hash.
77
88
  def modify( attributes )
78
89
  attributes = stringify_keys( attributes )
@@ -81,6 +92,7 @@ class Arborist::Node::Webservice < Arborist::Node::Service
81
92
 
82
93
  self.uri( attributes['uri'] )
83
94
  self.http_method( attributes['http_method'] )
95
+ self.http_version( attributes['http_version'] )
84
96
  self.expected_status( attributes['expected_status'] )
85
97
  self.body( attributes['body'] )
86
98
  self.body_mimetype( attributes['body_mimetype'] )
@@ -95,6 +107,8 @@ class Arborist::Node::Webservice < Arborist::Node::Service
95
107
  URI( self.uri ) == URI( val )
96
108
  when 'http_method'
97
109
  self.http_method == val
110
+ when 'http_version'
111
+ self.http_version == val
98
112
  when 'expected_status'
99
113
  self.expected_status == val
100
114
  when 'body'
@@ -122,10 +136,11 @@ class Arborist::Node::Webservice < Arborist::Node::Service
122
136
 
123
137
  ### Return service-node-specific information for #inspect.
124
138
  def node_description
125
- desc = "%s %s %s/1.1" % [
139
+ desc = "%s %s %s/%s" % [
126
140
  self.http_method,
127
141
  self.uri,
128
142
  self.app_protocol.upcase,
143
+ self.http_version,
129
144
  ]
130
145
 
131
146
  if body && !body.empty?
@@ -0,0 +1,76 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'arborist/webservice' unless defined?( Arborist::Webservice )
5
+
6
+
7
+ module Arborist::Webservice::Constants
8
+
9
+ # The default HTTP verb to use for monitoring requests
10
+ DEFAULT_HTTP_METHOD = 'HEAD'.freeze
11
+
12
+ # The default HTTP status code to expect from responses
13
+ DEFAULT_EXPECTED_STATUS = 200
14
+
15
+ # The default Content-type to use for requests with a body
16
+ DEFAULT_BODY_MIMETYPE = 'text/plain'.freeze
17
+
18
+ # The version of HTTP to use in the request line
19
+ DEFAULT_HTTP_VERSION = '2.0'
20
+
21
+ # The headers to include with the request
22
+ DEFAULT_HTTP_HEADERS = {
23
+ 'Connection' => 'close',
24
+ 'Accept' => '*/*',
25
+ 'User-Agent' => "Arborist-WebService/%s" % [ Arborist::Webservice::VERSION ],
26
+ }.freeze
27
+
28
+ # The SSL attributes that are settable
29
+ SSL_ATTRIBUTES = {
30
+ sslcert: "Client cert.",
31
+ sslcerttype: "Client cert type.",
32
+ sslkey: "Client key.",
33
+ sslkeytype: "Client key type.",
34
+ keypasswd: "Client key password.",
35
+ ssl_enable_alpn: "Enable use of ALPN.",
36
+ ssl_enable_npn: "Enable use of NPN.",
37
+ sslengine: "Use identifier with SSL engine.",
38
+ sslengine_default: "Default SSL engine.",
39
+ ssl_falsestart: "Enable TLS False Start.",
40
+ sslversion: "SSL version to use.",
41
+ ssl_verifyhost: "Verify the host name in the SSL certificate.",
42
+ ssl_verifypeer: "Verify the SSL certificate.",
43
+ ssl_verifystatus: "Verify the SSL certificate's status.",
44
+ cainfo: "CA cert bundle.",
45
+ issuercert: "Issuer certificate.",
46
+ capath: "Path to CA cert bundle.",
47
+ crlfile: "Certificate Revocation List.",
48
+ certinfo: "Extract certificate info.",
49
+ pinnedpublickey: "Set pinned SSL public key .",
50
+ random_file: "Provide source for entropy random data.",
51
+ egdsocket: "Identify EGD socket for entropy.",
52
+ ssl_cipher_list: "Ciphers to use.",
53
+ tls13_ciphers: "TLS 1.3 cipher suites to use.",
54
+ ssl_sessionid_cache: "Disable SSL session-id cache.",
55
+ ssl_options: "Control SSL behavior.",
56
+ krblevel: "Kerberos security level.",
57
+ gssapi_delegation: "Disable GSS-API delegation.",
58
+ proxy_sslcert: "Proxy client cert.",
59
+ proxy_sslcerttype: "Proxy client cert type.",
60
+ proxy_sslkey: "Proxy client key.",
61
+ proxy_sslkeytype: "Proxy client key type.",
62
+ proxy_keypasswd: "Proxy client key password.",
63
+ proxy_sslversion: "Proxy SSL version to use.",
64
+ proxy_ssl_verifyhost: "Verify the host name in the proxy SSL certificate.",
65
+ proxy_ssl_verifypeer: "Verify the proxy SSL certificate.",
66
+ proxy_cainfo: "Proxy CA cert bundle.",
67
+ proxy_capath: "Path to proxy CA cert bundle.",
68
+ proxy_crlfile: "Proxy Certificate Revocation List.",
69
+ proxy_pinnedpublickey: "Set the proxy's pinned SSL public key.",
70
+ proxy_ssl_cipher_list: "Proxy ciphers to use.",
71
+ proxy_tls13_ciphers: "Proxy TLS 1.3 cipher suites to use.",
72
+ proxy_ssl_options: "Control proxy SSL behavior.",
73
+ }.freeze
74
+
75
+
76
+ end # module Arborist::Webservice::Constants
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../../spec_helper'
4
+
5
+ require 'typhoeus'
6
+ require 'arborist/webservice'
7
+
8
+
9
+ describe Arborist::Monitor::Webservice do
10
+
11
+ using Arborist::TimeRefinements
12
+
13
+ before( :each ) do
14
+ Typhoeus::Expectation.clear
15
+ end
16
+ after( :each ) do
17
+ Typhoeus::Expectation.clear
18
+ end
19
+
20
+
21
+ describe Arborist::Monitor::Webservice::HTTP do
22
+
23
+ let( :monitor ) { described_class.new }
24
+ let( :host_node ) do
25
+ Arborist::Node.create( :host, 'webserver' ) do
26
+ description "Test host node with a few web services"
27
+ address '10.2.18.64'
28
+ tags :testing
29
+ end
30
+ end
31
+
32
+ let( :webservice_node1 ) { host_node.webservice('marketing', 'https://www.acme.com/') }
33
+ let( :webservice_node2 ) { host_node.webservice('store', 'https://store.acme.com/') }
34
+ let( :webservice_node3 ) { host_node.webservice('support', 'https://int.support.acme.com/') }
35
+
36
+ let( :nodes ) {[ webservice_node1, webservice_node2, webservice_node3 ]}
37
+ let( :nodes_hash ) do
38
+ nodes.each_with_object({}) do |node, accum|
39
+ accum[ node.identifier ] = node.fetch_values
40
+ end
41
+ end
42
+
43
+
44
+ it "is created with a default timeout" do
45
+ expect( monitor.timeout ).to be_an( Numeric )
46
+ end
47
+
48
+
49
+ it "can clone itself with a new timeout" do
50
+ new_monitor = monitor.with_timeout( 2.minutes )
51
+ expect( new_monitor ).to_not equal( monitor )
52
+ expect( new_monitor.timeout ).to eq( 2.minutes )
53
+ end
54
+
55
+
56
+ it "runs against a collection of nodes and updates the statuses of each one" do
57
+ Typhoeus.stub( /acme/i ).and_return do |req|
58
+ Typhoeus::Response.new( code: 200, body: "OK" )
59
+ end
60
+
61
+ result = monitor.run( nodes_hash )
62
+
63
+ expect( result ).to be_a( Hash )
64
+ expect( result.keys ).to contain_exactly( *nodes.map(&:identifier) )
65
+ end
66
+
67
+
68
+ it "sets an error for HTTP error response statuses" do
69
+ Typhoeus.stub( /support\.acme/i ).and_return do |req|
70
+ Typhoeus::Response.new( code: 500, status_message: 'Server Error' )
71
+ end
72
+ Typhoeus.stub( /(www|store)\.acme/i ).and_return do |req|
73
+ Typhoeus::Response.new( code: 200, body: "OK" )
74
+ end
75
+
76
+ result = monitor.run( nodes_hash )
77
+
78
+ expect( result[webservice_node3.identifier] ).to include( error: '500 Server Error' )
79
+ end
80
+
81
+
82
+ it "sets a human-readable error message for lower-layer error response statuses" do
83
+ Typhoeus.stub( /store\.acme/i ).and_return do |req|
84
+ Typhoeus::Response.new( code: 0, return_code: :couldnt_connect )
85
+ end
86
+ Typhoeus.stub( /(www|support)\.acme/i ).and_return do |req|
87
+ Typhoeus::Response.new( code: 200, body: "OK" )
88
+ end
89
+
90
+ result = monitor.run( nodes_hash )
91
+
92
+ expect( result[webservice_node2.identifier] ).to include( error: "Couldn't connect to server" )
93
+ end
94
+
95
+
96
+ it "sets an error for timeouts" do
97
+ Typhoeus.stub( /store\.acme/i ).and_return do |req|
98
+ Typhoeus::Response.new( code: 0, return_code: :operation_timedout )
99
+ end
100
+ Typhoeus.stub( /(www|support)\.acme/i ).and_return do |req|
101
+ Typhoeus::Response.new( code: 200, body: "OK" )
102
+ end
103
+
104
+ result = monitor.run( nodes_hash )
105
+
106
+ expect( result[webservice_node2.identifier] ).to include( error: 'Request timed out.' )
107
+ end
108
+
109
+
110
+ it "doesn't error if HTTP error response status matches the expected status" do
111
+ Typhoeus.stub( /store\.acme/i ).and_return do |req|
112
+ Typhoeus::Response.new( code: 401, status_message: 'Access denied' )
113
+ end
114
+ Typhoeus.stub( /(www|support)\.acme/i ).and_return do |req|
115
+ Typhoeus::Response.new( code: 200, body: "OK" )
116
+ end
117
+
118
+ webservice_node2.expected_status( 401 )
119
+ result = monitor.run( nodes_hash )
120
+
121
+ expect( result[webservice_node2.identifier] ).to_not include( :error )
122
+ end
123
+
124
+
125
+ it "posts with the provided body if one is set" do
126
+ Typhoeus.stub( /support\.acme/i ).and_return do |req|
127
+ expect( req.options[:method] ).to eq( 'POST' )
128
+ expect( req.options[:body] ).to eq( '[1, 2, 3, 4]' )
129
+ expect( req.options[:headers] ).to include( 'Content-type' => 'application/json' )
130
+ Typhoeus::Response.new( code: 201, status_message: 'Object created' )
131
+ end
132
+ Typhoeus.stub( /(www|store)\.acme/i ).and_return do |req|
133
+ Typhoeus::Response.new( code: 200, body: "OK" )
134
+ end
135
+
136
+ webservice_node3.http_method( 'POST' )
137
+ webservice_node3.body( '[1, 2, 3, 4]' )
138
+ webservice_node3.body_mimetype( 'application/json' )
139
+ webservice_node3.expected_status( 201 )
140
+
141
+ result = monitor.run( nodes_hash )
142
+
143
+ expect( result.keys ).to contain_exactly( *nodes.map(&:identifier) )
144
+ end
145
+
146
+
147
+ it "uses valid entries from the node's config as SSL configuration" do
148
+ Typhoeus.stub( /acme/i ).and_return do |req|
149
+ expect( req.options[:ssl_verifypeer] ).to eq( 0 )
150
+ Typhoeus::Response.new( code: 200, body: "OK" )
151
+ end
152
+
153
+ nodes.each do |node|
154
+ node.config( ssl_verifypeer: 0 )
155
+ end
156
+
157
+ result = monitor.run( nodes_hash )
158
+
159
+ expect( result ).to be_a( Hash )
160
+ expect( result.keys ).to contain_exactly( *nodes.map(&:identifier) )
161
+ end
162
+
163
+ end
164
+
165
+
166
+ describe "REST monitor logic"
167
+
168
+ end
169
+
@@ -4,21 +4,71 @@
4
4
  require_relative '../../spec_helper'
5
5
 
6
6
  require 'rspec'
7
+ require 'arborist/node/host'
7
8
  require 'arborist/node/webservice'
8
9
 
9
10
  describe Arborist::Node::Webservice do
10
11
 
11
- it "can match on URI"
12
- it "can match on HTTP method"
13
- it "can match on request body"
14
- it "can match on request body media type"
12
+ let( :host_node ) do
13
+ Arborist::Host 'testhost' do
14
+ address '192.168.66.12'
15
+ address '10.2.12.68'
16
+ hostname 'example.com'
17
+ end
18
+ end
15
19
 
16
- it "includes the URI in the operational attributes"
17
- it "includes the HTTP method in the operational attributes"
18
- it "includes the request body in the operational attributes"
19
- it "includes the request body media type in the operational attributes"
20
+ let( :node ) { host_node.webservice('api', 'https://example.com/api/v1') }
21
+ let( :getonly_node ) do
22
+ host_node.webservice( 'repo-api', 'https://repo.example.com/' ) do
23
+ http_method 'GET'
24
+ end
25
+ end
26
+ let( :http10_node ) do
27
+ host_node.webservice( 'archive-site', 'http://archive.example.com/' ) do
28
+ http_version '1.0'
29
+ end
30
+ end
31
+
32
+
33
+ it "can match on URI" do
34
+ expect( node ).to match_criteria( uri: 'https://example.com/api/v1' )
35
+ expect( node ).to_not match_criteria( uri: 'https://example.com/api/v2' )
36
+ expect( node ).to_not match_criteria( uri: 'https://bitter.com/api/v1' )
37
+ expect( node ).to_not match_criteria( uri: 'http://example.com/api/v1' )
38
+ end
39
+
40
+
41
+ it "can match on HTTP method" do
42
+ expect( node ).to match_criteria( http_method: 'HEAD' )
43
+ expect( node ).to_not match_criteria( http_method: 'GET' )
44
+ expect( getonly_node ).to match_criteria( http_method: 'GET' )
45
+ expect( getonly_node ).to_not match_criteria( http_method: 'HEAD' )
46
+ end
47
+
48
+
49
+ it "can match on HTTP version" do
50
+ expect( node ).to match_criteria( http_version: '2.0' )
51
+ expect( node ).to_not match_criteria( http_version: '1.0' )
52
+ expect( http10_node ).to match_criteria( http_version: '1.0' )
53
+ expect( http10_node ).to_not match_criteria( http_version: '1.1' )
54
+ end
55
+
56
+
57
+ it "includes the URI in the operational attributes" do
58
+ expect( node.operational_values ).to include( uri: node.uri )
59
+ end
60
+
61
+
62
+ it "includes the HTTP method in the operational attributes" do
63
+ expect( node.operational_values ).to include( http_method: node.http_method )
64
+ end
65
+
66
+
67
+ it "allows shorthand URI syntax for implicit host" do
68
+ node = host_node.webservice( 'djinn', 'http:///' )
69
+ expect( node.uri ).to eq( 'http://192.168.66.12/' )
70
+ end
20
71
 
21
- it "provides a DSL declaration to disable SSL verification"
22
72
 
23
73
  end
24
74
 
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../spec_helper'
4
+
5
+ require 'arborist/webservice'
6
+
7
+
8
+ describe Arborist::Webservice do
9
+
10
+ it "has a version constant" do
11
+ expect( described_class::VERSION ).to match( /^\d+(\.\d+){2}$/ )
12
+ end
13
+
14
+
15
+ it "can return a version string for itself" do
16
+ expect( described_class.version_string ).
17
+ to match( /Arborist::Webservice v\d+\.\d+\.\d+/ )
18
+ end
19
+
20
+
21
+ it "can return a version string with the build ID" do
22
+ expect( described_class.version_string(include_build: true) ).
23
+ to match( /Arborist::Webservice v\d+\.\d+\.\d+.*\(Revision: \w+\)/ )
24
+ end
25
+
26
+ end
27
+
@@ -6,6 +6,17 @@ require 'simplecov' if ENV['COVERAGE']
6
6
  require 'rspec'
7
7
 
8
8
  require 'loggability/spechelpers'
9
+ require 'arborist'
10
+ require 'arborist/mixins'
11
+ require 'arborist/webservice'
12
+
13
+
14
+ RSpec::Matchers.define( :match_criteria ) do |criteria|
15
+ match do |node|
16
+ criteria = Arborist::HashUtilities.stringify_keys( criteria )
17
+ node.matches?( criteria )
18
+ end
19
+ end
9
20
 
10
21
 
11
22
  ### Mock with RSpec
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arborist-webservice
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre20180815100446
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -35,7 +35,7 @@ cert_chain:
35
35
  X0qdrKi+2aZZ0NGuFj9AItBsVmAvkBGIpX4TEKQp5haEbPpmaqO5nIIhV26PXmyT
36
36
  OMKv6pWsoS81vw5KAGBmfX8nht/Py90DQrbRvakATGI=
37
37
  -----END CERTIFICATE-----
38
- date: 2018-08-15 00:00:00.000000000 Z
38
+ date: 2018-08-31 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: arborist
@@ -43,28 +43,28 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0'
46
+ version: '0.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '0.2'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: loggability
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0.11'
60
+ version: '0.14'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0.11'
67
+ version: '0.14'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: typhoeus
70
70
  requirement: !ruby/object:Gem::Requirement
@@ -141,14 +141,14 @@ dependencies:
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '0.1'
144
+ version: '0.4'
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '0.1'
151
+ version: '0.4'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: rdoc
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -202,7 +202,10 @@ files:
202
202
  - lib/arborist/monitor/webservice.rb
203
203
  - lib/arborist/node/webservice.rb
204
204
  - lib/arborist/webservice.rb
205
+ - lib/arborist/webservice/constants.rb
206
+ - spec/arborist/monitor/webservice_spec.rb
205
207
  - spec/arborist/node/webservice_spec.rb
208
+ - spec/arborist/webservice_spec.rb
206
209
  - spec/spec_helper.rb
207
210
  homepage: http://deveiate.org/projects/arborist-webservice
208
211
  licenses:
@@ -221,9 +224,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
221
224
  version: '0'
222
225
  required_rubygems_version: !ruby/object:Gem::Requirement
223
226
  requirements:
224
- - - ">"
227
+ - - ">="
225
228
  - !ruby/object:Gem::Version
226
- version: 1.3.1
229
+ version: '0'
227
230
  requirements: []
228
231
  rubyforge_project:
229
232
  rubygems_version: 2.7.6
Binary file