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