Rename [Nn]amespace -> [Uu]ser in go code

Use gopls, ag and perl to rename all occurances of Namespace

Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
Kristoffer Dalby 2023-01-17 17:43:44 +01:00 committed by Juan Font
parent bafb6791d3
commit e3a2593344
37 changed files with 1130 additions and 1130 deletions

36
acls.go
View file

@ -424,7 +424,7 @@ func parseProtocol(protocol string) ([]int, bool, error) {
}
// expandalias has an input of either
// - a namespace
// - a user
// - a group
// - a tag
// and transform these in IPAddresses.
@ -444,12 +444,12 @@ func expandAlias(
Msg("Expanding")
if strings.HasPrefix(alias, "group:") {
namespaces, err := expandGroup(aclPolicy, alias, stripEmailDomain)
users, err := expandGroup(aclPolicy, alias, stripEmailDomain)
if err != nil {
return ips, err
}
for _, n := range namespaces {
nodes := filterMachinesByNamespace(machines, n)
for _, n := range users {
nodes := filterMachinesByUser(machines, n)
for _, node := range nodes {
ips = append(ips, node.IPAddresses.ToStringSlice()...)
}
@ -485,8 +485,8 @@ func expandAlias(
}
// filter out machines per tag owner
for _, namespace := range owners {
machines := filterMachinesByNamespace(machines, namespace)
for _, user := range owners {
machines := filterMachinesByUser(machines, user)
for _, machine := range machines {
hi := machine.GetHostInfo()
if contains(hi.RequestTags, alias) {
@ -498,8 +498,8 @@ func expandAlias(
return ips, nil
}
// if alias is a namespace
nodes := filterMachinesByNamespace(machines, alias)
// if alias is a user
nodes := filterMachinesByUser(machines, alias)
nodes = excludeCorrectlyTaggedNodes(aclPolicy, nodes, alias, stripEmailDomain)
for _, n := range nodes {
@ -532,20 +532,20 @@ func expandAlias(
}
// excludeCorrectlyTaggedNodes will remove from the list of input nodes the ones
// that are correctly tagged since they should not be listed as being in the namespace
// we assume in this function that we only have nodes from 1 namespace.
// that are correctly tagged since they should not be listed as being in the user
// we assume in this function that we only have nodes from 1 user.
func excludeCorrectlyTaggedNodes(
aclPolicy ACLPolicy,
nodes []Machine,
namespace string,
user string,
stripEmailDomain bool,
) []Machine {
out := []Machine{}
tags := []string{}
for tag := range aclPolicy.TagOwners {
owners, _ := expandTagOwners(aclPolicy, namespace, stripEmailDomain)
ns := append(owners, namespace)
if contains(ns, namespace) {
owners, _ := expandTagOwners(aclPolicy, user, stripEmailDomain)
ns := append(owners, user)
if contains(ns, user) {
tags = append(tags, tag)
}
}
@ -619,10 +619,10 @@ func expandPorts(portsStr string, needsWildcard bool) (*[]tailcfg.PortRange, err
return &ports, nil
}
func filterMachinesByNamespace(machines []Machine, namespace string) []Machine {
func filterMachinesByUser(machines []Machine, user string) []Machine {
out := []Machine{}
for _, machine := range machines {
if machine.Namespace.Name == namespace {
if machine.User.Name == user {
out = append(out, machine)
}
}
@ -630,7 +630,7 @@ func filterMachinesByNamespace(machines []Machine, namespace string) []Machine {
return out
}
// expandTagOwners will return a list of namespace. An owner can be either a namespace or a group
// expandTagOwners will return a list of user. An owner can be either a user or a group
// a group cannot be composed of groups.
func expandTagOwners(
aclPolicy ACLPolicy,
@ -661,7 +661,7 @@ func expandTagOwners(
return owners, nil
}
// expandGroup will return the list of namespace inside the group
// expandGroup will return the list of user inside the group
// after some validation.
func expandGroup(
aclPolicy ACLPolicy,

View file

@ -77,10 +77,10 @@ func (s *Suite) TestInvalidAction(c *check.C) {
func (s *Suite) TestSshRules(c *check.C) {
envknob.Setenv("HEADSCALE_EXPERIMENTAL_FEATURE_SSH", "1")
namespace, err := app.CreateNamespace("user1")
user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
@ -98,7 +98,7 @@ func (s *Suite) TestSshRules(c *check.C) {
DiscoKey: "faa",
Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -187,10 +187,10 @@ func (s *Suite) TestInvalidTagOwners(c *check.C) {
// match properly the IP's of the related hosts. The owner is valid and the tag is also valid.
// the tag is matched in the Sources section.
func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
namespace, err := app.CreateNamespace("user1")
user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
@ -208,7 +208,7 @@ func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
DiscoKey: "faa",
Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -237,10 +237,10 @@ func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
// match properly the IP's of the related hosts. The owner is valid and the tag is also valid.
// the tag is matched in the Destinations section.
func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
namespace, err := app.CreateNamespace("user1")
user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
@ -258,7 +258,7 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
DiscoKey: "faa",
Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -284,13 +284,13 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
}
// need a test with:
// tag on a host that isn't owned by a tag owners. So the namespace
// tag on a host that isn't owned by a tag owners. So the user
// of the host should be valid.
func (s *Suite) TestInvalidTagValidNamespace(c *check.C) {
namespace, err := app.CreateNamespace("user1")
func (s *Suite) TestInvalidTagValidUser(c *check.C) {
user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine")
@ -308,7 +308,7 @@ func (s *Suite) TestInvalidTagValidNamespace(c *check.C) {
DiscoKey: "faa",
Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -333,13 +333,13 @@ func (s *Suite) TestInvalidTagValidNamespace(c *check.C) {
}
// tag on a host is owned by a tag owner, the tag is valid.
// an ACL rule is matching the tag to a namespace. It should not be valid since the
// an ACL rule is matching the tag to a user. It should not be valid since the
// host should be tied to the tag now.
func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
namespace, err := app.CreateNamespace("user1")
func (s *Suite) TestValidTagInvalidUser(c *check.C) {
user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "webserver")
@ -357,7 +357,7 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
DiscoKey: "faa",
Hostname: "webserver",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -376,7 +376,7 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
DiscoKey: "faab",
Hostname: "user",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo2),
@ -467,14 +467,14 @@ func (s *Suite) TestPortWildcardYAML(c *check.C) {
c.Assert(rules[0].SrcIPs[0], check.Equals, "*")
}
func (s *Suite) TestPortNamespace(c *check.C) {
namespace, err := app.CreateNamespace("testnamespace")
func (s *Suite) TestPortUser(c *check.C) {
user, err := app.CreateUser("testuser")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("testnamespace", "testmachine")
_, err = app.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs()
machine := Machine{
@ -483,7 +483,7 @@ func (s *Suite) TestPortNamespace(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: ips,
AuthKeyID: uint(pak.ID),
@ -491,7 +491,7 @@ func (s *Suite) TestPortNamespace(c *check.C) {
app.db.Save(&machine)
err = app.LoadACLPolicy(
"./tests/acls/acl_policy_basic_namespace_as_user.hujson",
"./tests/acls/acl_policy_basic_user_as_user.hujson",
)
c.Assert(err, check.IsNil)
@ -513,13 +513,13 @@ func (s *Suite) TestPortNamespace(c *check.C) {
}
func (s *Suite) TestPortGroup(c *check.C) {
namespace, err := app.CreateNamespace("testnamespace")
user, err := app.CreateUser("testuser")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("testnamespace", "testmachine")
_, err = app.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs()
machine := Machine{
@ -528,7 +528,7 @@ func (s *Suite) TestPortGroup(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: ips,
AuthKeyID: uint(pak.ID),
@ -689,7 +689,7 @@ func Test_expandTagOwners(t *testing.T) {
wantErr: false,
},
{
name: "expand with namespace and group",
name: "expand with user and group",
args: args{
aclPolicy: ACLPolicy{
Groups: Groups{"group:foo": []string{"user1", "user2"}},
@ -843,10 +843,10 @@ func Test_expandPorts(t *testing.T) {
}
}
func Test_listMachinesInNamespace(t *testing.T) {
func Test_listMachinesInUser(t *testing.T) {
type args struct {
machines []Machine
namespace string
user string
}
tests := []struct {
name string
@ -854,54 +854,54 @@ func Test_listMachinesInNamespace(t *testing.T) {
want []Machine
}{
{
name: "1 machine in namespace",
name: "1 machine in user",
args: args{
machines: []Machine{
{Namespace: Namespace{Name: "joe"}},
{User: User{Name: "joe"}},
},
namespace: "joe",
user: "joe",
},
want: []Machine{
{Namespace: Namespace{Name: "joe"}},
{User: User{Name: "joe"}},
},
},
{
name: "3 machines, 2 in namespace",
name: "3 machines, 2 in user",
args: args{
machines: []Machine{
{ID: 1, Namespace: Namespace{Name: "joe"}},
{ID: 2, Namespace: Namespace{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}},
{ID: 1, User: User{Name: "joe"}},
{ID: 2, User: User{Name: "marc"}},
{ID: 3, User: User{Name: "marc"}},
},
namespace: "marc",
user: "marc",
},
want: []Machine{
{ID: 2, Namespace: Namespace{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}},
{ID: 2, User: User{Name: "marc"}},
{ID: 3, User: User{Name: "marc"}},
},
},
{
name: "5 machines, 0 in namespace",
name: "5 machines, 0 in user",
args: args{
machines: []Machine{
{ID: 1, Namespace: Namespace{Name: "joe"}},
{ID: 2, Namespace: Namespace{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}},
{ID: 4, Namespace: Namespace{Name: "marc"}},
{ID: 5, Namespace: Namespace{Name: "marc"}},
{ID: 1, User: User{Name: "joe"}},
{ID: 2, User: User{Name: "marc"}},
{ID: 3, User: User{Name: "marc"}},
{ID: 4, User: User{Name: "marc"}},
{ID: 5, User: User{Name: "marc"}},
},
namespace: "mickael",
user: "mickael",
},
want: []Machine{},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
if got := filterMachinesByNamespace(test.args.machines, test.args.namespace); !reflect.DeepEqual(
if got := filterMachinesByUser(test.args.machines, test.args.user); !reflect.DeepEqual(
got,
test.want,
) {
t.Errorf("listMachinesInNamespace() = %v, want %v", got, test.want)
t.Errorf("listMachinesInUser() = %v, want %v", got, test.want)
}
})
}
@ -947,25 +947,25 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
aclPolicy: ACLPolicy{
@ -985,25 +985,25 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
aclPolicy: ACLPolicy{
@ -1071,7 +1071,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1082,7 +1082,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1093,13 +1093,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
aclPolicy: ACLPolicy{
@ -1119,25 +1119,25 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
aclPolicy: ACLPolicy{
@ -1160,27 +1160,27 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
aclPolicy: ACLPolicy{},
@ -1198,14 +1198,14 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1216,13 +1216,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
aclPolicy: ACLPolicy{
@ -1236,7 +1236,7 @@ func Test_expandAlias(t *testing.T) {
wantErr: false,
},
{
name: "list host in namespace without correctly tagged servers",
name: "list host in user without correctly tagged servers",
args: args{
alias: "joe",
machines: []Machine{
@ -1244,7 +1244,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1255,7 +1255,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1266,13 +1266,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
aclPolicy: ACLPolicy{
@ -1308,7 +1308,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
type args struct {
aclPolicy ACLPolicy
nodes []Machine
namespace string
user string
stripEmailDomain bool
}
tests := []struct {
@ -1328,7 +1328,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1339,7 +1339,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1350,16 +1350,16 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
namespace: "joe",
user: "joe",
stripEmailDomain: true,
},
want: []Machine{
{
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
},
@ -1379,7 +1379,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1390,7 +1390,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1401,16 +1401,16 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
namespace: "joe",
user: "joe",
stripEmailDomain: true,
},
want: []Machine{
{
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
},
@ -1425,7 +1425,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "foo",
@ -1436,23 +1436,23 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
ForcedTags: []string{"tag:accountant-webserver"},
},
{
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
namespace: "joe",
user: "joe",
stripEmailDomain: true,
},
want: []Machine{
{
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
},
@ -1467,7 +1467,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "hr-web1",
@ -1478,7 +1478,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "hr-web2",
@ -1489,10 +1489,10 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
namespace: "joe",
user: "joe",
stripEmailDomain: true,
},
want: []Machine{
@ -1500,7 +1500,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "hr-web1",
@ -1511,7 +1511,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
HostInfo: HostInfo{
OS: "centos",
Hostname: "hr-web2",
@ -1522,7 +1522,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
},
@ -1532,7 +1532,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
got := excludeCorrectlyTaggedNodes(
test.args.aclPolicy,
test.args.nodes,
test.args.namespace,
test.args.user,
test.args.stripEmailDomain,
)
if !reflect.DeepEqual(got, test.want) {

View file

@ -34,7 +34,7 @@ type Groups map[string][]string
// Hosts are alias for IP addresses or subnets.
type Hosts map[string]netip.Prefix
// TagOwners specify what users (namespaces?) are allow to use certain tags.
// TagOwners specify what users (users?) are allow to use certain tags.
type TagOwners map[string][]string
// ACLTest is not implemented, but should be use to check if a certain rule is allowed.
@ -44,7 +44,7 @@ type ACLTest struct {
Deny []string `json:"deny,omitempty" yaml:"deny,omitempty"`
}
// AutoApprovers specify which users (namespaces?), groups or tags have their advertised routes
// AutoApprovers specify which users (users?), groups or tags have their advertised routes
// or exit node status automatically enabled.
type AutoApprovers struct {
Routes map[string][]string `json:"routes" yaml:"routes"`
@ -119,7 +119,7 @@ func (policy ACLPolicy) IsZero() bool {
return false
}
// Returns the list of autoApproving namespaces, groups or tags for a given IPPrefix.
// Returns the list of autoApproving users, groups or tags for a given IPPrefix.
func (autoApprovers *AutoApprovers) GetRouteApprovers(
prefix netip.Prefix,
) ([]string, error) {

View file

@ -29,7 +29,7 @@ type APIKey struct {
LastSeen *time.Time
}
// CreateAPIKey creates a new ApiKey in a namespace, and returns it.
// CreateAPIKey creates a new ApiKey in a user, and returns it.
func (h *Headscale) CreateAPIKey(
expiration *time.Time,
) (string, *APIKey, error) {
@ -64,7 +64,7 @@ func (h *Headscale) CreateAPIKey(
return keyStr, &key, nil
}
// ListAPIKeys returns the list of ApiKeys for a namespace.
// ListAPIKeys returns the list of ApiKeys for a user.
func (h *Headscale) ListAPIKeys() ([]APIKey, error) {
keys := []APIKey{}
if err := h.db.Find(&keys).Error; err != nil {

48
app.go
View file

@ -238,20 +238,20 @@ func (h *Headscale) failoverSubnetRoutes(milliSeconds int64) {
}
func (h *Headscale) expireEphemeralNodesWorker() {
namespaces, err := h.ListNamespaces()
users, err := h.ListUsers()
if err != nil {
log.Error().Err(err).Msg("Error listing namespaces")
log.Error().Err(err).Msg("Error listing users")
return
}
for _, namespace := range namespaces {
machines, err := h.ListMachinesInNamespace(namespace.Name)
for _, user := range users {
machines, err := h.ListMachinesByUser(user.Name)
if err != nil {
log.Error().
Err(err).
Str("namespace", namespace.Name).
Msg("Error listing machines in namespace")
Str("user", user.Name).
Msg("Error listing machines in user")
return
}
@ -283,20 +283,20 @@ func (h *Headscale) expireEphemeralNodesWorker() {
}
func (h *Headscale) expireExpiredMachinesWorker() {
namespaces, err := h.ListNamespaces()
users, err := h.ListUsers()
if err != nil {
log.Error().Err(err).Msg("Error listing namespaces")
log.Error().Err(err).Msg("Error listing users")
return
}
for _, namespace := range namespaces {
machines, err := h.ListMachinesInNamespace(namespace.Name)
for _, user := range users {
machines, err := h.ListMachinesByUser(user.Name)
if err != nil {
log.Error().
Err(err).
Str("namespace", namespace.Name).
Msg("Error listing machines in namespace")
Str("user", user.Name).
Msg("Error listing machines in user")
return
}
@ -304,7 +304,7 @@ func (h *Headscale) expireExpiredMachinesWorker() {
expiredFound := false
for index, machine := range machines {
if machine.isExpired() &&
machine.Expiry.After(h.getLastStateChange(namespace)) {
machine.Expiry.After(h.getLastStateChange(user)) {
expiredFound = true
err := h.ExpireMachine(&machines[index])
@ -908,31 +908,31 @@ func (h *Headscale) setLastStateChangeToNow() {
now := time.Now().UTC()
namespaces, err := h.ListNamespaces()
users, err := h.ListUsers()
if err != nil {
log.Error().
Caller().
Err(err).
Msg("failed to fetch all namespaces, failing to update last changed state.")
Msg("failed to fetch all users, failing to update last changed state.")
}
for _, namespace := range namespaces {
lastStateUpdate.WithLabelValues(namespace.Name, "headscale").Set(float64(now.Unix()))
for _, user := range users {
lastStateUpdate.WithLabelValues(user.Name, "headscale").Set(float64(now.Unix()))
if h.lastStateChange == nil {
h.lastStateChange = xsync.NewMapOf[time.Time]()
}
h.lastStateChange.Store(namespace.Name, now)
h.lastStateChange.Store(user.Name, now)
}
}
func (h *Headscale) getLastStateChange(namespaces ...Namespace) time.Time {
func (h *Headscale) getLastStateChange(users ...User) time.Time {
times := []time.Time{}
// getLastStateChange takes a list of namespaces as a "filter", if no namespaces
// are past, then use the entier list of namespaces and look for the last update
if len(namespaces) > 0 {
for _, namespace := range namespaces {
if lastChange, ok := h.lastStateChange.Load(namespace.Name); ok {
// getLastStateChange takes a list of users as a "filter", if no users
// are past, then use the entier list of users and look for the last update
if len(users) > 0 {
for _, user := range users {
if lastChange, ok := h.lastStateChange.Load(user.Name); ok {
times = append(times, lastChange)
}
}

View file

@ -77,7 +77,7 @@ func main() {
"TestCreateTailscale",
"TestEnablingRoutes",
"TestHeadscale",
"TestNamespaceCommand",
"TestUserCommand",
"TestOIDCAuthenticationPingAll",
"TestOIDCExpireNodes",
"TestPingAllByHostname",
@ -87,10 +87,10 @@ func main() {
"TestPreAuthKeyCommandWithoutExpiry",
"TestResolveMagicDNS",
"TestSSHIsBlockedInACL",
"TestSSHMultipleNamespacesAllToAll",
"TestSSHMultipleUsersAllToAll",
"TestSSHNoSSHConfigured",
"TestSSHOneNamespaceAllToAll",
"TestSSNamespaceOnlyIsolation",
"TestSSHOneUserAllToAll",
"TestSSUserOnlyIsolation",
"TestTaildrop",
"TestTailscaleNodesJoiningHeadcale",
}

View file

@ -27,8 +27,8 @@ func init() {
if err != nil {
log.Fatal().Err(err).Msg("")
}
createNodeCmd.Flags().StringP("namespace", "n", "", "Namespace")
err = createNodeCmd.MarkFlagRequired("namespace")
createNodeCmd.Flags().StringP("user", "n", "", "User")
err = createNodeCmd.MarkFlagRequired("user")
if err != nil {
log.Fatal().Err(err).Msg("")
}
@ -55,9 +55,9 @@ var createNodeCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -112,7 +112,7 @@ var createNodeCmd = &cobra.Command{
request := &v1.DebugCreateMachineRequest{
Key: machineKey,
Name: name,
Namespace: namespace,
User: user,
Routes: routes,
}

View file

@ -13,26 +13,26 @@ import (
)
func init() {
rootCmd.AddCommand(namespaceCmd)
namespaceCmd.AddCommand(createNamespaceCmd)
namespaceCmd.AddCommand(listNamespacesCmd)
namespaceCmd.AddCommand(destroyNamespaceCmd)
namespaceCmd.AddCommand(renameNamespaceCmd)
rootCmd.AddCommand(userCmd)
userCmd.AddCommand(createUserCmd)
userCmd.AddCommand(listUsersCmd)
userCmd.AddCommand(destroyUserCmd)
userCmd.AddCommand(renameUserCmd)
}
const (
errMissingParameter = headscale.Error("missing parameters")
)
var namespaceCmd = &cobra.Command{
Use: "namespaces",
Short: "Manage the namespaces of Headscale",
Aliases: []string{"namespace", "ns", "user", "users"},
var userCmd = &cobra.Command{
Use: "users",
Short: "Manage the users of Headscale",
Aliases: []string{"user", "ns", "user", "users"},
}
var createNamespaceCmd = &cobra.Command{
var createUserCmd = &cobra.Command{
Use: "create NAME",
Short: "Creates a new namespace",
Short: "Creates a new user",
Aliases: []string{"c", "new"},
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
@ -44,7 +44,7 @@ var createNamespaceCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespaceName := args[0]
userName := args[0]
ctx, client, conn, cancel := getHeadscaleCLIClient()
defer cancel()
@ -52,15 +52,15 @@ var createNamespaceCmd = &cobra.Command{
log.Trace().Interface("client", client).Msg("Obtained gRPC client")
request := &v1.CreateNamespaceRequest{Name: namespaceName}
request := &v1.CreateUserRequest{Name: userName}
log.Trace().Interface("request", request).Msg("Sending CreateNamespace request")
response, err := client.CreateNamespace(ctx, request)
log.Trace().Interface("request", request).Msg("Sending CreateUser request")
response, err := client.CreateUser(ctx, request)
if err != nil {
ErrorOutput(
err,
fmt.Sprintf(
"Cannot create namespace: %s",
"Cannot create user: %s",
status.Convert(err).Message(),
),
output,
@ -69,13 +69,13 @@ var createNamespaceCmd = &cobra.Command{
return
}
SuccessOutput(response.Namespace, "Namespace created", output)
SuccessOutput(response.User, "User created", output)
},
}
var destroyNamespaceCmd = &cobra.Command{
var destroyUserCmd = &cobra.Command{
Use: "destroy NAME",
Short: "Destroys a namespace",
Short: "Destroys a user",
Aliases: []string{"delete"},
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
@ -87,17 +87,17 @@ var destroyNamespaceCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespaceName := args[0]
userName := args[0]
request := &v1.GetNamespaceRequest{
Name: namespaceName,
request := &v1.GetUserRequest{
Name: userName,
}
ctx, client, conn, cancel := getHeadscaleCLIClient()
defer cancel()
defer conn.Close()
_, err := client.GetNamespace(ctx, request)
_, err := client.GetUser(ctx, request)
if err != nil {
ErrorOutput(
err,
@ -113,8 +113,8 @@ var destroyNamespaceCmd = &cobra.Command{
if !force {
prompt := &survey.Confirm{
Message: fmt.Sprintf(
"Do you want to remove the namespace '%s' and any associated preauthkeys?",
namespaceName,
"Do you want to remove the user '%s' and any associated preauthkeys?",
userName,
),
}
err := survey.AskOne(prompt, &confirm)
@ -124,14 +124,14 @@ var destroyNamespaceCmd = &cobra.Command{
}
if confirm || force {
request := &v1.DeleteNamespaceRequest{Name: namespaceName}
request := &v1.DeleteUserRequest{Name: userName}
response, err := client.DeleteNamespace(ctx, request)
response, err := client.DeleteUser(ctx, request)
if err != nil {
ErrorOutput(
err,
fmt.Sprintf(
"Cannot destroy namespace: %s",
"Cannot destroy user: %s",
status.Convert(err).Message(),
),
output,
@ -139,16 +139,16 @@ var destroyNamespaceCmd = &cobra.Command{
return
}
SuccessOutput(response, "Namespace destroyed", output)
SuccessOutput(response, "User destroyed", output)
} else {
SuccessOutput(map[string]string{"Result": "Namespace not destroyed"}, "Namespace not destroyed", output)
SuccessOutput(map[string]string{"Result": "User not destroyed"}, "User not destroyed", output)
}
},
}
var listNamespacesCmd = &cobra.Command{
var listUsersCmd = &cobra.Command{
Use: "list",
Short: "List all the namespaces",
Short: "List all the users",
Aliases: []string{"ls", "show"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
@ -157,13 +157,13 @@ var listNamespacesCmd = &cobra.Command{
defer cancel()
defer conn.Close()
request := &v1.ListNamespacesRequest{}
request := &v1.ListUsersRequest{}
response, err := client.ListNamespaces(ctx, request)
response, err := client.ListUsers(ctx, request)
if err != nil {
ErrorOutput(
err,
fmt.Sprintf("Cannot get namespaces: %s", status.Convert(err).Message()),
fmt.Sprintf("Cannot get users: %s", status.Convert(err).Message()),
output,
)
@ -171,19 +171,19 @@ var listNamespacesCmd = &cobra.Command{
}
if output != "" {
SuccessOutput(response.Namespaces, "", output)
SuccessOutput(response.Users, "", output)
return
}
tableData := pterm.TableData{{"ID", "Name", "Created"}}
for _, namespace := range response.GetNamespaces() {
for _, user := range response.GetUsers() {
tableData = append(
tableData,
[]string{
namespace.GetId(),
namespace.GetName(),
namespace.GetCreatedAt().AsTime().Format("2006-01-02 15:04:05"),
user.GetId(),
user.GetName(),
user.GetCreatedAt().AsTime().Format("2006-01-02 15:04:05"),
},
)
}
@ -200,9 +200,9 @@ var listNamespacesCmd = &cobra.Command{
},
}
var renameNamespaceCmd = &cobra.Command{
var renameUserCmd = &cobra.Command{
Use: "rename OLD_NAME NEW_NAME",
Short: "Renames a namespace",
Short: "Renames a user",
Aliases: []string{"mv"},
Args: func(cmd *cobra.Command, args []string) error {
expectedArguments := 2
@ -219,17 +219,17 @@ var renameNamespaceCmd = &cobra.Command{
defer cancel()
defer conn.Close()
request := &v1.RenameNamespaceRequest{
request := &v1.RenameUserRequest{
OldName: args[0],
NewName: args[1],
}
response, err := client.RenameNamespace(ctx, request)
response, err := client.RenameUser(ctx, request)
if err != nil {
ErrorOutput(
err,
fmt.Sprintf(
"Cannot rename namespace: %s",
"Cannot rename user: %s",
status.Convert(err).Message(),
),
output,
@ -238,6 +238,6 @@ var renameNamespaceCmd = &cobra.Command{
return
}
SuccessOutput(response.Namespace, "Namespace renamed", output)
SuccessOutput(response.User, "User renamed", output)
},
}

View file

@ -19,12 +19,12 @@ import (
func init() {
rootCmd.AddCommand(nodeCmd)
listNodesCmd.Flags().StringP("namespace", "n", "", "Filter by namespace")
listNodesCmd.Flags().StringP("user", "n", "", "Filter by user")
listNodesCmd.Flags().BoolP("tags", "t", false, "Show tags")
nodeCmd.AddCommand(listNodesCmd)
registerNodeCmd.Flags().StringP("namespace", "n", "", "Namespace")
err := registerNodeCmd.MarkFlagRequired("namespace")
registerNodeCmd.Flags().StringP("user", "n", "", "User")
err := registerNodeCmd.MarkFlagRequired("user")
if err != nil {
log.Fatalf(err.Error())
}
@ -63,9 +63,9 @@ func init() {
log.Fatalf(err.Error())
}
moveNodeCmd.Flags().StringP("namespace", "n", "", "New namespace")
moveNodeCmd.Flags().StringP("user", "n", "", "New user")
err = moveNodeCmd.MarkFlagRequired("namespace")
err = moveNodeCmd.MarkFlagRequired("user")
if err != nil {
log.Fatalf(err.Error())
}
@ -93,9 +93,9 @@ var registerNodeCmd = &cobra.Command{
Short: "Registers a machine to your network",
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -117,7 +117,7 @@ var registerNodeCmd = &cobra.Command{
request := &v1.RegisterMachineRequest{
Key: machineKey,
Namespace: namespace,
User: user,
}
response, err := client.RegisterMachine(ctx, request)
@ -146,9 +146,9 @@ var listNodesCmd = &cobra.Command{
Aliases: []string{"ls", "show"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -164,7 +164,7 @@ var listNodesCmd = &cobra.Command{
defer conn.Close()
request := &v1.ListMachinesRequest{
Namespace: namespace,
User: user,
}
response, err := client.ListMachines(ctx, request)
@ -184,7 +184,7 @@ var listNodesCmd = &cobra.Command{
return
}
tableData, err := nodesToPtables(namespace, showTags, response.Machines)
tableData, err := nodesToPtables(user, showTags, response.Machines)
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error converting to table: %s", err), output)
@ -388,7 +388,7 @@ var deleteNodeCmd = &cobra.Command{
var moveNodeCmd = &cobra.Command{
Use: "move",
Short: "Move node to another namespace",
Short: "Move node to another user",
Aliases: []string{"mv"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
@ -404,11 +404,11 @@ var moveNodeCmd = &cobra.Command{
return
}
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(
err,
fmt.Sprintf("Error getting namespace: %s", err),
fmt.Sprintf("Error getting user: %s", err),
output,
)
@ -439,7 +439,7 @@ var moveNodeCmd = &cobra.Command{
moveRequest := &v1.MoveMachineRequest{
MachineId: identifier,
Namespace: namespace,
User: user,
}
moveResponse, err := client.MoveMachine(ctx, moveRequest)
@ -456,12 +456,12 @@ var moveNodeCmd = &cobra.Command{
return
}
SuccessOutput(moveResponse.Machine, "Node moved to another namespace", output)
SuccessOutput(moveResponse.Machine, "Node moved to another user", output)
},
}
func nodesToPtables(
currentNamespace string,
currentUser string,
showTags bool,
machines []*v1.Machine,
) (pterm.TableData, error) {
@ -471,7 +471,7 @@ func nodesToPtables(
"Name",
"MachineKey",
"NodeKey",
"Namespace",
"User",
"IP addresses",
"Ephemeral",
"Last seen",
@ -560,12 +560,12 @@ func nodesToPtables(
}
validTags = strings.TrimLeft(validTags, ",")
var namespace string
if currentNamespace == "" || (currentNamespace == machine.Namespace.Name) {
namespace = pterm.LightMagenta(machine.Namespace.Name)
var user string
if currentUser == "" || (currentUser == machine.User.Name) {
user = pterm.LightMagenta(machine.User.Name)
} else {
// Shared into this namespace
namespace = pterm.LightYellow(machine.Namespace.Name)
// Shared into this user
user = pterm.LightYellow(machine.User.Name)
}
var IPV4Address string
@ -584,7 +584,7 @@ func nodesToPtables(
machine.GetGivenName(),
machineKey.ShortString(),
nodeKey.ShortString(),
namespace,
user,
strings.Join([]string{IPV4Address, IPV6Address}, ", "),
strconv.FormatBool(ephemeral),
lastSeenTime,

View file

@ -20,8 +20,8 @@ const (
func init() {
rootCmd.AddCommand(preauthkeysCmd)
preauthkeysCmd.PersistentFlags().StringP("namespace", "n", "", "Namespace")
err := preauthkeysCmd.MarkPersistentFlagRequired("namespace")
preauthkeysCmd.PersistentFlags().StringP("user", "n", "", "User")
err := preauthkeysCmd.MarkPersistentFlagRequired("user")
if err != nil {
log.Fatal().Err(err).Msg("")
}
@ -46,14 +46,14 @@ var preauthkeysCmd = &cobra.Command{
var listPreAuthKeys = &cobra.Command{
Use: "list",
Short: "List the preauthkeys for this namespace",
Short: "List the preauthkeys for this user",
Aliases: []string{"ls", "show"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -63,7 +63,7 @@ var listPreAuthKeys = &cobra.Command{
defer conn.Close()
request := &v1.ListPreAuthKeysRequest{
Namespace: namespace,
User: user,
}
response, err := client.ListPreAuthKeys(ctx, request)
@ -143,14 +143,14 @@ var listPreAuthKeys = &cobra.Command{
var createPreAuthKeyCmd = &cobra.Command{
Use: "create",
Short: "Creates a new preauthkey in the specified namespace",
Short: "Creates a new preauthkey in the specified user",
Aliases: []string{"c", "new"},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -162,11 +162,11 @@ var createPreAuthKeyCmd = &cobra.Command{
log.Trace().
Bool("reusable", reusable).
Bool("ephemeral", ephemeral).
Str("namespace", namespace).
Str("user", user).
Msg("Preparing to create preauthkey")
request := &v1.CreatePreAuthKeyRequest{
Namespace: namespace,
User: user,
Reusable: reusable,
Ephemeral: ephemeral,
AclTags: tags,
@ -225,9 +225,9 @@ var expirePreAuthKeyCmd = &cobra.Command{
},
Run: func(cmd *cobra.Command, args []string) {
output, _ := cmd.Flags().GetString("output")
namespace, err := cmd.Flags().GetString("namespace")
user, err := cmd.Flags().GetString("user")
if err != nil {
ErrorOutput(err, fmt.Sprintf("Error getting namespace: %s", err), output)
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
return
}
@ -237,7 +237,7 @@ var expirePreAuthKeyCmd = &cobra.Command{
defer conn.Close()
request := &v1.ExpirePreAuthKeyRequest{
Namespace: namespace,
User: user,
Key: args[0],
}

14
dns.go
View file

@ -190,23 +190,23 @@ func getMapResponseDNSConfig(
) *tailcfg.DNSConfig {
var dnsConfig *tailcfg.DNSConfig = dnsConfigOrig.Clone()
if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled
// Only inject the Search Domain of the current namespace - shared nodes should use their full FQDN
// Only inject the Search Domain of the current user - shared nodes should use their full FQDN
dnsConfig.Domains = append(
dnsConfig.Domains,
fmt.Sprintf(
"%s.%s",
machine.Namespace.Name,
machine.User.Name,
baseDomain,
),
)
namespaceSet := mapset.NewSet[Namespace]()
namespaceSet.Add(machine.Namespace)
userSet := mapset.NewSet[User]()
userSet.Add(machine.User)
for _, p := range peers {
namespaceSet.Add(p.Namespace)
userSet.Add(p.User)
}
for _, namespace := range namespaceSet.ToSlice() {
dnsRoute := fmt.Sprintf("%v.%v", namespace.Name, baseDomain)
for _, user := range userSet.ToSlice() {
dnsRoute := fmt.Sprintf("%v.%v", user.Name, baseDomain)
dnsConfig.Routes[dnsRoute] = nil
}
} else {

View file

@ -112,17 +112,17 @@ func (s *Suite) TestMagicDNSRootDomainsIPv6SingleMultiple(c *check.C) {
}
func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
namespaceShared1, err := app.CreateNamespace("shared1")
userShared1, err := app.CreateUser("shared1")
c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2")
userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3")
userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil)
preAuthKeyInShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -131,7 +131,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyInShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name,
userShared2.Name,
false,
false,
nil,
@ -140,7 +140,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyInShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name,
userShared3.Name,
false,
false,
nil,
@ -149,7 +149,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
PreAuthKey2InShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -157,7 +157,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
)
c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespaceShared1.Name, "test_get_shared_nodes_1")
_, err = app.GetMachine(userShared1.Name, "test_get_shared_nodes_1")
c.Assert(err, check.NotNil)
machineInShared1 := &Machine{
@ -166,15 +166,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyInShared1.ID),
}
app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname)
_, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil)
machineInShared2 := &Machine{
@ -183,15 +183,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID,
Namespace: *namespaceShared2,
UserID: userShared2.ID,
User: *userShared2,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyInShared2.ID),
}
app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname)
_, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil)
machineInShared3 := &Machine{
@ -200,15 +200,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID,
Namespace: *namespaceShared3,
UserID: userShared3.ID,
User: *userShared3,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyInShared3.ID),
}
app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname)
_, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{
@ -217,8 +217,8 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(PreAuthKey2InShared1.ID),
@ -245,31 +245,31 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(len(dnsConfig.Routes), check.Equals, 3)
domainRouteShared1 := fmt.Sprintf("%s.%s", namespaceShared1.Name, baseDomain)
domainRouteShared1 := fmt.Sprintf("%s.%s", userShared1.Name, baseDomain)
_, ok := dnsConfig.Routes[domainRouteShared1]
c.Assert(ok, check.Equals, true)
domainRouteShared2 := fmt.Sprintf("%s.%s", namespaceShared2.Name, baseDomain)
domainRouteShared2 := fmt.Sprintf("%s.%s", userShared2.Name, baseDomain)
_, ok = dnsConfig.Routes[domainRouteShared2]
c.Assert(ok, check.Equals, true)
domainRouteShared3 := fmt.Sprintf("%s.%s", namespaceShared3.Name, baseDomain)
domainRouteShared3 := fmt.Sprintf("%s.%s", userShared3.Name, baseDomain)
_, ok = dnsConfig.Routes[domainRouteShared3]
c.Assert(ok, check.Equals, true)
}
func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
namespaceShared1, err := app.CreateNamespace("shared1")
userShared1, err := app.CreateUser("shared1")
c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2")
userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3")
userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil)
preAuthKeyInShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -278,7 +278,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyInShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name,
userShared2.Name,
false,
false,
nil,
@ -287,7 +287,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyInShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name,
userShared3.Name,
false,
false,
nil,
@ -296,7 +296,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKey2InShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -304,7 +304,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
)
c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespaceShared1.Name, "test_get_shared_nodes_1")
_, err = app.GetMachine(userShared1.Name, "test_get_shared_nodes_1")
c.Assert(err, check.NotNil)
machineInShared1 := &Machine{
@ -313,15 +313,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyInShared1.ID),
}
app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname)
_, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil)
machineInShared2 := &Machine{
@ -330,15 +330,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID,
Namespace: *namespaceShared2,
UserID: userShared2.ID,
User: *userShared2,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyInShared2.ID),
}
app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname)
_, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil)
machineInShared3 := &Machine{
@ -347,15 +347,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID,
Namespace: *namespaceShared3,
UserID: userShared3.ID,
User: *userShared3,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyInShared3.ID),
}
app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname)
_, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{
@ -364,8 +364,8 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(preAuthKey2InShared1.ID),

View file

@ -26,76 +26,76 @@ func newHeadscaleV1APIServer(h *Headscale) v1.HeadscaleServiceServer {
}
}
func (api headscaleV1APIServer) GetNamespace(
func (api headscaleV1APIServer) GetUser(
ctx context.Context,
request *v1.GetNamespaceRequest,
) (*v1.GetNamespaceResponse, error) {
namespace, err := api.h.GetNamespace(request.GetName())
request *v1.GetUserRequest,
) (*v1.GetUserResponse, error) {
user, err := api.h.GetUser(request.GetName())
if err != nil {
return nil, err
}
return &v1.GetNamespaceResponse{Namespace: namespace.toProto()}, nil
return &v1.GetUserResponse{User: user.toProto()}, nil
}
func (api headscaleV1APIServer) CreateNamespace(
func (api headscaleV1APIServer) CreateUser(
ctx context.Context,
request *v1.CreateNamespaceRequest,
) (*v1.CreateNamespaceResponse, error) {
namespace, err := api.h.CreateNamespace(request.GetName())
request *v1.CreateUserRequest,
) (*v1.CreateUserResponse, error) {
user, err := api.h.CreateUser(request.GetName())
if err != nil {
return nil, err
}
return &v1.CreateNamespaceResponse{Namespace: namespace.toProto()}, nil
return &v1.CreateUserResponse{User: user.toProto()}, nil
}
func (api headscaleV1APIServer) RenameNamespace(
func (api headscaleV1APIServer) RenameUser(
ctx context.Context,
request *v1.RenameNamespaceRequest,
) (*v1.RenameNamespaceResponse, error) {
err := api.h.RenameNamespace(request.GetOldName(), request.GetNewName())
request *v1.RenameUserRequest,
) (*v1.RenameUserResponse, error) {
err := api.h.RenameUser(request.GetOldName(), request.GetNewName())
if err != nil {
return nil, err
}
namespace, err := api.h.GetNamespace(request.GetNewName())
user, err := api.h.GetUser(request.GetNewName())
if err != nil {
return nil, err
}
return &v1.RenameNamespaceResponse{Namespace: namespace.toProto()}, nil
return &v1.RenameUserResponse{User: user.toProto()}, nil
}
func (api headscaleV1APIServer) DeleteNamespace(
func (api headscaleV1APIServer) DeleteUser(
ctx context.Context,
request *v1.DeleteNamespaceRequest,
) (*v1.DeleteNamespaceResponse, error) {
err := api.h.DestroyNamespace(request.GetName())
request *v1.DeleteUserRequest,
) (*v1.DeleteUserResponse, error) {
err := api.h.DestroyUser(request.GetName())
if err != nil {
return nil, err
}
return &v1.DeleteNamespaceResponse{}, nil
return &v1.DeleteUserResponse{}, nil
}
func (api headscaleV1APIServer) ListNamespaces(
func (api headscaleV1APIServer) ListUsers(
ctx context.Context,
request *v1.ListNamespacesRequest,
) (*v1.ListNamespacesResponse, error) {
namespaces, err := api.h.ListNamespaces()
request *v1.ListUsersRequest,
) (*v1.ListUsersResponse, error) {
users, err := api.h.ListUsers()
if err != nil {
return nil, err
}
response := make([]*v1.Namespace, len(namespaces))
for index, namespace := range namespaces {
response[index] = namespace.toProto()
response := make([]*v1.User, len(users))
for index, user := range users {
response[index] = user.toProto()
}
log.Trace().Caller().Interface("namespaces", response).Msg("")
log.Trace().Caller().Interface("users", response).Msg("")
return &v1.ListNamespacesResponse{Namespaces: response}, nil
return &v1.ListUsersResponse{Users: response}, nil
}
func (api headscaleV1APIServer) CreatePreAuthKey(
@ -117,7 +117,7 @@ func (api headscaleV1APIServer) CreatePreAuthKey(
}
preAuthKey, err := api.h.CreatePreAuthKey(
request.GetNamespace(),
request.GetUser(),
request.GetReusable(),
request.GetEphemeral(),
&expiration,
@ -134,7 +134,7 @@ func (api headscaleV1APIServer) ExpirePreAuthKey(
ctx context.Context,
request *v1.ExpirePreAuthKeyRequest,
) (*v1.ExpirePreAuthKeyResponse, error) {
preAuthKey, err := api.h.GetPreAuthKey(request.GetNamespace(), request.Key)
preAuthKey, err := api.h.GetPreAuthKey(request.GetUser(), request.Key)
if err != nil {
return nil, err
}
@ -151,7 +151,7 @@ func (api headscaleV1APIServer) ListPreAuthKeys(
ctx context.Context,
request *v1.ListPreAuthKeysRequest,
) (*v1.ListPreAuthKeysResponse, error) {
preAuthKeys, err := api.h.ListPreAuthKeys(request.GetNamespace())
preAuthKeys, err := api.h.ListPreAuthKeys(request.GetUser())
if err != nil {
return nil, err
}
@ -169,13 +169,13 @@ func (api headscaleV1APIServer) RegisterMachine(
request *v1.RegisterMachineRequest,
) (*v1.RegisterMachineResponse, error) {
log.Trace().
Str("namespace", request.GetNamespace()).
Str("user", request.GetUser()).
Str("node_key", request.GetKey()).
Msg("Registering machine")
machine, err := api.h.RegisterMachineFromAuthCallback(
request.GetKey(),
request.GetNamespace(),
request.GetUser(),
nil,
RegisterMethodCLI,
)
@ -313,8 +313,8 @@ func (api headscaleV1APIServer) ListMachines(
ctx context.Context,
request *v1.ListMachinesRequest,
) (*v1.ListMachinesResponse, error) {
if request.GetNamespace() != "" {
machines, err := api.h.ListMachinesInNamespace(request.GetNamespace())
if request.GetUser() != "" {
machines, err := api.h.ListMachinesByUser(request.GetUser())
if err != nil {
return nil, err
}
@ -357,7 +357,7 @@ func (api headscaleV1APIServer) MoveMachine(
return nil, err
}
err = api.h.SetMachineNamespace(machine, request.GetNamespace())
err = api.h.SetMachineUser(machine, request.GetUser())
if err != nil {
return nil, err
}
@ -483,7 +483,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
ctx context.Context,
request *v1.DebugCreateMachineRequest,
) (*v1.DebugCreateMachineResponse, error) {
namespace, err := api.h.GetNamespace(request.GetNamespace())
user, err := api.h.GetUser(request.GetUser())
if err != nil {
return nil, err
}
@ -514,7 +514,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
MachineKey: request.GetKey(),
Hostname: request.GetName(),
GivenName: givenName,
Namespace: *namespace,
User: *user,
Expiry: &time.Time{},
LastSeen: &time.Time{},

View file

@ -49,7 +49,7 @@ func TestOIDCAuthenticationPingAll(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"user1": len(TailscaleVersions),
}
oidcConfig, err := scenario.runMockOIDC(defaultAccessTTL)
@ -116,7 +116,7 @@ func TestOIDCExpireNodes(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"user1": len(TailscaleVersions),
}
oidcConfig, err := scenario.runMockOIDC(shortAccessTTL)
@ -169,7 +169,7 @@ func TestOIDCExpireNodes(t *testing.T) {
}
func (s *AuthOIDCScenario) CreateHeadscaleEnv(
namespaces map[string]int,
users map[string]int,
opts ...hsic.Option,
) error {
headscale, err := s.Headscale(opts...)
@ -182,19 +182,19 @@ func (s *AuthOIDCScenario) CreateHeadscaleEnv(
return err
}
for namespaceName, clientCount := range namespaces {
log.Printf("creating namespace %s with %d clients", namespaceName, clientCount)
err = s.CreateNamespace(namespaceName)
for userName, clientCount := range users {
log.Printf("creating user %s with %d clients", userName, clientCount)
err = s.CreateUser(userName)
if err != nil {
return err
}
err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount)
err = s.CreateTailscaleNodesInUser(userName, "all", clientCount)
if err != nil {
return err
}
err = s.runTailscaleUp(namespaceName, headscale.GetEndpoint())
err = s.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil {
return err
}
@ -287,20 +287,20 @@ func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*headscale.OIDC
}
func (s *AuthOIDCScenario) runTailscaleUp(
namespaceStr, loginServer string,
userStr, loginServer string,
) error {
headscale, err := s.Headscale()
if err != nil {
return err
}
log.Printf("running tailscale up for namespace %s", namespaceStr)
if namespace, ok := s.namespaces[namespaceStr]; ok {
for _, client := range namespace.Clients {
namespace.joinWaitGroup.Add(1)
log.Printf("running tailscale up for user %s", userStr)
if user, ok := s.users[userStr]; ok {
for _, client := range user.Clients {
user.joinWaitGroup.Add(1)
go func(c TailscaleClient) {
defer namespace.joinWaitGroup.Done()
defer user.joinWaitGroup.Done()
// TODO(juanfont): error handle this
loginURL, err := c.UpWithLoginURL(loginServer)
@ -347,12 +347,12 @@ func (s *AuthOIDCScenario) runTailscaleUp(
log.Printf("client %s is ready", client.Hostname())
}
namespace.joinWaitGroup.Wait()
user.joinWaitGroup.Wait()
return nil
}
return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable)
return fmt.Errorf("failed to up tailscale node: %w", errNoUserAvailable)
}
func pingAll(t *testing.T, clients []TailscaleClient, ips []netip.Addr) int {

View file

@ -35,8 +35,8 @@ func TestAuthWebFlowAuthenticationPingAll(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions),
"user1": len(TailscaleVersions),
"user2": len(TailscaleVersions),
}
err = scenario.CreateHeadscaleEnv(spec, hsic.WithTestName("webauthping"))
@ -93,8 +93,8 @@ func TestAuthWebFlowLogoutAndRelogin(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions),
"user1": len(TailscaleVersions),
"user2": len(TailscaleVersions),
}
err = scenario.CreateHeadscaleEnv(spec, hsic.WithTestName("weblogout"))
@ -156,8 +156,8 @@ func TestAuthWebFlowLogoutAndRelogin(t *testing.T) {
t.Errorf("failed to get headscale server: %s", err)
}
for namespaceName := range spec {
err = scenario.runTailscaleUp(namespaceName, headscale.GetEndpoint())
for userName := range spec {
err = scenario.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil {
t.Errorf("failed to run tailscale up: %s", err)
}
@ -225,7 +225,7 @@ func TestAuthWebFlowLogoutAndRelogin(t *testing.T) {
}
func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
namespaces map[string]int,
users map[string]int,
opts ...hsic.Option,
) error {
headscale, err := s.Headscale(opts...)
@ -238,19 +238,19 @@ func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
return err
}
for namespaceName, clientCount := range namespaces {
log.Printf("creating namespace %s with %d clients", namespaceName, clientCount)
err = s.CreateNamespace(namespaceName)
for userName, clientCount := range users {
log.Printf("creating user %s with %d clients", userName, clientCount)
err = s.CreateUser(userName)
if err != nil {
return err
}
err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount)
err = s.CreateTailscaleNodesInUser(userName, "all", clientCount)
if err != nil {
return err
}
err = s.runTailscaleUp(namespaceName, headscale.GetEndpoint())
err = s.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil {
return err
}
@ -260,15 +260,15 @@ func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
}
func (s *AuthWebFlowScenario) runTailscaleUp(
namespaceStr, loginServer string,
userStr, loginServer string,
) error {
log.Printf("running tailscale up for namespace %s", namespaceStr)
if namespace, ok := s.namespaces[namespaceStr]; ok {
for _, client := range namespace.Clients {
namespace.joinWaitGroup.Add(1)
log.Printf("running tailscale up for user %s", userStr)
if user, ok := s.users[userStr]; ok {
for _, client := range user.Clients {
user.joinWaitGroup.Add(1)
go func(c TailscaleClient) {
defer namespace.joinWaitGroup.Done()
defer user.joinWaitGroup.Done()
// TODO(juanfont): error handle this
loginURL, err := c.UpWithLoginURL(loginServer)
@ -276,7 +276,7 @@ func (s *AuthWebFlowScenario) runTailscaleUp(
log.Printf("failed to run tailscale up: %s", err)
}
err = s.runHeadscaleRegister(namespaceStr, loginURL)
err = s.runHeadscaleRegister(userStr, loginURL)
if err != nil {
log.Printf("failed to register client: %s", err)
}
@ -287,15 +287,15 @@ func (s *AuthWebFlowScenario) runTailscaleUp(
log.Printf("error waiting for client %s to be ready: %s", client.Hostname(), err)
}
}
namespace.joinWaitGroup.Wait()
user.joinWaitGroup.Wait()
return nil
}
return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable)
return fmt.Errorf("failed to up tailscale node: %w", errNoUserAvailable)
}
func (s *AuthWebFlowScenario) runHeadscaleRegister(namespaceStr string, loginURL *url.URL) error {
func (s *AuthWebFlowScenario) runHeadscaleRegister(userStr string, loginURL *url.URL) error {
headscale, err := s.Headscale()
if err != nil {
return err
@ -335,7 +335,7 @@ func (s *AuthWebFlowScenario) runHeadscaleRegister(namespaceStr string, loginURL
if headscale, err := s.Headscale(); err == nil {
_, err = headscale.Execute(
[]string{"headscale", "-n", namespaceStr, "nodes", "register", "--key", key},
[]string{"headscale", "-n", userStr, "nodes", "register", "--key", key},
)
if err != nil {
log.Printf("failed to register node: %s", err)

View file

@ -28,7 +28,7 @@ func executeAndUnmarshal[T any](headscale ControlServer, command []string, resul
return nil
}
func TestNamespaceCommand(t *testing.T) {
func TestUserCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
@ -36,8 +36,8 @@ func TestNamespaceCommand(t *testing.T) {
assert.NoError(t, err)
spec := map[string]int{
"namespace1": 0,
"namespace2": 0,
"user1": 0,
"user2": 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
@ -46,60 +46,60 @@ func TestNamespaceCommand(t *testing.T) {
headscale, err := scenario.Headscale()
assert.NoError(t, err)
var listNamespaces []v1.Namespace
var listUsers []v1.User
err = executeAndUnmarshal(headscale,
[]string{
"headscale",
"namespaces",
"users",
"list",
"--output",
"json",
},
&listNamespaces,
&listUsers,
)
assert.NoError(t, err)
result := []string{listNamespaces[0].Name, listNamespaces[1].Name}
result := []string{listUsers[0].Name, listUsers[1].Name}
sort.Strings(result)
assert.Equal(
t,
[]string{"namespace1", "namespace2"},
[]string{"user1", "user2"},
result,
)
_, err = headscale.Execute(
[]string{
"headscale",
"namespaces",
"users",
"rename",
"--output",
"json",
"namespace2",
"user2",
"newname",
},
)
assert.NoError(t, err)
var listAfterRenameNamespaces []v1.Namespace
var listAfterRenameUsers []v1.User
err = executeAndUnmarshal(headscale,
[]string{
"headscale",
"namespaces",
"users",
"list",
"--output",
"json",
},
&listAfterRenameNamespaces,
&listAfterRenameUsers,
)
assert.NoError(t, err)
result = []string{listAfterRenameNamespaces[0].Name, listAfterRenameNamespaces[1].Name}
result = []string{listAfterRenameUsers[0].Name, listAfterRenameUsers[1].Name}
sort.Strings(result)
assert.Equal(
t,
[]string{"namespace1", "newname"},
[]string{"user1", "newname"},
result,
)
@ -111,14 +111,14 @@ func TestPreAuthKeyCommand(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
namespace := "preauthkeyspace"
user := "preauthkeyspace"
count := 3
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
namespace: 0,
user: 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipak"))
@ -137,8 +137,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"create",
"--reusable",
"--expiration",
@ -163,8 +163,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"list",
"--output",
"json",
@ -216,8 +216,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"expire",
listedPreAuthKeys[1].Key,
},
@ -230,8 +230,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"list",
"--output",
"json",
@ -252,13 +252,13 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
namespace := "pre-auth-key-without-exp-namespace"
user := "pre-auth-key-without-exp-user"
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
namespace: 0,
user: 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipaknaexp"))
@ -273,8 +273,8 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"create",
"--reusable",
"--output",
@ -290,8 +290,8 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"list",
"--output",
"json",
@ -317,13 +317,13 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
namespace := "pre-auth-key-reus-ephm-namespace"
user := "pre-auth-key-reus-ephm-user"
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
namespace: 0,
user: 0,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipakresueeph"))
@ -338,8 +338,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"create",
"--reusable=true",
"--output",
@ -355,8 +355,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"create",
"--ephemeral=true",
"--output",
@ -375,8 +375,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace,
"--user",
user,
"list",
"--output",
"json",
@ -396,13 +396,13 @@ func TestEnablingRoutes(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
namespace := "enable-routing"
user := "enable-routing"
scenario, err := NewScenario()
assert.NoError(t, err)
spec := map[string]int{
namespace: 3,
user: 3,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clienableroute"))

View file

@ -10,9 +10,9 @@ type ControlServer interface {
GetHealthEndpoint() string
GetEndpoint() string
WaitForReady() error
CreateNamespace(namespace string) error
CreateAuthKey(namespace string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
ListMachinesInNamespace(namespace string) ([]*v1.Machine, error)
CreateUser(user string) error
CreateAuthKey(user string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error)
ListMachinesInUser(user string) ([]*v1.Machine, error)
GetCert() []byte
GetHostname() string
GetIP() string

View file

@ -22,8 +22,8 @@ func TestPingAllByIP(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions),
"user1": len(TailscaleVersions),
"user2": len(TailscaleVersions),
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyip"))
@ -77,8 +77,8 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions),
"user1": len(TailscaleVersions),
"user2": len(TailscaleVersions),
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyip"))
@ -121,15 +121,15 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) {
t.Errorf("failed to get headscale server: %s", err)
}
for namespaceName := range spec {
key, err := scenario.CreatePreAuthKey(namespaceName, true, false)
for userName := range spec {
key, err := scenario.CreatePreAuthKey(userName, true, false)
if err != nil {
t.Errorf("failed to create pre-auth key for namespace %s: %s", namespaceName, err)
t.Errorf("failed to create pre-auth key for user %s: %s", userName, err)
}
err = scenario.RunTailscaleUp(namespaceName, headscale.GetEndpoint(), key.GetKey())
err = scenario.RunTailscaleUp(userName, headscale.GetEndpoint(), key.GetKey())
if err != nil {
t.Errorf("failed to run tailscale up for namespace %s: %s", namespaceName, err)
t.Errorf("failed to run tailscale up for user %s: %s", userName, err)
}
}
@ -207,8 +207,8 @@ func TestEphemeral(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions),
"user1": len(TailscaleVersions),
"user2": len(TailscaleVersions),
}
headscale, err := scenario.Headscale(hsic.WithTestName("ephemeral"))
@ -216,25 +216,25 @@ func TestEphemeral(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err)
}
for namespaceName, clientCount := range spec {
err = scenario.CreateNamespace(namespaceName)
for userName, clientCount := range spec {
err = scenario.CreateUser(userName)
if err != nil {
t.Errorf("failed to create namespace %s: %s", namespaceName, err)
t.Errorf("failed to create user %s: %s", userName, err)
}
err = scenario.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount, []tsic.Option{}...)
err = scenario.CreateTailscaleNodesInUser(userName, "all", clientCount, []tsic.Option{}...)
if err != nil {
t.Errorf("failed to create tailscale nodes in namespace %s: %s", namespaceName, err)
t.Errorf("failed to create tailscale nodes in user %s: %s", userName, err)
}
key, err := scenario.CreatePreAuthKey(namespaceName, true, true)
key, err := scenario.CreatePreAuthKey(userName, true, true)
if err != nil {
t.Errorf("failed to create pre-auth key for namespace %s: %s", namespaceName, err)
t.Errorf("failed to create pre-auth key for user %s: %s", userName, err)
}
err = scenario.RunTailscaleUp(namespaceName, headscale.GetEndpoint(), key.GetKey())
err = scenario.RunTailscaleUp(userName, headscale.GetEndpoint(), key.GetKey())
if err != nil {
t.Errorf("failed to run tailscale up for namespace %s: %s", namespaceName, err)
t.Errorf("failed to run tailscale up for user %s: %s", userName, err)
}
}
@ -278,19 +278,19 @@ func TestEphemeral(t *testing.T) {
t.Logf("all clients logged out")
for namespaceName := range spec {
machines, err := headscale.ListMachinesInNamespace(namespaceName)
for userName := range spec {
machines, err := headscale.ListMachinesInUser(userName)
if err != nil {
log.Error().
Err(err).
Str("namespace", namespaceName).
Msg("Error listing machines in namespace")
Str("user", userName).
Msg("Error listing machines in user")
return
}
if len(machines) != 0 {
t.Errorf("expected no machines, got %d in namespace %s", len(machines), namespaceName)
t.Errorf("expected no machines, got %d in user %s", len(machines), userName)
}
}
@ -311,8 +311,8 @@ func TestPingAllByHostname(t *testing.T) {
spec := map[string]int{
// Omit 1.16.2 (-1) because it does not have the FQDN field
"namespace3": len(TailscaleVersions) - 1,
"namespace4": len(TailscaleVersions) - 1,
"user3": len(TailscaleVersions) - 1,
"user4": len(TailscaleVersions) - 1,
}
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyname"))

View file

@ -328,10 +328,10 @@ func (t *HeadscaleInContainer) WaitForReady() error {
})
}
func (t *HeadscaleInContainer) CreateNamespace(
namespace string,
func (t *HeadscaleInContainer) CreateUser(
user string,
) error {
command := []string{"headscale", "namespaces", "create", namespace}
command := []string{"headscale", "users", "create", user}
_, _, err := dockertestutil.ExecuteCommand(
t.container,
@ -346,14 +346,14 @@ func (t *HeadscaleInContainer) CreateNamespace(
}
func (t *HeadscaleInContainer) CreateAuthKey(
namespace string,
user string,
reusable bool,
ephemeral bool,
) (*v1.PreAuthKey, error) {
command := []string{
"headscale",
"--namespace",
namespace,
"--user",
user,
"preauthkeys",
"create",
"--expiration",
@ -388,10 +388,10 @@ func (t *HeadscaleInContainer) CreateAuthKey(
return &preAuthKey, nil
}
func (t *HeadscaleInContainer) ListMachinesInNamespace(
namespace string,
func (t *HeadscaleInContainer) ListMachinesInUser(
user string,
) ([]*v1.Machine, error) {
command := []string{"headscale", "--namespace", namespace, "nodes", "list", "--output", "json"}
command := []string{"headscale", "--user", user, "nodes", "list", "--output", "json"}
result, _, err := dockertestutil.ExecuteCommand(
t.container,

View file

@ -25,7 +25,7 @@ const (
var (
errNoHeadscaleAvailable = errors.New("no headscale available")
errNoNamespaceAvailable = errors.New("no namespace available")
errNoUserAvailable = errors.New("no user available")
// Tailscale started adding TS2021 support in CapabilityVersion>=28 (v1.24.0), but
// proper support in Headscale was only added for CapabilityVersion>=39 clients (v1.30.0).
@ -61,7 +61,7 @@ var (
)
)
type Namespace struct {
type User struct {
Clients map[string]TailscaleClient
createWaitGroup sync.WaitGroup
@ -75,7 +75,7 @@ type Scenario struct {
// use one.
controlServers *xsync.MapOf[string, ControlServer]
namespaces map[string]*Namespace
users map[string]*User
pool *dockertest.Pool
network *dockertest.Network
@ -116,7 +116,7 @@ func NewScenario() (*Scenario, error) {
return &Scenario{
controlServers: xsync.NewMapOf[ControlServer](),
namespaces: make(map[string]*Namespace),
users: make(map[string]*User),
pool: pool,
network: network,
@ -136,9 +136,9 @@ func (s *Scenario) Shutdown() error {
return true
})
for namespaceName, namespace := range s.namespaces {
for _, client := range namespace.Clients {
log.Printf("removing client %s in namespace %s", client.Hostname(), namespaceName)
for userName, user := range s.users {
for _, client := range user.Clients {
log.Printf("removing client %s in user %s", client.Hostname(), userName)
err := client.Shutdown()
if err != nil {
return fmt.Errorf("failed to tear down client: %w", err)
@ -158,13 +158,13 @@ func (s *Scenario) Shutdown() error {
return nil
}
func (s *Scenario) Namespaces() []string {
namespaces := make([]string, 0)
for namespace := range s.namespaces {
namespaces = append(namespaces, namespace)
func (s *Scenario) Users() []string {
users := make([]string, 0)
for user := range s.users {
users = append(users, user)
}
return namespaces
return users
}
/// Headscale related stuff
@ -194,45 +194,45 @@ func (s *Scenario) Headscale(opts ...hsic.Option) (ControlServer, error) {
return headscale, nil
}
func (s *Scenario) CreatePreAuthKey(namespace string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error) {
func (s *Scenario) CreatePreAuthKey(user string, reusable bool, ephemeral bool) (*v1.PreAuthKey, error) {
if headscale, err := s.Headscale(); err == nil {
key, err := headscale.CreateAuthKey(namespace, reusable, ephemeral)
key, err := headscale.CreateAuthKey(user, reusable, ephemeral)
if err != nil {
return nil, fmt.Errorf("failed to create namespace: %w", err)
return nil, fmt.Errorf("failed to create user: %w", err)
}
return key, nil
}
return nil, fmt.Errorf("failed to create namespace: %w", errNoHeadscaleAvailable)
return nil, fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable)
}
func (s *Scenario) CreateNamespace(namespace string) error {
func (s *Scenario) CreateUser(user string) error {
if headscale, err := s.Headscale(); err == nil {
err := headscale.CreateNamespace(namespace)
err := headscale.CreateUser(user)
if err != nil {
return fmt.Errorf("failed to create namespace: %w", err)
return fmt.Errorf("failed to create user: %w", err)
}
s.namespaces[namespace] = &Namespace{
s.users[user] = &User{
Clients: make(map[string]TailscaleClient),
}
return nil
}
return fmt.Errorf("failed to create namespace: %w", errNoHeadscaleAvailable)
return fmt.Errorf("failed to create user: %w", errNoHeadscaleAvailable)
}
/// Client related stuff
func (s *Scenario) CreateTailscaleNodesInNamespace(
namespaceStr string,
func (s *Scenario) CreateTailscaleNodesInUser(
userStr string,
requestedVersion string,
count int,
opts ...tsic.Option,
) error {
if namespace, ok := s.namespaces[namespaceStr]; ok {
if user, ok := s.users[userStr]; ok {
for i := 0; i < count; i++ {
version := requestedVersion
if requestedVersion == "all" {
@ -247,7 +247,7 @@ func (s *Scenario) CreateTailscaleNodesInNamespace(
cert := headscale.GetCert()
hostname := headscale.GetHostname()
namespace.createWaitGroup.Add(1)
user.createWaitGroup.Add(1)
opts = append(opts,
tsic.WithHeadscaleTLS(cert),
@ -255,7 +255,7 @@ func (s *Scenario) CreateTailscaleNodesInNamespace(
)
go func() {
defer namespace.createWaitGroup.Done()
defer user.createWaitGroup.Done()
// TODO(kradalby): error handle this
tsClient, err := tsic.New(
@ -275,26 +275,26 @@ func (s *Scenario) CreateTailscaleNodesInNamespace(
log.Printf("failed to wait for tailscaled: %s", err)
}
namespace.Clients[tsClient.Hostname()] = tsClient
user.Clients[tsClient.Hostname()] = tsClient
}()
}
namespace.createWaitGroup.Wait()
user.createWaitGroup.Wait()
return nil
}
return fmt.Errorf("failed to add tailscale node: %w", errNoNamespaceAvailable)
return fmt.Errorf("failed to add tailscale node: %w", errNoUserAvailable)
}
func (s *Scenario) RunTailscaleUp(
namespaceStr, loginServer, authKey string,
userStr, loginServer, authKey string,
) error {
if namespace, ok := s.namespaces[namespaceStr]; ok {
for _, client := range namespace.Clients {
namespace.joinWaitGroup.Add(1)
if user, ok := s.users[userStr]; ok {
for _, client := range user.Clients {
user.joinWaitGroup.Add(1)
go func(c TailscaleClient) {
defer namespace.joinWaitGroup.Done()
defer user.joinWaitGroup.Done()
// TODO(kradalby): error handle this
_ = c.Up(loginServer, authKey)
@ -306,19 +306,19 @@ func (s *Scenario) RunTailscaleUp(
}
}
namespace.joinWaitGroup.Wait()
user.joinWaitGroup.Wait()
return nil
}
return fmt.Errorf("failed to up tailscale node: %w", errNoNamespaceAvailable)
return fmt.Errorf("failed to up tailscale node: %w", errNoUserAvailable)
}
func (s *Scenario) CountTailscale() int {
count := 0
for _, namespace := range s.namespaces {
count += len(namespace.Clients)
for _, user := range s.users {
count += len(user.Clients)
}
return count
@ -327,18 +327,18 @@ func (s *Scenario) CountTailscale() int {
func (s *Scenario) WaitForTailscaleSync() error {
tsCount := s.CountTailscale()
for _, namespace := range s.namespaces {
for _, client := range namespace.Clients {
namespace.syncWaitGroup.Add(1)
for _, user := range s.users {
for _, client := range user.Clients {
user.syncWaitGroup.Add(1)
go func(c TailscaleClient) {
defer namespace.syncWaitGroup.Done()
defer user.syncWaitGroup.Done()
// TODO(kradalby): error handle this
_ = c.WaitForPeers(tsCount)
}(client)
}
namespace.syncWaitGroup.Wait()
user.syncWaitGroup.Wait()
}
return nil
@ -346,9 +346,9 @@ func (s *Scenario) WaitForTailscaleSync() error {
// CreateHeadscaleEnv is a conventient method returning a set up Headcale
// test environment with nodes of all versions, joined to the server with X
// namespaces.
// users.
func (s *Scenario) CreateHeadscaleEnv(
namespaces map[string]int,
users map[string]int,
tsOpts []tsic.Option,
opts ...hsic.Option,
) error {
@ -357,23 +357,23 @@ func (s *Scenario) CreateHeadscaleEnv(
return err
}
for namespaceName, clientCount := range namespaces {
err = s.CreateNamespace(namespaceName)
for userName, clientCount := range users {
err = s.CreateUser(userName)
if err != nil {
return err
}
err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount, tsOpts...)
err = s.CreateTailscaleNodesInUser(userName, "all", clientCount, tsOpts...)
if err != nil {
return err
}
key, err := s.CreatePreAuthKey(namespaceName, true, false)
key, err := s.CreatePreAuthKey(userName, true, false)
if err != nil {
return err
}
err = s.RunTailscaleUp(namespaceName, headscale.GetEndpoint(), key.GetKey())
err = s.RunTailscaleUp(userName, headscale.GetEndpoint(), key.GetKey())
if err != nil {
return err
}
@ -382,9 +382,9 @@ func (s *Scenario) CreateHeadscaleEnv(
return nil
}
func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) {
func (s *Scenario) GetIPs(user string) ([]netip.Addr, error) {
var ips []netip.Addr
if ns, ok := s.namespaces[namespace]; ok {
if ns, ok := s.users[user]; ok {
for _, client := range ns.Clients {
clientIps, err := client.IPs()
if err != nil {
@ -396,12 +396,12 @@ func (s *Scenario) GetIPs(namespace string) ([]netip.Addr, error) {
return ips, nil
}
return ips, fmt.Errorf("failed to get ips: %w", errNoNamespaceAvailable)
return ips, fmt.Errorf("failed to get ips: %w", errNoUserAvailable)
}
func (s *Scenario) GetClients(namespace string) ([]TailscaleClient, error) {
func (s *Scenario) GetClients(user string) ([]TailscaleClient, error) {
var clients []TailscaleClient
if ns, ok := s.namespaces[namespace]; ok {
if ns, ok := s.users[user]; ok {
for _, client := range ns.Clients {
clients = append(clients, client)
}
@ -409,18 +409,18 @@ func (s *Scenario) GetClients(namespace string) ([]TailscaleClient, error) {
return clients, nil
}
return clients, fmt.Errorf("failed to get clients: %w", errNoNamespaceAvailable)
return clients, fmt.Errorf("failed to get clients: %w", errNoUserAvailable)
}
func (s *Scenario) ListTailscaleClients(namespaces ...string) ([]TailscaleClient, error) {
func (s *Scenario) ListTailscaleClients(users ...string) ([]TailscaleClient, error) {
var allClients []TailscaleClient
if len(namespaces) == 0 {
namespaces = s.Namespaces()
if len(users) == 0 {
users = s.Users()
}
for _, namespace := range namespaces {
clients, err := s.GetClients(namespace)
for _, user := range users {
clients, err := s.GetClients(user)
if err != nil {
return nil, err
}
@ -431,15 +431,15 @@ func (s *Scenario) ListTailscaleClients(namespaces ...string) ([]TailscaleClient
return allClients, nil
}
func (s *Scenario) ListTailscaleClientsIPs(namespaces ...string) ([]netip.Addr, error) {
func (s *Scenario) ListTailscaleClientsIPs(users ...string) ([]netip.Addr, error) {
var allIps []netip.Addr
if len(namespaces) == 0 {
namespaces = s.Namespaces()
if len(users) == 0 {
users = s.Users()
}
for _, namespace := range namespaces {
ips, err := s.GetIPs(namespace)
for _, user := range users {
ips, err := s.GetIPs(user)
if err != nil {
return nil, err
}
@ -450,10 +450,10 @@ func (s *Scenario) ListTailscaleClientsIPs(namespaces ...string) ([]netip.Addr,
return allIps, nil
}
func (s *Scenario) ListTailscaleClientsFQDNs(namespaces ...string) ([]string, error) {
func (s *Scenario) ListTailscaleClientsFQDNs(users ...string) ([]string, error) {
allFQDNs := make([]string, 0)
clients, err := s.ListTailscaleClients(namespaces...)
clients, err := s.ListTailscaleClients(users...)
if err != nil {
return nil, err
}
@ -471,17 +471,17 @@ func (s *Scenario) ListTailscaleClientsFQDNs(namespaces ...string) ([]string, er
}
func (s *Scenario) WaitForTailscaleLogout() {
for _, namespace := range s.namespaces {
for _, client := range namespace.Clients {
namespace.syncWaitGroup.Add(1)
for _, user := range s.users {
for _, client := range user.Clients {
user.syncWaitGroup.Add(1)
go func(c TailscaleClient) {
defer namespace.syncWaitGroup.Done()
defer user.syncWaitGroup.Done()
// TODO(kradalby): error handle this
_ = c.WaitForLogout()
}(client)
}
namespace.syncWaitGroup.Wait()
user.syncWaitGroup.Wait()
}
}

View file

@ -31,7 +31,7 @@ func TestHeadscale(t *testing.T) {
var err error
namespace := "test-space"
user := "test-space"
scenario, err := NewScenario()
if err != nil {
@ -50,19 +50,19 @@ func TestHeadscale(t *testing.T) {
}
})
t.Run("create-namespace", func(t *testing.T) {
err := scenario.CreateNamespace(namespace)
t.Run("create-user", func(t *testing.T) {
err := scenario.CreateUser(user)
if err != nil {
t.Errorf("failed to create namespace: %s", err)
t.Errorf("failed to create user: %s", err)
}
if _, ok := scenario.namespaces[namespace]; !ok {
t.Errorf("namespace is not in scenario")
if _, ok := scenario.users[user]; !ok {
t.Errorf("user is not in scenario")
}
})
t.Run("create-auth-key", func(t *testing.T) {
_, err := scenario.CreatePreAuthKey(namespace, true, false)
_, err := scenario.CreatePreAuthKey(user, true, false)
if err != nil {
t.Errorf("failed to create preauthkey: %s", err)
}
@ -82,24 +82,24 @@ func TestCreateTailscale(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
namespace := "only-create-containers"
user := "only-create-containers"
scenario, err := NewScenario()
if err != nil {
t.Errorf("failed to create scenario: %s", err)
}
scenario.namespaces[namespace] = &Namespace{
scenario.users[user] = &User{
Clients: make(map[string]TailscaleClient),
}
t.Run("create-tailscale", func(t *testing.T) {
err := scenario.CreateTailscaleNodesInNamespace(namespace, "all", 3)
err := scenario.CreateTailscaleNodesInUser(user, "all", 3)
if err != nil {
t.Errorf("failed to add tailscale nodes: %s", err)
}
if clients := len(scenario.namespaces[namespace].Clients); clients != 3 {
if clients := len(scenario.users[user].Clients); clients != 3 {
t.Errorf("wrong number of tailscale clients: %d != %d", clients, 3)
}
@ -122,7 +122,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
var err error
namespace := "join-node-test"
user := "join-node-test"
count := 1
@ -143,30 +143,30 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
}
})
t.Run("create-namespace", func(t *testing.T) {
err := scenario.CreateNamespace(namespace)
t.Run("create-user", func(t *testing.T) {
err := scenario.CreateUser(user)
if err != nil {
t.Errorf("failed to create namespace: %s", err)
t.Errorf("failed to create user: %s", err)
}
if _, ok := scenario.namespaces[namespace]; !ok {
t.Errorf("namespace is not in scenario")
if _, ok := scenario.users[user]; !ok {
t.Errorf("user is not in scenario")
}
})
t.Run("create-tailscale", func(t *testing.T) {
err := scenario.CreateTailscaleNodesInNamespace(namespace, "1.30.2", count)
err := scenario.CreateTailscaleNodesInUser(user, "1.30.2", count)
if err != nil {
t.Errorf("failed to add tailscale nodes: %s", err)
}
if clients := len(scenario.namespaces[namespace].Clients); clients != count {
if clients := len(scenario.users[user].Clients); clients != count {
t.Errorf("wrong number of tailscale clients: %d != %d", clients, count)
}
})
t.Run("join-headscale", func(t *testing.T) {
key, err := scenario.CreatePreAuthKey(namespace, true, false)
key, err := scenario.CreatePreAuthKey(user, true, false)
if err != nil {
t.Errorf("failed to create preauthkey: %s", err)
}
@ -177,7 +177,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
}
err = scenario.RunTailscaleUp(
namespace,
user,
headscale.GetEndpoint(),
key.GetKey(),
)
@ -187,7 +187,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
})
t.Run("get-ips", func(t *testing.T) {
ips, err := scenario.GetIPs(namespace)
ips, err := scenario.GetIPs(user)
if err != nil {
t.Errorf("failed to get tailscale ips: %s", err)
}

View file

@ -41,7 +41,7 @@ var retry = func(times int, sleepInterval time.Duration,
return result, stderr, err
}
func TestSSHOneNamespaceAllToAll(t *testing.T) {
func TestSSHOneUserAllToAll(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
@ -51,7 +51,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5,
"user1": len(TailscaleVersions) - 5,
}
err = scenario.CreateHeadscaleEnv(spec,
@ -59,7 +59,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
hsic.WithACLPolicy(
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"namespace1"},
"group:integration-test": {"user1"},
},
ACLs: []headscale.ACL{
{
@ -117,7 +117,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
}
}
func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
func TestSSHMultipleUsersAllToAll(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
@ -127,8 +127,8 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5,
"namespace2": len(TailscaleVersions) - 5,
"user1": len(TailscaleVersions) - 5,
"user2": len(TailscaleVersions) - 5,
}
err = scenario.CreateHeadscaleEnv(spec,
@ -136,7 +136,7 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
hsic.WithACLPolicy(
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"namespace1", "namespace2"},
"group:integration-test": {"user1", "user2"},
},
ACLs: []headscale.ACL{
{
@ -163,12 +163,12 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err)
}
nsOneClients, err := scenario.ListTailscaleClients("namespace1")
nsOneClients, err := scenario.ListTailscaleClients("user1")
if err != nil {
t.Errorf("failed to get clients: %s", err)
}
nsTwoClients, err := scenario.ListTailscaleClients("namespace2")
nsTwoClients, err := scenario.ListTailscaleClients("user2")
if err != nil {
t.Errorf("failed to get clients: %s", err)
}
@ -183,7 +183,7 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
t.Errorf("failed to get FQDNs: %s", err)
}
testInterNamespaceSSH := func(sourceClients []TailscaleClient, targetClients []TailscaleClient) {
testInterUserSSH := func(sourceClients []TailscaleClient, targetClients []TailscaleClient) {
for _, client := range sourceClients {
for _, peer := range targetClients {
assertSSHHostname(t, client, peer)
@ -191,8 +191,8 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
}
}
testInterNamespaceSSH(nsOneClients, nsTwoClients)
testInterNamespaceSSH(nsTwoClients, nsOneClients)
testInterUserSSH(nsOneClients, nsTwoClients)
testInterUserSSH(nsTwoClients, nsOneClients)
err = scenario.Shutdown()
if err != nil {
@ -210,7 +210,7 @@ func TestSSHNoSSHConfigured(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5,
"user1": len(TailscaleVersions) - 5,
}
err = scenario.CreateHeadscaleEnv(spec,
@ -218,7 +218,7 @@ func TestSSHNoSSHConfigured(t *testing.T) {
hsic.WithACLPolicy(
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"namespace1"},
"group:integration-test": {"user1"},
},
ACLs: []headscale.ACL{
{
@ -280,7 +280,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
}
spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5,
"user1": len(TailscaleVersions) - 5,
}
err = scenario.CreateHeadscaleEnv(spec,
@ -288,7 +288,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
hsic.WithACLPolicy(
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:integration-test": {"namespace1"},
"group:integration-test": {"user1"},
},
ACLs: []headscale.ACL{
{
@ -347,7 +347,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
}
}
func TestSSNamespaceOnlyIsolation(t *testing.T) {
func TestSSUserOnlyIsolation(t *testing.T) {
IntegrationSkip(t)
t.Parallel()
@ -357,8 +357,8 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
}
spec := map[string]int{
"namespaceacl1": len(TailscaleVersions) - 5,
"namespaceacl2": len(TailscaleVersions) - 5,
"useracl1": len(TailscaleVersions) - 5,
"useracl2": len(TailscaleVersions) - 5,
}
err = scenario.CreateHeadscaleEnv(spec,
@ -366,8 +366,8 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
hsic.WithACLPolicy(
&headscale.ACLPolicy{
Groups: map[string][]string{
"group:ssh1": {"namespaceacl1"},
"group:ssh2": {"namespaceacl2"},
"group:ssh1": {"useracl1"},
"group:ssh2": {"useracl2"},
},
ACLs: []headscale.ACL{
{
@ -392,7 +392,7 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
},
},
),
hsic.WithTestName("sshtwonamespaceaclblock"),
hsic.WithTestName("sshtwouseraclblock"),
hsic.WithConfigEnv(map[string]string{
"HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1",
}),
@ -401,12 +401,12 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err)
}
ssh1Clients, err := scenario.ListTailscaleClients("namespaceacl1")
ssh1Clients, err := scenario.ListTailscaleClients("useracl1")
if err != nil {
t.Errorf("failed to get clients: %s", err)
}
ssh2Clients, err := scenario.ListTailscaleClients("namespaceacl2")
ssh2Clients, err := scenario.ListTailscaleClients("useracl2")
if err != nil {
t.Errorf("failed to get clients: %s", err)
}

View file

@ -138,12 +138,12 @@ func (s *IntegrationCLITestSuite) HandleStats(
s.stats = stats
}
func (s *IntegrationCLITestSuite) createNamespace(name string) (*v1.Namespace, error) {
func (s *IntegrationCLITestSuite) createUser(name string) (*v1.User, error) {
result, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"namespaces",
"users",
"create",
name,
"--output",
@ -155,38 +155,38 @@ func (s *IntegrationCLITestSuite) createNamespace(name string) (*v1.Namespace, e
return nil, err
}
var namespace v1.Namespace
err = json.Unmarshal([]byte(result), &namespace)
var user v1.User
err = json.Unmarshal([]byte(result), &user)
if err != nil {
return nil, err
}
return &namespace, nil
return &user, nil
}
func (s *IntegrationCLITestSuite) TestNamespaceCommand() {
names := []string{"namespace1", "otherspace", "tasty"}
namespaces := make([]*v1.Namespace, len(names))
func (s *IntegrationCLITestSuite) TestUserCommand() {
names := []string{"user1", "otherspace", "tasty"}
users := make([]*v1.User, len(names))
for index, namespaceName := range names {
namespace, err := s.createNamespace(namespaceName)
for index, userName := range names {
user, err := s.createUser(userName)
assert.Nil(s.T(), err)
namespaces[index] = namespace
users[index] = user
}
assert.Len(s.T(), namespaces, len(names))
assert.Len(s.T(), users, len(names))
assert.Equal(s.T(), names[0], namespaces[0].Name)
assert.Equal(s.T(), names[1], namespaces[1].Name)
assert.Equal(s.T(), names[2], namespaces[2].Name)
assert.Equal(s.T(), names[0], users[0].Name)
assert.Equal(s.T(), names[1], users[1].Name)
assert.Equal(s.T(), names[2], users[2].Name)
// Test list namespaces
// Test list users
listResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"namespaces",
"users",
"list",
"--output",
"json",
@ -195,20 +195,20 @@ func (s *IntegrationCLITestSuite) TestNamespaceCommand() {
)
assert.Nil(s.T(), err)
var listedNamespaces []v1.Namespace
err = json.Unmarshal([]byte(listResult), &listedNamespaces)
var listedUsers []v1.User
err = json.Unmarshal([]byte(listResult), &listedUsers)
assert.Nil(s.T(), err)
assert.Equal(s.T(), names[0], listedNamespaces[0].Name)
assert.Equal(s.T(), names[1], listedNamespaces[1].Name)
assert.Equal(s.T(), names[2], listedNamespaces[2].Name)
assert.Equal(s.T(), names[0], listedUsers[0].Name)
assert.Equal(s.T(), names[1], listedUsers[1].Name)
assert.Equal(s.T(), names[2], listedUsers[2].Name)
// Test rename namespace
// Test rename user
renameResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"namespaces",
"users",
"rename",
"--output",
"json",
@ -219,18 +219,18 @@ func (s *IntegrationCLITestSuite) TestNamespaceCommand() {
)
assert.Nil(s.T(), err)
var renamedNamespace v1.Namespace
err = json.Unmarshal([]byte(renameResult), &renamedNamespace)
var renamedUser v1.User
err = json.Unmarshal([]byte(renameResult), &renamedUser)
assert.Nil(s.T(), err)
assert.Equal(s.T(), renamedNamespace.Name, "newname")
assert.Equal(s.T(), renamedUser.Name, "newname")
// Test list after rename namespaces
// Test list after rename users
listAfterRenameResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"namespaces",
"users",
"list",
"--output",
"json",
@ -239,19 +239,19 @@ func (s *IntegrationCLITestSuite) TestNamespaceCommand() {
)
assert.Nil(s.T(), err)
var listedAfterRenameNamespaces []v1.Namespace
err = json.Unmarshal([]byte(listAfterRenameResult), &listedAfterRenameNamespaces)
var listedAfterRenameUsers []v1.User
err = json.Unmarshal([]byte(listAfterRenameResult), &listedAfterRenameUsers)
assert.Nil(s.T(), err)
assert.Equal(s.T(), names[0], listedAfterRenameNamespaces[0].Name)
assert.Equal(s.T(), names[1], listedAfterRenameNamespaces[1].Name)
assert.Equal(s.T(), "newname", listedAfterRenameNamespaces[2].Name)
assert.Equal(s.T(), names[0], listedAfterRenameUsers[0].Name)
assert.Equal(s.T(), names[1], listedAfterRenameUsers[1].Name)
assert.Equal(s.T(), "newname", listedAfterRenameUsers[2].Name)
}
func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
count := 5
namespace, err := s.createNamespace("pre-auth-key-namespace")
user, err := s.createUser("pre-auth-key-user")
keys := make([]*v1.PreAuthKey, count)
assert.Nil(s.T(), err)
@ -262,8 +262,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"create",
"--reusable",
"--expiration",
@ -292,8 +292,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"list",
"--output",
"json",
@ -357,8 +357,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"expire",
listedPreAuthKeys[i].Key,
},
@ -373,8 +373,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"list",
"--output",
"json",
@ -410,7 +410,7 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommand() {
}
func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() {
namespace, err := s.createNamespace("pre-auth-key-without-exp-namespace")
user, err := s.createUser("pre-auth-key-without-exp-user")
assert.Nil(s.T(), err)
preAuthResult, _, err := ExecuteCommand(
@ -418,8 +418,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"create",
"--reusable",
"--output",
@ -439,8 +439,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"list",
"--output",
"json",
@ -463,7 +463,7 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandWithoutExpiry() {
}
func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
namespace, err := s.createNamespace("pre-auth-key-reus-ephm-namespace")
user, err := s.createUser("pre-auth-key-reus-ephm-user")
assert.Nil(s.T(), err)
preAuthReusableResult, _, err := ExecuteCommand(
@ -471,8 +471,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"create",
"--reusable=true",
"--output",
@ -494,8 +494,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"create",
"--ephemeral=true",
"--output",
@ -518,8 +518,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
// []string{
// "headscale",
// "preauthkeys",
// "--namespace",
// namespace.Name,
// "--user",
// user.Name,
// "create",
// "--ephemeral",
// "--reusable",
@ -536,8 +536,8 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
[]string{
"headscale",
"preauthkeys",
"--namespace",
namespace.Name,
"--user",
user.Name,
"list",
"--output",
"json",
@ -554,7 +554,7 @@ func (s *IntegrationCLITestSuite) TestPreAuthKeyCommandReusableEphemeral() {
}
func (s *IntegrationCLITestSuite) TestNodeTagCommand() {
namespace, err := s.createNamespace("machine-namespace")
user, err := s.createUser("machine-user")
assert.Nil(s.T(), err)
machineKeys := []string{
@ -573,8 +573,8 @@ func (s *IntegrationCLITestSuite) TestNodeTagCommand() {
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--namespace",
namespace.Name,
"--user",
user.Name,
"--key",
machineKey,
"--output",
@ -589,8 +589,8 @@ func (s *IntegrationCLITestSuite) TestNodeTagCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
namespace.Name,
"--user",
user.Name,
"register",
"--key",
machineKey,
@ -683,10 +683,10 @@ func (s *IntegrationCLITestSuite) TestNodeTagCommand() {
}
func (s *IntegrationCLITestSuite) TestNodeCommand() {
namespace, err := s.createNamespace("machine-namespace")
user, err := s.createUser("machine-user")
assert.Nil(s.T(), err)
secondNamespace, err := s.createNamespace("other-namespace")
secondUser, err := s.createUser("other-user")
assert.Nil(s.T(), err)
// Randomly generated machine keys
@ -709,8 +709,8 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--namespace",
namespace.Name,
"--user",
user.Name,
"--key",
machineKey,
"--output",
@ -725,8 +725,8 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
namespace.Name,
"--user",
user.Name,
"register",
"--key",
machineKey,
@ -778,14 +778,14 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
assert.Equal(s.T(), "machine-4", listAll[3].Name)
assert.Equal(s.T(), "machine-5", listAll[4].Name)
otherNamespaceMachineKeys := []string{
otherUserMachineKeys := []string{
"nodekey:b5b444774186d4217adcec407563a1223929465ee2c68a4da13af0d0185b4f8e",
"nodekey:dc721977ac7415aafa87f7d4574cbe07c6b171834a6d37375782bdc1fb6b3584",
}
otherNamespaceMachines := make([]*v1.Machine, len(otherNamespaceMachineKeys))
otherUserMachines := make([]*v1.Machine, len(otherUserMachineKeys))
assert.Nil(s.T(), err)
for index, machineKey := range otherNamespaceMachineKeys {
for index, machineKey := range otherUserMachineKeys {
_, _, err := ExecuteCommand(
&s.headscale,
[]string{
@ -793,9 +793,9 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
"debug",
"create-node",
"--name",
fmt.Sprintf("otherNamespace-machine-%d", index+1),
"--namespace",
secondNamespace.Name,
fmt.Sprintf("otherUser-machine-%d", index+1),
"--user",
secondUser.Name,
"--key",
machineKey,
"--output",
@ -810,8 +810,8 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
secondNamespace.Name,
"--user",
secondUser.Name,
"register",
"--key",
machineKey,
@ -826,13 +826,13 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
err = json.Unmarshal([]byte(machineResult), &machine)
assert.Nil(s.T(), err)
otherNamespaceMachines[index] = &machine
otherUserMachines[index] = &machine
}
assert.Len(s.T(), otherNamespaceMachines, len(otherNamespaceMachineKeys))
assert.Len(s.T(), otherUserMachines, len(otherUserMachineKeys))
// Test list all nodes after added otherNamespace
listAllWithotherNamespaceResult, _, err := ExecuteCommand(
// Test list all nodes after added otherUser
listAllWithotherUserResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
@ -845,31 +845,31 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
)
assert.Nil(s.T(), err)
var listAllWithotherNamespace []v1.Machine
var listAllWithotherUser []v1.Machine
err = json.Unmarshal(
[]byte(listAllWithotherNamespaceResult),
&listAllWithotherNamespace,
[]byte(listAllWithotherUserResult),
&listAllWithotherUser,
)
assert.Nil(s.T(), err)
// All nodes, machines + otherNamespace
assert.Len(s.T(), listAllWithotherNamespace, 7)
// All nodes, machines + otherUser
assert.Len(s.T(), listAllWithotherUser, 7)
assert.Equal(s.T(), uint64(6), listAllWithotherNamespace[5].Id)
assert.Equal(s.T(), uint64(7), listAllWithotherNamespace[6].Id)
assert.Equal(s.T(), uint64(6), listAllWithotherUser[5].Id)
assert.Equal(s.T(), uint64(7), listAllWithotherUser[6].Id)
assert.Equal(s.T(), "otherNamespace-machine-1", listAllWithotherNamespace[5].Name)
assert.Equal(s.T(), "otherNamespace-machine-2", listAllWithotherNamespace[6].Name)
assert.Equal(s.T(), "otherUser-machine-1", listAllWithotherUser[5].Name)
assert.Equal(s.T(), "otherUser-machine-2", listAllWithotherUser[6].Name)
// Test list all nodes after added otherNamespace
listOnlyotherNamespaceMachineNamespaceResult, _, err := ExecuteCommand(
// Test list all nodes after added otherUser
listOnlyotherUserMachineUserResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"nodes",
"list",
"--namespace",
secondNamespace.Name,
"--user",
secondUser.Name,
"--output",
"json",
},
@ -877,27 +877,27 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
)
assert.Nil(s.T(), err)
var listOnlyotherNamespaceMachineNamespace []v1.Machine
var listOnlyotherUserMachineUser []v1.Machine
err = json.Unmarshal(
[]byte(listOnlyotherNamespaceMachineNamespaceResult),
&listOnlyotherNamespaceMachineNamespace,
[]byte(listOnlyotherUserMachineUserResult),
&listOnlyotherUserMachineUser,
)
assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlyotherNamespaceMachineNamespace, 2)
assert.Len(s.T(), listOnlyotherUserMachineUser, 2)
assert.Equal(s.T(), uint64(6), listOnlyotherNamespaceMachineNamespace[0].Id)
assert.Equal(s.T(), uint64(7), listOnlyotherNamespaceMachineNamespace[1].Id)
assert.Equal(s.T(), uint64(6), listOnlyotherUserMachineUser[0].Id)
assert.Equal(s.T(), uint64(7), listOnlyotherUserMachineUser[1].Id)
assert.Equal(
s.T(),
"otherNamespace-machine-1",
listOnlyotherNamespaceMachineNamespace[0].Name,
"otherUser-machine-1",
listOnlyotherUserMachineUser[0].Name,
)
assert.Equal(
s.T(),
"otherNamespace-machine-2",
listOnlyotherNamespaceMachineNamespace[1].Name,
"otherUser-machine-2",
listOnlyotherUserMachineUser[1].Name,
)
// Delete a machines
@ -918,15 +918,15 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
)
assert.Nil(s.T(), err)
// Test: list main namespace after machine is deleted
listOnlyMachineNamespaceAfterDeleteResult, _, err := ExecuteCommand(
// Test: list main user after machine is deleted
listOnlyMachineUserAfterDeleteResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"nodes",
"list",
"--namespace",
namespace.Name,
"--user",
user.Name,
"--output",
"json",
},
@ -934,18 +934,18 @@ func (s *IntegrationCLITestSuite) TestNodeCommand() {
)
assert.Nil(s.T(), err)
var listOnlyMachineNamespaceAfterDelete []v1.Machine
var listOnlyMachineUserAfterDelete []v1.Machine
err = json.Unmarshal(
[]byte(listOnlyMachineNamespaceAfterDeleteResult),
&listOnlyMachineNamespaceAfterDelete,
[]byte(listOnlyMachineUserAfterDeleteResult),
&listOnlyMachineUserAfterDelete,
)
assert.Nil(s.T(), err)
assert.Len(s.T(), listOnlyMachineNamespaceAfterDelete, 4)
assert.Len(s.T(), listOnlyMachineUserAfterDelete, 4)
}
func (s *IntegrationCLITestSuite) TestNodeExpireCommand() {
namespace, err := s.createNamespace("machine-expire-namespace")
user, err := s.createUser("machine-expire-user")
assert.Nil(s.T(), err)
// Randomly generated machine keys
@ -968,8 +968,8 @@ func (s *IntegrationCLITestSuite) TestNodeExpireCommand() {
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--namespace",
namespace.Name,
"--user",
user.Name,
"--key",
machineKey,
"--output",
@ -984,8 +984,8 @@ func (s *IntegrationCLITestSuite) TestNodeExpireCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
namespace.Name,
"--user",
user.Name,
"register",
"--key",
machineKey,
@ -1072,7 +1072,7 @@ func (s *IntegrationCLITestSuite) TestNodeExpireCommand() {
}
func (s *IntegrationCLITestSuite) TestNodeRenameCommand() {
namespace, err := s.createNamespace("machine-rename-command")
user, err := s.createUser("machine-rename-command")
assert.Nil(s.T(), err)
// Randomly generated machine keys
@ -1095,8 +1095,8 @@ func (s *IntegrationCLITestSuite) TestNodeRenameCommand() {
"create-node",
"--name",
fmt.Sprintf("machine-%d", index+1),
"--namespace",
namespace.Name,
"--user",
user.Name,
"--key",
machineKey,
"--output",
@ -1111,8 +1111,8 @@ func (s *IntegrationCLITestSuite) TestNodeRenameCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
namespace.Name,
"--user",
user.Name,
"register",
"--key",
machineKey,
@ -1389,9 +1389,9 @@ func (s *IntegrationCLITestSuite) TestApiKeyCommand() {
}
func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
oldNamespace, err := s.createNamespace("old-namespace")
oldUser, err := s.createUser("old-user")
assert.Nil(s.T(), err)
newNamespace, err := s.createNamespace("new-namespace")
newUser, err := s.createUser("new-user")
assert.Nil(s.T(), err)
// Randomly generated machine key
@ -1405,8 +1405,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
"create-node",
"--name",
"nomad-machine",
"--namespace",
oldNamespace.Name,
"--user",
oldUser.Name,
"--key",
machineKey,
"--output",
@ -1421,8 +1421,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
[]string{
"headscale",
"nodes",
"--namespace",
oldNamespace.Name,
"--user",
oldUser.Name,
"register",
"--key",
machineKey,
@ -1439,7 +1439,7 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
assert.Equal(s.T(), uint64(1), machine.Id)
assert.Equal(s.T(), "nomad-machine", machine.Name)
assert.Equal(s.T(), machine.Namespace.Name, oldNamespace.Name)
assert.Equal(s.T(), machine.User.Name, oldUser.Name)
machineId := fmt.Sprintf("%d", machine.Id)
@ -1451,8 +1451,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
"move",
"--identifier",
machineId,
"--namespace",
newNamespace.Name,
"--user",
newUser.Name,
"--output",
"json",
},
@ -1463,7 +1463,7 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
err = json.Unmarshal([]byte(moveToNewNSResult), &machine)
assert.Nil(s.T(), err)
assert.Equal(s.T(), machine.Namespace, newNamespace)
assert.Equal(s.T(), machine.User, newUser)
listAllNodesResult, _, err := ExecuteCommand(
&s.headscale,
@ -1485,8 +1485,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
assert.Len(s.T(), allNodes, 1)
assert.Equal(s.T(), allNodes[0].Id, machine.Id)
assert.Equal(s.T(), allNodes[0].Namespace, machine.Namespace)
assert.Equal(s.T(), allNodes[0].Namespace, newNamespace)
assert.Equal(s.T(), allNodes[0].User, machine.User)
assert.Equal(s.T(), allNodes[0].User, newUser)
moveToNonExistingNSResult, _, err := ExecuteCommand(
&s.headscale,
@ -1496,8 +1496,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
"move",
"--identifier",
machineId,
"--namespace",
"non-existing-namespace",
"--user",
"non-existing-user",
"--output",
"json",
},
@ -1508,9 +1508,9 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
assert.Contains(
s.T(),
string(moveToNonExistingNSResult),
"Namespace not found",
"User not found",
)
assert.Equal(s.T(), machine.Namespace, newNamespace)
assert.Equal(s.T(), machine.User, newUser)
moveToOldNSResult, _, err := ExecuteCommand(
&s.headscale,
@ -1520,8 +1520,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
"move",
"--identifier",
machineId,
"--namespace",
oldNamespace.Name,
"--user",
oldUser.Name,
"--output",
"json",
},
@ -1532,7 +1532,7 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
err = json.Unmarshal([]byte(moveToOldNSResult), &machine)
assert.Nil(s.T(), err)
assert.Equal(s.T(), machine.Namespace, oldNamespace)
assert.Equal(s.T(), machine.User, oldUser)
moveToSameNSResult, _, err := ExecuteCommand(
&s.headscale,
@ -1542,8 +1542,8 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
"move",
"--identifier",
machineId,
"--namespace",
oldNamespace.Name,
"--user",
oldUser.Name,
"--output",
"json",
},
@ -1554,7 +1554,7 @@ func (s *IntegrationCLITestSuite) TestNodeMoveCommand() {
err = json.Unmarshal([]byte(moveToSameNSResult), &machine)
assert.Nil(s.T(), err)
assert.Equal(s.T(), machine.Namespace, oldNamespace)
assert.Equal(s.T(), machine.User, oldUser)
}
func (s *IntegrationCLITestSuite) TestLoadConfigFromCommand() {

View file

@ -47,7 +47,7 @@ var (
}
)
type TestNamespace struct {
type TestUser struct {
count int
tailscales map[string]dockertest.Resource
}
@ -296,7 +296,7 @@ func getMagicFQDN(
hostnames[index] = fmt.Sprintf(
"%s.%s.headscale.net",
listAll[index].GetGivenName(),
listAll[index].GetNamespace().GetName(),
listAll[index].GetUser().GetName(),
)
}

View file

@ -26,7 +26,7 @@ import (
const (
headscaleDerpHostname = "headscale-derp"
namespaceName = "derpnamespace"
userName = "derpuser"
totalContainers = 3
)
@ -199,22 +199,22 @@ func (s *IntegrationDERPTestSuite) SetupSuite() {
}
log.Println("headscale container is ready for embedded DERP tests")
log.Printf("Creating headscale namespace: %s\n", namespaceName)
log.Printf("Creating headscale user: %s\n", userName)
result, _, err := ExecuteCommand(
&s.headscale,
[]string{"headscale", "namespaces", "create", namespaceName},
[]string{"headscale", "users", "create", userName},
[]string{},
)
log.Println("headscale create namespace result: ", result)
log.Println("headscale create user result: ", result)
assert.Nil(s.T(), err)
log.Printf("Creating pre auth key for %s\n", namespaceName)
log.Printf("Creating pre auth key for %s\n", userName)
preAuthResult, _, err := ExecuteCommand(
&s.headscale,
[]string{
"headscale",
"--namespace",
namespaceName,
"--user",
userName,
"preauthkeys",
"create",
"--reusable",

View file

@ -27,8 +27,8 @@ const (
)
ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface")
ErrHostnameTooLong = Error("Hostname too long")
ErrDifferentRegisteredNamespace = Error(
"machine was previously registered with a different namespace",
ErrDifferentRegisteredUser = Error(
"machine was previously registered with a different user",
)
MachineGivenNameHashLength = 8
MachineGivenNameTrimSize = 2
@ -57,8 +57,8 @@ type Machine struct {
// GivenName is the name used in all DNS related
// parts of headscale.
GivenName string `gorm:"type:varchar(63);unique_index"`
NamespaceID uint
Namespace Namespace `gorm:"foreignKey:NamespaceID"`
UserID uint
User User `gorm:"foreignKey:UserID"`
RegisterMethod string
@ -192,7 +192,7 @@ func getFilteredByACLPeers(
Msg("Finding peers filtered by ACLs")
peers := make(map[uint64]Machine)
// Aclfilter peers here. We are itering through machines in all namespaces and search through the computed aclRules
// Aclfilter peers here. We are itering through machines in all users and search through the computed aclRules
// for match between rule SrcIPs and DstPorts. If the rule is a match we allow the machine to be viewable.
machineIPs := machine.IPAddresses.ToStringSlice()
for _, peer := range machines {
@ -270,7 +270,7 @@ func (h *Headscale) ListPeers(machine *Machine) (Machines, error) {
Msg("Finding direct peers")
machines := Machines{}
if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Where("node_key <> ?",
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where("node_key <> ?",
machine.NodeKey).Find(&machines).Error; err != nil {
log.Error().Err(err).Msg("Error accessing db")
@ -292,7 +292,7 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) {
var err error
// If ACLs rules are defined, filter visible host list with the ACLs
// else use the classic namespace scope
// else use the classic user scope
if h.aclPolicy != nil {
var machines []Machine
machines, err = h.ListMachines()
@ -343,7 +343,7 @@ func (h *Headscale) getValidPeers(machine *Machine) (Machines, error) {
func (h *Headscale) ListMachines() ([]Machine, error) {
machines := []Machine{}
if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Find(&machines).Error; err != nil {
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Find(&machines).Error; err != nil {
return nil, err
}
@ -352,16 +352,16 @@ func (h *Headscale) ListMachines() ([]Machine, error) {
func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error) {
machines := []Machine{}
if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Find(&machines).Where("given_name = ?", givenName).Error; err != nil {
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Find(&machines).Where("given_name = ?", givenName).Error; err != nil {
return nil, err
}
return machines, nil
}
// GetMachine finds a Machine by name and namespace and returns the Machine struct.
func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error) {
machines, err := h.ListMachinesInNamespace(namespace)
// GetMachine finds a Machine by name and user and returns the Machine struct.
func (h *Headscale) GetMachine(user string, name string) (*Machine, error) {
machines, err := h.ListMachinesByUser(user)
if err != nil {
return nil, err
}
@ -375,9 +375,9 @@ func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error)
return nil, ErrMachineNotFound
}
// GetMachineByGivenName finds a Machine by given name and namespace and returns the Machine struct.
func (h *Headscale) GetMachineByGivenName(namespace string, givenName string) (*Machine, error) {
machines, err := h.ListMachinesInNamespace(namespace)
// GetMachineByGivenName finds a Machine by given name and user and returns the Machine struct.
func (h *Headscale) GetMachineByGivenName(user string, givenName string) (*Machine, error) {
machines, err := h.ListMachinesByUser(user)
if err != nil {
return nil, err
}
@ -394,7 +394,7 @@ func (h *Headscale) GetMachineByGivenName(namespace string, givenName string) (*
// GetMachineByID finds a Machine by ID and returns the Machine struct.
func (h *Headscale) GetMachineByID(id uint64) (*Machine, error) {
m := Machine{}
if result := h.db.Preload("AuthKey").Preload("Namespace").Find(&Machine{ID: id}).First(&m); result.Error != nil {
if result := h.db.Preload("AuthKey").Preload("User").Find(&Machine{ID: id}).First(&m); result.Error != nil {
return nil, result.Error
}
@ -406,7 +406,7 @@ func (h *Headscale) GetMachineByMachineKey(
machineKey key.MachinePublic,
) (*Machine, error) {
m := Machine{}
if result := h.db.Preload("AuthKey").Preload("Namespace").First(&m, "machine_key = ?", MachinePublicKeyStripPrefix(machineKey)); result.Error != nil {
if result := h.db.Preload("AuthKey").Preload("User").First(&m, "machine_key = ?", MachinePublicKeyStripPrefix(machineKey)); result.Error != nil {
return nil, result.Error
}
@ -418,7 +418,7 @@ func (h *Headscale) GetMachineByNodeKey(
nodeKey key.NodePublic,
) (*Machine, error) {
machine := Machine{}
if result := h.db.Preload("AuthKey").Preload("Namespace").First(&machine, "node_key = ?",
if result := h.db.Preload("AuthKey").Preload("User").First(&machine, "node_key = ?",
NodePublicKeyStripPrefix(nodeKey)); result.Error != nil {
return nil, result.Error
}
@ -431,7 +431,7 @@ func (h *Headscale) GetMachineByAnyKey(
machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic,
) (*Machine, error) {
machine := Machine{}
if result := h.db.Preload("AuthKey").Preload("Namespace").First(&machine, "machine_key = ? OR node_key = ? OR node_key = ?",
if result := h.db.Preload("AuthKey").Preload("User").First(&machine, "machine_key = ? OR node_key = ? OR node_key = ?",
MachinePublicKeyStripPrefix(machineKey),
NodePublicKeyStripPrefix(nodeKey),
NodePublicKeyStripPrefix(oldNodeKey)); result.Error != nil {
@ -570,9 +570,9 @@ func (h *Headscale) isOutdated(machine *Machine) bool {
return true
}
// Get the last update from all headscale namespaces to compare with our nodes
// Get the last update from all headscale users to compare with our nodes
// last update.
// TODO(kradalby): Only request updates from namespaces where we can talk to nodes
// TODO(kradalby): Only request updates from users where we can talk to nodes
// This would mostly be for a bit of performance, and can be calculated based on
// ACLs.
lastChange := h.getLastStateChange()
@ -720,7 +720,7 @@ func (h *Headscale) toNode(
hostname = fmt.Sprintf(
"%s.%s.%s",
machine.GivenName,
machine.Namespace.Name,
machine.User.Name,
baseDomain,
)
if len(hostname) > maxHostnameLength {
@ -744,7 +744,7 @@ func (h *Headscale) toNode(
strconv.FormatUint(machine.ID, Base10),
), // in headscale, unlike tailcontrol server, IDs are permanent
Name: hostname,
User: tailcfg.UserID(machine.NamespaceID),
User: tailcfg.UserID(machine.UserID),
Key: nodeKey,
KeyExpiry: keyExpiry,
Machine: machineKey,
@ -782,7 +782,7 @@ func (machine *Machine) toProto() *v1.Machine {
IpAddresses: machine.IPAddresses.ToStringSlice(),
Name: machine.Hostname,
GivenName: machine.GivenName,
Namespace: machine.Namespace.toProto(),
User: machine.User.toProto(),
ForcedTags: machine.ForcedTags,
Online: machine.isOnline(),
@ -837,7 +837,7 @@ func getTags(
}
var found bool
for _, owner := range owners {
if machine.Namespace.Name == owner {
if machine.User.Name == owner {
found = true
}
}
@ -859,7 +859,7 @@ func getTags(
func (h *Headscale) RegisterMachineFromAuthCallback(
nodeKeyStr string,
namespaceName string,
userName string,
machineExpiry *time.Time,
registrationMethod string,
) (*Machine, error) {
@ -871,28 +871,28 @@ func (h *Headscale) RegisterMachineFromAuthCallback(
log.Debug().
Str("nodeKey", nodeKey.ShortString()).
Str("namespaceName", namespaceName).
Str("userName", userName).
Str("registrationMethod", registrationMethod).
Str("expiresAt", fmt.Sprintf("%v", machineExpiry)).
Msg("Registering machine from API/CLI or auth callback")
if machineInterface, ok := h.registrationCache.Get(NodePublicKeyStripPrefix(nodeKey)); ok {
if registrationMachine, ok := machineInterface.(Machine); ok {
namespace, err := h.GetNamespace(namespaceName)
user, err := h.GetUser(userName)
if err != nil {
return nil, fmt.Errorf(
"failed to find namespace in register machine from auth callback, %w",
"failed to find user in register machine from auth callback, %w",
err,
)
}
// Registration of expired machine with different namespace
// Registration of expired machine with different user
if registrationMachine.ID != 0 &&
registrationMachine.NamespaceID != namespace.ID {
return nil, ErrDifferentRegisteredNamespace
registrationMachine.UserID != user.ID {
return nil, ErrDifferentRegisteredUser
}
registrationMachine.NamespaceID = namespace.ID
registrationMachine.UserID = user.ID
registrationMachine.RegisterMethod = registrationMethod
if machineExpiry != nil {
@ -923,7 +923,7 @@ func (h *Headscale) RegisterMachine(machine Machine,
Str("machine", machine.Hostname).
Str("machine_key", machine.MachineKey).
Str("node_key", machine.NodeKey).
Str("namespace", machine.Namespace.Name).
Str("user", machine.User.Name).
Msg("Registering machine")
// If the machine exists and we had already IPs for it, we just save it
@ -939,7 +939,7 @@ func (h *Headscale) RegisterMachine(machine Machine,
Str("machine", machine.Hostname).
Str("machine_key", machine.MachineKey).
Str("node_key", machine.NodeKey).
Str("namespace", machine.Namespace.Name).
Str("user", machine.User.Name).
Msg("Machine authorized again")
return &machine, nil
@ -1137,7 +1137,7 @@ func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error {
}
for _, approvedAlias := range routeApprovers {
if approvedAlias == machine.Namespace.Name {
if approvedAlias == machine.User.Name {
approvedRoutes = append(approvedRoutes, advertisedRoute)
} else {
approvedIps, err := expandAlias([]Machine{*machine}, *h.aclPolicy, approvedAlias, h.cfg.OIDC.StripEmaildomain)

View file

@ -15,10 +15,10 @@ import (
)
func (s *Suite) TestGetMachine(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -30,7 +30,7 @@ func (s *Suite) TestGetMachine(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -41,10 +41,10 @@ func (s *Suite) TestGetMachine(c *check.C) {
}
func (s *Suite) TestGetMachineByID(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0)
@ -56,7 +56,7 @@ func (s *Suite) TestGetMachineByID(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -67,10 +67,10 @@ func (s *Suite) TestGetMachineByID(c *check.C) {
}
func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0)
@ -85,7 +85,7 @@ func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -96,10 +96,10 @@ func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
}
func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0)
@ -116,7 +116,7 @@ func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -127,7 +127,7 @@ func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
}
func (s *Suite) TestDeleteMachine(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
machine := Machine{
ID: 0,
@ -135,7 +135,7 @@ func (s *Suite) TestDeleteMachine(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(1),
}
@ -144,12 +144,12 @@ func (s *Suite) TestDeleteMachine(c *check.C) {
err = app.DeleteMachine(&machine)
c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespace.Name, "testmachine")
_, err = app.GetMachine(user.Name, "testmachine")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestHardDeleteMachine(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
machine := Machine{
ID: 0,
@ -157,7 +157,7 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine3",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(1),
}
@ -166,15 +166,15 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) {
err = app.HardDeleteMachine(&machine)
c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespace.Name, "testmachine3")
_, err = app.GetMachine(user.Name, "testmachine3")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestListPeers(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0)
@ -187,7 +187,7 @@ func (s *Suite) TestListPeers(c *check.C) {
NodeKey: "bar" + strconv.Itoa(index),
DiscoKey: "faa" + strconv.Itoa(index),
Hostname: "testmachine" + strconv.Itoa(index),
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -208,18 +208,18 @@ func (s *Suite) TestListPeers(c *check.C) {
func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
type base struct {
namespace *Namespace
user *User
key *PreAuthKey
}
stor := make([]base, 0)
for _, name := range []string{"test", "admin"} {
namespace, err := app.CreateNamespace(name)
user, err := app.CreateUser(name)
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
stor = append(stor, base{namespace, pak})
stor = append(stor, base{user, pak})
}
_, err := app.GetMachineByID(0)
@ -235,7 +235,7 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))),
},
Hostname: "testmachine" + strconv.Itoa(index),
NamespaceID: stor[index%2].namespace.ID,
UserID: stor[index%2].user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(stor[index%2].key.ID),
}
@ -267,11 +267,11 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
c.Assert(err, check.IsNil)
adminMachine, err := app.GetMachineByID(1)
c.Logf("Machine(%v), namespace: %v", adminMachine.Hostname, adminMachine.Namespace)
c.Logf("Machine(%v), user: %v", adminMachine.Hostname, adminMachine.User)
c.Assert(err, check.IsNil)
testMachine, err := app.GetMachineByID(2)
c.Logf("Machine(%v), namespace: %v", testMachine.Hostname, testMachine.Namespace)
c.Logf("Machine(%v), user: %v", testMachine.Hostname, testMachine.User)
c.Assert(err, check.IsNil)
machines, err := app.ListMachines()
@ -294,10 +294,10 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
}
func (s *Suite) TestExpireMachine(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -309,7 +309,7 @@ func (s *Suite) TestExpireMachine(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
Expiry: &time.Time{},
@ -350,13 +350,13 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
}
func (s *Suite) TestGenerateGivenName(c *check.C) {
namespace1, err := app.CreateNamespace("namespace-1")
user1, err := app.CreateUser("user-1")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace1.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user1.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("namespace-1", "testmachine")
_, err = app.GetMachine("user-1", "testmachine")
c.Assert(err, check.NotNil)
machine := &Machine{
@ -366,38 +366,38 @@ func (s *Suite) TestGenerateGivenName(c *check.C) {
DiscoKey: "disco-key-1",
Hostname: "hostname-1",
GivenName: "hostname-1",
NamespaceID: namespace1.ID,
UserID: user1.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
app.db.Save(machine)
givenName, err := app.GenerateGivenName("machine-key-2", "hostname-2")
comment := check.Commentf("Same namespace, unique machines, unique hostnames, no conflict")
comment := check.Commentf("Same user, unique machines, unique hostnames, no conflict")
c.Assert(err, check.IsNil, comment)
c.Assert(givenName, check.Equals, "hostname-2", comment)
givenName, err = app.GenerateGivenName("machine-key-1", "hostname-1")
comment = check.Commentf("Same namespace, same machine, same hostname, no conflict")
comment = check.Commentf("Same user, same machine, same hostname, no conflict")
c.Assert(err, check.IsNil, comment)
c.Assert(givenName, check.Equals, "hostname-1", comment)
givenName, err = app.GenerateGivenName("machine-key-2", "hostname-1")
comment = check.Commentf("Same namespace, unique machines, same hostname, conflict")
comment = check.Commentf("Same user, unique machines, same hostname, conflict")
c.Assert(err, check.IsNil, comment)
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment)
givenName, err = app.GenerateGivenName("machine-key-2", "hostname-1")
comment = check.Commentf("Unique namespaces, unique machines, same hostname, conflict")
comment = check.Commentf("Unique users, unique machines, same hostname, conflict")
c.Assert(err, check.IsNil, comment)
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment)
}
func (s *Suite) TestSetTags(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -409,7 +409,7 @@ func (s *Suite) TestSetTags(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -457,7 +457,7 @@ func Test_getTags(t *testing.T) {
},
},
machine: Machine{
Namespace: Namespace{
User: User{
Name: "joe",
},
HostInfo: HostInfo{
@ -478,7 +478,7 @@ func Test_getTags(t *testing.T) {
},
},
machine: Machine{
Namespace: Namespace{
User: User{
Name: "joe",
},
HostInfo: HostInfo{
@ -499,7 +499,7 @@ func Test_getTags(t *testing.T) {
},
},
machine: Machine{
Namespace: Namespace{
User: User{
Name: "joe",
},
HostInfo: HostInfo{
@ -524,7 +524,7 @@ func Test_getTags(t *testing.T) {
},
},
machine: Machine{
Namespace: Namespace{
User: User{
Name: "joe",
},
HostInfo: HostInfo{
@ -541,7 +541,7 @@ func Test_getTags(t *testing.T) {
args: args{
aclPolicy: nil,
machine: Machine{
Namespace: Namespace{
User: User{
Name: "joe",
},
HostInfo: HostInfo{
@ -607,21 +607,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -635,19 +635,19 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine
ID: 1,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
want: Machines{
{
ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.3")},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
},
@ -660,21 +660,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -688,14 +688,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine
ID: 1,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
want: Machines{
{
ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
},
@ -708,21 +708,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -736,14 +736,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine
ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
want: Machines{
{
ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.3")},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
},
@ -756,21 +756,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -786,7 +786,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
},
want: Machines{
@ -795,7 +795,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
},
@ -808,21 +808,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -838,7 +838,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
want: Machines{
@ -847,14 +847,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
},
@ -867,21 +867,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -895,7 +895,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine
ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
want: Machines{
@ -904,12 +904,12 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.3")},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
},
@ -922,21 +922,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"),
},
Namespace: Namespace{Name: "joe"},
User: User{Name: "joe"},
},
{
ID: 2,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"),
},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
{
ID: 3,
IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"),
},
Namespace: Namespace{Name: "mickael"},
User: User{Name: "mickael"},
},
},
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -944,7 +944,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine
ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"},
User: User{Name: "marc"},
},
},
want: Machines{},
@ -1125,10 +1125,10 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
err := app.LoadACLPolicy("./tests/acls/acl_policy_autoapprovers.hujson")
c.Assert(err, check.IsNil)
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
nodeKey := key.NewNode()
@ -1144,7 +1144,7 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa",
Hostname: "test",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo{

View file

@ -8,34 +8,34 @@ import (
const prometheusNamespace = "headscale"
var (
// This is a high cardinality metric (namespace x machines), we might want to make this
// This is a high cardinality metric (user x machines), we might want to make this
// configurable/opt-in in the future.
lastStateUpdate = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: prometheusNamespace,
Name: "last_update_seconds",
Help: "Time stamp in unix time when a machine or headscale was updated",
}, []string{"namespace", "machine"})
}, []string{"user", "machine"})
machineRegistrations = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace,
Name: "machine_registrations_total",
Help: "The total amount of registered machine attempts",
}, []string{"action", "auth", "status", "namespace"})
}, []string{"action", "auth", "status", "user"})
updateRequestsFromNode = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace,
Name: "update_request_from_node_total",
Help: "The number of updates requested by a node/update function",
}, []string{"namespace", "machine", "state"})
}, []string{"user", "machine", "state"})
updateRequestsSentToNode = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace,
Name: "update_request_sent_to_node_total",
Help: "The number of calls/messages issued on a specific nodes update channel",
}, []string{"namespace", "machine", "status"})
}, []string{"user", "machine", "status"})
// TODO(kradalby): This is very debugging, we might want to remove it.
updateRequestsReceivedOnChannel = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace,
Name: "update_request_received_on_channel_total",
Help: "The number of update requests received on an update channel",
}, []string{"namespace", "machine"})
}, []string{"user", "machine"})
)

View file

@ -16,10 +16,10 @@ import (
)
const (
ErrNamespaceExists = Error("Namespace already exists")
ErrNamespaceNotFound = Error("Namespace not found")
ErrNamespaceNotEmptyOfNodes = Error("Namespace not empty: node(s) found")
ErrInvalidNamespaceName = Error("Invalid namespace name")
ErrUserExists = Error("User already exists")
ErrUserNotFound = Error("User not found")
ErrUserStillHasNodes = Error("User not empty: node(s) found")
ErrInvalidUserName = Error("Invalid user name")
)
const (
@ -27,55 +27,55 @@ const (
labelHostnameLength = 63
)
var invalidCharsInNamespaceRegex = regexp.MustCompile("[^a-z0-9-.]+")
var invalidCharsInUserRegex = regexp.MustCompile("[^a-z0-9-.]+")
// Namespace is the way Headscale implements the concept of users in Tailscale
// User is the way Headscale implements the concept of users in Tailscale
//
// At the end of the day, users in Tailscale are some kind of 'bubbles' or namespaces
// At the end of the day, users in Tailscale are some kind of 'bubbles' or users
// that contain our machines.
type Namespace struct {
type User struct {
gorm.Model
Name string `gorm:"unique"`
}
// CreateNamespace creates a new Namespace. Returns error if could not be created
// or another namespace already exists.
func (h *Headscale) CreateNamespace(name string) (*Namespace, error) {
// CreateUser creates a new User. Returns error if could not be created
// or another user already exists.
func (h *Headscale) CreateUser(name string) (*User, error) {
err := CheckForFQDNRules(name)
if err != nil {
return nil, err
}
namespace := Namespace{}
if err := h.db.Where("name = ?", name).First(&namespace).Error; err == nil {
return nil, ErrNamespaceExists
user := User{}
if err := h.db.Where("name = ?", name).First(&user).Error; err == nil {
return nil, ErrUserExists
}
namespace.Name = name
if err := h.db.Create(&namespace).Error; err != nil {
user.Name = name
if err := h.db.Create(&user).Error; err != nil {
log.Error().
Str("func", "CreateNamespace").
Str("func", "CreateUser").
Err(err).
Msg("Could not create row")
return nil, err
}
return &namespace, nil
return &user, nil
}
// DestroyNamespace destroys a Namespace. Returns error if the Namespace does
// DestroyUser destroys a User. Returns error if the User does
// not exist or if there are machines associated with it.
func (h *Headscale) DestroyNamespace(name string) error {
namespace, err := h.GetNamespace(name)
func (h *Headscale) DestroyUser(name string) error {
user, err := h.GetUser(name)
if err != nil {
return ErrNamespaceNotFound
return ErrUserNotFound
}
machines, err := h.ListMachinesInNamespace(name)
machines, err := h.ListMachinesByUser(name)
if err != nil {
return err
}
if len(machines) > 0 {
return ErrNamespaceNotEmptyOfNodes
return ErrUserStillHasNodes
}
keys, err := h.ListPreAuthKeys(name)
@ -89,18 +89,18 @@ func (h *Headscale) DestroyNamespace(name string) error {
}
}
if result := h.db.Unscoped().Delete(&namespace); result.Error != nil {
if result := h.db.Unscoped().Delete(&user); result.Error != nil {
return result.Error
}
return nil
}
// RenameNamespace renames a Namespace. Returns error if the Namespace does
// not exist or if another Namespace exists with the new name.
func (h *Headscale) RenameNamespace(oldName, newName string) error {
// RenameUser renames a User. Returns error if the User does
// not exist or if another User exists with the new name.
func (h *Headscale) RenameUser(oldName, newName string) error {
var err error
oldNamespace, err := h.GetNamespace(oldName)
oldUser, err := h.GetUser(oldName)
if err != nil {
return err
}
@ -108,76 +108,76 @@ func (h *Headscale) RenameNamespace(oldName, newName string) error {
if err != nil {
return err
}
_, err = h.GetNamespace(newName)
_, err = h.GetUser(newName)
if err == nil {
return ErrNamespaceExists
return ErrUserExists
}
if !errors.Is(err, ErrNamespaceNotFound) {
if !errors.Is(err, ErrUserNotFound) {
return err
}
oldNamespace.Name = newName
oldUser.Name = newName
if result := h.db.Save(&oldNamespace); result.Error != nil {
if result := h.db.Save(&oldUser); result.Error != nil {
return result.Error
}
return nil
}
// GetNamespace fetches a namespace by name.
func (h *Headscale) GetNamespace(name string) (*Namespace, error) {
namespace := Namespace{}
if result := h.db.First(&namespace, "name = ?", name); errors.Is(
// GetUser fetches a user by name.
func (h *Headscale) GetUser(name string) (*User, error) {
user := User{}
if result := h.db.First(&user, "name = ?", name); errors.Is(
result.Error,
gorm.ErrRecordNotFound,
) {
return nil, ErrNamespaceNotFound
return nil, ErrUserNotFound
}
return &namespace, nil
return &user, nil
}
// ListNamespaces gets all the existing namespaces.
func (h *Headscale) ListNamespaces() ([]Namespace, error) {
namespaces := []Namespace{}
if err := h.db.Find(&namespaces).Error; err != nil {
// ListUsers gets all the existing users.
func (h *Headscale) ListUsers() ([]User, error) {
users := []User{}
if err := h.db.Find(&users).Error; err != nil {
return nil, err
}
return namespaces, nil
return users, nil
}
// ListMachinesInNamespace gets all the nodes in a given namespace.
func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) {
// ListMachinesByUser gets all the nodes in a given user.
func (h *Headscale) ListMachinesByUser(name string) ([]Machine, error) {
err := CheckForFQDNRules(name)
if err != nil {
return nil, err
}
namespace, err := h.GetNamespace(name)
user, err := h.GetUser(name)
if err != nil {
return nil, err
}
machines := []Machine{}
if err := h.db.Preload("AuthKey").Preload("AuthKey.Namespace").Preload("Namespace").Where(&Machine{NamespaceID: namespace.ID}).Find(&machines).Error; err != nil {
if err := h.db.Preload("AuthKey").Preload("AuthKey.User").Preload("User").Where(&Machine{UserID: user.ID}).Find(&machines).Error; err != nil {
return nil, err
}
return machines, nil
}
// SetMachineNamespace assigns a Machine to a namespace.
func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string) error {
err := CheckForFQDNRules(namespaceName)
// SetMachineUser assigns a Machine to a user.
func (h *Headscale) SetMachineUser(machine *Machine, username string) error {
err := CheckForFQDNRules(username)
if err != nil {
return err
}
namespace, err := h.GetNamespace(namespaceName)
user, err := h.GetUser(username)
if err != nil {
return err
}
machine.Namespace = *namespace
machine.User = *user
if result := h.db.Save(&machine); result.Error != nil {
return result.Error
}
@ -185,7 +185,7 @@ func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string)
return nil
}
func (n *Namespace) toUser() *tailcfg.User {
func (n *User) toTailscaleUser() *tailcfg.User {
user := tailcfg.User{
ID: tailcfg.UserID(n.ID),
LoginName: n.Name,
@ -199,7 +199,7 @@ func (n *Namespace) toUser() *tailcfg.User {
return &user
}
func (n *Namespace) toLogin() *tailcfg.Login {
func (n *User) toTailscaleLogin() *tailcfg.Login {
login := tailcfg.Login{
ID: tailcfg.LoginID(n.ID),
LoginName: n.Name,
@ -215,24 +215,24 @@ func (h *Headscale) getMapResponseUserProfiles(
machine Machine,
peers Machines,
) []tailcfg.UserProfile {
namespaceMap := make(map[string]Namespace)
namespaceMap[machine.Namespace.Name] = machine.Namespace
userMap := make(map[string]User)
userMap[machine.User.Name] = machine.User
for _, peer := range peers {
namespaceMap[peer.Namespace.Name] = peer.Namespace // not worth checking if already is there
userMap[peer.User.Name] = peer.User // not worth checking if already is there
}
profiles := []tailcfg.UserProfile{}
for _, namespace := range namespaceMap {
displayName := namespace.Name
for _, user := range userMap {
displayName := user.Name
if h.cfg.BaseDomain != "" {
displayName = fmt.Sprintf("%s@%s", namespace.Name, h.cfg.BaseDomain)
displayName = fmt.Sprintf("%s@%s", user.Name, h.cfg.BaseDomain)
}
profiles = append(profiles,
tailcfg.UserProfile{
ID: tailcfg.UserID(namespace.ID),
LoginName: namespace.Name,
ID: tailcfg.UserID(user.ID),
LoginName: user.Name,
DisplayName: displayName,
})
}
@ -240,16 +240,16 @@ func (h *Headscale) getMapResponseUserProfiles(
return profiles
}
func (n *Namespace) toProto() *v1.Namespace {
return &v1.Namespace{
func (n *User) toProto() *v1.User {
return &v1.User{
Id: strconv.FormatUint(uint64(n.ID), Base10),
Name: n.Name,
CreatedAt: timestamppb.New(n.CreatedAt),
}
}
// NormalizeToFQDNRules will replace forbidden chars in namespace
// it can also return an error if the namespace doesn't respect RFC 952 and 1123.
// NormalizeToFQDNRules will replace forbidden chars in user
// it can also return an error if the user doesn't respect RFC 952 and 1123.
func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) {
name = strings.ToLower(name)
name = strings.ReplaceAll(name, "'", "")
@ -259,14 +259,14 @@ func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) {
} else {
name = strings.ReplaceAll(name, "@", ".")
}
name = invalidCharsInNamespaceRegex.ReplaceAllString(name, "-")
name = invalidCharsInUserRegex.ReplaceAllString(name, "-")
for _, elt := range strings.Split(name, ".") {
if len(elt) > labelHostnameLength {
return "", fmt.Errorf(
"label %v is more than 63 chars: %w",
elt,
ErrInvalidNamespaceName,
ErrInvalidUserName,
)
}
}
@ -279,21 +279,21 @@ func CheckForFQDNRules(name string) error {
return fmt.Errorf(
"DNS segment must not be over 63 chars. %v doesn't comply with this rule: %w",
name,
ErrInvalidNamespaceName,
ErrInvalidUserName,
)
}
if strings.ToLower(name) != name {
return fmt.Errorf(
"DNS segment should be lowercase. %v doesn't comply with this rule: %w",
name,
ErrInvalidNamespaceName,
ErrInvalidUserName,
)
}
if invalidCharsInNamespaceRegex.MatchString(name) {
if invalidCharsInUserRegex.MatchString(name) {
return fmt.Errorf(
"DNS segment should only be composed of lowercase ASCII letters numbers, hyphen and dots. %v doesn't comply with theses rules: %w",
name,
ErrInvalidNamespaceName,
ErrInvalidUserName,
)
}

View file

@ -8,43 +8,43 @@ import (
"gorm.io/gorm"
)
func (s *Suite) TestCreateAndDestroyNamespace(c *check.C) {
namespace, err := app.CreateNamespace("test")
func (s *Suite) TestCreateAndDestroyUser(c *check.C) {
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
c.Assert(namespace.Name, check.Equals, "test")
c.Assert(user.Name, check.Equals, "test")
namespaces, err := app.ListNamespaces()
users, err := app.ListUsers()
c.Assert(err, check.IsNil)
c.Assert(len(namespaces), check.Equals, 1)
c.Assert(len(users), check.Equals, 1)
err = app.DestroyNamespace("test")
err = app.DestroyUser("test")
c.Assert(err, check.IsNil)
_, err = app.GetNamespace("test")
_, err = app.GetUser("test")
c.Assert(err, check.NotNil)
}
func (s *Suite) TestDestroyNamespaceErrors(c *check.C) {
err := app.DestroyNamespace("test")
c.Assert(err, check.Equals, ErrNamespaceNotFound)
func (s *Suite) TestDestroyUserErrors(c *check.C) {
err := app.DestroyUser("test")
c.Assert(err, check.Equals, ErrUserNotFound)
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
err = app.DestroyNamespace("test")
err = app.DestroyUser("test")
c.Assert(err, check.IsNil)
result := app.db.Preload("Namespace").First(&pak, "key = ?", pak.Key)
// destroying a namespace also deletes all associated preauthkeys
result := app.db.Preload("User").First(&pak, "key = ?", pak.Key)
// destroying a user also deletes all associated preauthkeys
c.Assert(result.Error, check.Equals, gorm.ErrRecordNotFound)
namespace, err = app.CreateNamespace("test")
user, err = app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err = app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err = app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
machine := Machine{
@ -53,57 +53,57 @@ func (s *Suite) TestDestroyNamespaceErrors(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
app.db.Save(&machine)
err = app.DestroyNamespace("test")
c.Assert(err, check.Equals, ErrNamespaceNotEmptyOfNodes)
err = app.DestroyUser("test")
c.Assert(err, check.Equals, ErrUserStillHasNodes)
}
func (s *Suite) TestRenameNamespace(c *check.C) {
namespaceTest, err := app.CreateNamespace("test")
func (s *Suite) TestRenameUser(c *check.C) {
userTest, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
c.Assert(namespaceTest.Name, check.Equals, "test")
c.Assert(userTest.Name, check.Equals, "test")
namespaces, err := app.ListNamespaces()
users, err := app.ListUsers()
c.Assert(err, check.IsNil)
c.Assert(len(namespaces), check.Equals, 1)
c.Assert(len(users), check.Equals, 1)
err = app.RenameNamespace("test", "test-renamed")
err = app.RenameUser("test", "test-renamed")
c.Assert(err, check.IsNil)
_, err = app.GetNamespace("test")
c.Assert(err, check.Equals, ErrNamespaceNotFound)
_, err = app.GetUser("test")
c.Assert(err, check.Equals, ErrUserNotFound)
_, err = app.GetNamespace("test-renamed")
_, err = app.GetUser("test-renamed")
c.Assert(err, check.IsNil)
err = app.RenameNamespace("test-does-not-exit", "test")
c.Assert(err, check.Equals, ErrNamespaceNotFound)
err = app.RenameUser("test-does-not-exit", "test")
c.Assert(err, check.Equals, ErrUserNotFound)
namespaceTest2, err := app.CreateNamespace("test2")
userTest2, err := app.CreateUser("test2")
c.Assert(err, check.IsNil)
c.Assert(namespaceTest2.Name, check.Equals, "test2")
c.Assert(userTest2.Name, check.Equals, "test2")
err = app.RenameNamespace("test2", "test-renamed")
c.Assert(err, check.Equals, ErrNamespaceExists)
err = app.RenameUser("test2", "test-renamed")
c.Assert(err, check.Equals, ErrUserExists)
}
func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
namespaceShared1, err := app.CreateNamespace("shared1")
userShared1, err := app.CreateUser("shared1")
c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2")
userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3")
userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil)
preAuthKeyShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -112,7 +112,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name,
userShared2.Name,
false,
false,
nil,
@ -121,7 +121,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKeyShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name,
userShared3.Name,
false,
false,
nil,
@ -130,7 +130,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil)
preAuthKey2Shared1, err := app.CreatePreAuthKey(
namespaceShared1.Name,
userShared1.Name,
false,
false,
nil,
@ -138,7 +138,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
)
c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespaceShared1.Name, "test_get_shared_nodes_1")
_, err = app.GetMachine(userShared1.Name, "test_get_shared_nodes_1")
c.Assert(err, check.NotNil)
machineInShared1 := &Machine{
@ -147,15 +147,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyShared1.ID),
}
app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname)
_, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil)
machineInShared2 := &Machine{
@ -164,15 +164,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID,
Namespace: *namespaceShared2,
UserID: userShared2.ID,
User: *userShared2,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyShared2.ID),
}
app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname)
_, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil)
machineInShared3 := &Machine{
@ -181,15 +181,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID,
Namespace: *namespaceShared3,
UserID: userShared3.ID,
User: *userShared3,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyShared3.ID),
}
app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname)
_, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{
@ -198,8 +198,8 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID,
Namespace: *namespaceShared1,
UserID: userShared1.ID,
User: *userShared1,
RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(preAuthKey2Shared1.ID),
@ -218,7 +218,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
found := false
for _, userProfiles := range userProfiles {
if userProfiles.DisplayName == namespaceShared1.Name {
if userProfiles.DisplayName == userShared1.Name {
found = true
break
@ -228,7 +228,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
found = false
for _, userProfile := range userProfiles {
if userProfile.DisplayName == namespaceShared2.Name {
if userProfile.DisplayName == userShared2.Name {
found = true
break
@ -294,7 +294,7 @@ func TestNormalizeToFQDNRules(t *testing.T) {
wantErr: false,
},
{
name: "namespace name with space",
name: "user name with space",
args: args{
name: "name space",
stripEmailDomain: false,
@ -303,7 +303,7 @@ func TestNormalizeToFQDNRules(t *testing.T) {
wantErr: false,
},
{
name: "namespace with quote",
name: "user with quote",
args: args{
name: "Jamie's iPhone 5",
stripEmailDomain: false,
@ -341,29 +341,29 @@ func TestCheckForFQDNRules(t *testing.T) {
wantErr bool
}{
{
name: "valid: namespace",
args: args{name: "valid-namespace"},
name: "valid: user",
args: args{name: "valid-user"},
wantErr: false,
},
{
name: "invalid: capitalized namespace",
args: args{name: "Invalid-CapItaLIzed-namespace"},
name: "invalid: capitalized user",
args: args{name: "Invalid-CapItaLIzed-user"},
wantErr: true,
},
{
name: "invalid: email as namespace",
name: "invalid: email as user",
args: args{name: "foo.bar@example.com"},
wantErr: true,
},
{
name: "invalid: chars in namespace name",
args: args{name: "super-namespace+name"},
name: "invalid: chars in user name",
args: args{name: "super-user+name"},
wantErr: true,
},
{
name: "invalid: too long name for namespace",
name: "invalid: too long name for user",
args: args{
name: "super-long-namespace-name-that-should-be-a-little-more-than-63-chars",
name: "super-long-user-name-that-should-be-a-little-more-than-63-chars",
},
wantErr: true,
},
@ -377,14 +377,14 @@ func TestCheckForFQDNRules(t *testing.T) {
}
}
func (s *Suite) TestSetMachineNamespace(c *check.C) {
oldNamespace, err := app.CreateNamespace("old")
func (s *Suite) TestSetMachineUser(c *check.C) {
oldUser, err := app.CreateUser("old")
c.Assert(err, check.IsNil)
newNamespace, err := app.CreateNamespace("new")
newUser, err := app.CreateUser("new")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(oldNamespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(oldUser.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
machine := Machine{
@ -393,23 +393,23 @@ func (s *Suite) TestSetMachineNamespace(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: oldNamespace.ID,
UserID: oldUser.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
app.db.Save(&machine)
c.Assert(machine.NamespaceID, check.Equals, oldNamespace.ID)
c.Assert(machine.UserID, check.Equals, oldUser.ID)
err = app.SetMachineNamespace(&machine, newNamespace.Name)
err = app.SetMachineUser(&machine, newUser.Name)
c.Assert(err, check.IsNil)
c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID)
c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name)
c.Assert(machine.UserID, check.Equals, newUser.ID)
c.Assert(machine.User.Name, check.Equals, newUser.Name)
err = app.SetMachineNamespace(&machine, "non-existing-namespace")
c.Assert(err, check.Equals, ErrNamespaceNotFound)
err = app.SetMachineUser(&machine, "non-existing-user")
c.Assert(err, check.Equals, ErrUserNotFound)
err = app.SetMachineNamespace(&machine, newNamespace.Name)
err = app.SetMachineUser(&machine, newUser.Name)
c.Assert(err, check.IsNil)
c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID)
c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name)
c.Assert(machine.UserID, check.Equals, newUser.ID)
c.Assert(machine.User.Name, check.Equals, newUser.Name)
}

42
oidc.go
View file

@ -171,7 +171,7 @@ var oidcCallbackTemplate = template.Must(
)
// OIDCCallback handles the callback from the OIDC endpoint
// Retrieves the nkey from the state cache and adds the machine to the users email namespace
// Retrieves the nkey from the state cache and adds the machine to the users email user
// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities
// TODO: Add groups information from OIDC tokens into machine HostInfo
// Listens in /oidc/callback.
@ -223,7 +223,7 @@ func (h *Headscale) OIDCCallback(
return
}
namespaceName, err := getNamespaceName(writer, claims, h.cfg.OIDC.StripEmaildomain)
userName, err := getUserName(writer, claims, h.cfg.OIDC.StripEmaildomain)
if err != nil {
return
}
@ -231,12 +231,12 @@ func (h *Headscale) OIDCCallback(
// register the machine if it's new
log.Debug().Msg("Registering new machine after successful callback")
namespace, err := h.findOrCreateNewNamespaceForOIDCCallback(writer, namespaceName)
user, err := h.findOrCreateNewUserForOIDCCallback(writer, userName)
if err != nil {
return
}
if err := h.registerMachineForOIDCCallback(writer, namespace, nodeKey, idToken.Expiry); err != nil {
if err := h.registerMachineForOIDCCallback(writer, user, nodeKey, idToken.Expiry); err != nil {
return
}
@ -606,12 +606,12 @@ func (h *Headscale) validateMachineForOIDCCallback(
return &nodeKey, false, nil
}
func getNamespaceName(
func getUserName(
writer http.ResponseWriter,
claims *IDTokenClaims,
stripEmaildomain bool,
) (string, error) {
namespaceName, err := NormalizeToFQDNRules(
userName, err := NormalizeToFQDNRules(
claims.Email,
stripEmaildomain,
)
@ -630,25 +630,25 @@ func getNamespaceName(
return "", err
}
return namespaceName, nil
return userName, nil
}
func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback(
func (h *Headscale) findOrCreateNewUserForOIDCCallback(
writer http.ResponseWriter,
namespaceName string,
) (*Namespace, error) {
namespace, err := h.GetNamespace(namespaceName)
if errors.Is(err, ErrNamespaceNotFound) {
namespace, err = h.CreateNamespace(namespaceName)
userName string,
) (*User, error) {
user, err := h.GetUser(userName)
if errors.Is(err, ErrUserNotFound) {
user, err = h.CreateUser(userName)
if err != nil {
log.Error().
Err(err).
Caller().
Msgf("could not create new namespace '%s'", namespaceName)
Msgf("could not create new user '%s'", userName)
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError)
_, werr := writer.Write([]byte("could not create namespace"))
_, werr := writer.Write([]byte("could not create user"))
if werr != nil {
log.Error().
Caller().
@ -662,11 +662,11 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback(
log.Error().
Caller().
Err(err).
Str("namespace", namespaceName).
Msg("could not find or create namespace")
Str("user", userName).
Msg("could not find or create user")
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError)
_, werr := writer.Write([]byte("could not find or create namespace"))
_, werr := writer.Write([]byte("could not find or create user"))
if werr != nil {
log.Error().
Caller().
@ -677,18 +677,18 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback(
return nil, err
}
return namespace, nil
return user, nil
}
func (h *Headscale) registerMachineForOIDCCallback(
writer http.ResponseWriter,
namespace *Namespace,
user *User,
nodeKey *key.NodePublic,
expiry time.Time,
) error {
if _, err := h.RegisterMachineFromAuthCallback(
nodeKey.String(),
namespace.Name,
user.Name,
&expiry,
RegisterMethodOIDC,
); err != nil {

View file

@ -18,16 +18,16 @@ const (
ErrPreAuthKeyNotFound = Error("AuthKey not found")
ErrPreAuthKeyExpired = Error("AuthKey expired")
ErrSingleUseAuthKeyHasBeenUsed = Error("AuthKey has already been used")
ErrNamespaceMismatch = Error("namespace mismatch")
ErrUserMismatch = Error("user mismatch")
ErrPreAuthKeyACLTagInvalid = Error("AuthKey tag is invalid")
)
// PreAuthKey describes a pre-authorization key usable in a particular namespace.
// PreAuthKey describes a pre-authorization key usable in a particular user.
type PreAuthKey struct {
ID uint64 `gorm:"primary_key"`
Key string
NamespaceID uint
Namespace Namespace
UserID uint
User User
Reusable bool
Ephemeral bool `gorm:"default:false"`
Used bool `gorm:"default:false"`
@ -44,15 +44,15 @@ type PreAuthKeyACLTag struct {
Tag string
}
// CreatePreAuthKey creates a new PreAuthKey in a namespace, and returns it.
// CreatePreAuthKey creates a new PreAuthKey in a user, and returns it.
func (h *Headscale) CreatePreAuthKey(
namespaceName string,
userName string,
reusable bool,
ephemeral bool,
expiration *time.Time,
aclTags []string,
) (*PreAuthKey, error) {
namespace, err := h.GetNamespace(namespaceName)
user, err := h.GetUser(userName)
if err != nil {
return nil, err
}
@ -71,8 +71,8 @@ func (h *Headscale) CreatePreAuthKey(
key := PreAuthKey{
Key: kstr,
NamespaceID: namespace.ID,
Namespace: *namespace,
UserID: user.ID,
User: *user,
Reusable: reusable,
Ephemeral: ephemeral,
CreatedAt: &now,
@ -110,15 +110,15 @@ func (h *Headscale) CreatePreAuthKey(
return &key, nil
}
// ListPreAuthKeys returns the list of PreAuthKeys for a namespace.
func (h *Headscale) ListPreAuthKeys(namespaceName string) ([]PreAuthKey, error) {
namespace, err := h.GetNamespace(namespaceName)
// ListPreAuthKeys returns the list of PreAuthKeys for a user.
func (h *Headscale) ListPreAuthKeys(userName string) ([]PreAuthKey, error) {
user, err := h.GetUser(userName)
if err != nil {
return nil, err
}
keys := []PreAuthKey{}
if err := h.db.Preload("Namespace").Preload("ACLTags").Where(&PreAuthKey{NamespaceID: namespace.ID}).Find(&keys).Error; err != nil {
if err := h.db.Preload("User").Preload("ACLTags").Where(&PreAuthKey{UserID: user.ID}).Find(&keys).Error; err != nil {
return nil, err
}
@ -126,14 +126,14 @@ func (h *Headscale) ListPreAuthKeys(namespaceName string) ([]PreAuthKey, error)
}
// GetPreAuthKey returns a PreAuthKey for a given key.
func (h *Headscale) GetPreAuthKey(namespace string, key string) (*PreAuthKey, error) {
func (h *Headscale) GetPreAuthKey(user string, key string) (*PreAuthKey, error) {
pak, err := h.checkKeyValidity(key)
if err != nil {
return nil, err
}
if pak.Namespace.Name != namespace {
return nil, ErrNamespaceMismatch
if pak.User.Name != user {
return nil, ErrUserMismatch
}
return pak, nil
@ -178,7 +178,7 @@ func (h *Headscale) UsePreAuthKey(k *PreAuthKey) error {
// If returns no error and a PreAuthKey, it can be used.
func (h *Headscale) checkKeyValidity(k string) (*PreAuthKey, error) {
pak := PreAuthKey{}
if result := h.db.Preload("Namespace").Preload("ACLTags").First(&pak, "key = ?", k); errors.Is(
if result := h.db.Preload("User").Preload("ACLTags").First(&pak, "key = ?", k); errors.Is(
result.Error,
gorm.ErrRecordNotFound,
) {
@ -217,7 +217,7 @@ func (h *Headscale) generateKey() (string, error) {
func (key *PreAuthKey) toProto() *v1.PreAuthKey {
protoKey := v1.PreAuthKey{
Namespace: key.Namespace.Name,
User: key.User.Name,
Id: strconv.FormatUint(key.ID, Base10),
Key: key.Key,
Ephemeral: key.Ephemeral,

View file

@ -11,36 +11,36 @@ func (*Suite) TestCreatePreAuthKey(c *check.C) {
c.Assert(err, check.NotNil)
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
key, err := app.CreatePreAuthKey(namespace.Name, true, false, nil, nil)
key, err := app.CreatePreAuthKey(user.Name, true, false, nil, nil)
c.Assert(err, check.IsNil)
// Did we get a valid key?
c.Assert(key.Key, check.NotNil)
c.Assert(len(key.Key), check.Equals, 48)
// Make sure the Namespace association is populated
c.Assert(key.Namespace.Name, check.Equals, namespace.Name)
// Make sure the User association is populated
c.Assert(key.User.Name, check.Equals, user.Name)
_, err = app.ListPreAuthKeys("bogus")
c.Assert(err, check.NotNil)
keys, err := app.ListPreAuthKeys(namespace.Name)
keys, err := app.ListPreAuthKeys(user.Name)
c.Assert(err, check.IsNil)
c.Assert(len(keys), check.Equals, 1)
// Make sure the Namespace association is populated
c.Assert((keys)[0].Namespace.Name, check.Equals, namespace.Name)
// Make sure the User association is populated
c.Assert((keys)[0].User.Name, check.Equals, user.Name)
}
func (*Suite) TestExpiredPreAuthKey(c *check.C) {
namespace, err := app.CreateNamespace("test2")
user, err := app.CreateUser("test2")
c.Assert(err, check.IsNil)
now := time.Now()
pak, err := app.CreatePreAuthKey(namespace.Name, true, false, &now, nil)
pak, err := app.CreatePreAuthKey(user.Name, true, false, &now, nil)
c.Assert(err, check.IsNil)
key, err := app.checkKeyValidity(pak.Key)
@ -55,10 +55,10 @@ func (*Suite) TestPreAuthKeyDoesNotExist(c *check.C) {
}
func (*Suite) TestValidateKeyOk(c *check.C) {
namespace, err := app.CreateNamespace("test3")
user, err := app.CreateUser("test3")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, true, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, true, false, nil, nil)
c.Assert(err, check.IsNil)
key, err := app.checkKeyValidity(pak.Key)
@ -67,10 +67,10 @@ func (*Suite) TestValidateKeyOk(c *check.C) {
}
func (*Suite) TestAlreadyUsedKey(c *check.C) {
namespace, err := app.CreateNamespace("test4")
user, err := app.CreateUser("test4")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
machine := Machine{
@ -79,7 +79,7 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testest",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -91,10 +91,10 @@ func (*Suite) TestAlreadyUsedKey(c *check.C) {
}
func (*Suite) TestReusableBeingUsedKey(c *check.C) {
namespace, err := app.CreateNamespace("test5")
user, err := app.CreateUser("test5")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, true, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, true, false, nil, nil)
c.Assert(err, check.IsNil)
machine := Machine{
@ -103,7 +103,7 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testest",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}
@ -115,10 +115,10 @@ func (*Suite) TestReusableBeingUsedKey(c *check.C) {
}
func (*Suite) TestNotReusableNotBeingUsedKey(c *check.C) {
namespace, err := app.CreateNamespace("test6")
user, err := app.CreateUser("test6")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
key, err := app.checkKeyValidity(pak.Key)
@ -127,10 +127,10 @@ func (*Suite) TestNotReusableNotBeingUsedKey(c *check.C) {
}
func (*Suite) TestEphemeralKey(c *check.C) {
namespace, err := app.CreateNamespace("test7")
user, err := app.CreateUser("test7")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, true, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, true, nil, nil)
c.Assert(err, check.IsNil)
now := time.Now()
@ -140,7 +140,7 @@ func (*Suite) TestEphemeralKey(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testest",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
LastSeen: &now,
AuthKeyID: uint(pak.ID),
@ -162,10 +162,10 @@ func (*Suite) TestEphemeralKey(c *check.C) {
}
func (*Suite) TestExpirePreauthKey(c *check.C) {
namespace, err := app.CreateNamespace("test3")
user, err := app.CreateUser("test3")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, true, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, true, false, nil, nil)
c.Assert(err, check.IsNil)
c.Assert(pak.Expiration, check.IsNil)
@ -179,10 +179,10 @@ func (*Suite) TestExpirePreauthKey(c *check.C) {
}
func (*Suite) TestNotReusableMarkedAsUsed(c *check.C) {
namespace, err := app.CreateNamespace("test6")
user, err := app.CreateUser("test6")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
pak.Used = true
app.db.Save(&pak)
@ -192,15 +192,15 @@ func (*Suite) TestNotReusableMarkedAsUsed(c *check.C) {
}
func (*Suite) TestPreAuthKeyACLTags(c *check.C) {
namespace, err := app.CreateNamespace("test8")
user, err := app.CreateUser("test8")
c.Assert(err, check.IsNil)
_, err = app.CreatePreAuthKey(namespace.Name, false, false, nil, []string{"badtag"})
_, err = app.CreatePreAuthKey(user.Name, false, false, nil, []string{"badtag"})
c.Assert(err, check.NotNil) // Confirm that malformed tags are rejected
tags := []string{"tag:test1", "tag:test2"}
tagsWithDuplicate := []string{"tag:test1", "tag:test2", "tag:test2"}
_, err = app.CreatePreAuthKey(namespace.Name, false, false, nil, tagsWithDuplicate)
_, err = app.CreatePreAuthKey(user.Name, false, false, nil, tagsWithDuplicate)
c.Assert(err, check.IsNil)
listedPaks, err := app.ListPreAuthKeys("test8")

View file

@ -325,7 +325,7 @@ func (h *Headscale) handleAuthKeyCommon(
Err(err).
Msg("Cannot encode message")
http.Error(writer, "Internal server error", http.StatusInternalServerError)
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
return
@ -350,7 +350,7 @@ func (h *Headscale) handleAuthKeyCommon(
Msg("Failed authentication via AuthKey")
if pak != nil {
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
} else {
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", "unknown").Inc()
@ -428,7 +428,7 @@ func (h *Headscale) handleAuthKeyCommon(
machineToRegister := Machine{
Hostname: registerRequest.Hostinfo.Hostname,
GivenName: givenName,
NamespaceID: pak.Namespace.ID,
UserID: pak.User.ID,
MachineKey: MachinePublicKeyStripPrefix(machineKey),
RegisterMethod: RegisterMethodAuthKey,
Expiry: &registerRequest.Expiry,
@ -447,7 +447,7 @@ func (h *Headscale) handleAuthKeyCommon(
Bool("noise", isNoise).
Err(err).
Msg("could not register machine")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -462,7 +462,7 @@ func (h *Headscale) handleAuthKeyCommon(
Bool("noise", isNoise).
Err(err).
Msg("Failed to use pre-auth key")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -470,10 +470,10 @@ func (h *Headscale) handleAuthKeyCommon(
}
resp.MachineAuthorized = true
resp.User = *pak.Namespace.toUser()
resp.User = *pak.User.toTailscaleUser()
// Provide LoginName when registering with pre-auth key
// Otherwise it will need to exec `tailscale up` twice to fetch the *LoginName*
resp.Login = *pak.Namespace.toLogin()
resp.Login = *pak.User.toTailscaleLogin()
respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil {
@ -484,13 +484,13 @@ func (h *Headscale) handleAuthKeyCommon(
Str("machine", registerRequest.Hostinfo.Hostname).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "success", pak.Namespace.Name).
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "success", pak.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
writer.WriteHeader(http.StatusOK)
@ -600,7 +600,7 @@ func (h *Headscale) handleMachineLogOutCommon(
resp.AuthURL = ""
resp.MachineAuthorized = false
resp.NodeKeyExpired = true
resp.User = *machine.Namespace.toUser()
resp.User = *machine.User.toTailscaleUser()
respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil {
log.Error().
@ -662,8 +662,8 @@ func (h *Headscale) handleMachineValidRegistrationCommon(
resp.AuthURL = ""
resp.MachineAuthorized = true
resp.User = *machine.Namespace.toUser()
resp.Login = *machine.Namespace.toLogin()
resp.User = *machine.User.toTailscaleUser()
resp.Login = *machine.User.toTailscaleLogin()
respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil {
@ -672,13 +672,13 @@ func (h *Headscale) handleMachineValidRegistrationCommon(
Bool("noise", isNoise).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("update", "web", "error", machine.Namespace.Name).
machineRegistrations.WithLabelValues("update", "web", "error", machine.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("update", "web", "success", machine.Namespace.Name).
machineRegistrations.WithLabelValues("update", "web", "success", machine.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
@ -726,7 +726,7 @@ func (h *Headscale) handleMachineRefreshKeyCommon(
}
resp.AuthURL = ""
resp.User = *machine.Namespace.toUser()
resp.User = *machine.User.toTailscaleUser()
respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil {
log.Error().
@ -801,13 +801,13 @@ func (h *Headscale) handleMachineExpiredOrLoggedOutCommon(
Bool("noise", isNoise).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("reauth", "web", "error", machine.Namespace.Name).
machineRegistrations.WithLabelValues("reauth", "web", "error", machine.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("reauth", "web", "success", machine.Namespace.Name).
machineRegistrations.WithLabelValues("reauth", "web", "success", machine.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")

View file

@ -183,7 +183,7 @@ func (h *Headscale) handlePollCommon(
}
// It sounds like we should update the nodes when we have received a endpoint update
// even tho the comments in the tailscale code dont explicitly say so.
updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "endpoint-update").
updateRequestsFromNode.WithLabelValues(machine.User.Name, machine.Hostname, "endpoint-update").
Inc()
updateChan <- struct{}{}
@ -216,7 +216,7 @@ func (h *Headscale) handlePollCommon(
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Msg("Notifying peers")
updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "full-update").
updateRequestsFromNode.WithLabelValues(machine.User.Name, machine.Hostname, "full-update").
Inc()
updateChan <- struct{}{}
@ -342,7 +342,7 @@ func (h *Headscale) pollNetMapStream(
now := time.Now().UTC()
machine.LastSeen = &now
lastStateUpdate.WithLabelValues(machine.Namespace.Name, machine.Hostname).
lastStateUpdate.WithLabelValues(machine.User.Name, machine.Hostname).
Set(float64(now.Unix()))
machine.LastSuccessfulUpdate = &now
@ -453,7 +453,7 @@ func (h *Headscale) pollNetMapStream(
Str("machine", machine.Hostname).
Str("channel", "update").
Msg("Received a request for update")
updateRequestsReceivedOnChannel.WithLabelValues(machine.Namespace.Name, machine.Hostname).
updateRequestsReceivedOnChannel.WithLabelValues(machine.User.Name, machine.Hostname).
Inc()
if h.isOutdated(machine) {
@ -466,7 +466,7 @@ func (h *Headscale) pollNetMapStream(
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Time("last_successful_update", lastUpdate).
Time("last_state_change", h.getLastStateChange(machine.Namespace)).
Time("last_state_change", h.getLastStateChange(machine.User)).
Msgf("There has been updates since the last successful update to %s", machine.Hostname)
data, err := h.getMapResponseData(mapRequest, machine, isNoise)
if err != nil {
@ -489,7 +489,7 @@ func (h *Headscale) pollNetMapStream(
Str("channel", "update").
Err(err).
Msg("Could not write the map response")
updateRequestsSentToNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "failed").
updateRequestsSentToNode.WithLabelValues(machine.User.Name, machine.Hostname, "failed").
Inc()
return
@ -514,7 +514,7 @@ func (h *Headscale) pollNetMapStream(
Str("machine", machine.Hostname).
Str("channel", "update").
Msg("Updated Map has been sent")
updateRequestsSentToNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "success").
updateRequestsSentToNode.WithLabelValues(machine.User.Name, machine.Hostname, "success").
Inc()
// Keep track of the last successful update,
@ -540,7 +540,7 @@ func (h *Headscale) pollNetMapStream(
}
now := time.Now().UTC()
lastStateUpdate.WithLabelValues(machine.Namespace.Name, machine.Hostname).
lastStateUpdate.WithLabelValues(machine.User.Name, machine.Hostname).
Set(float64(now.Unix()))
machine.LastSuccessfulUpdate = &now
@ -566,7 +566,7 @@ func (h *Headscale) pollNetMapStream(
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Time("last_successful_update", lastUpdate).
Time("last_state_change", h.getLastStateChange(machine.Namespace)).
Time("last_state_change", h.getLastStateChange(machine.User)).
Msgf("%s is up to date", machine.Hostname)
}
@ -676,7 +676,7 @@ func (h *Headscale) scheduledPollWorker(
Str("machine", machine.Hostname).
Bool("noise", isNoise).
Msg("Sending update request")
updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "scheduled-update").
updateRequestsFromNode.WithLabelValues(machine.User.Name, machine.Hostname, "scheduled-update").
Inc()
select {
case updateChan <- struct{}{}:

View file

@ -10,10 +10,10 @@ import (
)
func (s *Suite) TestGetRoutes(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "test_get_route_machine")
@ -32,7 +32,7 @@ func (s *Suite) TestGetRoutes(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_get_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -54,10 +54,10 @@ func (s *Suite) TestGetRoutes(c *check.C) {
}
func (s *Suite) TestGetEnableRoutes(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "test_enable_route_machine")
@ -83,7 +83,7 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo),
@ -129,10 +129,10 @@ func (s *Suite) TestGetEnableRoutes(c *check.C) {
}
func (s *Suite) TestIsUniquePrefix(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "test_enable_route_machine")
@ -157,7 +157,7 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo1),
@ -182,7 +182,7 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo2),
@ -213,10 +213,10 @@ func (s *Suite) TestIsUniquePrefix(c *check.C) {
}
func (s *Suite) TestSubnetFailover(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "test_enable_route_machine")
@ -243,7 +243,7 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo1),
@ -280,7 +280,7 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo2),
@ -358,10 +358,10 @@ func (s *Suite) TestSubnetFailover(c *check.C) {
// including both the primary routes the node is responsible for, and the
// exit node routes if enabled.
func (s *Suite) TestAllowedIPRoutes(c *check.C) {
namespace, err := app.CreateNamespace("test")
user, err := app.CreateUser("test")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "test_enable_route_machine")
@ -402,7 +402,7 @@ func (s *Suite) TestAllowedIPRoutes(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: DiscoPublicKeyStripPrefix(discoKey.Public()),
Hostname: "test_enable_route_machine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo1),

View file

@ -22,10 +22,10 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
ips, err := app.getAvailableIPs()
c.Assert(err, check.IsNil)
namespace, err := app.CreateNamespace("test-ip")
user, err := app.CreateUser("test-ip")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -37,7 +37,7 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
IPAddresses: ips,
@ -64,7 +64,7 @@ func (s *Suite) TestGetUsedIps(c *check.C) {
}
func (s *Suite) TestGetMultiIp(c *check.C) {
namespace, err := app.CreateNamespace("test-ip-multi")
user, err := app.CreateUser("test-ip-multi")
c.Assert(err, check.IsNil)
for index := 1; index <= 350; index++ {
@ -73,7 +73,7 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
ips, err := app.getAvailableIPs()
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -85,7 +85,7 @@ func (s *Suite) TestGetMultiIp(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
IPAddresses: ips,
@ -160,10 +160,10 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
c.Assert(len(ips), check.Equals, 1)
c.Assert(ips[0].String(), check.Equals, expected.String())
namespace, err := app.CreateNamespace("test-ip")
user, err := app.CreateUser("test-ip")
c.Assert(err, check.IsNil)
pak, err := app.CreatePreAuthKey(namespace.Name, false, false, nil, nil)
pak, err := app.CreatePreAuthKey(user.Name, false, false, nil, nil)
c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine")
@ -175,7 +175,7 @@ func (s *Suite) TestGetAvailableIpMachineWithoutIP(c *check.C) {
NodeKey: "bar",
DiscoKey: "faa",
Hostname: "testmachine",
NamespaceID: namespace.ID,
UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID),
}