vcloud-rest 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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