Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sandbox API when calling sandboxed shims #7684

Merged
merged 4 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 8 additions & 9 deletions pkg/cri/sbserver/container_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
return nil, fmt.Errorf("failed to find sandbox id %q: %w", r.GetPodSandboxId(), err)
}
sandboxID := sandbox.ID

// TODO: Add PID endpoint to Controller interface.
mxpv marked this conversation as resolved.
Show resolved Hide resolved
s, err := sandbox.Container.Task(ctx, nil)
if err != nil {
return nil, fmt.Errorf("failed to get sandbox container task: %w", err)
Expand Down Expand Up @@ -104,11 +106,6 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta
}

start := time.Now()
// Run container using the same runtime with sandbox.
sandboxInfo, err := sandbox.Container.Info(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get sandbox %q info: %w", sandboxID, err)
}

// Create container root directory.
containerRootDir := c.getContainerRootDir(id)
Expand Down Expand Up @@ -236,16 +233,18 @@ func (c *criService) CreateContainer(ctx context.Context, r *runtime.CreateConta

containerLabels := buildLabels(config.Labels, image.ImageSpec.Config.Labels, containerKindContainer)

runtimeOptions, err := getRuntimeOptions(sandboxInfo)
sandboxInfo, err := c.client.SandboxStore().Get(ctx, sandboxID)
if err != nil {
return nil, fmt.Errorf("failed to get runtime options: %w", err)
return nil, fmt.Errorf("unable to get sandbox %q metdata: %w", sandboxID, err)
}

opts = append(opts,
containerd.WithSpec(spec, specOpts...),
containerd.WithRuntime(sandboxInfo.Runtime.Name, runtimeOptions),
containerd.WithRuntime(sandboxInfo.Runtime.Name, sandboxInfo.Runtime.Options),
containerd.WithContainerLabels(containerLabels),
containerd.WithContainerExtension(containerMetadataExtension, &meta))
containerd.WithContainerExtension(containerMetadataExtension, &meta),
)

var cntr containerd.Container
if cntr, err = c.client.NewContainer(ctx, id, opts...); err != nil {
return nil, fmt.Errorf("failed to create containerd container: %w", err)
Expand Down
62 changes: 0 additions & 62 deletions pkg/cri/sbserver/podsandbox/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,11 @@ import (
criconfig "github.com/containerd/containerd/pkg/cri/config"
imagestore "github.com/containerd/containerd/pkg/cri/store/image"
ctrdutil "github.com/containerd/containerd/pkg/cri/util"
runtimeoptions "github.com/containerd/containerd/pkg/runtimeoptions/v1"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/reference/docker"
"github.com/containerd/containerd/runtime/linux/runctypes"
runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/typeurl"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/sirupsen/logrus"

runhcsoptions "github.com/Microsoft/hcsshim/cmd/containerd-shim-runhcs-v1/options"
imagedigest "github.com/opencontainers/go-digest"
"github.com/pelletier/go-toml"
)

const (
Expand All @@ -61,8 +54,6 @@ const (
containerKindSandbox = "sandbox"
// sandboxMetadataExtension is an extension name that identify metadata of sandbox in CreateContainerRequest
sandboxMetadataExtension = criContainerdPrefix + ".sandbox.metadata"
// runtimeRunhcsV1 is the runtime type for runhcs.
runtimeRunhcsV1 = "io.containerd.runhcs.v1"
// MetadataKey is the key used for storing metadata in the sandbox extensions
MetadataKey = "metadata"
)
Expand Down Expand Up @@ -170,59 +161,6 @@ func parseImageReferences(refs []string) ([]string, []string) {
return tags, digests
}

// generateRuntimeOptions generates runtime options from cri plugin config.
func generateRuntimeOptions(r criconfig.Runtime, c criconfig.Config) (interface{}, error) {
if r.Options == nil {
if r.Type != plugin.RuntimeLinuxV1 {
return nil, nil
}
// This is a legacy config, generate runctypes.RuncOptions.
return &runctypes.RuncOptions{
Runtime: r.Engine,
RuntimeRoot: r.Root,
SystemdCgroup: c.SystemdCgroup,
}, nil
}
optionsTree, err := toml.TreeFromMap(r.Options)
if err != nil {
return nil, err
}
options := getRuntimeOptionsType(r.Type)
if err := optionsTree.Unmarshal(options); err != nil {
return nil, err
}
return options, nil
}

// getRuntimeOptionsType gets empty runtime options by the runtime type name.
func getRuntimeOptionsType(t string) interface{} {
switch t {
case plugin.RuntimeRuncV1:
fallthrough
case plugin.RuntimeRuncV2:
return &runcoptions.Options{}
case plugin.RuntimeLinuxV1:
return &runctypes.RuncOptions{}
case runtimeRunhcsV1:
return &runhcsoptions.Options{}
default:
return &runtimeoptions.Options{}
}
}

// getRuntimeOptions get runtime options from container metadata.
func getRuntimeOptions(c containers.Container) (interface{}, error) {
from := c.Runtime.Options
if from == nil || from.GetValue() == nil {
return nil, nil
}
opts, err := typeurl.UnmarshalAny(from)
if err != nil {
return nil, err
}
return opts, nil
}

// getPassthroughAnnotations filters requested pod annotations by comparing
// against permitted annotations for the given runtime.
func getPassthroughAnnotations(podAnnotations map[string]string,
Expand Down
126 changes: 0 additions & 126 deletions pkg/cri/sbserver/podsandbox/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,11 @@ import (
"strings"
"testing"

"github.com/containerd/containerd/containers"
"github.com/containerd/containerd/oci"
criconfig "github.com/containerd/containerd/pkg/cri/config"
"github.com/containerd/containerd/plugin"
"github.com/containerd/containerd/protobuf/types"
"github.com/containerd/containerd/reference/docker"
"github.com/containerd/containerd/runtime/linux/runctypes"
runcoptions "github.com/containerd/containerd/runtime/v2/runc/options"
"github.com/containerd/typeurl"

imagedigest "github.com/opencontainers/go-digest"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pelletier/go-toml"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestGetUserFromImage tests the logic of getting image uid or user name of image user.
Expand Down Expand Up @@ -158,112 +148,6 @@ func TestParseImageReferences(t *testing.T) {
assert.Equal(t, expectedDigests, digests)
}

func TestGenerateRuntimeOptions(t *testing.T) {
nilOpts := `
systemd_cgroup = true
[containerd]
no_pivot = true
default_runtime_name = "default"
[containerd.runtimes.legacy]
runtime_type = "` + plugin.RuntimeLinuxV1 + `"
[containerd.runtimes.runc]
runtime_type = "` + plugin.RuntimeRuncV1 + `"
[containerd.runtimes.runcv2]
runtime_type = "` + plugin.RuntimeRuncV2 + `"
`
nonNilOpts := `
systemd_cgroup = true
[containerd]
no_pivot = true
default_runtime_name = "default"
[containerd.runtimes.legacy]
runtime_type = "` + plugin.RuntimeLinuxV1 + `"
[containerd.runtimes.legacy.options]
Runtime = "legacy"
RuntimeRoot = "/legacy"
[containerd.runtimes.runc]
runtime_type = "` + plugin.RuntimeRuncV1 + `"
[containerd.runtimes.runc.options]
BinaryName = "runc"
Root = "/runc"
NoNewKeyring = true
[containerd.runtimes.runcv2]
runtime_type = "` + plugin.RuntimeRuncV2 + `"
[containerd.runtimes.runcv2.options]
BinaryName = "runc"
Root = "/runcv2"
NoNewKeyring = true
`
var nilOptsConfig, nonNilOptsConfig criconfig.Config
tree, err := toml.Load(nilOpts)
require.NoError(t, err)
err = tree.Unmarshal(&nilOptsConfig)
require.NoError(t, err)
require.Len(t, nilOptsConfig.Runtimes, 3)

tree, err = toml.Load(nonNilOpts)
require.NoError(t, err)
err = tree.Unmarshal(&nonNilOptsConfig)
require.NoError(t, err)
require.Len(t, nonNilOptsConfig.Runtimes, 3)

for desc, test := range map[string]struct {
r criconfig.Runtime
c criconfig.Config
expectedOptions interface{}
}{
"when options is nil, should return nil option for io.containerd.runc.v1": {
r: nilOptsConfig.Runtimes["runc"],
c: nilOptsConfig,
expectedOptions: nil,
},
"when options is nil, should return nil option for io.containerd.runc.v2": {
r: nilOptsConfig.Runtimes["runcv2"],
c: nilOptsConfig,
expectedOptions: nil,
},
"when options is nil, should use legacy fields for legacy runtime": {
r: nilOptsConfig.Runtimes["legacy"],
c: nilOptsConfig,
expectedOptions: &runctypes.RuncOptions{
SystemdCgroup: true,
},
},
"when options is not nil, should be able to decode for io.containerd.runc.v1": {
r: nonNilOptsConfig.Runtimes["runc"],
c: nonNilOptsConfig,
expectedOptions: &runcoptions.Options{
BinaryName: "runc",
Root: "/runc",
NoNewKeyring: true,
},
},
"when options is not nil, should be able to decode for io.containerd.runc.v2": {
r: nonNilOptsConfig.Runtimes["runcv2"],
c: nonNilOptsConfig,
expectedOptions: &runcoptions.Options{
BinaryName: "runc",
Root: "/runcv2",
NoNewKeyring: true,
},
},
"when options is not nil, should be able to decode for legacy runtime": {
r: nonNilOptsConfig.Runtimes["legacy"],
c: nonNilOptsConfig,
expectedOptions: &runctypes.RuncOptions{
Runtime: "legacy",
RuntimeRoot: "/legacy",
},
},
} {
t.Run(desc, func(t *testing.T) {
opts, err := generateRuntimeOptions(test.r, test.c)
assert.NoError(t, err)
assert.Equal(t, test.expectedOptions, opts)
})
}
}

func TestEnvDeduplication(t *testing.T) {
for desc, test := range map[string]struct {
existing []string
Expand Down Expand Up @@ -471,13 +355,3 @@ func TestEnsureRemoveAllWithFile(t *testing.T) {
t.Fatal(err)
}
}

func TestGetRuntimeOptions(t *testing.T) {
_, err := getRuntimeOptions(containers.Container{})
require.NoError(t, err)

var pbany *types.Any // This is nil.
var typeurlAny typeurl.Any = pbany // This is typed nil.
_, err = getRuntimeOptions(containers.Container{Runtime: containers.RuntimeInfo{Options: typeurlAny}})
require.NoError(t, err)
}
11 changes: 4 additions & 7 deletions pkg/cri/sbserver/podsandbox/sandbox_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (c *Controller) Start(ctx context.Context, id string) (resp *api.Controller
return nil, fmt.Errorf("failed to get image from containerd %q: %w", image.ID, err)
}

ociRuntime, err := c.getSandboxRuntime(config, sandboxInfo.Runtime.Name)
ociRuntime, err := c.getSandboxRuntime(config, metadata.RuntimeHandler)
if err != nil {
return nil, fmt.Errorf("failed to get sandbox runtime: %w", err)
}
Expand Down Expand Up @@ -131,19 +131,15 @@ func (c *Controller) Start(ctx context.Context, id string) (resp *api.Controller

sandboxLabels := buildLabels(config.Labels, image.ImageSpec.Config.Labels, containerKindSandbox)

runtimeOpts, err := generateRuntimeOptions(ociRuntime, c.config)
if err != nil {
return nil, fmt.Errorf("failed to generate runtime options: %w", err)
}

snapshotterOpt := snapshots.WithLabels(snapshots.FilterInheritedLabels(config.Annotations))
opts := []containerd.NewContainerOpts{
containerd.WithSnapshotter(c.runtimeSnapshotter(ctx, ociRuntime)),
customopts.WithNewSnapshot(id, containerdImage, snapshotterOpt),
containerd.WithSpec(spec, specOpts...),
containerd.WithContainerLabels(sandboxLabels),
containerd.WithContainerExtension(sandboxMetadataExtension, &metadata),
containerd.WithRuntime(ociRuntime.Type, runtimeOpts)}
containerd.WithRuntime(ociRuntime.Type, sandboxInfo.Runtime.Options),
}

container, err := c.client.NewContainer(ctx, id, opts...)
if err != nil {
Expand Down Expand Up @@ -263,6 +259,7 @@ func (c *Controller) Start(ctx context.Context, id string) (resp *api.Controller
SandboxID: id,
Pid: task.Pid(),
CreatedAt: protobuf.ToTimestamp(info.CreatedAt),
Labels: labels,
}

return resp, nil
Expand Down
38 changes: 29 additions & 9 deletions pkg/cri/sbserver/sandbox_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,29 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
}
}()

sandboxInfo := sb.Sandbox{
ID: id,
// TODO: runtime handler can be an empty string, should use default one and enable back validation of this field in metadata store.
Runtime: sb.RuntimeOpts{Name: r.GetRuntimeHandler()},
var (
err error
sandboxInfo = sb.Sandbox{ID: id}
)

ociRuntime, err := c.getSandboxRuntime(config, r.GetRuntimeHandler())
if err != nil {
return nil, fmt.Errorf("unable to get OCI runtime for sandbox %q: %w", id, err)
}

sandboxInfo.Runtime.Name = ociRuntime.Type

// Retrieve runtime options
runtimeOpts, err := generateRuntimeOptions(ociRuntime, c.config)
if err != nil {
return nil, fmt.Errorf("failed to generate sandbox runtime options: %w", err)
}

if runtimeOpts != nil {
sandboxInfo.Runtime.Options, err = typeurl.MarshalAny(runtimeOpts)
if err != nil {
return nil, fmt.Errorf("failed to marshal runtime options: %w", err)
}
}

// Save sandbox name
Expand Down Expand Up @@ -127,11 +146,7 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
}
}()

var (
podNetwork = true
err error
)

podNetwork := true
if goruntime.GOOS != "windows" &&
config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetNetwork() == runtime.NamespaceMode_NODE {
// Pod network is not needed on linux with host network.
Expand All @@ -143,6 +158,11 @@ func (c *criService) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox
podNetwork = false
}

// No CNI on darwin yet
if goruntime.GOOS == "darwin" {
podNetwork = false
}

if podNetwork {
netStart := time.Now()
// If it is not in host network namespace then create a namespace and set the sandbox
Expand Down