vsphere-automation-runtime 0.3.0 → 0.4.0
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 +4 -4
- data/Gemfile.lock +6 -12
- data/README.md +1 -1
- data/lib/vsphere-automation-runtime/api_client.rb +154 -291
- data/lib/vsphere-automation-runtime/version.rb +1 -1
- data/pkg/vsphere-automation-runtime-0.3.0.gem +0 -0
- data/pkg/vsphere-automation-runtime-0.4.0.gem +0 -0
- data/spec/api_client_spec.rb +178 -164
- data/spec/spec_helper.rb +3 -0
- data/vsphere-automation-runtime.gemspec +0 -2
- metadata +4 -18
- data/pkg/vsphere-automation-runtime-0.2.1.gem +0 -0
- data/pkg/vsphere-automation-runtime-0.2.2.gem +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e3ced8b72983d106a8c17f4cdb4739deb2528a39e9401df2f1f6b77947ec305
|
4
|
+
data.tar.gz: ad42fda3b57f5d50096c843bab5bb2a377098cee166d272cdeee5f52c440778e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa8fbb24d7d5d79ee0296782742238e3dac960cf8c489f62805c026ef81816f003d5ce3b87d7e5c32b97c4de7b43cd3f8e7c52cd7114b92d42272920c39a6cff
|
7
|
+
data.tar.gz: dbd31185017068890cf6c3379a6b747a74be62be85fffec7aa5c593c5a020c717cdc1b12a56c79310427cd5574721e7ff771aeabfc1ce744aed2726fd406ba8f
|
data/Gemfile.lock
CHANGED
@@ -1,32 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
vsphere-automation-runtime (0.
|
5
|
-
typhoeus (~> 1.3)
|
4
|
+
vsphere-automation-runtime (0.4.0)
|
6
5
|
|
7
6
|
GEM
|
8
7
|
remote: https://rubygems.org/
|
9
8
|
specs:
|
10
|
-
addressable (2.
|
11
|
-
public_suffix (>= 2.0.2, <
|
9
|
+
addressable (2.7.0)
|
10
|
+
public_suffix (>= 2.0.2, < 5.0)
|
12
11
|
ast (2.4.0)
|
13
12
|
coderay (1.1.2)
|
14
13
|
crack (0.4.3)
|
15
14
|
safe_yaml (~> 1.0.0)
|
16
15
|
diff-lcs (1.3)
|
17
|
-
ethon (0.12.0)
|
18
|
-
ffi (>= 1.3.0)
|
19
|
-
ffi (1.11.1)
|
20
16
|
hashdiff (1.0.0)
|
21
17
|
jaro_winkler (1.5.3)
|
22
18
|
method_source (0.9.2)
|
23
19
|
parallel (1.17.0)
|
24
|
-
parser (2.6.
|
20
|
+
parser (2.6.4.0)
|
25
21
|
ast (~> 2.4.0)
|
26
22
|
pry (0.12.2)
|
27
23
|
coderay (~> 1.1.0)
|
28
24
|
method_source (~> 0.9.0)
|
29
|
-
public_suffix (
|
25
|
+
public_suffix (4.0.1)
|
30
26
|
rainbow (3.0.0)
|
31
27
|
rake (12.3.3)
|
32
28
|
rspec (3.8.0)
|
@@ -51,11 +47,9 @@ GEM
|
|
51
47
|
unicode-display_width (>= 1.4.0, < 1.7)
|
52
48
|
ruby-progressbar (1.10.1)
|
53
49
|
safe_yaml (1.0.5)
|
54
|
-
typhoeus (1.3.1)
|
55
|
-
ethon (>= 0.9.0)
|
56
50
|
unicode-display_width (1.6.0)
|
57
51
|
vcr (5.0.0)
|
58
|
-
webmock (3.
|
52
|
+
webmock (3.7.2)
|
59
53
|
addressable (>= 2.3.6)
|
60
54
|
crack (>= 0.3.2)
|
61
55
|
hashdiff (>= 0.4.0, < 2.0.0)
|
data/README.md
CHANGED
@@ -1,184 +1,188 @@
|
|
1
|
-
|
2
|
-
# Copyright (c) 2018-2019 VMware, Inc. All Rights Reserved.
|
3
|
-
# SPDX-License-Identifier: MIT
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
# DO NOT MODIFY. THIS CODE IS GENERATED. CHANGES WILL BE OVERWRITTEN.
|
6
|
-
|
7
|
-
# runtime - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
8
|
-
|
9
|
-
=end
|
10
|
-
|
11
|
-
require 'date'
|
12
3
|
require 'json'
|
13
4
|
require 'logger'
|
14
|
-
require '
|
15
|
-
require '
|
5
|
+
require 'net/http'
|
6
|
+
require 'openssl'
|
16
7
|
require 'uri'
|
8
|
+
require 'vsphere-automation-runtime/configuration'
|
17
9
|
|
18
10
|
module VSphereAutomation
|
11
|
+
# The client responsible for communicating with the API.
|
19
12
|
class ApiClient
|
20
13
|
# The Configuration object holding settings to be used in the API client.
|
21
14
|
attr_accessor :config
|
22
15
|
|
23
|
-
# Defines the headers to be used in HTTP requests of all API calls by
|
16
|
+
# Defines the headers to be used in HTTP requests of all API calls by
|
17
|
+
# default.
|
24
18
|
#
|
25
19
|
# @return [Hash]
|
26
|
-
|
20
|
+
attr_reader :default_headers
|
27
21
|
|
28
|
-
#
|
29
|
-
#
|
22
|
+
# Creates a new instance
|
23
|
+
#
|
24
|
+
# @param config [Configuration] configuration object with values to use
|
30
25
|
def initialize(config = Configuration.default)
|
31
26
|
@config = config
|
32
|
-
@
|
33
|
-
@
|
34
|
-
|
35
|
-
|
36
|
-
}
|
27
|
+
@http = create_http
|
28
|
+
@user_agent = default_user_agent
|
29
|
+
@default_headers = { 'Content-Type' => 'application/json',
|
30
|
+
'User-Agent' => @user_agent }
|
37
31
|
end
|
38
32
|
|
33
|
+
# Retrieves an instance of the object in it's default state
|
34
|
+
#
|
35
|
+
# @return [ApiClient] an instance of the object in it's default state
|
39
36
|
def self.default
|
40
|
-
|
37
|
+
DEFAULT
|
41
38
|
end
|
42
39
|
|
43
|
-
#
|
40
|
+
# Build the collection of parameters
|
41
|
+
def build_collection_param(params, format)
|
42
|
+
params
|
43
|
+
end
|
44
|
+
|
45
|
+
# Make a request to an API endpoint with the given options
|
44
46
|
#
|
45
|
-
# @
|
46
|
-
#
|
47
|
+
# @param http_method [Symbol] the HTTP method to be used
|
48
|
+
# @param path [String] the path request will be made to
|
49
|
+
# @param opts [Hash] any additional options needed
|
50
|
+
# @return [Array<(Object, Fixnum, Hash)>] the deserialized body, status
|
51
|
+
# code, and headers.
|
47
52
|
def call_api(http_method, path, opts = {})
|
48
|
-
|
49
|
-
|
53
|
+
query_params = opts.fetch(:query_params, {})
|
54
|
+
header_params = opts.fetch(:header_params, {})
|
55
|
+
form_params = opts.fetch(:form_params, {})
|
56
|
+
add_auth(query_params, header_params, opts.fetch(:auth_names, []))
|
57
|
+
|
58
|
+
uri = build_request_uri(path, query_params)
|
59
|
+
request = Net::HTTP.const_get(http_method.capitalize).new(uri)
|
60
|
+
|
61
|
+
add_form_params(request, form_params)
|
62
|
+
add_header_params(request, header_params)
|
63
|
+
request.body = opts[:body] if opts[:body]
|
64
|
+
request.content_type = request['Content-Type'] if request['Content-Type']
|
50
65
|
|
51
66
|
if @config.debugging
|
52
|
-
@config.logger.debug
|
67
|
+
@config.logger.debug("Request Body:\n#{request.body}\n")
|
53
68
|
end
|
54
69
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
elsif response.code == 0
|
59
|
-
# Errors from libcurl will be made visible here
|
60
|
-
fail ApiError.new(:code => 0,
|
61
|
-
:message => response.return_message)
|
62
|
-
else
|
63
|
-
fail ApiError.new(:code => response.code,
|
64
|
-
:response_headers => response.headers,
|
65
|
-
:response_body => response.body),
|
66
|
-
response.status_message
|
67
|
-
end
|
68
|
-
end
|
70
|
+
response = @http.request(request)
|
71
|
+
@cookie = cookie_from_response(response)
|
72
|
+
api_key_from_response(response)
|
69
73
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
74
|
+
return_type = opts.fetch(:return_type, {}).fetch(response.code, nil)
|
75
|
+
data = deserialize(response, return_type)
|
76
|
+
[data, Integer(response.code), response.each_header.to_h]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Takes an object and returns the object as an HTTP body
|
80
|
+
#
|
81
|
+
# @param object [Object] object to transform
|
82
|
+
# @return [String] object as JSON string
|
83
|
+
def object_to_http_body(object)
|
84
|
+
return object.map { |o| object_to_http_body(o) } if object.is_a?(Array)
|
85
|
+
|
86
|
+
return object unless object.respond_to?(:to_hash)
|
87
|
+
|
88
|
+
object.to_hash.to_json
|
89
|
+
end
|
90
|
+
|
91
|
+
# Select an Accept header to use
|
92
|
+
#
|
93
|
+
# @param types [Array] a list of suggested types
|
94
|
+
# @return [String] the Accept header value
|
95
|
+
def select_header_accept(types)
|
96
|
+
return DEFAULT_MIME_TYPE unless types.is_a?(Array)
|
97
|
+
|
98
|
+
types.find { |t| t.include?('json') } || types.join(', ')
|
79
99
|
end
|
80
100
|
|
81
|
-
#
|
101
|
+
# Select an Content-Type header to use
|
82
102
|
#
|
83
|
-
# @param [
|
84
|
-
# @
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
req_opts = {
|
104
|
-
:method => http_method,
|
105
|
-
:headers => header_params,
|
106
|
-
:params => query_params,
|
107
|
-
:params_encoding => @config.params_encoding,
|
108
|
-
:timeout => @config.timeout,
|
109
|
-
:ssl_verifypeer => @config.verify_ssl,
|
110
|
-
:ssl_verifyhost => _verify_ssl_host,
|
111
|
-
:sslcert => @config.cert_file,
|
112
|
-
:sslkey => @config.key_file,
|
113
|
-
:verbose => @config.debugging
|
114
|
-
}
|
115
|
-
|
116
|
-
# set custom cert, if provided
|
117
|
-
req_opts[:cainfo] = @config.ssl_ca_cert if @config.ssl_ca_cert
|
118
|
-
|
119
|
-
if [:post, :patch, :put, :delete].include?(http_method)
|
120
|
-
req_body = build_request_body(header_params, form_params, opts[:body])
|
121
|
-
req_opts.update :body => req_body
|
122
|
-
if @config.debugging
|
123
|
-
@config.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
|
103
|
+
# @param types [Array] a list of suggested types
|
104
|
+
# @return [String] the Content-Type header value
|
105
|
+
def select_header_content_type(types)
|
106
|
+
return DEFAULT_MIME_TYPE unless types.is_a?(Array)
|
107
|
+
|
108
|
+
types.find { |t| t.include?('json') } || types.first
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def add_auth(query_params, header_params, auth_names)
|
114
|
+
auth_names.map do |name|
|
115
|
+
settings = @config.auth_settings.fetch(name, {})
|
116
|
+
case settings[:in]
|
117
|
+
when 'header'
|
118
|
+
header_params[settings[:key]] = settings[:value]
|
119
|
+
api_key_from_cookie(header_params, settings) unless settings[:value]
|
120
|
+
when 'query'
|
121
|
+
query_params[settings[:key]] = settings[:value]
|
124
122
|
end
|
125
123
|
end
|
124
|
+
end
|
126
125
|
|
127
|
-
|
128
|
-
|
129
|
-
request
|
126
|
+
def add_form_params(request, form_params)
|
127
|
+
request.set_form_data(form_params) unless form_params.empty?
|
130
128
|
end
|
131
129
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# application/json; charset=UTF8
|
136
|
-
# APPLICATION/JSON
|
137
|
-
# */*
|
138
|
-
# @param [String] mime MIME
|
139
|
-
# @return [Boolean] True if the MIME is application/json
|
140
|
-
def json_mime?(mime)
|
141
|
-
(mime == '*/*') || !(mime =~ /Application\/.*json(?!p)(;.*)?/i).nil?
|
130
|
+
def add_header_params(request, headers)
|
131
|
+
header_params = @default_headers.merge(headers, Hash(@cookie))
|
132
|
+
header_params.map { |name, value| request[name] = value }
|
142
133
|
end
|
143
134
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
# @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
|
148
|
-
def deserialize(response, return_type)
|
149
|
-
body = response.body
|
135
|
+
def add_query_params(uri, query_params)
|
136
|
+
uri.query = URI.encode_www_form(query_params)
|
137
|
+
end
|
150
138
|
|
151
|
-
|
152
|
-
|
153
|
-
|
139
|
+
def build_request_uri(path = '', query_params = {})
|
140
|
+
path = "/#{path}".gsub(%r{/+}, '/')
|
141
|
+
uri = URI.parse(@config.base_url + path)
|
142
|
+
add_query_params(uri, query_params)
|
143
|
+
uri
|
144
|
+
end
|
154
145
|
|
155
|
-
|
146
|
+
def create_http
|
147
|
+
uri = build_request_uri
|
148
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
149
|
+
http.use_ssl = @config.scheme == 'https'
|
150
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @config.verify_ssl_host
|
151
|
+
http
|
152
|
+
end
|
156
153
|
|
157
|
-
|
158
|
-
|
154
|
+
# The default user agent
|
155
|
+
#
|
156
|
+
# @return [String] the default user agent
|
157
|
+
def default_user_agent
|
158
|
+
"SDK/#{VSphereAutomation::Runtime::VERSION} "\
|
159
|
+
"Ruby/#{RUBY_VERSION} "\
|
160
|
+
"(#{Gem::Platform.local.os}; "\
|
161
|
+
"#{Gem::Platform.local.version}; "\
|
162
|
+
"#{Gem::Platform.local.cpu})"
|
163
|
+
end
|
159
164
|
|
160
|
-
|
161
|
-
|
165
|
+
# Deserialize the response to the given return type
|
166
|
+
#
|
167
|
+
# @param [Response] response the HTTP response
|
168
|
+
# @param [String] return_type the type to return
|
169
|
+
# @return [Object] the response represented as the return type
|
170
|
+
def deserialize(response, return_type)
|
171
|
+
body = response.body
|
162
172
|
|
163
|
-
|
173
|
+
return nil if body.nil? || body.empty? || return_type.nil?
|
164
174
|
|
165
175
|
begin
|
166
|
-
data = JSON.parse("[#{body}]", :
|
176
|
+
data = JSON.parse("[#{body}]", symbolize_names: true).first
|
167
177
|
rescue JSON::ParserError => e
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
raise e
|
172
|
-
end
|
178
|
+
raise e unless %w[String Date DateTime].include?(return_type)
|
179
|
+
|
180
|
+
data = body
|
173
181
|
end
|
174
182
|
|
175
|
-
convert_to_type
|
183
|
+
convert_to_type(data, return_type)
|
176
184
|
end
|
177
185
|
|
178
|
-
# Convert data to the given return type.
|
179
|
-
# @param [Object] data Data to be converted
|
180
|
-
# @param [String] return_type Return type
|
181
|
-
# @return [Mixed] Data in a particular type
|
182
186
|
def convert_to_type(data, return_type)
|
183
187
|
return nil if data.nil?
|
184
188
|
case return_type
|
@@ -217,174 +221,33 @@ module VSphereAutomation
|
|
217
221
|
end
|
218
222
|
end
|
219
223
|
|
220
|
-
#
|
221
|
-
# from the "Content-Disposition" header if provided, otherwise a random filename.
|
222
|
-
# The response body is written to the file in chunks in order to handle files which
|
223
|
-
# size is larger than maximum Ruby String or even larger than the maximum memory a Ruby
|
224
|
-
# process can use.
|
225
|
-
#
|
226
|
-
# @see Configuration#temp_folder_path
|
227
|
-
def download_file(request)
|
228
|
-
tempfile = nil
|
229
|
-
encoding = nil
|
230
|
-
request.on_headers do |response|
|
231
|
-
content_disposition = response.headers['Content-Disposition']
|
232
|
-
if content_disposition && content_disposition =~ /filename=/i
|
233
|
-
filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
|
234
|
-
prefix = sanitize_filename(filename)
|
235
|
-
else
|
236
|
-
prefix = 'download-'
|
237
|
-
end
|
238
|
-
prefix = prefix + '-' unless prefix.end_with?('-')
|
239
|
-
encoding = response.body.encoding
|
240
|
-
tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
|
241
|
-
@tempfile = tempfile
|
242
|
-
end
|
243
|
-
request.on_body do |chunk|
|
244
|
-
chunk.force_encoding(encoding)
|
245
|
-
tempfile.write(chunk)
|
246
|
-
end
|
247
|
-
request.on_complete do |response|
|
248
|
-
tempfile.close
|
249
|
-
@config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
|
250
|
-
"with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
|
251
|
-
"will be deleted automatically with GC. It's also recommended to delete the temp file "\
|
252
|
-
"explicitly with `tempfile.delete`"
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# Sanitize filename by removing path.
|
257
|
-
# e.g. ../../sun.gif becomes sun.gif
|
258
|
-
#
|
259
|
-
# @param [String] filename the filename to be sanitized
|
260
|
-
# @return [String] the sanitized filename
|
261
|
-
def sanitize_filename(filename)
|
262
|
-
filename.gsub(/.*[\/\\]/, '')
|
263
|
-
end
|
264
|
-
|
265
|
-
def build_request_url(path)
|
266
|
-
# Add leading and trailing slashes to path
|
267
|
-
path = "/#{path}".gsub(/\/+/, '/')
|
268
|
-
URI.encode(@config.base_url + path)
|
269
|
-
end
|
270
|
-
|
271
|
-
# Builds the HTTP request body
|
272
|
-
#
|
273
|
-
# @param [Hash] header_params Header parameters
|
274
|
-
# @param [Hash] form_params Query parameters
|
275
|
-
# @param [Object] body HTTP body (JSON/XML)
|
276
|
-
# @return [String] HTTP body data in the form of string
|
277
|
-
def build_request_body(header_params, form_params, body)
|
278
|
-
# http form
|
279
|
-
if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
|
280
|
-
header_params['Content-Type'] == 'multipart/form-data'
|
281
|
-
data = {}
|
282
|
-
form_params.each do |key, value|
|
283
|
-
case value
|
284
|
-
when ::File, ::Array, nil
|
285
|
-
# let typhoeus handle File, Array and nil parameters
|
286
|
-
data[key] = value
|
287
|
-
else
|
288
|
-
data[key] = value.to_s
|
289
|
-
end
|
290
|
-
end
|
291
|
-
elsif body
|
292
|
-
data = body.is_a?(String) ? body : body.to_json
|
293
|
-
else
|
294
|
-
data = nil
|
295
|
-
end
|
296
|
-
data
|
297
|
-
end
|
298
|
-
|
299
|
-
# Update hearder and query params based on authentication settings.
|
224
|
+
# Create the Cookie header from a response
|
300
225
|
#
|
301
|
-
# @param [
|
302
|
-
# @
|
303
|
-
|
304
|
-
|
305
|
-
Array(auth_names).each do |auth_name|
|
306
|
-
auth_setting = @config.auth_settings[auth_name]
|
307
|
-
next unless auth_setting
|
308
|
-
case auth_setting[:in]
|
309
|
-
when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
|
310
|
-
when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
|
311
|
-
else fail ArgumentError, 'Authentication token must be in `query` of `header`'
|
312
|
-
end
|
313
|
-
end
|
226
|
+
# @param response [Net::HTTPResponse] the response
|
227
|
+
# @return [Hash, nil] the Cookie header
|
228
|
+
def cookie_from_response(response)
|
229
|
+
{ 'Cookie' => response['set-cookie'] } if response['set-cookie']
|
314
230
|
end
|
315
231
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
def user_agent=(user_agent)
|
320
|
-
@user_agent = user_agent
|
321
|
-
@default_headers['User-Agent'] = @user_agent
|
232
|
+
def api_key_from_response(response)
|
233
|
+
key = @config.auth_settings['api_key'][:key]
|
234
|
+
@config.api_key[key] = response[key] if response[key]
|
322
235
|
end
|
323
236
|
|
324
|
-
|
325
|
-
|
326
|
-
# @return [String] the Accept header (e.g. application/json)
|
327
|
-
def select_header_accept(accepts)
|
328
|
-
return nil if accepts.nil? || accepts.empty?
|
329
|
-
# use JSON when present, otherwise use all of the provided
|
330
|
-
json_accept = accepts.find { |s| json_mime?(s) }
|
331
|
-
json_accept || accepts.join(',')
|
332
|
-
end
|
237
|
+
def api_key_from_cookie(headers, auth)
|
238
|
+
return if @cookie.nil?
|
333
239
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
def select_header_content_type(content_types)
|
338
|
-
# use application/json by default
|
339
|
-
return 'application/json' if content_types.nil? || content_types.empty?
|
340
|
-
# use JSON when present, otherwise use the first one
|
341
|
-
json_content_type = content_types.find { |s| json_mime?(s) }
|
342
|
-
json_content_type || content_types.first
|
240
|
+
regex = /(?<key>#{auth[:key]})=(?<value>\w+)/
|
241
|
+
matches = Hash(@cookie)['Cookie'].match(regex)
|
242
|
+
headers[matches[:key]] = matches[:value] if matches
|
343
243
|
end
|
344
244
|
|
345
|
-
#
|
346
|
-
|
347
|
-
# @return [String] JSON string representation of the object
|
348
|
-
def object_to_http_body(model)
|
349
|
-
return model if model.nil? || model.is_a?(String)
|
350
|
-
local_body = nil
|
351
|
-
if model.is_a?(Array)
|
352
|
-
local_body = model.map { |m| object_to_hash(m) }
|
353
|
-
else
|
354
|
-
local_body = object_to_hash(model)
|
355
|
-
end
|
356
|
-
local_body.to_json
|
357
|
-
end
|
245
|
+
# An instance of the object in it's default state
|
246
|
+
DEFAULT = new
|
358
247
|
|
359
|
-
#
|
360
|
-
|
361
|
-
# @return [String] JSON string representation of the object
|
362
|
-
def object_to_hash(obj)
|
363
|
-
if obj.respond_to?(:to_hash)
|
364
|
-
obj.to_hash
|
365
|
-
else
|
366
|
-
obj
|
367
|
-
end
|
368
|
-
end
|
248
|
+
# The default MIME type for Content-Type and Accept headers
|
249
|
+
DEFAULT_MIME_TYPE = 'application/json'
|
369
250
|
|
370
|
-
|
371
|
-
# @param [String] collection_format one of :csv, :ssv, :tsv, :pipes and :multi
|
372
|
-
def build_collection_param(param, collection_format)
|
373
|
-
case collection_format
|
374
|
-
when :csv
|
375
|
-
param.join(',')
|
376
|
-
when :ssv
|
377
|
-
param.join(' ')
|
378
|
-
when :tsv
|
379
|
-
param.join("\t")
|
380
|
-
when :pipes
|
381
|
-
param.join('|')
|
382
|
-
when :multi
|
383
|
-
# return the array directly as typhoeus will handle it as expected
|
384
|
-
param
|
385
|
-
else
|
386
|
-
fail "unknown collection format: #{collection_format.inspect}"
|
387
|
-
end
|
388
|
-
end
|
251
|
+
private_constant :DEFAULT, :DEFAULT_MIME_TYPE
|
389
252
|
end
|
390
253
|
end
|
Binary file
|
Binary file
|
data/spec/api_client_spec.rb
CHANGED
@@ -1,222 +1,236 @@
|
|
1
|
-
# Copyright (c) 2018-2019 VMware, Inc. All Rights Reserved.
|
2
|
-
# SPDX-License-Identifier: MIT
|
3
|
-
|
4
|
-
# DO NOT MODIFY. THIS CODE IS GENERATED. CHANGES WILL BE OVERWRITTEN.
|
5
|
-
|
6
|
-
# runtime - No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
7
|
-
|
8
|
-
|
9
1
|
require 'spec_helper'
|
10
2
|
|
11
3
|
describe VSphereAutomation::ApiClient do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
describe '.default' do
|
5
|
+
it 'returns the same instance every time' do
|
6
|
+
first_instance = VSphereAutomation::ApiClient.default
|
7
|
+
second_instance = VSphereAutomation::ApiClient.default
|
8
|
+
third_instance = VSphereAutomation::ApiClient.default
|
9
|
+
expect(first_instance).to be(second_instance)
|
10
|
+
expect(first_instance).to be(third_instance)
|
11
|
+
end
|
12
|
+
end
|
19
13
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
describe '#build_collection_param' do
|
15
|
+
context 'when called with format :multi' do
|
16
|
+
it 'returns the collection' do
|
17
|
+
params = { foo: 'bar', baz: 'quux' }
|
18
|
+
expect(subject.build_collection_param(params, :multi)).to eq(params)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
describe '#call_api' do
|
24
|
+
let(:host) { 'example.com' }
|
25
|
+
let(:config) do
|
26
|
+
VSphereAutomation::Configuration.new.tap do |c|
|
27
|
+
c.scheme = 'https'
|
28
|
+
c.host = host
|
29
29
|
end
|
30
|
+
end
|
31
|
+
let(:url) { 'https://example.com/rest/test' }
|
32
|
+
subject { VSphereAutomation::ApiClient.new(config) }
|
30
33
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
expect(VSphereAutomation::Configuration.default.base_path).to eq('/v4/dog')
|
35
|
-
end
|
34
|
+
it 'adds headers to request' do
|
35
|
+
headers = { 'foo' => 'bar' }
|
36
|
+
stub_request(:get, url).with(headers: headers)
|
36
37
|
|
37
|
-
|
38
|
-
VSphereAutomation.configure { |c| c.base_path = '/v4/dog' }
|
39
|
-
expect(VSphereAutomation::Configuration.default.base_path).to eq('/v4/dog')
|
40
|
-
end
|
38
|
+
subject.call_api(:GET, '/test', header_params: headers)
|
41
39
|
|
42
|
-
|
43
|
-
VSphereAutomation.configure { |c| c.base_path = nil }
|
44
|
-
expect(VSphereAutomation::Configuration.default.base_path).to eq('')
|
45
|
-
end
|
46
|
-
end
|
40
|
+
expect(a_request(:get, url).with(headers: headers)).to have_been_made
|
47
41
|
end
|
48
|
-
end
|
49
42
|
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
it 'adds query parameters to request' do
|
44
|
+
query_params = { 'foo' => 'bar' }
|
45
|
+
stub_request(:get, url).with(query: query_params)
|
53
46
|
|
54
|
-
|
55
|
-
expect(VSphereAutomation::Configuration.default.params_encoding).to eq(nil)
|
56
|
-
expect(config.params_encoding).to eq(nil)
|
47
|
+
subject.call_api(:GET, '/test', query_params: query_params)
|
57
48
|
|
58
|
-
|
59
|
-
expect(request.options[:params_encoding]).to eq(nil)
|
49
|
+
expect(a_request(:get, url).with(query: query_params)).to have_been_made
|
60
50
|
end
|
61
51
|
|
62
|
-
it '
|
63
|
-
|
64
|
-
|
65
|
-
|
52
|
+
it 'adds form parameters to the request body' do
|
53
|
+
form_params = { 'foo' => 'bar' }
|
54
|
+
body = form_params.to_a.map { |e| e.join('=') }.join('&')
|
55
|
+
stub_request(:get, url).with(body: body)
|
56
|
+
|
57
|
+
subject.call_api(:GET, '/test', form_params: form_params)
|
58
|
+
|
59
|
+
expect(a_request(:get, url).with(body: body)).to have_been_made
|
66
60
|
end
|
67
|
-
end
|
68
61
|
|
69
|
-
|
70
|
-
|
71
|
-
|
62
|
+
it 'uses basic auth information from configuration' do
|
63
|
+
auth_name = 'basic_auth'
|
64
|
+
auth_header = { config.auth_settings[auth_name][:key] =>
|
65
|
+
config.auth_settings[auth_name][:value] }
|
66
|
+
stub_request(:get, url).with(headers: auth_header)
|
72
67
|
|
73
|
-
|
74
|
-
expect(VSphereAutomation::Configuration.default.timeout).to eq(0)
|
75
|
-
expect(config.timeout).to eq(0)
|
68
|
+
subject.call_api(:GET, '/test', auth_names: [auth_name])
|
76
69
|
|
77
|
-
|
78
|
-
|
70
|
+
expect(a_request(:get, url)
|
71
|
+
.with(headers: auth_header)).to have_been_made
|
79
72
|
end
|
80
73
|
|
81
|
-
it '
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
74
|
+
it 'use API key information from configuration' do
|
75
|
+
auth_name = 'api_key'
|
76
|
+
config.api_key[config.auth_settings[auth_name][:key]] = 'foo'
|
77
|
+
auth_header = { config.auth_settings[auth_name][:key] =>
|
78
|
+
config.auth_settings[auth_name][:value] }
|
79
|
+
stub_request(:get, url).with(headers: auth_header)
|
87
80
|
|
88
|
-
|
89
|
-
it "handles Array<Integer>" do
|
90
|
-
api_client = VSphereAutomation::ApiClient.new
|
91
|
-
headers = { 'Content-Type' => 'application/json' }
|
92
|
-
response = double('response', headers: headers, body: '[12, 34]')
|
93
|
-
data = api_client.deserialize(response, 'Array<Integer>')
|
94
|
-
expect(data).to be_instance_of(Array)
|
95
|
-
expect(data).to eq([12, 34])
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'handles Array<Array<Integer>>' do
|
99
|
-
api_client = VSphereAutomation::ApiClient.new
|
100
|
-
headers = { 'Content-Type' => 'application/json' }
|
101
|
-
response = double('response', headers: headers, body: '[[12, 34], [56]]')
|
102
|
-
data = api_client.deserialize(response, 'Array<Array<Integer>>')
|
103
|
-
expect(data).to be_instance_of(Array)
|
104
|
-
expect(data).to eq([[12, 34], [56]])
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'handles Hash<String, String>' do
|
108
|
-
api_client = VSphereAutomation::ApiClient.new
|
109
|
-
headers = { 'Content-Type' => 'application/json' }
|
110
|
-
response = double('response', headers: headers, body: '{"message": "Hello"}')
|
111
|
-
data = api_client.deserialize(response, 'Hash<String, String>')
|
112
|
-
expect(data).to be_instance_of(Hash)
|
113
|
-
expect(data).to eq(:message => 'Hello')
|
114
|
-
end
|
115
|
-
end
|
81
|
+
subject.call_api(:GET, '/test', auth_names: [auth_name])
|
116
82
|
|
117
|
-
|
118
|
-
|
119
|
-
# uncomment below to test object_to_hash for model
|
120
|
-
# api_client = VSphereAutomation::ApiClient.new
|
121
|
-
# _model = VSphereAutomation::ModelName.new
|
122
|
-
# update the model attribute below
|
123
|
-
# _model.id = 1
|
124
|
-
# update the expected value (hash) below
|
125
|
-
# expected = {id: 1, name: '', tags: []}
|
126
|
-
# expect(api_client.object_to_hash(_model)).to eq(expected)
|
83
|
+
expect(a_request(:get, url)
|
84
|
+
.with(headers: auth_header)).to have_been_made
|
127
85
|
end
|
128
|
-
end
|
129
86
|
|
130
|
-
|
131
|
-
|
132
|
-
|
87
|
+
it 'updates api_key from responses with set-cookie header' do
|
88
|
+
key = config.auth_settings['api_key'][:key]
|
89
|
+
value = 'foo'
|
90
|
+
cookie = "#{key}=#{value};Path=/rest;Secure;HttpOnly"
|
91
|
+
set_cookie_header = { 'set-cookie' => cookie }
|
92
|
+
auth_header = { key => value }
|
93
|
+
stub_request(:get, url + '1').to_return(headers: set_cookie_header)
|
94
|
+
stub_request(:get, url + '2').with(headers: auth_header)
|
95
|
+
|
96
|
+
subject.call_api(:GET, '/test1')
|
97
|
+
subject.call_api(:GET, '/test2', auth_names: ['api_key'])
|
133
98
|
|
134
|
-
|
135
|
-
expect(
|
99
|
+
expect(a_request(:get, url + '1')).to have_been_made
|
100
|
+
expect(a_request(:get, url + '2')
|
101
|
+
.with(headers: auth_header)).to have_been_made
|
136
102
|
end
|
137
103
|
|
138
|
-
it '
|
139
|
-
|
104
|
+
it 'updates api_key from responses with api_key header' do
|
105
|
+
key = config.auth_settings['api_key'][:key]
|
106
|
+
value = 'foo'
|
107
|
+
auth_header = { key => value }
|
108
|
+
|
109
|
+
stub_request(:get, url + '1').to_return(headers: auth_header)
|
110
|
+
stub_request(:get, url + '2').with(headers: auth_header)
|
111
|
+
|
112
|
+
subject.call_api(:GET, '/test1')
|
113
|
+
subject.call_api(:GET, '/test2', auth_names: ['api_key'])
|
114
|
+
|
115
|
+
expect(a_request(:get, url + '1')).to have_been_made
|
116
|
+
expect(a_request(:get, url + '2')
|
117
|
+
.with(headers: auth_header)).to have_been_made
|
140
118
|
end
|
141
119
|
|
142
|
-
it '
|
143
|
-
|
120
|
+
it 'adds the body to requests when available' do
|
121
|
+
body = { foo: 'bar' }.to_json
|
122
|
+
stub_request(:post, url).with(body: body)
|
123
|
+
|
124
|
+
subject.call_api(:POST, '/test', body: body)
|
125
|
+
|
126
|
+
expect(a_request(:post, url).with(body: body)).to have_been_made
|
144
127
|
end
|
145
128
|
|
146
|
-
it '
|
147
|
-
|
129
|
+
it 'sets the Content-Type on requests when available' do
|
130
|
+
content_type = { 'Content-Type' => 'application/json' }
|
131
|
+
body = { foo: 'bar' }.to_json
|
132
|
+
|
133
|
+
stub_request(:post, url).with(body: body, headers: content_type)
|
134
|
+
|
135
|
+
subject.call_api(:POST, '/test', body: body, header_params: content_type)
|
136
|
+
|
137
|
+
expect(a_request(:post, url)
|
138
|
+
.with(body: body, headers: content_type)).to have_been_made
|
148
139
|
end
|
140
|
+
end
|
149
141
|
|
150
|
-
|
151
|
-
|
142
|
+
describe '#object_to_http_body' do
|
143
|
+
context 'when given nil' do
|
144
|
+
it 'returns the object as is' do
|
145
|
+
expect(subject.object_to_http_body(nil)).to be_nil
|
146
|
+
end
|
152
147
|
end
|
153
148
|
|
154
|
-
|
155
|
-
|
149
|
+
context 'when given a string' do
|
150
|
+
it 'returns the object as is' do
|
151
|
+
expect(subject.object_to_http_body('asdf')).to eq('asdf')
|
152
|
+
end
|
156
153
|
end
|
157
|
-
end
|
158
154
|
|
159
|
-
|
160
|
-
|
155
|
+
context 'when given an object that responds to `to_hash`' do
|
156
|
+
it 'returns that object as JSON' do
|
157
|
+
obj = OpenStruct.new(foo: 'bar', baz: 'quux')
|
158
|
+
obj.to_hash = obj.to_h
|
159
|
+
json = obj.to_hash.to_json
|
161
160
|
|
162
|
-
|
163
|
-
|
164
|
-
|
161
|
+
expect(subject.object_to_http_body(obj)).to eq(json)
|
162
|
+
end
|
163
|
+
end
|
165
164
|
|
166
|
-
|
167
|
-
|
168
|
-
|
165
|
+
context 'when given an array' do
|
166
|
+
it 'returns a JSON array of objects' do
|
167
|
+
obj = OpenStruct.new(foo: 'bar', baz: 'quux')
|
168
|
+
obj.to_hash = obj.to_h
|
169
|
+
json = obj.to_hash.to_json
|
169
170
|
|
170
|
-
|
171
|
-
|
172
|
-
expect(api_client.json_mime?('application/jsonp')).to eq false
|
171
|
+
expect(subject.object_to_http_body([obj])).to eq([json])
|
172
|
+
end
|
173
173
|
end
|
174
174
|
end
|
175
175
|
|
176
176
|
describe '#select_header_accept' do
|
177
|
-
|
177
|
+
context 'when given anything other than an array' do
|
178
|
+
it 'returns application/json as a default' do
|
179
|
+
expect(subject.select_header_accept(nil)).to eq('application/json')
|
180
|
+
expect(subject.select_header_accept('')).to eq('application/json')
|
181
|
+
expect(subject.select_header_accept(1)).to eq('application/json')
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'when given a list of types' do
|
186
|
+
context 'that includes a JSON type' do
|
187
|
+
it 'returns the first type containing JSON' do
|
188
|
+
xml = 'application/xml'
|
189
|
+
json = 'application/json'
|
178
190
|
|
179
|
-
|
180
|
-
|
181
|
-
|
191
|
+
expect(subject.select_header_accept([xml, json])).to eq(json)
|
192
|
+
end
|
193
|
+
end
|
182
194
|
|
183
|
-
|
184
|
-
|
185
|
-
|
195
|
+
context 'that does not include a JSON type' do
|
196
|
+
it 'returns the all of the types' do
|
197
|
+
xml = 'application/xml'
|
198
|
+
html = 'text/html'
|
199
|
+
result = [xml, html].join(', ')
|
186
200
|
|
187
|
-
|
188
|
-
|
201
|
+
expect(subject.select_header_accept([xml, html])).to eq(result)
|
202
|
+
end
|
203
|
+
end
|
189
204
|
end
|
190
205
|
end
|
191
206
|
|
192
207
|
describe '#select_header_content_type' do
|
193
|
-
|
208
|
+
context 'when given anything other than an array' do
|
209
|
+
it 'returns application/json as a default' do
|
210
|
+
expect(subject.select_header_content_type(nil)).to eq('application/json')
|
211
|
+
expect(subject.select_header_content_type('')).to eq('application/json')
|
212
|
+
expect(subject.select_header_content_type(1)).to eq('application/json')
|
213
|
+
end
|
214
|
+
end
|
194
215
|
|
195
|
-
|
196
|
-
|
197
|
-
|
216
|
+
context 'when given a list of types' do
|
217
|
+
context 'that includes a JSON type' do
|
218
|
+
it 'returns the first type containing JSON' do
|
219
|
+
xml = 'application/xml'
|
220
|
+
json = 'application/json'
|
198
221
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
expect(api_client.select_header_content_type(['application/xml'])).to eq('application/xml')
|
203
|
-
expect(api_client.select_header_content_type(['text/plain', 'application/xml'])).to eq('text/plain')
|
204
|
-
end
|
205
|
-
end
|
222
|
+
expect(subject.select_header_content_type([xml, json])).to eq(json)
|
223
|
+
end
|
224
|
+
end
|
206
225
|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
expect(api_client.sanitize_filename('./sun.gif')).to eq('sun.gif')
|
216
|
-
expect(api_client.sanitize_filename('..\sun.gif')).to eq('sun.gif')
|
217
|
-
expect(api_client.sanitize_filename('\var\tmp\sun.gif')).to eq('sun.gif')
|
218
|
-
expect(api_client.sanitize_filename('c:\var\tmp\sun.gif')).to eq('sun.gif')
|
219
|
-
expect(api_client.sanitize_filename('.\sun.gif')).to eq('sun.gif')
|
226
|
+
context 'that does not include a JSON type' do
|
227
|
+
it 'returns the first type' do
|
228
|
+
xml = 'application/xml'
|
229
|
+
html = 'text/html'
|
230
|
+
|
231
|
+
expect(subject.select_header_content_type([xml, html])).to eq(xml)
|
232
|
+
end
|
233
|
+
end
|
220
234
|
end
|
221
235
|
end
|
222
236
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,6 +8,9 @@
|
|
8
8
|
|
9
9
|
# load the gem
|
10
10
|
require 'vsphere-automation-runtime'
|
11
|
+
require 'webmock/rspec'
|
12
|
+
|
13
|
+
WebMock.disable_net_connect!(allow_localhost: true)
|
11
14
|
|
12
15
|
# The following was generated by the `rspec --init` command. Conventionally, all
|
13
16
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
@@ -23,8 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.license = 'MIT'
|
24
24
|
s.required_ruby_version = ">= 2.3"
|
25
25
|
|
26
|
-
s.add_runtime_dependency 'typhoeus', '~> 1.3'
|
27
|
-
|
28
26
|
s.add_development_dependency 'bundler', '~> 2.0'
|
29
27
|
s.add_development_dependency 'pry', '~> 0.12.2'
|
30
28
|
s.add_development_dependency 'rake', '~> 12.3'
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vsphere-automation-runtime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- J.R. Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: typhoeus
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.3'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.3'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,8 +125,8 @@ files:
|
|
139
125
|
- lib/vsphere-automation-runtime/api_error.rb
|
140
126
|
- lib/vsphere-automation-runtime/configuration.rb
|
141
127
|
- lib/vsphere-automation-runtime/version.rb
|
142
|
-
- pkg/vsphere-automation-runtime-0.
|
143
|
-
- pkg/vsphere-automation-runtime-0.
|
128
|
+
- pkg/vsphere-automation-runtime-0.3.0.gem
|
129
|
+
- pkg/vsphere-automation-runtime-0.4.0.gem
|
144
130
|
- spec/api_client_spec.rb
|
145
131
|
- spec/configuration_spec.rb
|
146
132
|
- spec/spec_helper.rb
|
Binary file
|
Binary file
|