Skip to content

cdi: add resolved edits API#322

Open
ebendler wants to merge 1 commit into
cncf-tags:mainfrom
ebendler:edits_api
Open

cdi: add resolved edits API#322
ebendler wants to merge 1 commit into
cncf-tags:mainfrom
ebendler:edits_api

Conversation

@ebendler

Copy link
Copy Markdown

The idea here is that some CDI consumers may not be operating on an OCI container (think sandbox wrappers), but it would be silly to have them all re-implement the code that maps the specfile to the running host when the reference implementations are already doing all of that work.

See also: cncf-tags/container-device-interface-rs#101

@zvonkok
zvonkok requested review from Copilot and klihub and removed request for klihub July 15, 2026 17:58

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread pkg/cdi/resolved-edits.go Outdated
Comment thread pkg/cdi/resolved-edits.go Outdated
@ebendler

Copy link
Copy Markdown
Author

Thanks, @klihub — your comments made the result API clearer. I’ve updated the resolved device-node and mount outputs to embed the effective CDI types with scope metadata, and added coverage for the FIFO zero-value convention.

Comment thread pkg/cdi/resolved-edits.go Outdated
import cdi "tags.cncf.io/container-device-interface/specs-go"

// ResolvedEdits contains CDI edits resolved without applying OCI semantics.
type ResolvedEdits struct {

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.

My first thought here is why we need a new type and can't just return the appended ContainerEdits? I'm not saying that distinguishing between supported and unsupported edits is not useful, but I would argue that this is something that the CLIENT must decide and not be hard-coded into the CDI API implementation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I think the new version is more what you had in mind?

Signed-off-by: Ehren Bendler <ebendler@nvidia.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 6 out of 6 changed files in this pull request and generated 1 comment.

Comment thread pkg/cdi/cache.go
Comment on lines +258 to +281
func (c *Cache) ResolveEdits(devices ...string) (*ContainerEdits, error) {
c.Lock()
defer c.Unlock()

if _, err := c.refreshIfRequired(false); err != nil {
return nil, err
}

selected, unresolved := c.collectContainerEdits(devices)
if len(unresolved) > 0 {
return nil, fmt.Errorf("unresolvable CDI devices %s", strings.Join(unresolved, ", "))
}

resolved := cloneContainerEdits(nil)
for _, entry := range selected {
copy := cloneContainerEdits(entry)
if err := copy.resolveDeviceNodes(); err != nil {
return nil, err
}
resolved.Append(copy)
}

return resolved, nil
}

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.

We could decide whether we want to release the lock after we have cloned the collected ContainerEdits.

Comment thread pkg/cdi/cache.go

// ResolveEdits resolves the given qualified devices to their effective CDI
// edits without applying OCI conversion or mutating an OCI Spec.
func (c *Cache) ResolveEdits(devices ...string) (*ContainerEdits, error) {

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.

Question: Should this return a cdi.ContainerEdits type instead?

Comment thread pkg/cdi/cache.go
Comment on lines +271 to +278
resolved := cloneContainerEdits(nil)
for _, entry := range selected {
copy := cloneContainerEdits(entry)
if err := copy.resolveDeviceNodes(); err != nil {
return nil, err
}
resolved.Append(copy)
}

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.

Instead of manually implementing clone functions that would need to be updated for every added non-value field, what about constructing a copy by marshalling to JSON and then unmarshalling again?

Comment thread pkg/cdi/cache.go
Comment on lines +266 to +278
selected, unresolved := c.collectContainerEdits(devices)
if len(unresolved) > 0 {
return nil, fmt.Errorf("unresolvable CDI devices %s", strings.Join(unresolved, ", "))
}

resolved := cloneContainerEdits(nil)
for _, entry := range selected {
copy := cloneContainerEdits(entry)
if err := copy.resolveDeviceNodes(); err != nil {
return nil, err
}
resolved.Append(copy)
}

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.

What about:

  1. call collectContainerEdits
  2. Use the same flow to construct a single ContainerEdits that we use in InjectDevices
  3. Marshal the collected edits to JSON.
  4. Unmarshal the selected edits.
  5. Fill missing info for included device nodes.

This also seems to indicate that collectContainerEdits should be:

func (c *Cache) collectContainerEdits(devices []string) (*ContainerEdits, error) {
	...
}

and include its current content as well as unresolved error handling and looping over the resolved edits.

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.

4 participants