mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-23 02:24:10 +00:00
all: modernize sorting with slices package
Replace deprecated sort package functions with their modern slices package equivalents: - sort.Slice -> slices.SortFunc - sort.SliceStable -> slices.SortStableFunc - sort.Sort -> slices.Sort - sort.Strings -> slices.Sort Also removes the now-unused sort.Interface implementation (Len, Less, Swap methods) from types.NodeIDs since slices.Sort works directly with ordered types.
This commit is contained in:
parent
f9b3265158
commit
094faf7a6a
12 changed files with 98 additions and 111 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -371,8 +372,8 @@ func (sc *StatsCollector) GetSummary() []ContainerStatsSummary {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort by container name for consistent output
|
// Sort by container name for consistent output
|
||||||
sort.Slice(summaries, func(i, j int) bool {
|
slices.SortFunc(summaries, func(a, b ContainerStatsSummary) int {
|
||||||
return summaries[i].ContainerName < summaries[j].ContainerName
|
return cmp.Compare(a.ContainerName, b.ContainerName)
|
||||||
})
|
})
|
||||||
|
|
||||||
return summaries
|
return summaries
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
"tailscale.com/types/ptr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -60,7 +59,7 @@ func ListPeers(tx *gorm.DB, nodeID types.NodeID, peerIDs ...types.NodeID) (types
|
||||||
return types.Nodes{}, err
|
return types.Nodes{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(nodes, func(i, j int) bool { return nodes[i].ID < nodes[j].ID })
|
slices.SortFunc(nodes, func(a, b *types.Node) int { return cmp.Compare(a.ID, b.ID) })
|
||||||
|
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
@ -668,7 +667,7 @@ func (hsdb *HSDatabase) CreateNodeForTest(user *types.User, hostname ...string)
|
||||||
Hostname: nodeName,
|
Hostname: nodeName,
|
||||||
UserID: &user.ID,
|
UserID: &user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: ptr.To(pak.ID),
|
AuthKeyID: new(pak.ID),
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hsdb.DB.Save(node).Error
|
err = hsdb.DB.Save(node).Error
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"tailscale.com/types/ptr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreatePreAuthKey(t *testing.T) {
|
func TestCreatePreAuthKey(t *testing.T) {
|
||||||
|
|
@ -24,7 +23,7 @@ func TestCreatePreAuthKey(t *testing.T) {
|
||||||
test: func(t *testing.T, db *HSDatabase) {
|
test: func(t *testing.T, db *HSDatabase) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
_, err := db.CreatePreAuthKey(ptr.To(types.UserID(12345)), true, false, nil, nil)
|
_, err := db.CreatePreAuthKey(new(types.UserID(12345)), true, false, nil, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -127,7 +126,7 @@ func TestCannotDeleteAssignedPreAuthKey(t *testing.T) {
|
||||||
Hostname: "testest",
|
Hostname: "testest",
|
||||||
UserID: &user.ID,
|
UserID: &user.ID,
|
||||||
RegisterMethod: util.RegisterMethodAuthKey,
|
RegisterMethod: util.RegisterMethodAuthKey,
|
||||||
AuthKeyID: ptr.To(key.ID),
|
AuthKeyID: new(key.ID),
|
||||||
}
|
}
|
||||||
db.DB.Save(&node)
|
db.DB.Save(&node)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
package mapper
|
package mapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"errors"
|
"errors"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sort"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/juanfont/headscale/hscontrol/policy"
|
"github.com/juanfont/headscale/hscontrol/policy"
|
||||||
|
|
@ -261,8 +262,8 @@ func (b *MapResponseBuilder) buildTailPeers(peers views.Slice[types.NodeView]) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peers is always returned sorted by Node.ID.
|
// Peers is always returned sorted by Node.ID.
|
||||||
sort.SliceStable(tailPeers, func(x, y int) bool {
|
slices.SortStableFunc(tailPeers, func(a, b *tailcfg.Node) int {
|
||||||
return tailPeers[x].ID < tailPeers[y].ID
|
return cmp.Compare(a.ID, b.ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
return tailPeers, nil
|
return tailPeers, nil
|
||||||
|
|
|
||||||
|
|
@ -956,14 +956,7 @@ func (pm *PolicyManager) invalidateGlobalPolicyCache(newNodes views.Slice[types.
|
||||||
// It will return a Owners list where all the Tag types have been resolved to their underlying Owners.
|
// It will return a Owners list where all the Tag types have been resolved to their underlying Owners.
|
||||||
func flattenTags(tagOwners TagOwners, tag Tag, visiting map[Tag]bool, chain []Tag) (Owners, error) {
|
func flattenTags(tagOwners TagOwners, tag Tag, visiting map[Tag]bool, chain []Tag) (Owners, error) {
|
||||||
if visiting[tag] {
|
if visiting[tag] {
|
||||||
cycleStart := 0
|
cycleStart := slices.Index(chain, tag)
|
||||||
|
|
||||||
for i, t := range chain {
|
|
||||||
if t == tag {
|
|
||||||
cycleStart = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cycleTags := make([]string, len(chain[cycleStart:]))
|
cycleTags := make([]string, len(chain[cycleStart:]))
|
||||||
for i, t := range chain[cycleStart:] {
|
for i, t := range chain[cycleStart:] {
|
||||||
|
|
|
||||||
|
|
@ -333,7 +333,7 @@ func NodeOnline(nodeID types.NodeID) Change {
|
||||||
PeerPatches: []*tailcfg.PeerChange{
|
PeerPatches: []*tailcfg.PeerChange{
|
||||||
{
|
{
|
||||||
NodeID: nodeID.NodeID(),
|
NodeID: nodeID.NodeID(),
|
||||||
Online: ptrTo(true),
|
Online: new(true),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +346,7 @@ func NodeOffline(nodeID types.NodeID) Change {
|
||||||
PeerPatches: []*tailcfg.PeerChange{
|
PeerPatches: []*tailcfg.PeerChange{
|
||||||
{
|
{
|
||||||
NodeID: nodeID.NodeID(),
|
NodeID: nodeID.NodeID(),
|
||||||
Online: ptrTo(false),
|
Online: new(false),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -366,8 +366,10 @@ func KeyExpiry(nodeID types.NodeID, expiry *time.Time) Change {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ptrTo returns a pointer to the given value.
|
// ptrTo returns a pointer to the given value.
|
||||||
|
//
|
||||||
|
//go:fix inline
|
||||||
func ptrTo[T any](v T) *T {
|
func ptrTo[T any](v T) *T {
|
||||||
return &v
|
return new(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// High-level change constructors
|
// High-level change constructors
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ func TestChange_FieldSync(t *testing.T) {
|
||||||
typ := reflect.TypeFor[Change]()
|
typ := reflect.TypeFor[Change]()
|
||||||
boolCount := 0
|
boolCount := 0
|
||||||
|
|
||||||
for i := range typ.NumField() {
|
for field := range typ.Fields() {
|
||||||
if typ.Field(i).Type.Kind() == reflect.Bool {
|
if field.Type.Kind() == reflect.Bool {
|
||||||
boolCount++
|
boolCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"maps"
|
"maps"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sort"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
gocmp "github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
policyv2 "github.com/juanfont/headscale/hscontrol/policy/v2"
|
||||||
|
|
@ -111,11 +112,11 @@ func TestOIDCAuthenticationPingAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(want, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(want, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
t.Fatalf("unexpected users: %s", diff)
|
t.Fatalf("unexpected users: %s", diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -388,11 +389,11 @@ func TestOIDC024UserCreation(t *testing.T) {
|
||||||
listUsers, err := headscale.ListUsers()
|
listUsers, err := headscale.ListUsers()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(want, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(want, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
t.Errorf("unexpected users: %s", diff)
|
t.Errorf("unexpected users: %s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -517,11 +518,11 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
||||||
}
|
}
|
||||||
}, 30*time.Second, 1*time.Second, "validating user1 creation after initial OIDC login")
|
}, 30*time.Second, 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||||
|
|
@ -599,11 +600,11 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
ct.Errorf("User validation failed after user2 login - expected both user1 and user2: %s", diff)
|
ct.Errorf("User validation failed after user2 login - expected both user1 and user2: %s", diff)
|
||||||
}
|
}
|
||||||
}, 30*time.Second, 1*time.Second, "validating both user1 and user2 exist after second OIDC login")
|
}, 30*time.Second, 1*time.Second, "validating both user1 and user2 exist after second OIDC login")
|
||||||
|
|
@ -763,11 +764,11 @@ func TestOIDCReloginSameNodeNewUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
ct.Errorf("Final user validation failed - both users should persist after relogin cycle: %s", diff)
|
ct.Errorf("Final user validation failed - both users should persist after relogin cycle: %s", diff)
|
||||||
}
|
}
|
||||||
}, 30*time.Second, 1*time.Second, "validating user persistence after complete relogin cycle (user1->user2->user1)")
|
}, 30*time.Second, 1*time.Second, "validating user persistence after complete relogin cycle (user1->user2->user1)")
|
||||||
|
|
@ -935,13 +936,11 @@ func TestOIDCFollowUpUrl(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
listUsers, func(i, j int) bool {
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if diff := cmp.Diff(
|
if diff := gocmp.Diff(
|
||||||
wantUsers,
|
wantUsers,
|
||||||
listUsers,
|
listUsers,
|
||||||
cmpopts.IgnoreUnexported(v1.User{}),
|
cmpopts.IgnoreUnexported(v1.User{}),
|
||||||
|
|
@ -1046,13 +1045,11 @@ func TestOIDCMultipleOpenedLoginUrls(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
listUsers, func(i, j int) bool {
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
})
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if diff := cmp.Diff(
|
if diff := gocmp.Diff(
|
||||||
wantUsers,
|
wantUsers,
|
||||||
listUsers,
|
listUsers,
|
||||||
cmpopts.IgnoreUnexported(v1.User{}),
|
cmpopts.IgnoreUnexported(v1.User{}),
|
||||||
|
|
@ -1155,11 +1152,11 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
ct.Errorf("User validation failed after first login - unexpected users: %s", diff)
|
||||||
}
|
}
|
||||||
}, 30*time.Second, 1*time.Second, "validating user1 creation after initial OIDC login")
|
}, 30*time.Second, 1*time.Second, "validating user1 creation after initial OIDC login")
|
||||||
|
|
@ -1249,11 +1246,11 @@ func TestOIDCReloginSameNodeSameUser(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(listUsers, func(i, j int) bool {
|
slices.SortFunc(listUsers, func(a, b *v1.User) int {
|
||||||
return listUsers[i].GetId() < listUsers[j].GetId()
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
if diff := cmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
if diff := gocmp.Diff(wantUsers, listUsers, cmpopts.IgnoreUnexported(v1.User{}), cmpopts.IgnoreFields(v1.User{}, "CreatedAt")); diff != "" {
|
||||||
ct.Errorf("Final user validation failed - user1 should persist after same-user relogin: %s", diff)
|
ct.Errorf("Final user validation failed - user1 should persist after same-user relogin: %s", diff)
|
||||||
}
|
}
|
||||||
}, 30*time.Second, 1*time.Second, "validating user1 persistence after same-user OIDC relogin cycle")
|
}, 30*time.Second, 1*time.Second, "validating user1 persistence after same-user OIDC relogin cycle")
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/ptr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -839,32 +838,32 @@ func wildcard() policyv2.Alias {
|
||||||
// usernamep returns a pointer to a Username as an Alias for policy v2 configurations.
|
// usernamep returns a pointer to a Username as an Alias for policy v2 configurations.
|
||||||
// Used in ACL rules to reference specific users in network access policies.
|
// Used in ACL rules to reference specific users in network access policies.
|
||||||
func usernamep(name string) policyv2.Alias {
|
func usernamep(name string) policyv2.Alias {
|
||||||
return ptr.To(policyv2.Username(name))
|
return new(policyv2.Username(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// hostp returns a pointer to a Host as an Alias for policy v2 configurations.
|
// hostp returns a pointer to a Host as an Alias for policy v2 configurations.
|
||||||
// Used in ACL rules to reference specific hosts in network access policies.
|
// Used in ACL rules to reference specific hosts in network access policies.
|
||||||
func hostp(name string) policyv2.Alias {
|
func hostp(name string) policyv2.Alias {
|
||||||
return ptr.To(policyv2.Host(name))
|
return new(policyv2.Host(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// groupp returns a pointer to a Group as an Alias for policy v2 configurations.
|
// groupp returns a pointer to a Group as an Alias for policy v2 configurations.
|
||||||
// Used in ACL rules to reference user groups in network access policies.
|
// Used in ACL rules to reference user groups in network access policies.
|
||||||
func groupp(name string) policyv2.Alias {
|
func groupp(name string) policyv2.Alias {
|
||||||
return ptr.To(policyv2.Group(name))
|
return new(policyv2.Group(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// tagp returns a pointer to a Tag as an Alias for policy v2 configurations.
|
// tagp returns a pointer to a Tag as an Alias for policy v2 configurations.
|
||||||
// Used in ACL rules to reference node tags in network access policies.
|
// Used in ACL rules to reference node tags in network access policies.
|
||||||
func tagp(name string) policyv2.Alias {
|
func tagp(name string) policyv2.Alias {
|
||||||
return ptr.To(policyv2.Tag(name))
|
return new(policyv2.Tag(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefixp returns a pointer to a Prefix from a CIDR string for policy v2 configurations.
|
// prefixp returns a pointer to a Prefix from a CIDR string for policy v2 configurations.
|
||||||
// Converts CIDR notation to policy prefix format for network range specifications.
|
// Converts CIDR notation to policy prefix format for network range specifications.
|
||||||
func prefixp(cidr string) policyv2.Alias {
|
func prefixp(cidr string) policyv2.Alias {
|
||||||
prefix := netip.MustParsePrefix(cidr)
|
prefix := netip.MustParsePrefix(cidr)
|
||||||
return ptr.To(policyv2.Prefix(prefix))
|
return new(policyv2.Prefix(prefix))
|
||||||
}
|
}
|
||||||
|
|
||||||
// aliasWithPorts creates an AliasWithPorts structure from an alias and port ranges.
|
// aliasWithPorts creates an AliasWithPorts structure from an alias and port ranges.
|
||||||
|
|
@ -880,31 +879,31 @@ func aliasWithPorts(alias policyv2.Alias, ports ...tailcfg.PortRange) policyv2.A
|
||||||
// usernameOwner returns a Username as an Owner for use in TagOwners policies.
|
// usernameOwner returns a Username as an Owner for use in TagOwners policies.
|
||||||
// Specifies which users can assign and manage specific tags in ACL configurations.
|
// Specifies which users can assign and manage specific tags in ACL configurations.
|
||||||
func usernameOwner(name string) policyv2.Owner {
|
func usernameOwner(name string) policyv2.Owner {
|
||||||
return ptr.To(policyv2.Username(name))
|
return new(policyv2.Username(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// groupOwner returns a Group as an Owner for use in TagOwners policies.
|
// groupOwner returns a Group as an Owner for use in TagOwners policies.
|
||||||
// Specifies which groups can assign and manage specific tags in ACL configurations.
|
// Specifies which groups can assign and manage specific tags in ACL configurations.
|
||||||
func groupOwner(name string) policyv2.Owner {
|
func groupOwner(name string) policyv2.Owner {
|
||||||
return ptr.To(policyv2.Group(name))
|
return new(policyv2.Group(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// usernameApprover returns a Username as an AutoApprover for subnet route policies.
|
// usernameApprover returns a Username as an AutoApprover for subnet route policies.
|
||||||
// Specifies which users can automatically approve subnet route advertisements.
|
// Specifies which users can automatically approve subnet route advertisements.
|
||||||
func usernameApprover(name string) policyv2.AutoApprover {
|
func usernameApprover(name string) policyv2.AutoApprover {
|
||||||
return ptr.To(policyv2.Username(name))
|
return new(policyv2.Username(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// groupApprover returns a Group as an AutoApprover for subnet route policies.
|
// groupApprover returns a Group as an AutoApprover for subnet route policies.
|
||||||
// Specifies which groups can automatically approve subnet route advertisements.
|
// Specifies which groups can automatically approve subnet route advertisements.
|
||||||
func groupApprover(name string) policyv2.AutoApprover {
|
func groupApprover(name string) policyv2.AutoApprover {
|
||||||
return ptr.To(policyv2.Group(name))
|
return new(policyv2.Group(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// tagApprover returns a Tag as an AutoApprover for subnet route policies.
|
// tagApprover returns a Tag as an AutoApprover for subnet route policies.
|
||||||
// Specifies which tagged nodes can automatically approve subnet route advertisements.
|
// Specifies which tagged nodes can automatically approve subnet route advertisements.
|
||||||
func tagApprover(name string) policyv2.AutoApprover {
|
func tagApprover(name string) policyv2.AutoApprover {
|
||||||
return ptr.To(policyv2.Tag(name))
|
return new(policyv2.Tag(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// oidcMockUser creates a MockUser for OIDC authentication testing.
|
// oidcMockUser creates a MockUser for OIDC authentication testing.
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -1232,8 +1232,8 @@ func (t *HeadscaleInContainer) ListNodes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(ret, func(i, j int) bool {
|
slices.SortFunc(ret, func(a, b *v1.Node) int {
|
||||||
return cmp.Compare(ret[i].GetId(), ret[j].GetId()) == -1
|
return cmp.Compare(a.GetId(), b.GetId())
|
||||||
})
|
})
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"maps"
|
"maps"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -287,11 +286,10 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
t.Logf("webservice: %s, %s", webip.String(), weburl)
|
t.Logf("webservice: %s, %s", webip.String(), weburl)
|
||||||
|
|
||||||
// Sort nodes by ID
|
// Sort nodes by ID
|
||||||
sort.SliceStable(allClients, func(i, j int) bool {
|
slices.SortStableFunc(allClients, func(a, b TailscaleClient) int {
|
||||||
statusI := allClients[i].MustStatus()
|
statusA := a.MustStatus()
|
||||||
statusJ := allClients[j].MustStatus()
|
statusB := b.MustStatus()
|
||||||
|
return cmp.Compare(statusA.Self.ID, statusB.Self.ID)
|
||||||
return statusI.Self.ID < statusJ.Self.ID
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// This is ok because the scenario makes users in order, so the three first
|
// This is ok because the scenario makes users in order, so the three first
|
||||||
|
|
@ -1359,10 +1357,10 @@ func TestSubnetRouteACL(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort nodes by ID
|
// Sort nodes by ID
|
||||||
sort.SliceStable(allClients, func(i, j int) bool {
|
slices.SortStableFunc(allClients, func(a, b TailscaleClient) int {
|
||||||
statusI := allClients[i].MustStatus()
|
statusA := a.MustStatus()
|
||||||
statusJ := allClients[j].MustStatus()
|
statusB := b.MustStatus()
|
||||||
return statusI.Self.ID < statusJ.Self.ID
|
return cmp.Compare(statusA.Self.ID, statusB.Self.ID)
|
||||||
})
|
})
|
||||||
|
|
||||||
subRouter1 := allClients[0]
|
subRouter1 := allClients[0]
|
||||||
|
|
@ -2403,11 +2401,10 @@ func TestAutoApproveMultiNetwork(t *testing.T) {
|
||||||
t.Logf("webservice: %s, %s", webip.String(), weburl)
|
t.Logf("webservice: %s, %s", webip.String(), weburl)
|
||||||
|
|
||||||
// Sort nodes by ID
|
// Sort nodes by ID
|
||||||
sort.SliceStable(allClients, func(i, j int) bool {
|
slices.SortStableFunc(allClients, func(a, b TailscaleClient) int {
|
||||||
statusI := allClients[i].MustStatus()
|
statusA := a.MustStatus()
|
||||||
statusJ := allClients[j].MustStatus()
|
statusB := b.MustStatus()
|
||||||
|
return cmp.Compare(statusA.Self.ID, statusB.Self.ID)
|
||||||
return statusI.Self.ID < statusJ.Self.ID
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// This is ok because the scenario makes users in order, so the three first
|
// This is ok because the scenario makes users in order, so the three first
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/ptr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const tagTestUser = "taguser"
|
const tagTestUser = "taguser"
|
||||||
|
|
@ -30,9 +29,9 @@ const tagTestUser = "taguser"
|
||||||
func tagsTestPolicy() *policyv2.Policy {
|
func tagsTestPolicy() *policyv2.Policy {
|
||||||
return &policyv2.Policy{
|
return &policyv2.Policy{
|
||||||
TagOwners: policyv2.TagOwners{
|
TagOwners: policyv2.TagOwners{
|
||||||
"tag:valid-owned": policyv2.Owners{ptr.To(policyv2.Username(tagTestUser + "@"))},
|
"tag:valid-owned": policyv2.Owners{new(policyv2.Username(tagTestUser + "@"))},
|
||||||
"tag:second": policyv2.Owners{ptr.To(policyv2.Username(tagTestUser + "@"))},
|
"tag:second": policyv2.Owners{new(policyv2.Username(tagTestUser + "@"))},
|
||||||
"tag:valid-unowned": policyv2.Owners{ptr.To(policyv2.Username("other-user@"))},
|
"tag:valid-unowned": policyv2.Owners{new(policyv2.Username("other-user@"))},
|
||||||
// Note: tag:nonexistent deliberately NOT defined
|
// Note: tag:nonexistent deliberately NOT defined
|
||||||
},
|
},
|
||||||
ACLs: []policyv2.ACL{
|
ACLs: []policyv2.ACL{
|
||||||
|
|
@ -51,11 +50,11 @@ func tagsEqual(actual, expected []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedActual := append([]string{}, actual...)
|
sortedActual := slices.Clone(actual)
|
||||||
sortedExpected := append([]string{}, expected...)
|
sortedExpected := slices.Clone(expected)
|
||||||
|
|
||||||
sort.Strings(sortedActual)
|
slices.Sort(sortedActual)
|
||||||
sort.Strings(sortedExpected)
|
slices.Sort(sortedExpected)
|
||||||
|
|
||||||
for i := range sortedActual {
|
for i := range sortedActual {
|
||||||
if sortedActual[i] != sortedExpected[i] {
|
if sortedActual[i] != sortedExpected[i] {
|
||||||
|
|
@ -69,11 +68,11 @@ func tagsEqual(actual, expected []string) bool {
|
||||||
// assertNodeHasTagsWithCollect asserts that a node has exactly the expected tags (order-independent).
|
// assertNodeHasTagsWithCollect asserts that a node has exactly the expected tags (order-independent).
|
||||||
func assertNodeHasTagsWithCollect(c *assert.CollectT, node *v1.Node, expectedTags []string) {
|
func assertNodeHasTagsWithCollect(c *assert.CollectT, node *v1.Node, expectedTags []string) {
|
||||||
actualTags := node.GetTags()
|
actualTags := node.GetTags()
|
||||||
sortedActual := append([]string{}, actualTags...)
|
sortedActual := slices.Clone(actualTags)
|
||||||
sortedExpected := append([]string{}, expectedTags...)
|
sortedExpected := slices.Clone(expectedTags)
|
||||||
|
|
||||||
sort.Strings(sortedActual)
|
slices.Sort(sortedActual)
|
||||||
sort.Strings(sortedExpected)
|
slices.Sort(sortedExpected)
|
||||||
assert.Equal(c, sortedExpected, sortedActual, "Node %s tags mismatch", node.GetName())
|
assert.Equal(c, sortedExpected, sortedActual, "Node %s tags mismatch", node.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,11 +101,11 @@ func assertNodeSelfHasTagsWithCollect(c *assert.CollectT, client TailscaleClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedActual := append([]string{}, actualTagsSlice...)
|
sortedActual := slices.Clone(actualTagsSlice)
|
||||||
sortedExpected := append([]string{}, expectedTags...)
|
sortedExpected := slices.Clone(expectedTags)
|
||||||
|
|
||||||
sort.Strings(sortedActual)
|
slices.Sort(sortedActual)
|
||||||
sort.Strings(sortedExpected)
|
slices.Sort(sortedExpected)
|
||||||
assert.Equal(c, sortedExpected, sortedActual, "Client %s self tags mismatch", client.Hostname())
|
assert.Equal(c, sortedExpected, sortedActual, "Client %s self tags mismatch", client.Hostname())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2507,11 +2506,11 @@ func assertNetmapSelfHasTagsWithCollect(c *assert.CollectT, client TailscaleClie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sortedActual := append([]string{}, actualTagsSlice...)
|
sortedActual := slices.Clone(actualTagsSlice)
|
||||||
sortedExpected := append([]string{}, expectedTags...)
|
sortedExpected := slices.Clone(expectedTags)
|
||||||
|
|
||||||
sort.Strings(sortedActual)
|
slices.Sort(sortedActual)
|
||||||
sort.Strings(sortedExpected)
|
slices.Sort(sortedExpected)
|
||||||
assert.Equal(c, sortedExpected, sortedActual, "Client %s netmap self tags mismatch", client.Hostname())
|
assert.Equal(c, sortedExpected, sortedActual, "Client %s netmap self tags mismatch", client.Hostname())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue