github.com/raghuse92/packer@v1.3.2/builder/openstack/step_allocate_ip.go (about)

     1  package openstack
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
     8  	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
     9  	"github.com/hashicorp/packer/helper/multistep"
    10  	"github.com/hashicorp/packer/packer"
    11  )
    12  
    13  type StepAllocateIp struct {
    14  	FloatingIPNetwork string
    15  	FloatingIP        string
    16  	ReuseIPs          bool
    17  }
    18  
    19  func (s *StepAllocateIp) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
    20  	ui := state.Get("ui").(packer.Ui)
    21  	config := state.Get("config").(*Config)
    22  	server := state.Get("server").(*servers.Server)
    23  
    24  	// We need the v2 compute client
    25  	computeClient, err := config.computeV2Client()
    26  	if err != nil {
    27  		err = fmt.Errorf("Error initializing compute client: %s", err)
    28  		state.Put("error", err)
    29  		return multistep.ActionHalt
    30  	}
    31  
    32  	// We need the v2 network client
    33  	networkClient, err := config.networkV2Client()
    34  	if err != nil {
    35  		err = fmt.Errorf("Error initializing network client: %s", err)
    36  		state.Put("error", err)
    37  		return multistep.ActionHalt
    38  	}
    39  
    40  	var instanceIP floatingips.FloatingIP
    41  
    42  	// This is here in case we error out before putting instanceIp into the
    43  	// statebag below, because it is requested by Cleanup()
    44  	state.Put("access_ip", &instanceIP)
    45  
    46  	// Try to Use the OpenStack floating IP by checking provided parameters in
    47  	// the following order:
    48  	//  - try to use "FloatingIP" ID directly if it's provided
    49  	//  - try to find free floating IP in the project if "ReuseIPs" is set
    50  	//  - create a new floating IP if "FloatingIPNetwork" is provided (it can be
    51  	//    ID or name of the network).
    52  	if s.FloatingIP != "" {
    53  		// Try to use FloatingIP if it was provided by the user.
    54  		freeFloatingIP, err := CheckFloatingIP(networkClient, s.FloatingIP)
    55  		if err != nil {
    56  			err := fmt.Errorf("Error using provided floating IP '%s': %s", s.FloatingIP, err)
    57  			state.Put("error", err)
    58  			ui.Error(err.Error())
    59  			return multistep.ActionHalt
    60  		}
    61  
    62  		instanceIP = *freeFloatingIP
    63  		ui.Message(fmt.Sprintf("Selected floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
    64  		state.Put("floatingip_istemp", false)
    65  	} else if s.ReuseIPs {
    66  		// If ReuseIPs is set to true and we have a free floating IP, use it rather
    67  		// than creating one.
    68  		ui.Say(fmt.Sprint("Searching for unassociated floating IP"))
    69  		freeFloatingIP, err := FindFreeFloatingIP(networkClient)
    70  		if err != nil {
    71  			err := fmt.Errorf("Error searching for floating IP: %s", err)
    72  			state.Put("error", err)
    73  			ui.Error(err.Error())
    74  			return multistep.ActionHalt
    75  		}
    76  
    77  		instanceIP = *freeFloatingIP
    78  		ui.Message(fmt.Sprintf("Selected floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
    79  		state.Put("floatingip_istemp", false)
    80  	} else if s.FloatingIPNetwork != "" {
    81  		// Lastly, if FloatingIPNetwork was provided by the user, we need to use it
    82  		// to allocate a new floating IP and associate it to the instance.
    83  		floatingNetwork, err := CheckFloatingIPNetwork(networkClient, s.FloatingIPNetwork)
    84  		if err != nil {
    85  			err := fmt.Errorf("Error using the provided floating_ip_network: %s", err)
    86  			state.Put("error", err)
    87  			ui.Error(err.Error())
    88  			return multistep.ActionHalt
    89  		}
    90  
    91  		ui.Say(fmt.Sprintf("Creating floating IP using network %s ...", floatingNetwork))
    92  		newIP, err := floatingips.Create(networkClient, floatingips.CreateOpts{
    93  			FloatingNetworkID: floatingNetwork,
    94  		}).Extract()
    95  		if err != nil {
    96  			err := fmt.Errorf("Error creating floating IP from floating network '%s': %s", floatingNetwork, err)
    97  			state.Put("error", err)
    98  			ui.Error(err.Error())
    99  			return multistep.ActionHalt
   100  		}
   101  
   102  		instanceIP = *newIP
   103  		ui.Message(fmt.Sprintf("Created floating IP: '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
   104  		state.Put("floatingip_istemp", true)
   105  	}
   106  
   107  	// Assoctate a floating IP if it was obtained in the previous steps.
   108  	if instanceIP.ID != "" {
   109  		ui.Say(fmt.Sprintf("Associating floating IP '%s' (%s) with instance port...",
   110  			instanceIP.ID, instanceIP.FloatingIP))
   111  
   112  		portID, err := GetInstancePortID(computeClient, server.ID)
   113  		if err != nil {
   114  			err := fmt.Errorf("Error getting interfaces of the instance '%s': %s", server.ID, err)
   115  			state.Put("error", err)
   116  			ui.Error(err.Error())
   117  			return multistep.ActionHalt
   118  		}
   119  
   120  		_, err = floatingips.Update(networkClient, instanceIP.ID, floatingips.UpdateOpts{
   121  			PortID: &portID,
   122  		}).Extract()
   123  		if err != nil {
   124  			err := fmt.Errorf(
   125  				"Error associating floating IP '%s' (%s) with instance port '%s': %s",
   126  				instanceIP.ID, instanceIP.FloatingIP, portID, err)
   127  			state.Put("error", err)
   128  			ui.Error(err.Error())
   129  			return multistep.ActionHalt
   130  		}
   131  
   132  		ui.Message(fmt.Sprintf(
   133  			"Added floating IP '%s' (%s) to instance!", instanceIP.ID, instanceIP.FloatingIP))
   134  	}
   135  
   136  	state.Put("access_ip", &instanceIP)
   137  	return multistep.ActionContinue
   138  }
   139  
   140  func (s *StepAllocateIp) Cleanup(state multistep.StateBag) {
   141  	config := state.Get("config").(*Config)
   142  	ui := state.Get("ui").(packer.Ui)
   143  	instanceIP := state.Get("access_ip").(*floatingips.FloatingIP)
   144  
   145  	// Don't delete pool addresses we didn't allocate
   146  	if state.Get("floatingip_istemp") == false {
   147  		return
   148  	}
   149  
   150  	// We need the v2 network client
   151  	client, err := config.networkV2Client()
   152  	if err != nil {
   153  		ui.Error(fmt.Sprintf(
   154  			"Error deleting temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
   155  		return
   156  	}
   157  
   158  	if instanceIP.ID != "" {
   159  		if err := floatingips.Delete(client, instanceIP.ID).ExtractErr(); err != nil {
   160  			ui.Error(fmt.Sprintf(
   161  				"Error deleting temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
   162  			return
   163  		}
   164  
   165  		ui.Say(fmt.Sprintf("Deleted temporary floating IP '%s' (%s)", instanceIP.ID, instanceIP.FloatingIP))
   166  	}
   167  }