-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat: add autogroup:member, autogroup:tagged #2572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add autogroup:member, autogroup:tagged #2572
Conversation
Pull Request Revisions
✅ AI review completed for r3 HelpReact with emojis to give feedback on AI-generated reviews:
We'd love to hear from you—reach out anytime at [email protected]. |
hscontrol/policy/v2/types.go
Outdated
func allIPs() *netipx.IPSet { | ||
if allIPSet != nil { | ||
return allIPSet | ||
} | ||
|
||
var build netipx.IPSetBuilder | ||
build.AddPrefix(netip.MustParsePrefix("::/0")) | ||
build.AddPrefix(netip.MustParsePrefix("0.0.0.0/0")) | ||
|
||
allTheIps, _ := build.IPSet() | ||
|
||
return allTheIps | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In allIPs()
function, the IPSet is being built but not stored in the global allIPSet
variable. This means the caching mechanism isn't working - the function always builds a new set even if it's already been created.
}, | ||
}, | ||
}, | ||
2, | ||
) | ||
defer scenario.ShutdownAssertNoPanics(t) | ||
|
||
allClients, err := scenario.ListTailscaleClients() | ||
require.NoError(t, err) | ||
|
||
err = scenario.WaitForTailscaleSync() | ||
require.NoError(t, err) | ||
|
||
// Test that untagged nodes can access each other | ||
for _, client := range allClients { | ||
status, err := client.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
for _, peer := range allClients { | ||
if client.Hostname() == peer.Hostname() { | ||
continue | ||
} | ||
|
||
status, err := peer.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
fqdn, err := peer.FQDN() | ||
require.NoError(t, err) | ||
|
||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn) | ||
t.Logf("url from %s to %s", client.Hostname(), url) | ||
|
||
result, err := client.Curl(url) | ||
assert.Len(t, result, 13) | ||
require.NoError(t, err) | ||
} | ||
} | ||
} | ||
|
||
func TestACLAutogroupTagged(t *testing.T) { | ||
IntegrationSkip(t) | ||
t.Parallel() | ||
|
||
scenario := aclScenario(t, | ||
&policyv1.ACLPolicy{ | ||
ACLs: []policyv1.ACL{ | ||
{ | ||
Action: "accept", | ||
Sources: []string{"autogroup:tagged"}, | ||
Destinations: []string{"autogroup:tagged:*"}, | ||
}, | ||
}, | ||
}, | ||
2, | ||
) | ||
defer scenario.ShutdownAssertNoPanics(t) | ||
|
||
allClients, err := scenario.ListTailscaleClients() | ||
require.NoError(t, err) | ||
|
||
err = scenario.WaitForTailscaleSync() | ||
require.NoError(t, err) | ||
|
||
// Test that tagged nodes can access each other | ||
for _, client := range allClients { | ||
status, err := client.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags == nil || status.Self.Tags.Len() == 0 { | ||
continue | ||
} | ||
|
||
for _, peer := range allClients { | ||
if client.Hostname() == peer.Hostname() { | ||
continue | ||
} | ||
|
||
status, err := peer.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags == nil || status.Self.Tags.Len() == 0 { | ||
continue | ||
} | ||
|
||
fqdn, err := peer.FQDN() | ||
require.NoError(t, err) | ||
|
||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn) | ||
t.Logf("url from %s to %s", client.Hostname(), url) | ||
|
||
result, err := client.Curl(url) | ||
assert.Len(t, result, 13) | ||
require.NoError(t, err) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The integration tests for autogroup:member
and autogroup:tagged
have duplicated code structures. Consider extracting a common test helper function that takes the autogroup type and condition check as parameters to reduce duplication and increase maintainability.
@@ -122,6 +122,7 @@ working in v1 and not tested might be broken in v2 (and vice versa). | |||
[#2438](https://github.com/juanfont/headscale/pull/2438) | |||
- Add documentation for routes | |||
[#2496](https://github.com/juanfont/headscale/pull/2496) | |||
- Add support for `autogroup:member`, `autogroup:tagged` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets add the PR to this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 2b3ee90
Great start! |
require.NoError(t, err) | ||
|
||
err = scenario.WaitForTailscaleSync() | ||
require.NoError(t, err) | ||
|
||
// Test that untagged nodes can access each other | ||
for _, client := range allClients { | ||
status, err := client.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
for _, peer := range allClients { | ||
if client.Hostname() == peer.Hostname() { | ||
continue | ||
} | ||
|
||
status, err := peer.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
fqdn, err := peer.FQDN() | ||
require.NoError(t, err) | ||
|
||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn) | ||
t.Logf("url from %s to %s", client.Hostname(), url) | ||
|
||
result, err := client.Curl(url) | ||
assert.Len(t, result, 13) | ||
require.NoError(t, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both TestACLAutogroupMember and TestACLAutogroupTagged contain similar error handling and test setup logic. Consider extracting a helper function to reduce duplication and improve maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message in validateAutogroupForSSHDst incorrectly states 'for SSH sources' but should say 'for SSH destinations' to match the function's purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the comments are for me to better understand the logic, i was getting lost in it a bit.
@@ -122,6 +122,7 @@ working in v1 and not tested might be broken in v2 (and vice versa). | |||
[#2438](https://github.com/juanfont/headscale/pull/2438) | |||
- Add documentation for routes | |||
[#2496](https://github.com/juanfont/headscale/pull/2496) | |||
- Add support for `autogroup:member`, `autogroup:tagged` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in 2b3ee90
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks great, I am happy to merge this and add more tests as we continue testing.
Okay, cool. I will squash the fixup commit. |
None of them seem to out of place, let's leave them and then we can update them as needed |
I'll run the tests when you have squashed and if all passes I'll merge it |
2b3ee90
to
54d7e61
Compare
Squashed |
}, | ||
}, | ||
}, | ||
2, | ||
) | ||
defer scenario.ShutdownAssertNoPanics(t) | ||
|
||
allClients, err := scenario.ListTailscaleClients() | ||
require.NoError(t, err) | ||
|
||
err = scenario.WaitForTailscaleSync() | ||
require.NoError(t, err) | ||
|
||
// Test that untagged nodes can access each other | ||
for _, client := range allClients { | ||
status, err := client.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
for _, peer := range allClients { | ||
if client.Hostname() == peer.Hostname() { | ||
continue | ||
} | ||
|
||
status, err := peer.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags != nil && status.Self.Tags.Len() > 0 { | ||
continue | ||
} | ||
|
||
fqdn, err := peer.FQDN() | ||
require.NoError(t, err) | ||
|
||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn) | ||
t.Logf("url from %s to %s", client.Hostname(), url) | ||
|
||
result, err := client.Curl(url) | ||
assert.Len(t, result, 13) | ||
require.NoError(t, err) | ||
} | ||
} | ||
} | ||
|
||
func TestACLAutogroupTagged(t *testing.T) { | ||
IntegrationSkip(t) | ||
t.Parallel() | ||
|
||
scenario := aclScenario(t, | ||
&policyv1.ACLPolicy{ | ||
ACLs: []policyv1.ACL{ | ||
{ | ||
Action: "accept", | ||
Sources: []string{"autogroup:tagged"}, | ||
Destinations: []string{"autogroup:tagged:*"}, | ||
}, | ||
}, | ||
}, | ||
2, | ||
) | ||
defer scenario.ShutdownAssertNoPanics(t) | ||
|
||
allClients, err := scenario.ListTailscaleClients() | ||
require.NoError(t, err) | ||
|
||
err = scenario.WaitForTailscaleSync() | ||
require.NoError(t, err) | ||
|
||
// Test that tagged nodes can access each other | ||
for _, client := range allClients { | ||
status, err := client.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags == nil || status.Self.Tags.Len() == 0 { | ||
continue | ||
} | ||
|
||
for _, peer := range allClients { | ||
if client.Hostname() == peer.Hostname() { | ||
continue | ||
} | ||
|
||
status, err := peer.Status() | ||
require.NoError(t, err) | ||
if status.Self.Tags == nil || status.Self.Tags.Len() == 0 { | ||
continue | ||
} | ||
|
||
fqdn, err := peer.FQDN() | ||
require.NoError(t, err) | ||
|
||
url := fmt.Sprintf("http://%s/etc/hostname", fqdn) | ||
t.Logf("url from %s to %s", client.Hostname(), url) | ||
|
||
result, err := client.Curl(url) | ||
assert.Len(t, result, 13) | ||
require.NoError(t, err) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The integration tests for autogroup:member
and autogroup:tagged
have nearly identical structure and logic. Consider extracting a common test helper function that takes the autogroup type and filter conditions as parameters to reduce duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the validateAutogroupForSSHDst function, the error message incorrectly refers to 'SSH sources' instead of 'SSH destinations', which could be confusing during troubleshooting.
This implements two autogroups
autogroup:member
andautogroup:tagged
. I talked with @kradalby about leaving outautogroup:self
for now, as that is a bit trickier in the end.The logic of the autogroups and test is taken from the draft pr #2230, but it has been implemented for the new policy structure.