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