Add stub to build common OCI spec

Signed-off-by: Maksym Pavlenko <pavlenko.maksym@gmail.com>
This commit is contained in:
Maksym Pavlenko 2023-01-08 19:25:03 -08:00
parent f318e5630b
commit 21338d2777
7 changed files with 121 additions and 43 deletions

View File

@ -23,23 +23,24 @@ import (
"path/filepath"
"time"
"github.com/containerd/typeurl"
"github.com/davecgh/go-spew/spew"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/containerd"
"github.com/containerd/containerd/api/types"
"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/log"
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/pkg/cri/config"
criconfig "github.com/containerd/containerd/pkg/cri/config"
cio "github.com/containerd/containerd/pkg/cri/io"
customopts "github.com/containerd/containerd/pkg/cri/opts"
containerstore "github.com/containerd/containerd/pkg/cri/store/container"
"github.com/containerd/containerd/pkg/cri/util"
ctrdutil "github.com/containerd/containerd/pkg/cri/util"
"github.com/containerd/typeurl"
"github.com/davecgh/go-spew/spew"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
)
func init() {
@ -161,8 +162,25 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
}
log.G(ctx).Debugf("Use OCI runtime %+v for sandbox %q and container %q", ociRuntime, sandboxID, id)
spec, err := c.containerSpec(id, sandboxID, sandboxPid, sandbox.NetNSPath, containerName, containerdImage.Name(), config, sandboxConfig,
&image.ImageSpec.Config, append(mounts, volumeMounts...), ociRuntime)
platform, err := controller.Platform(ctx, sandboxID)
if err != nil {
return nil, fmt.Errorf("failed to query sandbox platform: %w", err)
}
spec, err := c.buildContainerSpec(
platform,
id,
sandboxID,
sandboxPid,
sandbox.NetNSPath,
containerName,
containerdImage.Name(),
config,
sandboxConfig,
&image.ImageSpec.Config,
append(mounts, volumeMounts...),
ociRuntime,
)
if err != nil {
return nil, fmt.Errorf("failed to generate container %q spec: %w", id, err)
}
@ -375,3 +393,57 @@ func (c *criService) runtimeSnapshotter(ctx context.Context, ociRuntime criconfi
log.G(ctx).Debugf("Set snapshotter for runtime %s to %s", ociRuntime.Type, ociRuntime.Snapshotter)
return ociRuntime.Snapshotter
}
// buildContainerSpec build container's OCI spec depending on controller's target platform OS.
func (c *criService) buildContainerSpec(
platform *types.Platform,
id string,
sandboxID string,
sandboxPid uint32,
netNSPath string,
containerName string,
imageName string,
config *runtime.ContainerConfig,
sandboxConfig *runtime.PodSandboxConfig,
imageConfig *imagespec.ImageConfig,
extraMounts []*runtime.Mount,
ociRuntime config.Runtime,
) (_ *runtimespec.Spec, retErr error) {
var (
specOpts []oci.SpecOpts
isLinux = platform.OS == "linux"
)
if isLinux {
specOpts = append(specOpts, oci.WithoutRunMount)
// Only clear the default security settings if the runtime does not have a custom
// base runtime spec. Admins can use this functionality to define
// default ulimits, seccomp, or other default settings.
if ociRuntime.BaseRuntimeSpec == "" {
specOpts = append(specOpts, customopts.WithoutDefaultSecuritySettings)
}
}
// Get spec opts that depend on features offered by the platform containerd daemon is running on.
platformSpecOpts, err := c.platformSpec(
id,
sandboxID,
sandboxPid,
netNSPath,
containerName,
imageName,
config,
sandboxConfig,
imageConfig,
extraMounts,
ociRuntime,
)
if err != nil {
return nil, err
}
specOpts = append(specOpts, platformSpecOpts...)
return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec, specOpts...)
}

View File

@ -113,7 +113,7 @@ func (c *criService) containerMounts(sandboxID string, config *runtime.Container
return mounts
}
func (c *criService) containerSpec(
func (c *criService) platformSpec(
id string,
sandboxID string,
sandboxPid uint32,
@ -125,7 +125,7 @@ func (c *criService) containerSpec(
imageConfig *imagespec.ImageConfig,
extraMounts []*runtime.Mount,
ociRuntime config.Runtime,
) (_ *runtimespec.Spec, retErr error) {
) (_ []oci.SpecOpts, retErr error) {
specOpts := []oci.SpecOpts{
oci.WithoutRunMount,
}
@ -334,7 +334,8 @@ func (c *criService) containerSpec(
Type: runtimespec.CgroupNamespace,
}))
}
return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec, specOpts...)
return specOpts, nil
}
func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) {

View File

@ -248,7 +248,7 @@ func TestContainerCapabilities(t *testing.T) {
c.allCaps = allCaps
containerConfig.Linux.SecurityContext.Capabilities = test.capability
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
if selinux.GetEnabled() {
@ -283,7 +283,7 @@ func TestContainerSpecTty(t *testing.T) {
c := newTestCRIService()
for _, tty := range []bool{true, false} {
containerConfig.Tty = tty
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
assert.Equal(t, tty, spec.Process.Terminal)
@ -310,7 +310,7 @@ func TestContainerSpecDefaultPath(t *testing.T) {
imageConfig.Env = append(imageConfig.Env, pathenv)
expected = pathenv
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
assert.Contains(t, spec.Process.Env, expected)
@ -327,7 +327,7 @@ func TestContainerSpecReadonlyRootfs(t *testing.T) {
c := newTestCRIService()
for _, readonly := range []bool{true, false} {
containerConfig.Linux.SecurityContext.ReadonlyRootfs = readonly
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
assert.Equal(t, readonly, spec.Root.Readonly)
@ -366,7 +366,7 @@ func TestContainerSpecWithExtraMounts(t *testing.T) {
Readonly: false,
},
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, extraMounts, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, extraMounts, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
var mounts, sysMounts, devMounts []runtimespec.Mount
@ -434,7 +434,7 @@ func TestContainerAndSandboxPrivileged(t *testing.T) {
sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
Privileged: test.sandboxPrivileged,
}
_, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
_, err := c.platformSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
if test.expectError {
assert.Error(t, err)
} else {
@ -638,7 +638,7 @@ func TestPrivilegedBindMount(t *testing.T) {
containerConfig.Linux.SecurityContext.Privileged = test.privileged
sandboxConfig.Linux.SecurityContext.Privileged = test.privileged
spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
if test.expectedSysFSRO {
@ -797,7 +797,7 @@ func TestPidNamespace(t *testing.T) {
} {
t.Run(desc, func(t *testing.T) {
containerConfig.Linux.SecurityContext.NamespaceOptions = &runtime.NamespaceOption{Pid: test.pidNS}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
assert.Contains(t, spec.Linux.Namespaces, test.expected)
})
@ -813,7 +813,7 @@ func TestNoDefaultRunMount(t *testing.T) {
ociRuntime := config.Runtime{}
c := newTestCRIService()
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
for _, mount := range spec.Mounts {
assert.NotEqual(t, "/run", mount.Destination)
@ -1187,7 +1187,7 @@ func TestMaskedAndReadonlyPaths(t *testing.T) {
sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
Privileged: test.privileged,
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
if !test.privileged { // specCheck presumes an unprivileged container
specCheck(t, testID, testSandboxID, testPid, spec)
@ -1235,7 +1235,7 @@ func TestHostname(t *testing.T) {
sandboxConfig.Linux.SecurityContext = &runtime.LinuxSandboxSecurityContext{
NamespaceOptions: &runtime.NamespaceOption{Network: test.networkNs},
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
assert.Contains(t, spec.Process.Env, test.expectedEnv)
@ -1248,7 +1248,7 @@ func TestDisableCgroup(t *testing.T) {
ociRuntime := config.Runtime{}
c := newTestCRIService()
c.config.DisableCgroup = true
spec, err := c.containerSpec("test-id", "sandbox-id", 1234, "", "container-name", testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, "test-id", "sandbox-id", 1234, "", "container-name", testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
t.Log("resource limit should not be set")
@ -1387,7 +1387,7 @@ func TestNonRootUserAndDevices(t *testing.T) {
},
}
spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
spec, err := c.buildContainerSpec(linuxPlatform, t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
assert.NoError(t, err)
assert.Equal(t, test.expectedDeviceUID, *spec.Linux.Devices[0].UID)
@ -1454,7 +1454,7 @@ func TestPrivilegedDevices(t *testing.T) {
PrivilegedWithoutHostDevices: test.privilegedWithoutHostDevices,
PrivilegedWithoutHostDevicesAllDevicesAllowed: test.privilegedWithoutHostDevicesAllDevicesAllowed,
}
spec, err := c.containerSpec(t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, t.Name(), testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
hostDevicesRaw, err := oci.HostDevices()
@ -1508,7 +1508,7 @@ func TestBaseOCISpec(t *testing.T) {
testPid := uint32(1234)
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
@ -1642,7 +1642,7 @@ containerEdits:
},
} {
t.Run(test.description, func(t *testing.T) {
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)

View File

@ -22,7 +22,6 @@ import (
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/snapshots"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/containerd/pkg/cri/config"
@ -34,7 +33,7 @@ func (c *criService) containerMounts(sandboxID string, config *runtime.Container
return []*runtime.Mount{}
}
func (c *criService) containerSpec(
func (c *criService) platformSpec(
id string,
sandboxID string,
sandboxPid uint32,
@ -46,8 +45,8 @@ func (c *criService) containerSpec(
imageConfig *imagespec.ImageConfig,
extraMounts []*runtime.Mount,
ociRuntime config.Runtime,
) (_ *runtimespec.Spec, retErr error) {
return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec)
) ([]oci.SpecOpts, error) {
return []oci.SpecOpts{}, nil
}
func (c *criService) containerSpecOpts(config *runtime.ContainerConfig, imageConfig *imagespec.ImageConfig) ([]oci.SpecOpts, error) {

View File

@ -22,6 +22,7 @@ import (
goruntime "runtime"
"testing"
"github.com/containerd/containerd/api/types"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
@ -34,6 +35,8 @@ import (
"github.com/containerd/containerd/pkg/cri/opts"
)
var linuxPlatform = &types.Platform{OS: "linux"}
func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string,
contains, notcontains []string) {
found := false
@ -63,7 +66,7 @@ func TestGeneralContainerSpec(t *testing.T) {
c := newTestCRIService()
testSandboxID := "sandbox-id"
testContainerName := "container-name"
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
require.NoError(t, err)
specCheck(t, testID, testSandboxID, testPid, spec)
}
@ -134,7 +137,7 @@ func TestPodAnnotationPassthroughContainerSpec(t *testing.T) {
ociRuntime := config.Runtime{
PodAnnotations: test.podAnnotations,
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName,
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName,
containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
assert.NotNil(t, spec)
@ -391,7 +394,7 @@ func TestContainerAnnotationPassthroughContainerSpec(t *testing.T) {
PodAnnotations: test.podAnnotations,
ContainerAnnotations: test.containerAnnotations,
}
spec, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName,
spec, err := c.buildContainerSpec(linuxPlatform, testID, testSandboxID, testPid, "", testContainerName, testImageName,
containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
assert.NoError(t, err)
assert.NotNil(t, spec)

View File

@ -24,7 +24,6 @@ import (
"github.com/containerd/containerd/oci"
"github.com/containerd/containerd/snapshots"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
runtime "k8s.io/cri-api/pkg/apis/runtime/v1"
"github.com/containerd/containerd/pkg/cri/annotations"
@ -37,7 +36,7 @@ func (c *criService) containerMounts(sandboxID string, config *runtime.Container
return nil
}
func (c *criService) containerSpec(
func (c *criService) platformSpec(
id string,
sandboxID string,
sandboxPid uint32,
@ -49,7 +48,7 @@ func (c *criService) containerSpec(
imageConfig *imagespec.ImageConfig,
extraMounts []*runtime.Mount,
ociRuntime config.Runtime,
) (*runtimespec.Spec, error) {
) ([]oci.SpecOpts, error) {
specOpts := []oci.SpecOpts{
customopts.WithProcessArgs(config, imageConfig),
}
@ -136,7 +135,8 @@ func (c *criService) containerSpec(
customopts.WithAnnotation(annotations.ImageName, imageName),
customopts.WithAnnotation(annotations.WindowsHostProcess, strconv.FormatBool(sandboxHpc)),
)
return c.runtimeSpec(id, ociRuntime.BaseRuntimeSpec, specOpts...)
return specOpts, nil
}
// No extra spec options needed for windows.

View File

@ -19,6 +19,7 @@ package sbserver
import (
"testing"
"github.com/containerd/containerd/api/types"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
@ -142,6 +143,8 @@ func getCreateContainerTestData() (*runtime.ContainerConfig, *runtime.PodSandbox
return config, sandboxConfig, imageConfig, specCheck
}
var windowsPlatform = &types.Platform{OS: "windows"}
func TestContainerWindowsNetworkNamespace(t *testing.T) {
testID := "test-id"
testSandboxID := "sandbox-id"
@ -151,7 +154,7 @@ func TestContainerWindowsNetworkNamespace(t *testing.T) {
c := newTestCRIService()
containerConfig, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
spec, err := c.buildContainerSpec(windowsPlatform, testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
assert.NoError(t, err)
assert.NotNil(t, spec)
specCheck(t, testID, testSandboxID, testPid, spec)
@ -173,7 +176,7 @@ func TestMountCleanPath(t *testing.T) {
ContainerPath: "c:/test/container-path",
HostPath: "c:/test/host-path",
})
spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
spec, err := c.buildContainerSpec(windowsPlatform, testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
assert.NoError(t, err)
assert.NotNil(t, spec)
specCheck(t, testID, testSandboxID, testPid, spec)
@ -193,7 +196,7 @@ func TestMountNamedPipe(t *testing.T) {
ContainerPath: `\\.\pipe\foo`,
HostPath: `\\.\pipe\foo`,
})
spec, err := c.containerSpec(testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
spec, err := c.buildContainerSpec(windowsPlatform, testID, testSandboxID, testPid, nsPath, testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, config.Runtime{})
assert.NoError(t, err)
assert.NotNil(t, spec)
specCheck(t, testID, testSandboxID, testPid, spec)
@ -239,7 +242,7 @@ func TestHostProcessRequirements(t *testing.T) {
sandboxConfig.Windows.SecurityContext = &runtime.WindowsSandboxSecurityContext{
HostProcess: test.sandboxHostProcess,
}
_, err := c.containerSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
_, err := c.platformSpec(testID, testSandboxID, testPid, "", testContainerName, testImageName, containerConfig, sandboxConfig, imageConfig, nil, ociRuntime)
if test.expectError {
assert.Error(t, err)
} else {