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

View file

@ -77,10 +77,10 @@ func (s *Suite) TestInvalidAction(c *check.C) {
func (s *Suite) TestSshRules(c *check.C) { func (s *Suite) TestSshRules(c *check.C) {
envknob.Setenv("HEADSCALE_EXPERIMENTAL_FEATURE_SSH", "1") envknob.Setenv("HEADSCALE_EXPERIMENTAL_FEATURE_SSH", "1")
namespace, err := app.CreateNamespace("user1") user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine") _, err = app.GetMachine("user1", "testmachine")
@ -98,7 +98,7 @@ func (s *Suite) TestSshRules(c *check.C) {
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo), 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. // 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. // the tag is matched in the Sources section.
func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) { func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
namespace, err := app.CreateNamespace("user1") user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine") _, err = app.GetMachine("user1", "testmachine")
@ -208,7 +208,7 @@ func (s *Suite) TestValidExpandTagOwnersInSources(c *check.C) {
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo), 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. // 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. // the tag is matched in the Destinations section.
func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) { func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
namespace, err := app.CreateNamespace("user1") user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine") _, err = app.GetMachine("user1", "testmachine")
@ -258,7 +258,7 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo), HostInfo: HostInfo(hostInfo),
@ -284,13 +284,13 @@ func (s *Suite) TestValidExpandTagOwnersInDestinations(c *check.C) {
} }
// need a test with: // 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. // of the host should be valid.
func (s *Suite) TestInvalidTagValidNamespace(c *check.C) { func (s *Suite) TestInvalidTagValidUser(c *check.C) {
namespace, err := app.CreateNamespace("user1") user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "testmachine") _, err = app.GetMachine("user1", "testmachine")
@ -308,7 +308,7 @@ func (s *Suite) TestInvalidTagValidNamespace(c *check.C) {
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo), 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. // 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. // host should be tied to the tag now.
func (s *Suite) TestValidTagInvalidNamespace(c *check.C) { func (s *Suite) TestValidTagInvalidUser(c *check.C) {
namespace, err := app.CreateNamespace("user1") user, err := app.CreateUser("user1")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("user1", "webserver") _, err = app.GetMachine("user1", "webserver")
@ -357,7 +357,7 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "webserver", Hostname: "webserver",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo), HostInfo: HostInfo(hostInfo),
@ -376,7 +376,7 @@ func (s *Suite) TestValidTagInvalidNamespace(c *check.C) {
DiscoKey: "faab", DiscoKey: "faab",
Hostname: "user", Hostname: "user",
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo(hostInfo2), HostInfo: HostInfo(hostInfo2),
@ -467,14 +467,14 @@ func (s *Suite) TestPortWildcardYAML(c *check.C) {
c.Assert(rules[0].SrcIPs[0], check.Equals, "*") c.Assert(rules[0].SrcIPs[0], check.Equals, "*")
} }
func (s *Suite) TestPortNamespace(c *check.C) { func (s *Suite) TestPortUser(c *check.C) {
namespace, err := app.CreateNamespace("testnamespace") user, err := app.CreateUser("testuser")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("testnamespace", "testmachine") _, err = app.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs() ips, _ := app.getAvailableIPs()
machine := Machine{ machine := Machine{
@ -483,7 +483,7 @@ func (s *Suite) TestPortNamespace(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: ips, IPAddresses: ips,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
@ -491,7 +491,7 @@ func (s *Suite) TestPortNamespace(c *check.C) {
app.db.Save(&machine) app.db.Save(&machine)
err = app.LoadACLPolicy( 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) c.Assert(err, check.IsNil)
@ -513,13 +513,13 @@ func (s *Suite) TestPortNamespace(c *check.C) {
} }
func (s *Suite) TestPortGroup(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("testnamespace", "testmachine") _, err = app.GetMachine("testuser", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
ips, _ := app.getAvailableIPs() ips, _ := app.getAvailableIPs()
machine := Machine{ machine := Machine{
@ -528,7 +528,7 @@ func (s *Suite) TestPortGroup(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: ips, IPAddresses: ips,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
@ -689,7 +689,7 @@ func Test_expandTagOwners(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "expand with namespace and group", name: "expand with user and group",
args: args{ args: args{
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
Groups: Groups{"group:foo": []string{"user1", "user2"}}, 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 { type args struct {
machines []Machine machines []Machine
namespace string user string
} }
tests := []struct { tests := []struct {
name string name string
@ -854,54 +854,54 @@ func Test_listMachinesInNamespace(t *testing.T) {
want []Machine want []Machine
}{ }{
{ {
name: "1 machine in namespace", name: "1 machine in user",
args: args{ args: args{
machines: []Machine{ machines: []Machine{
{Namespace: Namespace{Name: "joe"}}, {User: User{Name: "joe"}},
}, },
namespace: "joe", user: "joe",
}, },
want: []Machine{ want: []Machine{
{Namespace: Namespace{Name: "joe"}}, {User: User{Name: "joe"}},
}, },
}, },
{ {
name: "3 machines, 2 in namespace", name: "3 machines, 2 in user",
args: args{ args: args{
machines: []Machine{ machines: []Machine{
{ID: 1, Namespace: Namespace{Name: "joe"}}, {ID: 1, User: User{Name: "joe"}},
{ID: 2, Namespace: Namespace{Name: "marc"}}, {ID: 2, User: User{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}}, {ID: 3, User: User{Name: "marc"}},
}, },
namespace: "marc", user: "marc",
}, },
want: []Machine{ want: []Machine{
{ID: 2, Namespace: Namespace{Name: "marc"}}, {ID: 2, User: User{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}}, {ID: 3, User: User{Name: "marc"}},
}, },
}, },
{ {
name: "5 machines, 0 in namespace", name: "5 machines, 0 in user",
args: args{ args: args{
machines: []Machine{ machines: []Machine{
{ID: 1, Namespace: Namespace{Name: "joe"}}, {ID: 1, User: User{Name: "joe"}},
{ID: 2, Namespace: Namespace{Name: "marc"}}, {ID: 2, User: User{Name: "marc"}},
{ID: 3, Namespace: Namespace{Name: "marc"}}, {ID: 3, User: User{Name: "marc"}},
{ID: 4, Namespace: Namespace{Name: "marc"}}, {ID: 4, User: User{Name: "marc"}},
{ID: 5, Namespace: Namespace{Name: "marc"}}, {ID: 5, User: User{Name: "marc"}},
}, },
namespace: "mickael", user: "mickael",
}, },
want: []Machine{}, want: []Machine{},
}, },
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { 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, got,
test.want, 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -985,25 +985,25 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -1071,7 +1071,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1082,7 +1082,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1093,13 +1093,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -1119,25 +1119,25 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -1160,27 +1160,27 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"}, ForcedTags: []string{"tag:hr-webserver"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"}, ForcedTags: []string{"tag:hr-webserver"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
aclPolicy: ACLPolicy{}, aclPolicy: ACLPolicy{},
@ -1198,14 +1198,14 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
ForcedTags: []string{"tag:hr-webserver"}, ForcedTags: []string{"tag:hr-webserver"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1216,13 +1216,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -1236,7 +1236,7 @@ func Test_expandAlias(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "list host in namespace without correctly tagged servers", name: "list host in user without correctly tagged servers",
args: args{ args: args{
alias: "joe", alias: "joe",
machines: []Machine{ machines: []Machine{
@ -1244,7 +1244,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1255,7 +1255,7 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1266,13 +1266,13 @@ func Test_expandAlias(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
aclPolicy: ACLPolicy{ aclPolicy: ACLPolicy{
@ -1308,7 +1308,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
type args struct { type args struct {
aclPolicy ACLPolicy aclPolicy ACLPolicy
nodes []Machine nodes []Machine
namespace string user string
stripEmailDomain bool stripEmailDomain bool
} }
tests := []struct { tests := []struct {
@ -1328,7 +1328,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1339,7 +1339,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1350,16 +1350,16 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
namespace: "joe", user: "joe",
stripEmailDomain: true, stripEmailDomain: true,
}, },
want: []Machine{ want: []Machine{
{ {
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")}, 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1390,7 +1390,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1401,16 +1401,16 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
namespace: "joe", user: "joe",
stripEmailDomain: true, stripEmailDomain: true,
}, },
want: []Machine{ want: []Machine{
{ {
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")}, 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "foo", Hostname: "foo",
@ -1436,23 +1436,23 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
ForcedTags: []string{"tag:accountant-webserver"}, ForcedTags: []string{"tag:accountant-webserver"},
}, },
{ {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
namespace: "joe", user: "joe",
stripEmailDomain: true, stripEmailDomain: true,
}, },
want: []Machine{ want: []Machine{
{ {
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.4")}, 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "hr-web1", Hostname: "hr-web1",
@ -1478,7 +1478,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "hr-web2", Hostname: "hr-web2",
@ -1489,10 +1489,10 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), netip.MustParseAddr("100.64.0.4"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
namespace: "joe", user: "joe",
stripEmailDomain: true, stripEmailDomain: true,
}, },
want: []Machine{ want: []Machine{
@ -1500,7 +1500,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "hr-web1", Hostname: "hr-web1",
@ -1511,7 +1511,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
HostInfo: HostInfo{ HostInfo: HostInfo{
OS: "centos", OS: "centos",
Hostname: "hr-web2", Hostname: "hr-web2",
@ -1522,7 +1522,7 @@ func Test_excludeCorrectlyTaggedNodes(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.4"), 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( got := excludeCorrectlyTaggedNodes(
test.args.aclPolicy, test.args.aclPolicy,
test.args.nodes, test.args.nodes,
test.args.namespace, test.args.user,
test.args.stripEmailDomain, test.args.stripEmailDomain,
) )
if !reflect.DeepEqual(got, test.want) { 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. // Hosts are alias for IP addresses or subnets.
type Hosts map[string]netip.Prefix 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 type TagOwners map[string][]string
// ACLTest is not implemented, but should be use to check if a certain rule is allowed. // 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"` 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. // or exit node status automatically enabled.
type AutoApprovers struct { type AutoApprovers struct {
Routes map[string][]string `json:"routes" yaml:"routes"` Routes map[string][]string `json:"routes" yaml:"routes"`
@ -119,7 +119,7 @@ func (policy ACLPolicy) IsZero() bool {
return false 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( func (autoApprovers *AutoApprovers) GetRouteApprovers(
prefix netip.Prefix, prefix netip.Prefix,
) ([]string, error) { ) ([]string, error) {

View file

@ -29,7 +29,7 @@ type APIKey struct {
LastSeen *time.Time 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( func (h *Headscale) CreateAPIKey(
expiration *time.Time, expiration *time.Time,
) (string, *APIKey, error) { ) (string, *APIKey, error) {
@ -64,7 +64,7 @@ func (h *Headscale) CreateAPIKey(
return keyStr, &key, nil 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) { func (h *Headscale) ListAPIKeys() ([]APIKey, error) {
keys := []APIKey{} keys := []APIKey{}
if err := h.db.Find(&keys).Error; err != nil { 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() { func (h *Headscale) expireEphemeralNodesWorker() {
namespaces, err := h.ListNamespaces() users, err := h.ListUsers()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Error listing namespaces") log.Error().Err(err).Msg("Error listing users")
return return
} }
for _, namespace := range namespaces { for _, user := range users {
machines, err := h.ListMachinesInNamespace(namespace.Name) machines, err := h.ListMachinesByUser(user.Name)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("namespace", namespace.Name). Str("user", user.Name).
Msg("Error listing machines in namespace") Msg("Error listing machines in user")
return return
} }
@ -283,20 +283,20 @@ func (h *Headscale) expireEphemeralNodesWorker() {
} }
func (h *Headscale) expireExpiredMachinesWorker() { func (h *Headscale) expireExpiredMachinesWorker() {
namespaces, err := h.ListNamespaces() users, err := h.ListUsers()
if err != nil { if err != nil {
log.Error().Err(err).Msg("Error listing namespaces") log.Error().Err(err).Msg("Error listing users")
return return
} }
for _, namespace := range namespaces { for _, user := range users {
machines, err := h.ListMachinesInNamespace(namespace.Name) machines, err := h.ListMachinesByUser(user.Name)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("namespace", namespace.Name). Str("user", user.Name).
Msg("Error listing machines in namespace") Msg("Error listing machines in user")
return return
} }
@ -304,7 +304,7 @@ func (h *Headscale) expireExpiredMachinesWorker() {
expiredFound := false expiredFound := false
for index, machine := range machines { for index, machine := range machines {
if machine.isExpired() && if machine.isExpired() &&
machine.Expiry.After(h.getLastStateChange(namespace)) { machine.Expiry.After(h.getLastStateChange(user)) {
expiredFound = true expiredFound = true
err := h.ExpireMachine(&machines[index]) err := h.ExpireMachine(&machines[index])
@ -908,31 +908,31 @@ func (h *Headscale) setLastStateChangeToNow() {
now := time.Now().UTC() now := time.Now().UTC()
namespaces, err := h.ListNamespaces() users, err := h.ListUsers()
if err != nil { if err != nil {
log.Error(). log.Error().
Caller(). Caller().
Err(err). 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 { for _, user := range users {
lastStateUpdate.WithLabelValues(namespace.Name, "headscale").Set(float64(now.Unix())) lastStateUpdate.WithLabelValues(user.Name, "headscale").Set(float64(now.Unix()))
if h.lastStateChange == nil { if h.lastStateChange == nil {
h.lastStateChange = xsync.NewMapOf[time.Time]() 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{} times := []time.Time{}
// getLastStateChange takes a list of namespaces as a "filter", if no namespaces // getLastStateChange takes a list of users as a "filter", if no users
// are past, then use the entier list of namespaces and look for the last update // are past, then use the entier list of users and look for the last update
if len(namespaces) > 0 { if len(users) > 0 {
for _, namespace := range namespaces { for _, user := range users {
if lastChange, ok := h.lastStateChange.Load(namespace.Name); ok { if lastChange, ok := h.lastStateChange.Load(user.Name); ok {
times = append(times, lastChange) times = append(times, lastChange)
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

14
dns.go
View file

@ -190,23 +190,23 @@ func getMapResponseDNSConfig(
) *tailcfg.DNSConfig { ) *tailcfg.DNSConfig {
var dnsConfig *tailcfg.DNSConfig = dnsConfigOrig.Clone() var dnsConfig *tailcfg.DNSConfig = dnsConfigOrig.Clone()
if dnsConfigOrig != nil && dnsConfigOrig.Proxied { // if MagicDNS is enabled 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 = append(
dnsConfig.Domains, dnsConfig.Domains,
fmt.Sprintf( fmt.Sprintf(
"%s.%s", "%s.%s",
machine.Namespace.Name, machine.User.Name,
baseDomain, baseDomain,
), ),
) )
namespaceSet := mapset.NewSet[Namespace]() userSet := mapset.NewSet[User]()
namespaceSet.Add(machine.Namespace) userSet.Add(machine.User)
for _, p := range peers { for _, p := range peers {
namespaceSet.Add(p.Namespace) userSet.Add(p.User)
} }
for _, namespace := range namespaceSet.ToSlice() { for _, user := range userSet.ToSlice() {
dnsRoute := fmt.Sprintf("%v.%v", namespace.Name, baseDomain) dnsRoute := fmt.Sprintf("%v.%v", user.Name, baseDomain)
dnsConfig.Routes[dnsRoute] = nil dnsConfig.Routes[dnsRoute] = nil
} }
} else { } else {

View file

@ -112,17 +112,17 @@ func (s *Suite) TestMagicDNSRootDomainsIPv6SingleMultiple(c *check.C) {
} }
func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(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) c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2") userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3") userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared1, err := app.CreatePreAuthKey( preAuthKeyInShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -131,7 +131,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared2, err := app.CreatePreAuthKey( preAuthKeyInShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name, userShared2.Name,
false, false,
false, false,
nil, nil,
@ -140,7 +140,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared3, err := app.CreatePreAuthKey( preAuthKeyInShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name, userShared3.Name,
false, false,
false, false,
nil, nil,
@ -149,7 +149,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
PreAuthKey2InShared1, err := app.CreatePreAuthKey( PreAuthKey2InShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -157,7 +157,7 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
) )
c.Assert(err, check.IsNil) 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) c.Assert(err, check.NotNil)
machineInShared1 := &Machine{ machineInShared1 := &Machine{
@ -166,15 +166,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1", Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyInShared1.ID), AuthKeyID: uint(preAuthKeyInShared1.ID),
} }
app.db.Save(machineInShared1) app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname) _, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared2 := &Machine{ machineInShared2 := &Machine{
@ -183,15 +183,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2", Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID, UserID: userShared2.ID,
Namespace: *namespaceShared2, User: *userShared2,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyInShared2.ID), AuthKeyID: uint(preAuthKeyInShared2.ID),
} }
app.db.Save(machineInShared2) app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname) _, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared3 := &Machine{ machineInShared3 := &Machine{
@ -200,15 +200,15 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3", Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID, UserID: userShared3.ID,
Namespace: *namespaceShared3, User: *userShared3,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyInShared3.ID), AuthKeyID: uint(preAuthKeyInShared3.ID),
} }
app.db.Save(machineInShared3) app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname) _, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{ machine2InShared1 := &Machine{
@ -217,8 +217,8 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4", Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(PreAuthKey2InShared1.ID), AuthKeyID: uint(PreAuthKey2InShared1.ID),
@ -245,31 +245,31 @@ func (s *Suite) TestDNSConfigMapResponseWithMagicDNS(c *check.C) {
c.Assert(len(dnsConfig.Routes), check.Equals, 3) 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] _, ok := dnsConfig.Routes[domainRouteShared1]
c.Assert(ok, check.Equals, true) 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] _, ok = dnsConfig.Routes[domainRouteShared2]
c.Assert(ok, check.Equals, true) 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] _, ok = dnsConfig.Routes[domainRouteShared3]
c.Assert(ok, check.Equals, true) c.Assert(ok, check.Equals, true)
} }
func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) { func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
namespaceShared1, err := app.CreateNamespace("shared1") userShared1, err := app.CreateUser("shared1")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2") userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3") userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared1, err := app.CreatePreAuthKey( preAuthKeyInShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -278,7 +278,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared2, err := app.CreatePreAuthKey( preAuthKeyInShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name, userShared2.Name,
false, false,
false, false,
nil, nil,
@ -287,7 +287,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyInShared3, err := app.CreatePreAuthKey( preAuthKeyInShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name, userShared3.Name,
false, false,
false, false,
nil, nil,
@ -296,7 +296,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKey2InShared1, err := app.CreatePreAuthKey( preAuthKey2InShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -304,7 +304,7 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
) )
c.Assert(err, check.IsNil) 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) c.Assert(err, check.NotNil)
machineInShared1 := &Machine{ machineInShared1 := &Machine{
@ -313,15 +313,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1", Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyInShared1.ID), AuthKeyID: uint(preAuthKeyInShared1.ID),
} }
app.db.Save(machineInShared1) app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname) _, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared2 := &Machine{ machineInShared2 := &Machine{
@ -330,15 +330,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2", Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID, UserID: userShared2.ID,
Namespace: *namespaceShared2, User: *userShared2,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyInShared2.ID), AuthKeyID: uint(preAuthKeyInShared2.ID),
} }
app.db.Save(machineInShared2) app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname) _, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared3 := &Machine{ machineInShared3 := &Machine{
@ -347,15 +347,15 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3", Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID, UserID: userShared3.ID,
Namespace: *namespaceShared3, User: *userShared3,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyInShared3.ID), AuthKeyID: uint(preAuthKeyInShared3.ID),
} }
app.db.Save(machineInShared3) app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname) _, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{ machine2InShared1 := &Machine{
@ -364,8 +364,8 @@ func (s *Suite) TestDNSConfigMapResponseWithoutMagicDNS(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4", Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(preAuthKey2InShared1.ID), 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, ctx context.Context,
request *v1.GetNamespaceRequest, request *v1.GetUserRequest,
) (*v1.GetNamespaceResponse, error) { ) (*v1.GetUserResponse, error) {
namespace, err := api.h.GetNamespace(request.GetName()) user, err := api.h.GetUser(request.GetName())
if err != nil { if err != nil {
return nil, err 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, ctx context.Context,
request *v1.CreateNamespaceRequest, request *v1.CreateUserRequest,
) (*v1.CreateNamespaceResponse, error) { ) (*v1.CreateUserResponse, error) {
namespace, err := api.h.CreateNamespace(request.GetName()) user, err := api.h.CreateUser(request.GetName())
if err != nil { if err != nil {
return nil, err 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, ctx context.Context,
request *v1.RenameNamespaceRequest, request *v1.RenameUserRequest,
) (*v1.RenameNamespaceResponse, error) { ) (*v1.RenameUserResponse, error) {
err := api.h.RenameNamespace(request.GetOldName(), request.GetNewName()) err := api.h.RenameUser(request.GetOldName(), request.GetNewName())
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespace, err := api.h.GetNamespace(request.GetNewName()) user, err := api.h.GetUser(request.GetNewName())
if err != nil { if err != nil {
return nil, err 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, ctx context.Context,
request *v1.DeleteNamespaceRequest, request *v1.DeleteUserRequest,
) (*v1.DeleteNamespaceResponse, error) { ) (*v1.DeleteUserResponse, error) {
err := api.h.DestroyNamespace(request.GetName()) err := api.h.DestroyUser(request.GetName())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &v1.DeleteNamespaceResponse{}, nil return &v1.DeleteUserResponse{}, nil
} }
func (api headscaleV1APIServer) ListNamespaces( func (api headscaleV1APIServer) ListUsers(
ctx context.Context, ctx context.Context,
request *v1.ListNamespacesRequest, request *v1.ListUsersRequest,
) (*v1.ListNamespacesResponse, error) { ) (*v1.ListUsersResponse, error) {
namespaces, err := api.h.ListNamespaces() users, err := api.h.ListUsers()
if err != nil { if err != nil {
return nil, err return nil, err
} }
response := make([]*v1.Namespace, len(namespaces)) response := make([]*v1.User, len(users))
for index, namespace := range namespaces { for index, user := range users {
response[index] = namespace.toProto() 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( func (api headscaleV1APIServer) CreatePreAuthKey(
@ -117,7 +117,7 @@ func (api headscaleV1APIServer) CreatePreAuthKey(
} }
preAuthKey, err := api.h.CreatePreAuthKey( preAuthKey, err := api.h.CreatePreAuthKey(
request.GetNamespace(), request.GetUser(),
request.GetReusable(), request.GetReusable(),
request.GetEphemeral(), request.GetEphemeral(),
&expiration, &expiration,
@ -134,7 +134,7 @@ func (api headscaleV1APIServer) ExpirePreAuthKey(
ctx context.Context, ctx context.Context,
request *v1.ExpirePreAuthKeyRequest, request *v1.ExpirePreAuthKeyRequest,
) (*v1.ExpirePreAuthKeyResponse, error) { ) (*v1.ExpirePreAuthKeyResponse, error) {
preAuthKey, err := api.h.GetPreAuthKey(request.GetNamespace(), request.Key) preAuthKey, err := api.h.GetPreAuthKey(request.GetUser(), request.Key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -151,7 +151,7 @@ func (api headscaleV1APIServer) ListPreAuthKeys(
ctx context.Context, ctx context.Context,
request *v1.ListPreAuthKeysRequest, request *v1.ListPreAuthKeysRequest,
) (*v1.ListPreAuthKeysResponse, error) { ) (*v1.ListPreAuthKeysResponse, error) {
preAuthKeys, err := api.h.ListPreAuthKeys(request.GetNamespace()) preAuthKeys, err := api.h.ListPreAuthKeys(request.GetUser())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -169,13 +169,13 @@ func (api headscaleV1APIServer) RegisterMachine(
request *v1.RegisterMachineRequest, request *v1.RegisterMachineRequest,
) (*v1.RegisterMachineResponse, error) { ) (*v1.RegisterMachineResponse, error) {
log.Trace(). log.Trace().
Str("namespace", request.GetNamespace()). Str("user", request.GetUser()).
Str("node_key", request.GetKey()). Str("node_key", request.GetKey()).
Msg("Registering machine") Msg("Registering machine")
machine, err := api.h.RegisterMachineFromAuthCallback( machine, err := api.h.RegisterMachineFromAuthCallback(
request.GetKey(), request.GetKey(),
request.GetNamespace(), request.GetUser(),
nil, nil,
RegisterMethodCLI, RegisterMethodCLI,
) )
@ -313,8 +313,8 @@ func (api headscaleV1APIServer) ListMachines(
ctx context.Context, ctx context.Context,
request *v1.ListMachinesRequest, request *v1.ListMachinesRequest,
) (*v1.ListMachinesResponse, error) { ) (*v1.ListMachinesResponse, error) {
if request.GetNamespace() != "" { if request.GetUser() != "" {
machines, err := api.h.ListMachinesInNamespace(request.GetNamespace()) machines, err := api.h.ListMachinesByUser(request.GetUser())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -357,7 +357,7 @@ func (api headscaleV1APIServer) MoveMachine(
return nil, err return nil, err
} }
err = api.h.SetMachineNamespace(machine, request.GetNamespace()) err = api.h.SetMachineUser(machine, request.GetUser())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -483,7 +483,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
ctx context.Context, ctx context.Context,
request *v1.DebugCreateMachineRequest, request *v1.DebugCreateMachineRequest,
) (*v1.DebugCreateMachineResponse, error) { ) (*v1.DebugCreateMachineResponse, error) {
namespace, err := api.h.GetNamespace(request.GetNamespace()) user, err := api.h.GetUser(request.GetUser())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -514,7 +514,7 @@ func (api headscaleV1APIServer) DebugCreateMachine(
MachineKey: request.GetKey(), MachineKey: request.GetKey(),
Hostname: request.GetName(), Hostname: request.GetName(),
GivenName: givenName, GivenName: givenName,
Namespace: *namespace, User: *user,
Expiry: &time.Time{}, Expiry: &time.Time{},
LastSeen: &time.Time{}, LastSeen: &time.Time{},

View file

@ -49,7 +49,7 @@ func TestOIDCAuthenticationPingAll(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
} }
oidcConfig, err := scenario.runMockOIDC(defaultAccessTTL) oidcConfig, err := scenario.runMockOIDC(defaultAccessTTL)
@ -116,7 +116,7 @@ func TestOIDCExpireNodes(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
} }
oidcConfig, err := scenario.runMockOIDC(shortAccessTTL) oidcConfig, err := scenario.runMockOIDC(shortAccessTTL)
@ -169,7 +169,7 @@ func TestOIDCExpireNodes(t *testing.T) {
} }
func (s *AuthOIDCScenario) CreateHeadscaleEnv( func (s *AuthOIDCScenario) CreateHeadscaleEnv(
namespaces map[string]int, users map[string]int,
opts ...hsic.Option, opts ...hsic.Option,
) error { ) error {
headscale, err := s.Headscale(opts...) headscale, err := s.Headscale(opts...)
@ -182,19 +182,19 @@ func (s *AuthOIDCScenario) CreateHeadscaleEnv(
return err return err
} }
for namespaceName, clientCount := range namespaces { for userName, clientCount := range users {
log.Printf("creating namespace %s with %d clients", namespaceName, clientCount) log.Printf("creating user %s with %d clients", userName, clientCount)
err = s.CreateNamespace(namespaceName) err = s.CreateUser(userName)
if err != nil { if err != nil {
return err return err
} }
err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount) err = s.CreateTailscaleNodesInUser(userName, "all", clientCount)
if err != nil { if err != nil {
return err return err
} }
err = s.runTailscaleUp(namespaceName, headscale.GetEndpoint()) err = s.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil { if err != nil {
return err return err
} }
@ -287,20 +287,20 @@ func (s *AuthOIDCScenario) runMockOIDC(accessTTL time.Duration) (*headscale.OIDC
} }
func (s *AuthOIDCScenario) runTailscaleUp( func (s *AuthOIDCScenario) runTailscaleUp(
namespaceStr, loginServer string, userStr, loginServer string,
) error { ) error {
headscale, err := s.Headscale() headscale, err := s.Headscale()
if err != nil { if err != nil {
return err return err
} }
log.Printf("running tailscale up for namespace %s", namespaceStr) log.Printf("running tailscale up for user %s", userStr)
if namespace, ok := s.namespaces[namespaceStr]; ok { if user, ok := s.users[userStr]; ok {
for _, client := range namespace.Clients { for _, client := range user.Clients {
namespace.joinWaitGroup.Add(1) user.joinWaitGroup.Add(1)
go func(c TailscaleClient) { go func(c TailscaleClient) {
defer namespace.joinWaitGroup.Done() defer user.joinWaitGroup.Done()
// TODO(juanfont): error handle this // TODO(juanfont): error handle this
loginURL, err := c.UpWithLoginURL(loginServer) loginURL, err := c.UpWithLoginURL(loginServer)
@ -347,12 +347,12 @@ func (s *AuthOIDCScenario) runTailscaleUp(
log.Printf("client %s is ready", client.Hostname()) log.Printf("client %s is ready", client.Hostname())
} }
namespace.joinWaitGroup.Wait() user.joinWaitGroup.Wait()
return nil 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 { 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{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions), "user2": len(TailscaleVersions),
} }
err = scenario.CreateHeadscaleEnv(spec, hsic.WithTestName("webauthping")) err = scenario.CreateHeadscaleEnv(spec, hsic.WithTestName("webauthping"))
@ -93,8 +93,8 @@ func TestAuthWebFlowLogoutAndRelogin(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions), "user2": len(TailscaleVersions),
} }
err = scenario.CreateHeadscaleEnv(spec, hsic.WithTestName("weblogout")) 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) t.Errorf("failed to get headscale server: %s", err)
} }
for namespaceName := range spec { for userName := range spec {
err = scenario.runTailscaleUp(namespaceName, headscale.GetEndpoint()) err = scenario.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil { if err != nil {
t.Errorf("failed to run tailscale up: %s", err) t.Errorf("failed to run tailscale up: %s", err)
} }
@ -225,7 +225,7 @@ func TestAuthWebFlowLogoutAndRelogin(t *testing.T) {
} }
func (s *AuthWebFlowScenario) CreateHeadscaleEnv( func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
namespaces map[string]int, users map[string]int,
opts ...hsic.Option, opts ...hsic.Option,
) error { ) error {
headscale, err := s.Headscale(opts...) headscale, err := s.Headscale(opts...)
@ -238,19 +238,19 @@ func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
return err return err
} }
for namespaceName, clientCount := range namespaces { for userName, clientCount := range users {
log.Printf("creating namespace %s with %d clients", namespaceName, clientCount) log.Printf("creating user %s with %d clients", userName, clientCount)
err = s.CreateNamespace(namespaceName) err = s.CreateUser(userName)
if err != nil { if err != nil {
return err return err
} }
err = s.CreateTailscaleNodesInNamespace(namespaceName, "all", clientCount) err = s.CreateTailscaleNodesInUser(userName, "all", clientCount)
if err != nil { if err != nil {
return err return err
} }
err = s.runTailscaleUp(namespaceName, headscale.GetEndpoint()) err = s.runTailscaleUp(userName, headscale.GetEndpoint())
if err != nil { if err != nil {
return err return err
} }
@ -260,15 +260,15 @@ func (s *AuthWebFlowScenario) CreateHeadscaleEnv(
} }
func (s *AuthWebFlowScenario) runTailscaleUp( func (s *AuthWebFlowScenario) runTailscaleUp(
namespaceStr, loginServer string, userStr, loginServer string,
) error { ) error {
log.Printf("running tailscale up for namespace %s", namespaceStr) log.Printf("running tailscale up for user %s", userStr)
if namespace, ok := s.namespaces[namespaceStr]; ok { if user, ok := s.users[userStr]; ok {
for _, client := range namespace.Clients { for _, client := range user.Clients {
namespace.joinWaitGroup.Add(1) user.joinWaitGroup.Add(1)
go func(c TailscaleClient) { go func(c TailscaleClient) {
defer namespace.joinWaitGroup.Done() defer user.joinWaitGroup.Done()
// TODO(juanfont): error handle this // TODO(juanfont): error handle this
loginURL, err := c.UpWithLoginURL(loginServer) loginURL, err := c.UpWithLoginURL(loginServer)
@ -276,7 +276,7 @@ func (s *AuthWebFlowScenario) runTailscaleUp(
log.Printf("failed to run tailscale up: %s", err) log.Printf("failed to run tailscale up: %s", err)
} }
err = s.runHeadscaleRegister(namespaceStr, loginURL) err = s.runHeadscaleRegister(userStr, loginURL)
if err != nil { if err != nil {
log.Printf("failed to register client: %s", err) 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) log.Printf("error waiting for client %s to be ready: %s", client.Hostname(), err)
} }
} }
namespace.joinWaitGroup.Wait() user.joinWaitGroup.Wait()
return nil 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() headscale, err := s.Headscale()
if err != nil { if err != nil {
return err return err
@ -335,7 +335,7 @@ func (s *AuthWebFlowScenario) runHeadscaleRegister(namespaceStr string, loginURL
if headscale, err := s.Headscale(); err == nil { if headscale, err := s.Headscale(); err == nil {
_, err = headscale.Execute( _, err = headscale.Execute(
[]string{"headscale", "-n", namespaceStr, "nodes", "register", "--key", key}, []string{"headscale", "-n", userStr, "nodes", "register", "--key", key},
) )
if err != nil { if err != nil {
log.Printf("failed to register node: %s", err) 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 return nil
} }
func TestNamespaceCommand(t *testing.T) { func TestUserCommand(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
@ -36,8 +36,8 @@ func TestNamespaceCommand(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
spec := map[string]int{ spec := map[string]int{
"namespace1": 0, "user1": 0,
"namespace2": 0, "user2": 0,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clins"))
@ -46,60 +46,60 @@ func TestNamespaceCommand(t *testing.T) {
headscale, err := scenario.Headscale() headscale, err := scenario.Headscale()
assert.NoError(t, err) assert.NoError(t, err)
var listNamespaces []v1.Namespace var listUsers []v1.User
err = executeAndUnmarshal(headscale, err = executeAndUnmarshal(headscale,
[]string{ []string{
"headscale", "headscale",
"namespaces", "users",
"list", "list",
"--output", "--output",
"json", "json",
}, },
&listNamespaces, &listUsers,
) )
assert.NoError(t, err) assert.NoError(t, err)
result := []string{listNamespaces[0].Name, listNamespaces[1].Name} result := []string{listUsers[0].Name, listUsers[1].Name}
sort.Strings(result) sort.Strings(result)
assert.Equal( assert.Equal(
t, t,
[]string{"namespace1", "namespace2"}, []string{"user1", "user2"},
result, result,
) )
_, err = headscale.Execute( _, err = headscale.Execute(
[]string{ []string{
"headscale", "headscale",
"namespaces", "users",
"rename", "rename",
"--output", "--output",
"json", "json",
"namespace2", "user2",
"newname", "newname",
}, },
) )
assert.NoError(t, err) assert.NoError(t, err)
var listAfterRenameNamespaces []v1.Namespace var listAfterRenameUsers []v1.User
err = executeAndUnmarshal(headscale, err = executeAndUnmarshal(headscale,
[]string{ []string{
"headscale", "headscale",
"namespaces", "users",
"list", "list",
"--output", "--output",
"json", "json",
}, },
&listAfterRenameNamespaces, &listAfterRenameUsers,
) )
assert.NoError(t, err) assert.NoError(t, err)
result = []string{listAfterRenameNamespaces[0].Name, listAfterRenameNamespaces[1].Name} result = []string{listAfterRenameUsers[0].Name, listAfterRenameUsers[1].Name}
sort.Strings(result) sort.Strings(result)
assert.Equal( assert.Equal(
t, t,
[]string{"namespace1", "newname"}, []string{"user1", "newname"},
result, result,
) )
@ -111,14 +111,14 @@ func TestPreAuthKeyCommand(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
namespace := "preauthkeyspace" user := "preauthkeyspace"
count := 3 count := 3
scenario, err := NewScenario() scenario, err := NewScenario()
assert.NoError(t, err) assert.NoError(t, err)
spec := map[string]int{ spec := map[string]int{
namespace: 0, user: 0,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipak")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipak"))
@ -137,8 +137,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"create", "create",
"--reusable", "--reusable",
"--expiration", "--expiration",
@ -163,8 +163,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"list", "list",
"--output", "--output",
"json", "json",
@ -216,8 +216,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"expire", "expire",
listedPreAuthKeys[1].Key, listedPreAuthKeys[1].Key,
}, },
@ -230,8 +230,8 @@ func TestPreAuthKeyCommand(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"list", "list",
"--output", "--output",
"json", "json",
@ -252,13 +252,13 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
namespace := "pre-auth-key-without-exp-namespace" user := "pre-auth-key-without-exp-user"
scenario, err := NewScenario() scenario, err := NewScenario()
assert.NoError(t, err) assert.NoError(t, err)
spec := map[string]int{ spec := map[string]int{
namespace: 0, user: 0,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipaknaexp")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipaknaexp"))
@ -273,8 +273,8 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"create", "create",
"--reusable", "--reusable",
"--output", "--output",
@ -290,8 +290,8 @@ func TestPreAuthKeyCommandWithoutExpiry(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"list", "list",
"--output", "--output",
"json", "json",
@ -317,13 +317,13 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
namespace := "pre-auth-key-reus-ephm-namespace" user := "pre-auth-key-reus-ephm-user"
scenario, err := NewScenario() scenario, err := NewScenario()
assert.NoError(t, err) assert.NoError(t, err)
spec := map[string]int{ spec := map[string]int{
namespace: 0, user: 0,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipakresueeph")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clipakresueeph"))
@ -338,8 +338,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"create", "create",
"--reusable=true", "--reusable=true",
"--output", "--output",
@ -355,8 +355,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"create", "create",
"--ephemeral=true", "--ephemeral=true",
"--output", "--output",
@ -375,8 +375,8 @@ func TestPreAuthKeyCommandReusableEphemeral(t *testing.T) {
[]string{ []string{
"headscale", "headscale",
"preauthkeys", "preauthkeys",
"--namespace", "--user",
namespace, user,
"list", "list",
"--output", "--output",
"json", "json",
@ -396,13 +396,13 @@ func TestEnablingRoutes(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
namespace := "enable-routing" user := "enable-routing"
scenario, err := NewScenario() scenario, err := NewScenario()
assert.NoError(t, err) assert.NoError(t, err)
spec := map[string]int{ spec := map[string]int{
namespace: 3, user: 3,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clienableroute")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("clienableroute"))

View file

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

View file

@ -22,8 +22,8 @@ func TestPingAllByIP(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions), "user2": len(TailscaleVersions),
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyip")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyip"))
@ -77,8 +77,8 @@ func TestAuthKeyLogoutAndRelogin(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions), "user2": len(TailscaleVersions),
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyip")) 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) t.Errorf("failed to get headscale server: %s", err)
} }
for namespaceName := range spec { for userName := range spec {
key, err := scenario.CreatePreAuthKey(namespaceName, true, false) key, err := scenario.CreatePreAuthKey(userName, true, false)
if err != nil { 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 { 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{ spec := map[string]int{
"namespace1": len(TailscaleVersions), "user1": len(TailscaleVersions),
"namespace2": len(TailscaleVersions), "user2": len(TailscaleVersions),
} }
headscale, err := scenario.Headscale(hsic.WithTestName("ephemeral")) 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) t.Errorf("failed to create headscale environment: %s", err)
} }
for namespaceName, clientCount := range spec { for userName, clientCount := range spec {
err = scenario.CreateNamespace(namespaceName) err = scenario.CreateUser(userName)
if err != nil { 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 { 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 { 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 { 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") t.Logf("all clients logged out")
for namespaceName := range spec { for userName := range spec {
machines, err := headscale.ListMachinesInNamespace(namespaceName) machines, err := headscale.ListMachinesInUser(userName)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("namespace", namespaceName). Str("user", userName).
Msg("Error listing machines in namespace") Msg("Error listing machines in user")
return return
} }
if len(machines) != 0 { 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{ spec := map[string]int{
// Omit 1.16.2 (-1) because it does not have the FQDN field // Omit 1.16.2 (-1) because it does not have the FQDN field
"namespace3": len(TailscaleVersions) - 1, "user3": len(TailscaleVersions) - 1,
"namespace4": len(TailscaleVersions) - 1, "user4": len(TailscaleVersions) - 1,
} }
err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyname")) err = scenario.CreateHeadscaleEnv(spec, []tsic.Option{}, hsic.WithTestName("pingallbyname"))

View file

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

View file

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

View file

@ -31,7 +31,7 @@ func TestHeadscale(t *testing.T) {
var err error var err error
namespace := "test-space" user := "test-space"
scenario, err := NewScenario() scenario, err := NewScenario()
if err != nil { if err != nil {
@ -50,19 +50,19 @@ func TestHeadscale(t *testing.T) {
} }
}) })
t.Run("create-namespace", func(t *testing.T) { t.Run("create-user", func(t *testing.T) {
err := scenario.CreateNamespace(namespace) err := scenario.CreateUser(user)
if err != nil { 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 { if _, ok := scenario.users[user]; !ok {
t.Errorf("namespace is not in scenario") t.Errorf("user is not in scenario")
} }
}) })
t.Run("create-auth-key", func(t *testing.T) { t.Run("create-auth-key", func(t *testing.T) {
_, err := scenario.CreatePreAuthKey(namespace, true, false) _, err := scenario.CreatePreAuthKey(user, true, false)
if err != nil { if err != nil {
t.Errorf("failed to create preauthkey: %s", err) t.Errorf("failed to create preauthkey: %s", err)
} }
@ -82,24 +82,24 @@ func TestCreateTailscale(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
namespace := "only-create-containers" user := "only-create-containers"
scenario, err := NewScenario() scenario, err := NewScenario()
if err != nil { if err != nil {
t.Errorf("failed to create scenario: %s", err) t.Errorf("failed to create scenario: %s", err)
} }
scenario.namespaces[namespace] = &Namespace{ scenario.users[user] = &User{
Clients: make(map[string]TailscaleClient), Clients: make(map[string]TailscaleClient),
} }
t.Run("create-tailscale", func(t *testing.T) { t.Run("create-tailscale", func(t *testing.T) {
err := scenario.CreateTailscaleNodesInNamespace(namespace, "all", 3) err := scenario.CreateTailscaleNodesInUser(user, "all", 3)
if err != nil { if err != nil {
t.Errorf("failed to add tailscale nodes: %s", err) 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) t.Errorf("wrong number of tailscale clients: %d != %d", clients, 3)
} }
@ -122,7 +122,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
var err error var err error
namespace := "join-node-test" user := "join-node-test"
count := 1 count := 1
@ -143,30 +143,30 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
} }
}) })
t.Run("create-namespace", func(t *testing.T) { t.Run("create-user", func(t *testing.T) {
err := scenario.CreateNamespace(namespace) err := scenario.CreateUser(user)
if err != nil { 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 { if _, ok := scenario.users[user]; !ok {
t.Errorf("namespace is not in scenario") t.Errorf("user is not in scenario")
} }
}) })
t.Run("create-tailscale", func(t *testing.T) { 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 { if err != nil {
t.Errorf("failed to add tailscale nodes: %s", err) 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.Errorf("wrong number of tailscale clients: %d != %d", clients, count)
} }
}) })
t.Run("join-headscale", func(t *testing.T) { 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 { if err != nil {
t.Errorf("failed to create preauthkey: %s", err) t.Errorf("failed to create preauthkey: %s", err)
} }
@ -177,7 +177,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
} }
err = scenario.RunTailscaleUp( err = scenario.RunTailscaleUp(
namespace, user,
headscale.GetEndpoint(), headscale.GetEndpoint(),
key.GetKey(), key.GetKey(),
) )
@ -187,7 +187,7 @@ func TestTailscaleNodesJoiningHeadcale(t *testing.T) {
}) })
t.Run("get-ips", func(t *testing.T) { t.Run("get-ips", func(t *testing.T) {
ips, err := scenario.GetIPs(namespace) ips, err := scenario.GetIPs(user)
if err != nil { if err != nil {
t.Errorf("failed to get tailscale ips: %s", err) 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 return result, stderr, err
} }
func TestSSHOneNamespaceAllToAll(t *testing.T) { func TestSSHOneUserAllToAll(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
@ -51,7 +51,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5, "user1": len(TailscaleVersions) - 5,
} }
err = scenario.CreateHeadscaleEnv(spec, err = scenario.CreateHeadscaleEnv(spec,
@ -59,7 +59,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
hsic.WithACLPolicy( hsic.WithACLPolicy(
&headscale.ACLPolicy{ &headscale.ACLPolicy{
Groups: map[string][]string{ Groups: map[string][]string{
"group:integration-test": {"namespace1"}, "group:integration-test": {"user1"},
}, },
ACLs: []headscale.ACL{ ACLs: []headscale.ACL{
{ {
@ -117,7 +117,7 @@ func TestSSHOneNamespaceAllToAll(t *testing.T) {
} }
} }
func TestSSHMultipleNamespacesAllToAll(t *testing.T) { func TestSSHMultipleUsersAllToAll(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
@ -127,8 +127,8 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5, "user1": len(TailscaleVersions) - 5,
"namespace2": len(TailscaleVersions) - 5, "user2": len(TailscaleVersions) - 5,
} }
err = scenario.CreateHeadscaleEnv(spec, err = scenario.CreateHeadscaleEnv(spec,
@ -136,7 +136,7 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
hsic.WithACLPolicy( hsic.WithACLPolicy(
&headscale.ACLPolicy{ &headscale.ACLPolicy{
Groups: map[string][]string{ Groups: map[string][]string{
"group:integration-test": {"namespace1", "namespace2"}, "group:integration-test": {"user1", "user2"},
}, },
ACLs: []headscale.ACL{ ACLs: []headscale.ACL{
{ {
@ -163,12 +163,12 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err) t.Errorf("failed to create headscale environment: %s", err)
} }
nsOneClients, err := scenario.ListTailscaleClients("namespace1") nsOneClients, err := scenario.ListTailscaleClients("user1")
if err != nil { if err != nil {
t.Errorf("failed to get clients: %s", err) t.Errorf("failed to get clients: %s", err)
} }
nsTwoClients, err := scenario.ListTailscaleClients("namespace2") nsTwoClients, err := scenario.ListTailscaleClients("user2")
if err != nil { if err != nil {
t.Errorf("failed to get clients: %s", err) 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) 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 _, client := range sourceClients {
for _, peer := range targetClients { for _, peer := range targetClients {
assertSSHHostname(t, client, peer) assertSSHHostname(t, client, peer)
@ -191,8 +191,8 @@ func TestSSHMultipleNamespacesAllToAll(t *testing.T) {
} }
} }
testInterNamespaceSSH(nsOneClients, nsTwoClients) testInterUserSSH(nsOneClients, nsTwoClients)
testInterNamespaceSSH(nsTwoClients, nsOneClients) testInterUserSSH(nsTwoClients, nsOneClients)
err = scenario.Shutdown() err = scenario.Shutdown()
if err != nil { if err != nil {
@ -210,7 +210,7 @@ func TestSSHNoSSHConfigured(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5, "user1": len(TailscaleVersions) - 5,
} }
err = scenario.CreateHeadscaleEnv(spec, err = scenario.CreateHeadscaleEnv(spec,
@ -218,7 +218,7 @@ func TestSSHNoSSHConfigured(t *testing.T) {
hsic.WithACLPolicy( hsic.WithACLPolicy(
&headscale.ACLPolicy{ &headscale.ACLPolicy{
Groups: map[string][]string{ Groups: map[string][]string{
"group:integration-test": {"namespace1"}, "group:integration-test": {"user1"},
}, },
ACLs: []headscale.ACL{ ACLs: []headscale.ACL{
{ {
@ -280,7 +280,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespace1": len(TailscaleVersions) - 5, "user1": len(TailscaleVersions) - 5,
} }
err = scenario.CreateHeadscaleEnv(spec, err = scenario.CreateHeadscaleEnv(spec,
@ -288,7 +288,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
hsic.WithACLPolicy( hsic.WithACLPolicy(
&headscale.ACLPolicy{ &headscale.ACLPolicy{
Groups: map[string][]string{ Groups: map[string][]string{
"group:integration-test": {"namespace1"}, "group:integration-test": {"user1"},
}, },
ACLs: []headscale.ACL{ ACLs: []headscale.ACL{
{ {
@ -347,7 +347,7 @@ func TestSSHIsBlockedInACL(t *testing.T) {
} }
} }
func TestSSNamespaceOnlyIsolation(t *testing.T) { func TestSSUserOnlyIsolation(t *testing.T) {
IntegrationSkip(t) IntegrationSkip(t)
t.Parallel() t.Parallel()
@ -357,8 +357,8 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
} }
spec := map[string]int{ spec := map[string]int{
"namespaceacl1": len(TailscaleVersions) - 5, "useracl1": len(TailscaleVersions) - 5,
"namespaceacl2": len(TailscaleVersions) - 5, "useracl2": len(TailscaleVersions) - 5,
} }
err = scenario.CreateHeadscaleEnv(spec, err = scenario.CreateHeadscaleEnv(spec,
@ -366,8 +366,8 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
hsic.WithACLPolicy( hsic.WithACLPolicy(
&headscale.ACLPolicy{ &headscale.ACLPolicy{
Groups: map[string][]string{ Groups: map[string][]string{
"group:ssh1": {"namespaceacl1"}, "group:ssh1": {"useracl1"},
"group:ssh2": {"namespaceacl2"}, "group:ssh2": {"useracl2"},
}, },
ACLs: []headscale.ACL{ ACLs: []headscale.ACL{
{ {
@ -392,7 +392,7 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
}, },
}, },
), ),
hsic.WithTestName("sshtwonamespaceaclblock"), hsic.WithTestName("sshtwouseraclblock"),
hsic.WithConfigEnv(map[string]string{ hsic.WithConfigEnv(map[string]string{
"HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1", "HEADSCALE_EXPERIMENTAL_FEATURE_SSH": "1",
}), }),
@ -401,12 +401,12 @@ func TestSSNamespaceOnlyIsolation(t *testing.T) {
t.Errorf("failed to create headscale environment: %s", err) t.Errorf("failed to create headscale environment: %s", err)
} }
ssh1Clients, err := scenario.ListTailscaleClients("namespaceacl1") ssh1Clients, err := scenario.ListTailscaleClients("useracl1")
if err != nil { if err != nil {
t.Errorf("failed to get clients: %s", err) t.Errorf("failed to get clients: %s", err)
} }
ssh2Clients, err := scenario.ListTailscaleClients("namespaceacl2") ssh2Clients, err := scenario.ListTailscaleClients("useracl2")
if err != nil { if err != nil {
t.Errorf("failed to get clients: %s", err) t.Errorf("failed to get clients: %s", err)
} }

View file

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

View file

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

View file

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

View file

@ -27,8 +27,8 @@ const (
) )
ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface") ErrCouldNotConvertMachineInterface = Error("failed to convert machine interface")
ErrHostnameTooLong = Error("Hostname too long") ErrHostnameTooLong = Error("Hostname too long")
ErrDifferentRegisteredNamespace = Error( ErrDifferentRegisteredUser = Error(
"machine was previously registered with a different namespace", "machine was previously registered with a different user",
) )
MachineGivenNameHashLength = 8 MachineGivenNameHashLength = 8
MachineGivenNameTrimSize = 2 MachineGivenNameTrimSize = 2
@ -57,8 +57,8 @@ type Machine struct {
// GivenName is the name used in all DNS related // GivenName is the name used in all DNS related
// parts of headscale. // parts of headscale.
GivenName string `gorm:"type:varchar(63);unique_index"` GivenName string `gorm:"type:varchar(63);unique_index"`
NamespaceID uint UserID uint
Namespace Namespace `gorm:"foreignKey:NamespaceID"` User User `gorm:"foreignKey:UserID"`
RegisterMethod string RegisterMethod string
@ -192,7 +192,7 @@ func getFilteredByACLPeers(
Msg("Finding peers filtered by ACLs") Msg("Finding peers filtered by ACLs")
peers := make(map[uint64]Machine) 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. // for match between rule SrcIPs and DstPorts. If the rule is a match we allow the machine to be viewable.
machineIPs := machine.IPAddresses.ToStringSlice() machineIPs := machine.IPAddresses.ToStringSlice()
for _, peer := range machines { for _, peer := range machines {
@ -270,7 +270,7 @@ func (h *Headscale) ListPeers(machine *Machine) (Machines, error) {
Msg("Finding direct peers") Msg("Finding direct peers")
machines := Machines{} 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 { machine.NodeKey).Find(&machines).Error; err != nil {
log.Error().Err(err).Msg("Error accessing db") log.Error().Err(err).Msg("Error accessing db")
@ -292,7 +292,7 @@ func (h *Headscale) getPeers(machine *Machine) (Machines, error) {
var err error var err error
// If ACLs rules are defined, filter visible host list with the ACLs // 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 { if h.aclPolicy != nil {
var machines []Machine var machines []Machine
machines, err = h.ListMachines() machines, err = h.ListMachines()
@ -343,7 +343,7 @@ func (h *Headscale) getValidPeers(machine *Machine) (Machines, error) {
func (h *Headscale) ListMachines() ([]Machine, error) { func (h *Headscale) ListMachines() ([]Machine, error) {
machines := []Machine{} 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 return nil, err
} }
@ -352,16 +352,16 @@ func (h *Headscale) ListMachines() ([]Machine, error) {
func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error) { func (h *Headscale) ListMachinesByGivenName(givenName string) ([]Machine, error) {
machines := []Machine{} 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 nil, err
} }
return machines, nil return machines, nil
} }
// GetMachine finds a Machine by name and namespace and returns the Machine struct. // GetMachine finds a Machine by name and user and returns the Machine struct.
func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error) { func (h *Headscale) GetMachine(user string, name string) (*Machine, error) {
machines, err := h.ListMachinesInNamespace(namespace) machines, err := h.ListMachinesByUser(user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -375,9 +375,9 @@ func (h *Headscale) GetMachine(namespace string, name string) (*Machine, error)
return nil, ErrMachineNotFound return nil, ErrMachineNotFound
} }
// GetMachineByGivenName finds a Machine by given name and namespace and returns the Machine struct. // GetMachineByGivenName finds a Machine by given name and user and returns the Machine struct.
func (h *Headscale) GetMachineByGivenName(namespace string, givenName string) (*Machine, error) { func (h *Headscale) GetMachineByGivenName(user string, givenName string) (*Machine, error) {
machines, err := h.ListMachinesInNamespace(namespace) machines, err := h.ListMachinesByUser(user)
if err != nil { if err != nil {
return nil, err 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. // GetMachineByID finds a Machine by ID and returns the Machine struct.
func (h *Headscale) GetMachineByID(id uint64) (*Machine, error) { func (h *Headscale) GetMachineByID(id uint64) (*Machine, error) {
m := Machine{} 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 return nil, result.Error
} }
@ -406,7 +406,7 @@ func (h *Headscale) GetMachineByMachineKey(
machineKey key.MachinePublic, machineKey key.MachinePublic,
) (*Machine, error) { ) (*Machine, error) {
m := Machine{} 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 return nil, result.Error
} }
@ -418,7 +418,7 @@ func (h *Headscale) GetMachineByNodeKey(
nodeKey key.NodePublic, nodeKey key.NodePublic,
) (*Machine, error) { ) (*Machine, error) {
machine := Machine{} 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 { NodePublicKeyStripPrefix(nodeKey)); result.Error != nil {
return nil, result.Error return nil, result.Error
} }
@ -431,7 +431,7 @@ func (h *Headscale) GetMachineByAnyKey(
machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic, machineKey key.MachinePublic, nodeKey key.NodePublic, oldNodeKey key.NodePublic,
) (*Machine, error) { ) (*Machine, error) {
machine := Machine{} 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), MachinePublicKeyStripPrefix(machineKey),
NodePublicKeyStripPrefix(nodeKey), NodePublicKeyStripPrefix(nodeKey),
NodePublicKeyStripPrefix(oldNodeKey)); result.Error != nil { NodePublicKeyStripPrefix(oldNodeKey)); result.Error != nil {
@ -570,9 +570,9 @@ func (h *Headscale) isOutdated(machine *Machine) bool {
return true 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. // 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 // This would mostly be for a bit of performance, and can be calculated based on
// ACLs. // ACLs.
lastChange := h.getLastStateChange() lastChange := h.getLastStateChange()
@ -720,7 +720,7 @@ func (h *Headscale) toNode(
hostname = fmt.Sprintf( hostname = fmt.Sprintf(
"%s.%s.%s", "%s.%s.%s",
machine.GivenName, machine.GivenName,
machine.Namespace.Name, machine.User.Name,
baseDomain, baseDomain,
) )
if len(hostname) > maxHostnameLength { if len(hostname) > maxHostnameLength {
@ -744,7 +744,7 @@ func (h *Headscale) toNode(
strconv.FormatUint(machine.ID, Base10), strconv.FormatUint(machine.ID, Base10),
), // in headscale, unlike tailcontrol server, IDs are permanent ), // in headscale, unlike tailcontrol server, IDs are permanent
Name: hostname, Name: hostname,
User: tailcfg.UserID(machine.NamespaceID), User: tailcfg.UserID(machine.UserID),
Key: nodeKey, Key: nodeKey,
KeyExpiry: keyExpiry, KeyExpiry: keyExpiry,
Machine: machineKey, Machine: machineKey,
@ -782,7 +782,7 @@ func (machine *Machine) toProto() *v1.Machine {
IpAddresses: machine.IPAddresses.ToStringSlice(), IpAddresses: machine.IPAddresses.ToStringSlice(),
Name: machine.Hostname, Name: machine.Hostname,
GivenName: machine.GivenName, GivenName: machine.GivenName,
Namespace: machine.Namespace.toProto(), User: machine.User.toProto(),
ForcedTags: machine.ForcedTags, ForcedTags: machine.ForcedTags,
Online: machine.isOnline(), Online: machine.isOnline(),
@ -837,7 +837,7 @@ func getTags(
} }
var found bool var found bool
for _, owner := range owners { for _, owner := range owners {
if machine.Namespace.Name == owner { if machine.User.Name == owner {
found = true found = true
} }
} }
@ -859,7 +859,7 @@ func getTags(
func (h *Headscale) RegisterMachineFromAuthCallback( func (h *Headscale) RegisterMachineFromAuthCallback(
nodeKeyStr string, nodeKeyStr string,
namespaceName string, userName string,
machineExpiry *time.Time, machineExpiry *time.Time,
registrationMethod string, registrationMethod string,
) (*Machine, error) { ) (*Machine, error) {
@ -871,28 +871,28 @@ func (h *Headscale) RegisterMachineFromAuthCallback(
log.Debug(). log.Debug().
Str("nodeKey", nodeKey.ShortString()). Str("nodeKey", nodeKey.ShortString()).
Str("namespaceName", namespaceName). Str("userName", userName).
Str("registrationMethod", registrationMethod). Str("registrationMethod", registrationMethod).
Str("expiresAt", fmt.Sprintf("%v", machineExpiry)). Str("expiresAt", fmt.Sprintf("%v", machineExpiry)).
Msg("Registering machine from API/CLI or auth callback") Msg("Registering machine from API/CLI or auth callback")
if machineInterface, ok := h.registrationCache.Get(NodePublicKeyStripPrefix(nodeKey)); ok { if machineInterface, ok := h.registrationCache.Get(NodePublicKeyStripPrefix(nodeKey)); ok {
if registrationMachine, ok := machineInterface.(Machine); ok { if registrationMachine, ok := machineInterface.(Machine); ok {
namespace, err := h.GetNamespace(namespaceName) user, err := h.GetUser(userName)
if err != nil { if err != nil {
return nil, fmt.Errorf( 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, err,
) )
} }
// Registration of expired machine with different namespace // Registration of expired machine with different user
if registrationMachine.ID != 0 && if registrationMachine.ID != 0 &&
registrationMachine.NamespaceID != namespace.ID { registrationMachine.UserID != user.ID {
return nil, ErrDifferentRegisteredNamespace return nil, ErrDifferentRegisteredUser
} }
registrationMachine.NamespaceID = namespace.ID registrationMachine.UserID = user.ID
registrationMachine.RegisterMethod = registrationMethod registrationMachine.RegisterMethod = registrationMethod
if machineExpiry != nil { if machineExpiry != nil {
@ -923,7 +923,7 @@ func (h *Headscale) RegisterMachine(machine Machine,
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Str("machine_key", machine.MachineKey). Str("machine_key", machine.MachineKey).
Str("node_key", machine.NodeKey). Str("node_key", machine.NodeKey).
Str("namespace", machine.Namespace.Name). Str("user", machine.User.Name).
Msg("Registering machine") Msg("Registering machine")
// If the machine exists and we had already IPs for it, we just save it // 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", machine.Hostname).
Str("machine_key", machine.MachineKey). Str("machine_key", machine.MachineKey).
Str("node_key", machine.NodeKey). Str("node_key", machine.NodeKey).
Str("namespace", machine.Namespace.Name). Str("user", machine.User.Name).
Msg("Machine authorized again") Msg("Machine authorized again")
return &machine, nil return &machine, nil
@ -1137,7 +1137,7 @@ func (h *Headscale) EnableAutoApprovedRoutes(machine *Machine) error {
} }
for _, approvedAlias := range routeApprovers { for _, approvedAlias := range routeApprovers {
if approvedAlias == machine.Namespace.Name { if approvedAlias == machine.User.Name {
approvedRoutes = append(approvedRoutes, advertisedRoute) approvedRoutes = append(approvedRoutes, advertisedRoute)
} else { } else {
approvedIps, err := expandAlias([]Machine{*machine}, *h.aclPolicy, approvedAlias, h.cfg.OIDC.StripEmaildomain) 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) { func (s *Suite) TestGetMachine(c *check.C) {
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine") _, err = app.GetMachine("test", "testmachine")
@ -30,7 +30,7 @@ func (s *Suite) TestGetMachine(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -41,10 +41,10 @@ func (s *Suite) TestGetMachine(c *check.C) {
} }
func (s *Suite) TestGetMachineByID(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0) _, err = app.GetMachineByID(0)
@ -56,7 +56,7 @@ func (s *Suite) TestGetMachineByID(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -67,10 +67,10 @@ func (s *Suite) TestGetMachineByID(c *check.C) {
} }
func (s *Suite) TestGetMachineByNodeKey(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0) _, err = app.GetMachineByID(0)
@ -85,7 +85,7 @@ func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()), NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -96,10 +96,10 @@ func (s *Suite) TestGetMachineByNodeKey(c *check.C) {
} }
func (s *Suite) TestGetMachineByAnyNodeKey(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0) _, err = app.GetMachineByID(0)
@ -116,7 +116,7 @@ func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()), NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -127,7 +127,7 @@ func (s *Suite) TestGetMachineByAnyNodeKey(c *check.C) {
} }
func (s *Suite) TestDeleteMachine(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) c.Assert(err, check.IsNil)
machine := Machine{ machine := Machine{
ID: 0, ID: 0,
@ -135,7 +135,7 @@ func (s *Suite) TestDeleteMachine(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(1), AuthKeyID: uint(1),
} }
@ -144,12 +144,12 @@ func (s *Suite) TestDeleteMachine(c *check.C) {
err = app.DeleteMachine(&machine) err = app.DeleteMachine(&machine)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespace.Name, "testmachine") _, err = app.GetMachine(user.Name, "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
} }
func (s *Suite) TestHardDeleteMachine(c *check.C) { func (s *Suite) TestHardDeleteMachine(c *check.C) {
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machine := Machine{ machine := Machine{
ID: 0, ID: 0,
@ -157,7 +157,7 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine3", Hostname: "testmachine3",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(1), AuthKeyID: uint(1),
} }
@ -166,15 +166,15 @@ func (s *Suite) TestHardDeleteMachine(c *check.C) {
err = app.HardDeleteMachine(&machine) err = app.HardDeleteMachine(&machine)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
_, err = app.GetMachine(namespace.Name, "testmachine3") _, err = app.GetMachine(user.Name, "testmachine3")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
} }
func (s *Suite) TestListPeers(c *check.C) { func (s *Suite) TestListPeers(c *check.C) {
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachineByID(0) _, err = app.GetMachineByID(0)
@ -187,7 +187,7 @@ func (s *Suite) TestListPeers(c *check.C) {
NodeKey: "bar" + strconv.Itoa(index), NodeKey: "bar" + strconv.Itoa(index),
DiscoKey: "faa" + strconv.Itoa(index), DiscoKey: "faa" + strconv.Itoa(index),
Hostname: "testmachine" + strconv.Itoa(index), Hostname: "testmachine" + strconv.Itoa(index),
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -208,18 +208,18 @@ func (s *Suite) TestListPeers(c *check.C) {
func (s *Suite) TestGetACLFilteredPeers(c *check.C) { func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
type base struct { type base struct {
namespace *Namespace user *User
key *PreAuthKey key *PreAuthKey
} }
stor := make([]base, 0) stor := make([]base, 0)
for _, name := range []string{"test", "admin"} { for _, name := range []string{"test", "admin"} {
namespace, err := app.CreateNamespace(name) user, err := app.CreateUser(name)
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
stor = append(stor, base{namespace, pak}) stor = append(stor, base{user, pak})
} }
_, err := app.GetMachineByID(0) _, 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))), netip.MustParseAddr(fmt.Sprintf("100.64.0.%v", strconv.Itoa(index+1))),
}, },
Hostname: "testmachine" + strconv.Itoa(index), Hostname: "testmachine" + strconv.Itoa(index),
NamespaceID: stor[index%2].namespace.ID, UserID: stor[index%2].user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(stor[index%2].key.ID), AuthKeyID: uint(stor[index%2].key.ID),
} }
@ -267,11 +267,11 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
adminMachine, err := app.GetMachineByID(1) 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) c.Assert(err, check.IsNil)
testMachine, err := app.GetMachineByID(2) 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) c.Assert(err, check.IsNil)
machines, err := app.ListMachines() machines, err := app.ListMachines()
@ -294,10 +294,10 @@ func (s *Suite) TestGetACLFilteredPeers(c *check.C) {
} }
func (s *Suite) TestExpireMachine(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine") _, err = app.GetMachine("test", "testmachine")
@ -309,7 +309,7 @@ func (s *Suite) TestExpireMachine(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
Expiry: &time.Time{}, Expiry: &time.Time{},
@ -350,13 +350,13 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
} }
func (s *Suite) TestGenerateGivenName(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) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("namespace-1", "testmachine") _, err = app.GetMachine("user-1", "testmachine")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
machine := &Machine{ machine := &Machine{
@ -366,38 +366,38 @@ func (s *Suite) TestGenerateGivenName(c *check.C) {
DiscoKey: "disco-key-1", DiscoKey: "disco-key-1",
Hostname: "hostname-1", Hostname: "hostname-1",
GivenName: "hostname-1", GivenName: "hostname-1",
NamespaceID: namespace1.ID, UserID: user1.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
app.db.Save(machine) app.db.Save(machine)
givenName, err := app.GenerateGivenName("machine-key-2", "hostname-2") 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(err, check.IsNil, comment)
c.Assert(givenName, check.Equals, "hostname-2", comment) c.Assert(givenName, check.Equals, "hostname-2", comment)
givenName, err = app.GenerateGivenName("machine-key-1", "hostname-1") 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(err, check.IsNil, comment)
c.Assert(givenName, check.Equals, "hostname-1", comment) c.Assert(givenName, check.Equals, "hostname-1", comment)
givenName, err = app.GenerateGivenName("machine-key-2", "hostname-1") 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(err, check.IsNil, comment)
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), 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") 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(err, check.IsNil, comment)
c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment) c.Assert(givenName, check.Matches, fmt.Sprintf("^hostname-1-[a-z0-9]{%d}$", MachineGivenNameHashLength), comment)
} }
func (s *Suite) TestSetTags(c *check.C) { func (s *Suite) TestSetTags(c *check.C) {
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
_, err = app.GetMachine("test", "testmachine") _, err = app.GetMachine("test", "testmachine")
@ -409,7 +409,7 @@ func (s *Suite) TestSetTags(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
@ -457,7 +457,7 @@ func Test_getTags(t *testing.T) {
}, },
}, },
machine: Machine{ machine: Machine{
Namespace: Namespace{ User: User{
Name: "joe", Name: "joe",
}, },
HostInfo: HostInfo{ HostInfo: HostInfo{
@ -478,7 +478,7 @@ func Test_getTags(t *testing.T) {
}, },
}, },
machine: Machine{ machine: Machine{
Namespace: Namespace{ User: User{
Name: "joe", Name: "joe",
}, },
HostInfo: HostInfo{ HostInfo: HostInfo{
@ -499,7 +499,7 @@ func Test_getTags(t *testing.T) {
}, },
}, },
machine: Machine{ machine: Machine{
Namespace: Namespace{ User: User{
Name: "joe", Name: "joe",
}, },
HostInfo: HostInfo{ HostInfo: HostInfo{
@ -524,7 +524,7 @@ func Test_getTags(t *testing.T) {
}, },
}, },
machine: Machine{ machine: Machine{
Namespace: Namespace{ User: User{
Name: "joe", Name: "joe",
}, },
HostInfo: HostInfo{ HostInfo: HostInfo{
@ -541,7 +541,7 @@ func Test_getTags(t *testing.T) {
args: args{ args: args{
aclPolicy: nil, aclPolicy: nil,
machine: Machine{ machine: Machine{
Namespace: Namespace{ User: User{
Name: "joe", Name: "joe",
}, },
HostInfo: HostInfo{ HostInfo: HostInfo{
@ -607,21 +607,21 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -635,19 +635,19 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine machine: &Machine{ // current machine
ID: 1, ID: 1,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
want: Machines{ want: Machines{
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -688,14 +688,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine machine: &Machine{ // current machine
ID: 1, ID: 1,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.1")},
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
want: Machines{ want: Machines{
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -736,14 +736,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine machine: &Machine{ // current machine
ID: 2, ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
}, },
want: Machines{ want: Machines{
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -786,7 +786,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
}, },
want: Machines{ want: Machines{
@ -795,7 +795,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -838,7 +838,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
}, },
want: Machines{ want: Machines{
@ -847,14 +847,14 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), 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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -895,7 +895,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine machine: &Machine{ // current machine
ID: 2, ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
}, },
want: Machines{ want: Machines{
@ -904,12 +904,12 @@ func Test_getFilteredByACLPeers(t *testing.T) {
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.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{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.1"), netip.MustParseAddr("100.64.0.1"),
}, },
Namespace: Namespace{Name: "joe"}, User: User{Name: "joe"},
}, },
{ {
ID: 2, ID: 2,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.2"), netip.MustParseAddr("100.64.0.2"),
}, },
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
{ {
ID: 3, ID: 3,
IPAddresses: MachineAddresses{ IPAddresses: MachineAddresses{
netip.MustParseAddr("100.64.0.3"), netip.MustParseAddr("100.64.0.3"),
}, },
Namespace: Namespace{Name: "mickael"}, User: User{Name: "mickael"},
}, },
}, },
rules: []tailcfg.FilterRule{ // list of all ACLRules registered rules: []tailcfg.FilterRule{ // list of all ACLRules registered
@ -944,7 +944,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
machine: &Machine{ // current machine machine: &Machine{ // current machine
ID: 2, ID: 2,
IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")}, IPAddresses: MachineAddresses{netip.MustParseAddr("100.64.0.2")},
Namespace: Namespace{Name: "marc"}, User: User{Name: "marc"},
}, },
}, },
want: Machines{}, want: Machines{},
@ -1125,10 +1125,10 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
err := app.LoadACLPolicy("./tests/acls/acl_policy_autoapprovers.hujson") err := app.LoadACLPolicy("./tests/acls/acl_policy_autoapprovers.hujson")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
nodeKey := key.NewNode() nodeKey := key.NewNode()
@ -1144,7 +1144,7 @@ func (s *Suite) TestAutoApproveRoutes(c *check.C) {
NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()), NodeKey: NodePublicKeyStripPrefix(nodeKey.Public()),
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "test", Hostname: "test",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
HostInfo: HostInfo{ HostInfo: HostInfo{

View file

@ -8,34 +8,34 @@ import (
const prometheusNamespace = "headscale" const prometheusNamespace = "headscale"
var ( 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. // configurable/opt-in in the future.
lastStateUpdate = promauto.NewGaugeVec(prometheus.GaugeOpts{ lastStateUpdate = promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "last_update_seconds", Name: "last_update_seconds",
Help: "Time stamp in unix time when a machine or headscale was updated", Help: "Time stamp in unix time when a machine or headscale was updated",
}, []string{"namespace", "machine"}) }, []string{"user", "machine"})
machineRegistrations = promauto.NewCounterVec(prometheus.CounterOpts{ machineRegistrations = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "machine_registrations_total", Name: "machine_registrations_total",
Help: "The total amount of registered machine attempts", Help: "The total amount of registered machine attempts",
}, []string{"action", "auth", "status", "namespace"}) }, []string{"action", "auth", "status", "user"})
updateRequestsFromNode = promauto.NewCounterVec(prometheus.CounterOpts{ updateRequestsFromNode = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "update_request_from_node_total", Name: "update_request_from_node_total",
Help: "The number of updates requested by a node/update function", Help: "The number of updates requested by a node/update function",
}, []string{"namespace", "machine", "state"}) }, []string{"user", "machine", "state"})
updateRequestsSentToNode = promauto.NewCounterVec(prometheus.CounterOpts{ updateRequestsSentToNode = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "update_request_sent_to_node_total", Name: "update_request_sent_to_node_total",
Help: "The number of calls/messages issued on a specific nodes update channel", 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. // TODO(kradalby): This is very debugging, we might want to remove it.
updateRequestsReceivedOnChannel = promauto.NewCounterVec(prometheus.CounterOpts{ updateRequestsReceivedOnChannel = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: prometheusNamespace, Namespace: prometheusNamespace,
Name: "update_request_received_on_channel_total", Name: "update_request_received_on_channel_total",
Help: "The number of update requests received on an update channel", 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 ( const (
ErrNamespaceExists = Error("Namespace already exists") ErrUserExists = Error("User already exists")
ErrNamespaceNotFound = Error("Namespace not found") ErrUserNotFound = Error("User not found")
ErrNamespaceNotEmptyOfNodes = Error("Namespace not empty: node(s) found") ErrUserStillHasNodes = Error("User not empty: node(s) found")
ErrInvalidNamespaceName = Error("Invalid namespace name") ErrInvalidUserName = Error("Invalid user name")
) )
const ( const (
@ -27,55 +27,55 @@ const (
labelHostnameLength = 63 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. // that contain our machines.
type Namespace struct { type User struct {
gorm.Model gorm.Model
Name string `gorm:"unique"` Name string `gorm:"unique"`
} }
// CreateNamespace creates a new Namespace. Returns error if could not be created // CreateUser creates a new User. Returns error if could not be created
// or another namespace already exists. // or another user already exists.
func (h *Headscale) CreateNamespace(name string) (*Namespace, error) { func (h *Headscale) CreateUser(name string) (*User, error) {
err := CheckForFQDNRules(name) err := CheckForFQDNRules(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespace := Namespace{} user := User{}
if err := h.db.Where("name = ?", name).First(&namespace).Error; err == nil { if err := h.db.Where("name = ?", name).First(&user).Error; err == nil {
return nil, ErrNamespaceExists return nil, ErrUserExists
} }
namespace.Name = name user.Name = name
if err := h.db.Create(&namespace).Error; err != nil { if err := h.db.Create(&user).Error; err != nil {
log.Error(). log.Error().
Str("func", "CreateNamespace"). Str("func", "CreateUser").
Err(err). Err(err).
Msg("Could not create row") Msg("Could not create row")
return nil, err 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. // not exist or if there are machines associated with it.
func (h *Headscale) DestroyNamespace(name string) error { func (h *Headscale) DestroyUser(name string) error {
namespace, err := h.GetNamespace(name) user, err := h.GetUser(name)
if err != nil { if err != nil {
return ErrNamespaceNotFound return ErrUserNotFound
} }
machines, err := h.ListMachinesInNamespace(name) machines, err := h.ListMachinesByUser(name)
if err != nil { if err != nil {
return err return err
} }
if len(machines) > 0 { if len(machines) > 0 {
return ErrNamespaceNotEmptyOfNodes return ErrUserStillHasNodes
} }
keys, err := h.ListPreAuthKeys(name) 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 result.Error
} }
return nil return nil
} }
// RenameNamespace renames a Namespace. Returns error if the Namespace does // RenameUser renames a User. Returns error if the User does
// not exist or if another Namespace exists with the new name. // not exist or if another User exists with the new name.
func (h *Headscale) RenameNamespace(oldName, newName string) error { func (h *Headscale) RenameUser(oldName, newName string) error {
var err error var err error
oldNamespace, err := h.GetNamespace(oldName) oldUser, err := h.GetUser(oldName)
if err != nil { if err != nil {
return err return err
} }
@ -108,76 +108,76 @@ func (h *Headscale) RenameNamespace(oldName, newName string) error {
if err != nil { if err != nil {
return err return err
} }
_, err = h.GetNamespace(newName) _, err = h.GetUser(newName)
if err == nil { if err == nil {
return ErrNamespaceExists return ErrUserExists
} }
if !errors.Is(err, ErrNamespaceNotFound) { if !errors.Is(err, ErrUserNotFound) {
return err 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 result.Error
} }
return nil return nil
} }
// GetNamespace fetches a namespace by name. // GetUser fetches a user by name.
func (h *Headscale) GetNamespace(name string) (*Namespace, error) { func (h *Headscale) GetUser(name string) (*User, error) {
namespace := Namespace{} user := User{}
if result := h.db.First(&namespace, "name = ?", name); errors.Is( if result := h.db.First(&user, "name = ?", name); errors.Is(
result.Error, result.Error,
gorm.ErrRecordNotFound, gorm.ErrRecordNotFound,
) { ) {
return nil, ErrNamespaceNotFound return nil, ErrUserNotFound
} }
return &namespace, nil return &user, nil
} }
// ListNamespaces gets all the existing namespaces. // ListUsers gets all the existing users.
func (h *Headscale) ListNamespaces() ([]Namespace, error) { func (h *Headscale) ListUsers() ([]User, error) {
namespaces := []Namespace{} users := []User{}
if err := h.db.Find(&namespaces).Error; err != nil { if err := h.db.Find(&users).Error; err != nil {
return nil, err return nil, err
} }
return namespaces, nil return users, nil
} }
// ListMachinesInNamespace gets all the nodes in a given namespace. // ListMachinesByUser gets all the nodes in a given user.
func (h *Headscale) ListMachinesInNamespace(name string) ([]Machine, error) { func (h *Headscale) ListMachinesByUser(name string) ([]Machine, error) {
err := CheckForFQDNRules(name) err := CheckForFQDNRules(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
namespace, err := h.GetNamespace(name) user, err := h.GetUser(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
machines := []Machine{} 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 nil, err
} }
return machines, nil return machines, nil
} }
// SetMachineNamespace assigns a Machine to a namespace. // SetMachineUser assigns a Machine to a user.
func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string) error { func (h *Headscale) SetMachineUser(machine *Machine, username string) error {
err := CheckForFQDNRules(namespaceName) err := CheckForFQDNRules(username)
if err != nil { if err != nil {
return err return err
} }
namespace, err := h.GetNamespace(namespaceName) user, err := h.GetUser(username)
if err != nil { if err != nil {
return err return err
} }
machine.Namespace = *namespace machine.User = *user
if result := h.db.Save(&machine); result.Error != nil { if result := h.db.Save(&machine); result.Error != nil {
return result.Error return result.Error
} }
@ -185,7 +185,7 @@ func (h *Headscale) SetMachineNamespace(machine *Machine, namespaceName string)
return nil return nil
} }
func (n *Namespace) toUser() *tailcfg.User { func (n *User) toTailscaleUser() *tailcfg.User {
user := tailcfg.User{ user := tailcfg.User{
ID: tailcfg.UserID(n.ID), ID: tailcfg.UserID(n.ID),
LoginName: n.Name, LoginName: n.Name,
@ -199,7 +199,7 @@ func (n *Namespace) toUser() *tailcfg.User {
return &user return &user
} }
func (n *Namespace) toLogin() *tailcfg.Login { func (n *User) toTailscaleLogin() *tailcfg.Login {
login := tailcfg.Login{ login := tailcfg.Login{
ID: tailcfg.LoginID(n.ID), ID: tailcfg.LoginID(n.ID),
LoginName: n.Name, LoginName: n.Name,
@ -215,24 +215,24 @@ func (h *Headscale) getMapResponseUserProfiles(
machine Machine, machine Machine,
peers Machines, peers Machines,
) []tailcfg.UserProfile { ) []tailcfg.UserProfile {
namespaceMap := make(map[string]Namespace) userMap := make(map[string]User)
namespaceMap[machine.Namespace.Name] = machine.Namespace userMap[machine.User.Name] = machine.User
for _, peer := range peers { 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{} profiles := []tailcfg.UserProfile{}
for _, namespace := range namespaceMap { for _, user := range userMap {
displayName := namespace.Name displayName := user.Name
if h.cfg.BaseDomain != "" { 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, profiles = append(profiles,
tailcfg.UserProfile{ tailcfg.UserProfile{
ID: tailcfg.UserID(namespace.ID), ID: tailcfg.UserID(user.ID),
LoginName: namespace.Name, LoginName: user.Name,
DisplayName: displayName, DisplayName: displayName,
}) })
} }
@ -240,16 +240,16 @@ func (h *Headscale) getMapResponseUserProfiles(
return profiles return profiles
} }
func (n *Namespace) toProto() *v1.Namespace { func (n *User) toProto() *v1.User {
return &v1.Namespace{ return &v1.User{
Id: strconv.FormatUint(uint64(n.ID), Base10), Id: strconv.FormatUint(uint64(n.ID), Base10),
Name: n.Name, Name: n.Name,
CreatedAt: timestamppb.New(n.CreatedAt), CreatedAt: timestamppb.New(n.CreatedAt),
} }
} }
// NormalizeToFQDNRules will replace forbidden chars in namespace // NormalizeToFQDNRules will replace forbidden chars in user
// it can also return an error if the namespace doesn't respect RFC 952 and 1123. // it can also return an error if the user doesn't respect RFC 952 and 1123.
func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) { func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) {
name = strings.ToLower(name) name = strings.ToLower(name)
name = strings.ReplaceAll(name, "'", "") name = strings.ReplaceAll(name, "'", "")
@ -259,14 +259,14 @@ func NormalizeToFQDNRules(name string, stripEmailDomain bool) (string, error) {
} else { } else {
name = strings.ReplaceAll(name, "@", ".") name = strings.ReplaceAll(name, "@", ".")
} }
name = invalidCharsInNamespaceRegex.ReplaceAllString(name, "-") name = invalidCharsInUserRegex.ReplaceAllString(name, "-")
for _, elt := range strings.Split(name, ".") { for _, elt := range strings.Split(name, ".") {
if len(elt) > labelHostnameLength { if len(elt) > labelHostnameLength {
return "", fmt.Errorf( return "", fmt.Errorf(
"label %v is more than 63 chars: %w", "label %v is more than 63 chars: %w",
elt, elt,
ErrInvalidNamespaceName, ErrInvalidUserName,
) )
} }
} }
@ -279,21 +279,21 @@ func CheckForFQDNRules(name string) error {
return fmt.Errorf( return fmt.Errorf(
"DNS segment must not be over 63 chars. %v doesn't comply with this rule: %w", "DNS segment must not be over 63 chars. %v doesn't comply with this rule: %w",
name, name,
ErrInvalidNamespaceName, ErrInvalidUserName,
) )
} }
if strings.ToLower(name) != name { if strings.ToLower(name) != name {
return fmt.Errorf( return fmt.Errorf(
"DNS segment should be lowercase. %v doesn't comply with this rule: %w", "DNS segment should be lowercase. %v doesn't comply with this rule: %w",
name, name,
ErrInvalidNamespaceName, ErrInvalidUserName,
) )
} }
if invalidCharsInNamespaceRegex.MatchString(name) { if invalidCharsInUserRegex.MatchString(name) {
return fmt.Errorf( 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", "DNS segment should only be composed of lowercase ASCII letters numbers, hyphen and dots. %v doesn't comply with theses rules: %w",
name, name,
ErrInvalidNamespaceName, ErrInvalidUserName,
) )
} }

View file

@ -8,43 +8,43 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
func (s *Suite) TestCreateAndDestroyNamespace(c *check.C) { func (s *Suite) TestCreateAndDestroyUser(c *check.C) {
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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(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) c.Assert(err, check.IsNil)
_, err = app.GetNamespace("test") _, err = app.GetUser("test")
c.Assert(err, check.NotNil) c.Assert(err, check.NotNil)
} }
func (s *Suite) TestDestroyNamespaceErrors(c *check.C) { func (s *Suite) TestDestroyUserErrors(c *check.C) {
err := app.DestroyNamespace("test") err := app.DestroyUser("test")
c.Assert(err, check.Equals, ErrNamespaceNotFound) c.Assert(err, check.Equals, ErrUserNotFound)
namespace, err := app.CreateNamespace("test") user, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
err = app.DestroyNamespace("test") err = app.DestroyUser("test")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
result := app.db.Preload("Namespace").First(&pak, "key = ?", pak.Key) result := app.db.Preload("User").First(&pak, "key = ?", pak.Key)
// destroying a namespace also deletes all associated preauthkeys // destroying a user also deletes all associated preauthkeys
c.Assert(result.Error, check.Equals, gorm.ErrRecordNotFound) c.Assert(result.Error, check.Equals, gorm.ErrRecordNotFound)
namespace, err = app.CreateNamespace("test") user, err = app.CreateUser("test")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
machine := Machine{ machine := Machine{
@ -53,57 +53,57 @@ func (s *Suite) TestDestroyNamespaceErrors(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: namespace.ID, UserID: user.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
app.db.Save(&machine) app.db.Save(&machine)
err = app.DestroyNamespace("test") err = app.DestroyUser("test")
c.Assert(err, check.Equals, ErrNamespaceNotEmptyOfNodes) c.Assert(err, check.Equals, ErrUserStillHasNodes)
} }
func (s *Suite) TestRenameNamespace(c *check.C) { func (s *Suite) TestRenameUser(c *check.C) {
namespaceTest, err := app.CreateNamespace("test") userTest, err := app.CreateUser("test")
c.Assert(err, check.IsNil) 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(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) c.Assert(err, check.IsNil)
_, err = app.GetNamespace("test") _, err = app.GetUser("test")
c.Assert(err, check.Equals, ErrNamespaceNotFound) c.Assert(err, check.Equals, ErrUserNotFound)
_, err = app.GetNamespace("test-renamed") _, err = app.GetUser("test-renamed")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
err = app.RenameNamespace("test-does-not-exit", "test") err = app.RenameUser("test-does-not-exit", "test")
c.Assert(err, check.Equals, ErrNamespaceNotFound) c.Assert(err, check.Equals, ErrUserNotFound)
namespaceTest2, err := app.CreateNamespace("test2") userTest2, err := app.CreateUser("test2")
c.Assert(err, check.IsNil) 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") err = app.RenameUser("test2", "test-renamed")
c.Assert(err, check.Equals, ErrNamespaceExists) c.Assert(err, check.Equals, ErrUserExists)
} }
func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) { func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
namespaceShared1, err := app.CreateNamespace("shared1") userShared1, err := app.CreateUser("shared1")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespaceShared2, err := app.CreateNamespace("shared2") userShared2, err := app.CreateUser("shared2")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
namespaceShared3, err := app.CreateNamespace("shared3") userShared3, err := app.CreateUser("shared3")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyShared1, err := app.CreatePreAuthKey( preAuthKeyShared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -112,7 +112,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyShared2, err := app.CreatePreAuthKey( preAuthKeyShared2, err := app.CreatePreAuthKey(
namespaceShared2.Name, userShared2.Name,
false, false,
false, false,
nil, nil,
@ -121,7 +121,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKeyShared3, err := app.CreatePreAuthKey( preAuthKeyShared3, err := app.CreatePreAuthKey(
namespaceShared3.Name, userShared3.Name,
false, false,
false, false,
nil, nil,
@ -130,7 +130,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
preAuthKey2Shared1, err := app.CreatePreAuthKey( preAuthKey2Shared1, err := app.CreatePreAuthKey(
namespaceShared1.Name, userShared1.Name,
false, false,
false, false,
nil, nil,
@ -138,7 +138,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
) )
c.Assert(err, check.IsNil) 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) c.Assert(err, check.NotNil)
machineInShared1 := &Machine{ machineInShared1 := &Machine{
@ -147,15 +147,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", NodeKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66", DiscoKey: "686824e749f3b7f2a5927ee6c1e422aee5292592d9179a271ed7b3e659b44a66",
Hostname: "test_get_shared_nodes_1", Hostname: "test_get_shared_nodes_1",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.1")},
AuthKeyID: uint(preAuthKeyShared1.ID), AuthKeyID: uint(preAuthKeyShared1.ID),
} }
app.db.Save(machineInShared1) app.db.Save(machineInShared1)
_, err = app.GetMachine(namespaceShared1.Name, machineInShared1.Hostname) _, err = app.GetMachine(userShared1.Name, machineInShared1.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared2 := &Machine{ machineInShared2 := &Machine{
@ -164,15 +164,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_2", Hostname: "test_get_shared_nodes_2",
NamespaceID: namespaceShared2.ID, UserID: userShared2.ID,
Namespace: *namespaceShared2, User: *userShared2,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.2")},
AuthKeyID: uint(preAuthKeyShared2.ID), AuthKeyID: uint(preAuthKeyShared2.ID),
} }
app.db.Save(machineInShared2) app.db.Save(machineInShared2)
_, err = app.GetMachine(namespaceShared2.Name, machineInShared2.Hostname) _, err = app.GetMachine(userShared2.Name, machineInShared2.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machineInShared3 := &Machine{ machineInShared3 := &Machine{
@ -181,15 +181,15 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_3", Hostname: "test_get_shared_nodes_3",
NamespaceID: namespaceShared3.ID, UserID: userShared3.ID,
Namespace: *namespaceShared3, User: *userShared3,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.3")},
AuthKeyID: uint(preAuthKeyShared3.ID), AuthKeyID: uint(preAuthKeyShared3.ID),
} }
app.db.Save(machineInShared3) app.db.Save(machineInShared3)
_, err = app.GetMachine(namespaceShared3.Name, machineInShared3.Hostname) _, err = app.GetMachine(userShared3.Name, machineInShared3.Hostname)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
machine2InShared1 := &Machine{ machine2InShared1 := &Machine{
@ -198,8 +198,8 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", NodeKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863", DiscoKey: "dec46ef9dc45c7d2f03bfcd5a640d9e24e3cc68ce3d9da223867c9bc6d5e9863",
Hostname: "test_get_shared_nodes_4", Hostname: "test_get_shared_nodes_4",
NamespaceID: namespaceShared1.ID, UserID: userShared1.ID,
Namespace: *namespaceShared1, User: *userShared1,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")}, IPAddresses: []netip.Addr{netip.MustParseAddr("100.64.0.4")},
AuthKeyID: uint(preAuthKey2Shared1.ID), AuthKeyID: uint(preAuthKey2Shared1.ID),
@ -218,7 +218,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
found := false found := false
for _, userProfiles := range userProfiles { for _, userProfiles := range userProfiles {
if userProfiles.DisplayName == namespaceShared1.Name { if userProfiles.DisplayName == userShared1.Name {
found = true found = true
break break
@ -228,7 +228,7 @@ func (s *Suite) TestGetMapResponseUserProfiles(c *check.C) {
found = false found = false
for _, userProfile := range userProfiles { for _, userProfile := range userProfiles {
if userProfile.DisplayName == namespaceShared2.Name { if userProfile.DisplayName == userShared2.Name {
found = true found = true
break break
@ -294,7 +294,7 @@ func TestNormalizeToFQDNRules(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "namespace name with space", name: "user name with space",
args: args{ args: args{
name: "name space", name: "name space",
stripEmailDomain: false, stripEmailDomain: false,
@ -303,7 +303,7 @@ func TestNormalizeToFQDNRules(t *testing.T) {
wantErr: false, wantErr: false,
}, },
{ {
name: "namespace with quote", name: "user with quote",
args: args{ args: args{
name: "Jamie's iPhone 5", name: "Jamie's iPhone 5",
stripEmailDomain: false, stripEmailDomain: false,
@ -341,29 +341,29 @@ func TestCheckForFQDNRules(t *testing.T) {
wantErr bool wantErr bool
}{ }{
{ {
name: "valid: namespace", name: "valid: user",
args: args{name: "valid-namespace"}, args: args{name: "valid-user"},
wantErr: false, wantErr: false,
}, },
{ {
name: "invalid: capitalized namespace", name: "invalid: capitalized user",
args: args{name: "Invalid-CapItaLIzed-namespace"}, args: args{name: "Invalid-CapItaLIzed-user"},
wantErr: true, wantErr: true,
}, },
{ {
name: "invalid: email as namespace", name: "invalid: email as user",
args: args{name: "foo.bar@example.com"}, args: args{name: "foo.bar@example.com"},
wantErr: true, wantErr: true,
}, },
{ {
name: "invalid: chars in namespace name", name: "invalid: chars in user name",
args: args{name: "super-namespace+name"}, args: args{name: "super-user+name"},
wantErr: true, wantErr: true,
}, },
{ {
name: "invalid: too long name for namespace", name: "invalid: too long name for user",
args: args{ 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, wantErr: true,
}, },
@ -377,14 +377,14 @@ func TestCheckForFQDNRules(t *testing.T) {
} }
} }
func (s *Suite) TestSetMachineNamespace(c *check.C) { func (s *Suite) TestSetMachineUser(c *check.C) {
oldNamespace, err := app.CreateNamespace("old") oldUser, err := app.CreateUser("old")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
newNamespace, err := app.CreateNamespace("new") newUser, err := app.CreateUser("new")
c.Assert(err, check.IsNil) 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) c.Assert(err, check.IsNil)
machine := Machine{ machine := Machine{
@ -393,23 +393,23 @@ func (s *Suite) TestSetMachineNamespace(c *check.C) {
NodeKey: "bar", NodeKey: "bar",
DiscoKey: "faa", DiscoKey: "faa",
Hostname: "testmachine", Hostname: "testmachine",
NamespaceID: oldNamespace.ID, UserID: oldUser.ID,
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
AuthKeyID: uint(pak.ID), AuthKeyID: uint(pak.ID),
} }
app.db.Save(&machine) 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(err, check.IsNil)
c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID) c.Assert(machine.UserID, check.Equals, newUser.ID)
c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name) c.Assert(machine.User.Name, check.Equals, newUser.Name)
err = app.SetMachineNamespace(&machine, "non-existing-namespace") err = app.SetMachineUser(&machine, "non-existing-user")
c.Assert(err, check.Equals, ErrNamespaceNotFound) 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(err, check.IsNil)
c.Assert(machine.NamespaceID, check.Equals, newNamespace.ID) c.Assert(machine.UserID, check.Equals, newUser.ID)
c.Assert(machine.Namespace.Name, check.Equals, newNamespace.Name) 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 // 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: A confirmation page for new machines should be added to avoid phishing vulnerabilities
// TODO: Add groups information from OIDC tokens into machine HostInfo // TODO: Add groups information from OIDC tokens into machine HostInfo
// Listens in /oidc/callback. // Listens in /oidc/callback.
@ -223,7 +223,7 @@ func (h *Headscale) OIDCCallback(
return return
} }
namespaceName, err := getNamespaceName(writer, claims, h.cfg.OIDC.StripEmaildomain) userName, err := getUserName(writer, claims, h.cfg.OIDC.StripEmaildomain)
if err != nil { if err != nil {
return return
} }
@ -231,12 +231,12 @@ func (h *Headscale) OIDCCallback(
// register the machine if it's new // register the machine if it's new
log.Debug().Msg("Registering new machine after successful callback") log.Debug().Msg("Registering new machine after successful callback")
namespace, err := h.findOrCreateNewNamespaceForOIDCCallback(writer, namespaceName) user, err := h.findOrCreateNewUserForOIDCCallback(writer, userName)
if err != nil { if err != nil {
return return
} }
if err := h.registerMachineForOIDCCallback(writer, namespace, nodeKey, idToken.Expiry); err != nil { if err := h.registerMachineForOIDCCallback(writer, user, nodeKey, idToken.Expiry); err != nil {
return return
} }
@ -606,12 +606,12 @@ func (h *Headscale) validateMachineForOIDCCallback(
return &nodeKey, false, nil return &nodeKey, false, nil
} }
func getNamespaceName( func getUserName(
writer http.ResponseWriter, writer http.ResponseWriter,
claims *IDTokenClaims, claims *IDTokenClaims,
stripEmaildomain bool, stripEmaildomain bool,
) (string, error) { ) (string, error) {
namespaceName, err := NormalizeToFQDNRules( userName, err := NormalizeToFQDNRules(
claims.Email, claims.Email,
stripEmaildomain, stripEmaildomain,
) )
@ -630,25 +630,25 @@ func getNamespaceName(
return "", err return "", err
} }
return namespaceName, nil return userName, nil
} }
func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback( func (h *Headscale) findOrCreateNewUserForOIDCCallback(
writer http.ResponseWriter, writer http.ResponseWriter,
namespaceName string, userName string,
) (*Namespace, error) { ) (*User, error) {
namespace, err := h.GetNamespace(namespaceName) user, err := h.GetUser(userName)
if errors.Is(err, ErrNamespaceNotFound) { if errors.Is(err, ErrUserNotFound) {
namespace, err = h.CreateNamespace(namespaceName) user, err = h.CreateUser(userName)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Caller(). 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.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError) writer.WriteHeader(http.StatusInternalServerError)
_, werr := writer.Write([]byte("could not create namespace")) _, werr := writer.Write([]byte("could not create user"))
if werr != nil { if werr != nil {
log.Error(). log.Error().
Caller(). Caller().
@ -662,11 +662,11 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback(
log.Error(). log.Error().
Caller(). Caller().
Err(err). Err(err).
Str("namespace", namespaceName). Str("user", userName).
Msg("could not find or create namespace") Msg("could not find or create user")
writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
writer.WriteHeader(http.StatusInternalServerError) 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 { if werr != nil {
log.Error(). log.Error().
Caller(). Caller().
@ -677,18 +677,18 @@ func (h *Headscale) findOrCreateNewNamespaceForOIDCCallback(
return nil, err return nil, err
} }
return namespace, nil return user, nil
} }
func (h *Headscale) registerMachineForOIDCCallback( func (h *Headscale) registerMachineForOIDCCallback(
writer http.ResponseWriter, writer http.ResponseWriter,
namespace *Namespace, user *User,
nodeKey *key.NodePublic, nodeKey *key.NodePublic,
expiry time.Time, expiry time.Time,
) error { ) error {
if _, err := h.RegisterMachineFromAuthCallback( if _, err := h.RegisterMachineFromAuthCallback(
nodeKey.String(), nodeKey.String(),
namespace.Name, user.Name,
&expiry, &expiry,
RegisterMethodOIDC, RegisterMethodOIDC,
); err != nil { ); err != nil {

View file

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

View file

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

View file

@ -325,7 +325,7 @@ func (h *Headscale) handleAuthKeyCommon(
Err(err). Err(err).
Msg("Cannot encode message") Msg("Cannot encode message")
http.Error(writer, "Internal server error", http.StatusInternalServerError) 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() Inc()
return return
@ -350,7 +350,7 @@ func (h *Headscale) handleAuthKeyCommon(
Msg("Failed authentication via AuthKey") Msg("Failed authentication via AuthKey")
if pak != nil { if pak != nil {
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name). machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc() Inc()
} else { } else {
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", "unknown").Inc() machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", "unknown").Inc()
@ -428,7 +428,7 @@ func (h *Headscale) handleAuthKeyCommon(
machineToRegister := Machine{ machineToRegister := Machine{
Hostname: registerRequest.Hostinfo.Hostname, Hostname: registerRequest.Hostinfo.Hostname,
GivenName: givenName, GivenName: givenName,
NamespaceID: pak.Namespace.ID, UserID: pak.User.ID,
MachineKey: MachinePublicKeyStripPrefix(machineKey), MachineKey: MachinePublicKeyStripPrefix(machineKey),
RegisterMethod: RegisterMethodAuthKey, RegisterMethod: RegisterMethodAuthKey,
Expiry: &registerRequest.Expiry, Expiry: &registerRequest.Expiry,
@ -447,7 +447,7 @@ func (h *Headscale) handleAuthKeyCommon(
Bool("noise", isNoise). Bool("noise", isNoise).
Err(err). Err(err).
Msg("could not register machine") Msg("could not register machine")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name). machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc() Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError) http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -462,7 +462,7 @@ func (h *Headscale) handleAuthKeyCommon(
Bool("noise", isNoise). Bool("noise", isNoise).
Err(err). Err(err).
Msg("Failed to use pre-auth key") Msg("Failed to use pre-auth key")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name). machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc() Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError) http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -470,10 +470,10 @@ func (h *Headscale) handleAuthKeyCommon(
} }
resp.MachineAuthorized = true resp.MachineAuthorized = true
resp.User = *pak.Namespace.toUser() resp.User = *pak.User.toTailscaleUser()
// Provide LoginName when registering with pre-auth key // Provide LoginName when registering with pre-auth key
// Otherwise it will need to exec `tailscale up` twice to fetch the *LoginName* // 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) respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil { if err != nil {
@ -484,13 +484,13 @@ func (h *Headscale) handleAuthKeyCommon(
Str("machine", registerRequest.Hostinfo.Hostname). Str("machine", registerRequest.Hostinfo.Hostname).
Err(err). Err(err).
Msg("Cannot encode message") Msg("Cannot encode message")
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.Namespace.Name). machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "error", pak.User.Name).
Inc() Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError) http.Error(writer, "Internal server error", http.StatusInternalServerError)
return return
} }
machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "success", pak.Namespace.Name). machineRegistrations.WithLabelValues("new", RegisterMethodAuthKey, "success", pak.User.Name).
Inc() Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.Header().Set("Content-Type", "application/json; charset=utf-8")
writer.WriteHeader(http.StatusOK) writer.WriteHeader(http.StatusOK)
@ -600,7 +600,7 @@ func (h *Headscale) handleMachineLogOutCommon(
resp.AuthURL = "" resp.AuthURL = ""
resp.MachineAuthorized = false resp.MachineAuthorized = false
resp.NodeKeyExpired = true resp.NodeKeyExpired = true
resp.User = *machine.Namespace.toUser() resp.User = *machine.User.toTailscaleUser()
respBody, err := h.marshalResponse(resp, machineKey, isNoise) respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil { if err != nil {
log.Error(). log.Error().
@ -662,8 +662,8 @@ func (h *Headscale) handleMachineValidRegistrationCommon(
resp.AuthURL = "" resp.AuthURL = ""
resp.MachineAuthorized = true resp.MachineAuthorized = true
resp.User = *machine.Namespace.toUser() resp.User = *machine.User.toTailscaleUser()
resp.Login = *machine.Namespace.toLogin() resp.Login = *machine.User.toTailscaleLogin()
respBody, err := h.marshalResponse(resp, machineKey, isNoise) respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil { if err != nil {
@ -672,13 +672,13 @@ func (h *Headscale) handleMachineValidRegistrationCommon(
Bool("noise", isNoise). Bool("noise", isNoise).
Err(err). Err(err).
Msg("Cannot encode message") Msg("Cannot encode message")
machineRegistrations.WithLabelValues("update", "web", "error", machine.Namespace.Name). machineRegistrations.WithLabelValues("update", "web", "error", machine.User.Name).
Inc() Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError) http.Error(writer, "Internal server error", http.StatusInternalServerError)
return return
} }
machineRegistrations.WithLabelValues("update", "web", "success", machine.Namespace.Name). machineRegistrations.WithLabelValues("update", "web", "success", machine.User.Name).
Inc() Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.Header().Set("Content-Type", "application/json; charset=utf-8")
@ -726,7 +726,7 @@ func (h *Headscale) handleMachineRefreshKeyCommon(
} }
resp.AuthURL = "" resp.AuthURL = ""
resp.User = *machine.Namespace.toUser() resp.User = *machine.User.toTailscaleUser()
respBody, err := h.marshalResponse(resp, machineKey, isNoise) respBody, err := h.marshalResponse(resp, machineKey, isNoise)
if err != nil { if err != nil {
log.Error(). log.Error().
@ -801,13 +801,13 @@ func (h *Headscale) handleMachineExpiredOrLoggedOutCommon(
Bool("noise", isNoise). Bool("noise", isNoise).
Err(err). Err(err).
Msg("Cannot encode message") Msg("Cannot encode message")
machineRegistrations.WithLabelValues("reauth", "web", "error", machine.Namespace.Name). machineRegistrations.WithLabelValues("reauth", "web", "error", machine.User.Name).
Inc() Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError) http.Error(writer, "Internal server error", http.StatusInternalServerError)
return return
} }
machineRegistrations.WithLabelValues("reauth", "web", "success", machine.Namespace.Name). machineRegistrations.WithLabelValues("reauth", "web", "success", machine.User.Name).
Inc() Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8") 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 // 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. // 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() Inc()
updateChan <- struct{}{} updateChan <- struct{}{}
@ -216,7 +216,7 @@ func (h *Headscale) handlePollCommon(
Bool("noise", isNoise). Bool("noise", isNoise).
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Msg("Notifying peers") Msg("Notifying peers")
updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "full-update"). updateRequestsFromNode.WithLabelValues(machine.User.Name, machine.Hostname, "full-update").
Inc() Inc()
updateChan <- struct{}{} updateChan <- struct{}{}
@ -342,7 +342,7 @@ func (h *Headscale) pollNetMapStream(
now := time.Now().UTC() now := time.Now().UTC()
machine.LastSeen = &now machine.LastSeen = &now
lastStateUpdate.WithLabelValues(machine.Namespace.Name, machine.Hostname). lastStateUpdate.WithLabelValues(machine.User.Name, machine.Hostname).
Set(float64(now.Unix())) Set(float64(now.Unix()))
machine.LastSuccessfulUpdate = &now machine.LastSuccessfulUpdate = &now
@ -453,7 +453,7 @@ func (h *Headscale) pollNetMapStream(
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Str("channel", "update"). Str("channel", "update").
Msg("Received a request for update") Msg("Received a request for update")
updateRequestsReceivedOnChannel.WithLabelValues(machine.Namespace.Name, machine.Hostname). updateRequestsReceivedOnChannel.WithLabelValues(machine.User.Name, machine.Hostname).
Inc() Inc()
if h.isOutdated(machine) { if h.isOutdated(machine) {
@ -466,7 +466,7 @@ func (h *Headscale) pollNetMapStream(
Bool("noise", isNoise). Bool("noise", isNoise).
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Time("last_successful_update", lastUpdate). 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) Msgf("There has been updates since the last successful update to %s", machine.Hostname)
data, err := h.getMapResponseData(mapRequest, machine, isNoise) data, err := h.getMapResponseData(mapRequest, machine, isNoise)
if err != nil { if err != nil {
@ -489,7 +489,7 @@ func (h *Headscale) pollNetMapStream(
Str("channel", "update"). Str("channel", "update").
Err(err). Err(err).
Msg("Could not write the map response") Msg("Could not write the map response")
updateRequestsSentToNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "failed"). updateRequestsSentToNode.WithLabelValues(machine.User.Name, machine.Hostname, "failed").
Inc() Inc()
return return
@ -514,7 +514,7 @@ func (h *Headscale) pollNetMapStream(
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Str("channel", "update"). Str("channel", "update").
Msg("Updated Map has been sent") Msg("Updated Map has been sent")
updateRequestsSentToNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "success"). updateRequestsSentToNode.WithLabelValues(machine.User.Name, machine.Hostname, "success").
Inc() Inc()
// Keep track of the last successful update, // Keep track of the last successful update,
@ -540,7 +540,7 @@ func (h *Headscale) pollNetMapStream(
} }
now := time.Now().UTC() now := time.Now().UTC()
lastStateUpdate.WithLabelValues(machine.Namespace.Name, machine.Hostname). lastStateUpdate.WithLabelValues(machine.User.Name, machine.Hostname).
Set(float64(now.Unix())) Set(float64(now.Unix()))
machine.LastSuccessfulUpdate = &now machine.LastSuccessfulUpdate = &now
@ -566,7 +566,7 @@ func (h *Headscale) pollNetMapStream(
Bool("noise", isNoise). Bool("noise", isNoise).
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Time("last_successful_update", lastUpdate). 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) Msgf("%s is up to date", machine.Hostname)
} }
@ -676,7 +676,7 @@ func (h *Headscale) scheduledPollWorker(
Str("machine", machine.Hostname). Str("machine", machine.Hostname).
Bool("noise", isNoise). Bool("noise", isNoise).
Msg("Sending update request") Msg("Sending update request")
updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "scheduled-update"). updateRequestsFromNode.WithLabelValues(machine.User.Name, machine.Hostname, "scheduled-update").
Inc() Inc()
select { select {
case updateChan <- struct{}{}: case updateChan <- struct{}{}:

View file

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

View file

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