ruby_vcloud_sdk 0.4.8 → 0.5.1
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.
- checksums.yaml +7 -0
- data/README.md +296 -0
- data/lib/ruby_vcloud_sdk.rb +0 -4
- data/lib/ruby_vcloud_sdk/catalog.rb +377 -0
- data/lib/ruby_vcloud_sdk/catalog_item.rb +26 -0
- data/lib/ruby_vcloud_sdk/client.rb +25 -882
- data/lib/ruby_vcloud_sdk/config.rb +1 -7
- data/lib/ruby_vcloud_sdk/connection/connection.rb +114 -54
- data/lib/ruby_vcloud_sdk/cpu.rb +11 -0
- data/lib/ruby_vcloud_sdk/disk.rb +55 -0
- data/lib/ruby_vcloud_sdk/edge_gateway.rb +32 -0
- data/lib/ruby_vcloud_sdk/infrastructure.rb +135 -0
- data/lib/ruby_vcloud_sdk/ip_ranges.rb +95 -0
- data/lib/ruby_vcloud_sdk/memory.rb +11 -0
- data/lib/ruby_vcloud_sdk/network.rb +32 -0
- data/lib/ruby_vcloud_sdk/powerable.rb +78 -0
- data/lib/ruby_vcloud_sdk/resources.rb +13 -0
- data/lib/ruby_vcloud_sdk/session.rb +46 -0
- data/lib/ruby_vcloud_sdk/vapp.rb +122 -0
- data/lib/ruby_vcloud_sdk/vdc.rb +210 -0
- data/lib/ruby_vcloud_sdk/vdc_storage_profile.rb +23 -0
- data/lib/ruby_vcloud_sdk/version.rb +1 -1
- data/lib/ruby_vcloud_sdk/vm.rb +132 -0
- data/lib/ruby_vcloud_sdk/xml/constants.rb +6 -4
- data/lib/ruby_vcloud_sdk/xml/wrapper.rb +109 -30
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes.rb +45 -2
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/admin_catalog.rb +13 -4
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/allocated_ip_addresses.rb +9 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/catalog_item.rb +6 -14
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk.rb +24 -14
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_attach_or_detach_params.rb +0 -2
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/disk_create_params.rb +1 -3
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/edge_gateway.rb +13 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/gateway_interface.rb +22 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/hard_disk_item_wrapper.rb +4 -4
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_address.rb +10 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_range.rb +13 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_ranges.rb +9 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/ip_scope.rb +6 -32
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/item.rb +1 -7
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/link.rb +14 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media.rb +4 -20
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/media_insert_or_eject_params.rb +1 -3
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/network_connection_section.rb +0 -4
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/nic_item_wrapper.rb +0 -2
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org.rb +44 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/org_vdc_network.rb +11 -3
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/query_result_records.rb +14 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/recompose_vapp_params.rb +42 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/session.rb +5 -5
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/supported_versions.rb +19 -0
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/task.rb +1 -1
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/upload_vapp_template_params.rb +2 -4
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp.rb +13 -22
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vapp_template.rb +0 -2
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vcloud.rb +5 -3
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vdc.rb +72 -15
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/virtual_hardware_section.rb +8 -6
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vm.rb +29 -25
- data/lib/ruby_vcloud_sdk/xml/wrapper_classes/vms.rb +12 -0
- data/lib/ruby_vcloud_sdk/xml/xml_templates/AdminCatalog.xml +6 -1
- data/lib/ruby_vcloud_sdk/xml/xml_templates/RecomposeVAppParams.xml +16 -1
- metadata +116 -233
- data/README +0 -1
- data/Rakefile +0 -50
- data/lib/ruby_vcloud_sdk/util.rb +0 -21
- data/spec/assets/admin_org_response.xml +0 -75
- data/spec/assets/catalog_add_item_response.xml +0 -8
- data/spec/assets/catalog_add_vapp_request.xml +0 -5
- data/spec/assets/catalog_item_added_response.xml +0 -19
- data/spec/assets/catalog_response.xml +0 -19
- data/spec/assets/existing_media_busy_response.xml +0 -19
- data/spec/assets/existing_media_catalog_item.xml +0 -8
- data/spec/assets/existing_media_delete_task_done.xml +0 -6
- data/spec/assets/existing_media_done_response.xml +0 -11
- data/spec/assets/existing_vapp_resolver_response.xml +0 -3
- data/spec/assets/existing_vapp_template_catalog_resolver_response.xml +0 -3
- data/spec/assets/existing_vapp_template_instantiate_response.xml +0 -20
- data/spec/assets/existing_vapp_template_instantiate_task_error_response.xml +0 -7
- data/spec/assets/existing_vapp_template_instantiate_task_start_response.xml +0 -7
- data/spec/assets/existing_vapp_template_instantiate_task_success_response.xml +0 -7
- data/spec/assets/existing_vapp_template_item_response.xml +0 -8
- data/spec/assets/existing_vapp_template_ready_response.xml +0 -79
- data/spec/assets/finalize_upload_task_done_response.xml +0 -7
- data/spec/assets/finalize_upload_task_response.xml +0 -7
- data/spec/assets/indy_disk_attach_request.xml +0 -3
- data/spec/assets/indy_disk_attach_task.xml +0 -6
- data/spec/assets/indy_disk_attach_task_error.xml +0 -6
- data/spec/assets/indy_disk_create_error.xml +0 -1
- data/spec/assets/indy_disk_create_request.xml +0 -4
- data/spec/assets/indy_disk_create_response.xml +0 -19
- data/spec/assets/indy_disk_delete_task.xml +0 -6
- data/spec/assets/indy_disk_detach_request.xml +0 -3
- data/spec/assets/indy_disk_detach_task.xml +0 -6
- data/spec/assets/indy_disk_response.xml +0 -11
- data/spec/assets/instantiated_suspended_vapp_response.xml +0 -209
- data/spec/assets/instantiated_vapp_delelete_done_task.xml +0 -5
- data/spec/assets/instantiated_vapp_delelete_running_task.xml +0 -6
- data/spec/assets/instantiated_vapp_network_config_add_network_request.xml +0 -36
- data/spec/assets/instantiated_vapp_network_config_modify_network_task_success.xml +0 -6
- data/spec/assets/instantiated_vapp_network_config_remove_network_request.xml +0 -6
- data/spec/assets/instantiated_vapp_network_config_section_response.xml +0 -17
- data/spec/assets/instantiated_vapp_off_response.xml +0 -206
- data/spec/assets/instantiated_vapp_on_response.xml +0 -205
- data/spec/assets/instantiated_vapp_power_task_running.xml +0 -6
- data/spec/assets/instantiated_vapp_power_task_success.xml +0 -6
- data/spec/assets/instantiated_vapp_response.xml +0 -205
- data/spec/assets/instantiated_vm_change_task_running.xml +0 -6
- data/spec/assets/instantiated_vm_change_task_success.xml +0 -6
- data/spec/assets/instantiated_vm_cpu_response.xml +0 -11
- data/spec/assets/instantiated_vm_insert_media_task_done.xml +0 -6
- data/spec/assets/instantiated_vm_memory_response.xml +0 -11
- data/spec/assets/instantiated_vm_modify_task_running.xml +0 -6
- data/spec/assets/instantiated_vm_modify_task_success.xml +0 -5
- data/spec/assets/instantiated_vm_network_section_response.xml +0 -11
- data/spec/assets/instantiated_vm_response.xml +0 -149
- data/spec/assets/media_add_to_catalog_request.xml +0 -5
- data/spec/assets/media_add_to_catalog_response.xml +0 -8
- data/spec/assets/media_delete_task_done.xml +0 -6
- data/spec/assets/media_upload_pending_response.xml +0 -13
- data/spec/assets/media_upload_request.xml +0 -2
- data/spec/assets/metadata_set_request.xml +0 -3
- data/spec/assets/metadata_set_task_done.xml +0 -6
- data/spec/assets/org_network_response.xml +0 -22
- data/spec/assets/reconfigure_vm_request.xml +0 -133
- data/spec/assets/reconfigure_vm_task.xml +0 -8
- data/spec/assets/session.xml +0 -7
- data/spec/assets/test-config.yml +0 -38
- data/spec/assets/undeploy_params.xml +0 -1
- data/spec/assets/vapp_template_catalog_resolver_response.xml +0 -3
- data/spec/assets/vapp_template_delelete_done_task.xml +0 -5
- data/spec/assets/vapp_template_delelete_running_task.xml +0 -6
- data/spec/assets/vapp_template_instantiate_request.xml +0 -8
- data/spec/assets/vapp_template_instantiate_with_locality_request.xml +0 -14
- data/spec/assets/vapp_template_no_disk_response.xml +0 -27
- data/spec/assets/vapp_template_ready_response.xml +0 -79
- data/spec/assets/vapp_template_upload_complete.xml +0 -28
- data/spec/assets/vapp_template_upload_failed.xml +0 -28
- data/spec/assets/vapp_template_upload_request.xml +0 -4
- data/spec/assets/vapp_template_upload_response.xml +0 -25
- data/spec/assets/vcloud_response.xml +0 -56
- data/spec/assets/vdc_response.xml +0 -57
- data/spec/spec_helper.rb +0 -107
- data/spec/unit/client_response.rb +0 -700
- 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,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,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
|