train-rest 0.2.0 → 0.3.2

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: 4b0cc26cff4431701e6fba113884d8c06a943c16cb231e8a564c464e7ba01cf2
4
- data.tar.gz: 78aa236a0c1b8a92480b096e9a40b9c3993be5dbafef907a01144cf630e4267f
3
+ metadata.gz: 45c7cbd2b28a41c2eba5d219545d4ff7e0bfbaf6305f239630352ce463bf8424
4
+ data.tar.gz: 6e5de06f898f95a2a2c519ac45bae42c797e39840e2aec0c80bb6204d5e69591
5
5
  SHA512:
6
- metadata.gz: cb7767fe6dbc98466d9f8450a75f6849d21a8876f8672177db891a91edcdf07a075ab6f59ae98ae24759f827b87ce13ecaaa63934d94d44a8e469716c3e04116
7
- data.tar.gz: 5f76c1a724b6b2c453f30240d71cd5717c818b722c0df527664980f94a32802492cfa267bab70bf105a37370e70dd61f0f28783980a2f584f7e9e9797298dce6
6
+ metadata.gz: 48c46e55522807433595d89e5bf414a3d487c9167b7f8fd365a8a64645789fd533fc614a835b319f8d8e6590d907b01c1fbf864ea80fc735d333d2961c065ddf
7
+ data.tar.gz: 9e24f8c14aa8000541aade240e46d0aaaac67a70a337672f821f9760336da98f482af80337e963ef64c218637f4ed36b059744c8dcc1a2d21cd08d73b5e5154d
data/README.md CHANGED
@@ -20,7 +20,7 @@ rake install:local
20
20
  | Option | Explanation | Default |
21
21
  | -------------------- | --------------------------------------- | ----------- |
22
22
  | `endpoint` | Endpoint of the REST API | _required_ |
23
- | `validate_ssl` | Check certificate and chain | true |
23
+ | `verify_ssl` | Check certificate and chain | true |
24
24
  | `auth_type` | Authentication type | `anonymous` |
25
25
  | `debug_rest` | Enable debugging of HTTP traffic | false |
26
26
  | `logger` | Alternative logging class | |
@@ -60,6 +60,9 @@ The Redfish standard is defined in <http://www.dmtf.org/standards/redfish> and
60
60
  this handler does initial login, reuses the received session and logs out when
61
61
  closing the transport cleanly.
62
62
 
63
+ Known vendors which implement RedFish based management for their systems include
64
+ HPE, Dell, IBM, SuperMicro, Lenovo, Huawei and others.
65
+
63
66
  ## Debugging and use in Chef
64
67
 
65
68
  You can activate debugging by setting the `debug_rest` flag to `true'. Please
@@ -77,6 +80,46 @@ train = Train.create('rest', {
77
80
  })
78
81
  ```
79
82
 
83
+ ## Request Methods
84
+
85
+ This transport does not implement the `run_command` method, as there is no
86
+ line-based protocol to execute commands against. Instead, it implements its own
87
+ custom methods which suit REST interfaces. Trying to call this method will
88
+ throw an Exception.
89
+
90
+ ### Generic Request
91
+
92
+ The `request` methods allows to send free-form requests against any defined or
93
+ custom methods.
94
+
95
+ `request(path, method = :get, request_parameters: {}, data: nil, headers: {},
96
+ json_processing: true)`
97
+
98
+ - `path`: The path to request, which will be appended to the `endpoint`
99
+ - `method`: The HTTP method in Ruby Symbol syntax
100
+ - `request_parameters`: A hash of parameters to the `rest-client` request
101
+ method for additional settings
102
+ - `data`: Data for actions like `:post` or `:put`. Not all methods accept
103
+ a data body.
104
+ - `headers`: Additional headers for the request
105
+ - `json_processing`: If the response is a JSON and you want to receive a
106
+ processed Hash/Array instead of text
107
+
108
+ For `request_parameters` and `headers`, there is data mixed in to add
109
+ authenticator responses, JSON processing etc. Please check the
110
+ implementation in `connection.rb` for details.
111
+
112
+ ### Convenience Methods
113
+
114
+ Simplified wrappers are generated for the most common request types:
115
+
116
+ - `delete(path, request_parameters: {}, headers: {}, json_processing: true)`
117
+ - `head(path, request_parameters: {}, headers: {}, json_processing: true)`
118
+ - `get(path, request_parameters: {}, headers: {}, json_processing: true)`
119
+ - `post(path, request_parameters: {}, data: nil, headers: {}, json_processing: true)`
120
+ - `put(path, request_parameters: {}, data: nil, headers: {}, json_processing: true)`
121
+ - `patch(path, request_parameters: {}, data: nil, headers: {}, json_processing: true)`
122
+
80
123
  ## Example use
81
124
 
82
125
  ```ruby
@@ -119,15 +162,21 @@ conn = train.connection
119
162
  conn.close
120
163
  ```
121
164
 
122
- Example for logging into a RedFish based system:
165
+ Example for logging into a RedFish based system. Please note that the RedFish
166
+ authentication handler will append `redfish/v1` to the endpoint automatically,
167
+ if it is not present.
168
+
169
+ Due to this, you can use RedFish systems either with a base URL like in the
170
+ example below or with a full one. Your own code needs to match the style
171
+ you choose.
123
172
 
124
173
  ```ruby
125
174
  require 'train-rest'
126
175
 
127
176
  # This will immediately do a login and add headers
128
177
  train = Train.create('rest', {
129
- endpoint: 'https://api.example.com/v1/',
130
- validate_ssl: false,
178
+ endpoint: 'https://10.20.30.40',
179
+ verify_ssl: false,
131
180
 
132
181
  auth_type: :redfish,
133
182
  username: 'iloadmin',
@@ -170,5 +219,28 @@ conn.close
170
219
  1. Run against the defiend targets via Chef Target Mode:
171
220
 
172
221
  ```shell
173
- chef-client --local-mode --target 10.0.0.1 --runlist 'recipe[my-cookbook:setup]'
222
+ chef-client --local-mode --target 10.0.0.1 --runlist 'recipe[my-cookbook::setup]'
174
223
  ```
224
+
225
+ ## Use with Prerecorded API responses
226
+
227
+ For testing during and after development, not all APIs can be used to verify your solution against.
228
+ The VCR gem offers the possibility to hook into web requests and intercept them to play back canned
229
+ responses.
230
+
231
+ Please read the documentation of the VCR gem on how to record your API and the concepts like
232
+ "cassettes", "libraries" and matchers.
233
+
234
+ The following options are available in train-rest for this:
235
+
236
+ | Option | Explanation | Default |
237
+ | -------------------- | --------------------------------------- | ------------ |
238
+ | `vcr_cassette` | Name of the response file | nil |
239
+ | `vcr_library` | Directory to search responses in | `vcr` |
240
+ | `vcr_match_on` | Elements to match request by | `method uri` |
241
+ | `vcr_record` | Recording mode | `none` |
242
+ | `vcr_hook_into` | Base library for intercepting | `webmock` |
243
+
244
+ VCR will only be required as a Gem and activated, if you supply a cassette name.
245
+
246
+ You can use all these settings in your Chef Target Mode `credentials` file as well.
@@ -1,4 +1,4 @@
1
- require_relative "../auth_handler.rb"
1
+ require_relative "../auth_handler"
2
2
 
3
3
  module TrainPlugins
4
4
  module Rest
@@ -1,4 +1,6 @@
1
- require_relative "../auth_handler.rb"
1
+ require "base64" unless defined?(Base64)
2
+
3
+ require_relative "../auth_handler"
2
4
 
3
5
  module TrainPlugins
4
6
  module Rest
@@ -11,8 +13,9 @@ module TrainPlugins
11
13
 
12
14
  def auth_parameters
13
15
  {
14
- user: options[:username],
15
- password: options[:password],
16
+ headers: {
17
+ "Authorization" => format("Basic %s", Base64.encode64(options[:username] + ":" + options[:password]).chomp),
18
+ },
16
19
  }
17
20
  end
18
21
  end
@@ -1,4 +1,4 @@
1
- require_relative "../auth_handler.rb"
1
+ require_relative "../auth_handler"
2
2
 
3
3
  module TrainPlugins
4
4
  module Rest
@@ -13,7 +13,7 @@ module TrainPlugins
13
13
 
14
14
  def login
15
15
  response = connection.post(
16
- "SessionService/Sessions/",
16
+ login_url,
17
17
  headers: {
18
18
  "Content-Type" => "application/json",
19
19
  "OData-Version" => "4.0",
@@ -24,10 +24,11 @@ module TrainPlugins
24
24
  }
25
25
  )
26
26
 
27
- raise StandardError.new("Authentication with Redfish failed") unless response.code === 201
28
-
29
27
  @session_token = response.headers["x-auth-token"].first
30
28
  @logout_url = response.headers["location"].first
29
+
30
+ rescue ::RestClient::RequestFailed => err
31
+ raise StandardError.new("Authentication with Redfish failed: " + err.message)
31
32
  end
32
33
 
33
34
  def logout
@@ -39,6 +40,15 @@ module TrainPlugins
39
40
 
40
41
  { "X-Auth-Token": @session_token }
41
42
  end
43
+
44
+ private
45
+
46
+ # Prepend the RedFish base, if not a global setting in the connection URL
47
+ def login_url
48
+ return "SessionService/Sessions/" if options[:endpoint].include?("redfish/v1")
49
+
50
+ "redfish/v1/SessionService/Sessions/"
51
+ end
42
52
  end
43
53
  end
44
54
  end
@@ -1,9 +1,9 @@
1
- require "json"
2
- require "ostruct"
3
- require "uri"
1
+ require "json" unless defined?(JSON)
2
+ require "ostruct" unless defined?(OpenStruct)
3
+ require "uri" unless defined?(URI)
4
4
 
5
- require "rest-client"
6
- require "train"
5
+ require "rest-client" unless defined?(RestClient)
6
+ require "train" unless defined?(Train)
7
7
 
8
8
  module TrainPlugins
9
9
  module Rest
@@ -13,9 +13,41 @@ module TrainPlugins
13
13
  def initialize(options)
14
14
  super(options)
15
15
 
16
+ # Plugin was called with an URI only
17
+ options[:endpoint] = options[:target].sub("rest://", "https://") unless options[:endpoint]
18
+
19
+ # Accept string (CLI) and boolean (API) options
20
+ options[:verify_ssl] = options[:verify_ssl].to_s == "false" ? false : true
21
+
22
+ setup_vcr
23
+
16
24
  connect
17
25
  end
18
26
 
27
+ def setup_vcr
28
+ return unless options[:vcr_cassette]
29
+
30
+ require "vcr" unless defined?(VCR)
31
+
32
+ # TODO: Starts from "/" :(
33
+ library = options[:vcr_library]
34
+ match_on = options[:vcr_match_on].split.map(&:to_sym)
35
+
36
+ VCR.configure do |config|
37
+ config.cassette_library_dir = library
38
+ config.hook_into options[:vcr_hook_into]
39
+ config.default_cassette_options = {
40
+ record: options[:vcr_record].to_sym,
41
+ match_requests_on: match_on,
42
+ }
43
+ end
44
+
45
+ VCR.insert_cassette options[:vcr_cassette]
46
+ rescue LoadError
47
+ logger.fatal "Install the vcr gem to use HTTP(S) playback capability"
48
+ raise
49
+ end
50
+
19
51
  def connect
20
52
  login if auth_handlers.include? auth_type
21
53
  end
@@ -25,17 +57,19 @@ module TrainPlugins
25
57
  end
26
58
 
27
59
  def uri
28
- components = URI.new(options[:endpoint])
60
+ components = URI(options[:endpoint])
29
61
  components.scheme = "rest"
30
62
  components.to_s
31
63
  end
32
64
 
65
+ # Allow overwriting to refine the type of REST API
66
+ attr_writer :detected_os
67
+
33
68
  def inventory
34
- # Faking it for Chef Target Mode only
35
69
  OpenStruct.new({
36
- name: "rest",
70
+ name: @detected_os || "rest",
37
71
  release: TrainPlugins::Rest::VERSION,
38
- family_hierarchy: ["", "api"],
72
+ family_hierarchy: %w{rest api},
39
73
  family: "api",
40
74
  platform: "rest",
41
75
  platform_version: 0,
@@ -53,8 +87,8 @@ module TrainPlugins
53
87
  # User-faced API
54
88
 
55
89
  %i{get post put patch delete head}.each do |method|
56
- define_method(method) do |path, *parameters|
57
- request(path, method, *parameters)
90
+ define_method(method) do |path, **keywords|
91
+ request(path, method, **keywords)
58
92
  end
59
93
  end
60
94
 
@@ -65,8 +99,9 @@ module TrainPlugins
65
99
  parameters[:url] = full_url(path)
66
100
 
67
101
  if json_processing
102
+ parameters[:headers]["Accept"] = "application/json"
68
103
  parameters[:headers]["Content-Type"] = "application/json"
69
- parameters[:payload] = JSON.generate(data)
104
+ parameters[:payload] = JSON.generate(data) unless data.nil?
70
105
  else
71
106
  parameters[:payload] = data
72
107
  end
@@ -139,11 +174,15 @@ module TrainPlugins
139
174
  end
140
175
 
141
176
  def login
177
+ logger.info format("REST Login via %s authentication handler", auth_type.to_s) unless %i{anonymous basic}.include? auth_type
178
+
142
179
  auth_handler.options = options
143
180
  auth_handler.login
144
181
  end
145
182
 
146
183
  def logout
184
+ logger.info format("REST Logout via %s authentication handler", auth_type.to_s) unless %i{anonymous basic}.include? auth_type
185
+
147
186
  auth_handler.logout
148
187
  end
149
188
  end
@@ -1,3 +1,5 @@
1
+ require "rubygems" unless defined?(Gem)
2
+
1
3
  require "train-rest/connection"
2
4
 
3
5
  module TrainPlugins
@@ -8,7 +10,7 @@ module TrainPlugins
8
10
  option :endpoint, required: true
9
11
  option :verify_ssl, default: true
10
12
  option :proxy, default: nil
11
- option :headers, default: nil
13
+ option :headers, default: {}
12
14
  option :timeout, default: 120
13
15
 
14
16
  option :auth_type, default: :anonymous
@@ -16,9 +18,32 @@ module TrainPlugins
16
18
  option :password, default: nil
17
19
  option :debug_rest, default: false
18
20
 
21
+ option :vcr_cassette, default: nil
22
+ option :vcr_library, default: "vcr"
23
+ option :vcr_match_on, default: "method uri"
24
+ option :vcr_record, default: "none"
25
+ option :vcr_hook_into, default: "webmock"
26
+
19
27
  def connection(_instance_opts = nil)
28
+ dependency_checks
29
+
20
30
  @connection ||= TrainPlugins::Rest::Connection.new(@options)
21
31
  end
32
+
33
+ private
34
+
35
+ def dependency_checks
36
+ return unless @options[:vcr_cassette]
37
+
38
+ raise Gem::LoadError.new("Install VCR Gem for API playback capability") unless gem_installed?("vcr")
39
+
40
+ stubber = @options[:vcr_hook_into]
41
+ raise Gem::LoadError.new("Install #{stubber} Gem for API playback capability") unless gem_installed?(stubber)
42
+ end
43
+
44
+ def gem_installed?(name)
45
+ Gem::Specification.find_all_by_name(name).any?
46
+ end
22
47
  end
23
48
  end
24
49
  end
@@ -1,5 +1,5 @@
1
1
  module TrainPlugins
2
2
  module Rest
3
- VERSION = "0.2.0".freeze
3
+ VERSION = "0.3.2".freeze
4
4
  end
5
5
  end
data/train-rest.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "train-rest/version"
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Heinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-12 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train