ovirt-engine-sdk 4.0.1 → 4.4.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 +5 -5
- data/CHANGES.adoc +684 -0
- data/README.adoc +729 -32
- data/ext/ovirtsdk4c/extconf.rb +31 -5
- data/ext/ovirtsdk4c/ov_error.c +9 -2
- data/ext/ovirtsdk4c/ov_error.h +3 -1
- data/ext/ovirtsdk4c/ov_http_client.c +1218 -0
- data/ext/ovirtsdk4c/ov_http_client.h +75 -0
- data/ext/ovirtsdk4c/ov_http_request.c +397 -0
- data/ext/ovirtsdk4c/ov_http_request.h +54 -0
- data/ext/ovirtsdk4c/ov_http_response.c +210 -0
- data/ext/ovirtsdk4c/ov_http_response.h +41 -0
- data/ext/ovirtsdk4c/ov_http_transfer.c +91 -0
- data/ext/ovirtsdk4c/ov_http_transfer.h +47 -0
- data/ext/ovirtsdk4c/ov_module.h +2 -2
- data/ext/ovirtsdk4c/ov_string.c +43 -0
- data/ext/ovirtsdk4c/ov_string.h +25 -0
- data/ext/ovirtsdk4c/ov_xml_reader.c +115 -99
- data/ext/ovirtsdk4c/ov_xml_reader.h +20 -3
- data/ext/ovirtsdk4c/ov_xml_writer.c +95 -77
- data/ext/ovirtsdk4c/ov_xml_writer.h +18 -3
- data/ext/ovirtsdk4c/ovirtsdk4c.c +10 -2
- data/lib/ovirtsdk4/connection.rb +695 -0
- data/lib/ovirtsdk4/errors.rb +70 -0
- data/lib/ovirtsdk4/probe.rb +324 -0
- data/lib/ovirtsdk4/reader.rb +74 -40
- data/lib/ovirtsdk4/readers.rb +3325 -976
- data/lib/ovirtsdk4/service.rb +439 -48
- data/lib/ovirtsdk4/services.rb +29365 -21180
- data/lib/ovirtsdk4/type.rb +20 -6
- data/lib/ovirtsdk4/types.rb +15048 -3198
- data/lib/ovirtsdk4/version.rb +1 -1
- data/lib/ovirtsdk4/writer.rb +108 -13
- data/lib/ovirtsdk4/writers.rb +1373 -294
- data/lib/ovirtsdk4.rb +4 -2
- metadata +88 -36
- data/lib/ovirtsdk4/http.rb +0 -548
@@ -0,0 +1,70 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2017 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
module OvirtSDK4
|
18
|
+
#
|
19
|
+
# The base class for all errors raised by the SDK.
|
20
|
+
#
|
21
|
+
class Error
|
22
|
+
#
|
23
|
+
# An error code associated to the error. For HTTP related errors, this will be the HTTP response code returned by
|
24
|
+
# the server. For example, if retrieving of a virtual machine fails because it doesn't exist this attribute will
|
25
|
+
# contain the integer value 404. Note that this may be `nil` if the error is not HTTP related.
|
26
|
+
#
|
27
|
+
# @return [Integer] The HTTP error code.
|
28
|
+
#
|
29
|
+
attr_accessor :code
|
30
|
+
|
31
|
+
#
|
32
|
+
# The `Fault` object associated to the error.
|
33
|
+
#
|
34
|
+
# @return [Fault] The fault object associated to the error, if a fault was provided by the server, `nil` otherwise.
|
35
|
+
#
|
36
|
+
attr_accessor :fault
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# This class of error indicates that an authentiation or authorization problem happenend, like incorrect user name,
|
41
|
+
# incorrect password, or missing permissions.
|
42
|
+
#
|
43
|
+
class AuthError < Error
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# This class of error indicates that the name of the server or the name of the proxy can't be resolved to an IP
|
48
|
+
# address, or that the connection can't be stablished because the server is down or unreachable.
|
49
|
+
#
|
50
|
+
# Note that for this class of error the `code` and `fault` attributes will always be empty, as no response from the
|
51
|
+
# server will be available to populate them.
|
52
|
+
#
|
53
|
+
class ConnectionError < Error
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# This class of error indicates that an object can't be found.
|
58
|
+
#
|
59
|
+
class NotFoundError < Error
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# This class of error indicates that an operation timed out.
|
64
|
+
#
|
65
|
+
# Note that for this class of error the `code` and `fault` attributes will always be empty, as no response from the
|
66
|
+
# server will be available to populate them.
|
67
|
+
#
|
68
|
+
class TimeoutError < Error
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2016-2017 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
module OvirtSDK4
|
18
|
+
#
|
19
|
+
# This class is used to probe the engine to find which API versions it supports.
|
20
|
+
#
|
21
|
+
class Probe
|
22
|
+
#
|
23
|
+
# This class method receives a set of options that define the server to probe and returns an arrays of objects of
|
24
|
+
# the OvirtSDK4::ProbeResult class containing the results of the probe.
|
25
|
+
#
|
26
|
+
# @param opts [Hash] The options used to create the probe.
|
27
|
+
#
|
28
|
+
# @option opts [String] :host The name or IP address of the host to probe.
|
29
|
+
#
|
30
|
+
# @option opts [Integer] :port (443) The port number to probe.
|
31
|
+
#
|
32
|
+
# @option opts [String] :username The name of the user, something like `admin@internal`.
|
33
|
+
#
|
34
|
+
# @option opts [String] :password The password of the user.
|
35
|
+
#
|
36
|
+
# @option opts [Boolean] :insecure (false) A boolean flag that indicates if the server TLS certificate and host
|
37
|
+
# name should be checked.
|
38
|
+
#
|
39
|
+
# @option opts [String] :ca_file The name of a PEM file containing the trusted CA certificates. The certificate
|
40
|
+
# presented by the server will be verified using these CA certificates. If not set then the system wide CA
|
41
|
+
# certificates store is used.
|
42
|
+
#
|
43
|
+
# @option opts [String] :log The logger where the log messages will be written.
|
44
|
+
#
|
45
|
+
# @option opts [Boolean] :debug (false) A boolean flag indicating if debug output should be generated. If the
|
46
|
+
# values is `true` and the `log` parameter isn't `nil` then the data sent to and received from the server will
|
47
|
+
# be written to the log. Be aware that user names and passwords will also be written, so handle with care.
|
48
|
+
#
|
49
|
+
# @option opts [String] :proxy_url A string containing the protocol, address and port number of the proxy server
|
50
|
+
# to use to connect to the server. For example, in order to use the HTTP proxy `proxy.example.com` that is
|
51
|
+
# listening on port `3128` the value should be `http://proxy.example.com:3128`. This is optional, and if not
|
52
|
+
# given the connection will go directly to the server specified in the `url` parameter.
|
53
|
+
#
|
54
|
+
# @option opts [String] :proxy_username The name of the user to authenticate to the proxy server.
|
55
|
+
#
|
56
|
+
# @option opts [String] :proxy_password The password of the user to authenticate to the proxy server.
|
57
|
+
#
|
58
|
+
# @return [Array<ProbeResult>] An array of objects of the OvirtSDK4::ProbeResult class.
|
59
|
+
#
|
60
|
+
def self.probe(opts)
|
61
|
+
probe = nil
|
62
|
+
begin
|
63
|
+
probe = Probe.new(opts)
|
64
|
+
probe.probe
|
65
|
+
ensure
|
66
|
+
probe.close if probe
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ENGINE_CERTIFICATE_PATH =
|
71
|
+
'/ovirt-engine/services/pki-resource?resource=engine-certificate&format=OPENSSH-PUBKEY'.freeze
|
72
|
+
|
73
|
+
#
|
74
|
+
# This class method receives a set of options that define the server to probe and returns a boolean value
|
75
|
+
# that represents whether an oVirt instance was detected.
|
76
|
+
#
|
77
|
+
# @param opts [Hash] The options used to create the probe.
|
78
|
+
#
|
79
|
+
# @option opts [String] :host The name or IP address of the host to probe.
|
80
|
+
#
|
81
|
+
# @option opts [Integer] :port (443) The port number to probe.
|
82
|
+
#
|
83
|
+
# @option opts [String] :log The logger where the log messages will be written.
|
84
|
+
#
|
85
|
+
# @option opts [Boolean] :debug (false) A boolean flag indicating if debug output should be generated. If the
|
86
|
+
# values is `true` and the `log` parameter isn't `nil` then the data sent to and received from the server will
|
87
|
+
# be written to the log. Be aware that user names and passwords will also be written, so handle with care.
|
88
|
+
#
|
89
|
+
# @option opts [String] :proxy_url A string containing the protocol, address and port number of the proxy server
|
90
|
+
# to use to connect to the server. For example, in order to use the HTTP proxy `proxy.example.com` that is
|
91
|
+
# listening on port `3128` the value should be `http://proxy.example.com:3128`. This is optional, and if not
|
92
|
+
# given the connection will go directly to the server specified in the `url` parameter.
|
93
|
+
#
|
94
|
+
# @option opts [Integer] :timeout (0) Set a connection timeout, in seconds. If the value is 0 no timeout is set.
|
95
|
+
#
|
96
|
+
# @return [Boolean] Boolean value, `true` if an oVirt instance was detected.
|
97
|
+
#
|
98
|
+
def self.exists?(opts)
|
99
|
+
probe = nil
|
100
|
+
begin
|
101
|
+
opts[:insecure] = true
|
102
|
+
probe = Probe.new(opts)
|
103
|
+
probe.exists?
|
104
|
+
ensure
|
105
|
+
probe.close if probe
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# Creates a new probe.
|
111
|
+
#
|
112
|
+
# @param opts [Hash] The options used to create the probe.
|
113
|
+
#
|
114
|
+
# @option opts [String] :host The name or IP address of the host to probe.
|
115
|
+
#
|
116
|
+
# @option opts [Integer] :port (443) The port number to probe.
|
117
|
+
#
|
118
|
+
# @option opts [String] :username The name of the user, something like `admin@internal`.
|
119
|
+
#
|
120
|
+
# @option opts [String] :password The password of the user.
|
121
|
+
#
|
122
|
+
# @option opts [Boolean] :insecure (false) A boolean flag that indicates if the server TLS certificate and host
|
123
|
+
# name should be checked.
|
124
|
+
#
|
125
|
+
# @option opts [String] :ca_file The name of a PEM file containing the trusted CA certificates. The certificate
|
126
|
+
# presented by the server will be verified using these CA certificates. If not set then the system wide CA
|
127
|
+
# certificates store is used.
|
128
|
+
#
|
129
|
+
# @option opts [String] :log The logger where the log messages will be written.
|
130
|
+
#
|
131
|
+
# @option opts [Boolean] :debug (false) A boolean flag indicating if debug output should be generated. If the
|
132
|
+
# values is `true` and the `log` parameter isn't `nil` then the data sent to and received from the server will
|
133
|
+
# be written to the log. Be aware that user names and passwords will also be written, so handle with care.
|
134
|
+
#
|
135
|
+
# @option opts [String] :proxy_url A string containing the protocol, address and port number of the proxy server
|
136
|
+
# to use to connect to the server. For example, in order to use the HTTP proxy `proxy.example.com` that is
|
137
|
+
# listening on port `3128` the value should be `http://proxy.example.com:3128`. This is optional, and if not
|
138
|
+
# given the connection will go directly to the server specified in the `url` parameter.
|
139
|
+
#
|
140
|
+
# @option opts [String] :proxy_username The name of the user to authenticate to the proxy server.
|
141
|
+
#
|
142
|
+
# @option opts [String] :proxy_password The password of the user to authenticate to the proxy server.
|
143
|
+
#
|
144
|
+
# @api private
|
145
|
+
#
|
146
|
+
def initialize(opts)
|
147
|
+
# Get the options and assign default values:
|
148
|
+
@host = opts[:host]
|
149
|
+
@port = opts[:port] || 443
|
150
|
+
@username = opts[:username]
|
151
|
+
@password = opts[:password]
|
152
|
+
@insecure = opts[:insecure] || false
|
153
|
+
@ca_file = opts[:ca_file]
|
154
|
+
@log = opts[:log]
|
155
|
+
@debug = opts[:debug] || false
|
156
|
+
@proxy_url = opts[:proxy_url]
|
157
|
+
@proxy_username = opts[:proxy_username]
|
158
|
+
@proxy_password = opts[:proxy_password]
|
159
|
+
@timeout = opts[:timeout]
|
160
|
+
|
161
|
+
# Create the HTTP client:
|
162
|
+
@client = HttpClient.new(
|
163
|
+
host: @host,
|
164
|
+
port: @port,
|
165
|
+
insecure: @insecure,
|
166
|
+
ca_file: @ca_file,
|
167
|
+
log: @log,
|
168
|
+
debug: @debug,
|
169
|
+
proxy_url: @proxy_url,
|
170
|
+
proxy_username: @proxy_username,
|
171
|
+
proxy_password: @proxy_password,
|
172
|
+
timeout: @timeout
|
173
|
+
)
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Probes the server to detect the supported versions of the API.
|
178
|
+
#
|
179
|
+
# @return [Array<ProbeResult>] An array of objects of the OvirtSDK4::ProbeResult class.
|
180
|
+
#
|
181
|
+
# @api private
|
182
|
+
#
|
183
|
+
def probe
|
184
|
+
path = detect_path
|
185
|
+
raise Error, 'API path not found' unless path
|
186
|
+
|
187
|
+
detect_version(path).map { |version| ProbeResult.new(version: version) }
|
188
|
+
end
|
189
|
+
|
190
|
+
#
|
191
|
+
# Probes the server to detect if it has an ovirt instance running on it
|
192
|
+
#
|
193
|
+
# @return [Boolean] `true` if oVirt instance was detected, false otherwise
|
194
|
+
#
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
def exists?
|
198
|
+
response = send(path: ENGINE_CERTIFICATE_PATH)
|
199
|
+
response.code == 200
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Releases the resources used by this probe.
|
204
|
+
#
|
205
|
+
# @api private
|
206
|
+
#
|
207
|
+
def close
|
208
|
+
# Close the HTTP client:
|
209
|
+
@client.close if @client
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
#
|
215
|
+
# We will only check these paths, as there is where the API is available in common installations of the engine.
|
216
|
+
#
|
217
|
+
PATH_CANDIDATES = [
|
218
|
+
'/api',
|
219
|
+
'/ovirt-engine/api'
|
220
|
+
].freeze
|
221
|
+
|
222
|
+
def send(opts = {})
|
223
|
+
# Get the options and assign default values:
|
224
|
+
path = opts[:path] || ''
|
225
|
+
version = opts[:version] || '4'
|
226
|
+
|
227
|
+
# Create the request:
|
228
|
+
request = HttpRequest.new
|
229
|
+
request.url = "https://#{@host}:#{@port}#{path}"
|
230
|
+
|
231
|
+
# Set the headers:
|
232
|
+
request.headers.merge!(
|
233
|
+
'User-Agent' => "RubyProbe/#{VERSION}",
|
234
|
+
'Version' => version,
|
235
|
+
'Content-Type' => 'application/xml',
|
236
|
+
'Accept' => 'application/xml'
|
237
|
+
)
|
238
|
+
|
239
|
+
# Set authentication:
|
240
|
+
request.username = @username
|
241
|
+
|
242
|
+
request.password = @password
|
243
|
+
# Send the request and wait for the response:
|
244
|
+
@client.send(request)
|
245
|
+
response = @client.wait(request)
|
246
|
+
raise response if response.is_a?(Exception)
|
247
|
+
|
248
|
+
response
|
249
|
+
end
|
250
|
+
|
251
|
+
def detect_path
|
252
|
+
PATH_CANDIDATES.each do |path|
|
253
|
+
response = send(path: path)
|
254
|
+
return path if response.code == 200
|
255
|
+
raise AuthError, 'Unauthorized' if response.code == 401
|
256
|
+
end
|
257
|
+
nil
|
258
|
+
end
|
259
|
+
|
260
|
+
def detect_version(path)
|
261
|
+
versions = []
|
262
|
+
versions << '3' if detect_v3(path)
|
263
|
+
versions << '4' if detect_v4(path)
|
264
|
+
versions
|
265
|
+
end
|
266
|
+
|
267
|
+
def detect_v3(path)
|
268
|
+
response = send(version: '3', path: path)
|
269
|
+
special_response_regexp_in_api3 =~ response.body
|
270
|
+
end
|
271
|
+
|
272
|
+
def detect_v4(path)
|
273
|
+
response = send(version: '4', path: path)
|
274
|
+
special_response_regexp_in_api4 =~ response.body
|
275
|
+
end
|
276
|
+
|
277
|
+
# The methods below are based on headers oVirt returns depending on the API
|
278
|
+
# version it supports when queried with <version: 3> or <version: 4> header.
|
279
|
+
# Refer to spec to see the return values.
|
280
|
+
def special_response_regexp_in_api3
|
281
|
+
/major=/
|
282
|
+
end
|
283
|
+
|
284
|
+
def special_response_regexp_in_api4
|
285
|
+
/<major>/
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
#
|
290
|
+
# The probe returns an array of instances of this class.
|
291
|
+
#
|
292
|
+
class ProbeResult
|
293
|
+
attr_reader :version
|
294
|
+
|
295
|
+
#
|
296
|
+
# This method is used to initialize a class instance,
|
297
|
+
#
|
298
|
+
# @param opts [Hash] The attributes of the result.
|
299
|
+
#
|
300
|
+
# @option opts [String] :version The version obtained as the result of the probe.
|
301
|
+
#
|
302
|
+
def initialize(opts)
|
303
|
+
@version = opts[:version]
|
304
|
+
end
|
305
|
+
|
306
|
+
# Override the comparison method.
|
307
|
+
def ==(other)
|
308
|
+
other.class == self.class && other.state == state
|
309
|
+
end
|
310
|
+
|
311
|
+
alias eql? ==
|
312
|
+
|
313
|
+
# Should always be overriden if one overrides ==, used to get a hash value
|
314
|
+
# for the object.
|
315
|
+
def hash
|
316
|
+
state.hash
|
317
|
+
end
|
318
|
+
|
319
|
+
# @api private
|
320
|
+
def state
|
321
|
+
[version]
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
data/lib/ovirtsdk4/reader.rb
CHANGED
@@ -15,7 +15,6 @@
|
|
15
15
|
#
|
16
16
|
|
17
17
|
module OvirtSDK4
|
18
|
-
|
19
18
|
#
|
20
19
|
# This is the base class for all the XML readers used by the SDK. It contains the utility methods used by all
|
21
20
|
# of them.
|
@@ -23,7 +22,6 @@ module OvirtSDK4
|
|
23
22
|
# @api private
|
24
23
|
#
|
25
24
|
class Reader
|
26
|
-
|
27
25
|
#
|
28
26
|
# Reads a string value, assuming that the cursor is positioned at the start element that contains the value.
|
29
27
|
#
|
@@ -31,7 +29,7 @@ module OvirtSDK4
|
|
31
29
|
# @return [String]
|
32
30
|
#
|
33
31
|
def self.read_string(reader)
|
34
|
-
|
32
|
+
reader.read_element
|
35
33
|
end
|
36
34
|
|
37
35
|
#
|
@@ -42,7 +40,7 @@ module OvirtSDK4
|
|
42
40
|
# @return [Array<String>]
|
43
41
|
#
|
44
42
|
def self.read_strings(reader)
|
45
|
-
|
43
|
+
reader.read_elements
|
46
44
|
end
|
47
45
|
|
48
46
|
#
|
@@ -53,13 +51,14 @@ module OvirtSDK4
|
|
53
51
|
#
|
54
52
|
def self.parse_boolean(text)
|
55
53
|
return nil if text.nil?
|
54
|
+
|
56
55
|
case text.downcase
|
57
56
|
when 'false', '0'
|
58
|
-
|
57
|
+
false
|
59
58
|
when 'true', '1'
|
60
|
-
|
59
|
+
true
|
61
60
|
else
|
62
|
-
raise Error
|
61
|
+
raise Error, "The text '#{text}' isn't a valid boolean value."
|
63
62
|
end
|
64
63
|
end
|
65
64
|
|
@@ -70,7 +69,7 @@ module OvirtSDK4
|
|
70
69
|
# @return [Boolean]
|
71
70
|
#
|
72
71
|
def self.read_boolean(reader)
|
73
|
-
|
72
|
+
Reader.parse_boolean(reader.read_element)
|
74
73
|
end
|
75
74
|
|
76
75
|
#
|
@@ -81,7 +80,7 @@ module OvirtSDK4
|
|
81
80
|
# @return [Array<Boolean>]
|
82
81
|
#
|
83
82
|
def self.read_booleans(reader)
|
84
|
-
|
83
|
+
reader.read_elements.map { |text| Reader.parse_boolean(text) }
|
85
84
|
end
|
86
85
|
|
87
86
|
#
|
@@ -92,10 +91,11 @@ module OvirtSDK4
|
|
92
91
|
#
|
93
92
|
def self.parse_integer(text)
|
94
93
|
return nil if text.nil?
|
94
|
+
|
95
95
|
begin
|
96
|
-
|
97
|
-
rescue
|
98
|
-
raise Error
|
96
|
+
Integer(text, 10)
|
97
|
+
rescue ArgumentError
|
98
|
+
raise Error, "The text '#{text}' isn't a valid integer value."
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
@@ -106,7 +106,7 @@ module OvirtSDK4
|
|
106
106
|
# @return [Integer]
|
107
107
|
#
|
108
108
|
def self.read_integer(reader)
|
109
|
-
|
109
|
+
Reader.parse_integer(reader.read_element)
|
110
110
|
end
|
111
111
|
|
112
112
|
#
|
@@ -117,20 +117,21 @@ module OvirtSDK4
|
|
117
117
|
# @return [Array<Integer>]
|
118
118
|
#
|
119
119
|
def self.read_integers(reader)
|
120
|
-
|
120
|
+
reader.read_elements.map { |text| Reader.parse_integer(text) }
|
121
121
|
end
|
122
122
|
|
123
123
|
#
|
124
124
|
# Converts the given text to a decimal value.
|
125
125
|
#
|
126
|
-
# @return [
|
126
|
+
# @return [Float]
|
127
127
|
#
|
128
128
|
def self.parse_decimal(text)
|
129
129
|
return nil if text.nil?
|
130
|
+
|
130
131
|
begin
|
131
|
-
|
132
|
-
rescue
|
133
|
-
raise Error
|
132
|
+
Float(text)
|
133
|
+
rescue ArgumentError
|
134
|
+
raise Error, "The text '#{text}' isn't a valid decimal value."
|
134
135
|
end
|
135
136
|
end
|
136
137
|
|
@@ -138,10 +139,10 @@ module OvirtSDK4
|
|
138
139
|
# Reads a decimal value, assuming that the cursor is positioned at the start element that contains the value.
|
139
140
|
#
|
140
141
|
# @param reader [XmlReader]
|
141
|
-
# @return [
|
142
|
+
# @return [Float]
|
142
143
|
#
|
143
144
|
def self.read_decimal(reader)
|
144
|
-
|
145
|
+
Reader.parse_decimal(reader.read_element)
|
145
146
|
end
|
146
147
|
|
147
148
|
#
|
@@ -149,10 +150,10 @@ module OvirtSDK4
|
|
149
150
|
# values.
|
150
151
|
#
|
151
152
|
# @param reader [XmlReader]
|
152
|
-
# @return [Array<
|
153
|
+
# @return [Array<Float>]
|
153
154
|
#
|
154
155
|
def self.read_decimals(reader)
|
155
|
-
|
156
|
+
reader.read_elements.map { |text| Reader.parse_decimal(text) }
|
156
157
|
end
|
157
158
|
|
158
159
|
#
|
@@ -163,10 +164,11 @@ module OvirtSDK4
|
|
163
164
|
#
|
164
165
|
def self.parse_date(text)
|
165
166
|
return nil if text.nil?
|
167
|
+
|
166
168
|
begin
|
167
|
-
|
168
|
-
rescue
|
169
|
-
raise Error
|
169
|
+
DateTime.xmlschema(text)
|
170
|
+
rescue ArgumentError
|
171
|
+
raise Error, "The text '#{text}' isn't a valid date."
|
170
172
|
end
|
171
173
|
end
|
172
174
|
|
@@ -177,7 +179,7 @@ module OvirtSDK4
|
|
177
179
|
# @return [DateTime]
|
178
180
|
#
|
179
181
|
def self.read_date(reader)
|
180
|
-
|
182
|
+
Reader.parse_date(reader.read_element)
|
181
183
|
end
|
182
184
|
|
183
185
|
#
|
@@ -188,7 +190,45 @@ module OvirtSDK4
|
|
188
190
|
# @return [Array<DateTime>]
|
189
191
|
#
|
190
192
|
def self.read_dates(reader)
|
191
|
-
|
193
|
+
reader.read_elements.map { |text| Reader.parse_date(text) }
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Converts the given text to an enum.
|
198
|
+
#
|
199
|
+
# @param enum_module [Module]
|
200
|
+
# @param text [String]
|
201
|
+
# @return [String]
|
202
|
+
#
|
203
|
+
def self.parse_enum(enum_module, text)
|
204
|
+
return nil unless text
|
205
|
+
|
206
|
+
values = enum_module.constants.map { |const| enum_module.const_get(const) }
|
207
|
+
values.detect { |value| value.casecmp(text).zero? }
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Reads a enum value, assuming that the cursor is positioned at the
|
212
|
+
# start element that contains the value.
|
213
|
+
#
|
214
|
+
# @param enum_module [Module]
|
215
|
+
# @param reader [XmlReader]
|
216
|
+
# @return [Array<String>]
|
217
|
+
#
|
218
|
+
def self.read_enum(enum_module, reader)
|
219
|
+
Reader.parse_enum(enum_module, reader.read_element)
|
220
|
+
end
|
221
|
+
|
222
|
+
#
|
223
|
+
# Reads a list of enum values, assuming that the cursor is positioned
|
224
|
+
# at the start element of the element that contains the first value.
|
225
|
+
#
|
226
|
+
# @param enum_module [Module]
|
227
|
+
# @param reader [XmlReader]
|
228
|
+
# @return [Array<String>]
|
229
|
+
#
|
230
|
+
def self.read_enums(enum_module, reader)
|
231
|
+
reader.read_elements.map { |text| Reader.parse_enum(enum_module, text) }
|
192
232
|
end
|
193
233
|
|
194
234
|
#
|
@@ -196,7 +236,7 @@ module OvirtSDK4
|
|
196
236
|
# example, for the `vm` tag it will contain a reference to the `VmReader.read_one` method, and for the `vms` tag
|
197
237
|
# it will contain a reference to the `VmReader.read_many` method.
|
198
238
|
#
|
199
|
-
|
239
|
+
@readers = {}
|
200
240
|
|
201
241
|
#
|
202
242
|
# Registers a read method.
|
@@ -205,7 +245,7 @@ module OvirtSDK4
|
|
205
245
|
# @param reader [Method] The reference to the method that reads the object corresponding to the `tag`.
|
206
246
|
#
|
207
247
|
def self.register(tag, reader)
|
208
|
-
|
248
|
+
@readers[tag] = reader
|
209
249
|
end
|
210
250
|
|
211
251
|
#
|
@@ -223,7 +263,7 @@ module OvirtSDK4
|
|
223
263
|
elsif source.is_a?(XmlReader)
|
224
264
|
cursor = source
|
225
265
|
else
|
226
|
-
raise ArgumentError
|
266
|
+
raise ArgumentError, "Expected a 'String' or 'XmlReader', but got '#{source.class}'"
|
227
267
|
end
|
228
268
|
|
229
269
|
# Do the actual read, and make sure to always close the XML reader if we created it:
|
@@ -233,20 +273,14 @@ module OvirtSDK4
|
|
233
273
|
|
234
274
|
# Select the specific reader according to the tag:
|
235
275
|
tag = cursor.node_name
|
236
|
-
reader =
|
237
|
-
if reader.nil?
|
238
|
-
raise Error.new("Can't find a reader for tag '#{tag}'")
|
239
|
-
end
|
276
|
+
reader = @readers[tag]
|
277
|
+
raise Error, "Can't find a reader for tag '#{tag}'" if reader.nil?
|
240
278
|
|
241
279
|
# Read the object using the specific reader:
|
242
|
-
|
280
|
+
reader.call(cursor)
|
243
281
|
ensure
|
244
|
-
if !cursor.nil? && !cursor.equal?(source)
|
245
|
-
cursor.close
|
246
|
-
end
|
282
|
+
cursor.close if !cursor.nil? && !cursor.equal?(source)
|
247
283
|
end
|
248
284
|
end
|
249
|
-
|
250
285
|
end
|
251
|
-
|
252
286
|
end
|