ruby_vcloud_sdk 0.4.8 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +296 -0
  3. data/lib/ruby_vcloud_sdk.rb +0 -4
  4. data/lib/ruby_vcloud_sdk/catalog.rb +377 -0
  5. data/lib/ruby_vcloud_sdk/catalog_item.rb +26 -0
  6. data/lib/ruby_vcloud_sdk/client.rb +25 -882
  7. data/lib/ruby_vcloud_sdk/config.rb +1 -7
  8. data/lib/ruby_vcloud_sdk/connection/connection.rb +114 -54
  9. data/lib/ruby_vcloud_sdk/cpu.rb +11 -0
  10. data/lib/ruby_vcloud_sdk/disk.rb +55 -0
  11. data/lib/ruby_vcloud_sdk/edge_gateway.rb +32 -0
  12. data/lib/ruby_vcloud_sdk/infrastructure.rb +135 -0
  13. data/lib/ruby_vcloud_sdk/ip_ranges.rb +95 -0
  14. data/lib/ruby_vcloud_sdk/memory.rb +11 -0
  15. data/lib/ruby_vcloud_sdk/network.rb +32 -0
  16. data/lib/ruby_vcloud_sdk/powerable.rb +78 -0
  17. data/lib/ruby_vcloud_sdk/resources.rb +13 -0
  18. data/lib/ruby_vcloud_sdk/session.rb +46 -0
  19. data/lib/ruby_vcloud_sdk/vapp.rb +122 -0
  20. data/lib/ruby_vcloud_sdk/vdc.rb +210 -0
  21. data/lib/ruby_vcloud_sdk/vdc_storage_profile.rb +23 -0
  22. data/lib/ruby_vcloud_sdk/version.rb +1 -1
  23. data/lib/ruby_vcloud_sdk/vm.rb +132 -0
  24. data/lib/ruby_vcloud_sdk/xml/constants.rb +6 -4
  25. data/lib/ruby_vcloud_sdk/xml/wrapper.rb +109 -30
  26. data/lib/ruby_vcloud_sdk/xml/wrapper_classes.rb +45 -2
  27. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_catalog.rb +13 -4
  28. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/allocated_ip_addresses.rb +9 -0
  29. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/catalog_item.rb +6 -14
  30. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk.rb +24 -14
  31. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_attach_or_detach_params.rb +0 -2
  32. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_create_params.rb +1 -3
  33. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/edge_gateway.rb +13 -0
  34. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/gateway_interface.rb +22 -0
  35. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/hard_disk_item_wrapper.rb +4 -4
  36. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_address.rb +10 -0
  37. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_range.rb +13 -0
  38. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_ranges.rb +9 -0
  39. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_scope.rb +6 -32
  40. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/item.rb +1 -7
  41. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/link.rb +14 -0
  42. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media.rb +4 -20
  43. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media_insert_or_eject_params.rb +1 -3
  44. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection_section.rb +0 -4
  45. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/nic_item_wrapper.rb +0 -2
  46. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org.rb +44 -0
  47. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_vdc_network.rb +11 -3
  48. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/query_result_records.rb +14 -0
  49. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/recompose_vapp_params.rb +42 -0
  50. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/session.rb +5 -5
  51. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/supported_versions.rb +19 -0
  52. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/task.rb +1 -1
  53. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/upload_vapp_template_params.rb +2 -4
  54. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp.rb +13 -22
  55. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp_template.rb +0 -2
  56. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vcloud.rb +5 -3
  57. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc.rb +72 -15
  58. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/virtual_hardware_section.rb +8 -6
  59. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vm.rb +29 -25
  60. data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vms.rb +12 -0
  61. data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalog.xml +6 -1
  62. data/lib/ruby_vcloud_sdk/xml/xml_templates/RecomposeVAppParams.xml +16 -1
  63. metadata +116 -233
  64. data/README +0 -1
  65. data/Rakefile +0 -50
  66. data/lib/ruby_vcloud_sdk/util.rb +0 -21
  67. data/spec/assets/admin_org_response.xml +0 -75
  68. data/spec/assets/catalog_add_item_response.xml +0 -8
  69. data/spec/assets/catalog_add_vapp_request.xml +0 -5
  70. data/spec/assets/catalog_item_added_response.xml +0 -19
  71. data/spec/assets/catalog_response.xml +0 -19
  72. data/spec/assets/existing_media_busy_response.xml +0 -19
  73. data/spec/assets/existing_media_catalog_item.xml +0 -8
  74. data/spec/assets/existing_media_delete_task_done.xml +0 -6
  75. data/spec/assets/existing_media_done_response.xml +0 -11
  76. data/spec/assets/existing_vapp_resolver_response.xml +0 -3
  77. data/spec/assets/existing_vapp_template_catalog_resolver_response.xml +0 -3
  78. data/spec/assets/existing_vapp_template_instantiate_response.xml +0 -20
  79. data/spec/assets/existing_vapp_template_instantiate_task_error_response.xml +0 -7
  80. data/spec/assets/existing_vapp_template_instantiate_task_start_response.xml +0 -7
  81. data/spec/assets/existing_vapp_template_instantiate_task_success_response.xml +0 -7
  82. data/spec/assets/existing_vapp_template_item_response.xml +0 -8
  83. data/spec/assets/existing_vapp_template_ready_response.xml +0 -79
  84. data/spec/assets/finalize_upload_task_done_response.xml +0 -7
  85. data/spec/assets/finalize_upload_task_response.xml +0 -7
  86. data/spec/assets/indy_disk_attach_request.xml +0 -3
  87. data/spec/assets/indy_disk_attach_task.xml +0 -6
  88. data/spec/assets/indy_disk_attach_task_error.xml +0 -6
  89. data/spec/assets/indy_disk_create_error.xml +0 -1
  90. data/spec/assets/indy_disk_create_request.xml +0 -4
  91. data/spec/assets/indy_disk_create_response.xml +0 -19
  92. data/spec/assets/indy_disk_delete_task.xml +0 -6
  93. data/spec/assets/indy_disk_detach_request.xml +0 -3
  94. data/spec/assets/indy_disk_detach_task.xml +0 -6
  95. data/spec/assets/indy_disk_response.xml +0 -11
  96. data/spec/assets/instantiated_suspended_vapp_response.xml +0 -209
  97. data/spec/assets/instantiated_vapp_delelete_done_task.xml +0 -5
  98. data/spec/assets/instantiated_vapp_delelete_running_task.xml +0 -6
  99. data/spec/assets/instantiated_vapp_network_config_add_network_request.xml +0 -36
  100. data/spec/assets/instantiated_vapp_network_config_modify_network_task_success.xml +0 -6
  101. data/spec/assets/instantiated_vapp_network_config_remove_network_request.xml +0 -6
  102. data/spec/assets/instantiated_vapp_network_config_section_response.xml +0 -17
  103. data/spec/assets/instantiated_vapp_off_response.xml +0 -206
  104. data/spec/assets/instantiated_vapp_on_response.xml +0 -205
  105. data/spec/assets/instantiated_vapp_power_task_running.xml +0 -6
  106. data/spec/assets/instantiated_vapp_power_task_success.xml +0 -6
  107. data/spec/assets/instantiated_vapp_response.xml +0 -205
  108. data/spec/assets/instantiated_vm_change_task_running.xml +0 -6
  109. data/spec/assets/instantiated_vm_change_task_success.xml +0 -6
  110. data/spec/assets/instantiated_vm_cpu_response.xml +0 -11
  111. data/spec/assets/instantiated_vm_insert_media_task_done.xml +0 -6
  112. data/spec/assets/instantiated_vm_memory_response.xml +0 -11
  113. data/spec/assets/instantiated_vm_modify_task_running.xml +0 -6
  114. data/spec/assets/instantiated_vm_modify_task_success.xml +0 -5
  115. data/spec/assets/instantiated_vm_network_section_response.xml +0 -11
  116. data/spec/assets/instantiated_vm_response.xml +0 -149
  117. data/spec/assets/media_add_to_catalog_request.xml +0 -5
  118. data/spec/assets/media_add_to_catalog_response.xml +0 -8
  119. data/spec/assets/media_delete_task_done.xml +0 -6
  120. data/spec/assets/media_upload_pending_response.xml +0 -13
  121. data/spec/assets/media_upload_request.xml +0 -2
  122. data/spec/assets/metadata_set_request.xml +0 -3
  123. data/spec/assets/metadata_set_task_done.xml +0 -6
  124. data/spec/assets/org_network_response.xml +0 -22
  125. data/spec/assets/reconfigure_vm_request.xml +0 -133
  126. data/spec/assets/reconfigure_vm_task.xml +0 -8
  127. data/spec/assets/session.xml +0 -7
  128. data/spec/assets/test-config.yml +0 -38
  129. data/spec/assets/undeploy_params.xml +0 -1
  130. data/spec/assets/vapp_template_catalog_resolver_response.xml +0 -3
  131. data/spec/assets/vapp_template_delelete_done_task.xml +0 -5
  132. data/spec/assets/vapp_template_delelete_running_task.xml +0 -6
  133. data/spec/assets/vapp_template_instantiate_request.xml +0 -8
  134. data/spec/assets/vapp_template_instantiate_with_locality_request.xml +0 -14
  135. data/spec/assets/vapp_template_no_disk_response.xml +0 -27
  136. data/spec/assets/vapp_template_ready_response.xml +0 -79
  137. data/spec/assets/vapp_template_upload_complete.xml +0 -28
  138. data/spec/assets/vapp_template_upload_failed.xml +0 -28
  139. data/spec/assets/vapp_template_upload_request.xml +0 -4
  140. data/spec/assets/vapp_template_upload_response.xml +0 -25
  141. data/spec/assets/vcloud_response.xml +0 -56
  142. data/spec/assets/vdc_response.xml +0 -57
  143. data/spec/spec_helper.rb +0 -107
  144. data/spec/unit/client_response.rb +0 -700
  145. data/spec/unit/client_spec.rb +0 -1152
@@ -0,0 +1,95 @@
1
+ require "netaddr"
2
+ require "set"
3
+
4
+ module VCloudSdk
5
+ class IpRanges
6
+ attr_reader :ranges
7
+
8
+ def initialize(value = nil)
9
+ @ranges = Set.new
10
+
11
+ parse_ip_ranges(value) unless value.nil?
12
+ end
13
+
14
+ def add(ip_ranges)
15
+ ip_ranges = objectify ip_ranges
16
+ result = IpRanges.new
17
+ result.ranges.merge @ranges
18
+ result.ranges.merge ip_ranges.ranges
19
+ result
20
+ end
21
+ alias_method :+, :add
22
+
23
+ def subtract(ip_ranges)
24
+ ip_ranges = objectify ip_ranges
25
+ difference = IpRanges.new
26
+ difference.ranges.merge @ranges
27
+ difference.ranges.subtract ip_ranges.ranges
28
+
29
+ difference
30
+ end
31
+ alias_method :-, :subtract
32
+
33
+ def include?(ip_ranges)
34
+ ip_ranges = objectify ip_ranges
35
+ @ranges.superset? ip_ranges.ranges
36
+ end
37
+
38
+ protected
39
+
40
+ attr_writer :ranges
41
+
42
+ private
43
+
44
+ def parse_ip_ranges(ip_ranges_string)
45
+ fail "Parameter is not a string" unless ip_ranges_string.is_a? String
46
+
47
+ # remove white space
48
+ ip_ranges_string.gsub(/\s+/, "").split(",").map do |i|
49
+ parse_ip_range(i)
50
+ end
51
+ end
52
+
53
+ def parse_ip_range(ip_range_string)
54
+ case ip_range_string
55
+ when /-/
56
+ ips = ip_range_string.split("-")
57
+ unless ips.length == 2
58
+ fail "Invalid input: #{ips.length} field/fields separated by '-'"
59
+ end
60
+
61
+ ips ips[0], ips[1]
62
+ when /\//
63
+ ips = NetAddr::CIDR.create(ip_range_string)
64
+ ips ips.first, ips.last
65
+ else
66
+ # A single IP address such as "10.142.15.11"
67
+ ip = NetAddr::CIDR.create(ip_range_string)
68
+ fail "IPv6 is not supported" if ip.is_a?(NetAddr::CIDRv6)
69
+ @ranges.add ip.ip
70
+ end
71
+ end
72
+
73
+ def ips(ip_start_string, ip_end_string)
74
+ ip_start = NetAddr::CIDR.create(ip_start_string)
75
+ ip_end = NetAddr::CIDR.create(ip_end_string)
76
+ if ip_start.is_a?(NetAddr::CIDRv6) || ip_end.is_a?(NetAddr::CIDRv6)
77
+ fail "IPv6 is not supported"
78
+ end
79
+
80
+ if ip_start > ip_end
81
+ fail "IP #{ip_start.ip} is bigger than IP #{ip_end.ip}"
82
+ end
83
+
84
+ @ranges.merge((ip_start..ip_end).map(&:ip))
85
+ end
86
+
87
+ def objectify(ip_ranges)
88
+ ip_ranges = IpRanges.new(ip_ranges) if ip_ranges.is_a? String
89
+ unless ip_ranges.is_a? IpRanges
90
+ fail "Unable to parse object that is not IpRange or string"
91
+ end
92
+ ip_ranges
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,11 @@
1
+ module VCloudSdk
2
+
3
+ class Memory
4
+ attr_reader :available_mb
5
+
6
+ def initialize(available_mb)
7
+ @available_mb = available_mb
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,32 @@
1
+ require_relative "infrastructure"
2
+ require_relative "ip_ranges"
3
+
4
+ module VCloudSdk
5
+ class Network
6
+ include Infrastructure
7
+
8
+ def initialize(session, link)
9
+ @session = session
10
+ @link = link
11
+ end
12
+
13
+ def name
14
+ entity_xml.name
15
+ end
16
+
17
+ def ip_ranges
18
+ entity_xml.ip_ranges
19
+ .ranges
20
+ .reduce(IpRanges.new) do |result, i|
21
+ result + IpRanges.new("#{i.start_address}-#{i.end_address}")
22
+ end
23
+ end
24
+
25
+ def allocated_ips
26
+ allocated_addresses = connection.get(entity_xml.allocated_addresses_link)
27
+ allocated_addresses.ip_addresses.map do |i|
28
+ i.ip_address
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,78 @@
1
+ module VCloudSdk
2
+ # Shared functions by classes VM and VApp
3
+ module Powerable
4
+ def status
5
+ status_code = entity_xml[:status].to_i
6
+ Xml::RESOURCE_ENTITY_STATUS.each_pair do |k, v|
7
+ return k.to_s if v == status_code
8
+ end
9
+
10
+ fail CloudError,
11
+ "Fail to find corresponding status for code '#{status_code}'"
12
+ end
13
+
14
+ # Power on VApp or VM
15
+ def power_on
16
+ target = entity_xml
17
+ class_name = self.class.name.split("::").last
18
+ Config.logger.debug "#{class_name} status: #{target[:status]}"
19
+ if is_status?(target, :POWERED_ON)
20
+ Config.logger.info "#{class_name} #{target.name} is already powered-on."
21
+ return
22
+ end
23
+
24
+ power_on_link = target.power_on_link
25
+ unless power_on_link
26
+ fail CloudError,
27
+ "#{class_name} #{target.name} not in a state able to power on."
28
+ end
29
+
30
+ Config.logger.info "Powering on #{class_name} #{target.name}."
31
+ task = connection.post(power_on_link, nil)
32
+ task = monitor_task task, @session.time_limit[:power_on]
33
+ Config.logger.info "#{class_name} #{target.name} is powered on."
34
+ task
35
+ end
36
+
37
+ # Power off VApp or VM
38
+ def power_off
39
+ target = entity_xml
40
+ class_name = self.class.name.split("::").last
41
+ Config.logger.debug "#{class_name} status: #{target[:status]}"
42
+ if is_status?(target, :SUSPENDED)
43
+ error_msg = "#{class_name} #{target.name} suspended, discard state before powering off."
44
+ fail class_name == "VApp" ? VappSuspendedError : VmSuspendedError,
45
+ error_msg
46
+ end
47
+ if is_status?(target, :POWERED_OFF)
48
+ Config.logger.info "#{class_name} #{target.name} is already powered off."
49
+ return
50
+ end
51
+
52
+ power_off_link = target.power_off_link
53
+ unless power_off_link
54
+ fail CloudError, "#{class_name} #{target.name} is not in a state that could be powered off."
55
+ end
56
+
57
+ task = connection.post(power_off_link, nil)
58
+ monitor_task task, @session.time_limit[:power_off]
59
+ Config.logger.info "#{class_name} #{target.name} is powered off."
60
+
61
+ undeploy(target, class_name)
62
+ end
63
+
64
+ private
65
+
66
+ def is_status?(target, status)
67
+ target[:status] == Xml::RESOURCE_ENTITY_STATUS[status].to_s
68
+ end
69
+
70
+ def undeploy(target, class_name)
71
+ params = Xml::WrapperFactory.create_instance("UndeployVAppParams") # Even for VM it's called UndeployVappParams
72
+ task = connection.post(target.undeploy_link, params)
73
+ task = monitor_task(task, @session.time_limit[:undeploy])
74
+ Config.logger.info "#{class_name} #{target.name} is undeployed."
75
+ task
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,13 @@
1
+ module VCloudSdk
2
+
3
+ class Resources
4
+ attr_reader :cpu
5
+ attr_reader :memory
6
+
7
+ def initialize(cpu, memory)
8
+ @cpu = cpu
9
+ @memory = memory
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,46 @@
1
+ module VCloudSdk
2
+ class Session
3
+ attr_reader :connection
4
+ attr_accessor :retries, :time_limit, :delay
5
+
6
+ RETRIES = {
7
+ default: 5,
8
+ upload_vapp_files: 7,
9
+ cpi: 1,
10
+ }
11
+
12
+ TIME_LIMIT_SEC = {
13
+ default: 120,
14
+ delete_vapp_template: 120,
15
+ delete_vapp: 120,
16
+ delete_media: 120,
17
+ instantiate_vapp_template: 300,
18
+ power_on: 600,
19
+ power_off: 600,
20
+ undeploy: 720,
21
+ process_descriptor_vapp_template: 300,
22
+ http_request: 240,
23
+ recompose_vapp: 200,
24
+ }
25
+
26
+ DELAY = 1
27
+
28
+ private_constant :RETRIES, :TIME_LIMIT_SEC, :DELAY
29
+
30
+ def initialize(url, username, password, options)
31
+ @time_limit = options[:time_limit_sec] || TIME_LIMIT_SEC
32
+ @retries = options[:retries] || RETRIES
33
+ @delay = options[:delay] || DELAY
34
+ @connection = Connection::Connection.new(
35
+ url,
36
+ @time_limit[:http_request])
37
+ @session_xml_obj = @connection.connect(username, password)
38
+ @org_link = @session_xml_obj.organization
39
+ end
40
+
41
+ def org
42
+ @connection.get(@org_link)
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,122 @@
1
+ require_relative "infrastructure"
2
+ require_relative "powerable"
3
+ require_relative "vm"
4
+
5
+ module VCloudSdk
6
+ class VApp
7
+ include Infrastructure
8
+ include Powerable
9
+
10
+ def initialize(session, link)
11
+ @session = session
12
+ @link = link
13
+ end
14
+
15
+ def name
16
+ entity_xml.name
17
+ end
18
+
19
+ def delete
20
+ vapp = entity_xml
21
+ vapp_name = name
22
+
23
+ if is_status?(vapp, :POWERED_ON)
24
+ fail CloudError,
25
+ "vApp #{vapp_name} is powered on, power-off before deleting."
26
+ end
27
+
28
+ wait_for_running_tasks(vapp, "VApp #{vapp_name}")
29
+
30
+ Config.logger.info "Deleting vApp #{vapp_name}."
31
+ monitor_task(connection.delete(vapp.remove_link),
32
+ @session.time_limit[:delete_vapp]) do |task|
33
+ Config.logger.info "vApp #{vapp_name} deleted."
34
+ return task
35
+ end
36
+
37
+ fail ApiRequestError,
38
+ "Fail to delete vApp #{vapp_name}"
39
+ end
40
+
41
+ def recompose_from_vapp_template(catalog_name, template_name)
42
+ recompose_vapp_link = get_recompose_vapp_link
43
+
44
+ Config.logger.info "Recomposing from template '#{template_name}' in catalog '#{catalog_name}'."
45
+ catalog = find_catalog_by_name catalog_name
46
+
47
+ template = catalog.find_vapp_template_by_name template_name
48
+
49
+ task = connection.post recompose_vapp_link.href,
50
+ recompose_from_vapp_template_param(template)
51
+
52
+ monitor_task task, @session.time_limit[:recompose_vapp]
53
+ Config.logger.info "vApp #{name} is recomposed."
54
+ self
55
+ end
56
+
57
+ def vms
58
+ entity_xml.vms.map do |vm|
59
+ VCloudSdk::VM.new(@session, vm.href)
60
+ end
61
+ end
62
+
63
+ def list_vms
64
+ entity_xml.vms.map do |vm|
65
+ vm.name
66
+ end
67
+ end
68
+
69
+ def find_vm_by_name(name)
70
+ entity_xml.vms.each do |vm|
71
+ return VCloudSdk::VM.new(@session, vm.href) if vm.name == name
72
+ end
73
+
74
+ fail ObjectNotFoundError, "VM '#{name}' is not found"
75
+ end
76
+
77
+ def remove_vm_by_name(vm_name)
78
+ target_vm = find_vm_by_name vm_name
79
+ recompose_vapp_link = get_recompose_vapp_link
80
+
81
+ task = connection.post recompose_vapp_link.href,
82
+ remove_vm_param(target_vm)
83
+
84
+ monitor_task task, @session.time_limit[:recompose_vapp]
85
+ Config.logger.info "VM #{vm_name} is removed."
86
+ self
87
+ end
88
+
89
+ private
90
+
91
+ def recompose_from_vapp_template_param(template)
92
+ Xml::WrapperFactory.create_instance("RecomposeVAppParams").tap do |params|
93
+ params.name = name
94
+ params.all_eulas_accepted = true
95
+ params.add_source_item template.href
96
+ end
97
+ end
98
+
99
+ def get_recompose_vapp_link
100
+ recompose_vapp_link = connection
101
+ .get(@link)
102
+ .recompose_vapp_link
103
+
104
+ if recompose_vapp_link.nil?
105
+ # We are able to recompose vapp when it is suspended or powered off
106
+ # If vapp is powered on, throw exception
107
+ fail CloudError,
108
+ "VApp is in status of '#{status}' and can not be recomposed"
109
+ end
110
+
111
+ recompose_vapp_link
112
+ end
113
+
114
+ def remove_vm_param(vm)
115
+ Xml::WrapperFactory.create_instance("RecomposeVAppParams").tap do |params|
116
+ params.name = name
117
+ params.all_eulas_accepted = true
118
+ params.add_delete_item vm.href
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,210 @@
1
+ require "forwardable"
2
+ require "uri"
3
+ require_relative "vdc_storage_profile"
4
+ require_relative "vapp"
5
+ require_relative "infrastructure"
6
+ require_relative "resources"
7
+ require_relative "cpu"
8
+ require_relative "disk"
9
+ require_relative "memory"
10
+ require_relative "network"
11
+ require_relative "edge_gateway"
12
+
13
+ module VCloudSdk
14
+ class VDC
15
+ include Infrastructure
16
+
17
+ extend Forwardable
18
+ def_delegators :@vdc_xml_obj,
19
+ :name, :upload_link, :upload_media_link,
20
+ :instantiate_vapp_template_link
21
+
22
+ BUS_TYPE = {
23
+ "scsi" => Xml::HARDWARE_TYPE[:SCSI_CONTROLLER]
24
+ }
25
+
26
+ BUS_SUB_TYPE = {
27
+ "lsilogic" => Xml::BUS_SUB_TYPE[:LSILOGIC]
28
+ }
29
+
30
+ private_constant :BUS_TYPE, :BUS_SUB_TYPE
31
+
32
+ def initialize(session, vdc_xml_obj)
33
+ @session = session
34
+ @vdc_xml_obj = vdc_xml_obj
35
+ end
36
+
37
+ def storage_profiles
38
+ storage_profile_records.map do |storage_profile|
39
+ VCloudSdk::VdcStorageProfile.new(storage_profile)
40
+ end
41
+ end
42
+
43
+ def list_storage_profiles
44
+ storage_profile_records.map do |storage_profile|
45
+ storage_profile.name
46
+ end
47
+ end
48
+
49
+ def find_storage_profile_by_name(name)
50
+ storage_profile_records.each do |storage_profile|
51
+ if storage_profile.name == name
52
+ return VCloudSdk::VdcStorageProfile.new(storage_profile)
53
+ end
54
+ end
55
+
56
+ fail ObjectNotFoundError, "Storage profile '#{name}' is not found"
57
+ end
58
+
59
+ def vapps
60
+ @vdc_xml_obj.vapps.map do |vapp_link|
61
+ VCloudSdk::VApp.new(@session, vapp_link)
62
+ end
63
+ end
64
+
65
+ def list_vapps
66
+ @vdc_xml_obj.vapps.map do |vapp_link|
67
+ vapp_link.name
68
+ end
69
+ end
70
+
71
+ def find_vapp_by_name(name)
72
+ @vdc_xml_obj.vapps.each do |vapp_link|
73
+ if vapp_link.name == name
74
+ return VCloudSdk::VApp.new(@session, vapp_link)
75
+ end
76
+ end
77
+
78
+ fail ObjectNotFoundError, "VApp '#{name}' is not found"
79
+ end
80
+
81
+ def resources
82
+ cpu = VCloudSdk::CPU.new(@vdc_xml_obj.available_cpu_cores)
83
+ memory = VCloudSdk::Memory.new(@vdc_xml_obj.available_memory_mb)
84
+ VCloudSdk::Resources.new(cpu, memory)
85
+ end
86
+
87
+ def networks
88
+ @session.org.networks.map do |network_link|
89
+ VCloudSdk::Network.new(@session, network_link)
90
+ end
91
+ end
92
+
93
+ def list_networks
94
+ @session.org.networks.map do |network_link|
95
+ network_link.name
96
+ end
97
+ end
98
+
99
+ def find_network_by_name(name)
100
+ @session.org.networks.each do |network_link|
101
+ if network_link.name == name
102
+ return VCloudSdk::Network.new(@session, network_link)
103
+ end
104
+ end
105
+
106
+ fail ObjectNotFoundError, "Network '#{name}' is not found"
107
+ end
108
+
109
+ def edge_gateways
110
+ connection
111
+ .get(@vdc_xml_obj.edge_gateways_link)
112
+ .edge_gateway_records
113
+ .map do |edge_gateway_link|
114
+ VCloudSdk::EdgeGateway.new(@session, edge_gateway_link.href)
115
+ end
116
+ end
117
+
118
+ def disks
119
+ @vdc_xml_obj.disks.map do |disk_link|
120
+ VCloudSdk::Disk.new(@session, disk_link)
121
+ end
122
+ end
123
+
124
+ def list_disks
125
+ @vdc_xml_obj.disks.map do |disk_link|
126
+ disk_link.name
127
+ end
128
+ end
129
+
130
+ def find_disks_by_name(name)
131
+ disks = @vdc_xml_obj
132
+ .disks
133
+ .select { |disk_link| disk_link.name == name }
134
+ .map { |disk_link| VCloudSdk::Disk.new(@session, disk_link.href) }
135
+
136
+ if disks.empty?
137
+ fail ObjectNotFoundError, "Disk '#{name}' is not found"
138
+ end
139
+
140
+ disks
141
+ end
142
+
143
+ def disk_exists?(name)
144
+ disks.any? do |disk|
145
+ disk.name == name
146
+ end
147
+ end
148
+
149
+ def create_disk(
150
+ name,
151
+ size_mb,
152
+ vm = nil,
153
+ bus_type = "scsi",
154
+ bus_sub_type = "lsilogic")
155
+
156
+ fail(CloudError,
157
+ "Invalid size in MB #{size_mb}") if size_mb <= 0
158
+
159
+ bus_type = BUS_TYPE[bus_type.downcase]
160
+ fail(CloudError,
161
+ "Invalid bus type!") unless bus_type
162
+
163
+ bus_sub_type = BUS_SUB_TYPE[bus_sub_type.downcase]
164
+ fail(CloudError,
165
+ "Invalid bus sub type!") unless bus_sub_type
166
+
167
+ Config
168
+ .logger
169
+ .info "Creating independent disk #{name} of #{size_mb}MB."
170
+
171
+ disk = connection.post(@vdc_xml_obj.add_disk_link,
172
+ disk_create_params(name, size_mb, bus_type, bus_sub_type, vm),
173
+ Xml::MEDIA_TYPE[:DISK_CREATE_PARAMS])
174
+
175
+ wait_for_running_tasks(disk, "Disk #{name}")
176
+
177
+ VCloudSdk::Disk.new(@session, disk.href)
178
+ end
179
+
180
+ def storage_profile_xml_node(name)
181
+ return nil if name.nil?
182
+
183
+ storage_profile = @vdc_xml_obj.storage_profile(name)
184
+ unless storage_profile
185
+ fail ObjectNotFoundError,
186
+ "Storage profile '#{name}' does not exist"
187
+ end
188
+
189
+ storage_profile
190
+ end
191
+
192
+ private
193
+
194
+ def storage_profile_records
195
+ connection
196
+ .get("/api/query?type=orgVdcStorageProfile&filter=vdcName==#{URI.encode(name)}")
197
+ .org_vdc_storage_profile_records
198
+ end
199
+
200
+ def disk_create_params(name, size_mb, bus_type, bus_sub_type, vm)
201
+ Xml::WrapperFactory.create_instance("DiskCreateParams").tap do |params|
202
+ params.name = name
203
+ params.size_bytes = size_mb * 1024 * 1024 # VCD expects bytes
204
+ params.bus_type = bus_type
205
+ params.bus_sub_type = bus_sub_type
206
+ params.add_locality(connection.get(vm.href)) if vm # Use xml form of vm
207
+ end
208
+ end
209
+ end
210
+ end