-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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.
| func TestACLAutogroupMember(t *testing.T) { | ||
| IntegrationSkip(t) | ||
| t.Parallel() | ||
|
|
||
| scenario := aclScenario(t, | ||
| &policyv1.ACLPolicy{ | ||
| ACLs: []policyv1.ACL{ | ||
| { | ||
| Action: "accept", | ||
| Sources: []string{"autogroup:member"}, | ||
| Destinations: []string{"autogroup:member:*"}, | ||
| }, | ||
| }, | ||
| }, | ||
| 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.
| [#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.
vdovhanych
left a comment
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.
| [#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
kradalby
left a comment
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 |
| func TestACLAutogroupMember(t *testing.T) { | ||
| IntegrationSkip(t) | ||
| t.Parallel() | ||
|
|
||
| scenario := aclScenario(t, | ||
| &policyv1.ACLPolicy{ | ||
| ACLs: []policyv1.ACL{ | ||
| { | ||
| Action: "accept", | ||
| Sources: []string{"autogroup:member"}, | ||
| Destinations: []string{"autogroup:member:*"}, | ||
| }, | ||
| }, | ||
| }, | ||
| 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:memberandautogroup:tagged. I talked with @kradalby about leaving outautogroup:selffor 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.