github.phpd.cn/hashicorp/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 }