github.com/raghuse92/packer@v1.3.2/builder/openstack/networks.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 6 "github.com/google/uuid" 7 "github.com/gophercloud/gophercloud" 8 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces" 9 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external" 10 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" 11 "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" 12 "github.com/gophercloud/gophercloud/pagination" 13 ) 14 15 // CheckFloatingIP gets a floating IP by its ID and checks if it is already 16 // associated with any internal interface. 17 // It returns floating IP if it can be used. 18 func CheckFloatingIP(client *gophercloud.ServiceClient, id string) (*floatingips.FloatingIP, error) { 19 floatingIP, err := floatingips.Get(client, id).Extract() 20 if err != nil { 21 return nil, err 22 } 23 if floatingIP.PortID != "" { 24 return nil, fmt.Errorf("provided floating IP '%s' is already associated with port '%s'", 25 id, floatingIP.PortID) 26 } 27 28 return floatingIP, nil 29 } 30 31 // FindFreeFloatingIP returns free unassociated floating IP. 32 // It will return first floating IP if there are many. 33 func FindFreeFloatingIP(client *gophercloud.ServiceClient) (*floatingips.FloatingIP, error) { 34 var freeFloatingIP *floatingips.FloatingIP 35 36 pager := floatingips.List(client, floatingips.ListOpts{ 37 Status: "DOWN", 38 }) 39 err := pager.EachPage(func(page pagination.Page) (bool, error) { 40 candidates, err := floatingips.ExtractFloatingIPs(page) 41 if err != nil { 42 return false, err // stop and throw error out 43 } 44 45 for _, candidate := range candidates { 46 if candidate.PortID != "" { 47 continue // this floating IP is associated with port, move to next in list 48 } 49 50 // Floating IP is able to be allocated. 51 freeFloatingIP = &candidate 52 return false, nil // stop iterating over pages 53 } 54 return true, nil // try the next page 55 }) 56 if err != nil { 57 return nil, err 58 } 59 if freeFloatingIP == nil { 60 return nil, fmt.Errorf("no free floating IPs found") 61 } 62 63 return freeFloatingIP, nil 64 } 65 66 // GetInstancePortID returns internal port of the instance that can be used for 67 // the association of a floating IP. 68 // It will return an ID of a first port if there are many. 69 func GetInstancePortID(client *gophercloud.ServiceClient, id string) (string, error) { 70 interfacesPage, err := attachinterfaces.List(client, id).AllPages() 71 if err != nil { 72 return "", err 73 } 74 interfaces, err := attachinterfaces.ExtractInterfaces(interfacesPage) 75 if err != nil { 76 return "", err 77 } 78 if len(interfaces) == 0 { 79 return "", fmt.Errorf("instance '%s' has no interfaces", id) 80 } 81 82 return interfaces[0].PortID, nil 83 } 84 85 // CheckFloatingIPNetwork checks provided network reference and returns a valid 86 // Networking service ID. 87 func CheckFloatingIPNetwork(client *gophercloud.ServiceClient, networkRef string) (string, error) { 88 if _, err := uuid.Parse(networkRef); err != nil { 89 return GetFloatingIPNetworkIDByName(client, networkRef) 90 } 91 92 return networkRef, nil 93 } 94 95 // ExternalNetwork is a network with external router. 96 type ExternalNetwork struct { 97 networks.Network 98 external.NetworkExternalExt 99 } 100 101 // GetFloatingIPNetworkIDByName searches for the external network ID by the provided name. 102 func GetFloatingIPNetworkIDByName(client *gophercloud.ServiceClient, networkName string) (string, error) { 103 var externalNetworks []ExternalNetwork 104 105 allPages, err := networks.List(client, networks.ListOpts{ 106 Name: networkName, 107 }).AllPages() 108 if err != nil { 109 return "", err 110 } 111 112 if err := networks.ExtractNetworksInto(allPages, &externalNetworks); err != nil { 113 return "", err 114 } 115 116 if len(externalNetworks) == 0 { 117 return "", fmt.Errorf("can't find external network %s", networkName) 118 } 119 // Check and return the first external network. 120 if !externalNetworks[0].External { 121 return "", fmt.Errorf("network %s is not external", networkName) 122 } 123 124 return externalNetworks[0].ID, nil 125 }