ruby_vcloud_sdk 0.5.1 → 0.6.0

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