From 03311bb0d62238d499f637912efea021d154b235 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 17 Jun 2021 14:16:09 -0700 Subject: [PATCH] hostinfo: add hostinfo package, move stuff out of controlclient And make it cheaper, so other parts of the code can check the environment. Signed-off-by: Brad Fitzpatrick --- cmd/tailscaled/depaware.txt | 3 +- control/controlclient/hostinfo_linux.go | 74 +-------------- hostinfo/hostinfo.go | 117 ++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 71 deletions(-) create mode 100644 hostinfo/hostinfo.go diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 6f6e3f1e4..ac4287b4d 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -25,7 +25,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de W 💣 github.com/tailscale/certstore from tailscale.com/control/controlclient github.com/tcnksm/go-httpstat from tailscale.com/net/netcheck 💣 go4.org/intern from inet.af/netaddr - 💣 go4.org/mem from tailscale.com/control/controlclient+ + 💣 go4.org/mem from tailscale.com/derp+ go4.org/unsafe/assume-no-moving-gc from go4.org/intern 💣 golang.zx2c4.com/wireguard/conn from golang.zx2c4.com/wireguard/device+ W 💣 golang.zx2c4.com/wireguard/conn/winrio from golang.zx2c4.com/wireguard/conn @@ -81,6 +81,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de tailscale.com/derp/derpmap from tailscale.com/cmd/tailscaled+ tailscale.com/disco from tailscale.com/derp+ tailscale.com/health from tailscale.com/control/controlclient+ + L tailscale.com/hostinfo from tailscale.com/control/controlclient tailscale.com/internal/deephash from tailscale.com/ipn/ipnlocal+ tailscale.com/ipn from tailscale.com/ipn/ipnserver+ tailscale.com/ipn/ipnlocal from tailscale.com/ipn/ipnserver+ diff --git a/control/controlclient/hostinfo_linux.go b/control/controlclient/hostinfo_linux.go index 4fbfb07e5..31f2d503e 100644 --- a/control/controlclient/hostinfo_linux.go +++ b/control/controlclient/hostinfo_linux.go @@ -9,13 +9,11 @@ import ( "bytes" "fmt" - "io" "io/ioutil" - "os" "strings" "syscall" - "go4.org/mem" + "tailscale.com/hostinfo" "tailscale.com/util/lineread" "tailscale.com/version/distro" ) @@ -56,20 +54,11 @@ func osVersionLinux() string { } attrBuf.WriteByte(byte(b)) } - if inContainer() { + if hostinfo.InContainer() { attrBuf.WriteString("; container") } - if inKnative() { - attrBuf.WriteString("; env=kn") - } - if inAWSLambda() { - attrBuf.WriteString("; env=lm") - } - if inHerokuDyno() { - attrBuf.WriteString("; env=hr") - } - if inAzureAppService() { - attrBuf.WriteString("; env=az") + if env := hostinfo.GetEnvType(); env != "" { + fmt.Fprintf(&attrBuf, "; env=%s", env) } attr := attrBuf.String() @@ -102,58 +91,3 @@ func osVersionLinux() string { } return fmt.Sprintf("Other%s", attr) } - -func inContainer() (ret bool) { - lineread.File("/proc/1/cgroup", func(line []byte) error { - if mem.Contains(mem.B(line), mem.S("/docker/")) || - mem.Contains(mem.B(line), mem.S("/lxc/")) { - ret = true - return io.EOF // arbitrary non-nil error to stop loop - } - return nil - }) - lineread.File("/proc/mounts", func(line []byte) error { - if mem.Contains(mem.B(line), mem.S("fuse.lxcfs")) { - ret = true - return io.EOF - } - return nil - }) - return -} - -func inKnative() bool { - // https://cloud.google.com/run/docs/reference/container-contract#env-vars - if os.Getenv("K_REVISION") != "" && os.Getenv("K_CONFIGURATION") != "" && - os.Getenv("K_SERVICE") != "" && os.Getenv("PORT") != "" { - return true - } - return false -} - -func inAWSLambda() bool { - // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html - if os.Getenv("AWS_LAMBDA_FUNCTION_NAME") != "" && - os.Getenv("AWS_LAMBDA_FUNCTION_VERSION") != "" && - os.Getenv("AWS_LAMBDA_INITIALIZATION_TYPE") != "" && - os.Getenv("AWS_LAMBDA_RUNTIME_API") != "" { - return true - } - return false -} - -func inHerokuDyno() bool { - // https://devcenter.heroku.com/articles/dynos#local-environment-variables - if os.Getenv("PORT") != "" && os.Getenv("DYNO") != "" { - return true - } - return false -} - -func inAzureAppService() bool { - if os.Getenv("APPSVC_RUN_ZIP") != "" && os.Getenv("WEBSITE_STACK") != "" && - os.Getenv("WEBSITE_AUTH_AUTO_AAD") != "" { - return true - } - return false -} diff --git a/hostinfo/hostinfo.go b/hostinfo/hostinfo.go new file mode 100644 index 000000000..3293692fc --- /dev/null +++ b/hostinfo/hostinfo.go @@ -0,0 +1,117 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package hostinfo answers questions about the host environment that Tailscale is +// running on. +// +// TODO(bradfitz): move more of control/controlclient/hostinfo_* into this package. +package hostinfo + +import ( + "io" + "os" + "runtime" + "sync/atomic" + + "go4.org/mem" + "tailscale.com/util/lineread" +) + +// EnvType represents a known environment type. +// The empty string, the default, means unknown. +type EnvType string + +const ( + KNative = EnvType("kn") + AWSLambda = EnvType("lm") + Heroku = EnvType("hr") + AzureAppService = EnvType("az") +) + +var envType atomic.Value // of EnvType + +func GetEnvType() EnvType { + if e, ok := envType.Load().(EnvType); ok { + return e + } + e := getEnvType() + envType.Store(e) + return e +} + +func getEnvType() EnvType { + if inKnative() { + return KNative + } + if inAWSLambda() { + return AWSLambda + } + if inHerokuDyno() { + return Heroku + } + if inAzureAppService() { + return AzureAppService + } + return "" +} + +// InContainer reports whether we're running in a container. +func InContainer() bool { + if runtime.GOOS != "linux" { + return false + } + var ret bool + lineread.File("/proc/1/cgroup", func(line []byte) error { + if mem.Contains(mem.B(line), mem.S("/docker/")) || + mem.Contains(mem.B(line), mem.S("/lxc/")) { + ret = true + return io.EOF // arbitrary non-nil error to stop loop + } + return nil + }) + lineread.File("/proc/mounts", func(line []byte) error { + if mem.Contains(mem.B(line), mem.S("fuse.lxcfs")) { + ret = true + return io.EOF + } + return nil + }) + return ret +} + +func inKnative() bool { + // https://cloud.google.com/run/docs/reference/container-contract#env-vars + if os.Getenv("K_REVISION") != "" && os.Getenv("K_CONFIGURATION") != "" && + os.Getenv("K_SERVICE") != "" && os.Getenv("PORT") != "" { + return true + } + return false +} + +func inAWSLambda() bool { + // https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html + if os.Getenv("AWS_LAMBDA_FUNCTION_NAME") != "" && + os.Getenv("AWS_LAMBDA_FUNCTION_VERSION") != "" && + os.Getenv("AWS_LAMBDA_INITIALIZATION_TYPE") != "" && + os.Getenv("AWS_LAMBDA_RUNTIME_API") != "" { + return true + } + return false +} + +func inHerokuDyno() bool { + // https://devcenter.heroku.com/articles/dynos#local-environment-variables + if os.Getenv("PORT") != "" && os.Getenv("DYNO") != "" { + return true + } + return false +} + +func inAzureAppService() bool { + if os.Getenv("APPSVC_RUN_ZIP") != "" && os.Getenv("WEBSITE_STACK") != "" && + os.Getenv("WEBSITE_AUTH_AUTO_AAD") != "" { + return true + } + return false +}