mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 22:15:51 +00:00
3a018e51bb
In order to be able to synthesize a new NetMap when a node expires, have LocalBackend start a timer when receiving a new NetMap that fires slightly after the next node expires. Additionally, move the logic that updates expired nodes into LocalBackend so it runs on every netmap (whether received from controlclient or self-triggered). Updates #6932 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I833390e16ad188983eac29eb34cc7574f555f2f3
151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
// 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.
|
|
|
|
package ipnlocal
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"tailscale.com/tailcfg"
|
|
"tailscale.com/types/key"
|
|
"tailscale.com/types/netmap"
|
|
)
|
|
|
|
func TestFlagExpiredPeers(t *testing.T) {
|
|
n := func(id tailcfg.NodeID, name string, expiry time.Time, mod ...func(*tailcfg.Node)) *tailcfg.Node {
|
|
n := &tailcfg.Node{ID: id, Name: name, KeyExpiry: expiry}
|
|
for _, f := range mod {
|
|
f(n)
|
|
}
|
|
return n
|
|
}
|
|
|
|
now := time.Unix(1673373129, 0)
|
|
|
|
timeInPast := now.Add(-1 * time.Hour)
|
|
timeInFuture := now.Add(1 * time.Hour)
|
|
|
|
timeBeforeEpoch := flagExpiredPeersEpoch.Add(-1 * time.Second)
|
|
if now.Before(timeBeforeEpoch) {
|
|
panic("current time in test cannot be before epoch")
|
|
}
|
|
|
|
var expiredKey key.NodePublic
|
|
if err := expiredKey.UnmarshalText([]byte("nodekey:6da774d5d7740000000000000000000000000000000000000000000000000000")); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
controlTime *time.Time
|
|
netmap *netmap.NetworkMap
|
|
want []*tailcfg.Node
|
|
}{
|
|
{
|
|
name: "no_expiry",
|
|
controlTime: &now,
|
|
netmap: &netmap.NetworkMap{
|
|
Peers: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeInFuture),
|
|
},
|
|
},
|
|
want: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeInFuture),
|
|
},
|
|
},
|
|
{
|
|
name: "expiry",
|
|
controlTime: &now,
|
|
netmap: &netmap.NetworkMap{
|
|
Peers: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeInPast),
|
|
},
|
|
},
|
|
want: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeInPast, func(n *tailcfg.Node) {
|
|
n.Expired = true
|
|
n.Key = expiredKey
|
|
}),
|
|
},
|
|
},
|
|
{
|
|
name: "bad_ControlTime",
|
|
// controlTime here is intentionally before our hardcoded epoch
|
|
controlTime: &timeBeforeEpoch,
|
|
|
|
netmap: &netmap.NetworkMap{
|
|
Peers: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // before ControlTime
|
|
},
|
|
},
|
|
want: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", timeBeforeEpoch.Add(-1*time.Hour)), // should have expired, but ControlTime is before epoch
|
|
},
|
|
},
|
|
{
|
|
name: "tagged_node",
|
|
controlTime: &now,
|
|
netmap: &netmap.NetworkMap{
|
|
Peers: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", time.Time{}), // tagged node; zero expiry
|
|
},
|
|
},
|
|
want: []*tailcfg.Node{
|
|
n(1, "foo", timeInFuture),
|
|
n(2, "bar", time.Time{}), // not expired
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
em := newExpiryManager(t.Logf)
|
|
em.timeNow = func() time.Time { return now }
|
|
|
|
if tt.controlTime != nil {
|
|
em.onControlTime(*tt.controlTime)
|
|
}
|
|
em.flagExpiredPeers(tt.netmap)
|
|
if !reflect.DeepEqual(tt.netmap.Peers, tt.want) {
|
|
t.Errorf("wrong results\n got: %s\nwant: %s", formatNodes(tt.netmap.Peers), formatNodes(tt.want))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func formatNodes(nodes []*tailcfg.Node) string {
|
|
var sb strings.Builder
|
|
for i, n := range nodes {
|
|
if i > 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
fmt.Fprintf(&sb, "(%d, %q", n.ID, n.Name)
|
|
|
|
if n.Online != nil {
|
|
fmt.Fprintf(&sb, ", online=%v", *n.Online)
|
|
}
|
|
if n.LastSeen != nil {
|
|
fmt.Fprintf(&sb, ", lastSeen=%v", n.LastSeen.Unix())
|
|
}
|
|
if n.Key != (key.NodePublic{}) {
|
|
fmt.Fprintf(&sb, ", key=%v", n.Key.String())
|
|
}
|
|
if n.Expired {
|
|
fmt.Fprintf(&sb, ", expired=true")
|
|
}
|
|
sb.WriteString(")")
|
|
}
|
|
return sb.String()
|
|
}
|