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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 470e97ca321d742340571fff5cbbaa6e5a8fbe2b
4
- data.tar.gz: 0460be22738dca2e1b05668a861777d6380dd3d4
3
+ metadata.gz: 2cd7e1b40d90b0ad7cfbab2d6e749409a23393c8
4
+ data.tar.gz: 7208fd95232db0ccbf5c0b786d18b7f94c00f42e
5
5
  SHA512:
6
- metadata.gz: acbace49f0444b3bff99e21ef01c9947597cba62adedf0b4385967627d4898cee59463cfbe1216f9abfdc75312344cd43146dd5608b48cc33eb894313f1e749c
7
- data.tar.gz: 813bdcc2737e13da061b0b76d659fe0147275e8d61c80220106dca631dfa5688ae48bbc35e6510cc5016ae3c686b87afd9cccec543f0d62d7def955c88523596
6
+ metadata.gz: 0489c4ca0013853e07dc5e753512be0ef897d812dbe53976772157e999661f493f804cd59cb8c7d5ad798c3dcdd8e5d486b0bd3c31f2d4840160998a5a23aa70
7
+ data.tar.gz: b857d5f5205648b1deaedb6416be2046ebb362fc313a8a5913760562d45f0867ff76a60ec227b2765861d493e88d5dcb2dcd86ff11a1722a6312adeb5fa8c729
@@ -1,10 +1,26 @@
1
- Changes
2
- ==
3
- 2014-06-03 (1.3.0)
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
- FEATURES:
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
- FIXES:
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
- FEATURES:
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
- DEPRECATIONS:
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
- FIXES:
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
- FEATURES:
69
+ **Features**
55
70
 
56
71
  * Add commands `[add|edit|delete]_vm_network` to manage multiple networks
57
72
 
58
- DEPRECATIONS:
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
- FEATURES:
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
- CHANGES:
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
- FIXES:
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
- FEATURES:
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
- CHANGES:
149
+ **Changes**
137
150
 
138
151
  * ```RetainNetInfoAcrossDeployments``` now defaults to false (fenced deployments)
139
152
 
140
- FIXES:
153
+ **Fixes**
141
154
 
142
155
  * Better handling of 500 errors
143
156
 
144
- REMARKS:
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
- FIXES:
161
+ **Fixes**
151
162
 
152
163
  * Fix retrieving of 'ipAddress' attribute of VMs inside VAPP
153
164
 
154
- VARIOUS:
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
- FIXES:
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
- FEATURES:
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
- FIXES:
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
- FIXES:
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
- FEATURES:
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 [![Build Status](https://secure.travis-ci.org/astratto/vcloud-rest.png?branch=master)](http://travis-ci.org/astratto/vcloud-rest) [![Dependency Status](https://gemnasium.com/astratto/vcloud-rest.png)](https://gemnasium.com/astratto/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.list_organizations
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-2014
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
- headers = {:accept => "application/*+xml;version=#{@api_version}"}
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
- headers.merge!({:content_type => content_type}) if content_type
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
- @logger.debug "Send request result: #{Nokogiri.parse(response)}"
160
-
161
- [Nokogiri.parse(response), response.headers]
162
- rescue RestClient::Unauthorized => e
163
- raise UnauthorizedAccess, "Client not authorized. Please check your credentials."
164
- rescue RestClient::BadRequest => e
165
- body = Nokogiri.parse(e.http_body)
166
- message = body.css("Error").first["message"]
167
- humanize_badrequest(message)
168
- rescue RestClient::Forbidden => e
169
- body = Nokogiri.parse(e.http_body)
170
- message = body.css("Error").first["message"]
171
- raise UnauthorizedAccess, "Operation not permitted: #{message}."
172
- rescue RestClient::InternalServerError => e
173
- body = Nokogiri.parse(e.http_body)
174
- message = body.css("Error").first["message"]
175
- raise InternalServerError, "Internal Server Error: #{message}."
176
- rescue RestClient::MethodNotAllowed => e
177
- body = Nokogiri.parse(e.http_body)
178
- message = body.css("Error").first["message"]
179
- raise MethodNotAllowed, "#{params['method']} to #{params['command']} not allowed: #{message}."
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
- # Generic method to send power actions to vApp/VM
229
- #
230
- # i.e., 'suspend', 'powerOn'
231
- def power_action(id, action, type=:vapp)
232
- target = "#{type}-#{id}"
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
- params = {
235
- 'method' => :post,
236
- 'command' => "/vApp/#{target}/power/action/#{action}"
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
- response, headers = send_request(params)
240
- task_id = headers[:location].gsub(/.*\/task\//, "")
241
- task_id
242
- end
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
- # Discard suspended state of a vApp/VM
246
- def discard_suspended_state_action(id, type=:vapp)
247
- params = {
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
- # Create a new vapp/vm snapshot (overwrites any existing)
258
- def create_snapshot_action(id, description="New Snapshot", type=:vapp)
259
- params = {
260
- "method" => :post,
261
- "command" => "/vApp/#{type}-#{id}/action/createSnapshot"
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
- # Discard all existing snapshots (vapp/vm)
288
- def discard_snapshot_action(id, type=:vapp)
289
- params = {
290
- "method" => :post,
291
- "command" => "/vApp/#{type}-#{id}/action/removeAllSnapshots"
292
- }
293
- response, headers = send_request(params)
294
- task_id = headers[:location].gsub(/.*\/task\//, "")
295
- task_id
296
- end
297
-
298
- ##
299
- # Upload a large file in configurable chunks, output an optional progressbar
300
- def upload_file(uploadURL, uploadFile, progressUrl, config={})
301
- raise ::IOError, "#{uploadFile} not found." unless File.exists?(uploadFile)
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
- # Disable SSL cert verification
334
- clnt.ssl_config.verify_mode=(OpenSSL::SSL::VERIFY_NONE)
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
- # Suppress SSL depth message
337
- clnt.ssl_config.verify_callback=proc{ |ok, ctx|; true };
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
- # Perform ranged upload until the file reaches its end
340
- until uploadFileHandle.eof?
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
- # Create ranges for this chunk upload
343
- rangeStart = uploadFileHandle.pos
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
- # Read current chunk
347
- fileContent = uploadFileHandle.read(chunkSize)
364
+ # Suppress SSL depth message
365
+ clnt.ssl_config.verify_callback=proc{ |ok, ctx|; true };
348
366
 
349
- # If statement to handle last chunk transfer if is > than filesize
350
- if rangeStop.to_i > uploadFileHandle.size.to_i
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
- # Build headers
359
- extheader = {
360
- 'x-vcloud-authorization' => @auth_key,
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
- begin
366
- uploadRequest = "#{@host_url}#{uploadURL}"
367
- connection = clnt.request('PUT', uploadRequest, nil, fileContent, extheader)
374
+ # Read current chunk
375
+ fileContent = uploadFileHandle.read(chunkSize)
368
376
 
369
- if config[:progressbar_enable] == true && uploadFileHandle.size.to_i > chunkSize
370
- params = {
371
- 'method' => :get,
372
- 'command' => progressUrl
373
- }
374
- response, headers = send_request(params)
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
- response.css("Files File [name='#{fileName}']").each do |file|
377
- progressbar.progress=file[:bytesTransferred].to_i
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 [rel=repair]')
38
- net_id = net_id.attribute('href').text.gsub(/.*\/network\/(.*)\/action.*/, '\1') unless net_id.nil?
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 [vcloud|href]").each do |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
@@ -1,3 +1,3 @@
1
1
  module VCloudClient
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
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.3.0
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: 2014-06-03 00:00:00.000000000 Z
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: '2.14'
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: '2.14'
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.2.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