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:
parent
bafb6791d3
commit
e3a2593344
36
acls.go
36
acls.go
|
@ -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,
|
||||||
|
|
212
acls_test.go
212
acls_test.go
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
48
app.go
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
14
dns.go
|
@ -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 {
|
||||||
|
|
82
dns_test.go
82
dns_test.go
|
@ -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),
|
||||||
|
|
80
grpcv1.go
80
grpcv1.go
|
@ -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{},
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"))
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
72
machine.go
72
machine.go
|
@ -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)
|
||||||
|
|
174
machine_test.go
174
machine_test.go
|
@ -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{
|
||||||
|
|
12
metrics.go
12
metrics.go
|
@ -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"})
|
||||||
)
|
)
|
||||||
|
|
148
namespaces.go
148
namespaces.go
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
42
oidc.go
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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: ®isterRequest.Expiry,
|
Expiry: ®isterRequest.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")
|
||||||
|
|
|
@ -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{}{}:
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue