types/persist: split controlclient.Persist into a small leaf package

This one alone doesn't modify the global dependency map much
(depaware.txt if anything looks slightly worse), but it leave
controlclient as only containing NetworkMap:

bradfitz@tsdev:~/src/tailscale.com/ipn$ grep -F "controlclient." *.go
backend.go:     NetMap        *controlclient.NetworkMap // new netmap received
fake_test.go:   b.notify(Notify{NetMap: &controlclient.NetworkMap{}})
fake_test.go:   b.notify(Notify{NetMap: &controlclient.NetworkMap{}})
handle.go:      netmapCache       *controlclient.NetworkMap
handle.go:func (h *Handle) NetMap() *controlclient.NetworkMap {

Once that goes into a leaf package, then ipn doesn't depend on
controlclient at all, and then the client gets smaller.

Updates #1278
This commit is contained in:
Brad Fitzpatrick
2021-02-05 15:23:01 -08:00
parent a046b48593
commit ddfcc4326c
13 changed files with 149 additions and 107 deletions

73
types/persist/persist.go Normal file
View File

@@ -0,0 +1,73 @@
// Copyright (c) 2021 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 persist contains the Persist type.
package persist
import (
"fmt"
"tailscale.com/types/structs"
"tailscale.com/types/wgkey"
)
//go:generate go run tailscale.com/cmd/cloner -type=Persist -output=persist_clone.go
// Persist is the JSON type stored on disk on nodes to remember their
// settings between runs.
type Persist struct {
_ structs.Incomparable
// LegacyFrontendPrivateMachineKey is here temporarily
// (starting 2020-09-28) during migration of Windows users'
// machine keys from frontend storage to the backend. On the
// first LocalBackend.Start call, the backend will initialize
// the real (backend-owned) machine key from the frontend's
// provided value (if non-zero), picking a new random one if
// needed. This field should be considered read-only from GUI
// frontends. The real value should not be written back in
// this field, lest the frontend persist it to disk.
LegacyFrontendPrivateMachineKey wgkey.Private `json:"PrivateMachineKey"`
PrivateNodeKey wgkey.Private
OldPrivateNodeKey wgkey.Private // needed to request key rotation
Provider string
LoginName string
}
func (p *Persist) Equals(p2 *Persist) bool {
if p == nil && p2 == nil {
return true
}
if p == nil || p2 == nil {
return false
}
return p.LegacyFrontendPrivateMachineKey.Equal(p2.LegacyFrontendPrivateMachineKey) &&
p.PrivateNodeKey.Equal(p2.PrivateNodeKey) &&
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
p.Provider == p2.Provider &&
p.LoginName == p2.LoginName
}
func (p *Persist) Pretty() string {
var mk, ok, nk wgkey.Key
if !p.LegacyFrontendPrivateMachineKey.IsZero() {
mk = p.LegacyFrontendPrivateMachineKey.Public()
}
if !p.OldPrivateNodeKey.IsZero() {
ok = p.OldPrivateNodeKey.Public()
}
if !p.PrivateNodeKey.IsZero() {
nk = p.PrivateNodeKey.Public()
}
ss := func(k wgkey.Key) string {
if k.IsZero() {
return ""
}
return k.ShortString()
}
return fmt.Sprintf("Persist{lm=%v, o=%v, n=%v u=%#v}",
ss(mk), ss(ok), ss(nk), p.LoginName)
}

View File

@@ -0,0 +1,34 @@
// 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.
// Code generated by tailscale.com/cmd/cloner -type Persist; DO NOT EDIT.
package persist
import (
"tailscale.com/types/structs"
"tailscale.com/types/wgkey"
)
// Clone makes a deep copy of Persist.
// The result aliases no memory with the original.
func (src *Persist) Clone() *Persist {
if src == nil {
return nil
}
dst := new(Persist)
*dst = *src
return dst
}
// A compilation failure here means this code must be regenerated, with command:
// tailscale.com/cmd/cloner -type Persist
var _PersistNeedsRegeneration = Persist(struct {
_ structs.Incomparable
LegacyFrontendPrivateMachineKey wgkey.Private
PrivateNodeKey wgkey.Private
OldPrivateNodeKey wgkey.Private
Provider string
LoginName string
}{})

View File

@@ -0,0 +1,107 @@
// 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 persist
import (
"reflect"
"testing"
"tailscale.com/types/wgkey"
)
func fieldsOf(t reflect.Type) (fields []string) {
for i := 0; i < t.NumField(); i++ {
if name := t.Field(i).Name; name != "_" {
fields = append(fields, name)
}
}
return
}
func TestPersistEqual(t *testing.T) {
persistHandles := []string{"LegacyFrontendPrivateMachineKey", "PrivateNodeKey", "OldPrivateNodeKey", "Provider", "LoginName"}
if have := fieldsOf(reflect.TypeOf(Persist{})); !reflect.DeepEqual(have, persistHandles) {
t.Errorf("Persist.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
have, persistHandles)
}
newPrivate := func() wgkey.Private {
k, err := wgkey.NewPrivate()
if err != nil {
panic(err)
}
return k
}
k1 := newPrivate()
tests := []struct {
a, b *Persist
want bool
}{
{nil, nil, true},
{nil, &Persist{}, false},
{&Persist{}, nil, false},
{&Persist{}, &Persist{}, true},
{
&Persist{LegacyFrontendPrivateMachineKey: k1},
&Persist{LegacyFrontendPrivateMachineKey: newPrivate()},
false,
},
{
&Persist{LegacyFrontendPrivateMachineKey: k1},
&Persist{LegacyFrontendPrivateMachineKey: k1},
true,
},
{
&Persist{PrivateNodeKey: k1},
&Persist{PrivateNodeKey: newPrivate()},
false,
},
{
&Persist{PrivateNodeKey: k1},
&Persist{PrivateNodeKey: k1},
true,
},
{
&Persist{OldPrivateNodeKey: k1},
&Persist{OldPrivateNodeKey: newPrivate()},
false,
},
{
&Persist{OldPrivateNodeKey: k1},
&Persist{OldPrivateNodeKey: k1},
true,
},
{
&Persist{Provider: "google"},
&Persist{Provider: "o365"},
false,
},
{
&Persist{Provider: "google"},
&Persist{Provider: "google"},
true,
},
{
&Persist{LoginName: "foo@tailscale.com"},
&Persist{LoginName: "bar@tailscale.com"},
false,
},
{
&Persist{LoginName: "foo@tailscale.com"},
&Persist{LoginName: "foo@tailscale.com"},
true,
},
}
for i, test := range tests {
if got := test.a.Equals(test.b); got != test.want {
t.Errorf("%d. Equals = %v; want %v", i, got, test.want)
}
}
}