github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/cloudstack/step_configure_networking.go (about)

     1  package cloudstack
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/mitchellh/multistep"
    10  	"github.com/mitchellh/packer/packer"
    11  	"github.com/xanzy/go-cloudstack/cloudstack"
    12  )
    13  
    14  type stepSetupNetworking struct {
    15  	privatePort int
    16  	publicPort  int
    17  }
    18  
    19  func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction {
    20  	client := state.Get("client").(*cloudstack.CloudStackClient)
    21  	config := state.Get("config").(*Config)
    22  	ui := state.Get("ui").(packer.Ui)
    23  
    24  	ui.Say("Setup networking...")
    25  
    26  	if config.UseLocalIPAddress {
    27  		ui.Message("Using the local IP address...")
    28  		ui.Message("Networking has been setup!")
    29  		return multistep.ActionContinue
    30  	}
    31  
    32  	// Generate a random public port used to configure our port forward.
    33  	rand.Seed(time.Now().UnixNano())
    34  	s.publicPort = 50000 + rand.Intn(10000)
    35  
    36  	// Set the currently configured port to be the private port.
    37  	s.privatePort = config.Comm.Port()
    38  
    39  	// Set the SSH or WinRM port to be the randomly generated public port.
    40  	switch config.Comm.Type {
    41  	case "ssh":
    42  		config.Comm.SSHPort = s.publicPort
    43  	case "winrm":
    44  		config.Comm.WinRMPort = s.publicPort
    45  	}
    46  
    47  	// Retrieve the instance ID from the previously saved state.
    48  	instanceID, ok := state.Get("instance_id").(string)
    49  	if !ok || instanceID == "" {
    50  		ui.Error("Could not retrieve instance_id from state!")
    51  		return multistep.ActionHalt
    52  	}
    53  
    54  	network, _, err := client.Network.GetNetworkByID(
    55  		config.Network,
    56  		cloudstack.WithProject(config.Project),
    57  	)
    58  	if err != nil {
    59  		ui.Error(fmt.Sprintf("Failed to retrieve the network object: %s", err))
    60  		return multistep.ActionHalt
    61  	}
    62  
    63  	if config.PublicIPAddress == "" {
    64  		ui.Message("Associating public IP address...")
    65  		p := client.Address.NewAssociateIpAddressParams()
    66  
    67  		if config.Project != "" {
    68  			p.SetProjectid(config.Project)
    69  		}
    70  
    71  		if network.Vpcid != "" {
    72  			p.SetVpcid(network.Vpcid)
    73  		} else {
    74  			p.SetNetworkid(network.Id)
    75  		}
    76  
    77  		// Associate a new public IP address.
    78  		ipAddr, err := client.Address.AssociateIpAddress(p)
    79  		if err != nil {
    80  			ui.Error(fmt.Sprintf("Failed to associate public IP address: %s", err))
    81  			return multistep.ActionHalt
    82  		}
    83  
    84  		// Set the IP address and it's ID.
    85  		config.PublicIPAddress = ipAddr.Id
    86  		config.hostAddress = ipAddr.Ipaddress
    87  
    88  		// Store the IP address ID.
    89  		state.Put("ip_address_id", ipAddr.Id)
    90  	}
    91  
    92  	ui.Message("Creating port forward...")
    93  	p := client.Firewall.NewCreatePortForwardingRuleParams(
    94  		config.PublicIPAddress,
    95  		s.privatePort,
    96  		"TCP",
    97  		s.publicPort,
    98  		instanceID,
    99  	)
   100  
   101  	// Configure the port forward.
   102  	p.SetNetworkid(network.Id)
   103  	p.SetOpenfirewall(false)
   104  
   105  	// Create the port forward.
   106  	forward, err := client.Firewall.CreatePortForwardingRule(p)
   107  	if err != nil {
   108  		ui.Error(fmt.Sprintf("Failed to create port forward: %s", err))
   109  	}
   110  
   111  	// Store the port forward ID.
   112  	state.Put("port_forward_id", forward.Id)
   113  
   114  	if network.Vpcid != "" {
   115  		ui.Message("Creating network ACL rule...")
   116  
   117  		if network.Aclid == "" {
   118  			ui.Error("Failed to configure the firewall: no ACL connected to the VPC network")
   119  			return multistep.ActionHalt
   120  		}
   121  
   122  		// Create a new parameter struct.
   123  		p := client.NetworkACL.NewCreateNetworkACLParams("TCP")
   124  
   125  		// Configure the network ACL rule.
   126  		p.SetAclid(network.Aclid)
   127  		p.SetAction("allow")
   128  		p.SetCidrlist(config.CIDRList)
   129  		p.SetStartport(s.privatePort)
   130  		p.SetEndport(s.privatePort)
   131  		p.SetTraffictype("ingress")
   132  
   133  		// Create the network ACL rule.
   134  		aclRule, err := client.NetworkACL.CreateNetworkACL(p)
   135  		if err != nil {
   136  			ui.Error(fmt.Sprintf("Failed to create network ACL rule: %s", err))
   137  			return multistep.ActionHalt
   138  		}
   139  
   140  		// Store the network ACL rule ID.
   141  		state.Put("network_acl_rule_id", aclRule.Id)
   142  	} else {
   143  		ui.Message("Creating firewall rule...")
   144  
   145  		// Create a new parameter struct.
   146  		p := client.Firewall.NewCreateFirewallRuleParams(config.PublicIPAddress, "TCP")
   147  
   148  		// Configure the firewall rule.
   149  		p.SetCidrlist(config.CIDRList)
   150  		p.SetStartport(s.publicPort)
   151  		p.SetEndport(s.publicPort)
   152  
   153  		fwRule, err := client.Firewall.CreateFirewallRule(p)
   154  		if err != nil {
   155  			ui.Error(fmt.Sprintf("Failed to create firewall rule: %s", err))
   156  			return multistep.ActionHalt
   157  		}
   158  
   159  		// Store the firewall rule ID.
   160  		state.Put("firewall_rule_id", fwRule.Id)
   161  	}
   162  
   163  	ui.Message("Networking has been setup!")
   164  
   165  	return multistep.ActionContinue
   166  }
   167  
   168  // Cleanup any resources that may have been created during the Run phase.
   169  func (s *stepSetupNetworking) Cleanup(state multistep.StateBag) {
   170  	client := state.Get("client").(*cloudstack.CloudStackClient)
   171  	ui := state.Get("ui").(packer.Ui)
   172  
   173  	ui.Say("Cleanup networking...")
   174  
   175  	if fwRuleID, ok := state.Get("firewall_rule_id").(string); ok && fwRuleID != "" {
   176  		// Create a new parameter struct.
   177  		p := client.Firewall.NewDeleteFirewallRuleParams(fwRuleID)
   178  
   179  		ui.Message("Deleting firewal rule...")
   180  		if _, err := client.Firewall.DeleteFirewallRule(p); err != nil {
   181  			// This is a very poor way to be told the ID does no longer exist :(
   182  			if !strings.Contains(err.Error(), fmt.Sprintf(
   183  				"Invalid parameter id value=%s due to incorrect long value format, "+
   184  					"or entity does not exist", fwRuleID)) {
   185  				ui.Error(fmt.Sprintf("Error deleting firewall rule: %s", err))
   186  			}
   187  		}
   188  	}
   189  
   190  	if aclRuleID, ok := state.Get("network_acl_rule_id").(string); ok && aclRuleID != "" {
   191  		// Create a new parameter struct.
   192  		p := client.NetworkACL.NewDeleteNetworkACLParams(aclRuleID)
   193  
   194  		ui.Message("Deleting network ACL rule...")
   195  		if _, err := client.NetworkACL.DeleteNetworkACL(p); err != nil {
   196  			// This is a very poor way to be told the ID does no longer exist :(
   197  			if !strings.Contains(err.Error(), fmt.Sprintf(
   198  				"Invalid parameter id value=%s due to incorrect long value format, "+
   199  					"or entity does not exist", aclRuleID)) {
   200  				ui.Error(fmt.Sprintf("Error deleting network ACL rule: %s", err))
   201  			}
   202  		}
   203  	}
   204  
   205  	if forwardID, ok := state.Get("port_forward_id").(string); ok && forwardID != "" {
   206  		// Create a new parameter struct.
   207  		p := client.Firewall.NewDeletePortForwardingRuleParams(forwardID)
   208  
   209  		ui.Message("Deleting port forward...")
   210  		if _, err := client.Firewall.DeletePortForwardingRule(p); err != nil {
   211  			// This is a very poor way to be told the ID does no longer exist :(
   212  			if !strings.Contains(err.Error(), fmt.Sprintf(
   213  				"Invalid parameter id value=%s due to incorrect long value format, "+
   214  					"or entity does not exist", forwardID)) {
   215  				ui.Error(fmt.Sprintf("Error deleting port forward: %s", err))
   216  			}
   217  		}
   218  	}
   219  
   220  	if ipAddrID, ok := state.Get("ip_address_id").(string); ok && ipAddrID != "" {
   221  		// Create a new parameter struct.
   222  		p := client.Address.NewDisassociateIpAddressParams(ipAddrID)
   223  
   224  		ui.Message("Releasing public IP address...")
   225  		if _, err := client.Address.DisassociateIpAddress(p); err != nil {
   226  			// This is a very poor way to be told the ID does no longer exist :(
   227  			if !strings.Contains(err.Error(), fmt.Sprintf(
   228  				"Invalid parameter id value=%s due to incorrect long value format, "+
   229  					"or entity does not exist", ipAddrID)) {
   230  				ui.Error(fmt.Sprintf("Error releasing public IP address: %s", err))
   231  			}
   232  		}
   233  	}
   234  
   235  	ui.Message("Networking has been cleaned!")
   236  
   237  	return
   238  }