vcloud-rest 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/astratto/vcloud-rest.png?branch=master)](http://travis-ci.org/astratto/vcloud-rest)
|
5
|
+
[![Dependency Status](https://gemnasium.com/astratto/vcloud-rest.png)](https://gemnasium.com/astratto/vcloud-rest)
|
6
|
+
[![Coverage Status](https://coveralls.io/repos/astratto/vcloud-rest/badge.png?branch=master)](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
|