From 1ebf29821b1338d19836a934e4b4f89582903df3 Mon Sep 17 00:00:00 2001
From: Evan Lezar <elezar@nvidia.com>
Date: Tue, 28 May 2024 14:32:26 +0200
Subject: [PATCH] Remove the ToOCI functions from the specs-go package

This change removes the ToOCI functions from the specs-go package.
They are implemented as private toOCI functions in the cdi package instead.
This means that there is no dependency on the OCI runtime spec for clients that
only need a CDI spec definition.

Signed-off-by: Evan Lezar <elezar@nvidia.com>
---
 pkg/cdi/container-edits.go | 34 ++++++++++++-----
 pkg/cdi/oci.go             | 65 ++++++++++++++++++++++++++++++++
 specs-go/go.mod            |  2 -
 specs-go/go.sum            |  2 -
 specs-go/oci.go            | 77 +++++++++++++++++++++-----------------
 5 files changed, 131 insertions(+), 49 deletions(-)
 create mode 100644 pkg/cdi/oci.go

diff --git a/pkg/cdi/container-edits.go b/pkg/cdi/container-edits.go
index e5b50db1..70791666 100644
--- a/pkg/cdi/container-edits.go
+++ b/pkg/cdi/container-edits.go
@@ -89,7 +89,7 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
 		if err != nil {
 			return err
 		}
-		dev := d.ToOCI()
+		dev := dn.toOCI()
 		if dev.UID == nil && spec.Process != nil {
 			if uid := spec.Process.User.UID; uid > 0 {
 				dev.UID = &uid
@@ -116,29 +116,30 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
 	if len(e.Mounts) > 0 {
 		for _, m := range e.Mounts {
 			specgen.RemoveMount(m.ContainerPath)
-			specgen.AddMount(m.ToOCI())
+			specgen.AddMount((&Mount{m}).toOCI())
 		}
 		sortMounts(&specgen)
 	}
 
 	for _, h := range e.Hooks {
+		ociHook := (&Hook{h}).toOCI()
 		switch h.HookName {
 		case PrestartHook:
-			specgen.AddPreStartHook(h.ToOCI())
+			specgen.AddPreStartHook(ociHook)
 		case PoststartHook:
-			specgen.AddPostStartHook(h.ToOCI())
+			specgen.AddPostStartHook(ociHook)
 		case PoststopHook:
-			specgen.AddPostStopHook(h.ToOCI())
+			specgen.AddPostStopHook(ociHook)
 			// TODO: Maybe runtime-tools/generate should be updated with these...
 		case CreateRuntimeHook:
 			ensureOCIHooks(spec)
-			spec.Hooks.CreateRuntime = append(spec.Hooks.CreateRuntime, h.ToOCI())
+			spec.Hooks.CreateRuntime = append(spec.Hooks.CreateRuntime, ociHook)
 		case CreateContainerHook:
 			ensureOCIHooks(spec)
-			spec.Hooks.CreateContainer = append(spec.Hooks.CreateContainer, h.ToOCI())
+			spec.Hooks.CreateContainer = append(spec.Hooks.CreateContainer, ociHook)
 		case StartContainerHook:
 			ensureOCIHooks(spec)
-			spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, h.ToOCI())
+			spec.Hooks.StartContainer = append(spec.Hooks.StartContainer, ociHook)
 		default:
 			return fmt.Errorf("unknown hook name %q", h.HookName)
 		}
@@ -148,7 +149,7 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error {
 		// The specgen is missing functionality to set all parameters so we
 		// just piggy-back on it to initialize all structs and the copy over.
 		specgen.SetLinuxIntelRdtClosID(e.IntelRdt.ClosID)
-		spec.Linux.IntelRdt = e.IntelRdt.ToOCI()
+		spec.Linux.IntelRdt = (&IntelRdt{e.IntelRdt}).toOCI()
 	}
 
 	for _, additionalGID := range e.AdditionalGIDs {
@@ -186,7 +187,7 @@ func (e *ContainerEdits) Validate() error {
 		}
 	}
 	if e.IntelRdt != nil {
-		if err := ValidateIntelRdt(e.IntelRdt); err != nil {
+		if err := (&IntelRdt{e.IntelRdt}).Validate(); err != nil {
 			return err
 		}
 	}
@@ -321,8 +322,21 @@ func (m *Mount) Validate() error {
 	return nil
 }
 
+// IntelRdt is a CDI IntelRdt wrapper.
+// This is used for validation and conversion to OCI specifications.
+type IntelRdt struct {
+	*specs.IntelRdt
+}
+
 // ValidateIntelRdt validates the IntelRdt configuration.
+//
+// Deprecated: ValidateIntelRdt is deprecated use IntelRdt.Validate() instead.
 func ValidateIntelRdt(i *specs.IntelRdt) error {
+	return (&IntelRdt{i}).Validate()
+}
+
+// Validate validates the IntelRdt configuration.
+func (i *IntelRdt) Validate() error {
 	// ClosID must be a valid Linux filename
 	if len(i.ClosID) >= 4096 || i.ClosID == "." || i.ClosID == ".." || strings.ContainsAny(i.ClosID, "/\n") {
 		return errors.New("invalid ClosID")
diff --git a/pkg/cdi/oci.go b/pkg/cdi/oci.go
new file mode 100644
index 00000000..4d62c41f
--- /dev/null
+++ b/pkg/cdi/oci.go
@@ -0,0 +1,65 @@
+/*
+Copyright © 2021 The CDI Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package cdi
+
+import (
+	spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
+// toOCI returns the opencontainers runtime Spec Hook for this Hook.
+func (h *Hook) toOCI() spec.Hook {
+	return spec.Hook{
+		Path:    h.Path,
+		Args:    h.Args,
+		Env:     h.Env,
+		Timeout: h.Timeout,
+	}
+}
+
+// toOCI returns the opencontainers runtime Spec Mount for this Mount.
+func (m *Mount) toOCI() spec.Mount {
+	return spec.Mount{
+		Source:      m.HostPath,
+		Destination: m.ContainerPath,
+		Options:     m.Options,
+		Type:        m.Type,
+	}
+}
+
+// toOCI returns the opencontainers runtime Spec LinuxDevice for this DeviceNode.
+func (d *DeviceNode) toOCI() spec.LinuxDevice {
+	return spec.LinuxDevice{
+		Path:     d.Path,
+		Type:     d.Type,
+		Major:    d.Major,
+		Minor:    d.Minor,
+		FileMode: d.FileMode,
+		UID:      d.UID,
+		GID:      d.GID,
+	}
+}
+
+// toOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config.
+func (i *IntelRdt) toOCI() *spec.LinuxIntelRdt {
+	return &spec.LinuxIntelRdt{
+		ClosID:        i.ClosID,
+		L3CacheSchema: i.L3CacheSchema,
+		MemBwSchema:   i.MemBwSchema,
+		EnableCMT:     i.EnableCMT,
+		EnableMBM:     i.EnableMBM,
+	}
+}
diff --git a/specs-go/go.mod b/specs-go/go.mod
index ad8f36b3..9b19b9ef 100644
--- a/specs-go/go.mod
+++ b/specs-go/go.mod
@@ -1,5 +1,3 @@
 module tags.cncf.io/container-device-interface/specs-go
 
 go 1.19
-
-require github.com/opencontainers/runtime-spec v1.1.0
diff --git a/specs-go/go.sum b/specs-go/go.sum
index 7ccea55c..e69de29b 100644
--- a/specs-go/go.sum
+++ b/specs-go/go.sum
@@ -1,2 +0,0 @@
-github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
-github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
diff --git a/specs-go/oci.go b/specs-go/oci.go
index 1b4d576b..ce485cb2 100644
--- a/specs-go/oci.go
+++ b/specs-go/oci.go
@@ -1,49 +1,56 @@
+/*
+Copyright © 2021 The CDI Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 package specs
 
-import (
-	spec "github.com/opencontainers/runtime-spec/specs-go"
-)
+import "errors"
+
+// errDeprecated is returned for the ToOCI functions below.
+// This should provide better guidance for user when migrating from the API
+// below to the APIs provided in the cdi package.
+var errDeprecated = errors.New("deprecated; Use cdi package functions instead")
 
 // ToOCI returns the opencontainers runtime Spec Hook for this Hook.
-func (h *Hook) ToOCI() spec.Hook {
-	return spec.Hook{
-		Path:    h.Path,
-		Args:    h.Args,
-		Env:     h.Env,
-		Timeout: h.Timeout,
-	}
+//
+// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.Hook.toOCI
+// and made private.
+func (h *Hook) ToOCI() error {
+	return errDeprecated
 }
 
 // ToOCI returns the opencontainers runtime Spec Mount for this Mount.
-func (m *Mount) ToOCI() spec.Mount {
-	return spec.Mount{
-		Source:      m.HostPath,
-		Destination: m.ContainerPath,
-		Options:     m.Options,
-		Type:        m.Type,
-	}
+//
+// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.Mount.toOCI
+// and made private.
+func (m *Mount) ToOCI() error {
+	return errDeprecated
 }
 
 // ToOCI returns the opencontainers runtime Spec LinuxDevice for this DeviceNode.
-func (d *DeviceNode) ToOCI() spec.LinuxDevice {
-	return spec.LinuxDevice{
-		Path:     d.Path,
-		Type:     d.Type,
-		Major:    d.Major,
-		Minor:    d.Minor,
-		FileMode: d.FileMode,
-		UID:      d.UID,
-		GID:      d.GID,
-	}
+//
+// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.DeviceNode.toOCI
+// and made private.
+func (d *DeviceNode) ToOCI() error {
+	return errDeprecated
 }
 
 // ToOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config.
-func (i *IntelRdt) ToOCI() *spec.LinuxIntelRdt {
-	return &spec.LinuxIntelRdt{
-		ClosID:        i.ClosID,
-		L3CacheSchema: i.L3CacheSchema,
-		MemBwSchema:   i.MemBwSchema,
-		EnableCMT:     i.EnableCMT,
-		EnableMBM:     i.EnableMBM,
-	}
+//
+// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.IntelRdt.toOCI
+// and made private.
+func (i *IntelRdt) ToOCI() error {
+	return errDeprecated
 }