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 }