vsphere-automation-runtime 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|