github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/cloudstack/step_configure_networking.go (about)

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