Remove usage of the deprecated OpenStack Compute service floating IP management and add methods to work with the OpenStack Networking service floating IPs API. Remove usage of the deprecated OpenStack Compute service floating IP pools and add methods to work with the OpenStack Networking service external networks API. Move reusable logic of working with the OpenStack Networking service API to a separate methods in the networking.go file. Pass error messages from the API services to the ui messages in the allocate IP step.
115 lines
3.4 KiB
Go
115 lines
3.4 KiB
Go
package openstack
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/gophercloud/gophercloud"
|
|
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces"
|
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external"
|
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
|
|
"github.com/gophercloud/gophercloud/pagination"
|
|
)
|
|
|
|
// ExternalNetwork is a network with external router.
|
|
type ExternalNetwork struct {
|
|
networks.Network
|
|
external.NetworkExternalExt
|
|
}
|
|
|
|
// FindExternalNetwork returns existing network with external router.
|
|
// It will return first network if there are many.
|
|
func FindExternalNetwork(client *gophercloud.ServiceClient) (*ExternalNetwork, error) {
|
|
var externalNetworks []ExternalNetwork
|
|
|
|
allPages, err := networks.List(client, networks.ListOpts{
|
|
Status: "ACTIVE",
|
|
}).AllPages()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Extract external networks from found networks.
|
|
err = networks.ExtractNetworksInto(allPages, &externalNetworks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(externalNetworks) == 0 {
|
|
return nil, fmt.Errorf("no external networks found")
|
|
}
|
|
|
|
// Return the first external network.
|
|
return &externalNetworks[0], nil
|
|
}
|
|
|
|
// CheckFloatingIP gets a floating IP by its ID and checks if it is already
|
|
// associated with any internal interface.
|
|
// It returns floating IP if it can be used.
|
|
func CheckFloatingIP(client *gophercloud.ServiceClient, id string) (*floatingips.FloatingIP, error) {
|
|
floatingIP, err := floatingips.Get(client, id).Extract()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if floatingIP.PortID != "" {
|
|
return nil, fmt.Errorf("provided floating IP '%s' is already associated with port '%s'",
|
|
id, floatingIP.PortID)
|
|
}
|
|
|
|
return floatingIP, nil
|
|
}
|
|
|
|
// FindFreeFloatingIP returns free unassociated floating IP.
|
|
// It will return first floating IP if there are many.
|
|
func FindFreeFloatingIP(client *gophercloud.ServiceClient) (*floatingips.FloatingIP, error) {
|
|
var freeFloatingIP *floatingips.FloatingIP
|
|
|
|
pager := floatingips.List(client, floatingips.ListOpts{
|
|
Status: "DOWN",
|
|
})
|
|
err := pager.EachPage(func(page pagination.Page) (bool, error) {
|
|
candidates, err := floatingips.ExtractFloatingIPs(page)
|
|
if err != nil {
|
|
return false, err // stop and throw error out
|
|
}
|
|
|
|
for _, candidate := range candidates {
|
|
if candidate.PortID != "" {
|
|
continue // this floating IP is associated with port, move to next in list
|
|
}
|
|
|
|
// Floating IP is able to be allocated.
|
|
freeFloatingIP = &candidate
|
|
return false, nil // stop iterating over pages
|
|
}
|
|
return true, nil // try the next page
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if freeFloatingIP == nil {
|
|
return nil, fmt.Errorf("no free floating IPs found")
|
|
}
|
|
|
|
return freeFloatingIP, nil
|
|
}
|
|
|
|
// GetInstancePortID returns internal port of the instance that can be used for
|
|
// the association of a floating IP.
|
|
// It will return an ID of a first port if there are many.
|
|
func GetInstancePortID(client *gophercloud.ServiceClient, id string) (string, error) {
|
|
interfacesPage, err := attachinterfaces.List(client, id).AllPages()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
interfaces, err := attachinterfaces.ExtractInterfaces(interfacesPage)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(interfaces) == 0 {
|
|
return "", fmt.Errorf("instance '%s' has no interfaces", id)
|
|
}
|
|
|
|
return interfaces[0].PortID, nil
|
|
}
|