Skip to content

feat(): Hub-and-Spoke partial mesh topology - #430

Open
Shreesha001 wants to merge 22 commits into
kubeslice:hub-spoke-integration-branchfrom
Shreesha001:feature/hub-and-spoke-integration
Open

feat(): Hub-and-Spoke partial mesh topology#430
Shreesha001 wants to merge 22 commits into
kubeslice:hub-spoke-integration-branchfrom
Shreesha001:feature/hub-and-spoke-integration

Conversation

@Shreesha001

@Shreesha001 Shreesha001 commented Aug 27, 2026

Copy link
Copy Markdown

Description

Adds the complete Hub-and-Spoke (partial mesh) feature. In this mode a hub cluster connects to each spoke, spokes don't connect to each other, and spoke-to-spoke traffic is relayed through the hub.

What's included:

Part of #301, #302, #303, #304, #471

How Has This Been Tested?

  • Unit tests: topology resolver, webhook (10 cases), gateway creation, status aggregation, worker route selection and flag propagation, sidecar route split and MSS clamp.
  • Reconciler tests (envtest): hub-and-spoke specs.
  • Automated e2e (make test-e2e-hns): 6 scenarios, all pass.
  • Real 4-cluster run on OpenVPN: spoke-to-spoke ping and iperf, gateway failover, tunnel-down recovery, hub change, add/remove spoke.

Full details and commands are in docs/hub-and-spoke-testing.md.

Checklist:

  • The title of the PR states what changed and the related issue number.
  • Does this PR require documentation updates?
  • I've updated documentation as required by this PR.
  • I have performed a self-review of my own code.
  • I have commented my code in hard-to-understand areas.
  • I have added the required unit test cases.

Does this PR introduce a breaking change for other components like worker-operator?

No. The new fields are additive. Spoke-to-spoke only works when the matching worker-operator and gateway-sidecar changes are also deployed.


Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
- pin Hubs to MaxItems=1 (schema now matches the single-hub webhook rule)
- order the single-hub check before the duplicate check; mark both as
  defense-in-depth behind the schema limit
- comment the unreachable spokes==0 guard
- clarify the sample is API/validation-only (topology not yet consumed)
- add trailing newline to sample; regen CRD with controller-gen v0.19.0

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…gy test cases

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…dition

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…e#304)

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…logy changes

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…oke-integration

# Conflicts:
#	apis/worker/v1alpha1/workerslicegateway_types.go
#	config/crd/bases/worker.kubeslice.io_workerslicegateways.yaml
@Shreesha001 Shreesha001 changed the title feat(): Hub-and-Spoke partial mesh — full feature for integration testing feat(): Hub-and-Spoke partial mesh topology Aug 27, 2026
…nfig only on gateway connection-state change

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
… remove dead require.NoError(t, nil) assertions

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds Hub-and-Spoke (partial mesh) topology support to the KubeSlice controller, including API/webhook validation, topology edge resolution, gateway reconciliation behavior (including spoke routing via hub), slice-level convergence status aggregation, and automated e2e coverage.

Changes:

  • Introduces spec.topology on SliceConfig (HubAndSpoke vs FullMesh) with admission validation and sample YAML.
  • Computes desired topology edges and reconciles WorkerSliceGateway objects accordingly (including spoke-side routeEntireSliceSubnet).
  • Aggregates per-gateway connectivity into a TopologyConverged SliceConfig status condition and adds an automated Kind-based e2e suite + docs.

Reviewed changes

Copilot reviewed 22 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/e2e/scenarios_test.go Adds scenario assertions for hub-and-spoke gateway graph, flag reconciliation, webhook rejection, and status field persistence.
test/e2e/hubandspoke_e2e_test.go Adds top-level e2e test that runs hub-and-spoke scenarios sequentially in one Kind cluster.
test/e2e/harness_test.go Implements the Kind/docker/kubectl-based e2e harness to deploy the controller and run scenarios.
service/worker_slice_gateway_service.go Reworks gateway creation/cleanup to be topology-driven and reconciles routeEntireSliceSubnet on surviving gateway pairs.
service/worker_slice_gateway_service_test.go Extends unit tests for hub-and-spoke edge behavior, spoke-to-spoke cleanup, and flag reconciliation.
service/topology_status.go Adds condition builder for aggregating gateway connectivity into TopologyConverged.
service/topology_status_test.go Adds unit tests for TopologyConverged condition aggregation behavior and message determinism.
service/topology_resolver.go Adds topology edge resolver + direction-insensitive edge set utility.
service/topology_resolver_test.go Adds unit tests for edge resolution and edge-set membership.
service/slice_config_webhook_validation.go Adds topology validation for SliceConfig create/update (including HubAndSpoke constraints).
service/slice_config_webhook_validation_test.go Adds table-driven unit tests for topology validation.
service/slice_config_service.go Calls topology-aware gateway reconciliation and aggregates TopologyConverged status (incl. NONET path).
service/slice_config_service_test.go Updates reconciliation tests to account for new gateway-creation signature and status aggregation path (partially).
service/mocks/IWorkerSliceGatewayService.go Updates mock for the new CreateMinimumWorkerSliceGateways(..., topology) signature.
Makefile Adds make test-e2e-hns target for the new e2e suite.
docs/hub-and-spoke-testing.md Adds comprehensive testing documentation and runbooks for hub-and-spoke.
controllers/controller/sliceconfig_hubandspoke_test.go Adds envtest coverage for hub-and-spoke behavior and topology changes.
controllers/controller/sliceconfig_controller.go Watches WorkerSliceGateway status changes to trigger SliceConfig reconcile for topology status aggregation.
config/samples/controller_v1alpha1_sliceconfig_hub_and_spoke.yaml Adds a sample SliceConfig manifest using HubAndSpoke topology.
config/crd/bases/worker.kubeslice.io_workerslicegateways.yaml Extends WorkerSliceGateway CRD schema for routing flag + connection status fields.
config/crd/bases/controller.kubeslice.io_sliceconfigs.yaml Extends SliceConfig CRD schema for spec.topology and status.conditions.
apis/worker/v1alpha1/workerslicegateway_types.go Adds routeEntireSliceSubnet and connection status fields/constants to the Worker API type.
apis/worker/v1alpha1/zz_generated.deepcopy.go Fixes deepcopy behavior for the expanded WorkerSliceGateway status (incl. pointer time).
apis/controller/v1alpha1/sliceconfig_types.go Adds spec.topology, topology enums, and slice condition types/reasons.
apis/controller/v1alpha1/zz_generated.deepcopy.go Adds deepcopy support for the new topology fields and status conditions.
Files not reviewed (3)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file
  • apis/worker/v1alpha1/zz_generated.deepcopy.go: Generated file
  • service/mocks/IWorkerSliceGatewayService.go: Generated file

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread service/worker_slice_gateway_service.go
Comment thread apis/controller/v1alpha1/sliceconfig_types.go
Comment thread service/slice_config_service.go
…ge and NONET status tests, remove dead assertions, document reconcile cost

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…-teardown and integration tests

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>
…s consistent with status reconcile; add partial-pair envtest

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 25 changed files in this pull request and generated no new comments.

Files not reviewed (3)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file
  • apis/worker/v1alpha1/zz_generated.deepcopy.go: Generated file
  • service/mocks/IWorkerSliceGatewayService.go: Generated file
Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

test/e2e/scenarios_test.go:165

  • The error-output check is partially case-sensitive ("Unsupported" / "Too many"), which can make this e2e test flaky across kubectl/server versions where the same message is emitted with different casing. Since you already lowercase for "invalid", it’s safer to lowercase once and check everything case-insensitively.
		if !strings.Contains(strings.ToLower(out), "invalid") && !strings.Contains(out, "Unsupported") && !strings.Contains(out, "Too many") {
			t.Fatalf("invalid topology %q rejected without a clear error:\n%s", c.name, out)
		}

apis/controller/v1alpha1/sliceconfig_types.go:101

  • The linked requirements in issue #301 specify topology.hubs supports 1–2 entries and also include an optional topology.spokes list (defaulting to all non-hub members). This API type currently supports only hubs and hard-limits it to 1 via MaxItems, which appears to diverge from the stated requirements.
// TopologySpec defines the inter-cluster connection topology of the slice
type TopologySpec struct {
	// Mode selects the connection topology. Absent defaults to FullMesh.
	//+optional
	Mode TopologyMode `json:"mode,omitempty"`
	// Hubs lists the clusters acting as hubs when Mode is HubAndSpoke.
	// Each entry must be a member of spec.clusters. All non-hub members
	// become spokes. Exactly one hub is supported in this release.
	//+optional
	//+kubebuilder:validation:MaxItems=1
	Hubs []string `json:"hubs,omitempty"`

…luster CR is not found yet

Signed-off-by: Shreesha001 <shettyshreesha552@gmail.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 22 out of 25 changed files in this pull request and generated no new comments.

Files not reviewed (3)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file
  • apis/worker/v1alpha1/zz_generated.deepcopy.go: Generated file
  • service/mocks/IWorkerSliceGatewayService.go: Generated file
Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

controllers/controller/sliceconfig_controller.go:85

  • gatewayConnectionStateChanged claims to allow create/delete events through, but the predicate only defines UpdateFunc. In controller-runtime, omitted funcs default to false, so gateway create/delete (and generic) events will be dropped and SliceConfig won’t be enqueued on gateway creation/deletion, potentially leaving TopologyConverged stale until some later update.
var gatewayConnectionStateChanged = predicate.Funcs{
	UpdateFunc: func(e event.UpdateEvent) bool {
		oldGw, ok1 := e.ObjectOld.(*workerv1alpha1.WorkerSliceGateway)
		newGw, ok2 := e.ObjectNew.(*workerv1alpha1.WorkerSliceGateway)
		if !ok1 || !ok2 {

test/e2e/scenarios_test.go:165

  • The rejection-message check is partially case-sensitive (Unsupported, Too many). Depending on kubectl/apiserver phrasing and capitalization, this can cause false failures even when the manifest was correctly rejected. Normalize the output once and compare in one case.
		if !strings.Contains(strings.ToLower(out), "invalid") && !strings.Contains(out, "Unsupported") && !strings.Contains(out, "Too many") {
			t.Fatalf("invalid topology %q rejected without a clear error:\n%s", c.name, out)
		}

apis/controller/v1alpha1/sliceconfig_types.go:101

  • The Topology API in this PR hard-codes a single-hub MVP (MaxItems=1) and does not provide the optional spokes list described in the linked requirements (#301 expects hubs size 1–2 and spokes optional/default). If the intent is to fully meet #301 as written, the API/schema/validation need to be extended accordingly (and edge resolution updated to respect explicit spokes).
	// Hubs lists the clusters acting as hubs when Mode is HubAndSpoke.
	// Each entry must be a member of spec.clusters. All non-hub members
	// become spokes. Exactly one hub is supported in this release.
	//+optional
	//+kubebuilder:validation:MaxItems=1
	Hubs []string `json:"hubs,omitempty"`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants