feat(): Hub-and-Spoke partial mesh topology - #430
Conversation
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
…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>
There was a problem hiding this comment.
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.topologyonSliceConfig(HubAndSpoke vs FullMesh) with admission validation and sample YAML. - Computes desired topology edges and reconciles
WorkerSliceGatewayobjects accordingly (including spoke-siderouteEntireSliceSubnet). - Aggregates per-gateway connectivity into a
TopologyConvergedSliceConfig 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.
…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>
There was a problem hiding this comment.
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.hubssupports 1–2 entries and also include an optionaltopology.spokeslist (defaulting to all non-hub members). This API type currently supports onlyhubsand 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>
There was a problem hiding this comment.
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
gatewayConnectionStateChangedclaims to allow create/delete events through, but the predicate only definesUpdateFunc. 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 leavingTopologyConvergedstale 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 optionalspokeslist described in the linked requirements (#301 expectshubssize 1–2 andspokesoptional/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"`
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:
TopologyConvergedstatus (Controller: Aggregate worker topology status into Slice status (Partial Mesh MVP) #303)Part of #301, #302, #303, #304, #471
How Has This Been Tested?
make test-e2e-hns): 6 scenarios, all pass.Full details and commands are in
docs/hub-and-spoke-testing.md.Checklist:
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.