Because of how CloudStack configures the firerwall on the router VM, you need to allow traffic to the private port instead of the public port.
238 lines
6.9 KiB
Go
238 lines
6.9 KiB
Go
package cloudstack
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mitchellh/multistep"
|
|
"github.com/mitchellh/packer/packer"
|
|
"github.com/xanzy/go-cloudstack/cloudstack"
|
|
)
|
|
|
|
type stepSetupNetworking struct {
|
|
privatePort int
|
|
publicPort int
|
|
}
|
|
|
|
func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction {
|
|
client := state.Get("client").(*cloudstack.CloudStackClient)
|
|
config := state.Get("config").(*Config)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
ui.Say("Setup networking...")
|
|
|
|
if config.UseLocalIPAddress {
|
|
ui.Message("Using the local IP address...")
|
|
ui.Message("Networking has been setup!")
|
|
return multistep.ActionContinue
|
|
}
|
|
// Generate a random public port used to configure our port forward.
|
|
rand.Seed(time.Now().UnixNano())
|
|
s.publicPort = 50000 + rand.Intn(10000)
|
|
|
|
// Set the currently configured port to be the private port.
|
|
s.privatePort = config.Comm.Port()
|
|
|
|
// Set the SSH or WinRM port to be the randomly generated public port.
|
|
switch config.Comm.Type {
|
|
case "ssh":
|
|
config.Comm.SSHPort = s.publicPort
|
|
case "winrm":
|
|
config.Comm.WinRMPort = s.publicPort
|
|
}
|
|
|
|
// Retrieve the instance ID from the previously saved state.
|
|
instanceID, ok := state.Get("instance_id").(string)
|
|
if !ok || instanceID == "" {
|
|
ui.Error("Could not retrieve instance_id from state!")
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
network, _, err := client.Network.GetNetworkByID(
|
|
config.Network,
|
|
cloudstack.WithProject(config.Project),
|
|
)
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Failed to retrieve the network object: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
if config.PublicIPAddress == "" {
|
|
ui.Message("Associating public IP address...")
|
|
p := client.Address.NewAssociateIpAddressParams()
|
|
|
|
if config.Project != "" {
|
|
p.SetProjectid(config.Project)
|
|
}
|
|
|
|
if network.Vpcid != "" {
|
|
p.SetVpcid(network.Vpcid)
|
|
} else {
|
|
p.SetNetworkid(network.Id)
|
|
}
|
|
|
|
// Associate a new public IP address.
|
|
ipAddr, err := client.Address.AssociateIpAddress(p)
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Failed to associate public IP address: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Set the IP address and it's ID.
|
|
config.PublicIPAddress = ipAddr.Id
|
|
config.hostAddress = ipAddr.Ipaddress
|
|
|
|
// Store the IP address ID.
|
|
state.Put("ip_address_id", ipAddr.Id)
|
|
}
|
|
|
|
ui.Message("Creating port forward...")
|
|
p := client.Firewall.NewCreatePortForwardingRuleParams(
|
|
config.PublicIPAddress,
|
|
s.privatePort,
|
|
"TCP",
|
|
s.publicPort,
|
|
instanceID,
|
|
)
|
|
|
|
// Configure the port forward.
|
|
p.SetNetworkid(network.Id)
|
|
p.SetOpenfirewall(false)
|
|
|
|
// Create the port forward.
|
|
forward, err := client.Firewall.CreatePortForwardingRule(p)
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Failed to create port forward: %s", err))
|
|
}
|
|
|
|
// Store the port forward ID.
|
|
state.Put("port_forward_id", forward.Id)
|
|
|
|
if network.Vpcid != "" {
|
|
ui.Message("Creating network ACL rule...")
|
|
|
|
if network.Aclid == "" {
|
|
ui.Error("Failed to configure the firewall: no ACL connected to the VPC network")
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Create a new parameter struct.
|
|
p := client.NetworkACL.NewCreateNetworkACLParams("TCP")
|
|
|
|
// Configure the network ACL rule.
|
|
p.SetAclid(network.Aclid)
|
|
p.SetAction("allow")
|
|
p.SetCidrlist(config.CIDRList)
|
|
p.SetStartport(s.privatePort)
|
|
p.SetEndport(s.privatePort)
|
|
p.SetTraffictype("ingress")
|
|
|
|
// Create the network ACL rule.
|
|
aclRule, err := client.NetworkACL.CreateNetworkACL(p)
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Failed to create network ACL rule: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Store the network ACL rule ID.
|
|
state.Put("network_acl_rule_id", aclRule.Id)
|
|
} else {
|
|
ui.Message("Creating firewall rule...")
|
|
|
|
// Create a new parameter struct.
|
|
p := client.Firewall.NewCreateFirewallRuleParams(config.PublicIPAddress, "TCP")
|
|
|
|
// Configure the firewall rule.
|
|
p.SetCidrlist(config.CIDRList)
|
|
p.SetStartport(s.privatePort)
|
|
p.SetEndport(s.privatePort)
|
|
|
|
fwRule, err := client.Firewall.CreateFirewallRule(p)
|
|
if err != nil {
|
|
ui.Error(fmt.Sprintf("Failed to create firewall rule: %s", err))
|
|
return multistep.ActionHalt
|
|
}
|
|
|
|
// Store the firewall rule ID.
|
|
state.Put("firewall_rule_id", fwRule.Id)
|
|
}
|
|
|
|
ui.Message("Networking has been setup!")
|
|
|
|
return multistep.ActionContinue
|
|
}
|
|
|
|
// Cleanup any resources that may have been created during the Run phase.
|
|
func (s *stepSetupNetworking) Cleanup(state multistep.StateBag) {
|
|
client := state.Get("client").(*cloudstack.CloudStackClient)
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
ui.Say("Cleanup networking...")
|
|
|
|
if fwRuleID, ok := state.Get("firewall_rule_id").(string); ok && fwRuleID != "" {
|
|
// Create a new parameter struct.
|
|
p := client.Firewall.NewDeleteFirewallRuleParams(fwRuleID)
|
|
|
|
ui.Message("Deleting firewal rule...")
|
|
if _, err := client.Firewall.DeleteFirewallRule(p); err != nil {
|
|
// This is a very poor way to be told the ID does no longer exist :(
|
|
if !strings.Contains(err.Error(), fmt.Sprintf(
|
|
"Invalid parameter id value=%s due to incorrect long value format, "+
|
|
"or entity does not exist", fwRuleID)) {
|
|
ui.Error(fmt.Sprintf("Error deleting firewall rule: %s", err))
|
|
}
|
|
}
|
|
}
|
|
|
|
if aclRuleID, ok := state.Get("network_acl_rule_id").(string); ok && aclRuleID != "" {
|
|
// Create a new parameter struct.
|
|
p := client.NetworkACL.NewDeleteNetworkACLParams(aclRuleID)
|
|
|
|
ui.Message("Deleting network ACL rule...")
|
|
if _, err := client.NetworkACL.DeleteNetworkACL(p); err != nil {
|
|
// This is a very poor way to be told the ID does no longer exist :(
|
|
if !strings.Contains(err.Error(), fmt.Sprintf(
|
|
"Invalid parameter id value=%s due to incorrect long value format, "+
|
|
"or entity does not exist", aclRuleID)) {
|
|
ui.Error(fmt.Sprintf("Error deleting network ACL rule: %s", err))
|
|
}
|
|
}
|
|
}
|
|
|
|
if forwardID, ok := state.Get("port_forward_id").(string); ok && forwardID != "" {
|
|
// Create a new parameter struct.
|
|
p := client.Firewall.NewDeletePortForwardingRuleParams(forwardID)
|
|
|
|
ui.Message("Deleting port forward...")
|
|
if _, err := client.Firewall.DeletePortForwardingRule(p); err != nil {
|
|
// This is a very poor way to be told the ID does no longer exist :(
|
|
if !strings.Contains(err.Error(), fmt.Sprintf(
|
|
"Invalid parameter id value=%s due to incorrect long value format, "+
|
|
"or entity does not exist", forwardID)) {
|
|
ui.Error(fmt.Sprintf("Error deleting port forward: %s", err))
|
|
}
|
|
}
|
|
}
|
|
|
|
if ipAddrID, ok := state.Get("ip_address_id").(string); ok && ipAddrID != "" {
|
|
// Create a new parameter struct.
|
|
p := client.Address.NewDisassociateIpAddressParams(ipAddrID)
|
|
|
|
ui.Message("Releasing public IP address...")
|
|
if _, err := client.Address.DisassociateIpAddress(p); err != nil {
|
|
// This is a very poor way to be told the ID does no longer exist :(
|
|
if !strings.Contains(err.Error(), fmt.Sprintf(
|
|
"Invalid parameter id value=%s due to incorrect long value format, "+
|
|
"or entity does not exist", ipAddrID)) {
|
|
ui.Error(fmt.Sprintf("Error releasing public IP address: %s", err))
|
|
}
|
|
}
|
|
}
|
|
|
|
ui.Message("Networking has been cleaned!")
|
|
|
|
return
|
|
}
|