Skip to content

feat(): add hub-and-spoke topology fields to SliceConfig CRD - #408

Open
Shreesha001 wants to merge 3 commits into
kubeslice:masterfrom
Shreesha001:feature/301-topology-crd
Open

feat(): add hub-and-spoke topology fields to SliceConfig CRD#408
Shreesha001 wants to merge 3 commits into
kubeslice:masterfrom
Shreesha001:feature/301-topology-crd

Conversation

@Shreesha001

@Shreesha001 Shreesha001 commented Jul 6, 2026

Copy link
Copy Markdown

Adds the API for Hub-and-Spoke topology (Partial Mesh MVP), per the ADR (#300).

  • New optional spec.topology field on SliceConfig: mode (FullMesh | HubAndSpoke) and hubs. All non-hub clusters are spokes automatically.
  • Validation: mode enum and max 1 hub in the CRD schema; cross-field rules in the webhook (hub must be a slice member, no duplicates, at least one spoke, single hub for this release).
  • Backward compatible: no topology field → existing full-mesh behavior, unchanged.
  • API only — gateway creation does not consume the field yet (that is Controller: Compute hub-and-spoke edges and publish worker intents (Partial Mesh MVP) #302).

Fixes #301

How Has This Been Tested?

  • 12 table-driven unit tests covering every validation rule and the valid paths.
  • Local Kind cluster: valid HubAndSpoke config accepted; each invalid config rejected with a clear error; slices without topology unaffected.

Checklist:

  • The title of the PR states what changed and the related issues number.
  • I have performed a self-review of my own code.
  • I have added all the required unit test cases.

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

No

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 MVP) API surface to the SliceConfig CRD and enforces the initial validation rules via the admission webhook, while keeping default behavior backward compatible (no spec.topology → full mesh).

Changes:

  • Introduces spec.topology (mode, hubs) in the SliceConfig Go types and CRD OpenAPI schema.
  • Adds create/update webhook validation for topology cross-field rules (single hub for this release, hub must be a member, etc.) with unit tests.
  • Adds a Hub-and-Spoke sample SliceConfig manifest.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
service/slice_config_webhook_validation.go Adds validateTopology + Hub-and-Spoke rules and wires validation into create/update paths.
service/slice_config_webhook_validation_test.go Adds table-driven unit tests covering valid/invalid topology configurations.
config/samples/controller_v1alpha1_sliceconfig_hub_and_spoke.yaml Adds a sample SliceConfig manifest demonstrating the new spec.topology fields.
config/crd/bases/controller.kubeslice.io_sliceconfigs.yaml Extends the CRD schema with spec.topology (mode enum, hubs maxItems).
apis/controller/v1alpha1/zz_generated.deepcopy.go Updates generated deepcopy functions for the new TopologySpec.
apis/controller/v1alpha1/sliceconfig_types.go Adds TopologySpec / TopologyMode types and integrates them into SliceConfigSpec.
Files not reviewed (1)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 4 to 7
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.19.0
controller-gen.kubebuilder.io/version: v0.17.3
name: sliceconfigs.controller.kubeslice.io
Comment on lines +3 to +9
# worker-1 acts as the hub; worker-2 and worker-3 become spokes (all
# non-hub members are spokes). Tunnel links are created only between
# hub and spokes: worker-1<->worker-2 and worker-1<->worker-3.
# No spoke<->spoke (worker-2<->worker-3) link is created.
#
# Omitting spec.topology entirely (or setting mode: FullMesh with no
# hubs) keeps the existing full-mesh behavior.

@gourishkb gourishkb 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.

Good first PR for this feature — the CRD schema, backward compatibility guarantee, and 12 table-driven tests all land well. A few things to address before merging:

Must fix

  • The CRD YAML was regenerated with controller-gen v0.17.3, but the project was on v0.19.0. This downgrades the tooling version in the committed manifest. Please regenerate with make manifests using the project's canonical controller-gen version (check go.mod or Makefile) and verify the output matches what CI produces.

Should fix

  • MaxItems=2 in the CRD schema permits two hubs, but the webhook (len(topology.Hubs) > 1) rejects anything above one for this release. The inconsistency is intentional (CRD left permissive for future use) but needs a code comment explaining it — otherwise the next person will either tighten the CRD or remove the webhook check assuming it's a mistake.
  • The spokes == 0 guard at the end of validateHubAndSpokeTopology is unreachable under the current constraints: the function already requires len(clusters) >= 2 and len(hubs) <= 1, so there is always at least one spoke. It's a good safety net for when the 2-hub limit is lifted, but should carry a comment to that effect so it isn't deleted as dead code.
  • Validation order in validateHubAndSpokeTopology: the duplicate-hubs check fires before the len > 1 release restriction check. Input ["cluster-1", "cluster-1"] returns "duplicate hub entry" rather than "only one hub is supported in this release". Suggest swapping the order so the release restriction (more specific) comes before the general duplicate check.

Minor

  • Sample YAML is missing a trailing newline (most editors and git diff will flag this).
  • Test case "all clusters as hubs leaves no spokes and is rejected" passes a single-element cluster list, so it actually hits the "requires at least 2 clusters" check, not the spoke check. The test passes but the name is misleading. Please rename it or add a distinct test for the no-spokes path (3 clusters, 1 hub, but... actually that path is unreachable today — see the spoke check comment above). Either add a comment in the test or rename to match what is actually being asserted.
  • No test exercises the update path (ValidateSliceConfigUpdate with a topology change, e.g. HubAndSpokeFullMesh on an existing live slice). Is that transition intended to be allowed without any guard? Worth a test and a note in the PR body either way.

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:

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.

The controller-gen version here has been downgraded from v0.19.0 to v0.17.3. This suggests make manifests was run with a different tool version than what the project uses. Please regenerate with the canonical version (go.mod / Makefile pins it) and push the corrected manifest. Committing a downgraded version can silently change CRD output for other fields.

// Each entry must be a member of spec.clusters. All non-hub members
// become spokes.
//+optional
//+kubebuilder:validation:MaxItems=2

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.

MaxItems=2 in the CRD schema allows two hubs at the API level, but the webhook currently rejects len(hubs) > 1. This intentional inconsistency (keeping the CRD permissive for future 2-hub support) should have a comment here:

// MaxItems=2 intentionally permits 2 hubs in the CRD schema to leave room
// for future active/active hub support. The webhook currently restricts this
// to 1 hub for the MVP release.

Without the comment, a future contributor will either tighten the CRD to MaxItems=1 or remove the webhook check, assuming one is wrong.

if len(topology.Hubs) == 0 {
return field.Required(topologyPath.Child("Hubs"), "HubAndSpoke topology requires at least one hub")
}
if duplicate, value := util.CheckDuplicateInArray(topology.Hubs); duplicate {

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.

These two checks are in the wrong order for clarity. len(topology.Hubs) > 1 (the current release restriction) should come before the duplicate check. As written, ["cluster-1", "cluster-1"] returns "duplicate hub entry" rather than "only one hub is supported in this release". Swap the order:

if len(topology.Hubs) > 1 {
    return field.Invalid(..., "only one hub is supported in this release")
}
if duplicate, value := util.CheckDuplicateInArray(topology.Hubs); duplicate {
    return field.Duplicate(...)
}

Comment thread service/slice_config_webhook_validation.go
tcType: BANDWIDTH_CONTROL
bandwidthCeilingKbps: 5120
bandwidthGuaranteedKbps: 2560
dscpClass: AF11 No newline at end of file

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.

Missing trailing newline at end of file — please add one.

{
name: "duplicate hub entries are rejected",
clusters: clusters,
topology: &controllerv1alpha1.TopologySpec{Mode: controllerv1alpha1.TopologyModeHubAndSpoke, Hubs: []string{"cluster-1", "cluster-1"}},

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.

Test name "all clusters as hubs leaves no spokes and is rejected" is misleading — clusters here is ["cluster-1"] (single item), so it hits the "requires at least 2 clusters" check first, not the spoke check. Please rename to "single-cluster HubAndSpoke is rejected (needs at least 2 clusters)" to match what is actually being asserted.

- 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>

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 5 out of 6 changed files in this pull request and generated 3 comments.

Files not reviewed (1)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file

Comment thread service/slice_config_webhook_validation.go
Comment thread apis/controller/v1alpha1/sliceconfig_types.go
Comment thread service/slice_config_webhook_validation_test.go Outdated
…gy test cases

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 5 out of 6 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • apis/controller/v1alpha1/zz_generated.deepcopy.go: Generated file

Comment thread apis/controller/v1alpha1/sliceconfig_types.go
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.

API: Add Hub-and-Spoke topology fields to Slice CRD (Partial Mesh MVP)

3 participants