tailcfg: update + clean up machine API docs, remove some dead code

The machine API docs were still often referring to the nacl boxes
which are no longer present in the client. Fix that up, fix the paths,
add the HTTP methods.

And then delete some unused code I found in the process.

Updates #cleanup

Change-Id: I1591274acbb00a08b7ca4879dfebd5e6b8a9fbcd
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2025-02-11 10:09:29 -08:00 committed by Brad Fitzpatrick
parent 8b347060f8
commit b865ceea20
2 changed files with 32 additions and 158 deletions

View File

@ -1092,68 +1092,6 @@ func (h *Hostinfo) Equal(h2 *Hostinfo) bool {
return reflect.DeepEqual(h, h2) return reflect.DeepEqual(h, h2)
} }
// HowUnequal returns a list of paths through Hostinfo where h and h2 differ.
// If they differ in nil-ness, the path is "nil", otherwise the path is like
// "ShieldsUp" or "NetInfo.nil" or "NetInfo.PCP".
func (h *Hostinfo) HowUnequal(h2 *Hostinfo) (path []string) {
return appendStructPtrDiff(nil, "", reflect.ValueOf(h), reflect.ValueOf(h2))
}
func appendStructPtrDiff(base []string, pfx string, p1, p2 reflect.Value) (ret []string) {
ret = base
if p1.IsNil() && p2.IsNil() {
return base
}
mkPath := func(b string) string {
if pfx == "" {
return b
}
return pfx + "." + b
}
if p1.IsNil() || p2.IsNil() {
return append(base, mkPath("nil"))
}
v1, v2 := p1.Elem(), p2.Elem()
t := v1.Type()
for i, n := 0, t.NumField(); i < n; i++ {
sf := t.Field(i)
switch sf.Type.Kind() {
case reflect.String:
if v1.Field(i).String() != v2.Field(i).String() {
ret = append(ret, mkPath(sf.Name))
}
continue
case reflect.Bool:
if v1.Field(i).Bool() != v2.Field(i).Bool() {
ret = append(ret, mkPath(sf.Name))
}
continue
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if v1.Field(i).Int() != v2.Field(i).Int() {
ret = append(ret, mkPath(sf.Name))
}
continue
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
if v1.Field(i).Uint() != v2.Field(i).Uint() {
ret = append(ret, mkPath(sf.Name))
}
continue
case reflect.Slice, reflect.Map:
if !reflect.DeepEqual(v1.Field(i).Interface(), v2.Field(i).Interface()) {
ret = append(ret, mkPath(sf.Name))
}
continue
case reflect.Ptr:
if sf.Type.Elem().Kind() == reflect.Struct {
ret = appendStructPtrDiff(ret, sf.Name, v1.Field(i), v2.Field(i))
continue
}
}
panic(fmt.Sprintf("unsupported type at %s: %s", mkPath(sf.Name), sf.Type.String()))
}
return ret
}
// SignatureType specifies a scheme for signing RegisterRequest messages. It // SignatureType specifies a scheme for signing RegisterRequest messages. It
// specifies the crypto algorithms to use, the contents of what is signed, and // specifies the crypto algorithms to use, the contents of what is signed, and
// any other relevant details. Historically, requests were unsigned so the zero // any other relevant details. Historically, requests were unsigned so the zero
@ -1234,11 +1172,11 @@ type RegisterResponseAuth struct {
AuthKey string `json:",omitempty"` AuthKey string `json:",omitempty"`
} }
// RegisterRequest is sent by a client to register the key for a node. // RegisterRequest is a request to register a key for a node.
// It is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box,
// using the local machine key, and sent to:
// //
// https://login.tailscale.com/machine/<mkey hex> // This is JSON-encoded and sent over the control plane connection to:
//
// POST https://<control-plane>/machine/register.
type RegisterRequest struct { type RegisterRequest struct {
_ structs.Incomparable _ structs.Incomparable
@ -1354,10 +1292,9 @@ type Endpoint struct {
// The request includes a copy of the client's current set of WireGuard // The request includes a copy of the client's current set of WireGuard
// endpoints and general host information. // endpoints and general host information.
// //
// The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // This is JSON-encoded and sent over the control plane connection to:
// using the local machine key, and sent to:
// //
// https://login.tailscale.com/machine/<mkey hex>/map // POST https://<control-plane>/machine/map
type MapRequest struct { type MapRequest struct {
// Version is incremented whenever the client code changes enough that // Version is incremented whenever the client code changes enough that
// we want to signal to the control server that we're capable of something // we want to signal to the control server that we're capable of something
@ -1797,9 +1734,14 @@ type DNSRecord struct {
PingPeerAPI PingType = "peerapi" PingPeerAPI PingType = "peerapi"
) )
// PingRequest with no IP and Types is a request to send an HTTP request to prove the // PingRequest is a request from the control plane to the local node to probe
// long-polling client is still connected. // something.
// PingRequest with Types and IP, will send a ping to the IP and send a POST //
// A PingRequest with no IP and Types is a request from the control plane to the
// local node to send an HTTP request to a URL to prove the long-polling client
// is still connected.
//
// A PingRequest with Types and IP, will send a ping to the IP and send a POST
// request containing a PingResponse to the URL containing results. // request containing a PingResponse to the URL containing results.
type PingRequest struct { type PingRequest struct {
// URL is the URL to reply to the PingRequest to. // URL is the URL to reply to the PingRequest to.
@ -2506,13 +2448,13 @@ type Oauth2Token struct {
// SetDNSRequest is a request to add a DNS record. // SetDNSRequest is a request to add a DNS record.
// //
// This is used for ACME DNS-01 challenges (so people can use // This is used to let tailscaled clients complete their ACME DNS-01 challenges
// LetsEncrypt, etc). // (so people can use LetsEncrypt, etc) to get TLS certificates for
// their foo.bar.ts.net MagicDNS names.
// //
// The request is encoded to JSON, encrypted with golang.org/x/crypto/nacl/box, // This is JSON-encoded and sent over the control plane connection to:
// using the local machine key, and sent to:
// //
// https://login.tailscale.com/machine/<mkey hex>/set-dns // POST https://<control-plane>/machine/set-dns
type SetDNSRequest struct { type SetDNSRequest struct {
// Version is the client's capabilities // Version is the client's capabilities
// (CurrentCapabilityVersion) when using the Noise transport. // (CurrentCapabilityVersion) when using the Noise transport.
@ -2542,7 +2484,9 @@ type SetDNSRequest struct {
type SetDNSResponse struct{} type SetDNSResponse struct{}
// HealthChangeRequest is the JSON request body type used to report // HealthChangeRequest is the JSON request body type used to report
// node health changes to https://<control>/machine/<mkey hex>/update-health. // node health changes to:
//
// POST https://<control-plane>/machine/update-health.
type HealthChangeRequest struct { type HealthChangeRequest struct {
Subsys string // a health.Subsystem value in string form Subsys string // a health.Subsystem value in string form
Error string // or empty if cleared Error string // or empty if cleared
@ -2557,6 +2501,10 @@ type HealthChangeRequest struct {
// //
// As of 2024-12-30, this is an experimental dev feature // As of 2024-12-30, this is an experimental dev feature
// for internal testing. See tailscale/corp#24690. // for internal testing. See tailscale/corp#24690.
//
// This is JSON-encoded and sent over the control plane connection to:
//
// PATCH https://<control-plane>/machine/set-device-attr
type SetDeviceAttributesRequest struct { type SetDeviceAttributesRequest struct {
// Version is the current binary's [CurrentCapabilityVersion]. // Version is the current binary's [CurrentCapabilityVersion].
Version CapabilityVersion Version CapabilityVersion
@ -2746,6 +2694,8 @@ type SSHRecorderFailureAction struct {
// SSHEventNotifyRequest is the JSON payload sent to the NotifyURL // SSHEventNotifyRequest is the JSON payload sent to the NotifyURL
// for an SSH event. // for an SSH event.
//
// POST https://<control-plane>/[...varies, sent in SSH policy...]
type SSHEventNotifyRequest struct { type SSHEventNotifyRequest struct {
// EventType is the type of notify request being sent. // EventType is the type of notify request being sent.
EventType SSHEventType EventType SSHEventType
@ -2806,9 +2756,9 @@ type SSHRecordingAttempt struct {
FailureMessage string FailureMessage string
} }
// QueryFeatureRequest is a request sent to "/machine/feature/query" // QueryFeatureRequest is a request sent to "POST /machine/feature/query" to get
// to get instructions on how to enable a feature, such as Funnel, // instructions on how to enable a feature, such as Funnel, for the node's
// for the node's tailnet. // tailnet.
// //
// See QueryFeatureResponse for response structure. // See QueryFeatureResponse for response structure.
type QueryFeatureRequest struct { type QueryFeatureRequest struct {
@ -2897,7 +2847,7 @@ type OverTLSPublicKeyResponse struct {
// The token can be presented to any resource provider which offers OIDC // The token can be presented to any resource provider which offers OIDC
// Federation. // Federation.
// //
// It is JSON-encoded and sent over Noise to "/machine/id-token". // It is JSON-encoded and sent over Noise to "POST /machine/id-token".
type TokenRequest struct { type TokenRequest struct {
// CapVersion is the client's current CapabilityVersion. // CapVersion is the client's current CapabilityVersion.
CapVersion CapabilityVersion CapVersion CapabilityVersion

View File

@ -281,82 +281,6 @@ func TestHostinfoEqual(t *testing.T) {
} }
} }
func TestHostinfoHowEqual(t *testing.T) {
tests := []struct {
a, b *Hostinfo
want []string
}{
{
a: nil,
b: nil,
want: nil,
},
{
a: new(Hostinfo),
b: nil,
want: []string{"nil"},
},
{
a: nil,
b: new(Hostinfo),
want: []string{"nil"},
},
{
a: new(Hostinfo),
b: new(Hostinfo),
want: nil,
},
{
a: &Hostinfo{
IPNVersion: "1",
ShieldsUp: false,
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/24")},
},
b: &Hostinfo{
IPNVersion: "2",
ShieldsUp: true,
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/25")},
},
want: []string{"IPNVersion", "ShieldsUp", "RoutableIPs"},
},
{
a: &Hostinfo{
IPNVersion: "1",
},
b: &Hostinfo{
IPNVersion: "2",
NetInfo: new(NetInfo),
},
want: []string{"IPNVersion", "NetInfo.nil"},
},
{
a: &Hostinfo{
IPNVersion: "1",
NetInfo: &NetInfo{
WorkingIPv6: "true",
HavePortMap: true,
LinkType: "foo",
PreferredDERP: 123,
DERPLatency: map[string]float64{
"foo": 1.0,
},
},
},
b: &Hostinfo{
IPNVersion: "2",
NetInfo: &NetInfo{},
},
want: []string{"IPNVersion", "NetInfo.WorkingIPv6", "NetInfo.HavePortMap", "NetInfo.PreferredDERP", "NetInfo.LinkType", "NetInfo.DERPLatency"},
},
}
for i, tt := range tests {
got := tt.a.HowUnequal(tt.b)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("%d. got %q; want %q", i, got, tt.want)
}
}
}
func TestHostinfoTailscaleSSHEnabled(t *testing.T) { func TestHostinfoTailscaleSSHEnabled(t *testing.T) {
tests := []struct { tests := []struct {
hi *Hostinfo hi *Hostinfo