/
l4_static_address.go
75 lines (63 loc) · 2.43 KB
/
l4_static_address.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package annotations
import (
"errors"
"strings"
"google.golang.org/api/googleapi"
"k8s.io/cloud-provider-gcp/providers/gce"
)
// IPVersion represents compute.Address IpVersion field
type IPVersion = string
const (
// StaticL4AddressesAnnotationKey is new annotation key to specify static IPs (by name) for the services.
// Supports both IPv4 and IPv6
StaticL4AddressesAnnotationKey = "networking.gke.io/load-balancer-ip-addresses"
maxNumberOfAddresses = 2
IPv4Version IPVersion = "IPV4"
IPv6Version IPVersion = "IPV6"
)
// IPv4AddressAnnotation return IPv4 address from networking.gke.io/load-balancer-ip-addresses annotation.
// If no IPv4 address found, returns empty string.
func (svc *Service) IPv4AddressAnnotation(cloud *gce.Cloud) (string, error) {
return ipAddressFromAnnotation(svc, cloud, IPv4Version)
}
// IPv6AddressAnnotation return IPv6 address from networking.gke.io/load-balancer-ip-addresses annotation.
// If no IPv6 address found, returns empty string.
func (svc *Service) IPv6AddressAnnotation(cloud *gce.Cloud) (string, error) {
return ipAddressFromAnnotation(svc, cloud, IPv6Version)
}
// ipAddressFromAnnotation checks annotation networking.gke.io/load-balancer-ip-addresses,
// which should store comma separate names of IP Addresses reserved in google cloud,
// and returns first address that matches required IpVersion (IPV4 or IPV6).
func ipAddressFromAnnotation(svc *Service, cloud *gce.Cloud, ipVersion string) (string, error) {
annotationVal, ok := svc.v[StaticL4AddressesAnnotationKey]
if !ok {
return "", nil
}
addressNames := strings.Split(annotationVal, ",")
// Truncated to 2 values (this is technically maximum, 1 IPv4 and 1 IPv6 address)
// to not make too many API calls.
if len(addressNames) > maxNumberOfAddresses {
addressNames = addressNames[:maxNumberOfAddresses]
}
for _, addressName := range addressNames {
trimmedAddressName := strings.TrimSpace(addressName)
cloudAddress, err := cloud.GetRegionAddress(trimmedAddressName, cloud.Region())
if err != nil {
if isNotFoundError(err) {
continue
}
return "", err
}
if cloudAddress.IpVersion == "" {
cloudAddress.IpVersion = IPv4Version
}
if cloudAddress.IpVersion == ipVersion {
return cloudAddress.Address, nil
}
}
return "", nil
}
func isNotFoundError(err error) bool {
var apiErr *googleapi.Error
return errors.As(err, &apiErr) && apiErr.Code == 404
}