diff --git a/README.md b/README.md index 69380bd8..bf102bbc 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,7 @@ Environment Variable | Default | Description `LINODE_INSTANCE_CACHE_TTL` | `15` | Default timeout of instance cache in seconds `LINODE_ROUTES_CACHE_TTL_SECONDS` | `60` | Default timeout of route cache in seconds `LINODE_REQUEST_TIMEOUT_SECONDS` | `120` | Default timeout in seconds for http requests to linode API +`LINODE_EXTERNAL_SUBNET` | `` | Mark private network as external. Example - `172.24.0.0/16` ## Generating a Manifest for Deployment Use the script located at `./deploy/generate-manifest.sh` to generate a self-contained deployment manifest for the Linode CCM. Two arguments are required. diff --git a/cloud/linode/cloud.go b/cloud/linode/cloud.go index f1138988..99f88e9a 100644 --- a/cloud/linode/cloud.go +++ b/cloud/linode/cloud.go @@ -3,6 +3,7 @@ package linode import ( "fmt" "io" + "net/netip" "os" "strconv" "sync" @@ -37,6 +38,7 @@ var Options struct { VPCName string LoadBalancerType string BGPNodeSelector string + LinodeExternalNetwork *netip.Prefix } // vpcDetails is set when VPCName options flag is set. diff --git a/cloud/linode/common.go b/cloud/linode/common.go index 39932c31..79f6ed38 100644 --- a/cloud/linode/common.go +++ b/cloud/linode/common.go @@ -2,6 +2,8 @@ package linode import ( "fmt" + "net" + "net/netip" "strconv" "strings" @@ -42,3 +44,14 @@ func IgnoreLinodeAPIError(err error, code int) error { return err } + +func isPrivate(ip *net.IP) bool { + if Options.LinodeExternalNetwork == nil { + return ip.IsPrivate() + } + ipAddr, err := netip.ParseAddr(ip.String()) + if err != nil { + panic(err) + } + return ip.IsPrivate() && !Options.LinodeExternalNetwork.Contains(ipAddr) +} diff --git a/cloud/linode/instances.go b/cloud/linode/instances.go index 21711745..0a78e5d6 100644 --- a/cloud/linode/instances.go +++ b/cloud/linode/instances.go @@ -49,7 +49,7 @@ func (nc *nodeCache) getInstanceAddresses(instance linodego.Instance, vpcips []s for _, ip := range instance.IPv4 { ipType := v1.NodeExternalIP - if ip.IsPrivate() { + if isPrivate(ip) { ipType = v1.NodeInternalIP } ips = append(ips, nodeIP{ip: ip.String(), ipType: ipType}) @@ -155,7 +155,7 @@ func (i *instances) linodeByIP(kNode *v1.Node) (*linodego.Instance, error) { } for _, node := range i.nodeCache.nodes { for _, nodeIP := range node.instance.IPv4 { - if !nodeIP.IsPrivate() && slices.Contains(kNodeAddresses, nodeIP.String()) { + if !isPrivate(nodeIP) && slices.Contains(kNodeAddresses, nodeIP.String()) { return node.instance, nil } } diff --git a/cloud/linode/node_controller.go b/cloud/linode/node_controller.go index 3c980bb7..fe502a6a 100644 --- a/cloud/linode/node_controller.go +++ b/cloud/linode/node_controller.go @@ -172,7 +172,7 @@ func (s *nodeController) handleNode(ctx context.Context, node *v1.Node) error { // supports other subnets with nodebalancer, this logic needs to be updated. // https://www.linode.com/docs/api/linode-instances/#linode-view for _, addr := range linode.IPv4 { - if addr.IsPrivate() { + if isPrivate(addr) { expectedPrivateIP = addr.String() break } diff --git a/main.go b/main.go index 2e99b10a..116dcaa5 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "context" "flag" "fmt" + "net/netip" "os" "k8s.io/component-base/logs" @@ -25,9 +26,10 @@ import ( ) const ( - sentryDSNVariable = "SENTRY_DSN" - sentryEnvironmentVariable = "SENTRY_ENVIRONMENT" - sentryReleaseVariable = "SENTRY_RELEASE" + sentryDSNVariable = "SENTRY_DSN" + sentryEnvironmentVariable = "SENTRY_ENVIRONMENT" + sentryReleaseVariable = "SENTRY_RELEASE" + linodeExternalSubnetVariable = "LINODE_EXTERNAL_SUBNET" ) func initializeSentry() { @@ -114,6 +116,17 @@ func main() { os.Exit(1) } + if externalSubnet, ok := os.LookupEnv(linodeExternalSubnetVariable); ok && externalSubnet != "" { + network, err := netip.ParsePrefix(externalSubnet) + if err != nil { + msg := fmt.Sprintf("Unable to parse %s as network subnet: %v", externalSubnet, err) + sentry.CaptureError(ctx, fmt.Errorf(msg)) + fmt.Fprintf(os.Stderr, "%v\n", msg) + os.Exit(1) + } + linode.Options.LinodeExternalNetwork = &network + } + pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) pflag.CommandLine.AddGoFlagSet(flag.CommandLine)