Repository navigation
Conversation
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open findings
The previous implementation listed ACLs using bothaclidandnetworkid, but… · NewrequireNoACLRulesis described as guarding tests that “count every rule on their port”, but it… · NewrequireNoACLRulesis described as guarding tests that “count every rule on their port”, but it… · Newstrings.Contains(r.Cidrlist, "0.0.0.0/0")can return true for unrelated CIDRs like"10.0.0.0/0"… · New
What changed in this PR
This PR fixes VPC-tier Network ACL rule ownership so each Kubernetes Service gets (and deletes) only its own ACL rule, preventing shared-port Services or operator-created rules from being accidentally removed (fixes #107).
Changes:
- Add per-Service ownership via the CloudStack ACL rule
reason, adopt legacy unowned rules when possible, and avoid touching operator rules. - Adjust deletion flow to retain LB rules when ACL rule deletion fails, ensuring Kubernetes retries cleanup.
- Expand unit and e2e coverage for ownership/adoption/retention scenarios and document upgrade behavior.
| File | Description |
|---|---|
cloudstack_loadbalancer.go |
Implements owned-per-Service ACL rules (reason-based), legacy adoption, and retry-safe deletion semantics. |
cloudstack_loadbalancer_test.go |
Adds unit coverage for ACL rule classification, listing, adoption, ownership-scoped create/delete, and end-to-end sync/delete flows. |
test/e2e/vpc_test.go |
Adds new VPC e2e regression tests for per-Service ACL rules, legacy adoption, and operator rule retention. |
test/e2e/framework.go |
Adds helper APIs for creating/listing/cleaning up ACL rules directly via CloudStack for e2e tests. |
docs/development.md |
Documents new e2e assumptions about counting ACL rules and failure mode when leftovers exist. |
README.md |
Documents per-Service ACL rule behavior and adds an “Upgrading” section with operational guidance. |
🧠 Review effort: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #109 +/- ##
==========================================
+ Coverage 71.97% 73.83% +1.86%
==========================================
Files 5 5
Lines 1470 1525 +55
==========================================
+ Hits 1058 1126 +68
+ Misses 361 350 -11
+ Partials 51 49 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
7bf1f07 to
8d54f21
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
5 open findings
WhenlbRule.Networkidis empty, the fallback useslb.ipAddrIDrather than the IP associated… · New This newly introduced error wraps the underlying error using%s, which loses unwrap-ability and… · New Same issue as above:%sprevents proper error unwrapping. Prefer%wforerrso higher-level… · New The reason prefix string is duplicated here and in production (networkACLReasonPrefix). Since the… · New The phrase “leaves the port to” is grammatically incomplete/unclear. Consider rewording to… · New
4 resolved since last review
strings.Contains(r.Cidrlist, "0.0.0.0/0")can return true for unrelated CIDRs like"10.0.0.0/0"…requireNoACLRulesis described as guarding tests that “count every rule on their port”, but it…requireNoACLRulesis described as guarding tests that “count every rule on their port”, but it… The previous implementation listed ACLs using bothaclidandnetworkid, but…
🧠 Review effort: Lite
8d54f21 to
6a381d4
Compare
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Copilot review overview
4 open findings
errors.Joinrequires Go 1.20+. If the project supports Go < 1.20, this introduces a compile-time… · New Importingslicesrequires Go 1.21+. If the repo’s supported Go version (go.mod/CI toolchain) is <… · New The comment says this fails the test when “any rule for the port” (regardless of… · New This error path should wrap the underlying error with%winstead of formatting it with%v, so… · New
5 resolved since last review
The reason prefix string is duplicated here and in production (networkACLReasonPrefix). Since the… Same issue as above:%sprevents proper error unwrapping. Prefer%wforerrso higher-level… This newly introduced error wraps the underlying error using%s, which loses unwrap-ability and… WhenlbRule.Networkidis empty, the fallback useslb.ipAddrIDrather than the IP associated… The phrase “leaves the port to” is grammatically incomplete/unclear. Consider rewording to…
🧠 Review effort: Lite
|
Hi @vishesh92 , @DaanHoogland , I reviewed the changes for per-Service Network ACL ownership. The ownership and cleanup approach looks worth testing carefully, particularly when multiple Services share a port. One additional improvement is to use |
On a VPC tier the controller opened a port with an ACL rule matched only on protocol and port. Every Service using that port shared the rule, and it was deleted when any of them was deleted or moved off the port, so the other Services lost traffic on it. Each rule the controller creates now carries the reason "Managed by the CloudStack Kubernetes Provider for <lb name>", and only rules with the Service's own reason are deleted. A rule created by an earlier release is taken over on the first sync; rules someone else made are left alone. A Service whose ACL rule cannot be deleted keeps its load balancer rule, so Kubernetes retries the cleanup. Fixes #107
6a381d4 to
a7a44ba
Compare
Thanks for the review. we need to ensure that deleting a service doesn't delete a rule which is used by another service. So, each service will have it's own rule. We don't really care about the range conflicts for these changes. |


Problem
On a VPC tier the controller opened a Service port with one Network ACL rule matched only on
protocol and port. Every Service using that port shared it, and it was deleted when any of them
was deleted or moved off the port, so the other Services lost ingress until their next sync.
Rules an operator made for the same port were taken over and deleted the same way.
Change
Managed by the CloudStack Kubernetes Provider for <lb name>, and only rules with theService's own reason are deleted. Each Service gets its own rule, even when another Service
already has one for the port.
0.0.0.0/0, one port, no reason) is taken over onthe first sync with
updateNetworkACLItem. If that is refused, the Service creates its ownrule; if creating is refused too, it keeps using the old rule, as before.
They are no longer deleted with the Service. Rules in a global ACL list are never taken over.
EnsureLoadBalancerDeletedlooks the ACL rule up in the load balancer rule's own network, andkeeps a load balancer rule whose ACL rule could not be deleted, so the cleanup is retried.
which are still ignored.
The issue proposed resource tags. This uses the rule's
reasoninstead: it is set in the createcall, so a new rule is never unmarked, and the account CloudStack's Kubernetes service creates
for project clusters cannot call
createTags.Upgrading
README has a new "Upgrading" section listing what users will notice, what to do before upgrading
and what to check after. In short: give hand-made
0.0.0.0/0rules a reason, allowupdateNetworkACLItem, and upgrade every controller whose Services share a tier or ACL list.Testing
delete, and full
EnsureLoadBalancer/EnsureLoadBalancerDeletedruns on a VPC tier.TestVPC_ACLRulePerService(the issue's reproduction),TestVPC_LegacyACLRuleAdoptedandTestVPC_OperatorACLRuleKept.TestVPC_ACLRulePerServicefails againstmainwith "port 80 is no longer open on the tierafter deleting one of the two Services using it" and passes with this change.
(
TestNode_ProviderID, kind sets provider IDs); phase 2 8 passed.Fixes #107