vcloud-rest 0.3.0 → 1.0.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.
@@ -0,0 +1,396 @@
1
+ module VCloudClient
2
+ class Connection
3
+ ##
4
+ # Retrieve information (i.e., memory and CPUs)
5
+ def get_vm_info(vmid)
6
+ params = {
7
+ 'method' => :get,
8
+ 'command' => "/vApp/vm-#{vmid}/virtualHardwareSection"
9
+ }
10
+
11
+ response, headers = send_request(params)
12
+
13
+ result = {}
14
+ response.css("ovf|Item [vcloud|href]").each do |item|
15
+ item_name = item.attribute('href').text.gsub(/.*\/vApp\/vm\-(\w+(-?))+\/virtualHardwareSection\//, "")
16
+ name = item.css("rasd|ElementName")
17
+ name = name.text unless name.nil?
18
+
19
+ description = item.css("rasd|Description")
20
+ description = description.text unless description.nil?
21
+
22
+ result[item_name] = {
23
+ :name => name,
24
+ :description => description
25
+ }
26
+ end
27
+
28
+ result
29
+ end
30
+
31
+ ##
32
+ # Retrieve information about Disks
33
+ def get_vm_disk_info(vmid)
34
+ response, headers = __get_disk_info(vmid)
35
+
36
+ disks = []
37
+ response.css("Item").each do |entry|
38
+ # Pick only entries with node "HostResource"
39
+ resource = entry.css("rasd|HostResource").first
40
+ next unless resource
41
+
42
+ name = entry.css("rasd|ElementName").first
43
+ name = name.text unless name.nil?
44
+ capacity = resource.attribute("capacity").text
45
+
46
+ disks << {
47
+ :name => name,
48
+ :capacity => "#{capacity} MB"
49
+ }
50
+ end
51
+ disks
52
+ end
53
+
54
+ ##
55
+ # Set information about Disks
56
+ #
57
+ # Disks can be added, deleted or modified
58
+ def set_vm_disk_info(vmid, disk_info={})
59
+ get_response, headers = __get_disk_info(vmid)
60
+
61
+ if disk_info[:add]
62
+ data = add_disk(get_response, disk_info)
63
+ else
64
+ data = edit_disk(get_response, disk_info)
65
+ end
66
+
67
+ params = {
68
+ 'method' => :put,
69
+ 'command' => "/vApp/vm-#{vmid}/virtualHardwareSection/disks"
70
+ }
71
+ put_response, headers = send_request(params, data, "application/vnd.vmware.vcloud.rasdItemsList+xml")
72
+
73
+ task_id = headers[:location].gsub(/.*\/task\//, "")
74
+ task_id
75
+ end
76
+
77
+ ##
78
+ # Set VM CPUs
79
+ def set_vm_cpus(vmid, cpu_number)
80
+ params = {
81
+ 'method' => :get,
82
+ 'command' => "/vApp/vm-#{vmid}/virtualHardwareSection/cpu"
83
+ }
84
+
85
+ get_response, headers = send_request(params)
86
+
87
+ # Change attributes from the previous invocation
88
+ get_response.css("rasd|ElementName").first.content = "#{cpu_number} virtual CPU(s)"
89
+ get_response.css("rasd|VirtualQuantity").first.content = cpu_number
90
+
91
+ params['method'] = :put
92
+ put_response, headers = send_request(params, get_response.to_xml, "application/vnd.vmware.vcloud.rasdItem+xml")
93
+
94
+ task_id = headers[:location].gsub(/.*\/task\//, "")
95
+ task_id
96
+ end
97
+
98
+ ##
99
+ # Set VM RAM
100
+ def set_vm_ram(vmid, memory_size)
101
+ params = {
102
+ 'method' => :get,
103
+ 'command' => "/vApp/vm-#{vmid}/virtualHardwareSection/memory"
104
+ }
105
+
106
+ get_response, headers = send_request(params)
107
+
108
+ # Change attributes from the previous invocation
109
+ get_response.css("rasd|ElementName").first.content = "#{memory_size} MB of memory"
110
+ get_response.css("rasd|VirtualQuantity").first.content = memory_size
111
+
112
+ params['method'] = :put
113
+ put_response, headers = send_request(params, get_response.to_xml, "application/vnd.vmware.vcloud.rasdItem+xml")
114
+
115
+ task_id = headers[:location].gsub(/.*\/task\//, "")
116
+ task_id
117
+ end
118
+
119
+ ##
120
+ # Set VM Network Config
121
+ def set_vm_network_config(vmid, network_name, config={})
122
+ builder = Nokogiri::XML::Builder.new do |xml|
123
+ xml.NetworkConnectionSection(
124
+ "xmlns" => "http://www.vmware.com/vcloud/v1.5",
125
+ "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
126
+ xml['ovf'].Info "VM Network configuration"
127
+ xml.PrimaryNetworkConnectionIndex(config[:primary_index] || 0)
128
+ xml.NetworkConnection("network" => network_name, "needsCustomization" => true) {
129
+ xml.NetworkConnectionIndex(config[:network_index] || 0)
130
+ xml.IpAddress config[:ip] if config[:ip]
131
+ xml.IsConnected(config[:is_connected] || true)
132
+ xml.IpAddressAllocationMode config[:ip_allocation_mode] if config[:ip_allocation_mode]
133
+ }
134
+ }
135
+ end
136
+
137
+ params = {
138
+ 'method' => :put,
139
+ 'command' => "/vApp/vm-#{vmid}/networkConnectionSection"
140
+ }
141
+
142
+ response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.networkConnectionSection+xml")
143
+
144
+ task_id = headers[:location].gsub(/.*\/task\//, "")
145
+ task_id
146
+ end
147
+
148
+
149
+ ##
150
+ # Set VM Guest Customization Config
151
+ def set_vm_guest_customization(vmid, computer_name, config={})
152
+ builder = Nokogiri::XML::Builder.new do |xml|
153
+ xml.GuestCustomizationSection(
154
+ "xmlns" => "http://www.vmware.com/vcloud/v1.5",
155
+ "xmlns:ovf" => "http://schemas.dmtf.org/ovf/envelope/1") {
156
+ xml['ovf'].Info "VM Guest Customization configuration"
157
+ xml.Enabled config[:enabled] if config[:enabled]
158
+ xml.AdminPasswordEnabled config[:admin_passwd_enabled] if config[:admin_passwd_enabled]
159
+ xml.AdminPassword config[:admin_passwd] if config[:admin_passwd]
160
+ xml.CustomizationScript config[:customization_script] if config[:customization_script]
161
+ xml.ComputerName computer_name
162
+ }
163
+ end
164
+
165
+ params = {
166
+ 'method' => :put,
167
+ 'command' => "/vApp/vm-#{vmid}/guestCustomizationSection"
168
+ }
169
+
170
+ response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.guestCustomizationSection+xml")
171
+
172
+ task_id = headers[:location].gsub(/.*\/task\//, "")
173
+ task_id
174
+ end
175
+
176
+ ##
177
+ # Force a guest customization
178
+ def force_customization_vm(vmId)
179
+ builder = Nokogiri::XML::Builder.new do |xml|
180
+ xml.DeployVAppParams(
181
+ "xmlns" => "http://www.vmware.com/vcloud/v1.5",
182
+ "forceCustomization" => "true")
183
+ end
184
+
185
+ params = {
186
+ "method" => :post,
187
+ "command" => "/vApp/vm-#{vmId}/action/deploy"
188
+ }
189
+
190
+ response, headers = send_request(params, builder.to_xml, "application/vnd.vmware.vcloud.deployVAppParams+xml")
191
+ task_id = headers[:location].gsub(/.*\/task\//, "")
192
+ task_id
193
+ end
194
+
195
+ def rename_vm(vmId, name)
196
+ params = {
197
+ 'method' => :get,
198
+ 'command' => "/vApp/vm-#{vmId}"
199
+ }
200
+
201
+ response, headers = send_request(params)
202
+ response.css('Vm').attribute("name").content = name
203
+
204
+ params['method'] = :put
205
+ response, headers = send_request(params, response.to_xml,
206
+ "application/vnd.vmware.vcloud.vm+xml")
207
+ task_id = headers[:location].gsub(/.*\/task\//, "")
208
+ task_id
209
+ end
210
+
211
+ ##
212
+ # Fetch details about a given VM
213
+ def get_vm(vmId)
214
+ params = {
215
+ 'method' => :get,
216
+ 'command' => "/vApp/vm-#{vmId}"
217
+ }
218
+
219
+ response, headers = send_request(params)
220
+
221
+ vm_name = response.css('Vm').attribute("name")
222
+ vm_name = vm_name.text unless vm_name.nil?
223
+
224
+ status = convert_vapp_status(response.css('Vm').attribute("status").text)
225
+
226
+ os_desc = response.css('ovf|OperatingSystemSection ovf|Description').first.text
227
+
228
+ networks = {}
229
+ response.css('NetworkConnection').each do |network|
230
+ ip = network.css('IpAddress').first
231
+ ip = ip.text if ip
232
+
233
+ external_ip = network.css('ExternalIpAddress').first
234
+ external_ip = external_ip.text if external_ip
235
+
236
+ networks[network['network']] = {
237
+ :index => network.css('NetworkConnectionIndex').first.text,
238
+ :ip => ip,
239
+ :external_ip => external_ip,
240
+ :is_connected => network.css('IsConnected').first.text,
241
+ :mac_address => network.css('MACAddress').first.text,
242
+ :ip_allocation_mode => network.css('IpAddressAllocationMode').first.text
243
+ }
244
+ end
245
+
246
+ admin_password = response.css('GuestCustomizationSection AdminPassword').first
247
+ admin_password = admin_password.text if admin_password
248
+
249
+ guest_customizations = {
250
+ :enabled => response.css('GuestCustomizationSection Enabled').first.text,
251
+ :admin_passwd_enabled => response.css('GuestCustomizationSection AdminPasswordEnabled').first.text,
252
+ :admin_passwd_auto => response.css('GuestCustomizationSection AdminPasswordAuto').first.text,
253
+ :admin_passwd => admin_password,
254
+ :reset_passwd_required => response.css('GuestCustomizationSection ResetPasswordRequired').first.text,
255
+ :computer_name => response.css('GuestCustomizationSection ComputerName').first.text
256
+ }
257
+
258
+ { :id => vmId,
259
+ :vm_name => vm_name, :os_desc => os_desc, :networks => networks,
260
+ :guest_customizations => guest_customizations, :status => status
261
+ }
262
+ end
263
+
264
+ ##
265
+ # Friendly helper method to fetch a vApp by name
266
+ # - Organization object
267
+ # - Organization VDC Name
268
+ # - vApp Name
269
+ # - VM Name
270
+ def get_vm_by_name(organization, vdcName, vAppName, vmName)
271
+ result = nil
272
+
273
+ get_vapp_by_name(organization, vdcName, vAppName)[:vms_hash].each do |key, values|
274
+ if key.downcase == vmName.downcase
275
+ result = get_vm(values[:id])
276
+ end
277
+ end
278
+
279
+ result
280
+ end
281
+
282
+ ##
283
+ # Shutdown a given vm
284
+ def poweroff_vm(vmId)
285
+ builder = Nokogiri::XML::Builder.new do |xml|
286
+ xml.UndeployVAppParams(
287
+ "xmlns" => "http://www.vmware.com/vcloud/v1.5") {
288
+ xml.UndeployPowerAction 'powerOff'
289
+ }
290
+ end
291
+
292
+ params = {
293
+ 'method' => :post,
294
+ 'command' => "/vApp/vm-#{vmId}/action/undeploy"
295
+ }
296
+
297
+ response, headers = send_request(params, builder.to_xml,
298
+ "application/vnd.vmware.vcloud.undeployVAppParams+xml")
299
+ task_id = headers[:location].gsub(/.*\/task\//, "")
300
+ task_id
301
+ end
302
+
303
+ ##
304
+ # Suspend a given vm
305
+ def suspend_vm(vmId)
306
+ power_action(vmId, 'suspend', :vm)
307
+ end
308
+
309
+ ##
310
+ # reboot a given vm
311
+ # This will basically initial a guest OS reboot, and will only work if
312
+ # VMware-tools are installed on the underlying VMs.
313
+ # vShield Edge devices are not affected
314
+ def reboot_vm(vmId)
315
+ power_action(vmId, 'reboot', :vm)
316
+ end
317
+
318
+ ##
319
+ # reset a given vm
320
+ def reset_vm(vmId)
321
+ power_action(vmId, 'reset', :vm)
322
+ end
323
+
324
+ ##
325
+ # Boot a given vm
326
+ def poweron_vm(vmId)
327
+ power_action(vmId, 'powerOn', :vm)
328
+ end
329
+
330
+ private
331
+ def add_disk(source_xml, disk_info)
332
+ disks_count = source_xml.css("Item").css("rasd|HostResource").count
333
+
334
+ # FIXME: This is a hack, but dealing with nokogiri APIs can be quite
335
+ # frustrating sometimes...
336
+ sibling = source_xml.css("Item").first
337
+ new_disk = Nokogiri::XML::Node.new "PLACEHOLDER", sibling.parent
338
+ sibling.add_next_sibling(new_disk)
339
+ result = source_xml.to_xml
340
+
341
+ result.gsub("<PLACEHOLDER/>", """
342
+ <Item>
343
+ <rasd:AddressOnParent>#{disks_count}</rasd:AddressOnParent>
344
+ <rasd:Description>Hard disk</rasd:Description>
345
+ <rasd:ElementName>Hard disk #{disks_count + 1}</rasd:ElementName>
346
+ <rasd:HostResource
347
+ xmlns:ns12=\"http://www.vmware.com/vcloud/v1.5\"
348
+ ns12:capacity=\"#{disk_info[:disk_size]}\"
349
+ ns12:busSubType=\"lsilogic\"
350
+ ns12:busType=\"6\"/>
351
+ <rasd:InstanceID>200#{disks_count}</rasd:InstanceID>
352
+ <rasd:Parent>1</rasd:Parent>
353
+ <rasd:ResourceType>17</rasd:ResourceType>
354
+ </Item>""")
355
+ end
356
+
357
+ def edit_disk(source_xml, disk_info)
358
+ changed = false
359
+
360
+ source_xml.css("Item").each do |entry|
361
+ # Pick only entries with node "HostResource"
362
+ resource = entry.css("rasd|HostResource").first
363
+ next unless resource
364
+
365
+ name = entry.css("rasd|ElementName").first
366
+ name = name.text unless name.nil?
367
+ next unless name == disk_info[:disk_name]
368
+
369
+ changed = true
370
+
371
+ if disk_info[:delete]
372
+ entry.remove
373
+ else
374
+ # Set disk size
375
+ resource.attribute("capacity").content = disk_info[:disk_size]
376
+ end
377
+ break
378
+ end
379
+
380
+ unless changed
381
+ @logger.warn "Disk #{disk_info[:disk_name]} not found."
382
+ raise WrongItemIDError, "Disk #{disk_info[:disk_name]} not found."
383
+ end
384
+ source_xml.to_xml
385
+ end
386
+
387
+ def __get_disk_info(vmid)
388
+ params = {
389
+ 'method' => :get,
390
+ 'command' => "/vApp/vm-#{vmid}/virtualHardwareSection/disks"
391
+ }
392
+
393
+ send_request(params)
394
+ end
395
+ end
396
+ end
@@ -0,0 +1,3 @@
1
+ module VCloudClient
2
+ VERSION = "1.0.0"
3
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vcloud-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.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: 2013-07-19 00:00:00.000000000 Z
11
+ date: 2013-11-29 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
- version: 1.6.0
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
- version: 1.6.0
26
+ version: 1.5.10
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rest-client
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 1.1.1
61
+ version: 1.2.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
- version: 1.1.1
68
+ version: 1.2.0
69
69
  description: Ruby bindings to create, list and manage vCloud servers
70
70
  email:
71
71
  - stefano.tortarolo@gmail.com
@@ -77,6 +77,15 @@ files:
77
77
  - README.md
78
78
  - LICENSE
79
79
  - lib/vcloud-rest/connection.rb
80
+ - lib/vcloud-rest/vcloud/catalog.rb
81
+ - lib/vcloud-rest/vcloud/network.rb
82
+ - lib/vcloud-rest/vcloud/org.rb
83
+ - lib/vcloud-rest/vcloud/ovf.rb
84
+ - lib/vcloud-rest/vcloud/vapp.rb
85
+ - lib/vcloud-rest/vcloud/vapp_networking.rb
86
+ - lib/vcloud-rest/vcloud/vdc.rb
87
+ - lib/vcloud-rest/vcloud/vm.rb
88
+ - lib/vcloud-rest/version.rb
80
89
  homepage: https://github.com/astratto/vcloud-rest
81
90
  licenses:
82
91
  - Apache 2.0
@@ -97,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
106
  version: '0'
98
107
  requirements: []
99
108
  rubyforge_project:
100
- rubygems_version: 2.0.3
109
+ rubygems_version: 2.1.11
101
110
  signing_key:
102
111
  specification_version: 4
103
112
  summary: Unofficial ruby bindings for VMWare vCloud's API