mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-05 14:57:49 +00:00
ipn/ipnlocal: use views for Peer.PrimaryRoutes and Peer.Tags
RELNOTE=`tailscale status --json` now shows Tags and PrimaryRoutes Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
9cbb0913be
commit
c7a8f0992d
@ -75,7 +75,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||
tailscale.com/types/persist from tailscale.com/ipn
|
||||
tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+
|
||||
tailscale.com/types/structs from tailscale.com/ipn+
|
||||
tailscale.com/types/views from tailscale.com/tailcfg
|
||||
tailscale.com/types/views from tailscale.com/tailcfg+
|
||||
tailscale.com/util/clientmetric from tailscale.com/net/netcheck+
|
||||
tailscale.com/util/dnsname from tailscale.com/cmd/tailscale/cli+
|
||||
W tailscale.com/util/endian from tailscale.com/net/netns
|
||||
|
@ -240,7 +240,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||
tailscale.com/types/persist from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/preftype from tailscale.com/ipn+
|
||||
tailscale.com/types/structs from tailscale.com/control/controlclient+
|
||||
tailscale.com/types/views from tailscale.com/tailcfg
|
||||
tailscale.com/types/views from tailscale.com/tailcfg+
|
||||
tailscale.com/util/clientmetric from tailscale.com/ipn/localapi+
|
||||
L tailscale.com/util/cmpver from tailscale.com/net/dns
|
||||
💣 tailscale.com/util/deephash from tailscale.com/ipn/ipnlocal+
|
||||
|
@ -48,6 +48,7 @@
|
||||
"tailscale.com/types/netmap"
|
||||
"tailscale.com/types/persist"
|
||||
"tailscale.com/types/preftype"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/deephash"
|
||||
"tailscale.com/util/dnsname"
|
||||
"tailscale.com/util/multierr"
|
||||
@ -443,13 +444,23 @@ func (b *LocalBackend) populatePeerStatusLocked(sb *ipnstate.StatusBuilder) {
|
||||
exitNodeOption := tsaddr.PrefixesContainsFunc(p.AllowedIPs, func(r netaddr.IPPrefix) bool {
|
||||
return r.Bits() == 0
|
||||
})
|
||||
var tags *views.StringSlice
|
||||
var primaryRoutes *views.IPPrefixSlice
|
||||
if p.Tags != nil {
|
||||
v := views.StringSliceOf(p.Tags)
|
||||
tags = &v
|
||||
}
|
||||
if p.PrimaryRoutes != nil {
|
||||
v := views.IPPrefixSliceOf(p.PrimaryRoutes)
|
||||
primaryRoutes = &v
|
||||
}
|
||||
sb.AddPeer(p.Key, &ipnstate.PeerStatus{
|
||||
InNetworkMap: true,
|
||||
ID: p.StableID,
|
||||
UserID: p.User,
|
||||
TailscaleIPs: tailscaleIPs,
|
||||
Tags: p.Tags,
|
||||
PrimaryRoutes: p.PrimaryRoutes,
|
||||
Tags: tags,
|
||||
PrimaryRoutes: primaryRoutes,
|
||||
HostName: p.Hostinfo.Hostname(),
|
||||
DNSName: p.Name,
|
||||
OS: p.Hostinfo.OS(),
|
||||
|
@ -20,6 +20,7 @@
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/views"
|
||||
"tailscale.com/util/dnsname"
|
||||
)
|
||||
|
||||
@ -111,12 +112,12 @@ type PeerStatus struct {
|
||||
|
||||
// Tags are the list of ACL tags applied to this node.
|
||||
// See tailscale.com/tailcfg#Node.Tags for more information.
|
||||
Tags []string `json:",omitempty"`
|
||||
Tags *views.StringSlice `json:",omitempty"`
|
||||
|
||||
// PrimaryRoutes are the routes this node is currently the primary
|
||||
// subnet router for, as determined by the control plane. It does
|
||||
// not include the IPs in TailscaleIPs.
|
||||
PrimaryRoutes []netaddr.IPPrefix `json:",omitempty"`
|
||||
PrimaryRoutes *views.IPPrefixSlice `json:",omitempty"`
|
||||
|
||||
// Endpoints:
|
||||
Addrs []string
|
||||
@ -274,10 +275,10 @@ func (sb *StatusBuilder) AddPeer(peer key.NodePublic, st *PeerStatus) {
|
||||
if v := st.TailscaleIPs; v != nil {
|
||||
e.TailscaleIPs = v
|
||||
}
|
||||
if v := st.PrimaryRoutes; v != nil {
|
||||
if v := st.PrimaryRoutes; v != nil && !v.IsNil() {
|
||||
e.PrimaryRoutes = v
|
||||
}
|
||||
if v := st.Tags; v != nil {
|
||||
if v := st.Tags; v != nil && !v.IsNil() {
|
||||
e.Tags = v
|
||||
}
|
||||
if v := st.OS; v != "" {
|
||||
|
@ -7,6 +7,9 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"inet.af/netaddr"
|
||||
"tailscale.com/net/tsaddr"
|
||||
)
|
||||
@ -21,6 +24,28 @@ type StringSlice struct {
|
||||
// StringSliceOf returns a StringSlice for the provided slice.
|
||||
func StringSliceOf(x []string) StringSlice { return StringSlice{x} }
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (v StringSlice) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.ж)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (v *StringSlice) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("StringSlice is already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(b, &v.ж); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNil reports whether the underlying slice is nil.
|
||||
func (v StringSlice) IsNil() bool { return v.ж == nil }
|
||||
|
||||
// Len returns the length of the slice.
|
||||
func (v StringSlice) Len() int { return len(v.ж) }
|
||||
|
||||
@ -47,6 +72,9 @@ type IPPrefixSlice struct {
|
||||
// IPPrefixSliceOf returns a IPPrefixSlice for the provided slice.
|
||||
func IPPrefixSliceOf(x []netaddr.IPPrefix) IPPrefixSlice { return IPPrefixSlice{x} }
|
||||
|
||||
// IsNil reports whether the underlying slice is nil.
|
||||
func (v IPPrefixSlice) IsNil() bool { return v.ж == nil }
|
||||
|
||||
// Len returns the length of the slice.
|
||||
func (v IPPrefixSlice) Len() int { return len(v.ж) }
|
||||
|
||||
@ -72,3 +100,22 @@ func (v IPPrefixSlice) ContainsIP(ip netaddr.IP) bool {
|
||||
func (v IPPrefixSlice) ContainsFunc(f func(netaddr.IPPrefix) bool) bool {
|
||||
return tsaddr.PrefixesContainsFunc(v.ж, f)
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (v IPPrefixSlice) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.ж)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (v *IPPrefixSlice) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("IPPrefixSlice is already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(b, &v.ж); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
73
types/views/views_test.go
Normal file
73
types/views/views_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2022 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 views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
func TestViewsJSON(t *testing.T) {
|
||||
mustCIDR := func(cidrs ...string) (out []netaddr.IPPrefix) {
|
||||
for _, cidr := range cidrs {
|
||||
out = append(out, netaddr.MustParseIPPrefix(cidr))
|
||||
}
|
||||
return
|
||||
}
|
||||
type viewStruct struct {
|
||||
Addrs IPPrefixSlice
|
||||
Strings StringSlice
|
||||
AddrsPtr *IPPrefixSlice `json:",omitempty"`
|
||||
StringsPtr *StringSlice `json:",omitempty"`
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
in viewStruct
|
||||
wantJSON string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
in: viewStruct{},
|
||||
wantJSON: `{"Addrs":null,"Strings":null}`,
|
||||
},
|
||||
{
|
||||
name: "everything",
|
||||
in: viewStruct{
|
||||
Addrs: IPPrefixSliceOf(mustCIDR("192.168.0.0/24")),
|
||||
AddrsPtr: &IPPrefixSlice{mustCIDR("192.168.0.0/24")},
|
||||
StringsPtr: &StringSlice{[]string{"foo"}},
|
||||
Strings: StringSlice{[]string{"bar"}},
|
||||
},
|
||||
wantJSON: `{"Addrs":["192.168.0.0/24"],"Strings":["bar"],"AddrsPtr":["192.168.0.0/24"],"StringsPtr":["foo"]}`,
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
encoder := json.NewEncoder(&buf)
|
||||
encoder.SetIndent("", "")
|
||||
for _, tc := range tests {
|
||||
buf.Reset()
|
||||
if err := encoder.Encode(&tc.in); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b := buf.Bytes()
|
||||
gotJSON := strings.TrimSpace(string(b))
|
||||
if tc.wantJSON != gotJSON {
|
||||
t.Fatalf("JSON: %v; want: %v", gotJSON, tc.wantJSON)
|
||||
}
|
||||
var got viewStruct
|
||||
if err := json.Unmarshal(b, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, tc.in) {
|
||||
t.Fatalf("unmarshal resulted in different output: %+v; want %+v", got, tc.in)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user