lib/vagrant-vcloud/action/forward_ports.rb
module VagrantPlugins
module VCloud
module Action
class ForwardPorts
include Util::CompileForwardedPorts
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_vcloud::action::forward_ports')
end
def call(env)
@env = env
# Get the ports we are forwarding
env[:forwarded_ports] ||= compile_forwarded_ports(
env[:machine]
)
forward_ports
@app.call(env)
end
def forward_ports
ports = {}
edge_ports = []
cfg = @env[:machine].provider_config
cnx = cfg.vcloud_cnx.driver
vapp_id = @env[:machine].get_vapp_id
vm_name = cfg.name ? cfg.name.to_sym : @env[:machine].name
# FIXME: why are we overriding this here ?
# It's already been taken care during the initial
# InventoryCheck. (tsugliani)
#
# cfg.org = cnx.get_organization_by_name(cfg.org_name)
# cfg.vdc_network_id = cfg.org[:networks][cfg.vdc_network_name]
@logger.debug('Getting VM info...')
vm = cnx.get_vapp(vapp_id)
vm_info = vm[:vms_hash][vm_name.to_sym]
network_name = ''
@env[:forwarded_ports].each do |fp|
@env[:ui].info(
"Forwarding Ports: VM port #{fp.guest_port} -> " +
"vShield Edge port #{fp.host_port}"
)
# Add the options to the ports array to send to the driver later
ports["#{fp.network_name}#{fp.edge_network_name}"] = { rules: [] } if !ports["#{fp.network_name}#{fp.edge_network_name}"]
ports["#{fp.network_name}#{fp.edge_network_name}"][:network_name] = fp.network_name
ports["#{fp.network_name}#{fp.edge_network_name}"][:parent_network] = fp.edge_network_id
ports["#{fp.network_name}#{fp.edge_network_name}"][:edge_network_name] = fp.edge_network_name
ports["#{fp.network_name}#{fp.edge_network_name}"][:rules] << {
:guestip => fp.guest_ip,
:nat_internal_port => fp.guest_port,
:hostip => fp.host_ip,
:nat_external_port => fp.host_port,
:name => fp.id,
:nat_vmnic_id => fp.vmnic_id,
:nat_protocol => fp.protocol.upcase,
:vapp_scoped_local_id => vm_info[:vapp_scoped_local_id]
}
end
if !ports.empty?
# We only need to forward ports if there are any to forward
@logger.debug("Port object to be passed: #{ports.inspect}")
### Here we apply the nat_rules to the vApp we just built
ports.values.each do |port|
add_ports = cnx.add_vapp_port_forwarding_rules(
vapp_id,
port[:network_name],
port[:edge_network_name],
{
:fence_mode => 'natRouted',
:parent_network => port[:parent_network],
:nat_policy_type => 'allowTraffic',
:nat_rules => port[:rules]
}
)
wait = cnx.wait_task_completion(add_ports)
if !wait[:errormsg].nil?
raise Errors::ComposeVAppError, :message => wait[:errormsg]
end
end
if cfg.vdc_edge_gateway_ip && \
cfg.vdc_edge_gateway && \
cfg.network_bridge.nil?
vapp_edge_ip = cnx.get_vapp_edge_public_ip(vapp_id)
@logger.debug('Getting edge gateway port forwarding rules...')
edge_gateway_rules = cnx.get_edge_gateway_rules(cfg.vdc_edge_gateway,
cfg.vdc_id)
vapp_edge_dnat_rules = edge_gateway_rules.select {|r| (r[:rule_type] == 'DNAT' &&
r[:translated_ip] == vapp_edge_ip)}
vapp_edge_ports_in_use = vapp_edge_dnat_rules.map{|r| r[:original_port].to_i}.to_set
ports.values.each do |port|
port[:rules].each do |rule|
if rule[:vapp_scoped_local_id] == vm_info[:vapp_scoped_local_id] &&
!vapp_edge_ports_in_use.include?(rule[:nat_external_port])
@env[:ui].info(
"Creating NAT rules on [#{cfg.vdc_edge_gateway}] " +
"for IP [#{vapp_edge_ip}] port #{rule[:nat_external_port]}."
)
edge_ports << rule[:nat_external_port]
end
end
end
if !edge_ports.empty?
# Add the vShield Edge Gateway rules
add_ports = cnx.add_edge_gateway_rules(
cfg.vdc_edge_gateway,
cfg.vdc_id,
cfg.vdc_edge_gateway_ip,
vapp_id,
edge_ports
)
wait = cnx.wait_task_completion(add_ports)
if !wait[:errormsg].nil?
raise Errors::ComposeVAppError, :message => wait[:errormsg]
end
end
end
end
end
end
end
end
end