Skip to content

Commit 5a781dd

Browse files
committed
Remove dependency on github.com/opencontainers/runtime-tools
The `generate` package was used in two places purely as a convenience wrapper over `*oci.Spec` field mutations -- none of its logic was load-bearing. Replace it with direct spec manipulation throughout. In `pkg/cdi/container-edits.go`, drop the `ocigen.Generator` value and operate on `*oci.Spec` directly in `Apply`. Extract small private helpers for the operations that have non-trivial logic: `addMultipleProcessEnv` (deduplicates by key), `removeDevice` and `removeMount` (find-and-splice), and `addProcessAdditionalGid` (append-if-absent). In `cmd/cdi/cmd/cdi-api.go`, replace the three-step `gen.NewFromSpec` / `ClearLinuxDevices` / `AddDevice` sequence in `collectCDIDevicesFromOCISpec` with a single partition loop over `spec.Linux.Devices`. Assisted-By: "claude my eyes right out"
1 parent 35765bd commit 5a781dd

4 files changed

Lines changed: 96 additions & 74 deletions

File tree

cmd/cdi/cmd/cdi-api.go

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"strings"
2424

2525
oci "github.com/opencontainers/runtime-spec/specs-go"
26-
gen "github.com/opencontainers/runtime-tools/generate"
2726
"tags.cncf.io/container-device-interface/pkg/cdi"
2827
"tags.cncf.io/container-device-interface/pkg/parser"
2928
)
@@ -218,25 +217,22 @@ func cdiResolveDevices(ociSpecFiles ...string) error {
218217
}
219218

220219
func collectCDIDevicesFromOCISpec(spec *oci.Spec) []string {
221-
var (
222-
cdiDevs []string
223-
)
224-
225220
if spec.Linux == nil || len(spec.Linux.Devices) == 0 {
226221
return nil
227222
}
228223

229-
devices := spec.Linux.Devices
230-
g := gen.NewFromSpec(spec)
231-
g.ClearLinuxDevices()
232-
233-
for _, d := range devices {
224+
var (
225+
cdiDevs []string
226+
kept []oci.LinuxDevice
227+
)
228+
for _, d := range spec.Linux.Devices {
234229
if !parser.IsQualifiedName(d.Path) {
235-
g.AddDevice(d)
230+
kept = append(kept, d)
236231
continue
237232
}
238233
cdiDevs = append(cdiDevs, d.Path)
239234
}
235+
spec.Linux.Devices = kept
240236

241237
return cdiDevs
242238
}

go.mod

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go 1.21
55
require (
66
github.com/fsnotify/fsnotify v1.5.1
77
github.com/opencontainers/runtime-spec v1.3.0
8-
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116
98
github.com/stretchr/testify v1.7.0
109
golang.org/x/sys v0.19.0
1110
gopkg.in/yaml.v3 v3.0.1
@@ -15,8 +14,6 @@ require (
1514

1615
require (
1716
github.com/davecgh/go-spew v1.1.1 // indirect
18-
github.com/moby/sys/capability v0.4.0 // indirect
19-
github.com/opencontainers/selinux v1.10.0 // indirect
2017
github.com/pmezard/go-difflib v1.0.0 // indirect
2118
golang.org/x/mod v0.19.0 // indirect
2219
)

go.sum

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,19 @@
1-
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
2-
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
31
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
42
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
53
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
64
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
75
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
86
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
97
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
10-
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
11-
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
12-
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
13-
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
14-
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
15-
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
168
github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=
179
github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
18-
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116 h1:tAKu3NkKWZYpqBSOJKwTxT1wIGueiF7gcmcNgr5pNTY=
19-
github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116/go.mod h1:DKDEfzxvRkoQ6n9TGhxQgg2IM1lY4aM0eaQP4e3oElw=
20-
github.com/opencontainers/selinux v1.10.0 h1:rAiKF8hTcgLI3w0DHm6i0ylVVcOrlgR1kK99DRLDhyU=
21-
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
2210
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2311
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
24-
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
25-
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
2612
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
2713
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
2814
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
29-
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
30-
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
31-
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
32-
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
33-
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
34-
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
3515
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
3616
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
37-
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
3817
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3918
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
4019
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

pkg/cdi/container-edits.go

Lines changed: 89 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"strings"
2626

2727
oci "github.com/opencontainers/runtime-spec/specs-go"
28-
ocigen "github.com/opencontainers/runtime-tools/generate"
2928
cdi "tags.cncf.io/container-device-interface/specs-go"
3029
)
3130

@@ -80,9 +79,11 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
8079
return nil
8180
}
8281

83-
specgen := ocigen.NewFromSpec(spec)
8482
if len(e.Env) > 0 {
85-
specgen.AddMultipleProcessEnv(e.Env)
83+
if spec.Process == nil {
84+
spec.Process = &oci.Process{}
85+
}
86+
addMultipleProcessEnv(spec.Process, e.Env)
8687
}
8788

8889
for _, d := range e.DeviceNodes {
@@ -104,8 +105,11 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
104105
}
105106
}
106107

107-
specgen.RemoveDevice(dev.Path)
108-
specgen.AddDevice(dev)
108+
if spec.Linux == nil {
109+
spec.Linux = &oci.Linux{}
110+
}
111+
removeDevice(spec, dev.Path)
112+
spec.Linux.Devices = append(spec.Linux.Devices, dev)
109113

110114
if dev.Type == "b" || dev.Type == "c" {
111115
access := d.Permissions
@@ -115,80 +119,134 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
115119
case NoPermissions:
116120
access = ""
117121
}
118-
specgen.AddLinuxResourcesDevice(true, dev.Type, &dev.Major, &dev.Minor, access)
122+
if spec.Linux.Resources == nil {
123+
spec.Linux.Resources = &oci.LinuxResources{}
124+
}
125+
spec.Linux.Resources.Devices = append(spec.Linux.Resources.Devices, oci.LinuxDeviceCgroup{
126+
Allow: true,
127+
Type: dev.Type,
128+
Major: &dev.Major,
129+
Minor: &dev.Minor,
130+
Access: access,
131+
})
119132
}
120133
}
121134

122-
if len(e.NetDevices) > 0 {
123-
// specgen is currently missing functionality to set Linux NetDevices,
124-
// so we use a locally rolled function for now.
125-
for _, dev := range e.NetDevices {
126-
specgenAddLinuxNetDevice(&specgen, dev.HostInterfaceName, (&LinuxNetDevice{dev}).toOCI())
127-
}
135+
for _, dev := range e.NetDevices {
136+
ensureLinuxNetDevices(spec)
137+
spec.Linux.NetDevices[dev.HostInterfaceName] = *(&LinuxNetDevice{dev}).toOCI()
128138
}
129139

130140
if len(e.Mounts) > 0 {
131141
for _, m := range e.Mounts {
132142
mnt := &Mount{m}
133143

134-
specgen.RemoveMount(m.ContainerPath)
144+
removeMount(spec, m.ContainerPath)
135145

136146
if !specHasUserNamespace(spec) {
137-
specgen.AddMount(mnt.toOCI())
147+
spec.Mounts = append(spec.Mounts, mnt.toOCI())
138148
} else {
139-
specgen.AddMount(mnt.toOCI(withIDMapForBindMount()))
149+
spec.Mounts = append(spec.Mounts, mnt.toOCI(withIDMapForBindMount()))
140150
}
141151
}
142-
sortMounts(&specgen)
152+
sort.Stable(orderedMounts(spec.Mounts))
143153
}
144154

145155
for _, h := range e.Hooks {
146156
ociHook := (&Hook{h}).toOCI()
157+
ensureOCIHooks(spec)
147158
switch h.HookName {
148159
case PrestartHook:
149-
specgen.AddPreStartHook(ociHook)
160+
spec.Hooks.Prestart = append(spec.Hooks.Prestart, ociHook) //nolint:staticcheck
150161
case PoststartHook:
151-
specgen.AddPostStartHook(ociHook)
162+
spec.Hooks.Poststart = append(spec.Hooks.Poststart, ociHook)
152163
case PoststopHook:
153-
specgen.AddPostStopHook(ociHook)
154-
// TODO: Maybe runtime-tools/generate should be updated with these...
164+
spec.Hooks.Poststop = append(spec.Hooks.Poststop, ociHook)
155165
case CreateRuntimeHook:
156-
ensureOCIHooks(spec)
157166
spec.Hooks.CreateRuntime = append(spec.Hooks.CreateRuntime, ociHook)
158167
case CreateContainerHook:
159-
ensureOCIHooks(spec)
160168
spec.Hooks.CreateContainer = append(spec.Hooks.CreateContainer, ociHook)
161169
case StartContainerHook:
162-
ensureOCIHooks(spec)
163170
spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, ociHook)
164171
default:
165172
return fmt.Errorf("unknown hook name %q", h.HookName)
166173
}
167174
}
168175

169176
if e.IntelRdt != nil {
170-
// The specgen is missing functionality to set all parameters so we
171-
// just piggy-back on it to initialize all structs and the copy over.
172-
specgen.SetLinuxIntelRdtClosID(e.IntelRdt.ClosID)
177+
if spec.Linux == nil {
178+
spec.Linux = &oci.Linux{}
179+
}
173180
spec.Linux.IntelRdt = (&IntelRdt{e.IntelRdt}).toOCI()
174181
}
175182

176183
for _, additionalGID := range e.AdditionalGIDs {
177184
if additionalGID == 0 {
178185
continue
179186
}
180-
specgen.AddProcessAdditionalGid(additionalGID)
187+
if spec.Process == nil {
188+
spec.Process = &oci.Process{}
189+
}
190+
addProcessAdditionalGid(spec, additionalGID)
181191
}
182192

183193
return nil
184194
}
185195

186-
func specgenAddLinuxNetDevice(specgen *ocigen.Generator, hostIf string, netDev *oci.LinuxNetDevice) {
187-
if specgen == nil || netDev == nil {
196+
// addMultipleProcessEnv adds or replaces environment variables on the process,
197+
// deduplicating by key.
198+
func addMultipleProcessEnv(process *oci.Process, envs []string) {
199+
for _, env := range envs {
200+
parts := strings.SplitN(env, "=", 2)
201+
if len(parts) < 2 {
202+
continue
203+
}
204+
prefix := parts[0] + "="
205+
replaced := false
206+
for i, e := range process.Env {
207+
if strings.HasPrefix(e, prefix) {
208+
process.Env[i] = env
209+
replaced = true
210+
break
211+
}
212+
}
213+
if !replaced {
214+
process.Env = append(process.Env, env)
215+
}
216+
}
217+
}
218+
219+
// removeDevice removes the device at path from spec.Linux.Devices.
220+
func removeDevice(spec *oci.Spec, path string) {
221+
if spec.Linux == nil {
188222
return
189223
}
190-
ensureLinuxNetDevices(specgen.Config)
191-
specgen.Config.Linux.NetDevices[hostIf] = *netDev
224+
for i, d := range spec.Linux.Devices {
225+
if d.Path == path {
226+
spec.Linux.Devices = append(spec.Linux.Devices[:i], spec.Linux.Devices[i+1:]...)
227+
return
228+
}
229+
}
230+
}
231+
232+
// removeMount removes the mount with the given destination from spec.Mounts.
233+
func removeMount(spec *oci.Spec, dest string) {
234+
for i, m := range spec.Mounts {
235+
if m.Destination == dest {
236+
spec.Mounts = append(spec.Mounts[:i], spec.Mounts[i+1:]...)
237+
return
238+
}
239+
}
240+
}
241+
242+
// addProcessAdditionalGid appends gid to spec.Process.User.AdditionalGids if not already present.
243+
func addProcessAdditionalGid(spec *oci.Spec, gid uint32) {
244+
for _, g := range spec.Process.User.AdditionalGids {
245+
if g == gid {
246+
return
247+
}
248+
}
249+
spec.Process.User.AdditionalGids = append(spec.Process.User.AdditionalGids, gid)
192250
}
193251

194252
// Ensure OCI Spec Linux NetDevices map is not nil.
@@ -444,14 +502,6 @@ func ensureOCIHooks(spec *oci.Spec) {
444502
}
445503
}
446504

447-
// sortMounts sorts the mounts in the given OCI Spec.
448-
func sortMounts(specgen *ocigen.Generator) {
449-
mounts := specgen.Mounts()
450-
specgen.ClearMounts()
451-
sort.Stable(orderedMounts(mounts))
452-
specgen.Config.Mounts = mounts
453-
}
454-
455505
// orderedMounts defines how to sort an OCI Spec Mount slice.
456506
// This is the almost the same implementation sa used by CRI-O and Docker,
457507
// with a minor tweak for stable sorting order (easier to test):

0 commit comments

Comments
 (0)