vcloud-rest 1.3.0 → 1.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/CHANGELOG.md +53 -47
- data/README.md +9 -5
- data/lib/vcloud-rest/connection.rb +205 -178
- data/lib/vcloud-rest/vcloud/extensibility.rb +22 -0
- data/lib/vcloud-rest/vcloud/vapp.rb +9 -2
- data/lib/vcloud-rest/vcloud/vm.rb +8 -8
- data/lib/vcloud-rest/version.rb +1 -1
- metadata +38 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cd7e1b40d90b0ad7cfbab2d6e749409a23393c8
|
4
|
+
data.tar.gz: 7208fd95232db0ccbf5c0b786d18b7f94c00f42e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0489c4ca0013853e07dc5e753512be0ef897d812dbe53976772157e999661f493f804cd59cb8c7d5ad798c3dcdd8e5d486b0bd3c31f2d4840160998a5a23aa70
|
7
|
+
data.tar.gz: b857d5f5205648b1deaedb6416be2046ebb362fc313a8a5913760562d45f0867ff76a60ec227b2765861d493e88d5dcb2dcd86ff11a1722a6312adeb5fa8c729
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,26 @@
|
|
1
|
-
Changes
|
2
|
-
|
3
|
-
|
1
|
+
# Changes
|
2
|
+
|
3
|
+
### 2015-06-28 (1.4.0)
|
4
|
+
|
5
|
+
Note that I don't have enough time anymore to actively maintain this gem and I'm
|
6
|
+
looking for a co-maintainer.
|
7
|
+
|
8
|
+
**Fixes**
|
9
|
+
|
10
|
+
* Fix add network with manually specified IP
|
11
|
+
* Fix css selector in get_vapp
|
12
|
+
* Fix nil when deleting vapp
|
13
|
+
|
14
|
+
**Features**
|
15
|
+
|
16
|
+
* Add extensibility capabilities
|
17
|
+
* Handle *nat_type* in `compose_vapp_from_vm`
|
18
|
+
|
19
|
+
### 2014-06-03 (1.3.0)
|
4
20
|
|
5
21
|
Note that starting from this release Ruby 1.8.7+ and 1.9.2 are not explicitly tested against anymore.
|
6
22
|
|
7
|
-
|
23
|
+
**Features**
|
8
24
|
|
9
25
|
* Add "media" item type management to `get_catalog_item`
|
10
26
|
* Add `discard_suspend_state_[vapp|vm]` to discard suspended state of a vApp or VM
|
@@ -13,7 +29,7 @@ FEATURES:
|
|
13
29
|
* Add `discard_[vm|vapp]_snapshot` to discard snapshots
|
14
30
|
* Add `acquire_ticket_vm` that retrieves a screen ticket (VMRC) for a given VM
|
15
31
|
|
16
|
-
|
32
|
+
**Fixes**
|
17
33
|
|
18
34
|
* Fix add network to VM for API v.5.5
|
19
35
|
* Fix VM IP address retrieval with different interfaces on same network
|
@@ -21,9 +37,9 @@ FIXES:
|
|
21
37
|
|
22
38
|
Note that now `get_vm` appends NetworkConnectionIndex to network name to generate a unique hash key.
|
23
39
|
|
24
|
-
2014-02-06 (1.2.0)
|
40
|
+
### 2014-02-06 (1.2.0)
|
25
41
|
|
26
|
-
|
42
|
+
**Features**
|
27
43
|
|
28
44
|
* vm
|
29
45
|
* actions to control vm snapshots just as vApp snapshots
|
@@ -31,42 +47,40 @@ FEATURES:
|
|
31
47
|
* revert_vm_snapshot
|
32
48
|
* network add/edit handle PrimaryNetworkConnectionIndex
|
33
49
|
|
34
|
-
|
50
|
+
**Deprecations**
|
35
51
|
|
36
52
|
* `create_snapshot` is deprecated in favour of create_vapp_snapshot
|
37
53
|
* `revert_snapshot` is deprecated in favour of revert_vapp_snapshot
|
38
54
|
* remove `set_vm_network_config` deprecated in 1.1.0
|
39
55
|
|
40
|
-
|
56
|
+
**Fixes**
|
41
57
|
|
42
58
|
* OVF: fix upload link retrieval (issue #23)
|
43
59
|
* Remove network placeholder when adding a network to a VM
|
44
60
|
|
45
|
-
2013-12-31 (1.1.1)
|
46
|
-
|
61
|
+
### 2013-12-31 (1.1.1)
|
62
|
+
|
63
|
+
**Fixes**
|
47
64
|
|
48
|
-
FIXES:
|
49
65
|
* Unify IP address retrieval (issue #20)
|
50
66
|
|
51
|
-
2013-12-13 (1.1.0)
|
52
|
-
--
|
67
|
+
### 2013-12-13 (1.1.0)
|
53
68
|
|
54
|
-
|
69
|
+
**Features**
|
55
70
|
|
56
71
|
* Add commands `[add|edit|delete]_vm_network` to manage multiple networks
|
57
72
|
|
58
|
-
|
73
|
+
**Deprecations**
|
59
74
|
|
60
75
|
* `set_vm_network_config` is now deprecated
|
61
76
|
|
62
|
-
2013-11-29 (1.0.0)
|
63
|
-
--
|
77
|
+
### 2013-11-29 (1.0.0)
|
64
78
|
|
65
79
|
This is the first release that leaves beta status.
|
66
80
|
It's actively used in production by at least one company and thus it's important
|
67
81
|
to offer a more stable interface.
|
68
82
|
|
69
|
-
|
83
|
+
**Features**
|
70
84
|
|
71
85
|
* General
|
72
86
|
* Add proper logging
|
@@ -100,7 +114,7 @@ FEATURES:
|
|
100
114
|
* Tasks
|
101
115
|
* Add methods to list/cancel Tasks
|
102
116
|
|
103
|
-
|
117
|
+
**Changes**
|
104
118
|
|
105
119
|
* vApp clone returns an hash to provide also the new vApp's ID
|
106
120
|
* retrieve VM's name directly instead of using the GuestCustomization section
|
@@ -108,7 +122,7 @@ CHANGES:
|
|
108
122
|
* Relax nokogiri version to >= 1.5.10
|
109
123
|
* set_vapp_network_config requires different parameters
|
110
124
|
|
111
|
-
|
125
|
+
**Fixes**
|
112
126
|
|
113
127
|
* Reset auth token when a session is destroyed
|
114
128
|
* Fix wait_task_completion
|
@@ -118,10 +132,9 @@ FIXES:
|
|
118
132
|
* set_vapp_network_config to ensure existing configs are not lost
|
119
133
|
* Better error handling for upload OVF
|
120
134
|
|
121
|
-
2013-07-25 (0.3.0)
|
122
|
-
--
|
135
|
+
### 2013-07-25 (0.3.0)
|
123
136
|
|
124
|
-
|
137
|
+
**Features**
|
125
138
|
|
126
139
|
* Add ```compose_vapp_from_vm``` to compose a vapp using VMs in a catalog
|
127
140
|
* Add ```get_vapp_template``` to get information on VMs inside a vapp template
|
@@ -133,40 +146,36 @@ FEATURES:
|
|
133
146
|
* Add ``reboot_vapp/suspend_vapp/reset_vapp``
|
134
147
|
* Add ```upload_ovf``` to upload an OVF Package
|
135
148
|
|
136
|
-
|
149
|
+
**Changes**
|
137
150
|
|
138
151
|
* ```RetainNetInfoAcrossDeployments``` now defaults to false (fenced deployments)
|
139
152
|
|
140
|
-
|
153
|
+
**Fixes**
|
141
154
|
|
142
155
|
* Better handling of 500 errors
|
143
156
|
|
144
|
-
|
145
|
-
A big thanks to Fabio Rapposelli and Timo Sugliani for the great work done!
|
157
|
+
*Remarks:* A big thanks to Fabio Rapposelli and Timo Sugliani for the great work done!
|
146
158
|
|
147
|
-
2013-05-13 (0.2.2)
|
148
|
-
--
|
159
|
+
### 2013-05-13 (0.2.2)
|
149
160
|
|
150
|
-
|
161
|
+
**Fixes**
|
151
162
|
|
152
163
|
* Fix retrieving of 'ipAddress' attribute of VMs inside VAPP
|
153
164
|
|
154
|
-
|
165
|
+
**Various**
|
155
166
|
|
156
167
|
* Add license field to gemspec
|
157
168
|
* Bump nokogiri dependency to 1.5.9
|
158
169
|
|
159
|
-
2012-12-27 (0.2.1)
|
160
|
-
--
|
170
|
+
### 2012-12-27 (0.2.1)
|
161
171
|
|
162
|
-
|
172
|
+
**Fixes**
|
163
173
|
|
164
174
|
* Fix VM's admin password retrieval
|
165
175
|
|
166
|
-
2012-12-21 (0.2.0)
|
167
|
-
--
|
176
|
+
### 2012-12-21 (0.2.0)
|
168
177
|
|
169
|
-
|
178
|
+
**Features**
|
170
179
|
|
171
180
|
* Allow Task tracking for vApp startup & shutdown
|
172
181
|
* Improve error message for operations on vApp not running
|
@@ -177,21 +186,19 @@ FEATURES:
|
|
177
186
|
* Basic VM network configuration
|
178
187
|
* Basic Guest Customization configuration
|
179
188
|
|
180
|
-
|
189
|
+
**Fixes**
|
181
190
|
|
182
191
|
* Show catalog item: fix ID parsing
|
183
192
|
|
184
|
-
2012-12-19 (0.1.1)
|
185
|
-
--
|
193
|
+
### 2012-12-19 (0.1.1)
|
186
194
|
|
187
|
-
|
195
|
+
**Fixes**
|
188
196
|
|
189
197
|
* Fix gemspec URL
|
190
198
|
|
191
|
-
2012-12-19 (0.1.0)
|
192
|
-
--
|
199
|
+
### 2012-12-19 (0.1.0)
|
193
200
|
|
194
|
-
|
201
|
+
**Features**
|
195
202
|
|
196
203
|
* Add support for main operations:
|
197
204
|
* login/logout
|
@@ -201,7 +208,6 @@ FEATURES:
|
|
201
208
|
* catalog item _show_
|
202
209
|
* vapp _create/delete/startup/shutdown_
|
203
210
|
|
204
|
-
2012-12-14 (0.0.1)
|
205
|
-
--
|
211
|
+
### 2012-12-14 (0.0.1)
|
206
212
|
|
207
213
|
* Initial release
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
vcloud-rest
|
1
|
+
vcloud-rest
|
2
2
|
===========
|
3
3
|
|
4
|
+
[](http://travis-ci.org/astratto/vcloud-rest)
|
5
|
+
[](https://gemnasium.com/astratto/vcloud-rest)
|
6
|
+
[](https://coveralls.io/r/astratto/vcloud-rest?branch=master)
|
7
|
+
|
4
8
|
DESCRIPTION
|
5
9
|
--
|
6
10
|
Unofficial ruby bindings for VMware® vCloud Director's rest APIs.
|
@@ -64,9 +68,9 @@ USAGE
|
|
64
68
|
--
|
65
69
|
|
66
70
|
require 'vcloud-rest/connection'
|
67
|
-
conn = VCloudClient::Connection.new(HOST, USER, PASSWORD, ORG_NAME)
|
71
|
+
conn = VCloudClient::Connection.new(HOST, USER, PASSWORD, ORG_NAME, VERSION)
|
68
72
|
conn.login
|
69
|
-
conn.
|
73
|
+
conn.get_organizations
|
70
74
|
|
71
75
|
EXAMPLE
|
72
76
|
--
|
@@ -78,7 +82,7 @@ DEBUGGING
|
|
78
82
|
--
|
79
83
|
Debug can be enabled setting the following environment variables:
|
80
84
|
|
81
|
-
* *VCLOUD_REST_DEBUG_LEVEL*: to specify the log level (e.g., INFO)
|
85
|
+
* *VCLOUD_REST_DEBUG_LEVEL*: to specify the log level (e.g., INFO, DEBUG)
|
82
86
|
* *VCLOUD_REST_LOG_FILE*: to specify the output file (defaults to STDOUT)
|
83
87
|
|
84
88
|
TESTING
|
@@ -138,7 +142,7 @@ LICENSE
|
|
138
142
|
|
139
143
|
Author:: Stefano Tortarolo <stefano.tortarolo@gmail.com>
|
140
144
|
|
141
|
-
Copyright:: Copyright (c) 2012-
|
145
|
+
Copyright:: Copyright (c) 2012-2015
|
142
146
|
License:: Apache License, Version 2.0
|
143
147
|
|
144
148
|
Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -32,6 +32,7 @@ require 'vcloud-rest/vcloud/ovf'
|
|
32
32
|
require 'vcloud-rest/vcloud/media'
|
33
33
|
require 'vcloud-rest/vcloud/network'
|
34
34
|
require 'vcloud-rest/vcloud/disk'
|
35
|
+
require 'vcloud-rest/vcloud/extensibility'
|
35
36
|
|
36
37
|
module VCloudClient
|
37
38
|
class UnauthorizedAccess < StandardError; end
|
@@ -46,6 +47,7 @@ module VCloudClient
|
|
46
47
|
# Main class to access vCloud rest APIs
|
47
48
|
class Connection
|
48
49
|
attr_reader :api_url, :auth_key
|
50
|
+
attr_reader :extensibility
|
49
51
|
|
50
52
|
def initialize(host, username, password, org_name, api_version)
|
51
53
|
@host = host
|
@@ -73,6 +75,9 @@ module VCloudClient
|
|
73
75
|
raise "Unable to authenticate: missing x_vcloud_authorization header"
|
74
76
|
end
|
75
77
|
|
78
|
+
extensibility_link = response.css("Link[rel='down:extensibility']")
|
79
|
+
@extensibility = extensibility_link.first['href'] unless extensibility_link.empty?
|
80
|
+
|
76
81
|
@auth_key = headers[:x_vcloud_authorization]
|
77
82
|
end
|
78
83
|
|
@@ -133,51 +138,44 @@ module VCloudClient
|
|
133
138
|
##
|
134
139
|
# Sends a synchronous request to the vCloud API and returns the response as parsed XML + headers.
|
135
140
|
def send_request(params, payload=nil, content_type=nil)
|
136
|
-
|
137
|
-
invocation_params = {:method => params['method'],
|
138
|
-
:headers => headers,
|
139
|
-
:url => "#{@api_url}#{params['command']}",
|
140
|
-
:payload => payload}
|
141
|
-
|
142
|
-
if @auth_key
|
143
|
-
headers.merge!({:x_vcloud_authorization => @auth_key})
|
144
|
-
else
|
145
|
-
invocation_params.merge!({:user => "#{@username}@#{@org_name}",
|
146
|
-
:password => @password })
|
147
|
-
end
|
141
|
+
req_params = setup_request(params, payload, content_type)
|
148
142
|
|
149
|
-
|
143
|
+
handled_request(req_params) do
|
144
|
+
request = RestClient::Request.new(req_params)
|
150
145
|
|
151
|
-
request = RestClient::Request.new(invocation_params)
|
152
|
-
|
153
|
-
begin
|
154
146
|
response = request.execute
|
155
147
|
if ![200, 201, 202, 204].include?(response.code)
|
156
148
|
@logger.warn "Warning: unattended code #{response.code}"
|
157
149
|
end
|
158
150
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
151
|
+
parsed_response = Nokogiri::XML(response)
|
152
|
+
@logger.debug "Send request result: #{parsed_response}"
|
153
|
+
|
154
|
+
[parsed_response, response.headers]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def parse_error_body(error)
|
159
|
+
body = Nokogiri.parse(error.http_body)
|
160
|
+
body.css("Error").first["message"]
|
161
|
+
end
|
162
|
+
|
163
|
+
def setup_request(params, payload=nil, content_type=nil)
|
164
|
+
req_params = {:method => params['method'],
|
165
|
+
:headers => {:accept => "application/*+xml;version=#{@api_version}"},
|
166
|
+
:url => "#{@api_url}#{params['command']}",
|
167
|
+
:payload => payload}
|
168
|
+
|
169
|
+
req_params[:headers].merge!({:content_type => content_type}) if content_type
|
170
|
+
|
171
|
+
if @auth_key
|
172
|
+
req_params[:headers].merge!({:x_vcloud_authorization => @auth_key})
|
173
|
+
else
|
174
|
+
req_params.merge!({:user => "#{@username}@#{@org_name}",
|
175
|
+
:password => @password })
|
180
176
|
end
|
177
|
+
|
178
|
+
req_params
|
181
179
|
end
|
182
180
|
|
183
181
|
##
|
@@ -224,168 +222,197 @@ module VCloudClient
|
|
224
222
|
end
|
225
223
|
end
|
226
224
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
225
|
+
def handled_request(params, &block)
|
226
|
+
fail InternalServerError, 'A block is required' unless block_given?
|
227
|
+
|
228
|
+
block.call(params)
|
229
|
+
rescue RestClient::Unauthorized => e
|
230
|
+
@logger.debug "Send request error: #{e.http_body}"
|
231
|
+
raise UnauthorizedAccess, "Client not authorized. Please check your credentials."
|
232
|
+
rescue RestClient::BadRequest => e
|
233
|
+
@logger.debug "Send request error: #{e.http_body}"
|
234
|
+
humanize_badrequest(parse_error_body(e))
|
235
|
+
rescue RestClient::Forbidden => e
|
236
|
+
@logger.debug "Send request error: #{e.http_body}"
|
237
|
+
raise UnauthorizedAccess, "Operation not permitted: #{parse_error_body(e)}."
|
238
|
+
rescue RestClient::InternalServerError => e
|
239
|
+
@logger.debug "Send request error: #{e.http_body}"
|
240
|
+
raise InternalServerError, "Internal Server Error: #{parse_error_body(e)}."
|
241
|
+
rescue RestClient::MethodNotAllowed => e
|
242
|
+
@logger.debug "Send request error: #{e.http_body}"
|
243
|
+
raise MethodNotAllowed,
|
244
|
+
"#{params['method']} to #{params['command']} not allowed: #{parse_error_body(e)}."
|
245
|
+
rescue SocketError => e
|
246
|
+
@logger.error "Failed to connect to #{params[:url]}: #{e}"
|
247
|
+
raise
|
248
|
+
end
|
233
249
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
250
|
+
def parse_error_body(error)
|
251
|
+
body = Nokogiri.parse(error.http_body)
|
252
|
+
body.css("Error").first["message"]
|
253
|
+
end
|
238
254
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
255
|
+
##
|
256
|
+
# Generic method to send power actions to vApp/VM
|
257
|
+
#
|
258
|
+
# i.e., 'suspend', 'powerOn'
|
259
|
+
def power_action(id, action, type=:vapp)
|
260
|
+
target = "#{type}-#{id}"
|
261
|
+
|
262
|
+
params = {
|
263
|
+
'method' => :post,
|
264
|
+
'command' => "/vApp/#{target}/power/action/#{action}"
|
265
|
+
}
|
243
266
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
"method" => :post,
|
249
|
-
"command" => "/vApp/#{type}-#{id}/action/discardSuspendedState"
|
250
|
-
}
|
251
|
-
response, headers = send_request(params)
|
252
|
-
task_id = headers[:location].gsub(/.*\/task\//, "")
|
253
|
-
task_id
|
254
|
-
end
|
267
|
+
response, headers = send_request(params)
|
268
|
+
task_id = headers[:location].gsub(/.*\/task\//, "")
|
269
|
+
task_id
|
270
|
+
end
|
255
271
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
}
|
263
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
264
|
-
xml.CreateSnapshotParams(
|
265
|
-
"xmlns" => "http://www.vmware.com/vcloud/v1.5") {
|
266
|
-
xml.Description description
|
272
|
+
##
|
273
|
+
# Discard suspended state of a vApp/VM
|
274
|
+
def discard_suspended_state_action(id, type=:vapp)
|
275
|
+
params = {
|
276
|
+
"method" => :post,
|
277
|
+
"command" => "/vApp/#{type}-#{id}/action/discardSuspendedState"
|
267
278
|
}
|
279
|
+
response, headers = send_request(params)
|
280
|
+
task_id = headers[:location].gsub(/.*\/task\//, "")
|
281
|
+
task_id
|
268
282
|
end
|
269
|
-
response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.createSnapshotParams+xml")
|
270
|
-
task_id = headers[:location].gsub(/.*\/task\//, "")
|
271
|
-
task_id
|
272
|
-
end
|
273
|
-
|
274
|
-
##
|
275
|
-
# Revert to an existing snapshot (vapp/vm)
|
276
|
-
def revert_snapshot_action(id, type=:vapp)
|
277
|
-
params = {
|
278
|
-
"method" => :post,
|
279
|
-
"command" => "/vApp/#{type}-#{id}/action/revertToCurrentSnapshot"
|
280
|
-
}
|
281
|
-
response, headers = send_request(params)
|
282
|
-
task_id = headers[:location].gsub(/.*\/task\//, "")
|
283
|
-
task_id
|
284
|
-
end
|
285
283
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
# Set chunksize to 10M if not specified otherwise
|
304
|
-
chunkSize = (config[:chunksize] || 10485760)
|
305
|
-
|
306
|
-
# Set progress bar to default format if not specified otherwise
|
307
|
-
progressBarFormat = (config[:progressbar_format] || "%e <%B> %p%% %t")
|
308
|
-
|
309
|
-
# Set progress bar length to 120 if not specified otherwise
|
310
|
-
progressBarLength = (config[:progressbar_length] || 120)
|
311
|
-
|
312
|
-
# Open our file for upload
|
313
|
-
uploadFileHandle = File.new(uploadFile, "rb" )
|
314
|
-
fileName = File.basename(uploadFileHandle)
|
315
|
-
|
316
|
-
progressBarTitle = "Uploading: " + uploadFile.to_s
|
317
|
-
|
318
|
-
# Create a progressbar object if progress bar is enabled
|
319
|
-
if config[:progressbar_enable] == true && uploadFileHandle.size.to_i > chunkSize
|
320
|
-
progressbar = ProgressBar.create(
|
321
|
-
:title => progressBarTitle,
|
322
|
-
:starting_at => 0,
|
323
|
-
:total => uploadFileHandle.size.to_i,
|
324
|
-
:length => progressBarLength,
|
325
|
-
:format => progressBarFormat
|
326
|
-
)
|
327
|
-
else
|
328
|
-
@logger.info progressBarTitle
|
284
|
+
##
|
285
|
+
# Create a new vapp/vm snapshot (overwrites any existing)
|
286
|
+
def create_snapshot_action(id, description="New Snapshot", type=:vapp)
|
287
|
+
params = {
|
288
|
+
"method" => :post,
|
289
|
+
"command" => "/vApp/#{type}-#{id}/action/createSnapshot"
|
290
|
+
}
|
291
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
292
|
+
xml.CreateSnapshotParams(
|
293
|
+
"xmlns" => "http://www.vmware.com/vcloud/v1.5") {
|
294
|
+
xml.Description description
|
295
|
+
}
|
296
|
+
end
|
297
|
+
response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.createSnapshotParams+xml")
|
298
|
+
task_id = headers[:location].gsub(/.*\/task\//, "")
|
299
|
+
task_id
|
329
300
|
end
|
330
|
-
# Create a new HTTP client
|
331
|
-
clnt = HTTPClient.new
|
332
301
|
|
333
|
-
|
334
|
-
|
302
|
+
##
|
303
|
+
# Revert to an existing snapshot (vapp/vm)
|
304
|
+
def revert_snapshot_action(id, type=:vapp)
|
305
|
+
params = {
|
306
|
+
"method" => :post,
|
307
|
+
"command" => "/vApp/#{type}-#{id}/action/revertToCurrentSnapshot"
|
308
|
+
}
|
309
|
+
response, headers = send_request(params)
|
310
|
+
task_id = headers[:location].gsub(/.*\/task\//, "")
|
311
|
+
task_id
|
312
|
+
end
|
335
313
|
|
336
|
-
|
337
|
-
|
314
|
+
##
|
315
|
+
# Discard all existing snapshots (vapp/vm)
|
316
|
+
def discard_snapshot_action(id, type=:vapp)
|
317
|
+
params = {
|
318
|
+
"method" => :post,
|
319
|
+
"command" => "/vApp/#{type}-#{id}/action/removeAllSnapshots"
|
320
|
+
}
|
321
|
+
response, headers = send_request(params)
|
322
|
+
task_id = headers[:location].gsub(/.*\/task\//, "")
|
323
|
+
task_id
|
324
|
+
end
|
338
325
|
|
339
|
-
|
340
|
-
|
326
|
+
##
|
327
|
+
# Upload a large file in configurable chunks, output an optional progressbar
|
328
|
+
def upload_file(uploadURL, uploadFile, progressUrl, config={})
|
329
|
+
raise ::IOError, "#{uploadFile} not found." unless File.exists?(uploadFile)
|
330
|
+
|
331
|
+
# Set chunksize to 10M if not specified otherwise
|
332
|
+
chunkSize = (config[:chunksize] || 10485760)
|
333
|
+
|
334
|
+
# Set progress bar to default format if not specified otherwise
|
335
|
+
progressBarFormat = (config[:progressbar_format] || "%e <%B> %p%% %t")
|
336
|
+
|
337
|
+
# Set progress bar length to 120 if not specified otherwise
|
338
|
+
progressBarLength = (config[:progressbar_length] || 120)
|
339
|
+
|
340
|
+
# Open our file for upload
|
341
|
+
uploadFileHandle = File.new(uploadFile, "rb" )
|
342
|
+
fileName = File.basename(uploadFileHandle)
|
343
|
+
|
344
|
+
progressBarTitle = "Uploading: " + uploadFile.to_s
|
345
|
+
|
346
|
+
# Create a progressbar object if progress bar is enabled
|
347
|
+
if config[:progressbar_enable] == true && uploadFileHandle.size.to_i > chunkSize
|
348
|
+
progressbar = ProgressBar.create(
|
349
|
+
:title => progressBarTitle,
|
350
|
+
:starting_at => 0,
|
351
|
+
:total => uploadFileHandle.size.to_i,
|
352
|
+
:length => progressBarLength,
|
353
|
+
:format => progressBarFormat
|
354
|
+
)
|
355
|
+
else
|
356
|
+
@logger.info progressBarTitle
|
357
|
+
end
|
358
|
+
# Create a new HTTP client
|
359
|
+
clnt = HTTPClient.new
|
341
360
|
|
342
|
-
#
|
343
|
-
|
344
|
-
rangeStop = uploadFileHandle.pos.to_i + chunkSize
|
361
|
+
# Disable SSL cert verification
|
362
|
+
clnt.ssl_config.verify_mode=(OpenSSL::SSL::VERIFY_NONE)
|
345
363
|
|
346
|
-
#
|
347
|
-
|
364
|
+
# Suppress SSL depth message
|
365
|
+
clnt.ssl_config.verify_callback=proc{ |ok, ctx|; true };
|
348
366
|
|
349
|
-
#
|
350
|
-
|
351
|
-
contentRange = "bytes #{rangeStart.to_s}-#{uploadFileHandle.size.to_s}/#{uploadFileHandle.size.to_s}"
|
352
|
-
rangeLen = uploadFileHandle.size.to_i - rangeStart.to_i
|
353
|
-
else
|
354
|
-
contentRange = "bytes #{rangeStart.to_s}-#{rangeStop.to_s}/#{uploadFileHandle.size.to_s}"
|
355
|
-
rangeLen = rangeStop.to_i - rangeStart.to_i
|
356
|
-
end
|
367
|
+
# Perform ranged upload until the file reaches its end
|
368
|
+
until uploadFileHandle.eof?
|
357
369
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
'Content-Range' => contentRange,
|
362
|
-
'Content-Length' => rangeLen.to_s
|
363
|
-
}
|
370
|
+
# Create ranges for this chunk upload
|
371
|
+
rangeStart = uploadFileHandle.pos
|
372
|
+
rangeStop = uploadFileHandle.pos.to_i + chunkSize
|
364
373
|
|
365
|
-
|
366
|
-
|
367
|
-
connection = clnt.request('PUT', uploadRequest, nil, fileContent, extheader)
|
374
|
+
# Read current chunk
|
375
|
+
fileContent = uploadFileHandle.read(chunkSize)
|
368
376
|
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
377
|
+
# If statement to handle last chunk transfer if is > than filesize
|
378
|
+
if rangeStop.to_i > uploadFileHandle.size.to_i
|
379
|
+
contentRange = "bytes #{rangeStart.to_s}-#{uploadFileHandle.size.to_s}/#{uploadFileHandle.size.to_s}"
|
380
|
+
rangeLen = uploadFileHandle.size.to_i - rangeStart.to_i
|
381
|
+
else
|
382
|
+
contentRange = "bytes #{rangeStart.to_s}-#{rangeStop.to_s}/#{uploadFileHandle.size.to_s}"
|
383
|
+
rangeLen = rangeStop.to_i - rangeStart.to_i
|
384
|
+
end
|
375
385
|
|
376
|
-
|
377
|
-
|
386
|
+
# Build headers
|
387
|
+
extheader = {
|
388
|
+
'x-vcloud-authorization' => @auth_key,
|
389
|
+
'Content-Range' => contentRange,
|
390
|
+
'Content-Length' => rangeLen.to_s
|
391
|
+
}
|
392
|
+
|
393
|
+
begin
|
394
|
+
uploadRequest = "#{@host_url}#{uploadURL}"
|
395
|
+
connection = clnt.request('PUT', uploadRequest, nil, fileContent, extheader)
|
396
|
+
|
397
|
+
if config[:progressbar_enable] == true && uploadFileHandle.size.to_i > chunkSize
|
398
|
+
params = {
|
399
|
+
'method' => :get,
|
400
|
+
'command' => progressUrl
|
401
|
+
}
|
402
|
+
response, headers = send_request(params)
|
403
|
+
|
404
|
+
response.css("Files File [name='#{fileName}']").each do |file|
|
405
|
+
progressbar.progress=file[:bytesTransferred].to_i
|
406
|
+
end
|
378
407
|
end
|
408
|
+
rescue
|
409
|
+
retryTime = (config[:retry_time] || 5)
|
410
|
+
@logger.warn "Range #{contentRange} failed to upload, retrying the chunk in #{retryTime.to_s} seconds, to stop the action press CTRL+C."
|
411
|
+
sleep retryTime.to_i
|
412
|
+
retry
|
379
413
|
end
|
380
|
-
rescue
|
381
|
-
retryTime = (config[:retry_time] || 5)
|
382
|
-
@logger.warn "Range #{contentRange} failed to upload, retrying the chunk in #{retryTime.to_s} seconds, to stop the action press CTRL+C."
|
383
|
-
sleep retryTime.to_i
|
384
|
-
retry
|
385
414
|
end
|
415
|
+
uploadFileHandle.close
|
386
416
|
end
|
387
|
-
uploadFileHandle.close
|
388
|
-
end
|
389
|
-
|
390
417
|
end # class
|
391
418
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module VCloudClient
|
2
|
+
class Connection
|
3
|
+
def get_extensibility
|
4
|
+
params = {
|
5
|
+
'method' => :get,
|
6
|
+
'command' => "/extensibility"
|
7
|
+
}
|
8
|
+
|
9
|
+
response, headers = send_request(params)
|
10
|
+
|
11
|
+
down_service = response.css("Link[@rel='down:service']").first['href']
|
12
|
+
down_apidefinitions = response.css("Link[@rel='down:apidefinitions']").first['href']
|
13
|
+
down_files = response.css("Link[@rel='down:files']").first['href']
|
14
|
+
|
15
|
+
{
|
16
|
+
:down_service => down_service,
|
17
|
+
:down_apidefinitions => down_apidefinitions,
|
18
|
+
:down_files => down_files,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -34,8 +34,8 @@ module VCloudClient
|
|
34
34
|
|
35
35
|
networks = response.css('NetworkConfig').reject{|n| n.attribute('networkName').text == 'none'}.
|
36
36
|
collect do |network|
|
37
|
-
net_id = network.css('Link
|
38
|
-
net_id = net_id.attribute('href').text.gsub(/.*\/network\/(.*)\/action.*/, '\1') unless net_id.
|
37
|
+
net_id = network.css('Link[rel="repair"]')
|
38
|
+
net_id = net_id.attribute('href').text.gsub(/.*\/network\/(.*)\/action.*/, '\1') unless net_id.empty?
|
39
39
|
|
40
40
|
net_name = network.attribute('networkName').text
|
41
41
|
|
@@ -276,6 +276,13 @@ module VCloudClient
|
|
276
276
|
xml.FirewallService {
|
277
277
|
xml.IsEnabled(network_config[:enable_firewall] || "false")
|
278
278
|
}
|
279
|
+
if network_config.has_key? :nat_type
|
280
|
+
xml.NatService {
|
281
|
+
xml.IsEnabled "true"
|
282
|
+
xml.NatType network_config[:nat_type]
|
283
|
+
xml.Policy(network_config[:nat_policy_type] || "allowTraffic")
|
284
|
+
}
|
285
|
+
end
|
279
286
|
}
|
280
287
|
}
|
281
288
|
}
|
@@ -11,7 +11,7 @@ module VCloudClient
|
|
11
11
|
response, headers = send_request(params)
|
12
12
|
|
13
13
|
result = {}
|
14
|
-
response.css("ovf|Item
|
14
|
+
response.css("ovf|Item[vcloud|href]").each do |item|
|
15
15
|
item_name = item.attribute('href').text.gsub(/.*\/vApp\/vm\-(\w+(-?))+\/virtualHardwareSection\//, "")
|
16
16
|
name = item.css("rasd|ElementName")
|
17
17
|
name = name.text unless name.nil?
|
@@ -207,6 +207,12 @@ module VCloudClient
|
|
207
207
|
idx_node.content = config[:network_index] || networks_count
|
208
208
|
new_network.add_child(idx_node)
|
209
209
|
|
210
|
+
if config[:ip]
|
211
|
+
ip_node = Nokogiri::XML::Node.new "IpAddress", new_network
|
212
|
+
ip_node.content = config[:ip]
|
213
|
+
new_network.add_child(ip_node)
|
214
|
+
end
|
215
|
+
|
210
216
|
is_connected_node = Nokogiri::XML::Node.new "IsConnected", new_network
|
211
217
|
is_connected_node.content = config[:is_connected] || true
|
212
218
|
new_network.add_child(is_connected_node)
|
@@ -215,12 +221,6 @@ module VCloudClient
|
|
215
221
|
allocation_node.content = config[:ip_allocation_mode] || "POOL"
|
216
222
|
new_network.add_child(allocation_node)
|
217
223
|
|
218
|
-
if config[:ip]
|
219
|
-
ip_node = Nokogiri::XML::Node.new "IpAddress", new_network
|
220
|
-
ip_node.content = config[:ip]
|
221
|
-
new_network.add_child(ip_node)
|
222
|
-
end
|
223
|
-
|
224
224
|
parent_section.add_child(new_network)
|
225
225
|
|
226
226
|
params = {
|
@@ -574,4 +574,4 @@ module VCloudClient
|
|
574
574
|
send_request(params)
|
575
575
|
end
|
576
576
|
end
|
577
|
-
end
|
577
|
+
end
|
data/lib/vcloud-rest/version.rb
CHANGED
metadata
CHANGED
@@ -1,177 +1,177 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vcloud-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefano Tortarolo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.5.10
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.5.10
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rest-client
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.6'
|
34
|
-
- -
|
34
|
+
- - '>='
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: 1.6.7
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '1.6'
|
44
|
-
- -
|
44
|
+
- - '>='
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 1.6.7
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: httpclient
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '2.3'
|
54
|
-
- -
|
54
|
+
- - '>='
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: 2.3.3
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
59
|
version_requirements: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ~>
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '2.3'
|
64
|
-
- -
|
64
|
+
- - '>='
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: 2.3.3
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: ruby-progressbar
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
|
-
- -
|
71
|
+
- - ~>
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '1.5'
|
74
|
-
- -
|
74
|
+
- - '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: 1.5.1
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ~>
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '1.5'
|
84
|
-
- -
|
84
|
+
- - '>='
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: 1.5.1
|
87
87
|
- !ruby/object:Gem::Dependency
|
88
88
|
name: rake
|
89
89
|
requirement: !ruby/object:Gem::Requirement
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '10.1'
|
94
94
|
type: :development
|
95
95
|
prerelease: false
|
96
96
|
version_requirements: !ruby/object:Gem::Requirement
|
97
97
|
requirements:
|
98
|
-
- -
|
98
|
+
- - ~>
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: '10.1'
|
101
101
|
- !ruby/object:Gem::Dependency
|
102
102
|
name: rspec
|
103
103
|
requirement: !ruby/object:Gem::Requirement
|
104
104
|
requirements:
|
105
|
-
- -
|
105
|
+
- - ~>
|
106
106
|
- !ruby/object:Gem::Version
|
107
|
-
version: '
|
107
|
+
version: '3.0'
|
108
108
|
type: :development
|
109
109
|
prerelease: false
|
110
110
|
version_requirements: !ruby/object:Gem::Requirement
|
111
111
|
requirements:
|
112
|
-
- -
|
112
|
+
- - ~>
|
113
113
|
- !ruby/object:Gem::Version
|
114
|
-
version: '
|
114
|
+
version: '3.0'
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: webmock
|
117
117
|
requirement: !ruby/object:Gem::Requirement
|
118
118
|
requirements:
|
119
|
-
- -
|
119
|
+
- - ~>
|
120
120
|
- !ruby/object:Gem::Version
|
121
121
|
version: '1.13'
|
122
122
|
type: :development
|
123
123
|
prerelease: false
|
124
124
|
version_requirements: !ruby/object:Gem::Requirement
|
125
125
|
requirements:
|
126
|
-
- -
|
126
|
+
- - ~>
|
127
127
|
- !ruby/object:Gem::Version
|
128
128
|
version: '1.13'
|
129
129
|
- !ruby/object:Gem::Dependency
|
130
130
|
name: vcr
|
131
131
|
requirement: !ruby/object:Gem::Requirement
|
132
132
|
requirements:
|
133
|
-
- -
|
133
|
+
- - ~>
|
134
134
|
- !ruby/object:Gem::Version
|
135
135
|
version: '2.9'
|
136
136
|
type: :development
|
137
137
|
prerelease: false
|
138
138
|
version_requirements: !ruby/object:Gem::Requirement
|
139
139
|
requirements:
|
140
|
-
- -
|
140
|
+
- - ~>
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '2.9'
|
143
143
|
- !ruby/object:Gem::Dependency
|
144
144
|
name: simplecov
|
145
145
|
requirement: !ruby/object:Gem::Requirement
|
146
146
|
requirements:
|
147
|
-
- -
|
147
|
+
- - ~>
|
148
148
|
- !ruby/object:Gem::Version
|
149
149
|
version: '0.8'
|
150
|
-
- -
|
150
|
+
- - '>='
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 0.8.2
|
153
153
|
type: :development
|
154
154
|
prerelease: false
|
155
155
|
version_requirements: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- -
|
157
|
+
- - ~>
|
158
158
|
- !ruby/object:Gem::Version
|
159
159
|
version: '0.8'
|
160
|
-
- -
|
160
|
+
- - '>='
|
161
161
|
- !ruby/object:Gem::Version
|
162
162
|
version: 0.8.2
|
163
163
|
- !ruby/object:Gem::Dependency
|
164
164
|
name: coveralls
|
165
165
|
requirement: !ruby/object:Gem::Requirement
|
166
166
|
requirements:
|
167
|
-
- -
|
167
|
+
- - '>='
|
168
168
|
- !ruby/object:Gem::Version
|
169
169
|
version: '0'
|
170
170
|
type: :development
|
171
171
|
prerelease: false
|
172
172
|
version_requirements: !ruby/object:Gem::Requirement
|
173
173
|
requirements:
|
174
|
-
- -
|
174
|
+
- - '>='
|
175
175
|
- !ruby/object:Gem::Version
|
176
176
|
version: '0'
|
177
177
|
description: Ruby bindings to create, list and manage vCloud servers
|
@@ -187,6 +187,7 @@ files:
|
|
187
187
|
- lib/vcloud-rest/connection.rb
|
188
188
|
- lib/vcloud-rest/vcloud/catalog.rb
|
189
189
|
- lib/vcloud-rest/vcloud/disk.rb
|
190
|
+
- lib/vcloud-rest/vcloud/extensibility.rb
|
190
191
|
- lib/vcloud-rest/vcloud/media.rb
|
191
192
|
- lib/vcloud-rest/vcloud/network.rb
|
192
193
|
- lib/vcloud-rest/vcloud/org.rb
|
@@ -200,23 +201,24 @@ homepage: https://github.com/astratto/vcloud-rest
|
|
200
201
|
licenses:
|
201
202
|
- Apache 2.0
|
202
203
|
metadata: {}
|
203
|
-
post_install_message:
|
204
|
+
post_install_message: 'NOTICE: vcloud-rest needs a co-maintainer! Feel free to ping
|
205
|
+
me at stefano.tortarolo@gmail.com'
|
204
206
|
rdoc_options: []
|
205
207
|
require_paths:
|
206
208
|
- lib
|
207
209
|
required_ruby_version: !ruby/object:Gem::Requirement
|
208
210
|
requirements:
|
209
|
-
- -
|
211
|
+
- - '>='
|
210
212
|
- !ruby/object:Gem::Version
|
211
213
|
version: '0'
|
212
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
213
215
|
requirements:
|
214
|
-
- -
|
216
|
+
- - '>='
|
215
217
|
- !ruby/object:Gem::Version
|
216
218
|
version: '0'
|
217
219
|
requirements: []
|
218
220
|
rubyforge_project:
|
219
|
-
rubygems_version: 2.
|
221
|
+
rubygems_version: 2.4.6
|
220
222
|
signing_key:
|
221
223
|
specification_version: 4
|
222
224
|
summary: Unofficial ruby bindings for VMWare vCloud's API
|