Skip to content

refactor(network): drop ExposureClass/ServiceExposure for native loadBalancerClass - #3218

Merged
Andrei Kvapil (kvaps) merged 3 commits into
mainfrom
feat/drop-exposureclass
Jul 16, 2026
Merged

Andrei Kvapil (kvaps) merged 3 commits into
mainfrom
feat/drop-exposureclass

Conversation

@kvaps

@kvaps Andrei Kvapil (kvaps) commented Jul 6, 2026 •

Copy link
Copy Markdown
Member

What

Removes the network.cozystack.io API group — ExposureClass + ServiceExposure (#3081) — and its reconciler, in favor of native Service type: LoadBalancer + loadBalancerClass.

Why

Full rationale and discussion in #3164. For managed applications the chart already owns the Service, so:

  • type: LoadBalancer + loadBalancerClass + an admin-provisioned pool covers vendor-neutral external exposure without a dedicated API group and controller;
  • the externalIPs (node-IP) default never went through ServiceExposure (its backend is a no-op) and is left unchanged;
  • the only current consumer, the host ingress, keeps rendering type: LoadBalancer and just drops the ServiceExposure; the admin provisions the address pool / announcer out of band, as the install docs already assume.

ServiceExposure's one unique feature — dynamic per-namespace scoping of a shared VIP pool — is a convenience the managed-app path does not need, and it does not justify a second tenant-networking API group next to sdn.cozystack.io.

Changes

  • Delete api/network/v1alpha1 and internal/controller/serviceexposure (+ CRD definitions, e2e bats, controller registration, RBAC).
  • Host ingress: drop the ServiceExposure template; add an optional publishing.loadBalancerClass that sets spec.loadBalancerClass on the host-ingress LoadBalancer Service.
  • The externalIPs path and default behavior are unchanged.

Verification

  • go build ./... — green.
  • helm unittest — core/platform 72/72, extra/ingress 25/25 (incl. host-vs-tenant loadBalancerClass scoping and the immutable-field migration guard).

Migration

None required. network.cozystack.io (#3081) has never shipped in a release — it is on main only (not backported to release-1.5; absent from v1.4.x / v1.5.x), so no upgrading cluster has these CRDs and this removes it before it is ever released.

Clusters that track main and explicitly set publishing.exposureClass (opt-in, only since 2026-06-30) should provision their MetalLB / Cilium address pool themselves and set publishing.loadBalancerClass; any orphaned cozystack-<class> pool can be deleted by hand. Default clusters (externalIPs path) are unaffected.

Status

Draft / RFC for the #3164 discussion — this removes an API group that landed only days ago, so nothing here should merge before the design call. cc Aleksei Sviridkin (@lexfrei) (author of #3081) and Timofei Larkin (@lllamnyp) (#3164).

Deferred: when Kubernetes actually removes Service.spec.externalIPs, the node-IP default migrates via a MetalLB IPAddressPool with no L2Advertisement (allocate-but-don't-announce) — a separate change.

Summary by CodeRabbit

  • New Features

    • Added support for configuring the ingress host Service with a native loadBalancerClass value.
    • Expanded chart tests to verify class wiring and immutability behavior across install and upgrade scenarios.
  • Bug Fixes

    • Removed the legacy exposure-class/service-exposure flow and related controller behavior.
    • Updated templates and CRD packaging so the platform no longer renders or depends on those deprecated resources.

@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/cleanup Categorizes issue or PR as related to cleanup of code, process, or technical debt labels Jul 6, 2026
@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes the network.cozystack.io/v1alpha1 API (ExposureClass, ServiceExposure), their CRDs, controllers, backends, and tests, along with manager wiring and RBAC rules. It replaces the exposure-class mechanism with native Kubernetes loadBalancerClass configuration, wired through platform values, cluster secrets, and ingress templates with an immutability guard.

Changes

ExposureClass/ServiceExposure API and controller removal

Layer / File(s) Summary
API types and generated code removal
api/network/v1alpha1/*
Deletes ExposureClass and ServiceExposure API types, GroupVersion registration, and generated deepcopy methods.
Controller and backend removal
internal/controller/serviceexposure/...
Removes the ClassReconciler, Reconciler, mapper, status, conflict helpers, and backend implementations (ExternalIPs, MetalLB, Cilium, RobotLB) plus their tests.
Manager wiring, codegen, and RBAC
cmd/cozystack-controller/main.go, hack/update-codegen.sh, packages/system/cozystack-controller/templates/rbac.yaml, packages/system/cozystack-controller/definitions/network.cozystack.io_*.yaml
Removes scheme registration and reconciler setup, drops network CRD codegen path, and trims RBAC rules for MetalLB/Cilium/network group; deletes generated CRD manifests.
Chart template and test removal
packages/core/platform/templates/exposureclass.yaml, packages/extra/ingress/templates/serviceexposure.yaml, hack/e2e-apps/serviceexposure.bats, associated *_test.yaml
Removes Helm templates rendering ExposureClass/ServiceExposure resources and their tests, including e2e bats tests.

Native loadBalancerClass adoption

Layer / File(s) Summary
Values and cluster secret wiring
packages/core/platform/values.yaml, packages/core/platform/templates/apps.yaml, packages/core/platform/tests/apps_load_balancer_class_wiring_test.yaml
Replaces publishing.exposureClass with publishing.loadBalancerClass, propagates it into the _cluster.load-balancer-class secret entry, with new wiring tests.
Ingress template injection and immutability guard
packages/extra/ingress/templates/nginx-ingress.yaml, packages/extra/ingress/tests/load_balancer_class_test.yaml, packages/extra/ingress/tests/load_balancer_class_immutable_test.yaml
Introduces $loadBalancerClass variable, a render-time guard preventing changes to an existing LoadBalancer Service's class, conditional injection into the host Service spec, and corresponding wiring/immutability test suites.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant HelmRender as nginx-ingress.yaml
  participant K8sAPI as Kubernetes API
  participant Service as ingress-nginx Service

  Operator->>HelmRender: render chart with publishing.loadBalancerClass
  HelmRender->>K8sAPI: lookup existing host Service
  K8sAPI-->>HelmRender: existing Service (type, loadBalancerClass)
  alt Service is LoadBalancer and class differs
    HelmRender-->>Operator: fail render (immutability error)
  else class matches or no Service exists
    HelmRender->>Service: set spec.loadBalancerClass
    HelmRender-->>Operator: render succeeds
  end
Loading

Possibly related issues

Possibly related PRs

  • cozystack/cozystack#2603: Both remove the Cilium-based exposure path generating CiliumLoadBalancerIPPool resources.
  • cozystack/cozystack#3081: Introduces the exact ExposureClass/ServiceExposure API, controller, and backends that this PR removes.

Suggested labels: kind/breaking-change, area/networking

Suggested reviewers: lllamnyp, androndo, sircthulhu, myasnikovdaniil

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing network ExposureClass/ServiceExposure in favor of native loadBalancerClass.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/drop-exposureclass

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the size/XXL This PR changes 1000+ lines, ignoring generated files label Jul 6, 2026
Andrei Kvapil (kvaps) added a commit to cozystack/community that referenced this pull request Jul 6, 2026
…s/ServiceExposure

Aligns the expose field with cozystack/cozystack#3218, which removes the
network.cozystack.io ExposureClass/ServiceExposure API group. expose[].class
now maps to a native Service.spec.loadBalancerClass; each entry renders an
additive type: LoadBalancer Service and the address is read from
status.loadBalancer.ingress. The dedicated exposure API is recorded as a
rejected alternative.

Signed-off-by: Andrei Kvapil <[email protected]>
Andrei Kvapil (kvaps) and others added 3 commits July 7, 2026 12:39
…BalancerClass

Remove the network.cozystack.io API group (ExposureClass + ServiceExposure)
and its reconciler. Managed-application charts own their Service, so native
type: LoadBalancer + loadBalancerClass + an admin-provisioned pool covers
external exposure without a dedicated API group and controller. The host
ingress -- the only consumer -- keeps rendering type: LoadBalancer and gains
an optional publishing.loadBalancerClass to pick the LB controller; the
externalIPs (node-IP) default path is unchanged.

Rationale in #3164.

Assisted-By: Claude
Signed-off-by: Andrei Kvapil <[email protected]>
…ress

publishing.loadBalancerClass is a host-publishing setting, but its
_cluster.load-balancer-class block was emitted on any ingress taking the
LoadBalancer branch — including tenant ingresses — unlike expose-external-ips
and proxy-protocol, which gate on the host namespace. A tenant ingress would
then be claimed by an LB controller the tenant never selected. Gate it the
same way, and add helm-unittest coverage for the host/tenant split and the
platform to _cluster wiring.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
…ting Services

spec.loadBalancerClass is immutable once a Service is type LoadBalancer, so
setting, changing, or clearing publishing.loadBalancerClass on a cluster whose
host ingress Service already exists would make Flux wedge on an API-rejected
patch instead of migrating. Fail the render early with the exact recreate command
whenever an existing type: LoadBalancer Service's class differs from the requested
value; a fresh install (lookup nil) or a ClusterIP Service transitioning to
LoadBalancer is left untouched. Note the caveat in the values comment and cover
the guard with helm-unittest.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei

Copy link
Copy Markdown
Contributor

Pushed two follow-up commits and rebased the branch onto current main.

Host-scoping fix — publishing.loadBalancerClass is carried in the shared _cluster secret and was emitted on every ingress that takes the LoadBalancer branch, including tenant ingresses, so a tenant Service would be claimed by the platform LB class it never asked for. Gated it to the host ingress (ns == expose-ingress), matching how expose-external-ips and proxy-protocol are scoped.

Immutability guard — spec.loadBalancerClass is immutable once a Service is type: LoadBalancer (Kubernetes rejects set/change/clear while the type stays LoadBalancer), so adopting or changing publishing.loadBalancerClass on a cluster whose host ingress Service already exists would wedge Flux on an API-rejected patch. Added a lookup-based render guard that fails early with the exact kubectl delete service recreate command; fresh installs and the ClusterIP→LoadBalancer transition are left untouched.

Both are covered by helm-unittest (host/tenant split, plus the guard's set/change/clear/silent paths via a mocked lookup). helm unittest green (core/platform 72/72, extra/ingress 25/25), go build ./... green.

Heads-up: the rebase replayed the refactor(network) commit onto current main, so its SHA changed and it now shows me as committer/signer with your authorship preserved — no content change.

@lexfrei
Aleksei Sviridkin (lexfrei) marked this pull request as ready for review July 7, 2026 09:55
@dosubot dosubot Bot added area/networking Issues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn) kind/breaking-change Indicates the change introduces a breaking API or behaviour change labels Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM at the code level.

I authored #3081 (the API group this removes), and I agree the managed-app path is fully covered by native Service type: LoadBalancer + loadBalancerClass. The only ServiceExposure capability lost is dynamic per-namespace VIP-pool scoping, which the sole consumer — the host ingress — doesn't need. The removal is clean: no dangling references, go build green, RBAC and codegen consistent, and it's main-only (absent from release-1.4/release-1.5), so no migration.

For transparency, I pushed two fix commits on top: host-scoping loadBalancerClass (it was leaking from the host ingress onto tenant ingresses) and a lookup-based guard that fails early instead of wedging Flux on the immutable-field migration. Both are covered by helm-unittest.

Whether to remove the group at all is the design call in #3164 — this is a code-level LGTM, not a substitute for that decision.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@hack/update-codegen.sh`:
- Line 94: The controller-gen invocation in update-codegen.sh passes the CRD
artifacts config path unquoted, which can break when TMPDIR contains spaces or
glob characters. Update the command so the output:crd:artifacts:config argument
in the controller-gen call is quoted or otherwise safely passed as a single
shell argument, and keep the change localized to the codegen command that uses
TMPDIR.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a206bc26-3b1e-48d7-a216-9bb23a7ae27d

📥 Commits

Reviewing files that changed from the base of the PR and between 63fcebd and 43104c9.

📒 Files selected for processing (35)
  • api/network/v1alpha1/exposureclass_types.go
  • api/network/v1alpha1/groupversion_info.go
  • api/network/v1alpha1/serviceexposure_types.go
  • api/network/v1alpha1/zz_generated.deepcopy.go
  • cmd/cozystack-controller/main.go
  • hack/e2e-apps/serviceexposure.bats
  • hack/update-codegen.sh
  • internal/controller/serviceexposure/backend/backend.go
  • internal/controller/serviceexposure/backend/backend_test.go
  • internal/controller/serviceexposure/backend/cilium.go
  • internal/controller/serviceexposure/backend/externalips.go
  • internal/controller/serviceexposure/backend/metallb.go
  • internal/controller/serviceexposure/backend/registry.go
  • internal/controller/serviceexposure/backend/robotlb.go
  • internal/controller/serviceexposure/classreconciler.go
  • internal/controller/serviceexposure/conflict.go
  • internal/controller/serviceexposure/mapper.go
  • internal/controller/serviceexposure/mapper_test.go
  • internal/controller/serviceexposure/reconciler.go
  • internal/controller/serviceexposure/reconciler_test.go
  • internal/controller/serviceexposure/status.go
  • packages/core/platform/templates/apps.yaml
  • packages/core/platform/templates/exposureclass.yaml
  • packages/core/platform/tests/apps_exposure_class_test.yaml
  • packages/core/platform/tests/apps_load_balancer_class_wiring_test.yaml
  • packages/core/platform/tests/exposureclass_wiring_test.yaml
  • packages/core/platform/values.yaml
  • packages/extra/ingress/templates/nginx-ingress.yaml
  • packages/extra/ingress/templates/serviceexposure.yaml
  • packages/extra/ingress/tests/load_balancer_class_immutable_test.yaml
  • packages/extra/ingress/tests/load_balancer_class_test.yaml
  • packages/extra/ingress/tests/serviceexposure_test.yaml
  • packages/system/cozystack-controller/definitions/network.cozystack.io_exposureclasses.yaml
  • packages/system/cozystack-controller/definitions/network.cozystack.io_serviceexposures.yaml
  • packages/system/cozystack-controller/templates/rbac.yaml
💤 Files with no reviewable changes (27)
  • packages/extra/ingress/tests/serviceexposure_test.yaml
  • packages/extra/ingress/templates/serviceexposure.yaml
  • internal/controller/serviceexposure/reconciler.go
  • internal/controller/serviceexposure/conflict.go
  • api/network/v1alpha1/serviceexposure_types.go
  • hack/e2e-apps/serviceexposure.bats
  • internal/controller/serviceexposure/backend/registry.go
  • packages/system/cozystack-controller/definitions/network.cozystack.io_serviceexposures.yaml
  • internal/controller/serviceexposure/status.go
  • packages/core/platform/tests/apps_exposure_class_test.yaml
  • packages/core/platform/templates/exposureclass.yaml
  • internal/controller/serviceexposure/classreconciler.go
  • packages/system/cozystack-controller/definitions/network.cozystack.io_exposureclasses.yaml
  • internal/controller/serviceexposure/backend/metallb.go
  • internal/controller/serviceexposure/backend/backend.go
  • internal/controller/serviceexposure/mapper.go
  • internal/controller/serviceexposure/backend/externalips.go
  • api/network/v1alpha1/zz_generated.deepcopy.go
  • internal/controller/serviceexposure/backend/cilium.go
  • internal/controller/serviceexposure/backend/robotlb.go
  • internal/controller/serviceexposure/backend/backend_test.go
  • packages/core/platform/tests/exposureclass_wiring_test.yaml
  • internal/controller/serviceexposure/mapper_test.go
  • api/network/v1alpha1/exposureclass_types.go
  • api/network/v1alpha1/groupversion_info.go
  • cmd/cozystack-controller/main.go
  • internal/controller/serviceexposure/reconciler_test.go

Comment thread hack/update-codegen.sh

$CONTROLLER_GEN object:headerFile="hack/boilerplate.go.txt" paths="./api/..."
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." paths="./api/network/..." output:crd:artifacts:config=${TMPDIR}
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." output:crd:artifacts:config=${TMPDIR}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Quote the CRD output path.

${TMPDIR} is interpolated into a controller-gen argument unquoted, so a temp directory path containing spaces or glob characters can split the argument.

Proposed fix
-$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." output:crd:artifacts:config=${TMPDIR}
+$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." output:crd:artifacts:config="${TMPDIR}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." output:crd:artifacts:config=${TMPDIR}
$CONTROLLER_GEN rbac:roleName=manager-role crd paths="./api/v1alpha1/..." paths="./api/backups/..." paths="./api/gateway/..." output:crd:artifacts:config="${TMPDIR}"
🧰 Tools
🪛 Shellcheck (0.11.0)

[info] 94-94: Double quote to prevent globbing and word splitting.

(SC2086)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hack/update-codegen.sh` at line 94, The controller-gen invocation in
update-codegen.sh passes the CRD artifacts config path unquoted, which can break
when TMPDIR contains spaces or glob characters. Update the command so the
output:crd:artifacts:config argument in the controller-gen call is quoted or
otherwise safely passed as a single shell argument, and keep the change
localized to the codegen command that uses TMPDIR.

Source: Linters/SAST tools

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request simplifies the network exposure architecture by deprecating the custom network.cozystack.io API group in favor of native Kubernetes LoadBalancer services. By leveraging the standard loadBalancerClass field, the platform reduces operational complexity and removes the need for a dedicated controller to manage VIP pools and announcers, aligning the project more closely with standard Kubernetes practices.

Highlights

  • API Group Removal: Removed the network.cozystack.io API group, including the ExposureClass and ServiceExposure CRDs and their associated controllers.
  • Native LoadBalancer Support: Transitioned to using native Kubernetes Service type: LoadBalancer with loadBalancerClass for external exposure.
  • Host Ingress Configuration: Updated host ingress templates to support the publishing.loadBalancerClass configuration, replacing the previous exposureClass approach.
  • Cleanup: Removed redundant RBAC rules, e2e tests, and codegen definitions related to the deprecated network API group.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: **/zz_generated.*.go (1)
    • api/network/v1alpha1/zz_generated.deepcopy.go
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

myasnikovdaniil added a commit to cozystack/community that referenced this pull request Jul 20, 2026
…review

- #29 (ServiceExposure/ExposureClass) was removed by cozystack/cozystack#3218
  in favor of native Service type: LoadBalancer + loadBalancerClass; retarget
  the tunnel entry point and drop the Phase 1 blocker
- record initiator-vs-responder as an explicit decision: Phase 1 responder-only
  (native LB), dial-out/either-end deferred to Phase 4 gated on stable
  per-tenant egress IPs (#35)
- reframe Phase 2 (site-gateway/NAT) as a deliberate design re-open
- add portal-side image/cloud-init synchronization requirement
- record NETMAP-style 1:1 subnet mapping as NAT future work

Assisted-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
myasnikovdaniil added a commit to cozystack/community that referenced this pull request Jul 21, 2026
…review

- #29 (ServiceExposure/ExposureClass) was removed by cozystack/cozystack#3218
  in favor of native Service type: LoadBalancer + loadBalancerClass; retarget
  the tunnel entry point and drop the Phase 1 blocker
- record initiator-vs-responder as an explicit decision: Phase 1 responder-only
  (native LB), dial-out/either-end deferred to Phase 4 gated on stable
  per-tenant egress IPs (#35)
- reframe Phase 2 (site-gateway/NAT) as a deliberate design re-open
- add portal-side image/cloud-init synchronization requirement
- record NETMAP-style 1:1 subnet mapping as NAT future work

Assisted-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
Aleksei Sviridkin (lexfrei) added a commit to cozystack/website that referenced this pull request Sep 2, 2026
… values

The publishing.* reference on the next trunk documented five
publishing.exposureClass.* keys the platform no longer has: the
ExposureClass/ServiceExposure machinery was dropped for the native
Service loadBalancerClass (cozystack/cozystack#3218), and
packages/core/platform/values.yaml carries no exposureClass key. Remove
those rows and rewrite the publishing.exposure note that still named
exposureClass as the successor.

Add the publishing.loadBalancerClass row that replaced them and never
had one: it names the LoadBalancer controller for the host ingress
Service, the address pool or announcer is provisioned out of band, and
because spec.loadBalancerClass is immutable an existing Service has to
be recreated once when the value changes.

Add the publishing.serviceDomain row for the new display-only DNS
suffix the dashboard shows under the external IP of LoadBalancer
Services (cozystack/cozystack#4035).

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/networking Issues or PRs related to networking (ingress, gateway, vpn, metallb, kube-ovn) area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/breaking-change Indicates the change introduces a breaking API or behaviour change kind/cleanup Categorizes issue or PR as related to cleanup of code, process, or technical debt size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants