ruby_vcloud_sdk 0.5.1 → 0.6.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.
Files changed (29) hide show
  1. data/README.md +182 -3
  2. data/lib/ruby_vcloud_sdk/catalog.rb +18 -13
  3. data/lib/ruby_vcloud_sdk/client.rb +10 -1
  4. data/lib/ruby_vcloud_sdk/connection/connection.rb +1 -1
  5. data/lib/ruby_vcloud_sdk/disk.rb +1 -13
  6. data/lib/ruby_vcloud_sdk/infrastructure.rb +11 -1
  7. data/lib/ruby_vcloud_sdk/internal_disk.rb +12 -0
  8. data/lib/ruby_vcloud_sdk/network.rb +8 -3
  9. data/lib/ruby_vcloud_sdk/right_record.rb +12 -0
  10. data/lib/ruby_vcloud_sdk/vapp.rb +85 -0
  11. data/lib/ruby_vcloud_sdk/vdc.rb +61 -41
  12. data/lib/ruby_vcloud_sdk/vm.rb +233 -0
  13. data/lib/ruby_vcloud_sdk/xml/constants.rb +10 -0
  14. data/lib/ruby_vcloud_sdk/xml/wrapper.rb +10 -1
  15. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk.rb +1 -1
  16. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_ranges.rb +16 -0
  17. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_scope.rb +4 -0
  18. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_config_section.rb +4 -6
  19. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_vdc_network.rb +0 -4
  20. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/product_section.rb +35 -0
  21. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/product_section_list.rb +14 -0
  22. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/query_result_records.rb +4 -0
  23. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/virtual_hardware_section.rb +6 -4
  24. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vm.rb +31 -47
  25. data/lib/ruby_vcloud_sdk/xml/wrapper_classes.rb +2 -0
  26. data/lib/ruby_vcloud_sdk/xml/xml_templates/NetworkConfig.xml +1 -6
  27. data/lib/ruby_vcloud_sdk/xml/xml_templates/ProductSectionList.xml +8 -1
  28. metadata +29 -13
  29. checksums.yaml +0 -7
data/README.md CHANGED
@@ -33,7 +33,9 @@ Copyright (c) VMware, Inc.
33
33
  throws:
34
34
  'RestClient::BadRequest' for un-expected errors
35
35
 
36
- delete_catalog
36
+ delete_catalog_by_name
37
+ parameters:
38
+ name (String): name of catalog
37
39
  returns: nil
38
40
  throws:
39
41
  'ObjectNotFoundError' when catalog with the name does not exist
@@ -110,7 +112,38 @@ Copyright (c) VMware, Inc.
110
112
  throws:
111
113
  'ObjectNotFoundError' when disk with the name does not exist
112
114
  'RestClient::BadRequest' for un-expected errors
113
-
115
+
116
+ create_disk
117
+ parameters:
118
+ name (String): name of disk
119
+ size_mb (Integer): disk size in megabyte
120
+ vm (VCloudSdk::VM, optional): VM that to add disk locality to
121
+ bus_type (String, optional): bus type of disk, defaults to "scsi"
122
+ bus_sub_type (String, optional): bus sub type of disk, defaults to "lsilogic"
123
+ returns: Disk object created
124
+ throws:
125
+ 'CloudError' when size_mb is less than or equal to 0
126
+ 'CloudError' when bus_type is invalid
127
+ 'CloudError' when bus_sub_type is invalid
128
+ 'RestClient::BadRequest' for un-expected errors
129
+
130
+ delete_disk_by_name
131
+ parameters:
132
+ name (String): name of disk
133
+ returns: nil
134
+ throws:
135
+ 'CloudError' when more than one disks matching the name exist
136
+ 'CloudError' when disk is attached to vm
137
+ 'RestClient::BadRequest' for un-expected errors
138
+
139
+ delete_all_disks_by_name
140
+ parameters:
141
+ name (String): name of disk
142
+ returns: nil
143
+ throws:
144
+ 'CloudError' when any disk deletion failure occurs
145
+ 'RestClient::BadRequest' for un-expected errors
146
+
114
147
  Catalog
115
148
 
116
149
  items
@@ -134,7 +167,10 @@ Copyright (c) VMware, Inc.
134
167
  throws:
135
168
  'RestClient::BadRequest' for un-expected errors
136
169
 
137
- delete_item
170
+ delete_item_by_name_and_type
171
+ parameters:
172
+ name (String): name of item
173
+ type (String, optional): type of item - "application/vnd.vmware.vcloud.vAppTemplate+xml" or "application/vnd.vmware.vcloud.media+xml"
138
174
  returns: nil
139
175
  throws:
140
176
  'ObjectNotFoundError' when an item matching the name and type is not found
@@ -152,11 +188,45 @@ Copyright (c) VMware, Inc.
152
188
  'ObjectNotFoundError' when storage profile with the name does not exist
153
189
  'RestClient::BadRequest' for un-expected errors
154
190
 
191
+ find_media_by_name
192
+ parameters:
193
+ name (String): name of media
194
+ returns: media catalog item matching name
195
+ throws:
196
+ 'ObjectNotFoundError' when an item matching the name and type is not found
197
+ 'RestClient::BadRequest' for un-expected error
198
+
155
199
  upload_vapp_template
200
+ parameters:
201
+ vdc_name (String): name of vdc
202
+ template_name (String): name of vapp template
203
+ directory (String): path of vapp template directory
204
+ storage_profile_name (String, optional): name of storage profile to upload vapp template to
205
+ returns: vapp template catalog item uploaded
206
+ throws:
207
+ 'CloudError' when vapp template matching name already exists
208
+ 'ApiTimeoutError' if uploading vapp files times out
209
+ 'CloudError' when uploading vapp template task is not successful
210
+ 'RestClient::BadRequest' for un-expected error
156
211
 
157
212
  find_vapp_template_by_name
213
+ parameters:
214
+ name (String): name of vapp template
215
+ returns: vapp template catalog item matching name
216
+ throws:
217
+ 'ObjectNotFoundError' when an item matching the name and type is not found
218
+ 'RestClient::BadRequest' for un-expected error
158
219
 
159
220
  instantiate_vapp_template
221
+ parameters:
222
+ template_name (String): name of vapp template
223
+ vdc_name (String): name of vdc
224
+ vapp_name (String): name of vapp
225
+ description (String, optional): description of vapp template
226
+ returns: vapp object instantiated
227
+ throws:
228
+ 'ApiError' when instantiating vapp template task is not successful
229
+ 'RestClient::BadRequest' for un-expected error
160
230
 
161
231
  Network
162
232
 
@@ -222,8 +292,70 @@ Copyright (c) VMware, Inc.
222
292
  'CloudError' when VApp is in status of 'POWERED_ON' and can not be recomposed
223
293
  'RestClient::BadRequest' for un-expected errors
224
294
 
295
+ list_networks
296
+ returns: array of network names
297
+ throws:
298
+ 'RestClient::BadRequest' for un-expected errors
299
+
300
+ add_network_by_name
301
+ parameters:
302
+ network_name (String): name of network in vdc org to add to vapp
303
+ vapp_net_name (String, optional): what to name the network of the vapp.
304
+ Default to network_name
305
+ fence_mode (String, optional): Fencing allows identical virtual machines in different
306
+ vApps to be powered on without conflict by isolating the MAC and IP addresses of the
307
+ virtual machines. Available options are "bridged", "isolated" and "natRouted". Default
308
+ to "bridged".
309
+ returns: task object
310
+ throws:
311
+ 'CloudError' when invalid fence mode is specified
312
+ 'ObjectNotFoundError' when network with the name does not exist
313
+ 'RestClient::BadRequest' for un-expected errors
314
+
315
+ delete_network_by_name
316
+ parameters:
317
+ name (String): name of network to delete
318
+ returns: nil
319
+ throws:
320
+ 'ObjectNotFoundError' when network with the name does not exist
321
+ 'RestClient::BadRequest' for un-expected errors
322
+
225
323
  VM
226
324
 
325
+ vcpu:
326
+ returns: number of virtual cpus of VM
327
+ throws:
328
+ 'CloudError' when information of number of virtual cpus of VM is unavailable
329
+ 'RestClient::BadRequest' for un-expected errors
330
+
331
+ vcpu=
332
+ parameters:
333
+ The virtual cpu count.
334
+ returns: VM object
335
+ throws:
336
+ 'CloudError' when the cpu count is less than or equal to 0
337
+ 'RestClient::BadRequest' for un-expected errors
338
+
339
+ memory
340
+ returns: integer number, the size of memory in megabyte
341
+ throws:
342
+ 'ApiError' when AllocationUnits of memory is in unexpected form
343
+ 'CloudError' when size of memory is zero
344
+ 'RestClient::BadRequest' for un-expected errors
345
+
346
+ memory=
347
+ parameters:
348
+ The size of memory in megabyte.
349
+ returns: VM object
350
+ throws:
351
+ 'CloudError' when the memory size is less than or equal to 0
352
+ 'RestClient::BadRequest' for un-expected errors
353
+
354
+ list_networks
355
+ returns: array of network names
356
+ throws:
357
+ 'RestClient::BadRequest' for un-expected errors
358
+
227
359
  independent_disks
228
360
  returns: array of disk objects
229
361
  throws:
@@ -280,6 +412,53 @@ Copyright (c) VMware, Inc.
280
412
  'ObjectNotFoundError' if when media with the name does not exist
281
413
  'RestClient::BadRequest' for un-expected errors
282
414
 
415
+ add_nic
416
+ parameters:
417
+ network_name (String): name of network to add NIC
418
+ ip_addressing_mode (String, optional): available options are "NONE", "MANUAL",
419
+ "POOL" and "DHCP". Default to "POOL"
420
+ ip (String, optional): IP address for "MANUAL" IP Mode
421
+ return: task object
422
+ throws:
423
+ 'CloudError' if when ip_addressing_mode is invalid
424
+ 'CloudError' if ip is not specified in "MANUAL" ip_addressing_mode
425
+ 'CloudError' if vm is powered on
426
+ 'ObjectNotFoundError' if network is not added to VM's parent VApp
427
+ 'RestClient::BadRequest' for un-expected errors
428
+
429
+ product_section_properties
430
+ returns:
431
+ array of hash values representing properties of product section of VM
432
+ empty array if VM does not have product section
433
+ throws:
434
+ 'RestClient::BadRequest' for un-expected errors
435
+
436
+ product_section_properties=
437
+ parameters:
438
+ properties (array of hash values): properties of product section of VM
439
+ returns: VM object
440
+ throws:
441
+ 'RestClient::BadRequest' for un-expected errors
442
+ note:
443
+ Rebooting VM is needed to reflect product section changes
444
+
445
+ internal_disks
446
+ returns: array of internal disk objects
447
+ throws:
448
+ 'RestClient::BadRequest' for un-expected errors
449
+
450
+ create_internal_disk
451
+ parameters:
452
+ capcity (Integer): disk size in megabyte
453
+ bus_type (String, optional): bus type of disk, defaults to "scsi"
454
+ bus_sub_type (String, optional): bus sub type of disk, defaults to "lsilogic"
455
+ returns: InternalDisk object created
456
+ throws:
457
+ 'CloudError' when capcity is less than or equal to 0
458
+ 'CloudError' when bus_type is invalid
459
+ 'CloudError' when bus_sub_type is invalid
460
+ 'RestClient::BadRequest' for un-expected errors
461
+
283
462
  VdcStorageProfile
284
463
 
285
464
  available_storage
@@ -51,7 +51,7 @@ module VCloudSdk
51
51
  end
52
52
  end
53
53
 
54
- def delete_item(name, item_type = nil)
54
+ def delete_item_by_name_and_type(name, item_type = nil)
55
55
  link = find_item_link(name)
56
56
  item = VCloudSdk::CatalogItem.new(@session, link)
57
57
 
@@ -97,15 +97,21 @@ module VCloudSdk
97
97
  media = upload_media_file media, media_file
98
98
 
99
99
  add_item(media)
100
+ find_media_by_name(media_name)
101
+ end
102
+
103
+ def find_media_by_name(name)
104
+ find_item(name, Xml::MEDIA_TYPE[:MEDIA])
100
105
  end
101
106
 
102
107
  def upload_vapp_template(
103
- vdc_name,
108
+ vdc_name,
104
109
  template_name,
105
110
  directory,
106
111
  storage_profile_name = nil)
107
112
  if item_exists?(template_name)
108
- fail "vApp template '#{template_name}' already exists in catalog #{name}"
113
+ fail CloudError,
114
+ "vApp template '#{template_name}' already exists in catalog #{name}"
109
115
  end
110
116
 
111
117
  vdc = find_vdc_by_name vdc_name
@@ -123,6 +129,7 @@ module VCloudSdk
123
129
  Template #{template_name} uploaded, adding to catalog #{name}.
124
130
  }
125
131
  add_item(vapp_template)
132
+ find_vapp_template_by_name(template_name)
126
133
  end
127
134
 
128
135
  def find_vapp_template_by_name(name)
@@ -156,18 +163,16 @@ module VCloudSdk
156
163
  private
157
164
 
158
165
  def add_item(item)
159
- catalog_item = create_catalog_item_payload(item)
166
+ payload = create_catalog_item_payload(item)
160
167
  catalog_name = name
161
- catalog_item_name = catalog_item.name
168
+ catalog_item_name = item.name
162
169
  Config.logger.info "Adding #{catalog_item_name} to catalog #{catalog_name}"
163
170
  connection.post(admin_xml.add_item_link,
164
- catalog_item,
171
+ payload,
165
172
  Xml::ADMIN_MEDIA_TYPE[:CATALOG_ITEM])
166
173
  Config.logger.info %Q{
167
- catalog_item #{catalog_item_name} added to catalog #{catalog_name}:
168
- #{catalog_item.to_s}
174
+ catalog_item #{catalog_item_name} added to catalog #{catalog_name}
169
175
  }
170
- catalog_item
171
176
  end
172
177
 
173
178
  def delete_item_by_link(link)
@@ -237,10 +242,10 @@ module VCloudSdk
237
242
  end
238
243
 
239
244
  def create_catalog_item_payload(item)
240
- catalog_item = Xml::WrapperFactory.create_instance(Xml::XML_TYPE[:CATALOGITEM])
241
- catalog_item.name = item.name
242
- catalog_item.entity = item
243
- catalog_item
245
+ Xml::WrapperFactory.create_instance(Xml::XML_TYPE[:CATALOGITEM]).tap do |payload|
246
+ payload.name = item.name
247
+ payload.entity = item
248
+ end
244
249
  end
245
250
 
246
251
  def validate_vapp_template_tasks(vapp_template)
@@ -2,6 +2,7 @@ require_relative "vdc"
2
2
  require_relative "catalog"
3
3
  require_relative "session"
4
4
  require_relative "infrastructure"
5
+ require_relative "right_record"
5
6
 
6
7
  module VCloudSdk
7
8
 
@@ -31,12 +32,20 @@ module VCloudSdk
31
32
  find_catalog_by_name name
32
33
  end
33
34
 
34
- def delete_catalog(name)
35
+ def delete_catalog_by_name(name)
35
36
  catalog = find_catalog_by_name(name)
36
37
  catalog.delete_all_items
37
38
  connection.delete("/api/admin/catalog/#{catalog.id}")
38
39
  nil
39
40
  end
41
+
42
+ def right_records
43
+ right_records = connection.get("/api/admin/rights/query").right_records
44
+
45
+ right_records.map do |right_record|
46
+ VCloudSdk::RightRecord.new(right_record)
47
+ end
48
+ end
40
49
  end
41
50
 
42
51
  end
@@ -142,7 +142,7 @@ module VCloudSdk
142
142
  }
143
143
  @login_url = default_login_url
144
144
  else
145
- # Typically url_content is the full URL such as "https://10.146.21.135/api/sessions"
145
+ # Typically url_content is the full URL such as "https://10.147.0.0/api/sessions"
146
146
  # In this case we need to trim the beginning of the url string
147
147
  @login_url = get_nested_resource(url_node.login_url.content)
148
148
  end
@@ -9,7 +9,7 @@ module VCloudSdk
9
9
  extend Forwardable
10
10
  def_delegators :entity_xml,
11
11
  :name, :bus_type, :bus_sub_type,
12
- :size_mb, :status
12
+ :capacity, :status
13
13
 
14
14
  def initialize(session, link)
15
15
  @session = session
@@ -32,18 +32,6 @@ module VCloudSdk
32
32
  VCloudSdk::VM.new(@session, vm_link.href)
33
33
  end
34
34
 
35
- def delete
36
- fail CloudError,
37
- "Disk '#{name}' of link #{href} is attached to VM '#{vm.name}'" if attached?
38
-
39
- disk_name = name
40
- task = connection.delete(entity_xml.remove_link.href)
41
- task = monitor_task(task)
42
-
43
- Config.logger.info "Disk '#{disk_name}' of link #{@link} is deleted successfully"
44
- task
45
- end
46
-
47
35
  private
48
36
 
49
37
  def vm_reference
@@ -11,7 +11,17 @@ module VCloudSdk
11
11
  def find_vdc_by_name(name)
12
12
  vdc_link = @session.org.vdc_link(name)
13
13
  fail ObjectNotFoundError, "VDC #{name} not found" unless vdc_link
14
- VCloudSdk::VDC.new(@session, connection.get(vdc_link))
14
+ VCloudSdk::VDC.new(@session, vdc_link)
15
+ end
16
+
17
+ def find_network_by_name(name)
18
+ @session.org.networks.each do |network_link|
19
+ if network_link.name == name
20
+ return VCloudSdk::Network.new(@session, network_link)
21
+ end
22
+ end
23
+
24
+ fail ObjectNotFoundError, "Network '#{name}' is not found"
15
25
  end
16
26
 
17
27
  def catalogs
@@ -0,0 +1,12 @@
1
+ module VCloudSdk
2
+
3
+ class InternalDisk
4
+ attr_reader :capacity, :bus_type, :bus_sub_type
5
+
6
+ def initialize(entity_xml)
7
+ @capacity = entity_xml.host_resource.attribute("capacity").to_s.to_i
8
+ @bus_type = entity_xml.host_resource.attribute("busType").to_s
9
+ @bus_sub_type = entity_xml.host_resource.attribute("busSubType").to_s
10
+ end
11
+ end
12
+ end
@@ -5,17 +5,22 @@ module VCloudSdk
5
5
  class Network
6
6
  include Infrastructure
7
7
 
8
+ extend Forwardable
9
+ def_delegator :entity_xml, :name
10
+
8
11
  def initialize(session, link)
9
12
  @session = session
10
13
  @link = link
11
14
  end
12
15
 
13
- def name
14
- entity_xml.name
16
+ def href
17
+ @link
15
18
  end
16
19
 
17
20
  def ip_ranges
18
- entity_xml.ip_ranges
21
+ entity_xml
22
+ .ip_scope
23
+ .ip_ranges
19
24
  .ranges
20
25
  .reduce(IpRanges.new) do |result, i|
21
26
  result + IpRanges.new("#{i.start_address}-#{i.end_address}")
@@ -0,0 +1,12 @@
1
+ module VCloudSdk
2
+
3
+ class RightRecord
4
+ attr_reader :name, :category
5
+
6
+ def initialize(right_record_xml_obj)
7
+ @right_record_xml_obj = right_record_xml_obj
8
+ @name = right_record_xml_obj[:name]
9
+ @category = right_record_xml_obj[:category]
10
+ end
11
+ end
12
+ end
@@ -86,6 +86,57 @@ module VCloudSdk
86
86
  self
87
87
  end
88
88
 
89
+ def list_networks
90
+ entity_xml
91
+ .network_config_section
92
+ .network_configs
93
+ .map { |network_config| network_config.network_name }
94
+ end
95
+
96
+ def add_network_by_name(
97
+ network_name,
98
+ vapp_net_name = nil,
99
+ fence_mode = Xml::FENCE_MODES[:BRIDGED])
100
+ fail CloudError,
101
+ "Invalid fence mode '#{fence_mode}'" unless Xml::FENCE_MODES
102
+ .each_value
103
+ .any? { |m| m == fence_mode }
104
+ network = find_network_by_name(network_name)
105
+ new_vapp_net_name = vapp_net_name.nil? ? network.name : vapp_net_name
106
+ network_config_param = network_config_param(
107
+ network,
108
+ new_vapp_net_name,
109
+ fence_mode)
110
+ payload = entity_xml.network_config_section
111
+ payload.add_network_config(network_config_param)
112
+ task = connection.put(payload.href,
113
+ payload,
114
+ Xml::MEDIA_TYPE[:NETWORK_CONFIG_SECTION])
115
+ monitor_task(task)
116
+ end
117
+
118
+ def delete_network_by_name(name)
119
+ unless list_networks.any? { |network_name| network_name == name}
120
+ fail ObjectNotFoundError,
121
+ "Network '#{name}' is not found"
122
+ end
123
+
124
+ fail CloudError,
125
+ %Q{
126
+ Network '#{name}' is being used by one or more VMs.
127
+ Please remove the NIC(s) in VM(s) that are in use of the network.
128
+ Check logs for details.
129
+ } if network_in_use?(name)
130
+
131
+ payload = entity_xml.network_config_section
132
+ payload.delete_network_config(name)
133
+ task = connection.put(payload.href,
134
+ payload,
135
+ Xml::MEDIA_TYPE[:NETWORK_CONFIG_SECTION])
136
+ monitor_task(task)
137
+ nil
138
+ end
139
+
89
140
  private
90
141
 
91
142
  def recompose_from_vapp_template_param(template)
@@ -118,5 +169,39 @@ module VCloudSdk
118
169
  params.add_delete_item vm.href
119
170
  end
120
171
  end
172
+
173
+ def network_config_param(
174
+ network,
175
+ vapp_net_name,
176
+ fence_mode)
177
+ Xml::WrapperFactory.create_instance("NetworkConfig").tap do |params|
178
+ network_entity_xml = connection.get(network.href)
179
+ params.ip_scope.tap do |ip_scope|
180
+ net_ip_scope = network_entity_xml.ip_scope
181
+ ip_scope.is_inherited = net_ip_scope.is_inherited?
182
+ ip_scope.gateway = net_ip_scope.gateway
183
+ ip_scope.netmask = net_ip_scope.netmask
184
+ ip_scope.ip_ranges.add_ranges(net_ip_scope.ip_ranges.ranges)
185
+ end
186
+ params.fence_mode = fence_mode
187
+ params.parent_network["name"] = network_entity_xml["name"]
188
+ params.parent_network["href"] = network_entity_xml["href"]
189
+ params["networkName"] = vapp_net_name
190
+ end
191
+ end
192
+
193
+ def network_in_use?(network_name)
194
+ network_in_use = false
195
+ vms.each do |vm|
196
+ vm.list_networks.each do |net_name|
197
+ if net_name == network_name
198
+ network_in_use = true
199
+ Config.logger.error "VM #{vm.name} is using network #{network_name}"
200
+ end
201
+ end
202
+ end
203
+
204
+ network_in_use
205
+ end
121
206
  end
122
207
  end