Skip to content

Commit

Permalink
Allow vApp customization prior provisioning
Browse files Browse the repository at this point in the history
vApp provisioning is already possible via service dialogs, but
only a very modest customization is allowed. With this commit
we implement support for much more enhanced vApp customization
by allowing modification of following parameters:

- vApp name, tenant, availability zone, deploy?, power_on?
- vApp network customization (parent, fence mode, gateway, netmask, dns1, dns2)
- VM customization: name, hostname, CPU, MEM, disk size, NIC configuration (network, ip mode, ip address)

Signed-off-by: Miha Pleško <miha.plesko@xlab.si>
  • Loading branch information
miha-plesko committed Feb 21, 2018
1 parent 233c1f7 commit 37f478c
Show file tree
Hide file tree
Showing 4 changed files with 730 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ def stack_create_options
:powerOn => stack_parameters['powerOn'] == 't'
}
options[:vdc_id] = @dialog_options['dialog_availability_zone'] unless @dialog_options['dialog_availability_zone'].blank?

options.merge!(customize_vapp_template(collect_vm_params))
options.merge!(customize_vapp_template(collect_vm_params, collect_vapp_net_params))
end

private
Expand All @@ -20,60 +19,94 @@ def stack_create_options
# deployed vApp. We are using IDs here and let fog library create concrete HREFs that are required
# by the vCloud director. The second object is an array of source items. Each source item references
# a single VM from the vApp template, customises its name and optionally sets network info.
def customize_vapp_template(vm_params)
network_config = {}

def customize_vapp_template(vm_params, vapp_net_params)
source_vms = vm_params.collect do |vm_id, vm_opts|
src_vm = { :vm_id => "vm-#{vm_id}" }
src_vm[:name] = vm_opts["instance_name"] if vm_opts.key?("instance_name")

network_id = vm_opts["vdc_network"]
unless network_id.nil?
# Create new network config if it hasn't been created before.
network_config[network_id] ||= {
:networkName => network_id,
:networkId => network_id,
:fenceMode => "bridged"
src_vm = {
:vm_id => "vm-#{vm_id}",
:networks => parse_nics(vm_opts),
:hardware => {
:cpu => { :num_cores => vm_opts['num_cores'], :cores_per_socket => vm_opts['cores_per_socket'] },
:memory => { :quantity_mb => vm_opts['memory_mb'] },
:disk => vm_opts['disk_mb']&.map { |disk| { :id => disk[:disk_id], :capacity_mb => disk[:value] } }
}

# Add network configuration to the source VM.
src_vm[:networks] = [
:networkName => network_id,
:IsConnected => true,
:IpAddressAllocationMode => "DHCP"
]
end

}
src_vm[:name] = vm_opts["instance_name"] if vm_opts.key?("instance_name")
src_vm[:guest_customization] = { :ComputerName => vm_opts['hostname'] } if vm_opts.key?("hostname")
src_vm
end

# Create options suitable for VMware vCloud provider.
custom_opts = {
:source_vms => source_vms
}
custom_opts[:InstantiationParams] = {
:NetworkConfig => network_config.values
} unless network_config.empty?
vapp_networks = vapp_net_params.collect do |vapp_net_name, opts|
{
:name => vapp_net_name,
:parent => opts['parent'],
:fence_mode => opts['fence_mode'],
:subnet => parse_subnets(opts)
}
end

custom_opts
{
:source_vms => source_vms,
:vapp_networks => vapp_networks
}
end

def collect_vm_params
allowed_vm_params = %w(instance_name vdc_network)
stack_parameters.each_with_object({}) do |(key, value), vm_params|
allowed_vm_params.each do |param|
# VM-specific parameters are named as instance_name-<VM_ID>. The
# following will test the param name for this kind of pattern and use
# the <VM_ID> to store the configuration about this VM.
param_match = key.match(/#{param}-([0-9a-f-]*)/)
collect_stack_parameters(
%w(instance_name vdc_network num_cores cores_per_socket memory_mb disk_mb hostname nic_network nic_mode nic_ip_address)
)
end

def collect_vapp_net_params
collect_stack_parameters(%w(gateway netmask dns1 dns2 parent fence_mode))
end

def collect_stack_parameters(allowed)
separator = '___'
stack_parameters.each_with_object({}) do |(key, value), params|
allowed.each do |param|
param_match = key.match(/#{param}-(.+)#{separator}(.+)?/)
next if param_match.nil?

vm_id = param_match.captures.first
vm_params[vm_id] ||= {}
# Store the parameter value.
vm_params[vm_id][param] = value
key = Base64.decode64(param_match.captures.first)
extra = YAML.safe_load(Base64.decode64(param_match.captures[1].to_s), [Symbol])
params[key] ||= {}

if extra
params[key][param] ||= []
params[key][param] << extra.merge(:value => value)
else
params[key][param] = value
end
end
end
end

def parse_subnets(opts)
opts['gateway']&.size&.times&.map do |idx|
{
:gateway => option_value(opts['gateway'], :ip_scope_idx, idx),
:netmask => option_value(opts['netmask'], :ip_scope_idx, idx),
:dns1 => option_value(opts['dns1'], :ip_scope_idx, idx),
:dns2 => option_value(opts['dns2'], :ip_scope_idx, idx),
}
end
end

def parse_nics(opts)
opts['nic_network']&.map do |nic_network|
idx = nic_network[:nic_idx]
{
:networkName => option_value(opts['nic_network'], :nic_idx, idx),
:IpAddressAllocationMode => option_value(opts['nic_mode'], :nic_idx, idx),
:IpAddress => option_value(opts['nic_ip_address'], :nic_idx, idx),
:IsConnected => true
}
end
end

def option_value(opts_group, key, key_val)
opt = opts_group&.detect { |o| o[key] == key_val }
opt[:value] unless opt.nil?
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ class ManageIQ::Providers::Vmware::CloudManager::OrchestrationStack < ManageIQ::
require_nested :Status

def self.raw_create_stack(orchestration_manager, stack_name, template, options = {})
log_prefix = "stack=[#{stack_name}]"
orchestration_manager.with_provider_connection do |service|
create_options = {:stack_name => stack_name, :template => template.ems_ref}.merge(options)

$vcloud_log.info("#{log_prefix} create_options: #{create_options}")
service.instantiate_template(create_options)
end
rescue => err
$vcloud_log.error("stack=[#{stack_name}], error: #{err}")
$vcloud_log.error("#{log_prefix} error: #{err}")
raise MiqException::MiqOrchestrationProvisionError, err.to_s, err.backtrace
end

Expand Down
Loading

0 comments on commit 37f478c

Please sign in to comment.