Skip to content

Conversation

@klihub
Copy link
Member

@klihub klihub commented Jan 20, 2026

This patch series

  • adds new fields for version exchange to the NRI protocol
  • updates the adaptation and the plugin stub to exchange NRI versions used
  • [removed: adds a default NRI version check (which can be disabled) to the plugin stub]
  • introduces capabilities intended to describe supported/required runtime NRI features
  • adds an option for the adaptation to advertise NRI features for the runtime
  • adds a plugins/stub option to declare capabilities required from the runtime
  • checks any required capabilities against advertised or inferred runtime capabilities

Updates:
@samuelkarp @mikebrow I reworked this, ditching version-based checks and implementing more complete support for capability-based checks. Also added capability requirements to plugins which need some specific features that correspond to a capability.

Original description:
@samuelkarp @mikebrow This is what I cooked up based on some ideas thrown around in the discussions when folks were trying to figure out why a plugin by @micahhausler was not working. It was tracked then down to running against a runtime with too old NRI version for all the necessary bits to be in place. I don't want to push more stuff to this or polish it too much before getting some initial feedback/A-OK/NAK from you guys, to check if this is something we want to push on with for an NRI 1.0, and if it is this way to push on with then...

@klihub klihub requested review from mikebrow and samuelkarp January 20, 2026 14:26
@klihub klihub force-pushed the devel/version-exchange-and-capabilities branch 7 times, most recently from 0d93f22 to fa03208 Compare January 20, 2026 15:04
Copy link
Member

@samuelkarp samuelkarp left a comment

Choose a reason for hiding this comment

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

I'm not entirely sure I understand the value of having both version comparison and capabilities. They both effectively serve the same purpose of understanding compatibility between plugin and runtime, but operate in slightly different ways. I tend to think capabilities are generally a better option in that they're more descriptive of the required functionality and need less manual mapping over time, but I can see some debugging value in exposing version too.

Comment on lines 29 to 36
emit "//go:build nri_git_version"
emit "// Code generated by $0. DO NOT EDIT."
emit ""
emit "package version"
emit ""
emit "const ("
emit " FallbackVersion = \"$version\""
emit ")"
Copy link
Member

Choose a reason for hiding this comment

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

Rather than generating a Go file (which can be a little weird from a compilation perspective, which you're working around with a build-tag...) I think go:embed will work more reliably; we can have this tool generate a plain text file, use //go:embed to read it in a built binary, and have some conditional that determines which value to use.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if that would eliminate the need for conditional compilation. I mean, the conditional compilation is only in place so that we can use a different method to determine the NRI version for plugins which are hosted in the main NRI repository. And the motivation for this is that (it looks to me as if) the golang runtime build info reports "(devel)" for the NRI repository itself, even when we are building from unmodified sources at an exact tag.

So then we have two choices for these plugins. 1) Either we ignore the replacement directive and take the (replaced) NRI version in the plugins' go.mod at face value, or 2) we try some other way to figure out what the NRI version of the repository might be and use that. This PR tried to do the second. Hence the go-generated git-based version detection at compile time and the extra build tag for the repo-hosted plugins to opt in for using that.

But maybe instead of this extra complication for a few sample plugins, we should instead just go with 1) above. Then whatever happens to be in a plugin's go.mod gets advertised as its NRI version.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if that would eliminate the need for conditional compilation.

go:embed wouldn't need to be conditional, though we'd still generate the same $version and store it in a text file. Something like:

package version

//go:embed version.txt
var fallbackVersion string

func FallbackVersion() string {
	if fallbackVersion == "" {
		return UnknownVersion
	}
	return fallbackVersion
}

To be clear I think the approach (2) above is reasonable, but I'd rather use go:embed like here than the build tag approach.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, but the problem with embed is that it is not optional. You cannot seed a string by go:embedding something only if it exists. Only using a bigger fs.FS hammer would allow semantically something equivalent. With a plain version string we also have to commit an empty version.txt to the repository. Otherwise compiling against NRI outside the repo would fail with a missing version.txt.

But then when compiling the repo-hosted plugins, we'd always end up with a dirty repository once we put the git-described NRI repo version in the originally empty file. So without extra logic, we'd never have a repo-hosted plugin reporting a clean NRI version without the .m suffix. Also, without extra logic I think making the repo dirty prior to compilation would break CI, where we verify that we build, run tests, etc. from a clean repo.

So if we go with embedding, then should we try to accommodate for a dirty repo in the affected places (version.txt generation, clean slate CI check), or go with fs.FS and version.txt becoming an embedded file which is present for in-repo compiled plugins but absent for others ? To me the latter then starts to sound more compelling.

Copy link
Member Author

@klihub klihub Jan 22, 2026

Choose a reason for hiding this comment

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

@samuelkarp Okay, I reworked fallback to git version using a simpler go:generator, go:embed:ing, and without using related build tags. I suspect those bits are now as good/simple as they can get.

@klihub
Copy link
Member Author

klihub commented Jan 21, 2026

I'm not entirely sure I understand the value of having both version comparison and capabilities. They both effectively serve the same purpose of understanding compatibility between plugin and runtime, but operate in slightly different ways. I tend to think capabilities are generally a better option in that they're more descriptive of the required functionality and need less manual mapping over time, but I can see some debugging value in exposing version too.

Yes, I'd like to add one more thing for existing runtime versions: supported capability inference based on runtime NRI version. Then as long as a plugin declares required capabilities, we could perform a capability based compatibility check for both old and new runtime versions, either using inferred or reported capabilities.

The PR now does a version check only if a plugin does not declare required capabilities. I added it so that similar cases than what @micahhausler ran into would be flagged as an error of (assumed) incompatibility by default. We can leave it out, and then if a plugin does not declare required capabilities, we don't do any compatibility check either...

@klihub klihub force-pushed the devel/version-exchange-and-capabilities branch 5 times, most recently from 4af55d0 to 1faa2b5 Compare January 22, 2026 13:55
Exchange NRI versions in use during plugin registration. If we
do not get an NRI version from the runtime (too old peer NRI)
try to infer it using the runtime type and version.

The NRI version in use is discovered using the golang runtime
provided build info. For plugins hosted in the main NRI repo
this does not produce any useful result (because NRI is subject
to a replace directive in the plugins' go.mod). Therefore within
the repo we fall back to using a git-describe generated version.

Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
@klihub klihub force-pushed the devel/version-exchange-and-capabilities branch from 1faa2b5 to ec393f2 Compare January 22, 2026 17:53
Introduce an NRI protocol capability enum, add a capability mask
to the protocol and define values for existing NRI features that
were not present in v0.2.0.

Add an option to advertise supported capabilities by the runtime.
Add an option to check required capabilities in the plugin stub.

If the runtime does not advertise capabilities, try to infer it
on the stub side using the runtime name, version, and (inferred
or reported) NRI version.

Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
Add required NRI capabilities to device-injector, ulimit-adjuster
and rdt sample plugins.

Signed-off-by: Krisztian Litkey <krisztian.litkey@intel.com>
@klihub klihub force-pushed the devel/version-exchange-and-capabilities branch from ec393f2 to 1a28e8a Compare January 22, 2026 18:08
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