tailcfg,hostinfo: add Hostinfo.Machine and Hostinfo.GoArchVar

For detecting a non-ideal binary running on the current CPU.

And for helping detect the best Synology package to update to.

Updates #6995

Change-Id: I722f806675b60ce95364471b11c388150c0d4aea
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2023-01-22 10:16:15 -08:00 committed by Brad Fitzpatrick
parent fd92fbd69e
commit 64547b2b86
6 changed files with 76 additions and 1 deletions

View File

@ -11,6 +11,7 @@ import (
"io"
"os"
"runtime"
"runtime/debug"
"strings"
"sync"
"sync/atomic"
@ -46,7 +47,9 @@ func New() *tailcfg.Hostinfo {
Desktop: desktop(),
Package: packageTypeCached(),
GoArch: runtime.GOARCH,
GoArchVar: lazyGoArchVar.Get(),
GoVersion: runtime.Version(),
Machine: condCall(unameMachine),
DeviceModel: deviceModel(),
Cloud: string(cloudenv.Get()),
NoLogsNoSupport: envknob.NoLogsNoSupport(),
@ -60,6 +63,7 @@ var (
distroName func() string
distroVersion func() string
distroCodeName func() string
unameMachine func() string
)
func condCall[T any](fn func() T) T {
@ -72,6 +76,7 @@ func condCall[T any](fn func() T) T {
var (
lazyInContainer = &lazyAtomicValue[opt.Bool]{f: ptr.To(inContainer)}
lazyGoArchVar = &lazyAtomicValue[string]{f: ptr.To(goArchVar)}
)
type lazyAtomicValue[T any] struct {
@ -321,6 +326,27 @@ func inDockerDesktop() bool {
return false
}
// goArchVar returns the GOARM or GOAMD64 etc value that the binary was built
// with.
func goArchVar() string {
bi, ok := debug.ReadBuildInfo()
if !ok {
return ""
}
// Look for GOARM, GOAMD64, GO386, etc. Note that the little-endian
// "le"-suffixed GOARCH values don't have their own environment variable.
//
// See https://pkg.go.dev/cmd/go#hdr-Environment_variables and the
// "Architecture-specific environment variables" section:
wantKey := "GO" + strings.ToUpper(strings.TrimSuffix(runtime.GOARCH, "le"))
for _, s := range bi.Settings {
if s.Key == wantKey {
return s.Value
}
}
return ""
}
type etcAptSrcResult struct {
mod time.Time
disabled bool

View File

@ -0,0 +1,39 @@
// Copyright (c) 2023 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.
//go:build linux || freebsd || openbsd || darwin
package hostinfo
import (
"runtime"
"golang.org/x/sys/unix"
"tailscale.com/types/ptr"
)
func init() {
unameMachine = lazyUnameMachine.Get
}
var lazyUnameMachine = &lazyAtomicValue[string]{f: ptr.To(unameMachineUnix)}
func unameMachineUnix() string {
switch runtime.GOOS {
case "android":
// Don't call on Android for now. We're late in the 1.36 release cycle
// and don't want to test syscall filters on various Android versions to
// see what's permitted. Notably, the hostinfo_linux.go file has build
// tag !android, so maybe Uname is verboten.
return ""
case "ios":
// For similar reasons, don't call on iOS. There aren't many iOS devices
// and we know their CPU properties so calling this is only risk and no
// reward.
return ""
}
var un unix.Utsname
unix.Uname(&un)
return unix.ByteSliceToString(un.Machine[:])
}

View File

@ -528,7 +528,9 @@ type Hostinfo struct {
ShareeNode bool `json:",omitempty"` // indicates this node exists in netmap because it's owned by a shared-to user
NoLogsNoSupport bool `json:",omitempty"` // indicates that the user has opted out of sending logs and support
WireIngress bool `json:",omitempty"` // indicates that the node wants the option to receive ingress connections
GoArch string `json:",omitempty"` // the host's GOARCH value (of the running binary)
Machine string `json:",omitempty"` // the current host's machine type (uname -m)
GoArch string `json:",omitempty"` // GOARCH value (of the built binary)
GoArchVar string `json:",omitempty"` // GOARM, GOAMD64, etc (of the built binary)
GoVersion string `json:",omitempty"` // Go version binary was built with
RoutableIPs []netip.Prefix `json:",omitempty"` // set of IP ranges this client can route
RequestTags []string `json:",omitempty"` // set of ACL tags this node wants to claim

View File

@ -137,7 +137,9 @@ var _HostinfoCloneNeedsRegeneration = Hostinfo(struct {
ShareeNode bool
NoLogsNoSupport bool
WireIngress bool
Machine string
GoArch string
GoArchVar string
GoVersion string
RoutableIPs []netip.Prefix
RequestTags []string

View File

@ -50,7 +50,9 @@ func TestHostinfoEqual(t *testing.T) {
"ShareeNode",
"NoLogsNoSupport",
"WireIngress",
"Machine",
"GoArch",
"GoArchVar",
"GoVersion",
"RoutableIPs",
"RequestTags",

View File

@ -276,7 +276,9 @@ func (v HostinfoView) ShieldsUp() bool { return v.ж.ShieldsUp }
func (v HostinfoView) ShareeNode() bool { return v.ж.ShareeNode }
func (v HostinfoView) NoLogsNoSupport() bool { return v.ж.NoLogsNoSupport }
func (v HostinfoView) WireIngress() bool { return v.ж.WireIngress }
func (v HostinfoView) Machine() string { return v.ж.Machine }
func (v HostinfoView) GoArch() string { return v.ж.GoArch }
func (v HostinfoView) GoArchVar() string { return v.ж.GoArchVar }
func (v HostinfoView) GoVersion() string { return v.ж.GoVersion }
func (v HostinfoView) RoutableIPs() views.IPPrefixSlice {
return views.IPPrefixSliceOf(v.ж.RoutableIPs)
@ -310,7 +312,9 @@ var _HostinfoViewNeedsRegeneration = Hostinfo(struct {
ShareeNode bool
NoLogsNoSupport bool
WireIngress bool
Machine string
GoArch string
GoArchVar string
GoVersion string
RoutableIPs []netip.Prefix
RequestTags []string