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