Skip to content

Bring Your Own DRANET Provider (BYODP) - #223

Merged
k8s-ci-robot merged 10 commits into
kubernetes-sigs:mainfrom
aojea:profiles
Jun 10, 2026
Merged

Bring Your Own DRANET Provider (BYODP)#223
k8s-ci-robot merged 10 commits into
kubernetes-sigs:mainfrom
aojea:profiles

Conversation

@aojea

@aojea aojea commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

/kind feature
/kind documentation

What this PR does / why we need it:

This PR introduces the Bring Your Own DRANET Provider (BYODP) feature, allowing users to provide custom implementations for both hardware discovery and user intent via external webhooks.

Instead of hardcoding bare-metal or CNI-specific logic directly into DRANET, we can now delegate these responsibilities to an external HTTP REST server or Unix domain socket. This ensures DRANET's core runtime remains solid, statically verifiable, and predictable, while still exposing flexibility for third-party extensions.

This PR specifically introduces:

  1. Cloud Providers (Cluster Provider Intent): Webhooks can dictate physical infrastructural (e.g., base MTU, hardware MAC, PCI boundaries).
  2. Profile Providers (User Intent): Webhooks can dictate logical network assignments like IPAM (e.g., allocating an IP address from an external IPAM plugin like whereabouts or from a Cloud Provider).
  3. Webhook Capabilities Discovery: DRANET queries /health on startup to negotiate cloudProvider and profileProvider capability support.
  4. Reference Implementation: Adds a fully functional reference webhook server (cmd/webhook-whereabouts) that wraps the standard CNI whereabouts plugin to deliver dynamic IPAM profiles.

Which issue(s) this PR is related to:

Fixes: #103

Special notes for your reviewer:

To make the review process this PR has 3 commits:

  1. Refactor: Decouples the existing cloud hardware discovery logic out of pkg/inventory into a distinct pkg/cloudprovider/discovery package.
  2. Feature & Docs: Introduces the generic webhook client, ProfileProvider interface integration in the inventory DB, and comprehensive architectural documentation (site/content/docs/contributing/webhook-providers.md).
  3. Example & Tests: Adds the webhook-whereabouts reference module and the associated E2E bats tests verifying the dynamic whereabouts CNI integration.
    4

Does this PR introduce a user-facing change?

Add support for Custom Webhook Providers (BYODP) via the `--cloud-provider-hint=webhook`, `--profile-provider=webhook`, and `--webhook-url` flags. This enables users to delegate physical hardware discovery and logical network IPAM assignments to external HTTP servers or Unix domain sockets.

@k8s-ci-robot k8s-ci-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. kind/feature Categorizes issue or PR as related to a new feature. kind/documentation Categorizes issue or PR as related to documentation. labels Jun 8, 2026
@aojea
aojea requested a review from kanlkan June 8, 2026 15:43
@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jun 8, 2026
@aojea
aojea requested a review from gauravkghildiyal June 8, 2026 15:43
Comment thread pkg/cloudprovider/discovery/discovery.go
Comment thread pkg/cloudprovider/discovery/discovery_test.go Outdated
@netlify

netlify Bot commented Jun 8, 2026

Copy link
Copy Markdown

Deploy Preview for dranet ready!

Name Link
🔨 Latest commit 7f86460
🔍 Latest deploy log https://app.netlify.com/projects/dranet/deploys/6a292c901512090008c0708a
😎 Deploy Preview https://deploy-preview-223--dranet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@aojea
aojea force-pushed the profiles branch 2 times, most recently from 83a4e42 to 0d437fa Compare June 8, 2026 16:08
Comment thread pkg/inventory/db.go
func (db *DB) GetProfileConfig(deviceName, profile string, claimUID types.UID) (*apis.NetworkConfig, error) {
p := db.getProfileProvider()
if p == nil {
return nil, fmt.Errorf("current cloud provider does not support dynamic profiles")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This means that the user hasn't configured a dynamic profile provider (e.g. they didn't start the dranet daemon with --profile-provider=webhook or the clooud provider does not implement it, however, if this function is being called, it strictly means that a Pod is attempting to start with a specific Profile explicitly requested in its DRANET Network Config

Comment thread cmd/dranet/app.go Outdated

var hint discovery.CloudProviderHint
// Auto-discover cloud provider if not explicitly set
if cloudProviderHint == "" {

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.

I understand the intent, the concern is that the code currently makes explicit cloud-provider failures indistinguishable from no underlay provider requested

I would suggest sth like this:

explicitCloudProvider := cloudProviderHint != ""
cloudInst, err = discovery.GetInstanceProperties(ctx, hint, webhookURL)
if err != nil {
    if explicitCloudProvider {
        klog.Fatalf("failed to initialize cloud provider %q: %v", hint, err)
    }
    klog.Infof("failed to initialize auto-discovered cloud provider %q: %v", hint, err)
    cloudInst = nil
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This keeps the same behavior as before, we do not want to make a breaking change because this will cause that dranets that worked before to start to fail ... also we explicitily indicated in the flag is just a hint because of this

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.

sounds good

Comment thread pkg/cloudprovider/webhook/webhook.go Outdated
if err := json.NewDecoder(resp.Body).Decode(&caps); err == nil {
p.caps = caps
} else {
p.caps = Capabilities{CloudProvider: true, ProfileProvider: true}

@anson627 anson627 Jun 8, 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.

This returns a provider even when /health failed, because all errors above are swallowed

For explicit webhook use, startup should fail if the capability contract cannot be validated, otherwise the dranet pod can become ready with a misconfigured webhook and fail later during claim preparation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

good catch, fixed, added new commits for simplifying reviews

Comment thread pkg/driver/dra_hooks.go
if devCfg.Claim.Namespace == claim.Namespace && devCfg.Claim.Name == claim.Name {
if devCfg.NetworkInterfaceConfigInPod.Profile != "" {
if err := np.netdb.ReleaseProfileConfig(deviceName, devCfg.NetworkInterfaceConfigInPod.Profile, claim.UID); err != nil {
klog.Errorf("failed to release profile config for claim %v: %v", claim.NamespacedName, err)

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.

it is better to return the ReleaseProfileConfig error instead of only logging it, otherwise unprepare reports success, deletes the claim state, and kubelet will not retry leaked profile/IPAM cleanup

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Everything on pod teardown use to get swallowed because a retry does not imply a retry of the operation and the risk of causing deadlock situations on exit.

This is also how CNI works and is how is also specified

Plugins should generally complete a DEL action without error even if some resources are missing

and how NRI works too, we are trying to document the NRI contract too containerd/nri#286

I understand your concern but is like a defer x.Close() , is on the provider to ensure there is no leaks

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.

make sense

aojea added 2 commits June 9, 2026 09:42
This e2e test uses a simple Python webhook to demonstrate the power and
flexibility of Dranet's architecture. It shows why we do not need to
couple traditional networking constructs (like IPAM) to the core API.

At its core, IPAM is just an internal process of assigning an IP to an
interface. The interface itself only cares about the addresses, routes,
and MTU assigned to it. By abstracting these details behind the Profile
and Cloud Provider interfaces, Dranet becomes highly portable. It can
seamlessly integrate with any kind of IPAM or environment-specific
configuration mechanism out there without having to implement or
hardcode them natively.

The included webhook script dynamically returns the necessary custom
attributes, MTU overrides (via cloud intent), and IP addresses (via user
intent profile), which Dranet successfully applies to the interface.
@anson627

anson627 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 9, 2026
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 9, 2026
@aojea

aojea commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/hold

latest e2e test is not working correctly, will unhold once I'm understanding better the problem

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 9, 2026
Comment thread tests/python_webhook.bats Outdated

# Wait for the interface to be discovered and validate the custom attribute from webhook
sleep 5
run kubectl --context kind-dranet-test-cluster get resourceslices --field-selector spec.nodeName="$NODE_NAME" -o jsonpath='{.items[0].spec.devices[?(@.name=="dummy1")].attributes.dra\.net\/webhook-attr.string}'

@aojea aojea Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the hyphen fails the apiserver validation webhook-attr and the ResourceSlice was never updated, I can see how this can happen in prod

@anson627

anson627 commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

these may fix e2e issues:

  1. Update tests/manifests/python_webhook_pod.yaml to use webhook_attr and avoid has on map indexing
  2. Run go mod tidy and include go.mod/go.sum changes for cmd/webhook-whereabouts

@aojea
aojea force-pushed the profiles branch 2 times, most recently from 4e98645 to f38ee84 Compare June 9, 2026 13:51
@aojea

aojea commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

/hold cancel

tests are passing, covering custom webhooks and wherabouts ipam

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jun 9, 2026
This refactor removes the redundant 'profile' string parameter from the
GetProfileConfig and ReleaseProfileConfig interface methods across the
driver, inventory, and cloudprovider packages, replacing it with the full
'NetworkConfig' struct.

Reasoning & Trade-offs:
Passing the entire NetworkConfig gives the node-level webhook full
context regarding the user and cloud intents. This allows the webhook
to behave like a Validating Admission Controller, enabling it to
intelligently accept or deny configurations (e.g., rejecting an
invalid static IP request) using HTTP status codes.

While this approach grants powerful node-level validation, it comes
with the trade-off of delayed feedback. Because validation happens
asynchronously during the DRA NodePrepareResources phase rather than at
the API Server, invalid configurations result in Pods getting stuck in a
Pending state and Kubelet repeatedly retrying NodePrepareResources, rather
than an immediate API rejection on 'kubectl apply'.

Includes updates to test mocks, a new webhook unit test, and
expanded documentation explaining these architectural trade-offs.

@kanlkan kanlkan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for opening this PR. I added some comments for the document.

Comment on lines +108 to +109
* **Kubelet Retry Loops**: Standard Kubernetes behavior is to retry failed resource preparations. A persistent denial (like a 400 Bad Request) will cause the Kubelet to continuously retry `NodePrepareResources`, which can generate unnecessary load on the node and webhook server compared to an upfront API rejection.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would like to add one more sentence here.

  * **Idempotency**: The kubelet may retry `NodePrepareResources`, so DRANET can call this more than once for the same `(device, claimUID)`. It must return an equivalent result without allocating additional resources (e.g. key the allocation by `claimUID`, as `whereabouts` does via `CNI_CONTAINERID`).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added

Comment on lines +110 to +111
* `POST /ReleaseProfileConfig`: Frees stateful resources (e.g., releasing an IP address). Also receives the full `NetworkConfig`. Should return `200 OK` on success or if the resource was already released (idempotency).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would like to add one more sentence here.

  * **Best-effort teardown**: A failed `ReleaseProfileConfig` is logged but not retried by DRANET (teardown must not block pod deletion). The provider therefore owns leak reclamation and must be able to garbage-collect orphaned allocations on its own, otherwise resources leak permanently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added

aojea added 2 commits June 10, 2026 09:17
This extracts the getDeviceNetworkConfig logic from prepareResourceClaim to allow for exhaustive unit testing of the configuration precedence. A comprehensive table-driven test was added to validate that User configurations properly override Cloud and Profile/Webhook intents, and that Webhook blocking correctly bubbles up errors.

@kanlkan kanlkan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!
/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Jun 10, 2026
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: anson627, aojea, kanlkan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot
k8s-ci-robot merged commit 1b7c7e5 into kubernetes-sigs:main Jun 10, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. lgtm "Looks good to me", indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for IPAM like Whereabouts

4 participants