mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-04 06:31:54 +00:00
util/cloudenv: add support for DigitalOcean
Updates #4984 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: Ib229eb40af36a80e6b0fd1dd0cabb07f0d50a7d1
This commit is contained in:
parent
55b372a79f
commit
c1c50cfcc0
@ -8,6 +8,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"log"
|
"log"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tailscale.com/syncs"
|
"tailscale.com/syncs"
|
||||||
|
"tailscale.com/types/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CommonNonRoutableMetadataIP is the IP address of the metadata server
|
// CommonNonRoutableMetadataIP is the IP address of the metadata server
|
||||||
@ -40,9 +42,10 @@ const AzureResolverIP = "168.63.129.16"
|
|||||||
type Cloud string
|
type Cloud string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AWS = Cloud("aws") // Amazon Web Services (EC2 in particular)
|
AWS = Cloud("aws") // Amazon Web Services (EC2 in particular)
|
||||||
Azure = Cloud("azure") // Microsoft Azure
|
Azure = Cloud("azure") // Microsoft Azure
|
||||||
GCP = Cloud("gcp") // Google Cloud
|
GCP = Cloud("gcp") // Google Cloud
|
||||||
|
DigitalOcean = Cloud("digitalocean") // DigitalOcean
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResolverIP returns the cloud host's recursive DNS server or the
|
// ResolverIP returns the cloud host's recursive DNS server or the
|
||||||
@ -55,10 +58,27 @@ func (c Cloud) ResolverIP() string {
|
|||||||
return AWSResolverIP
|
return AWSResolverIP
|
||||||
case Azure:
|
case Azure:
|
||||||
return AzureResolverIP
|
return AzureResolverIP
|
||||||
|
case DigitalOcean:
|
||||||
|
return getDigitalOceanResolver()
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// https://docs.digitalocean.com/support/check-your-droplets-network-configuration/
|
||||||
|
digitalOceanResolvers = []string{"67.207.67.2", "67.207.67.3"}
|
||||||
|
digitalOceanResolver lazy.SyncValue[string]
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDigitalOceanResolver() string {
|
||||||
|
// Randomly select one of the available resolvers so we don't overload
|
||||||
|
// one of them by sending all traffic there.
|
||||||
|
return digitalOceanResolver.Get(func() string {
|
||||||
|
rn := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
return digitalOceanResolvers[rn.Intn(len(digitalOceanResolvers))]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// HasInternalTLD reports whether c is a cloud environment
|
// HasInternalTLD reports whether c is a cloud environment
|
||||||
// whose ResolverIP serves *.internal records.
|
// whose ResolverIP serves *.internal records.
|
||||||
func (c Cloud) HasInternalTLD() bool {
|
func (c Cloud) HasInternalTLD() bool {
|
||||||
@ -98,6 +118,12 @@ func getCloud() Cloud {
|
|||||||
return AWS
|
return AWS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sysVendor := readFileTrimmed("/sys/class/dmi/id/sys_vendor")
|
||||||
|
if sysVendor == "DigitalOcean" {
|
||||||
|
return DigitalOcean
|
||||||
|
}
|
||||||
|
// TODO(andrew): "Vultr" is also valid if we need it
|
||||||
|
|
||||||
prod := readFileTrimmed("/sys/class/dmi/id/product_name")
|
prod := readFileTrimmed("/sys/class/dmi/id/product_name")
|
||||||
if prod == "Google Compute Engine" {
|
if prod == "Google Compute Engine" {
|
||||||
return GCP
|
return GCP
|
||||||
@ -109,6 +135,7 @@ func getCloud() Cloud {
|
|||||||
// Azure, or maybe all Hyper-V?
|
// Azure, or maybe all Hyper-V?
|
||||||
hitMetadata = true
|
hitMetadata = true
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// TODO(bradfitz): use Win32_SystemEnclosure from WMI or something on
|
// TODO(bradfitz): use Win32_SystemEnclosure from WMI or something on
|
||||||
// Windows to see if it's a physical machine and skip the cloud check
|
// Windows to see if it's a physical machine and skip the cloud check
|
||||||
|
29
util/cloudenv/cloudenv_test.go
Normal file
29
util/cloudenv/cloudenv_test.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
package cloudenv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var extNetwork = flag.Bool("use-external-network", false, "use the external network in tests")
|
||||||
|
|
||||||
|
// Informational only since we can run tests in a variety of places.
|
||||||
|
func TestGetCloud(t *testing.T) {
|
||||||
|
if !*extNetwork {
|
||||||
|
t.Skip("skipping test without --use-external-network")
|
||||||
|
}
|
||||||
|
|
||||||
|
cloud := getCloud()
|
||||||
|
t.Logf("Cloud: %q", cloud)
|
||||||
|
t.Logf("Cloud.HasInternalTLD: %v", cloud.HasInternalTLD())
|
||||||
|
t.Logf("Cloud.ResolverIP: %q", cloud.ResolverIP())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetDigitalOceanResolver(t *testing.T) {
|
||||||
|
addr := netip.MustParseAddr(getDigitalOceanResolver())
|
||||||
|
t.Logf("got: %v", addr)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user