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 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