mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-29 18:33:05 +00:00
Compare commits
6 commits
a3781fb6e2
...
5860b9d652
Author | SHA1 | Date | |
---|---|---|---|
|
5860b9d652 | ||
|
c59144a287 | ||
|
c905f0499b | ||
|
697ec7f46c | ||
|
dc17b4d378 | ||
|
a6b19e85db |
24 changed files with 1067 additions and 547 deletions
|
@ -27,6 +27,7 @@ linters:
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- musttag # causes issues with imported libs
|
- musttag # causes issues with imported libs
|
||||||
- depguard
|
- depguard
|
||||||
|
- exportloopref
|
||||||
|
|
||||||
# We should strive to enable these:
|
# We should strive to enable these:
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
|
@ -56,9 +57,14 @@ linters-settings:
|
||||||
- ok
|
- ok
|
||||||
- c
|
- c
|
||||||
- tt
|
- tt
|
||||||
|
- tx
|
||||||
|
- rx
|
||||||
|
|
||||||
gocritic:
|
gocritic:
|
||||||
disabled-checks:
|
disabled-checks:
|
||||||
- appendAssign
|
- appendAssign
|
||||||
# TODO(kradalby): Remove this
|
# TODO(kradalby): Remove this
|
||||||
- ifElseChain
|
- ifElseChain
|
||||||
|
|
||||||
|
nlreturn:
|
||||||
|
block-size: 4
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
cairosvg~=2.7.1
|
mkdocs-include-markdown-plugin~=7.1
|
||||||
mkdocs-include-markdown-plugin~=6.2.2
|
mkdocs-macros-plugin~=1.3
|
||||||
mkdocs-macros-plugin~=1.2.0
|
mkdocs-material[imaging]~=9.5
|
||||||
mkdocs-material~=9.5.18
|
mkdocs-minify-plugin~=0.7
|
||||||
mkdocs-minify-plugin~=0.7.1
|
mkdocs-redirects~=1.2
|
||||||
mkdocs-redirects~=1.2.1
|
|
||||||
pillow~=10.1.0
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
# When updating go.mod or go.sum, a new sha will need to be calculated,
|
# When updating go.mod or go.sum, a new sha will need to be calculated,
|
||||||
# update this if you have a mismatch after doing a change to thos files.
|
# update this if you have a mismatch after doing a change to thos files.
|
||||||
vendorHash = "sha256-CMkYTRjmhvTTrB7JbLj0cj9VEyzpG0iUWXkaOagwYTk=";
|
vendorHash = "sha256-Qoqu2k4vvnbRFLmT/v8lI+HCEWqJsHFs8uZRfNmwQpo=";
|
||||||
|
|
||||||
subPackages = ["cmd/headscale"];
|
subPackages = ["cmd/headscale"];
|
||||||
|
|
||||||
|
|
|
@ -1029,14 +1029,18 @@ func (h *Headscale) loadACLPolicy() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("loading nodes from database to validate policy: %w", err)
|
return fmt.Errorf("loading nodes from database to validate policy: %w", err)
|
||||||
}
|
}
|
||||||
|
users, err := h.db.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("loading users from database to validate policy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = pol.CompileFilterRules(nodes)
|
_, err = pol.CompileFilterRules(users, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("verifying policy rules: %w", err)
|
return fmt.Errorf("verifying policy rules: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(nodes) > 0 {
|
if len(nodes) > 0 {
|
||||||
_, err = pol.CompileSSHPolicy(nodes[0], nodes)
|
_, err = pol.CompileSSHPolicy(nodes[0], users, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("verifying SSH rules: %w", err)
|
return fmt.Errorf("verifying SSH rules: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
"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"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"zgo.at/zcache/v2"
|
"zgo.at/zcache/v2"
|
||||||
)
|
)
|
||||||
|
@ -44,7 +45,7 @@ func TestMigrations(t *testing.T) {
|
||||||
routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) {
|
routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) {
|
||||||
return GetRoutes(rx)
|
return GetRoutes(rx)
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, routes, 10)
|
assert.Len(t, routes, 10)
|
||||||
want := types.Routes{
|
want := types.Routes{
|
||||||
|
@ -70,7 +71,7 @@ func TestMigrations(t *testing.T) {
|
||||||
routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) {
|
routes, err := Read(h.DB, func(rx *gorm.DB) (types.Routes, error) {
|
||||||
return GetRoutes(rx)
|
return GetRoutes(rx)
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, routes, 4)
|
assert.Len(t, routes, 4)
|
||||||
want := types.Routes{
|
want := types.Routes{
|
||||||
|
@ -132,7 +133,7 @@ func TestMigrations(t *testing.T) {
|
||||||
|
|
||||||
return append(kratest, testkra...), nil
|
return append(kratest, testkra...), nil
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, keys, 5)
|
assert.Len(t, keys, 5)
|
||||||
want := []types.PreAuthKey{
|
want := []types.PreAuthKey{
|
||||||
|
@ -177,7 +178,7 @@ func TestMigrations(t *testing.T) {
|
||||||
nodes, err := Read(h.DB, func(rx *gorm.DB) (types.Nodes, error) {
|
nodes, err := Read(h.DB, func(rx *gorm.DB) (types.Nodes, error) {
|
||||||
return ListNodes(rx)
|
return ListNodes(rx)
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
assert.Falsef(t, node.MachineKey.IsZero(), "expected non zero machinekey")
|
assert.Falsef(t, node.MachineKey.IsZero(), "expected non zero machinekey")
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/juanfont/headscale/hscontrol/types"
|
||||||
"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"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
"tailscale.com/types/ptr"
|
"tailscale.com/types/ptr"
|
||||||
)
|
)
|
||||||
|
@ -457,7 +458,12 @@ func TestBackfillIPAddresses(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
db := tt.dbFunc()
|
db := tt.dbFunc()
|
||||||
|
|
||||||
alloc, err := NewIPAllocator(db, tt.prefix4, tt.prefix6, types.IPAllocationStrategySequential)
|
alloc, err := NewIPAllocator(
|
||||||
|
db,
|
||||||
|
tt.prefix4,
|
||||||
|
tt.prefix6,
|
||||||
|
types.IPAllocationStrategySequential,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to set up ip alloc: %s", err)
|
t.Fatalf("failed to set up ip alloc: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -482,24 +488,29 @@ func TestBackfillIPAddresses(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIPAllocatorNextNoReservedIPs(t *testing.T) {
|
func TestIPAllocatorNextNoReservedIPs(t *testing.T) {
|
||||||
alloc, err := NewIPAllocator(db, ptr.To(tsaddr.CGNATRange()), ptr.To(tsaddr.TailscaleULARange()), types.IPAllocationStrategySequential)
|
alloc, err := NewIPAllocator(
|
||||||
|
db,
|
||||||
|
ptr.To(tsaddr.CGNATRange()),
|
||||||
|
ptr.To(tsaddr.TailscaleULARange()),
|
||||||
|
types.IPAllocationStrategySequential,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to set up ip alloc: %s", err)
|
t.Fatalf("failed to set up ip alloc: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate that we do not give out 100.100.100.100
|
// Validate that we do not give out 100.100.100.100
|
||||||
nextQuad100, err := alloc.next(na("100.100.100.99"), ptr.To(tsaddr.CGNATRange()))
|
nextQuad100, err := alloc.next(na("100.100.100.99"), ptr.To(tsaddr.CGNATRange()))
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, na("100.100.100.101"), *nextQuad100)
|
assert.Equal(t, na("100.100.100.101"), *nextQuad100)
|
||||||
|
|
||||||
// Validate that we do not give out fd7a:115c:a1e0::53
|
// Validate that we do not give out fd7a:115c:a1e0::53
|
||||||
nextQuad100v6, err := alloc.next(na("fd7a:115c:a1e0::52"), ptr.To(tsaddr.TailscaleULARange()))
|
nextQuad100v6, err := alloc.next(na("fd7a:115c:a1e0::52"), ptr.To(tsaddr.TailscaleULARange()))
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, na("fd7a:115c:a1e0::54"), *nextQuad100v6)
|
assert.Equal(t, na("fd7a:115c:a1e0::54"), *nextQuad100v6)
|
||||||
|
|
||||||
// Validate that we do not give out fd7a:115c:a1e0::53
|
// Validate that we do not give out fd7a:115c:a1e0::53
|
||||||
nextChrome, err := alloc.next(na("100.115.91.255"), ptr.To(tsaddr.CGNATRange()))
|
nextChrome, err := alloc.next(na("100.115.91.255"), ptr.To(tsaddr.CGNATRange()))
|
||||||
t.Logf("chrome: %s", nextChrome.String())
|
t.Logf("chrome: %s", nextChrome.String())
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, na("100.115.94.0"), *nextChrome)
|
assert.Equal(t, na("100.115.94.0"), *nextChrome)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"gopkg.in/check.v1"
|
"gopkg.in/check.v1"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
"tailscale.com/net/tsaddr"
|
"tailscale.com/net/tsaddr"
|
||||||
|
@ -255,10 +256,10 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
c.Assert(len(testPeers), check.Equals, 9)
|
c.Assert(len(testPeers), check.Equals, 9)
|
||||||
|
|
||||||
adminRules, _, err := policy.GenerateFilterAndSSHRulesForTests(aclPolicy, adminNode, adminPeers)
|
adminRules, _, err := policy.GenerateFilterAndSSHRulesForTests(aclPolicy, adminNode, adminPeers, []types.User{*stor[0].user, *stor[1].user})
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
testRules, _, err := policy.GenerateFilterAndSSHRulesForTests(aclPolicy, testNode, testPeers)
|
testRules, _, err := policy.GenerateFilterAndSSHRulesForTests(aclPolicy, testNode, testPeers, []types.User{*stor[0].user, *stor[1].user})
|
||||||
c.Assert(err, check.IsNil)
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
peersOfAdminNode := policy.FilterNodesByACL(adminNode, adminPeers, adminRules)
|
peersOfAdminNode := policy.FilterNodesByACL(adminNode, adminPeers, adminRules)
|
||||||
|
@ -558,17 +559,17 @@ func TestAutoApproveRoutes(t *testing.T) {
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
adb, err := newTestDB()
|
adb, err := newTestDB()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
pol, err := policy.LoadACLPolicyFromBytes([]byte(tt.acl))
|
pol, err := policy.LoadACLPolicyFromBytes([]byte(tt.acl))
|
||||||
|
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotNil(t, pol)
|
assert.NotNil(t, pol)
|
||||||
|
|
||||||
user, err := adb.CreateUser("test")
|
user, err := adb.CreateUser("test")
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pak, err := adb.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := adb.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodeKey := key.NewNode()
|
nodeKey := key.NewNode()
|
||||||
machineKey := key.NewMachine()
|
machineKey := key.NewMachine()
|
||||||
|
@ -590,21 +591,21 @@ func TestAutoApproveRoutes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
trx := adb.DB.Save(&node)
|
trx := adb.DB.Save(&node)
|
||||||
assert.NoError(t, trx.Error)
|
require.NoError(t, trx.Error)
|
||||||
|
|
||||||
sendUpdate, err := adb.SaveNodeRoutes(&node)
|
sendUpdate, err := adb.SaveNodeRoutes(&node)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.False(t, sendUpdate)
|
assert.False(t, sendUpdate)
|
||||||
|
|
||||||
node0ByID, err := adb.GetNodeByID(0)
|
node0ByID, err := adb.GetNodeByID(0)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// TODO(kradalby): Check state update
|
// TODO(kradalby): Check state update
|
||||||
err = adb.EnableAutoApprovedRoutes(pol, node0ByID)
|
err = adb.EnableAutoApprovedRoutes(pol, node0ByID)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
enabledRoutes, err := adb.GetEnabledRoutes(node0ByID)
|
enabledRoutes, err := adb.GetEnabledRoutes(node0ByID)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, enabledRoutes, len(tt.want))
|
assert.Len(t, enabledRoutes, len(tt.want))
|
||||||
|
|
||||||
tsaddr.SortPrefixes(enabledRoutes)
|
tsaddr.SortPrefixes(enabledRoutes)
|
||||||
|
@ -697,13 +698,13 @@ func TestListEphemeralNodes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
pak, err := db.CreatePreAuthKey(user.Name, false, false, nil, nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pakEph, err := db.CreatePreAuthKey(user.Name, false, true, nil, nil)
|
pakEph, err := db.CreatePreAuthKey(user.Name, false, true, nil, nil)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
node := types.Node{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
|
@ -726,16 +727,16 @@ func TestListEphemeralNodes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.DB.Save(&node).Error
|
err = db.DB.Save(&node).Error
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = db.DB.Save(&nodeEph).Error
|
err = db.DB.Save(&nodeEph).Error
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes, err := db.ListNodes()
|
nodes, err := db.ListNodes()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ephemeralNodes, err := db.ListEphemeralNodes()
|
ephemeralNodes, err := db.ListEphemeralNodes()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, nodes, 2)
|
assert.Len(t, nodes, 2)
|
||||||
assert.Len(t, ephemeralNodes, 1)
|
assert.Len(t, ephemeralNodes, 1)
|
||||||
|
@ -753,10 +754,10 @@ func TestRenameNode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := db.CreateUser("test")
|
user, err := db.CreateUser("test")
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2, err := db.CreateUser("test2")
|
user2, err := db.CreateUser("test2")
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
node := types.Node{
|
node := types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
|
@ -777,10 +778,10 @@ func TestRenameNode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.DB.Save(&node).Error
|
err = db.DB.Save(&node).Error
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = db.DB.Save(&node2).Error
|
err = db.DB.Save(&node2).Error
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = db.DB.Transaction(func(tx *gorm.DB) error {
|
err = db.DB.Transaction(func(tx *gorm.DB) error {
|
||||||
_, err := RegisterNode(tx, node, nil, nil)
|
_, err := RegisterNode(tx, node, nil, nil)
|
||||||
|
@ -790,10 +791,10 @@ func TestRenameNode(t *testing.T) {
|
||||||
_, err = RegisterNode(tx, node2, nil, nil)
|
_, err = RegisterNode(tx, node2, nil, nil)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes, err := db.ListNodes()
|
nodes, err := db.ListNodes()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, nodes, 2)
|
assert.Len(t, nodes, 2)
|
||||||
|
|
||||||
|
@ -815,26 +816,26 @@ func TestRenameNode(t *testing.T) {
|
||||||
err = db.Write(func(tx *gorm.DB) error {
|
err = db.Write(func(tx *gorm.DB) error {
|
||||||
return RenameNode(tx, nodes[0].ID, "newname")
|
return RenameNode(tx, nodes[0].ID, "newname")
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes, err = db.ListNodes()
|
nodes, err = db.ListNodes()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, nodes, 2)
|
assert.Len(t, nodes, 2)
|
||||||
assert.Equal(t, nodes[0].Hostname, "test")
|
assert.Equal(t, "test", nodes[0].Hostname)
|
||||||
assert.Equal(t, nodes[0].GivenName, "newname")
|
assert.Equal(t, "newname", nodes[0].GivenName)
|
||||||
|
|
||||||
// Nodes can reuse name that is no longer used
|
// Nodes can reuse name that is no longer used
|
||||||
err = db.Write(func(tx *gorm.DB) error {
|
err = db.Write(func(tx *gorm.DB) error {
|
||||||
return RenameNode(tx, nodes[1].ID, "test")
|
return RenameNode(tx, nodes[1].ID, "test")
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes, err = db.ListNodes()
|
nodes, err = db.ListNodes()
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, nodes, 2)
|
assert.Len(t, nodes, 2)
|
||||||
assert.Equal(t, nodes[0].Hostname, "test")
|
assert.Equal(t, "test", nodes[0].Hostname)
|
||||||
assert.Equal(t, nodes[0].GivenName, "newname")
|
assert.Equal(t, "newname", nodes[0].GivenName)
|
||||||
assert.Equal(t, nodes[1].GivenName, "test")
|
assert.Equal(t, "test", nodes[1].GivenName)
|
||||||
|
|
||||||
// Nodes cannot be renamed to used names
|
// Nodes cannot be renamed to used names
|
||||||
err = db.Write(func(tx *gorm.DB) error {
|
err = db.Write(func(tx *gorm.DB) error {
|
||||||
|
|
|
@ -648,8 +648,13 @@ func EnableAutoApprovedRoutes(
|
||||||
if approvedAlias == node.User.Username() {
|
if approvedAlias == node.User.Username() {
|
||||||
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
approvedRoutes = append(approvedRoutes, advertisedRoute)
|
||||||
} else {
|
} else {
|
||||||
|
users, err := ListUsers(tx)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("looking up users to expand route alias: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(kradalby): figure out how to get this to depend on less stuff
|
// TODO(kradalby): figure out how to get this to depend on less stuff
|
||||||
approvedIps, err := aclPolicy.ExpandAlias(types.Nodes{node}, approvedAlias)
|
approvedIps, err := aclPolicy.ExpandAlias(types.Nodes{node}, users, approvedAlias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("expanding alias %q for autoApprovers: %w", approvedAlias, err)
|
return fmt.Errorf("expanding alias %q for autoApprovers: %w", approvedAlias, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,14 +737,18 @@ func (api headscaleV1APIServer) SetPolicy(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("loading nodes from database to validate policy: %w", err)
|
return nil, fmt.Errorf("loading nodes from database to validate policy: %w", err)
|
||||||
}
|
}
|
||||||
|
users, err := api.h.db.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("loading users from database to validate policy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = pol.CompileFilterRules(nodes)
|
_, err = pol.CompileFilterRules(users, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("verifying policy rules: %w", err)
|
return nil, fmt.Errorf("verifying policy rules: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(nodes) > 0 {
|
if len(nodes) > 0 {
|
||||||
_, err = pol.CompileSSHPolicy(nodes[0], nodes)
|
_, err = pol.CompileSSHPolicy(nodes[0], users, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("verifying SSH rules: %w", err)
|
return nil, fmt.Errorf("verifying SSH rules: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,7 @@ func addNextDNSMetadata(resolvers []*dnstype.Resolver, node *types.Node) {
|
||||||
func (m *Mapper) fullMapResponse(
|
func (m *Mapper) fullMapResponse(
|
||||||
node *types.Node,
|
node *types.Node,
|
||||||
peers types.Nodes,
|
peers types.Nodes,
|
||||||
|
users []types.User,
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
capVer tailcfg.CapabilityVersion,
|
capVer tailcfg.CapabilityVersion,
|
||||||
) (*tailcfg.MapResponse, error) {
|
) (*tailcfg.MapResponse, error) {
|
||||||
|
@ -167,6 +168,7 @@ func (m *Mapper) fullMapResponse(
|
||||||
pol,
|
pol,
|
||||||
node,
|
node,
|
||||||
capVer,
|
capVer,
|
||||||
|
users,
|
||||||
peers,
|
peers,
|
||||||
peers,
|
peers,
|
||||||
m.cfg,
|
m.cfg,
|
||||||
|
@ -189,8 +191,12 @@ func (m *Mapper) FullMapResponse(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
users, err := m.db.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := m.fullMapResponse(node, peers, pol, mapRequest.Version)
|
resp, err := m.fullMapResponse(node, peers, users, pol, mapRequest.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -253,6 +259,11 @@ func (m *Mapper) PeerChangedResponse(
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
users, err := m.db.ListUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("listing users for map response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
var removedIDs []tailcfg.NodeID
|
var removedIDs []tailcfg.NodeID
|
||||||
var changedIDs []types.NodeID
|
var changedIDs []types.NodeID
|
||||||
for nodeID, nodeChanged := range changed {
|
for nodeID, nodeChanged := range changed {
|
||||||
|
@ -276,6 +287,7 @@ func (m *Mapper) PeerChangedResponse(
|
||||||
pol,
|
pol,
|
||||||
node,
|
node,
|
||||||
mapRequest.Version,
|
mapRequest.Version,
|
||||||
|
users,
|
||||||
peers,
|
peers,
|
||||||
changedNodes,
|
changedNodes,
|
||||||
m.cfg,
|
m.cfg,
|
||||||
|
@ -508,16 +520,17 @@ func appendPeerChanges(
|
||||||
pol *policy.ACLPolicy,
|
pol *policy.ACLPolicy,
|
||||||
node *types.Node,
|
node *types.Node,
|
||||||
capVer tailcfg.CapabilityVersion,
|
capVer tailcfg.CapabilityVersion,
|
||||||
|
users []types.User,
|
||||||
peers types.Nodes,
|
peers types.Nodes,
|
||||||
changed types.Nodes,
|
changed types.Nodes,
|
||||||
cfg *types.Config,
|
cfg *types.Config,
|
||||||
) error {
|
) error {
|
||||||
packetFilter, err := pol.CompileFilterRules(append(peers, node))
|
packetFilter, err := pol.CompileFilterRules(users, append(peers, node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sshPolicy, err := pol.CompileSSHPolicy(node, peers)
|
sshPolicy, err := pol.CompileSSHPolicy(node, users, peers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,9 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
lastSeen := time.Date(2009, time.November, 10, 23, 9, 0, 0, time.UTC)
|
lastSeen := time.Date(2009, time.November, 10, 23, 9, 0, 0, time.UTC)
|
||||||
expire := time.Date(2500, time.November, 11, 23, 0, 0, 0, time.UTC)
|
expire := time.Date(2500, time.November, 11, 23, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
|
user1 := types.User{Model: gorm.Model{ID: 0}, Name: "mini"}
|
||||||
|
user2 := types.User{Model: gorm.Model{ID: 1}, Name: "peer2"}
|
||||||
|
|
||||||
mini := &types.Node{
|
mini := &types.Node{
|
||||||
ID: 0,
|
ID: 0,
|
||||||
MachineKey: mustMK(
|
MachineKey: mustMK(
|
||||||
|
@ -173,8 +176,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
IPv4: iap("100.64.0.1"),
|
IPv4: iap("100.64.0.1"),
|
||||||
Hostname: "mini",
|
Hostname: "mini",
|
||||||
GivenName: "mini",
|
GivenName: "mini",
|
||||||
UserID: 0,
|
UserID: user1.ID,
|
||||||
User: types.User{Name: "mini"},
|
User: user1,
|
||||||
ForcedTags: []string{},
|
ForcedTags: []string{},
|
||||||
AuthKey: &types.PreAuthKey{},
|
AuthKey: &types.PreAuthKey{},
|
||||||
LastSeen: &lastSeen,
|
LastSeen: &lastSeen,
|
||||||
|
@ -253,8 +256,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
IPv4: iap("100.64.0.2"),
|
IPv4: iap("100.64.0.2"),
|
||||||
Hostname: "peer1",
|
Hostname: "peer1",
|
||||||
GivenName: "peer1",
|
GivenName: "peer1",
|
||||||
UserID: 0,
|
UserID: user1.ID,
|
||||||
User: types.User{Name: "mini"},
|
User: user1,
|
||||||
ForcedTags: []string{},
|
ForcedTags: []string{},
|
||||||
LastSeen: &lastSeen,
|
LastSeen: &lastSeen,
|
||||||
Expiry: &expire,
|
Expiry: &expire,
|
||||||
|
@ -308,8 +311,8 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
IPv4: iap("100.64.0.3"),
|
IPv4: iap("100.64.0.3"),
|
||||||
Hostname: "peer2",
|
Hostname: "peer2",
|
||||||
GivenName: "peer2",
|
GivenName: "peer2",
|
||||||
UserID: 1,
|
UserID: user2.ID,
|
||||||
User: types.User{Name: "peer2"},
|
User: user2,
|
||||||
ForcedTags: []string{},
|
ForcedTags: []string{},
|
||||||
LastSeen: &lastSeen,
|
LastSeen: &lastSeen,
|
||||||
Expiry: &expire,
|
Expiry: &expire,
|
||||||
|
@ -468,6 +471,7 @@ func Test_fullMapResponse(t *testing.T) {
|
||||||
got, err := mappy.fullMapResponse(
|
got, err := mappy.fullMapResponse(
|
||||||
tt.node,
|
tt.node,
|
||||||
tt.peers,
|
tt.peers,
|
||||||
|
[]types.User{user1, user2},
|
||||||
tt.pol,
|
tt.pol,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
|
@ -488,7 +488,7 @@ func (a *AuthProviderOIDC) registerNode(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(kradalby):
|
// TODO(kradalby):
|
||||||
// Rewrite in elem-go
|
// Rewrite in elem-go.
|
||||||
func renderOIDCCallbackTemplate(
|
func renderOIDCCallbackTemplate(
|
||||||
user *types.User,
|
user *types.User,
|
||||||
) (*bytes.Buffer, error) {
|
) (*bytes.Buffer, error) {
|
||||||
|
|
|
@ -137,20 +137,21 @@ func GenerateFilterAndSSHRulesForTests(
|
||||||
policy *ACLPolicy,
|
policy *ACLPolicy,
|
||||||
node *types.Node,
|
node *types.Node,
|
||||||
peers types.Nodes,
|
peers types.Nodes,
|
||||||
|
users []types.User,
|
||||||
) ([]tailcfg.FilterRule, *tailcfg.SSHPolicy, error) {
|
) ([]tailcfg.FilterRule, *tailcfg.SSHPolicy, error) {
|
||||||
// If there is no policy defined, we default to allow all
|
// If there is no policy defined, we default to allow all
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
return tailcfg.FilterAllowAll, &tailcfg.SSHPolicy{}, nil
|
return tailcfg.FilterAllowAll, &tailcfg.SSHPolicy{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
rules, err := policy.CompileFilterRules(append(peers, node))
|
rules, err := policy.CompileFilterRules(users, append(peers, node))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().Interface("ACL", rules).Str("node", node.GivenName).Msg("ACL rules")
|
log.Trace().Interface("ACL", rules).Str("node", node.GivenName).Msg("ACL rules")
|
||||||
|
|
||||||
sshPolicy, err := policy.CompileSSHPolicy(node, peers)
|
sshPolicy, err := policy.CompileSSHPolicy(node, users, peers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
return []tailcfg.FilterRule{}, &tailcfg.SSHPolicy{}, err
|
||||||
}
|
}
|
||||||
|
@ -161,6 +162,7 @@ func GenerateFilterAndSSHRulesForTests(
|
||||||
// CompileFilterRules takes a set of nodes and an ACLPolicy and generates a
|
// CompileFilterRules takes a set of nodes and an ACLPolicy and generates a
|
||||||
// set of Tailscale compatible FilterRules used to allow traffic on clients.
|
// set of Tailscale compatible FilterRules used to allow traffic on clients.
|
||||||
func (pol *ACLPolicy) CompileFilterRules(
|
func (pol *ACLPolicy) CompileFilterRules(
|
||||||
|
users []types.User,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
) ([]tailcfg.FilterRule, error) {
|
) ([]tailcfg.FilterRule, error) {
|
||||||
if pol == nil {
|
if pol == nil {
|
||||||
|
@ -176,9 +178,14 @@ func (pol *ACLPolicy) CompileFilterRules(
|
||||||
|
|
||||||
var srcIPs []string
|
var srcIPs []string
|
||||||
for srcIndex, src := range acl.Sources {
|
for srcIndex, src := range acl.Sources {
|
||||||
srcs, err := pol.expandSource(src, nodes)
|
srcs, err := pol.expandSource(src, users, nodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing policy, acl index: %d->%d: %w", index, srcIndex, err)
|
return nil, fmt.Errorf(
|
||||||
|
"parsing policy, acl index: %d->%d: %w",
|
||||||
|
index,
|
||||||
|
srcIndex,
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
srcIPs = append(srcIPs, srcs...)
|
srcIPs = append(srcIPs, srcs...)
|
||||||
}
|
}
|
||||||
|
@ -197,6 +204,7 @@ func (pol *ACLPolicy) CompileFilterRules(
|
||||||
|
|
||||||
expanded, err := pol.ExpandAlias(
|
expanded, err := pol.ExpandAlias(
|
||||||
nodes,
|
nodes,
|
||||||
|
users,
|
||||||
alias,
|
alias,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -281,6 +289,7 @@ func ReduceFilterRules(node *types.Node, rules []tailcfg.FilterRule) []tailcfg.F
|
||||||
|
|
||||||
func (pol *ACLPolicy) CompileSSHPolicy(
|
func (pol *ACLPolicy) CompileSSHPolicy(
|
||||||
node *types.Node,
|
node *types.Node,
|
||||||
|
users []types.User,
|
||||||
peers types.Nodes,
|
peers types.Nodes,
|
||||||
) (*tailcfg.SSHPolicy, error) {
|
) (*tailcfg.SSHPolicy, error) {
|
||||||
if pol == nil {
|
if pol == nil {
|
||||||
|
@ -312,7 +321,7 @@ func (pol *ACLPolicy) CompileSSHPolicy(
|
||||||
for index, sshACL := range pol.SSHs {
|
for index, sshACL := range pol.SSHs {
|
||||||
var dest netipx.IPSetBuilder
|
var dest netipx.IPSetBuilder
|
||||||
for _, src := range sshACL.Destinations {
|
for _, src := range sshACL.Destinations {
|
||||||
expanded, err := pol.ExpandAlias(append(peers, node), src)
|
expanded, err := pol.ExpandAlias(append(peers, node), users, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -335,12 +344,21 @@ func (pol *ACLPolicy) CompileSSHPolicy(
|
||||||
case "check":
|
case "check":
|
||||||
checkAction, err := sshCheckAction(sshACL.CheckPeriod)
|
checkAction, err := sshCheckAction(sshACL.CheckPeriod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing SSH policy, parsing check duration, index: %d: %w", index, err)
|
return nil, fmt.Errorf(
|
||||||
|
"parsing SSH policy, parsing check duration, index: %d: %w",
|
||||||
|
index,
|
||||||
|
err,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
action = *checkAction
|
action = *checkAction
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("parsing SSH policy, unknown action %q, index: %d: %w", sshACL.Action, index, err)
|
return nil, fmt.Errorf(
|
||||||
|
"parsing SSH policy, unknown action %q, index: %d: %w",
|
||||||
|
sshACL.Action,
|
||||||
|
index,
|
||||||
|
err,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
principals := make([]*tailcfg.SSHPrincipal, 0, len(sshACL.Sources))
|
principals := make([]*tailcfg.SSHPrincipal, 0, len(sshACL.Sources))
|
||||||
|
@ -363,6 +381,7 @@ func (pol *ACLPolicy) CompileSSHPolicy(
|
||||||
} else {
|
} else {
|
||||||
expandedSrcs, err := pol.ExpandAlias(
|
expandedSrcs, err := pol.ExpandAlias(
|
||||||
peers,
|
peers,
|
||||||
|
users,
|
||||||
rawSrc,
|
rawSrc,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -512,9 +531,10 @@ func parseProtocol(protocol string) ([]int, bool, error) {
|
||||||
// with the given src alias.
|
// with the given src alias.
|
||||||
func (pol *ACLPolicy) expandSource(
|
func (pol *ACLPolicy) expandSource(
|
||||||
src string,
|
src string,
|
||||||
|
users []types.User,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
) ([]string, error) {
|
) ([]string, error) {
|
||||||
ipSet, err := pol.ExpandAlias(nodes, src)
|
ipSet, err := pol.ExpandAlias(nodes, users, src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
|
@ -538,6 +558,7 @@ func (pol *ACLPolicy) expandSource(
|
||||||
// and transform these in IPAddresses.
|
// and transform these in IPAddresses.
|
||||||
func (pol *ACLPolicy) ExpandAlias(
|
func (pol *ACLPolicy) ExpandAlias(
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
|
users []types.User,
|
||||||
alias string,
|
alias string,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
if isWildcard(alias) {
|
if isWildcard(alias) {
|
||||||
|
@ -552,12 +573,12 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
|
|
||||||
// if alias is a group
|
// if alias is a group
|
||||||
if isGroup(alias) {
|
if isGroup(alias) {
|
||||||
return pol.expandIPsFromGroup(alias, nodes)
|
return pol.expandIPsFromGroup(alias, users, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is a tag
|
// if alias is a tag
|
||||||
if isTag(alias) {
|
if isTag(alias) {
|
||||||
return pol.expandIPsFromTag(alias, nodes)
|
return pol.expandIPsFromTag(alias, users, nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isAutoGroup(alias) {
|
if isAutoGroup(alias) {
|
||||||
|
@ -565,7 +586,7 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is a user
|
// if alias is a user
|
||||||
if ips, err := pol.expandIPsFromUser(alias, nodes); ips != nil {
|
if ips, err := pol.expandIPsFromUser(alias, users, nodes); ips != nil {
|
||||||
return ips, err
|
return ips, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,7 +595,7 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
if h, ok := pol.Hosts[alias]; ok {
|
if h, ok := pol.Hosts[alias]; ok {
|
||||||
log.Trace().Str("host", h.String()).Msg("ExpandAlias got hosts entry")
|
log.Trace().Str("host", h.String()).Msg("ExpandAlias got hosts entry")
|
||||||
|
|
||||||
return pol.ExpandAlias(nodes, h.String())
|
return pol.ExpandAlias(nodes, users, h.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// if alias is an IP
|
// if alias is an IP
|
||||||
|
@ -599,7 +620,7 @@ func (pol *ACLPolicy) ExpandAlias(
|
||||||
// TODO(kradalby): It is quite hard to understand what this function is doing,
|
// TODO(kradalby): It is quite hard to understand what this function is doing,
|
||||||
// it seems like it trying to ensure that we dont include nodes that are tagged
|
// it seems like it trying to ensure that we dont include nodes that are tagged
|
||||||
// when we look up the nodes owned by a user.
|
// when we look up the nodes owned by a user.
|
||||||
// This should be refactored to be more clear as part of the Tags work in #1369
|
// This should be refactored to be more clear as part of the Tags work in #1369.
|
||||||
func excludeCorrectlyTaggedNodes(
|
func excludeCorrectlyTaggedNodes(
|
||||||
aclPolicy *ACLPolicy,
|
aclPolicy *ACLPolicy,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
|
@ -751,16 +772,17 @@ func (pol *ACLPolicy) expandUsersFromGroup(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromGroup(
|
func (pol *ACLPolicy) expandIPsFromGroup(
|
||||||
group string,
|
group string,
|
||||||
|
users []types.User,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
var build netipx.IPSetBuilder
|
var build netipx.IPSetBuilder
|
||||||
|
|
||||||
users, err := pol.expandUsersFromGroup(group)
|
userTokens, err := pol.expandUsersFromGroup(group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &netipx.IPSet{}, err
|
return &netipx.IPSet{}, err
|
||||||
}
|
}
|
||||||
for _, user := range users {
|
for _, user := range userTokens {
|
||||||
filteredNodes := filterNodesByUser(nodes, user)
|
filteredNodes := filterNodesByUser(nodes, users, user)
|
||||||
for _, node := range filteredNodes {
|
for _, node := range filteredNodes {
|
||||||
node.AppendToIPSet(&build)
|
node.AppendToIPSet(&build)
|
||||||
}
|
}
|
||||||
|
@ -771,6 +793,7 @@ func (pol *ACLPolicy) expandIPsFromGroup(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromTag(
|
func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
alias string,
|
alias string,
|
||||||
|
users []types.User,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
var build netipx.IPSetBuilder
|
var build netipx.IPSetBuilder
|
||||||
|
@ -803,7 +826,7 @@ func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
|
|
||||||
// filter out nodes per tag owner
|
// filter out nodes per tag owner
|
||||||
for _, user := range owners {
|
for _, user := range owners {
|
||||||
nodes := filterNodesByUser(nodes, user)
|
nodes := filterNodesByUser(nodes, users, user)
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if node.Hostinfo == nil {
|
if node.Hostinfo == nil {
|
||||||
continue
|
continue
|
||||||
|
@ -820,11 +843,12 @@ func (pol *ACLPolicy) expandIPsFromTag(
|
||||||
|
|
||||||
func (pol *ACLPolicy) expandIPsFromUser(
|
func (pol *ACLPolicy) expandIPsFromUser(
|
||||||
user string,
|
user string,
|
||||||
|
users []types.User,
|
||||||
nodes types.Nodes,
|
nodes types.Nodes,
|
||||||
) (*netipx.IPSet, error) {
|
) (*netipx.IPSet, error) {
|
||||||
var build netipx.IPSetBuilder
|
var build netipx.IPSetBuilder
|
||||||
|
|
||||||
filteredNodes := filterNodesByUser(nodes, user)
|
filteredNodes := filterNodesByUser(nodes, users, user)
|
||||||
filteredNodes = excludeCorrectlyTaggedNodes(pol, filteredNodes, user)
|
filteredNodes = excludeCorrectlyTaggedNodes(pol, filteredNodes, user)
|
||||||
|
|
||||||
// shortcurcuit if we have no nodes to get ips from.
|
// shortcurcuit if we have no nodes to get ips from.
|
||||||
|
@ -953,10 +977,43 @@ func (pol *ACLPolicy) TagsOfNode(
|
||||||
return validTags, invalidTags
|
return validTags, invalidTags
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterNodesByUser(nodes types.Nodes, user string) types.Nodes {
|
// filterNodesByUser returns a list of nodes that match the given userToken from a
|
||||||
|
// policy.
|
||||||
|
// Matching nodes are determined by first matching the user token to a user by checking:
|
||||||
|
// - If it is an ID that mactches the user database ID
|
||||||
|
// - It is the Provider Identifier from OIDC
|
||||||
|
// - It matches the username or email of a user
|
||||||
|
//
|
||||||
|
// If the token matches more than one user, zero nodes will returned.
|
||||||
|
func filterNodesByUser(nodes types.Nodes, users []types.User, userToken string) types.Nodes {
|
||||||
var out types.Nodes
|
var out types.Nodes
|
||||||
|
|
||||||
|
var potentialUsers []types.User
|
||||||
|
for _, user := range users {
|
||||||
|
if user.ProviderIdentifier.Valid && user.ProviderIdentifier.String == userToken {
|
||||||
|
// If a user is matching with a known unique field,
|
||||||
|
// disgard all other users and only keep the current
|
||||||
|
// user.
|
||||||
|
potentialUsers = []types.User{user}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if user.Email == userToken {
|
||||||
|
potentialUsers = append(potentialUsers, user)
|
||||||
|
}
|
||||||
|
if user.Name == userToken {
|
||||||
|
potentialUsers = append(potentialUsers, user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(potentialUsers) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user := potentialUsers[0]
|
||||||
|
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
if node.User.Username() == user {
|
if node.User.ID == user.ID {
|
||||||
out = append(out, node)
|
out = append(out, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@ func Windows(url string) *elem.Element {
|
||||||
elem.Text("headscale - Windows"),
|
elem.Text("headscale - Windows"),
|
||||||
),
|
),
|
||||||
elem.Body(attrs.Props{
|
elem.Body(attrs.Props{
|
||||||
attrs.Style : bodyStyle.ToInline(),
|
attrs.Style: bodyStyle.ToInline(),
|
||||||
},
|
},
|
||||||
headerOne("headscale: Windows configuration"),
|
headerOne("headscale: Windows configuration"),
|
||||||
elem.P(nil,
|
elem.P(nil,
|
||||||
|
@ -21,7 +21,8 @@ func Windows(url string) *elem.Element {
|
||||||
elem.A(attrs.Props{
|
elem.A(attrs.Props{
|
||||||
attrs.Href: "https://tailscale.com/download/windows",
|
attrs.Href: "https://tailscale.com/download/windows",
|
||||||
attrs.Rel: "noreferrer noopener",
|
attrs.Rel: "noreferrer noopener",
|
||||||
attrs.Target: "_blank"},
|
attrs.Target: "_blank",
|
||||||
|
},
|
||||||
elem.Text("Tailscale for Windows ")),
|
elem.Text("Tailscale for Windows ")),
|
||||||
elem.Text("and install it."),
|
elem.Text("and install it."),
|
||||||
),
|
),
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/dnstype"
|
"tailscale.com/types/dnstype"
|
||||||
)
|
)
|
||||||
|
@ -36,8 +37,17 @@ func TestReadConfig(t *testing.T) {
|
||||||
MagicDNS: true,
|
MagicDNS: true,
|
||||||
BaseDomain: "example.com",
|
BaseDomain: "example.com",
|
||||||
Nameservers: Nameservers{
|
Nameservers: Nameservers{
|
||||||
Global: []string{"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001", "https://dns.nextdns.io/abc123"},
|
Global: []string{
|
||||||
Split: map[string][]string{"darp.headscale.net": {"1.1.1.1", "8.8.8.8"}, "foo.bar.com": {"1.1.1.1"}},
|
"1.1.1.1",
|
||||||
|
"1.0.0.1",
|
||||||
|
"2606:4700:4700::1111",
|
||||||
|
"2606:4700:4700::1001",
|
||||||
|
"https://dns.nextdns.io/abc123",
|
||||||
|
},
|
||||||
|
Split: map[string][]string{
|
||||||
|
"darp.headscale.net": {"1.1.1.1", "8.8.8.8"},
|
||||||
|
"foo.bar.com": {"1.1.1.1"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ExtraRecords: []tailcfg.DNSRecord{
|
ExtraRecords: []tailcfg.DNSRecord{
|
||||||
{Name: "grafana.myvpn.example.com", Type: "A", Value: "100.64.0.3"},
|
{Name: "grafana.myvpn.example.com", Type: "A", Value: "100.64.0.3"},
|
||||||
|
@ -92,8 +102,17 @@ func TestReadConfig(t *testing.T) {
|
||||||
MagicDNS: false,
|
MagicDNS: false,
|
||||||
BaseDomain: "example.com",
|
BaseDomain: "example.com",
|
||||||
Nameservers: Nameservers{
|
Nameservers: Nameservers{
|
||||||
Global: []string{"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001", "https://dns.nextdns.io/abc123"},
|
Global: []string{
|
||||||
Split: map[string][]string{"darp.headscale.net": {"1.1.1.1", "8.8.8.8"}, "foo.bar.com": {"1.1.1.1"}},
|
"1.1.1.1",
|
||||||
|
"1.0.0.1",
|
||||||
|
"2606:4700:4700::1111",
|
||||||
|
"2606:4700:4700::1001",
|
||||||
|
"https://dns.nextdns.io/abc123",
|
||||||
|
},
|
||||||
|
Split: map[string][]string{
|
||||||
|
"darp.headscale.net": {"1.1.1.1", "8.8.8.8"},
|
||||||
|
"foo.bar.com": {"1.1.1.1"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
ExtraRecords: []tailcfg.DNSRecord{
|
ExtraRecords: []tailcfg.DNSRecord{
|
||||||
{Name: "grafana.myvpn.example.com", Type: "A", Value: "100.64.0.3"},
|
{Name: "grafana.myvpn.example.com", Type: "A", Value: "100.64.0.3"},
|
||||||
|
@ -187,7 +206,7 @@ func TestReadConfig(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
viper.Reset()
|
viper.Reset()
|
||||||
err := LoadConfig(tt.configPath, true)
|
err := LoadConfig(tt.configPath, true)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
conf, err := tt.setup(t)
|
conf, err := tt.setup(t)
|
||||||
|
|
||||||
|
@ -197,7 +216,7 @@ func TestReadConfig(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if diff := cmp.Diff(tt.want, conf); diff != "" {
|
if diff := cmp.Diff(tt.want, conf); diff != "" {
|
||||||
t.Errorf("ReadConfig() mismatch (-want +got):\n%s", diff)
|
t.Errorf("ReadConfig() mismatch (-want +got):\n%s", diff)
|
||||||
|
@ -277,10 +296,10 @@ func TestReadConfigFromEnv(t *testing.T) {
|
||||||
|
|
||||||
viper.Reset()
|
viper.Reset()
|
||||||
err := LoadConfig("testdata/minimal.yaml", true)
|
err := LoadConfig("testdata/minimal.yaml", true)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
conf, err := tt.setup(t)
|
conf, err := tt.setup(t)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if diff := cmp.Diff(tt.want, conf); diff != "" {
|
if diff := cmp.Diff(tt.want, conf); diff != "" {
|
||||||
t.Errorf("ReadConfig() mismatch (-want +got):\n%s", diff)
|
t.Errorf("ReadConfig() mismatch (-want +got):\n%s", diff)
|
||||||
|
@ -311,13 +330,25 @@ noise:
|
||||||
|
|
||||||
// Check configuration validation errors (1)
|
// Check configuration validation errors (1)
|
||||||
err = LoadConfig(tmpDir, false)
|
err = LoadConfig(tmpDir, false)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = validateServerConfig()
|
err = validateServerConfig()
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
assert.Contains(t, err.Error(), "Fatal config error: set either tls_letsencrypt_hostname or tls_cert_path/tls_key_path, not both")
|
assert.Contains(
|
||||||
assert.Contains(t, err.Error(), "Fatal config error: the only supported values for tls_letsencrypt_challenge_type are")
|
t,
|
||||||
assert.Contains(t, err.Error(), "Fatal config error: server_url must start with https:// or http://")
|
err.Error(),
|
||||||
|
"Fatal config error: set either tls_letsencrypt_hostname or tls_cert_path/tls_key_path, not both",
|
||||||
|
)
|
||||||
|
assert.Contains(
|
||||||
|
t,
|
||||||
|
err.Error(),
|
||||||
|
"Fatal config error: the only supported values for tls_letsencrypt_challenge_type are",
|
||||||
|
)
|
||||||
|
assert.Contains(
|
||||||
|
t,
|
||||||
|
err.Error(),
|
||||||
|
"Fatal config error: server_url must start with https:// or http://",
|
||||||
|
)
|
||||||
|
|
||||||
// Check configuration validation errors (2)
|
// Check configuration validation errors (2)
|
||||||
configYaml = []byte(`---
|
configYaml = []byte(`---
|
||||||
|
@ -332,7 +363,7 @@ tls_letsencrypt_challenge_type: TLS-ALPN-01
|
||||||
t.Fatalf("Couldn't write file %s", configFilePath)
|
t.Fatalf("Couldn't write file %s", configFilePath)
|
||||||
}
|
}
|
||||||
err = LoadConfig(tmpDir, false)
|
err = LoadConfig(tmpDir, false)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
|
|
|
@ -2,6 +2,8 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
|
"database/sql"
|
||||||
|
"net/mail"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
|
@ -34,7 +36,7 @@ type User struct {
|
||||||
// Unique identifier of the user from OIDC,
|
// Unique identifier of the user from OIDC,
|
||||||
// comes from `sub` claim in the OIDC token
|
// comes from `sub` claim in the OIDC token
|
||||||
// and is used to lookup the user.
|
// and is used to lookup the user.
|
||||||
ProviderIdentifier string `gorm:"index"`
|
ProviderIdentifier sql.NullString `gorm:"index"`
|
||||||
|
|
||||||
// Provider is the origin of the user account,
|
// Provider is the origin of the user account,
|
||||||
// same as RegistrationMethod, without authkey.
|
// same as RegistrationMethod, without authkey.
|
||||||
|
@ -51,7 +53,7 @@ type User struct {
|
||||||
// should be used throughout headscale, in information returned to the
|
// should be used throughout headscale, in information returned to the
|
||||||
// user and the Policy engine.
|
// user and the Policy engine.
|
||||||
func (u *User) Username() string {
|
func (u *User) Username() string {
|
||||||
return cmp.Or(u.Email, u.Name, u.ProviderIdentifier, strconv.FormatUint(uint64(u.ID), 10))
|
return cmp.Or(u.Email, u.Name, u.ProviderIdentifier.String, strconv.FormatUint(uint64(u.ID), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisplayNameOrUsername returns the DisplayName if it exists, otherwise
|
// DisplayNameOrUsername returns the DisplayName if it exists, otherwise
|
||||||
|
@ -107,7 +109,7 @@ func (u *User) Proto() *v1.User {
|
||||||
CreatedAt: timestamppb.New(u.CreatedAt),
|
CreatedAt: timestamppb.New(u.CreatedAt),
|
||||||
DisplayName: u.DisplayName,
|
DisplayName: u.DisplayName,
|
||||||
Email: u.Email,
|
Email: u.Email,
|
||||||
ProviderId: u.ProviderIdentifier,
|
ProviderId: u.ProviderIdentifier.String,
|
||||||
Provider: u.Provider,
|
Provider: u.Provider,
|
||||||
ProfilePicUrl: u.ProfilePicURL,
|
ProfilePicUrl: u.ProfilePicURL,
|
||||||
}
|
}
|
||||||
|
@ -129,10 +131,20 @@ type OIDCClaims struct {
|
||||||
// FromClaim overrides a User from OIDC claims.
|
// FromClaim overrides a User from OIDC claims.
|
||||||
// All fields will be updated, except for the ID.
|
// All fields will be updated, except for the ID.
|
||||||
func (u *User) FromClaim(claims *OIDCClaims) {
|
func (u *User) FromClaim(claims *OIDCClaims) {
|
||||||
u.ProviderIdentifier = claims.Sub
|
err := util.CheckForFQDNRules(claims.Username)
|
||||||
u.DisplayName = claims.Name
|
if err == nil {
|
||||||
u.Email = claims.Email
|
|
||||||
u.Name = claims.Username
|
u.Name = claims.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims.EmailVerified {
|
||||||
|
_, err = mail.ParseAddress(claims.Email)
|
||||||
|
if err == nil {
|
||||||
|
u.Email = claims.Email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u.ProviderIdentifier.String = claims.Sub
|
||||||
|
u.DisplayName = claims.Name
|
||||||
u.ProfilePicURL = claims.ProfilePictureURL
|
u.ProfilePicURL = claims.ProfilePictureURL
|
||||||
u.Provider = util.RegisterMethodOIDC
|
u.Provider = util.RegisterMethodOIDC
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenerateRandomStringDNSSafe(t *testing.T) {
|
func TestGenerateRandomStringDNSSafe(t *testing.T) {
|
||||||
for i := 0; i < 100000; i++ {
|
for i := 0; i < 100000; i++ {
|
||||||
str, err := GenerateRandomStringDNSSafe(8)
|
str, err := GenerateRandomStringDNSSafe(8)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, str, 8)
|
assert.Len(t, str, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/juanfont/headscale/integration/hsic"
|
"github.com/juanfont/headscale/integration/hsic"
|
||||||
"github.com/juanfont/headscale/integration/tsic"
|
"github.com/juanfont/headscale/integration/tsic"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var veryLargeDestination = []string{
|
var veryLargeDestination = []string{
|
||||||
|
@ -54,7 +55,7 @@ func aclScenario(
|
||||||
) *Scenario {
|
) *Scenario {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"user1": clientsPerUser,
|
"user1": clientsPerUser,
|
||||||
|
@ -77,10 +78,10 @@ func aclScenario(
|
||||||
hsic.WithACLPolicy(policy),
|
hsic.WithACLPolicy(policy),
|
||||||
hsic.WithTestName("acl"),
|
hsic.WithTestName("acl"),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = scenario.ListTailscaleClientsFQDNs()
|
_, err = scenario.ListTailscaleClientsFQDNs()
|
||||||
assertNoErrListFQDN(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return scenario
|
return scenario
|
||||||
}
|
}
|
||||||
|
@ -267,7 +268,7 @@ func TestACLHostsInNetMapTable(t *testing.T) {
|
||||||
for name, testCase := range tests {
|
for name, testCase := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
spec := testCase.users
|
spec := testCase.users
|
||||||
|
|
||||||
|
@ -275,22 +276,22 @@ func TestACLHostsInNetMapTable(t *testing.T) {
|
||||||
[]tsic.Option{},
|
[]tsic.Option{},
|
||||||
hsic.WithACLPolicy(&testCase.policy),
|
hsic.WithACLPolicy(&testCase.policy),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
allClients, err := scenario.ListTailscaleClients()
|
allClients, err := scenario.ListTailscaleClients()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = scenario.WaitForTailscaleSyncWithPeerCount(testCase.want["user1"])
|
err = scenario.WaitForTailscaleSyncWithPeerCount(testCase.want["user1"])
|
||||||
assertNoErrSync(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, client := range allClients {
|
for _, client := range allClients {
|
||||||
status, err := client.Status()
|
status, err := client.Status()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user := status.User[status.Self.UserID].LoginName
|
user := status.User[status.Self.UserID].LoginName
|
||||||
|
|
||||||
assert.Equal(t, (testCase.want[user]), len(status.Peer))
|
assert.Len(t, status.Peer, (testCase.want[user]))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -319,23 +320,23 @@ func TestACLAllowUser80Dst(t *testing.T) {
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
user1Clients, err := scenario.ListTailscaleClients("user1")
|
user1Clients, err := scenario.ListTailscaleClients("user1")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2Clients, err := scenario.ListTailscaleClients("user2")
|
user2Clients, err := scenario.ListTailscaleClients("user2")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test that user1 can visit all user2
|
// Test that user1 can visit all user2
|
||||||
for _, client := range user1Clients {
|
for _, client := range user1Clients {
|
||||||
for _, peer := range user2Clients {
|
for _, peer := range user2Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,14 +344,14 @@ func TestACLAllowUser80Dst(t *testing.T) {
|
||||||
for _, client := range user2Clients {
|
for _, client := range user2Clients {
|
||||||
for _, peer := range user1Clients {
|
for _, peer := range user1Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,10 +377,10 @@ func TestACLDenyAllPort80(t *testing.T) {
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
allClients, err := scenario.ListTailscaleClients()
|
allClients, err := scenario.ListTailscaleClients()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
allHostnames, err := scenario.ListTailscaleClientsFQDNs()
|
allHostnames, err := scenario.ListTailscaleClientsFQDNs()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, client := range allClients {
|
for _, client := range allClients {
|
||||||
for _, hostname := range allHostnames {
|
for _, hostname := range allHostnames {
|
||||||
|
@ -394,7 +395,7 @@ func TestACLDenyAllPort80(t *testing.T) {
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,23 +421,23 @@ func TestACLAllowUserDst(t *testing.T) {
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
user1Clients, err := scenario.ListTailscaleClients("user1")
|
user1Clients, err := scenario.ListTailscaleClients("user1")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2Clients, err := scenario.ListTailscaleClients("user2")
|
user2Clients, err := scenario.ListTailscaleClients("user2")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test that user1 can visit all user2
|
// Test that user1 can visit all user2
|
||||||
for _, client := range user1Clients {
|
for _, client := range user1Clients {
|
||||||
for _, peer := range user2Clients {
|
for _, peer := range user2Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,14 +445,14 @@ func TestACLAllowUserDst(t *testing.T) {
|
||||||
for _, client := range user2Clients {
|
for _, client := range user2Clients {
|
||||||
for _, peer := range user1Clients {
|
for _, peer := range user1Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,23 +477,23 @@ func TestACLAllowStarDst(t *testing.T) {
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
user1Clients, err := scenario.ListTailscaleClients("user1")
|
user1Clients, err := scenario.ListTailscaleClients("user1")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2Clients, err := scenario.ListTailscaleClients("user2")
|
user2Clients, err := scenario.ListTailscaleClients("user2")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test that user1 can visit all user2
|
// Test that user1 can visit all user2
|
||||||
for _, client := range user1Clients {
|
for _, client := range user1Clients {
|
||||||
for _, peer := range user2Clients {
|
for _, peer := range user2Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,14 +501,14 @@ func TestACLAllowStarDst(t *testing.T) {
|
||||||
for _, client := range user2Clients {
|
for _, client := range user2Clients {
|
||||||
for _, peer := range user1Clients {
|
for _, peer := range user1Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,23 +538,23 @@ func TestACLNamedHostsCanReachBySubnet(t *testing.T) {
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
user1Clients, err := scenario.ListTailscaleClients("user1")
|
user1Clients, err := scenario.ListTailscaleClients("user1")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2Clients, err := scenario.ListTailscaleClients("user2")
|
user2Clients, err := scenario.ListTailscaleClients("user2")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test that user1 can visit all user2
|
// Test that user1 can visit all user2
|
||||||
for _, client := range user1Clients {
|
for _, client := range user1Clients {
|
||||||
for _, peer := range user2Clients {
|
for _, peer := range user2Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -561,14 +562,14 @@ func TestACLNamedHostsCanReachBySubnet(t *testing.T) {
|
||||||
for _, client := range user2Clients {
|
for _, client := range user2Clients {
|
||||||
for _, peer := range user1Clients {
|
for _, peer := range user1Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -679,10 +680,10 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test1ip4 := netip.MustParseAddr("100.64.0.1")
|
test1ip4 := netip.MustParseAddr("100.64.0.1")
|
||||||
test1ip6 := netip.MustParseAddr("fd7a:115c:a1e0::1")
|
test1ip6 := netip.MustParseAddr("fd7a:115c:a1e0::1")
|
||||||
test1, err := scenario.FindTailscaleClientByIP(test1ip6)
|
test1, err := scenario.FindTailscaleClientByIP(test1ip6)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
test1fqdn, err := test1.FQDN()
|
test1fqdn, err := test1.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
test1ip4URL := fmt.Sprintf("http://%s/etc/hostname", test1ip4.String())
|
test1ip4URL := fmt.Sprintf("http://%s/etc/hostname", test1ip4.String())
|
||||||
test1ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test1ip6.String())
|
test1ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test1ip6.String())
|
||||||
test1fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test1fqdn)
|
test1fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test1fqdn)
|
||||||
|
@ -690,10 +691,10 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test2ip4 := netip.MustParseAddr("100.64.0.2")
|
test2ip4 := netip.MustParseAddr("100.64.0.2")
|
||||||
test2ip6 := netip.MustParseAddr("fd7a:115c:a1e0::2")
|
test2ip6 := netip.MustParseAddr("fd7a:115c:a1e0::2")
|
||||||
test2, err := scenario.FindTailscaleClientByIP(test2ip6)
|
test2, err := scenario.FindTailscaleClientByIP(test2ip6)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
test2fqdn, err := test2.FQDN()
|
test2fqdn, err := test2.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
test2ip4URL := fmt.Sprintf("http://%s/etc/hostname", test2ip4.String())
|
test2ip4URL := fmt.Sprintf("http://%s/etc/hostname", test2ip4.String())
|
||||||
test2ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test2ip6.String())
|
test2ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test2ip6.String())
|
||||||
test2fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test2fqdn)
|
test2fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test2fqdn)
|
||||||
|
@ -701,10 +702,10 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3ip4 := netip.MustParseAddr("100.64.0.3")
|
test3ip4 := netip.MustParseAddr("100.64.0.3")
|
||||||
test3ip6 := netip.MustParseAddr("fd7a:115c:a1e0::3")
|
test3ip6 := netip.MustParseAddr("fd7a:115c:a1e0::3")
|
||||||
test3, err := scenario.FindTailscaleClientByIP(test3ip6)
|
test3, err := scenario.FindTailscaleClientByIP(test3ip6)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
test3fqdn, err := test3.FQDN()
|
test3fqdn, err := test3.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
test3ip4URL := fmt.Sprintf("http://%s/etc/hostname", test3ip4.String())
|
test3ip4URL := fmt.Sprintf("http://%s/etc/hostname", test3ip4.String())
|
||||||
test3ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test3ip6.String())
|
test3ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test3ip6.String())
|
||||||
test3fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test3fqdn)
|
test3fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test3fqdn)
|
||||||
|
@ -719,7 +720,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3ip4URL,
|
test3ip4URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test1.Curl(test3ip6URL)
|
result, err = test1.Curl(test3ip6URL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -730,7 +731,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3ip6URL,
|
test3ip6URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test1.Curl(test3fqdnURL)
|
result, err = test1.Curl(test3fqdnURL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -741,7 +742,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3fqdnURL,
|
test3fqdnURL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// test2 can query test3
|
// test2 can query test3
|
||||||
result, err = test2.Curl(test3ip4URL)
|
result, err = test2.Curl(test3ip4URL)
|
||||||
|
@ -753,7 +754,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3ip4URL,
|
test3ip4URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test3ip6URL)
|
result, err = test2.Curl(test3ip6URL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -764,7 +765,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3ip6URL,
|
test3ip6URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test3fqdnURL)
|
result, err = test2.Curl(test3fqdnURL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -775,33 +776,33 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test3fqdnURL,
|
test3fqdnURL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// test3 cannot query test1
|
// test3 cannot query test1
|
||||||
result, err = test3.Curl(test1ip4URL)
|
result, err = test3.Curl(test1ip4URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test3.Curl(test1ip6URL)
|
result, err = test3.Curl(test1ip6URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test3.Curl(test1fqdnURL)
|
result, err = test3.Curl(test1fqdnURL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// test3 cannot query test2
|
// test3 cannot query test2
|
||||||
result, err = test3.Curl(test2ip4URL)
|
result, err = test3.Curl(test2ip4URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test3.Curl(test2ip6URL)
|
result, err = test3.Curl(test2ip6URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test3.Curl(test2fqdnURL)
|
result, err = test3.Curl(test2fqdnURL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
// test1 can query test2
|
// test1 can query test2
|
||||||
result, err = test1.Curl(test2ip4URL)
|
result, err = test1.Curl(test2ip4URL)
|
||||||
|
@ -814,7 +815,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
result, err = test1.Curl(test2ip6URL)
|
result, err = test1.Curl(test2ip6URL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
t,
|
t,
|
||||||
|
@ -824,7 +825,7 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test2ip6URL,
|
test2ip6URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test1.Curl(test2fqdnURL)
|
result, err = test1.Curl(test2fqdnURL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -835,20 +836,20 @@ func TestACLNamedHostsCanReach(t *testing.T) {
|
||||||
test2fqdnURL,
|
test2fqdnURL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// test2 cannot query test1
|
// test2 cannot query test1
|
||||||
result, err = test2.Curl(test1ip4URL)
|
result, err = test2.Curl(test1ip4URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test1ip6URL)
|
result, err = test2.Curl(test1ip6URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test1fqdnURL)
|
result, err = test2.Curl(test1fqdnURL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -946,10 +947,10 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
|
||||||
test1ip6 := netip.MustParseAddr("fd7a:115c:a1e0::1")
|
test1ip6 := netip.MustParseAddr("fd7a:115c:a1e0::1")
|
||||||
test1, err := scenario.FindTailscaleClientByIP(test1ip)
|
test1, err := scenario.FindTailscaleClientByIP(test1ip)
|
||||||
assert.NotNil(t, test1)
|
assert.NotNil(t, test1)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
test1fqdn, err := test1.FQDN()
|
test1fqdn, err := test1.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
test1ipURL := fmt.Sprintf("http://%s/etc/hostname", test1ip.String())
|
test1ipURL := fmt.Sprintf("http://%s/etc/hostname", test1ip.String())
|
||||||
test1ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test1ip6.String())
|
test1ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test1ip6.String())
|
||||||
test1fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test1fqdn)
|
test1fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test1fqdn)
|
||||||
|
@ -958,10 +959,10 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
|
||||||
test2ip6 := netip.MustParseAddr("fd7a:115c:a1e0::2")
|
test2ip6 := netip.MustParseAddr("fd7a:115c:a1e0::2")
|
||||||
test2, err := scenario.FindTailscaleClientByIP(test2ip)
|
test2, err := scenario.FindTailscaleClientByIP(test2ip)
|
||||||
assert.NotNil(t, test2)
|
assert.NotNil(t, test2)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
test2fqdn, err := test2.FQDN()
|
test2fqdn, err := test2.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
test2ipURL := fmt.Sprintf("http://%s/etc/hostname", test2ip.String())
|
test2ipURL := fmt.Sprintf("http://%s/etc/hostname", test2ip.String())
|
||||||
test2ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test2ip6.String())
|
test2ip6URL := fmt.Sprintf("http://[%s]/etc/hostname", test2ip6.String())
|
||||||
test2fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test2fqdn)
|
test2fqdnURL := fmt.Sprintf("http://%s/etc/hostname", test2fqdn)
|
||||||
|
@ -976,7 +977,7 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
|
||||||
test2ipURL,
|
test2ipURL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test1.Curl(test2ip6URL)
|
result, err = test1.Curl(test2ip6URL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -987,7 +988,7 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
|
||||||
test2ip6URL,
|
test2ip6URL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test1.Curl(test2fqdnURL)
|
result, err = test1.Curl(test2fqdnURL)
|
||||||
assert.Lenf(
|
assert.Lenf(
|
||||||
|
@ -998,19 +999,19 @@ func TestACLDevice1CanAccessDevice2(t *testing.T) {
|
||||||
test2fqdnURL,
|
test2fqdnURL,
|
||||||
result,
|
result,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test1ipURL)
|
result, err = test2.Curl(test1ipURL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test1ip6URL)
|
result, err = test2.Curl(test1ip6URL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|
||||||
result, err = test2.Curl(test1fqdnURL)
|
result, err = test2.Curl(test1fqdnURL)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1020,7 +1021,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1046,19 +1047,19 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
"HEADSCALE_POLICY_MODE": "database",
|
"HEADSCALE_POLICY_MODE": "database",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = scenario.ListTailscaleClientsFQDNs()
|
_, err = scenario.ListTailscaleClientsFQDNs()
|
||||||
assertNoErrListFQDN(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = scenario.WaitForTailscaleSync()
|
err = scenario.WaitForTailscaleSync()
|
||||||
assertNoErrSync(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user1Clients, err := scenario.ListTailscaleClients("user1")
|
user1Clients, err := scenario.ListTailscaleClients("user1")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
user2Clients, err := scenario.ListTailscaleClients("user2")
|
user2Clients, err := scenario.ListTailscaleClients("user2")
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
all := append(user1Clients, user2Clients...)
|
all := append(user1Clients, user2Clients...)
|
||||||
|
|
||||||
|
@ -1070,19 +1071,19 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
p := policy.ACLPolicy{
|
p := policy.ACLPolicy{
|
||||||
ACLs: []policy.ACL{
|
ACLs: []policy.ACL{
|
||||||
|
@ -1100,7 +1101,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
policyFilePath := "/etc/headscale/policy.json"
|
policyFilePath := "/etc/headscale/policy.json"
|
||||||
|
|
||||||
err = headscale.WriteFile(policyFilePath, pBytes)
|
err = headscale.WriteFile(policyFilePath, pBytes)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// No policy is present at this time.
|
// No policy is present at this time.
|
||||||
// Add a new policy from a file.
|
// Add a new policy from a file.
|
||||||
|
@ -1113,7 +1114,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
policyFilePath,
|
policyFilePath,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Get the current policy and check
|
// Get the current policy and check
|
||||||
// if it is the same as the one we set.
|
// if it is the same as the one we set.
|
||||||
|
@ -1129,7 +1130,7 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
},
|
},
|
||||||
&output,
|
&output,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, output.ACLs, 1)
|
assert.Len(t, output.ACLs, 1)
|
||||||
|
|
||||||
|
@ -1141,14 +1142,14 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
for _, client := range user1Clients {
|
for _, client := range user1Clients {
|
||||||
for _, peer := range user2Clients {
|
for _, peer := range user2Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Len(t, result, 13)
|
assert.Len(t, result, 13)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1156,14 +1157,14 @@ func TestPolicyUpdateWhileRunningWithCLIInDatabase(t *testing.T) {
|
||||||
for _, client := range user2Clients {
|
for _, client := range user2Clients {
|
||||||
for _, peer := range user1Clients {
|
for _, peer := range user1Clients {
|
||||||
fqdn, err := peer.FQDN()
|
fqdn, err := peer.FQDN()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
url := fmt.Sprintf("http://%s/etc/hostname", fqdn)
|
||||||
t.Logf("url from %s to %s", client.Hostname(), url)
|
t.Logf("url from %s to %s", client.Hostname(), url)
|
||||||
|
|
||||||
result, err := client.Curl(url)
|
result, err := client.Curl(url)
|
||||||
assert.Empty(t, result)
|
assert.Empty(t, result)
|
||||||
assert.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/juanfont/headscale/integration/hsic"
|
"github.com/juanfont/headscale/integration/hsic"
|
||||||
"github.com/juanfont/headscale/integration/tsic"
|
"github.com/juanfont/headscale/integration/tsic"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func executeAndUnmarshal[T any](headscale ControlServer, command []string, result T) error {
|
func executeAndUnmarshal[T any](headscale ControlServer, command []string, result T) error {
|
||||||
|
@ -34,7 +35,7 @@ func TestUserCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -43,10 +44,10 @@ func TestUserCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var listUsers []v1.User
|
var listUsers []v1.User
|
||||||
err = executeAndUnmarshal(headscale,
|
err = executeAndUnmarshal(headscale,
|
||||||
|
@ -59,7 +60,7 @@ func TestUserCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listUsers,
|
&listUsers,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result := []string{listUsers[0].GetName(), listUsers[1].GetName()}
|
result := []string{listUsers[0].GetName(), listUsers[1].GetName()}
|
||||||
sort.Strings(result)
|
sort.Strings(result)
|
||||||
|
@ -81,7 +82,7 @@ func TestUserCommand(t *testing.T) {
|
||||||
"newname",
|
"newname",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var listAfterRenameUsers []v1.User
|
var listAfterRenameUsers []v1.User
|
||||||
err = executeAndUnmarshal(headscale,
|
err = executeAndUnmarshal(headscale,
|
||||||
|
@ -94,7 +95,7 @@ func TestUserCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAfterRenameUsers,
|
&listAfterRenameUsers,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result = []string{listAfterRenameUsers[0].GetName(), listAfterRenameUsers[1].GetName()}
|
result = []string{listAfterRenameUsers[0].GetName(), listAfterRenameUsers[1].GetName()}
|
||||||
sort.Strings(result)
|
sort.Strings(result)
|
||||||
|
@ -114,7 +115,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
count := 3
|
count := 3
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -122,13 +123,13 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipak"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipak"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
keys := make([]*v1.PreAuthKey, count)
|
keys := make([]*v1.PreAuthKey, count)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index := 0; index < count; index++ {
|
for index := 0; index < count; index++ {
|
||||||
var preAuthKey v1.PreAuthKey
|
var preAuthKey v1.PreAuthKey
|
||||||
|
@ -150,7 +151,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&preAuthKey,
|
&preAuthKey,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
keys[index] = &preAuthKey
|
keys[index] = &preAuthKey
|
||||||
}
|
}
|
||||||
|
@ -171,7 +172,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedPreAuthKeys,
|
&listedPreAuthKeys,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||||
assert.Len(t, listedPreAuthKeys, 4)
|
assert.Len(t, listedPreAuthKeys, 4)
|
||||||
|
@ -212,7 +213,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, listedPreAuthKeys[index].GetAclTags(), []string{"tag:test1", "tag:test2"})
|
assert.Equal(t, []string{"tag:test1", "tag:test2"}, listedPreAuthKeys[index].GetAclTags())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test key expiry
|
// Test key expiry
|
||||||
|
@ -226,7 +227,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
listedPreAuthKeys[1].GetKey(),
|
listedPreAuthKeys[1].GetKey(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var listedPreAuthKeysAfterExpire []v1.PreAuthKey
|
var listedPreAuthKeysAfterExpire []v1.PreAuthKey
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -242,7 +243,7 @@ func TestPreAuthKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedPreAuthKeysAfterExpire,
|
&listedPreAuthKeysAfterExpire,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, listedPreAuthKeysAfterExpire[1].GetExpiration().AsTime().Before(time.Now()))
|
assert.True(t, listedPreAuthKeysAfterExpire[1].GetExpiration().AsTime().Before(time.Now()))
|
||||||
assert.True(t, listedPreAuthKeysAfterExpire[2].GetExpiration().AsTime().After(time.Now()))
|
assert.True(t, listedPreAuthKeysAfterExpire[2].GetExpiration().AsTime().After(time.Now()))
|
||||||
|
@ -256,7 +257,7 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||||
user := "pre-auth-key-without-exp-user"
|
user := "pre-auth-key-without-exp-user"
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -264,10 +265,10 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipaknaexp"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipaknaexp"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var preAuthKey v1.PreAuthKey
|
var preAuthKey v1.PreAuthKey
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -284,7 +285,7 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||||
},
|
},
|
||||||
&preAuthKey,
|
&preAuthKey,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var listedPreAuthKeys []v1.PreAuthKey
|
var listedPreAuthKeys []v1.PreAuthKey
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -300,7 +301,7 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedPreAuthKeys,
|
&listedPreAuthKeys,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||||
assert.Len(t, listedPreAuthKeys, 2)
|
assert.Len(t, listedPreAuthKeys, 2)
|
||||||
|
@ -319,7 +320,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||||
user := "pre-auth-key-reus-ephm-user"
|
user := "pre-auth-key-reus-ephm-user"
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -327,10 +328,10 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipakresueeph"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipakresueeph"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var preAuthReusableKey v1.PreAuthKey
|
var preAuthReusableKey v1.PreAuthKey
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -347,7 +348,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||||
},
|
},
|
||||||
&preAuthReusableKey,
|
&preAuthReusableKey,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var preAuthEphemeralKey v1.PreAuthKey
|
var preAuthEphemeralKey v1.PreAuthKey
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -364,7 +365,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||||
},
|
},
|
||||||
&preAuthEphemeralKey,
|
&preAuthEphemeralKey,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.True(t, preAuthEphemeralKey.GetEphemeral())
|
assert.True(t, preAuthEphemeralKey.GetEphemeral())
|
||||||
assert.False(t, preAuthEphemeralKey.GetReusable())
|
assert.False(t, preAuthEphemeralKey.GetReusable())
|
||||||
|
@ -383,7 +384,7 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedPreAuthKeys,
|
&listedPreAuthKeys,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// There is one key created by "scenario.CreateHeadscaleEnv"
|
// There is one key created by "scenario.CreateHeadscaleEnv"
|
||||||
assert.Len(t, listedPreAuthKeys, 3)
|
assert.Len(t, listedPreAuthKeys, 3)
|
||||||
|
@ -397,7 +398,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||||
user2 := "user2"
|
user2 := "user2"
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -413,10 +414,10 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||||
hsic.WithTLS(),
|
hsic.WithTLS(),
|
||||||
hsic.WithHostnameAsServerURL(),
|
hsic.WithHostnameAsServerURL(),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var user2Key v1.PreAuthKey
|
var user2Key v1.PreAuthKey
|
||||||
|
|
||||||
|
@ -438,10 +439,10 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&user2Key,
|
&user2Key,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
allClients, err := scenario.ListTailscaleClients()
|
allClients, err := scenario.ListTailscaleClients()
|
||||||
assertNoErrListClients(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, allClients, 1)
|
assert.Len(t, allClients, 1)
|
||||||
|
|
||||||
|
@ -449,22 +450,22 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||||
|
|
||||||
// Log out from user1
|
// Log out from user1
|
||||||
err = client.Logout()
|
err = client.Logout()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = scenario.WaitForTailscaleLogout()
|
err = scenario.WaitForTailscaleLogout()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
status, err := client.Status()
|
status, err := client.Status()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
if status.BackendState == "Starting" || status.BackendState == "Running" {
|
if status.BackendState == "Starting" || status.BackendState == "Running" {
|
||||||
t.Fatalf("expected node to be logged out, backend state: %s", status.BackendState)
|
t.Fatalf("expected node to be logged out, backend state: %s", status.BackendState)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = client.Login(headscale.GetEndpoint(), user2Key.GetKey())
|
err = client.Login(headscale.GetEndpoint(), user2Key.GetKey())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
status, err = client.Status()
|
status, err = client.Status()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
if status.BackendState != "Running" {
|
if status.BackendState != "Running" {
|
||||||
t.Fatalf("expected node to be logged in, backend state: %s", status.BackendState)
|
t.Fatalf("expected node to be logged in, backend state: %s", status.BackendState)
|
||||||
}
|
}
|
||||||
|
@ -485,7 +486,7 @@ func TestPreAuthKeyCorrectUserLoggedInCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listNodes,
|
&listNodes,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, listNodes, 1)
|
assert.Len(t, listNodes, 1)
|
||||||
|
|
||||||
assert.Equal(t, "user2", listNodes[0].GetUser().GetName())
|
assert.Equal(t, "user2", listNodes[0].GetUser().GetName())
|
||||||
|
@ -498,7 +499,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
count := 5
|
count := 5
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -507,10 +508,10 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
keys := make([]string, count)
|
keys := make([]string, count)
|
||||||
|
|
||||||
|
@ -526,7 +527,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotEmpty(t, apiResult)
|
assert.NotEmpty(t, apiResult)
|
||||||
|
|
||||||
keys[idx] = apiResult
|
keys[idx] = apiResult
|
||||||
|
@ -545,7 +546,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedAPIKeys,
|
&listedAPIKeys,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listedAPIKeys, 5)
|
assert.Len(t, listedAPIKeys, 5)
|
||||||
|
|
||||||
|
@ -601,7 +602,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
listedAPIKeys[idx].GetPrefix(),
|
listedAPIKeys[idx].GetPrefix(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expiredPrefixes[listedAPIKeys[idx].GetPrefix()] = true
|
expiredPrefixes[listedAPIKeys[idx].GetPrefix()] = true
|
||||||
}
|
}
|
||||||
|
@ -617,7 +618,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedAfterExpireAPIKeys,
|
&listedAfterExpireAPIKeys,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index := range listedAfterExpireAPIKeys {
|
for index := range listedAfterExpireAPIKeys {
|
||||||
if _, ok := expiredPrefixes[listedAfterExpireAPIKeys[index].GetPrefix()]; ok {
|
if _, ok := expiredPrefixes[listedAfterExpireAPIKeys[index].GetPrefix()]; ok {
|
||||||
|
@ -643,7 +644,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
"--prefix",
|
"--prefix",
|
||||||
listedAPIKeys[0].GetPrefix(),
|
listedAPIKeys[0].GetPrefix(),
|
||||||
})
|
})
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var listedAPIKeysAfterDelete []v1.ApiKey
|
var listedAPIKeysAfterDelete []v1.ApiKey
|
||||||
err = executeAndUnmarshal(headscale,
|
err = executeAndUnmarshal(headscale,
|
||||||
|
@ -656,7 +657,7 @@ func TestApiKeyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listedAPIKeysAfterDelete,
|
&listedAPIKeysAfterDelete,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listedAPIKeysAfterDelete, 4)
|
assert.Len(t, listedAPIKeysAfterDelete, 4)
|
||||||
}
|
}
|
||||||
|
@ -666,7 +667,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -674,17 +675,17 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
"mkey:6abd00bb5fdda622db51387088c68e97e71ce58e7056aa54f592b6a8219d524c",
|
||||||
}
|
}
|
||||||
nodes := make([]*v1.Node, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -702,7 +703,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -720,7 +721,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes[index] = &node
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
@ -739,7 +740,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, []string{"tag:test"}, node.GetForcedTags())
|
assert.Equal(t, []string{"tag:test"}, node.GetForcedTags())
|
||||||
|
|
||||||
|
@ -753,7 +754,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
"--output", "json",
|
"--output", "json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.ErrorContains(t, err, "tag must start with the string 'tag:'")
|
require.ErrorContains(t, err, "tag must start with the string 'tag:'")
|
||||||
|
|
||||||
// Test list all nodes after added seconds
|
// Test list all nodes after added seconds
|
||||||
resultMachines := make([]*v1.Node, len(machineKeys))
|
resultMachines := make([]*v1.Node, len(machineKeys))
|
||||||
|
@ -767,7 +768,7 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&resultMachines,
|
&resultMachines,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
found := false
|
found := false
|
||||||
for _, node := range resultMachines {
|
for _, node := range resultMachines {
|
||||||
if node.GetForcedTags() != nil {
|
if node.GetForcedTags() != nil {
|
||||||
|
@ -778,9 +779,8 @@ func TestNodeTagCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(
|
assert.True(
|
||||||
t,
|
t,
|
||||||
true,
|
|
||||||
found,
|
found,
|
||||||
"should find a node with the tag 'tag:test' in the list of nodes",
|
"should find a node with the tag 'tag:test' in the list of nodes",
|
||||||
)
|
)
|
||||||
|
@ -791,18 +791,22 @@ func TestNodeAdvertiseTagNoACLCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"user1": 1,
|
"user1": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{tsic.WithTags([]string{"tag:test"})}, hsic.WithTestName("cliadvtags"))
|
err = scenario.CreateHeadscaleEnv(
|
||||||
assertNoErr(t, err)
|
spec,
|
||||||
|
[]tsic.Option{tsic.WithTags([]string{"tag:test"})},
|
||||||
|
hsic.WithTestName("cliadvtags"),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test list all nodes after added seconds
|
// Test list all nodes after added seconds
|
||||||
resultMachines := make([]*v1.Node, spec["user1"])
|
resultMachines := make([]*v1.Node, spec["user1"])
|
||||||
|
@ -817,7 +821,7 @@ func TestNodeAdvertiseTagNoACLCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&resultMachines,
|
&resultMachines,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
found := false
|
found := false
|
||||||
for _, node := range resultMachines {
|
for _, node := range resultMachines {
|
||||||
if node.GetInvalidTags() != nil {
|
if node.GetInvalidTags() != nil {
|
||||||
|
@ -828,9 +832,8 @@ func TestNodeAdvertiseTagNoACLCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(
|
assert.True(
|
||||||
t,
|
t,
|
||||||
true,
|
|
||||||
found,
|
found,
|
||||||
"should not find a node with the tag 'tag:test' in the list of nodes",
|
"should not find a node with the tag 'tag:test' in the list of nodes",
|
||||||
)
|
)
|
||||||
|
@ -841,14 +844,18 @@ func TestNodeAdvertiseTagWithACLCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
"user1": 1,
|
"user1": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{tsic.WithTags([]string{"tag:exists"})}, hsic.WithTestName("cliadvtags"), hsic.WithACLPolicy(
|
err = scenario.CreateHeadscaleEnv(
|
||||||
|
spec,
|
||||||
|
[]tsic.Option{tsic.WithTags([]string{"tag:exists"})},
|
||||||
|
hsic.WithTestName("cliadvtags"),
|
||||||
|
hsic.WithACLPolicy(
|
||||||
&policy.ACLPolicy{
|
&policy.ACLPolicy{
|
||||||
ACLs: []policy.ACL{
|
ACLs: []policy.ACL{
|
||||||
{
|
{
|
||||||
|
@ -861,11 +868,12 @@ func TestNodeAdvertiseTagWithACLCommand(t *testing.T) {
|
||||||
"tag:exists": {"user1"},
|
"tag:exists": {"user1"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
))
|
),
|
||||||
assertNoErr(t, err)
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test list all nodes after added seconds
|
// Test list all nodes after added seconds
|
||||||
resultMachines := make([]*v1.Node, spec["user1"])
|
resultMachines := make([]*v1.Node, spec["user1"])
|
||||||
|
@ -880,7 +888,7 @@ func TestNodeAdvertiseTagWithACLCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&resultMachines,
|
&resultMachines,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
found := false
|
found := false
|
||||||
for _, node := range resultMachines {
|
for _, node := range resultMachines {
|
||||||
if node.GetValidTags() != nil {
|
if node.GetValidTags() != nil {
|
||||||
|
@ -891,9 +899,8 @@ func TestNodeAdvertiseTagWithACLCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.Equal(
|
assert.True(
|
||||||
t,
|
t,
|
||||||
true,
|
|
||||||
found,
|
found,
|
||||||
"should not find a node with the tag 'tag:exists' in the list of nodes",
|
"should not find a node with the tag 'tag:exists' in the list of nodes",
|
||||||
)
|
)
|
||||||
|
@ -904,7 +911,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -913,10 +920,10 @@ func TestNodeCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Pregenerated machine keys
|
// Pregenerated machine keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
|
@ -927,7 +934,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
"mkey:cf7b0fd05da556fdc3bab365787b506fd82d64a70745db70e00e86c1b1c03084",
|
||||||
}
|
}
|
||||||
nodes := make([]*v1.Node, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -945,7 +952,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -963,7 +970,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes[index] = &node
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
@ -983,7 +990,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAll,
|
&listAll,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAll, 5)
|
assert.Len(t, listAll, 5)
|
||||||
|
|
||||||
|
@ -1004,7 +1011,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"mkey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
|
"mkey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
|
||||||
}
|
}
|
||||||
otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys))
|
otherUserMachines := make([]*v1.Node, len(otherUserMachineKeys))
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index, machineKey := range otherUserMachineKeys {
|
for index, machineKey := range otherUserMachineKeys {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -1022,7 +1029,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1040,7 +1047,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
otherUserMachines[index] = &node
|
otherUserMachines[index] = &node
|
||||||
}
|
}
|
||||||
|
@ -1060,7 +1067,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAllWithotherUser,
|
&listAllWithotherUser,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// All nodes, nodes + otherUser
|
// All nodes, nodes + otherUser
|
||||||
assert.Len(t, listAllWithotherUser, 7)
|
assert.Len(t, listAllWithotherUser, 7)
|
||||||
|
@ -1086,7 +1093,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listOnlyotherUserMachineUser,
|
&listOnlyotherUserMachineUser,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listOnlyotherUserMachineUser, 2)
|
assert.Len(t, listOnlyotherUserMachineUser, 2)
|
||||||
|
|
||||||
|
@ -1118,7 +1125,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
"--force",
|
"--force",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Test: list main user after node is deleted
|
// Test: list main user after node is deleted
|
||||||
var listOnlyMachineUserAfterDelete []v1.Node
|
var listOnlyMachineUserAfterDelete []v1.Node
|
||||||
|
@ -1135,7 +1142,7 @@ func TestNodeCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listOnlyMachineUserAfterDelete,
|
&listOnlyMachineUserAfterDelete,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listOnlyMachineUserAfterDelete, 4)
|
assert.Len(t, listOnlyMachineUserAfterDelete, 4)
|
||||||
}
|
}
|
||||||
|
@ -1145,7 +1152,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1153,10 +1160,10 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Pregenerated machine keys
|
// Pregenerated machine keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
|
@ -1184,7 +1191,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1202,7 +1209,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes[index] = &node
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1228,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAll,
|
&listAll,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAll, 5)
|
assert.Len(t, listAll, 5)
|
||||||
|
|
||||||
|
@ -1241,7 +1248,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
fmt.Sprintf("%d", listAll[idx].GetId()),
|
fmt.Sprintf("%d", listAll[idx].GetId()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var listAllAfterExpiry []v1.Node
|
var listAllAfterExpiry []v1.Node
|
||||||
|
@ -1256,7 +1263,7 @@ func TestNodeExpireCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAllAfterExpiry,
|
&listAllAfterExpiry,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAllAfterExpiry, 5)
|
assert.Len(t, listAllAfterExpiry, 5)
|
||||||
|
|
||||||
|
@ -1272,7 +1279,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1280,10 +1287,10 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Pregenerated machine keys
|
// Pregenerated machine keys
|
||||||
machineKeys := []string{
|
machineKeys := []string{
|
||||||
|
@ -1294,7 +1301,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
"mkey:9b2ffa7e08cc421a3d2cca9012280f6a236fd0de0b4ce005b30a98ad930306fe",
|
||||||
}
|
}
|
||||||
nodes := make([]*v1.Node, len(machineKeys))
|
nodes := make([]*v1.Node, len(machineKeys))
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for index, machineKey := range machineKeys {
|
for index, machineKey := range machineKeys {
|
||||||
_, err := headscale.Execute(
|
_, err := headscale.Execute(
|
||||||
|
@ -1312,7 +1319,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1330,7 +1337,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
nodes[index] = &node
|
nodes[index] = &node
|
||||||
}
|
}
|
||||||
|
@ -1349,7 +1356,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAll,
|
&listAll,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAll, 5)
|
assert.Len(t, listAll, 5)
|
||||||
|
|
||||||
|
@ -1370,7 +1377,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
fmt.Sprintf("newnode-%d", idx+1),
|
fmt.Sprintf("newnode-%d", idx+1),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Contains(t, res, "Node renamed")
|
assert.Contains(t, res, "Node renamed")
|
||||||
}
|
}
|
||||||
|
@ -1387,7 +1394,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAllAfterRename,
|
&listAllAfterRename,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAllAfterRename, 5)
|
assert.Len(t, listAllAfterRename, 5)
|
||||||
|
|
||||||
|
@ -1408,7 +1415,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
strings.Repeat("t", 64),
|
strings.Repeat("t", 64),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.ErrorContains(t, err, "not be over 63 chars")
|
require.ErrorContains(t, err, "not be over 63 chars")
|
||||||
|
|
||||||
var listAllAfterRenameAttempt []v1.Node
|
var listAllAfterRenameAttempt []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1422,7 +1429,7 @@ func TestNodeRenameCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&listAllAfterRenameAttempt,
|
&listAllAfterRenameAttempt,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, listAllAfterRenameAttempt, 5)
|
assert.Len(t, listAllAfterRenameAttempt, 5)
|
||||||
|
|
||||||
|
@ -1438,7 +1445,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1447,10 +1454,10 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Randomly generated node key
|
// Randomly generated node key
|
||||||
machineKey := "mkey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa"
|
machineKey := "mkey:688411b767663479632d44140f08a9fde87383adc7cdeb518f62ce28a17ef0aa"
|
||||||
|
@ -1470,7 +1477,7 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var node v1.Node
|
var node v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1488,11 +1495,11 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, uint64(1), node.GetId())
|
assert.Equal(t, uint64(1), node.GetId())
|
||||||
assert.Equal(t, "nomad-node", node.GetName())
|
assert.Equal(t, "nomad-node", node.GetName())
|
||||||
assert.Equal(t, node.GetUser().GetName(), "old-user")
|
assert.Equal(t, "old-user", node.GetUser().GetName())
|
||||||
|
|
||||||
nodeID := fmt.Sprintf("%d", node.GetId())
|
nodeID := fmt.Sprintf("%d", node.GetId())
|
||||||
|
|
||||||
|
@ -1511,9 +1518,9 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, node.GetUser().GetName(), "new-user")
|
assert.Equal(t, "new-user", node.GetUser().GetName())
|
||||||
|
|
||||||
var allNodes []v1.Node
|
var allNodes []v1.Node
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
|
@ -1527,13 +1534,13 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&allNodes,
|
&allNodes,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, allNodes, 1)
|
assert.Len(t, allNodes, 1)
|
||||||
|
|
||||||
assert.Equal(t, allNodes[0].GetId(), node.GetId())
|
assert.Equal(t, allNodes[0].GetId(), node.GetId())
|
||||||
assert.Equal(t, allNodes[0].GetUser(), node.GetUser())
|
assert.Equal(t, allNodes[0].GetUser(), node.GetUser())
|
||||||
assert.Equal(t, allNodes[0].GetUser().GetName(), "new-user")
|
assert.Equal(t, "new-user", allNodes[0].GetUser().GetName())
|
||||||
|
|
||||||
_, err = headscale.Execute(
|
_, err = headscale.Execute(
|
||||||
[]string{
|
[]string{
|
||||||
|
@ -1548,12 +1555,12 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.ErrorContains(
|
require.ErrorContains(
|
||||||
t,
|
t,
|
||||||
err,
|
err,
|
||||||
"user not found",
|
"user not found",
|
||||||
)
|
)
|
||||||
assert.Equal(t, node.GetUser().GetName(), "new-user")
|
assert.Equal(t, "new-user", node.GetUser().GetName())
|
||||||
|
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
|
@ -1570,9 +1577,9 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, node.GetUser().GetName(), "old-user")
|
assert.Equal(t, "old-user", node.GetUser().GetName())
|
||||||
|
|
||||||
err = executeAndUnmarshal(
|
err = executeAndUnmarshal(
|
||||||
headscale,
|
headscale,
|
||||||
|
@ -1589,9 +1596,9 @@ func TestNodeMoveCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Equal(t, node.GetUser().GetName(), "old-user")
|
assert.Equal(t, "old-user", node.GetUser().GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPolicyCommand(t *testing.T) {
|
func TestPolicyCommand(t *testing.T) {
|
||||||
|
@ -1599,7 +1606,7 @@ func TestPolicyCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1614,10 +1621,10 @@ func TestPolicyCommand(t *testing.T) {
|
||||||
"HEADSCALE_POLICY_MODE": "database",
|
"HEADSCALE_POLICY_MODE": "database",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
p := policy.ACLPolicy{
|
p := policy.ACLPolicy{
|
||||||
ACLs: []policy.ACL{
|
ACLs: []policy.ACL{
|
||||||
|
@ -1637,7 +1644,7 @@ func TestPolicyCommand(t *testing.T) {
|
||||||
policyFilePath := "/etc/headscale/policy.json"
|
policyFilePath := "/etc/headscale/policy.json"
|
||||||
|
|
||||||
err = headscale.WriteFile(policyFilePath, pBytes)
|
err = headscale.WriteFile(policyFilePath, pBytes)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// No policy is present at this time.
|
// No policy is present at this time.
|
||||||
// Add a new policy from a file.
|
// Add a new policy from a file.
|
||||||
|
@ -1651,7 +1658,7 @@ func TestPolicyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Get the current policy and check
|
// Get the current policy and check
|
||||||
// if it is the same as the one we set.
|
// if it is the same as the one we set.
|
||||||
|
@ -1667,11 +1674,11 @@ func TestPolicyCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
&output,
|
&output,
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
assert.Len(t, output.TagOwners, 1)
|
assert.Len(t, output.TagOwners, 1)
|
||||||
assert.Len(t, output.ACLs, 1)
|
assert.Len(t, output.ACLs, 1)
|
||||||
assert.Equal(t, output.TagOwners["tag:exists"], []string{"policy-user"})
|
assert.Equal(t, []string{"policy-user"}, output.TagOwners["tag:exists"])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPolicyBrokenConfigCommand(t *testing.T) {
|
func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
|
@ -1679,7 +1686,7 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
scenario, err := NewScenario(dockertestMaxWait())
|
scenario, err := NewScenario(dockertestMaxWait())
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
defer scenario.ShutdownAssertNoPanics(t)
|
defer scenario.ShutdownAssertNoPanics(t)
|
||||||
|
|
||||||
spec := map[string]int{
|
spec := map[string]int{
|
||||||
|
@ -1694,10 +1701,10 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
"HEADSCALE_POLICY_MODE": "database",
|
"HEADSCALE_POLICY_MODE": "database",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
headscale, err := scenario.Headscale()
|
headscale, err := scenario.Headscale()
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
p := policy.ACLPolicy{
|
p := policy.ACLPolicy{
|
||||||
ACLs: []policy.ACL{
|
ACLs: []policy.ACL{
|
||||||
|
@ -1719,7 +1726,7 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
policyFilePath := "/etc/headscale/policy.json"
|
policyFilePath := "/etc/headscale/policy.json"
|
||||||
|
|
||||||
err = headscale.WriteFile(policyFilePath, pBytes)
|
err = headscale.WriteFile(policyFilePath, pBytes)
|
||||||
assertNoErr(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// No policy is present at this time.
|
// No policy is present at this time.
|
||||||
// Add a new policy from a file.
|
// Add a new policy from a file.
|
||||||
|
@ -1732,7 +1739,7 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
policyFilePath,
|
policyFilePath,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.ErrorContains(t, err, "verifying policy rules: invalid action")
|
require.ErrorContains(t, err, "verifying policy rules: invalid action")
|
||||||
|
|
||||||
// The new policy was invalid, the old one should still be in place, which
|
// The new policy was invalid, the old one should still be in place, which
|
||||||
// is none.
|
// is none.
|
||||||
|
@ -1745,5 +1752,5 @@ func TestPolicyBrokenConfigCommand(t *testing.T) {
|
||||||
"json",
|
"json",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.ErrorContains(t, err, "acl policy not found")
|
require.ErrorContains(t, err, "acl policy not found")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"tailscale.com/client/tailscale/apitype"
|
"tailscale.com/client/tailscale/apitype"
|
||||||
"tailscale.com/types/key"
|
"tailscale.com/types/key"
|
||||||
|
@ -244,7 +245,11 @@ func TestEphemeral(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEphemeralInAlternateTimezone(t *testing.T) {
|
func TestEphemeralInAlternateTimezone(t *testing.T) {
|
||||||
testEphemeralWithOptions(t, hsic.WithTestName("ephemeral-tz"), hsic.WithTimezone("America/Los_Angeles"))
|
testEphemeralWithOptions(
|
||||||
|
t,
|
||||||
|
hsic.WithTestName("ephemeral-tz"),
|
||||||
|
hsic.WithTimezone("America/Los_Angeles"),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testEphemeralWithOptions(t *testing.T, opts ...hsic.Option) {
|
func testEphemeralWithOptions(t *testing.T, opts ...hsic.Option) {
|
||||||
|
@ -1164,10 +1169,10 @@ func Test2118DeletingOnlineNodePanics(t *testing.T) {
|
||||||
},
|
},
|
||||||
&nodeList,
|
&nodeList,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, nodeList, 2)
|
assert.Len(t, nodeList, 2)
|
||||||
assert.True(t, nodeList[0].Online)
|
assert.True(t, nodeList[0].GetOnline())
|
||||||
assert.True(t, nodeList[1].Online)
|
assert.True(t, nodeList[1].GetOnline())
|
||||||
|
|
||||||
// Delete the first node, which is online
|
// Delete the first node, which is online
|
||||||
_, err = headscale.Execute(
|
_, err = headscale.Execute(
|
||||||
|
@ -1177,13 +1182,13 @@ func Test2118DeletingOnlineNodePanics(t *testing.T) {
|
||||||
"delete",
|
"delete",
|
||||||
"--identifier",
|
"--identifier",
|
||||||
// Delete the last added machine
|
// Delete the last added machine
|
||||||
fmt.Sprintf("%d", nodeList[0].Id),
|
fmt.Sprintf("%d", nodeList[0].GetId()),
|
||||||
"--output",
|
"--output",
|
||||||
"json",
|
"json",
|
||||||
"--force",
|
"--force",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
@ -1200,9 +1205,8 @@ func Test2118DeletingOnlineNodePanics(t *testing.T) {
|
||||||
},
|
},
|
||||||
&nodeListAfter,
|
&nodeListAfter,
|
||||||
)
|
)
|
||||||
assert.Nil(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, nodeListAfter, 1)
|
assert.Len(t, nodeListAfter, 1)
|
||||||
assert.True(t, nodeListAfter[0].Online)
|
assert.True(t, nodeListAfter[0].GetOnline())
|
||||||
assert.Equal(t, nodeList[1].Id, nodeListAfter[0].Id)
|
assert.Equal(t, nodeList[1].GetId(), nodeListAfter[0].GetId())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,9 @@ func TestEnablingRoutes(t *testing.T) {
|
||||||
assert.Len(t, routes, 3)
|
assert.Len(t, routes, 3)
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
assert.Equal(t, true, route.GetAdvertised())
|
assert.True(t, route.GetAdvertised())
|
||||||
assert.Equal(t, false, route.GetEnabled())
|
assert.False(t, route.GetEnabled())
|
||||||
assert.Equal(t, false, route.GetIsPrimary())
|
assert.False(t, route.GetIsPrimary())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that no routes has been sent to the client,
|
// Verify that no routes has been sent to the client,
|
||||||
|
@ -139,9 +139,9 @@ func TestEnablingRoutes(t *testing.T) {
|
||||||
assert.Len(t, enablingRoutes, 3)
|
assert.Len(t, enablingRoutes, 3)
|
||||||
|
|
||||||
for _, route := range enablingRoutes {
|
for _, route := range enablingRoutes {
|
||||||
assert.Equal(t, true, route.GetAdvertised())
|
assert.True(t, route.GetAdvertised())
|
||||||
assert.Equal(t, true, route.GetEnabled())
|
assert.True(t, route.GetEnabled())
|
||||||
assert.Equal(t, true, route.GetIsPrimary())
|
assert.True(t, route.GetIsPrimary())
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
@ -212,18 +212,18 @@ func TestEnablingRoutes(t *testing.T) {
|
||||||
assertNoErr(t, err)
|
assertNoErr(t, err)
|
||||||
|
|
||||||
for _, route := range disablingRoutes {
|
for _, route := range disablingRoutes {
|
||||||
assert.Equal(t, true, route.GetAdvertised())
|
assert.True(t, route.GetAdvertised())
|
||||||
|
|
||||||
if route.GetId() == routeToBeDisabled.GetId() {
|
if route.GetId() == routeToBeDisabled.GetId() {
|
||||||
assert.Equal(t, false, route.GetEnabled())
|
assert.False(t, route.GetEnabled())
|
||||||
|
|
||||||
// since this is the only route of this cidr,
|
// since this is the only route of this cidr,
|
||||||
// it will not failover, and remain Primary
|
// it will not failover, and remain Primary
|
||||||
// until something can replace it.
|
// until something can replace it.
|
||||||
assert.Equal(t, true, route.GetIsPrimary())
|
assert.True(t, route.GetIsPrimary())
|
||||||
} else {
|
} else {
|
||||||
assert.Equal(t, true, route.GetEnabled())
|
assert.True(t, route.GetEnabled())
|
||||||
assert.Equal(t, true, route.GetIsPrimary())
|
assert.True(t, route.GetIsPrimary())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,9 +342,9 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
t.Logf("initial routes %#v", routes)
|
t.Logf("initial routes %#v", routes)
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
assert.Equal(t, true, route.GetAdvertised())
|
assert.True(t, route.GetAdvertised())
|
||||||
assert.Equal(t, false, route.GetEnabled())
|
assert.False(t, route.GetEnabled())
|
||||||
assert.Equal(t, false, route.GetIsPrimary())
|
assert.False(t, route.GetIsPrimary())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that no routes has been sent to the client,
|
// Verify that no routes has been sent to the client,
|
||||||
|
@ -391,14 +391,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, enablingRoutes, 2)
|
assert.Len(t, enablingRoutes, 2)
|
||||||
|
|
||||||
// Node 1 is primary
|
// Node 1 is primary
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetAdvertised())
|
assert.True(t, enablingRoutes[0].GetAdvertised())
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetEnabled())
|
assert.True(t, enablingRoutes[0].GetEnabled())
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetIsPrimary(), "both subnet routers are up, expected r1 to be primary")
|
assert.True(t, enablingRoutes[0].GetIsPrimary(), "both subnet routers are up, expected r1 to be primary")
|
||||||
|
|
||||||
// Node 2 is not primary
|
// Node 2 is not primary
|
||||||
assert.Equal(t, true, enablingRoutes[1].GetAdvertised())
|
assert.True(t, enablingRoutes[1].GetAdvertised())
|
||||||
assert.Equal(t, true, enablingRoutes[1].GetEnabled())
|
assert.True(t, enablingRoutes[1].GetEnabled())
|
||||||
assert.Equal(t, false, enablingRoutes[1].GetIsPrimary(), "both subnet routers are up, expected r2 to be non-primary")
|
assert.False(t, enablingRoutes[1].GetIsPrimary(), "both subnet routers are up, expected r2 to be non-primary")
|
||||||
|
|
||||||
// Verify that the client has routes from the primary machine
|
// Verify that the client has routes from the primary machine
|
||||||
srs1, err := subRouter1.Status()
|
srs1, err := subRouter1.Status()
|
||||||
|
@ -446,14 +446,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, routesAfterMove, 2)
|
assert.Len(t, routesAfterMove, 2)
|
||||||
|
|
||||||
// Node 1 is not primary
|
// Node 1 is not primary
|
||||||
assert.Equal(t, true, routesAfterMove[0].GetAdvertised())
|
assert.True(t, routesAfterMove[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterMove[0].GetEnabled())
|
assert.True(t, routesAfterMove[0].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfterMove[0].GetIsPrimary(), "r1 is down, expected r2 to be primary")
|
assert.False(t, routesAfterMove[0].GetIsPrimary(), "r1 is down, expected r2 to be primary")
|
||||||
|
|
||||||
// Node 2 is primary
|
// Node 2 is primary
|
||||||
assert.Equal(t, true, routesAfterMove[1].GetAdvertised())
|
assert.True(t, routesAfterMove[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterMove[1].GetEnabled())
|
assert.True(t, routesAfterMove[1].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfterMove[1].GetIsPrimary(), "r1 is down, expected r2 to be primary")
|
assert.True(t, routesAfterMove[1].GetIsPrimary(), "r1 is down, expected r2 to be primary")
|
||||||
|
|
||||||
srs2, err = subRouter2.Status()
|
srs2, err = subRouter2.Status()
|
||||||
|
|
||||||
|
@ -501,16 +501,16 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, routesAfterBothDown, 2)
|
assert.Len(t, routesAfterBothDown, 2)
|
||||||
|
|
||||||
// Node 1 is not primary
|
// Node 1 is not primary
|
||||||
assert.Equal(t, true, routesAfterBothDown[0].GetAdvertised())
|
assert.True(t, routesAfterBothDown[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterBothDown[0].GetEnabled())
|
assert.True(t, routesAfterBothDown[0].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfterBothDown[0].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary")
|
assert.False(t, routesAfterBothDown[0].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary")
|
||||||
|
|
||||||
// Node 2 is primary
|
// Node 2 is primary
|
||||||
// if the node goes down, but no other suitable route is
|
// if the node goes down, but no other suitable route is
|
||||||
// available, keep the last known good route.
|
// available, keep the last known good route.
|
||||||
assert.Equal(t, true, routesAfterBothDown[1].GetAdvertised())
|
assert.True(t, routesAfterBothDown[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterBothDown[1].GetEnabled())
|
assert.True(t, routesAfterBothDown[1].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfterBothDown[1].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary")
|
assert.True(t, routesAfterBothDown[1].GetIsPrimary(), "r1 and r2 is down, expected r2 to _still_ be primary")
|
||||||
|
|
||||||
// TODO(kradalby): Check client status
|
// TODO(kradalby): Check client status
|
||||||
// Both are expected to be down
|
// Both are expected to be down
|
||||||
|
@ -560,14 +560,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, routesAfter1Up, 2)
|
assert.Len(t, routesAfter1Up, 2)
|
||||||
|
|
||||||
// Node 1 is primary
|
// Node 1 is primary
|
||||||
assert.Equal(t, true, routesAfter1Up[0].GetAdvertised())
|
assert.True(t, routesAfter1Up[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfter1Up[0].GetEnabled())
|
assert.True(t, routesAfter1Up[0].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfter1Up[0].GetIsPrimary(), "r1 is back up, expected r1 to become be primary")
|
assert.True(t, routesAfter1Up[0].GetIsPrimary(), "r1 is back up, expected r1 to become be primary")
|
||||||
|
|
||||||
// Node 2 is not primary
|
// Node 2 is not primary
|
||||||
assert.Equal(t, true, routesAfter1Up[1].GetAdvertised())
|
assert.True(t, routesAfter1Up[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfter1Up[1].GetEnabled())
|
assert.True(t, routesAfter1Up[1].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfter1Up[1].GetIsPrimary(), "r1 is back up, expected r1 to become be primary")
|
assert.False(t, routesAfter1Up[1].GetIsPrimary(), "r1 is back up, expected r1 to become be primary")
|
||||||
|
|
||||||
// Verify that the route is announced from subnet router 1
|
// Verify that the route is announced from subnet router 1
|
||||||
clientStatus, err = client.Status()
|
clientStatus, err = client.Status()
|
||||||
|
@ -614,14 +614,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, routesAfter2Up, 2)
|
assert.Len(t, routesAfter2Up, 2)
|
||||||
|
|
||||||
// Node 1 is not primary
|
// Node 1 is not primary
|
||||||
assert.Equal(t, true, routesAfter2Up[0].GetAdvertised())
|
assert.True(t, routesAfter2Up[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfter2Up[0].GetEnabled())
|
assert.True(t, routesAfter2Up[0].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfter2Up[0].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary")
|
assert.True(t, routesAfter2Up[0].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary")
|
||||||
|
|
||||||
// Node 2 is primary
|
// Node 2 is primary
|
||||||
assert.Equal(t, true, routesAfter2Up[1].GetAdvertised())
|
assert.True(t, routesAfter2Up[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfter2Up[1].GetEnabled())
|
assert.True(t, routesAfter2Up[1].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfter2Up[1].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary")
|
assert.False(t, routesAfter2Up[1].GetIsPrimary(), "r1 and r2 is back up, expected r1 to _still_ be primary")
|
||||||
|
|
||||||
// Verify that the route is announced from subnet router 1
|
// Verify that the route is announced from subnet router 1
|
||||||
clientStatus, err = client.Status()
|
clientStatus, err = client.Status()
|
||||||
|
@ -677,14 +677,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
t.Logf("routes after disabling r1 %#v", routesAfterDisabling1)
|
t.Logf("routes after disabling r1 %#v", routesAfterDisabling1)
|
||||||
|
|
||||||
// Node 1 is not primary
|
// Node 1 is not primary
|
||||||
assert.Equal(t, true, routesAfterDisabling1[0].GetAdvertised())
|
assert.True(t, routesAfterDisabling1[0].GetAdvertised())
|
||||||
assert.Equal(t, false, routesAfterDisabling1[0].GetEnabled())
|
assert.False(t, routesAfterDisabling1[0].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfterDisabling1[0].GetIsPrimary())
|
assert.False(t, routesAfterDisabling1[0].GetIsPrimary())
|
||||||
|
|
||||||
// Node 2 is primary
|
// Node 2 is primary
|
||||||
assert.Equal(t, true, routesAfterDisabling1[1].GetAdvertised())
|
assert.True(t, routesAfterDisabling1[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterDisabling1[1].GetEnabled())
|
assert.True(t, routesAfterDisabling1[1].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfterDisabling1[1].GetIsPrimary())
|
assert.True(t, routesAfterDisabling1[1].GetIsPrimary())
|
||||||
|
|
||||||
// Verify that the route is announced from subnet router 1
|
// Verify that the route is announced from subnet router 1
|
||||||
clientStatus, err = client.Status()
|
clientStatus, err = client.Status()
|
||||||
|
@ -735,14 +735,14 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
assert.Len(t, routesAfterEnabling1, 2)
|
assert.Len(t, routesAfterEnabling1, 2)
|
||||||
|
|
||||||
// Node 1 is not primary
|
// Node 1 is not primary
|
||||||
assert.Equal(t, true, routesAfterEnabling1[0].GetAdvertised())
|
assert.True(t, routesAfterEnabling1[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterEnabling1[0].GetEnabled())
|
assert.True(t, routesAfterEnabling1[0].GetEnabled())
|
||||||
assert.Equal(t, false, routesAfterEnabling1[0].GetIsPrimary())
|
assert.False(t, routesAfterEnabling1[0].GetIsPrimary())
|
||||||
|
|
||||||
// Node 2 is primary
|
// Node 2 is primary
|
||||||
assert.Equal(t, true, routesAfterEnabling1[1].GetAdvertised())
|
assert.True(t, routesAfterEnabling1[1].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterEnabling1[1].GetEnabled())
|
assert.True(t, routesAfterEnabling1[1].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfterEnabling1[1].GetIsPrimary())
|
assert.True(t, routesAfterEnabling1[1].GetIsPrimary())
|
||||||
|
|
||||||
// Verify that the route is announced from subnet router 1
|
// Verify that the route is announced from subnet router 1
|
||||||
clientStatus, err = client.Status()
|
clientStatus, err = client.Status()
|
||||||
|
@ -795,9 +795,9 @@ func TestHASubnetRouterFailover(t *testing.T) {
|
||||||
t.Logf("routes after deleting r2 %#v", routesAfterDeleting2)
|
t.Logf("routes after deleting r2 %#v", routesAfterDeleting2)
|
||||||
|
|
||||||
// Node 1 is primary
|
// Node 1 is primary
|
||||||
assert.Equal(t, true, routesAfterDeleting2[0].GetAdvertised())
|
assert.True(t, routesAfterDeleting2[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routesAfterDeleting2[0].GetEnabled())
|
assert.True(t, routesAfterDeleting2[0].GetEnabled())
|
||||||
assert.Equal(t, true, routesAfterDeleting2[0].GetIsPrimary())
|
assert.True(t, routesAfterDeleting2[0].GetIsPrimary())
|
||||||
|
|
||||||
// Verify that the route is announced from subnet router 1
|
// Verify that the route is announced from subnet router 1
|
||||||
clientStatus, err = client.Status()
|
clientStatus, err = client.Status()
|
||||||
|
@ -893,9 +893,9 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) {
|
||||||
assert.Len(t, routes, 1)
|
assert.Len(t, routes, 1)
|
||||||
|
|
||||||
// All routes should be auto approved and enabled
|
// All routes should be auto approved and enabled
|
||||||
assert.Equal(t, true, routes[0].GetAdvertised())
|
assert.True(t, routes[0].GetAdvertised())
|
||||||
assert.Equal(t, true, routes[0].GetEnabled())
|
assert.True(t, routes[0].GetEnabled())
|
||||||
assert.Equal(t, true, routes[0].GetIsPrimary())
|
assert.True(t, routes[0].GetIsPrimary())
|
||||||
|
|
||||||
// Stop advertising route
|
// Stop advertising route
|
||||||
command = []string{
|
command = []string{
|
||||||
|
@ -924,9 +924,9 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) {
|
||||||
assert.Len(t, notAdvertisedRoutes, 1)
|
assert.Len(t, notAdvertisedRoutes, 1)
|
||||||
|
|
||||||
// Route is no longer advertised
|
// Route is no longer advertised
|
||||||
assert.Equal(t, false, notAdvertisedRoutes[0].GetAdvertised())
|
assert.False(t, notAdvertisedRoutes[0].GetAdvertised())
|
||||||
assert.Equal(t, false, notAdvertisedRoutes[0].GetEnabled())
|
assert.False(t, notAdvertisedRoutes[0].GetEnabled())
|
||||||
assert.Equal(t, true, notAdvertisedRoutes[0].GetIsPrimary())
|
assert.True(t, notAdvertisedRoutes[0].GetIsPrimary())
|
||||||
|
|
||||||
// Advertise route again
|
// Advertise route again
|
||||||
command = []string{
|
command = []string{
|
||||||
|
@ -955,9 +955,9 @@ func TestEnableDisableAutoApprovedRoute(t *testing.T) {
|
||||||
assert.Len(t, reAdvertisedRoutes, 1)
|
assert.Len(t, reAdvertisedRoutes, 1)
|
||||||
|
|
||||||
// All routes should be auto approved and enabled
|
// All routes should be auto approved and enabled
|
||||||
assert.Equal(t, true, reAdvertisedRoutes[0].GetAdvertised())
|
assert.True(t, reAdvertisedRoutes[0].GetAdvertised())
|
||||||
assert.Equal(t, true, reAdvertisedRoutes[0].GetEnabled())
|
assert.True(t, reAdvertisedRoutes[0].GetEnabled())
|
||||||
assert.Equal(t, true, reAdvertisedRoutes[0].GetIsPrimary())
|
assert.True(t, reAdvertisedRoutes[0].GetIsPrimary())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAutoApprovedSubRoute2068(t *testing.T) {
|
func TestAutoApprovedSubRoute2068(t *testing.T) {
|
||||||
|
@ -1163,9 +1163,9 @@ func TestSubnetRouteACL(t *testing.T) {
|
||||||
assert.Len(t, routes, 1)
|
assert.Len(t, routes, 1)
|
||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
assert.Equal(t, true, route.GetAdvertised())
|
assert.True(t, route.GetAdvertised())
|
||||||
assert.Equal(t, false, route.GetEnabled())
|
assert.False(t, route.GetEnabled())
|
||||||
assert.Equal(t, false, route.GetIsPrimary())
|
assert.False(t, route.GetIsPrimary())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that no routes has been sent to the client,
|
// Verify that no routes has been sent to the client,
|
||||||
|
@ -1212,9 +1212,9 @@ func TestSubnetRouteACL(t *testing.T) {
|
||||||
assert.Len(t, enablingRoutes, 1)
|
assert.Len(t, enablingRoutes, 1)
|
||||||
|
|
||||||
// Node 1 has active route
|
// Node 1 has active route
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetAdvertised())
|
assert.True(t, enablingRoutes[0].GetAdvertised())
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetEnabled())
|
assert.True(t, enablingRoutes[0].GetEnabled())
|
||||||
assert.Equal(t, true, enablingRoutes[0].GetIsPrimary())
|
assert.True(t, enablingRoutes[0].GetIsPrimary())
|
||||||
|
|
||||||
// Verify that the client has routes from the primary machine
|
// Verify that the client has routes from the primary machine
|
||||||
srs1, _ := subRouter1.Status()
|
srs1, _ := subRouter1.Status()
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/puzpuzpuz/xsync/v3"
|
"github.com/puzpuzpuz/xsync/v3"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"tailscale.com/envknob"
|
"tailscale.com/envknob"
|
||||||
)
|
)
|
||||||
|
@ -205,11 +206,11 @@ func (s *Scenario) ShutdownAssertNoPanics(t *testing.T) {
|
||||||
|
|
||||||
if t != nil {
|
if t != nil {
|
||||||
stdout, err := os.ReadFile(stdoutPath)
|
stdout, err := os.ReadFile(stdoutPath)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotContains(t, string(stdout), "panic")
|
assert.NotContains(t, string(stdout), "panic")
|
||||||
|
|
||||||
stderr, err := os.ReadFile(stderrPath)
|
stderr, err := os.ReadFile(stderrPath)
|
||||||
assert.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NotContains(t, string(stderr), "panic")
|
assert.NotContains(t, string(stderr), "panic")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
---
|
||||||
site_name: Headscale
|
site_name: Headscale
|
||||||
site_url: https://juanfont.github.io/headscale
|
site_url: https://juanfont.github.io/headscale/
|
||||||
edit_uri: blob/main/docs/ # Change the master branch to main as we are using main as a main branch
|
edit_uri: blob/main/docs/ # Change the master branch to main as we are using main as a main branch
|
||||||
site_author: Headscale authors
|
site_author: Headscale authors
|
||||||
site_description: >-
|
site_description: >-
|
||||||
|
|
Loading…
Reference in a new issue