github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/openstack/step_allocate_ip.go (about)

     1  package openstack
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips"
     7  	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
     8  	"github.com/gophercloud/gophercloud/pagination"
     9  	"github.com/hashicorp/packer/packer"
    10  	"github.com/mitchellh/multistep"
    11  )
    12  
    13  type StepAllocateIp struct {
    14  	FloatingIpPool string
    15  	FloatingIp     string
    16  	ReuseIps       bool
    17  }
    18  
    19  func (s *StepAllocateIp) Run(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  	client, 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  	var instanceIp floatingips.FloatingIP
    33  
    34  	// This is here in case we error out before putting instanceIp into the
    35  	// statebag below, because it is requested by Cleanup()
    36  	state.Put("access_ip", &instanceIp)
    37  
    38  	if s.FloatingIp != "" {
    39  		instanceIp.IP = s.FloatingIp
    40  	} else if s.FloatingIpPool != "" {
    41  		// If ReuseIps is set to true and we have a free floating IP in
    42  		// the pool, use it first rather than creating one
    43  		if s.ReuseIps {
    44  			ui.Say(fmt.Sprintf("Searching for unassociated floating IP in pool %s", s.FloatingIpPool))
    45  			pager := floatingips.List(client)
    46  			err := pager.EachPage(func(page pagination.Page) (bool, error) {
    47  				candidates, err := floatingips.ExtractFloatingIPs(page)
    48  
    49  				if err != nil {
    50  					return false, err // stop and throw error out
    51  				}
    52  
    53  				for _, candidate := range candidates {
    54  					if candidate.Pool != s.FloatingIpPool || candidate.InstanceID != "" {
    55  						continue // move to next in list
    56  					}
    57  
    58  					// In correct pool and able to be allocated
    59  					instanceIp.IP = candidate.IP
    60  					ui.Message(fmt.Sprintf("Selected floating IP: %s", instanceIp.IP))
    61  					state.Put("floatingip_istemp", false)
    62  					return false, nil // stop iterating over pages
    63  				}
    64  				return true, nil // try the next page
    65  			})
    66  
    67  			if err != nil {
    68  				err := fmt.Errorf("Error searching for floating ip from pool '%s'", s.FloatingIpPool)
    69  				state.Put("error", err)
    70  				ui.Error(err.Error())
    71  				return multistep.ActionHalt
    72  			}
    73  		}
    74  
    75  		if instanceIp.IP == "" {
    76  			ui.Say(fmt.Sprintf("Creating floating IP..."))
    77  			ui.Message(fmt.Sprintf("Pool: %s", s.FloatingIpPool))
    78  			newIp, err := floatingips.Create(client, floatingips.CreateOpts{
    79  				Pool: s.FloatingIpPool,
    80  			}).Extract()
    81  			if err != nil {
    82  				err := fmt.Errorf("Error creating floating ip from pool '%s'", s.FloatingIpPool)
    83  				state.Put("error", err)
    84  				ui.Error(err.Error())
    85  				return multistep.ActionHalt
    86  			}
    87  
    88  			instanceIp = *newIp
    89  			ui.Message(fmt.Sprintf("Created floating IP: %s", instanceIp.IP))
    90  			state.Put("floatingip_istemp", true)
    91  		}
    92  	}
    93  
    94  	if instanceIp.IP != "" {
    95  		ui.Say(fmt.Sprintf("Associating floating IP with server..."))
    96  		ui.Message(fmt.Sprintf("IP: %s", instanceIp.IP))
    97  		err := floatingips.AssociateInstance(client, server.ID, floatingips.AssociateOpts{
    98  			FloatingIP: instanceIp.IP,
    99  		}).ExtractErr()
   100  		if err != nil {
   101  			err := fmt.Errorf(
   102  				"Error associating floating IP %s with instance: %s",
   103  				instanceIp.IP, err)
   104  			state.Put("error", err)
   105  			ui.Error(err.Error())
   106  			return multistep.ActionHalt
   107  		}
   108  
   109  		ui.Message(fmt.Sprintf(
   110  			"Added floating IP %s to instance!", instanceIp.IP))
   111  	}
   112  
   113  	state.Put("access_ip", &instanceIp)
   114  	return multistep.ActionContinue
   115  }
   116  
   117  func (s *StepAllocateIp) Cleanup(state multistep.StateBag) {
   118  	config := state.Get("config").(Config)
   119  	ui := state.Get("ui").(packer.Ui)
   120  	instanceIp := state.Get("access_ip").(*floatingips.FloatingIP)
   121  
   122  	// Don't delete pool addresses we didn't allocate
   123  	if state.Get("floatingip_istemp") == false {
   124  		return
   125  	}
   126  
   127  	// We need the v2 compute client
   128  	client, err := config.computeV2Client()
   129  	if err != nil {
   130  		ui.Error(fmt.Sprintf(
   131  			"Error deleting temporary floating IP %s", instanceIp.IP))
   132  		return
   133  	}
   134  
   135  	if s.FloatingIpPool != "" && instanceIp.ID != "" {
   136  		if err := floatingips.Delete(client, instanceIp.ID).ExtractErr(); err != nil {
   137  			ui.Error(fmt.Sprintf(
   138  				"Error deleting temporary floating IP %s", instanceIp.IP))
   139  			return
   140  		}
   141  
   142  		ui.Say(fmt.Sprintf("Deleted temporary floating IP %s", instanceIp.IP))
   143  	}
   144  }