Merge pull request #48 from Random-Liu/apply-sandbox-image-config

Apply sandbox image config
This commit is contained in:
Lantao Liu 2017-05-30 18:16:59 -07:00 committed by GitHub
commit 98bc3edf50
11 changed files with 218 additions and 91 deletions

View File

@ -49,6 +49,7 @@ func (c *criContainerdService) startEventMonitor() error {
func (c *criContainerdService) handleEventStream(events execution.ContainerService_EventsClient) {
// TODO(random-liu): [P1] Should backoff on this error, or else this will
// cause a busy loop.
// TODO(random-liu): Handle io.EOF.
e, err := events.Recv()
if err != nil {
glog.Errorf("Failed to receive event: %v", err)

View File

@ -55,6 +55,9 @@ const (
)
const (
// defaultSandboxImage is the image used by sandbox container.
// TODO(random-liu): [P1] Build schema 2 pause image and use it here.
defaultSandboxImage = "gcr.io/google.com/noogler-kubernetes/pause-amd64:3.0"
// relativeRootfsPath is the rootfs path relative to bundle path.
relativeRootfsPath = "rootfs"
// defaultRuntime is the runtime to use in containerd. We may support
@ -305,31 +308,39 @@ func getRepoDigestAndTag(namedRef reference.Named, digest imagedigest.Digest) (s
return repoDigest, repoTag
}
// localResolve resolves image reference to image id locally. It returns empty string
// without error if the reference doesn't exist.
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (string, error) {
// localResolve resolves image reference locally and returns corresponding image metadata. It returns
// nil without error if the reference doesn't exist.
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
_, err := imagedigest.Parse(ref)
if err == nil {
return ref, nil
}
// ref is not image id, try to resolve it locally.
normalized, err := normalizeImageRef(ref)
if err != nil {
return "", fmt.Errorf("invalid image reference %q: %v", ref, err)
}
image, err := c.imageStoreService.Get(ctx, normalized.String())
if err != nil {
if images.IsNotFound(err) {
return "", nil
// ref is not image id, try to resolve it locally.
normalized, err := normalizeImageRef(ref)
if err != nil {
return nil, fmt.Errorf("invalid image reference %q: %v", ref, err)
}
return "", fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
normalized.String(), err)
image, err := c.imageStoreService.Get(ctx, normalized.String())
if err != nil {
if images.IsNotFound(err) {
return nil, nil
}
return nil, fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
normalized.String(), err)
}
desc, err := image.Config(ctx, c.contentStoreService)
if err != nil {
return nil, fmt.Errorf("failed to get image config descriptor: %v", err)
}
ref = desc.Digest.String()
}
desc, err := image.Config(ctx, c.contentStoreService)
imageID := ref
meta, err := c.imageMetadataStore.Get(imageID)
if err != nil {
return "", fmt.Errorf("failed to get image config descriptor: %v", err)
if metadata.IsNotExistError(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to get image %q metadata: %v", imageID, err)
}
return desc.Digest.String(), nil
return meta, nil
}
// getUserFromImage gets uid or user name of the image user.
@ -350,3 +361,27 @@ func getUserFromImage(user string) (*int64, string) {
// If user is a numeric uid.
return &uid, ""
}
// ensureImageExists returns corresponding metadata of the image reference, if image is not
// pulled yet, the function will pull the image.
func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
meta, err := c.localResolve(ctx, ref)
if err != nil {
return nil, fmt.Errorf("failed to resolve image %q: %v", ref, err)
}
if meta != nil {
return meta, nil
}
// Pull image to ensure the image exists
resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}})
if err != nil {
return nil, fmt.Errorf("failed to pull image %q: %v", ref, err)
}
imageID := resp.GetImageRef()
meta, err = c.imageMetadataStore.Get(imageID)
if err != nil {
// It's still possible that someone removed the image right after it is pulled.
return nil, fmt.Errorf("failed to get image %q metadata after pulling: %v", imageID, err)
}
return meta, nil
}

View File

@ -41,21 +41,14 @@ func (c *criContainerdService) RemoveImage(ctx context.Context, r *runtime.Remov
glog.V(2).Infof("RemoveImage %q returns successfully", r.GetImage().GetImage())
}
}()
imageID, err := c.localResolve(ctx, r.GetImage().GetImage())
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
if err != nil {
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
}
if imageID == "" {
if meta == nil {
// return empty without error when image not found.
return &runtime.RemoveImageResponse{}, nil
}
meta, err := c.imageMetadataStore.Get(imageID)
if err != nil {
if metadata.IsNotExistError(err) {
return &runtime.RemoveImageResponse{}, nil
}
return nil, fmt.Errorf("an error occurred when get image %q metadata: %v", imageID, err)
}
// Also include repo digest, because if user pull image with digest,
// there will also be a corresponding repo digest reference.
for _, ref := range append(meta.RepoTags, meta.RepoDigests...) {
@ -65,14 +58,14 @@ func (c *criContainerdService) RemoveImage(ctx context.Context, r *runtime.Remov
if err == nil || images.IsNotFound(err) {
continue
}
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, imageID, err)
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, meta.ID, err)
}
err = c.imageMetadataStore.Delete(imageID)
err = c.imageMetadataStore.Delete(meta.ID)
if err != nil {
if metadata.IsNotExistError(err) {
return &runtime.RemoveImageResponse{}, nil
}
return nil, fmt.Errorf("an error occurred when delete image %q matadata: %v", imageID, err)
return nil, fmt.Errorf("an error occurred when delete image %q matadata: %v", meta.ID, err)
}
return &runtime.RemoveImageResponse{}, nil
}

View File

@ -22,8 +22,6 @@ import (
"github.com/golang/glog"
"golang.org/x/net/context"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
)
// ImageStatus returns the status of the image, returns nil if the image isn't present.
@ -37,23 +35,14 @@ func (c *criContainerdService) ImageStatus(ctx context.Context, r *runtime.Image
r.GetImage().GetImage(), retRes.GetImage())
}
}()
imageID, err := c.localResolve(ctx, r.GetImage().GetImage())
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
if err != nil {
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
}
if imageID == "" {
if meta == nil {
// return empty without error when image not found.
return &runtime.ImageStatusResponse{}, nil
}
meta, err := c.imageMetadataStore.Get(imageID)
if err != nil {
if metadata.IsNotExistError(err) {
return &runtime.ImageStatusResponse{}, nil
}
return nil, fmt.Errorf("an error occurred during get image %q metadata: %v",
imageID, err)
}
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
// doesn't exist?
runtimeImage := &runtime.Image{

View File

@ -35,7 +35,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
glog.V(2).Infof("RemovePodSandbox for sandbox %q", r.GetPodSandboxId())
defer func() {
if retErr == nil {
glog.V(2).Info("RemovePodSandbox %q returns successfully", r.GetPodSandboxId())
glog.V(2).Infof("RemovePodSandbox %q returns successfully", r.GetPodSandboxId())
}
}()
@ -65,6 +65,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
return nil, fmt.Errorf("sandbox container %q is not fully stopped", id)
}
// TODO(random-liu): [P0] Cleanup snapshot after switching to new snapshot api.
// TODO(random-liu): [P0] Cleanup shm created in RunPodSandbox.
// TODO(random-liu): [P1] Remove permanent namespace once used.

View File

@ -21,17 +21,18 @@ import (
"fmt"
"io"
"io/ioutil"
"strings"
"time"
"github.com/containerd/containerd/api/services/execution"
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
prototypes "github.com/gogo/protobuf/types"
"github.com/golang/glog"
imagedigest "github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"golang.org/x/net/context"
"github.com/containerd/containerd/api/services/execution"
"github.com/containerd/containerd/api/types/mount"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
@ -81,10 +82,22 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
Config: config,
}
// TODO(random-liu): [P0] Ensure pause image snapshot, apply default image config
// and get snapshot mounts.
// Use fixed rootfs path and sleep command.
const rootPath = "/"
// Ensure sandbox container image snapshot.
imageMeta, err := c.ensureImageExists(ctx, c.sandboxImage)
if err != nil {
return nil, fmt.Errorf("failed to get sandbox image %q: %v", defaultSandboxImage, err)
}
prepareResp, err := c.rootfsService.Prepare(ctx, &rootfsapi.PrepareRequest{
Name: id,
// We are sure that ChainID must be a digest.
ChainID: imagedigest.Digest(imageMeta.ChainID),
Readonly: true,
})
if err != nil {
return nil, fmt.Errorf("failed to prepare sandbox rootfs %q: %v", imageMeta.ChainID, err)
}
// TODO(random-liu): [P0] Cleanup snapshot on failure after switching to new rootfs api.
rootfsMounts := prepareResp.Mounts
// Create sandbox container root directory.
// Prepare streaming named pipe.
@ -124,7 +137,10 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
}
// Start sandbox container.
spec := c.generateSandboxContainerSpec(id, config)
spec, err := c.generateSandboxContainerSpec(id, config, imageMeta.Config)
if err != nil {
return nil, fmt.Errorf("failed to generate sandbox container spec: %v", err)
}
rawSpec, err := json.Marshal(spec)
if err != nil {
return nil, fmt.Errorf("failed to marshal oci spec %+v: %v", spec, err)
@ -137,16 +153,7 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
Value: rawSpec,
},
// TODO(random-liu): [P0] Get rootfs mount from containerd.
Rootfs: []*mount.Mount{
{
Type: "bind",
Source: rootPath,
Options: []string{
"rw",
"rbind",
},
},
},
Rootfs: rootfsMounts,
Runtime: defaultRuntime,
// No stdin for sandbox container.
Stdout: stdout,
@ -205,20 +212,35 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil
}
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig) *runtimespec.Spec {
// TODO(random-liu): [P0] Get command from image config.
pauseCommand := []string{"sh", "-c", "while true; do sleep 1000000000; done"}
func (c *criContainerdService) generateSandboxContainerSpec(id string, config *runtime.PodSandboxConfig,
imageConfig *imagespec.ImageConfig) (*runtimespec.Spec, error) {
// Creates a spec Generator with the default spec.
// TODO(random-liu): [P1] Compare the default settings with docker and containerd default.
g := generate.New()
// Apply default config from image config.
for _, e := range imageConfig.Env {
kv := strings.Split(e, "=")
if len(kv) != 2 {
return nil, fmt.Errorf("invalid environment variable in image config %+v", imageConfig)
}
g.AddProcessEnv(kv[0], kv[1])
}
if imageConfig.WorkingDir != "" {
g.SetProcessCwd(imageConfig.WorkingDir)
}
if len(imageConfig.Entrypoint) == 0 {
// Pause image must have entrypoint.
return nil, fmt.Errorf("invalid empty entrypoint in image config %+v", imageConfig)
}
// Set process commands.
g.SetProcessArgs(append(imageConfig.Entrypoint, imageConfig.Cmd...))
// Set relative root path.
g.SetRootPath(relativeRootfsPath)
// Set process commands.
g.SetProcessArgs(pauseCommand)
// Make root of sandbox container read-only.
g.SetRootReadonly(true)
@ -276,5 +298,5 @@ func (c *criContainerdService) generateSandboxContainerSpec(id string, config *r
// TODO(random-liu): [P1] Set default sandbox container resource limit.
return g.Spec()
return g.Spec(), nil
}

View File

@ -23,20 +23,22 @@ import (
"syscall"
"testing"
"github.com/containerd/containerd/api/services/execution"
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
imagedigest "github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/context"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
"github.com/containerd/containerd/api/services/execution"
runtimespec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
)
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, func(*testing.T, string, *runtimespec.Spec)) {
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) {
config := &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{
Name: "test-name",
@ -52,20 +54,31 @@ func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, func(*testing.T, str
CgroupParent: "/test/cgroup/parent",
},
}
imageConfig := &imagespec.ImageConfig{
Env: []string{"a=b", "c=d"},
Entrypoint: []string{"/pause"},
Cmd: []string{"forever"},
WorkingDir: "/workspace",
}
specCheck := func(t *testing.T, id string, spec *runtimespec.Spec) {
assert.Equal(t, "test-hostname", spec.Hostname)
assert.Equal(t, getCgroupsPath("/test/cgroup/parent", id), spec.Linux.CgroupsPath)
assert.Equal(t, relativeRootfsPath, spec.Root.Path)
assert.Equal(t, true, spec.Root.Readonly)
assert.Contains(t, spec.Process.Env, "a=b", "c=d")
assert.Equal(t, []string{"/pause", "forever"}, spec.Process.Args)
assert.Equal(t, "/workspace", spec.Process.Cwd)
}
return config, specCheck
return config, imageConfig, specCheck
}
func TestGenerateSandboxContainerSpec(t *testing.T) {
testID := "test-id"
for desc, test := range map[string]struct {
configChange func(*runtime.PodSandboxConfig)
specCheck func(*testing.T, *runtimespec.Spec)
configChange func(*runtime.PodSandboxConfig)
imageConfigChange func(*imagespec.ImageConfig)
specCheck func(*testing.T, *runtimespec.Spec)
expectErr bool
}{
"spec should reflect original config": {
specCheck: func(t *testing.T, spec *runtimespec.Spec) {
@ -106,14 +119,36 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
})
},
},
"should return error when entrypoint is empty": {
imageConfigChange: func(c *imagespec.ImageConfig) {
c.Entrypoint = nil
},
expectErr: true,
},
"should return error when env is invalid ": {
imageConfigChange: func(c *imagespec.ImageConfig) {
c.Env = []string{"a"}
},
expectErr: true,
},
} {
t.Logf("TestCase %q", desc)
c := newTestCRIContainerdService()
config, specCheck := getRunPodSandboxTestData()
config, imageConfig, specCheck := getRunPodSandboxTestData()
if test.configChange != nil {
test.configChange(config)
}
spec := c.generateSandboxContainerSpec(testID, config)
if test.imageConfigChange != nil {
test.imageConfigChange(imageConfig)
}
spec, err := c.generateSandboxContainerSpec(testID, config, imageConfig)
if test.expectErr {
assert.Error(t, err)
assert.Nil(t, spec)
continue
}
assert.NoError(t, err)
assert.NotNil(t, spec)
specCheck(t, testID, spec)
if test.specCheck != nil {
test.specCheck(t, spec)
@ -122,8 +157,9 @@ func TestGenerateSandboxContainerSpec(t *testing.T) {
}
func TestRunPodSandbox(t *testing.T) {
config, specCheck := getRunPodSandboxTestData()
config, imageConfig, specCheck := getRunPodSandboxTestData()
c := newTestCRIContainerdService()
fakeRootfsClient := c.rootfsService.(*servertesting.FakeRootfsClient)
fakeExecutionClient := c.containerService.(*servertesting.FakeExecutionClient)
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
fakeOS := c.os.(*ostesting.FakeOS)
@ -140,6 +176,17 @@ func TestRunPodSandbox(t *testing.T) {
assert.Equal(t, os.FileMode(0700), perm)
return nopReadWriteCloser{}, nil
}
testChainID := imagedigest.Digest("test-sandbox-chain-id")
imageMetadata := metadata.ImageMetadata{
ID: testSandboxImage,
ChainID: testChainID.String(),
Config: imageConfig,
}
// Insert sandbox image metadata.
assert.NoError(t, c.imageMetadataStore.Create(imageMetadata))
// Insert fake chainID
fakeRootfsClient.SetFakeChainIDs([]imagedigest.Digest{testChainID})
expectRootfsClientCalls := []string{"prepare"}
expectExecutionClientCalls := []string{"create", "start"}
res, err := c.RunPodSandbox(context.Background(), &runtime.RunPodSandboxRequest{Config: config})
@ -155,13 +202,24 @@ func TestRunPodSandbox(t *testing.T) {
assert.Contains(t, pipes, stdout, "sandbox stdout pipe should be created")
assert.Contains(t, pipes, stderr, "sandbox stderr pipe should be created")
assert.Equal(t, expectRootfsClientCalls, fakeRootfsClient.GetCalledNames(), "expect rootfs functions should be called")
calls := fakeRootfsClient.GetCalledDetails()
prepareOpts := calls[0].Argument.(*rootfsapi.PrepareRequest)
assert.Equal(t, &rootfsapi.PrepareRequest{
Name: id,
ChainID: testChainID,
Readonly: true,
}, prepareOpts, "prepare request should be correct")
assert.Equal(t, expectExecutionClientCalls, fakeExecutionClient.GetCalledNames(), "expect containerd functions should be called")
calls := fakeExecutionClient.GetCalledDetails()
calls = fakeExecutionClient.GetCalledDetails()
createOpts := calls[0].Argument.(*execution.CreateRequest)
assert.Equal(t, id, createOpts.ID, "create id should be correct")
// TODO(random-liu): Test rootfs mount when image management part is integrated.
assert.Equal(t, stdout, createOpts.Stdout, "stdout pipe should be passed to containerd")
assert.Equal(t, stderr, createOpts.Stderr, "stderr pipe should be passed to containerd")
mountsResp, err := fakeRootfsClient.Mounts(context.Background(), &rootfsapi.MountsRequest{Name: id})
assert.NoError(t, err)
assert.Equal(t, mountsResp.Mounts, createOpts.Rootfs, "rootfs mount should be correct")
spec := &runtimespec.Spec{}
assert.NoError(t, json.Unmarshal(createOpts.Spec.Value, spec))
t.Logf("oci spec check")

View File

@ -34,7 +34,7 @@ func (c *criContainerdService) StopPodSandbox(ctx context.Context, r *runtime.St
glog.V(2).Infof("StopPodSandbox for sandbox %q", r.GetPodSandboxId())
defer func() {
if retErr == nil {
glog.V(2).Info("StopPodSandbox %q returns successfully", r.GetPodSandboxId())
glog.V(2).Infof("StopPodSandbox %q returns successfully", r.GetPodSandboxId())
}
}()
@ -56,7 +56,7 @@ func (c *criContainerdService) StopPodSandbox(ctx context.Context, r *runtime.St
} else if !os.IsNotExist(err) { // It's ok for sandbox.NetNS to *not* exist
return nil, fmt.Errorf("failed to stat netns path for sandbox %q before tearing down the network: %v", id, err)
}
glog.V(2).Info("TearDown network for sandbox %q successfully", id)
glog.V(2).Infof("TearDown network for sandbox %q successfully", id)
// TODO(random-liu): [P1] Handle sandbox container graceful deletion.
// Delete the sandbox container from containerd.

View File

@ -65,6 +65,9 @@ type criContainerdService struct {
os osinterface.OS
// rootDir is the directory for managing cri-containerd files.
rootDir string
// sandboxImage is the image to use for sandbox container.
// TODO(random-liu): Make this configurable via flag.
sandboxImage string
// sandboxStore stores all sandbox metadata.
sandboxStore metadata.SandboxStore
// imageMetadataStore stores all image metadata.
@ -100,6 +103,7 @@ func NewCRIContainerdService(conn *grpc.ClientConn, rootDir, networkPluginBinDir
c := &criContainerdService{
os: osinterface.RealOS{},
rootDir: rootDir,
sandboxImage: defaultSandboxImage,
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
containerStore: metadata.NewContainerStore(store.NewMetadataStore()),
imageMetadataStore: metadata.NewImageMetadataStore(store.NewMetadataStore()),

View File

@ -32,6 +32,8 @@ import (
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
imagedigest "github.com/opencontainers/go-digest"
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
runtime "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1"
)
@ -43,20 +45,28 @@ func (nopReadWriteCloser) Read(p []byte) (n int, err error) { return 0, io.EOF
func (nopReadWriteCloser) Write(p []byte) (n int, err error) { return 0, io.ErrShortWrite }
func (nopReadWriteCloser) Close() error { return nil }
const testRootDir = "/test/rootfs"
const (
testRootDir = "/test/rootfs"
// Use an image id as test sandbox image to avoid image name resolve.
// TODO(random-liu): Change this to image name after we have complete image
// management unit test framework.
testSandboxImage = "sha256:c75bebcdd211f41b3a460c7bf82970ed6c75acaab9cd4c9a4e125b03ca113798"
)
// newTestCRIContainerdService creates a fake criContainerdService for test.
func newTestCRIContainerdService() *criContainerdService {
return &criContainerdService{
os: ostesting.NewFakeOS(),
rootDir: testRootDir,
containerService: servertesting.NewFakeExecutionClient(),
sandboxImage: testSandboxImage,
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
imageMetadataStore: metadata.NewImageMetadataStore(store.NewMetadataStore()),
sandboxNameIndex: registrar.NewRegistrar(),
sandboxIDIndex: truncindex.NewTruncIndex(nil),
containerStore: metadata.NewContainerStore(store.NewMetadataStore()),
containerNameIndex: registrar.NewRegistrar(),
containerService: servertesting.NewFakeExecutionClient(),
rootfsService: servertesting.NewFakeRootfsClient(),
netPlugin: servertesting.NewFakeCNIPlugin(),
}
}
@ -65,11 +75,21 @@ func newTestCRIContainerdService() *criContainerdService {
func TestSandboxOperations(t *testing.T) {
c := newTestCRIContainerdService()
fake := c.containerService.(*servertesting.FakeExecutionClient)
fakeRootfsClient := c.rootfsService.(*servertesting.FakeRootfsClient)
fakeOS := c.os.(*ostesting.FakeOS)
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
fakeOS.OpenFifoFn = func(ctx context.Context, fn string, flag int, perm os.FileMode) (io.ReadWriteCloser, error) {
return nopReadWriteCloser{}, nil
}
// Insert sandbox image metadata.
assert.NoError(t, c.imageMetadataStore.Create(metadata.ImageMetadata{
ID: testSandboxImage,
ChainID: "test-chain-id",
Config: &imagespec.ImageConfig{Entrypoint: []string{"/pause"}},
}))
// Insert fake chainID
fakeRootfsClient.SetFakeChainIDs([]imagedigest.Digest{imagedigest.Digest("test-chain-id")})
config := &runtime.PodSandboxConfig{
Metadata: &runtime.PodSandboxMetadata{
Name: "test-name",

View File

@ -169,7 +169,11 @@ func (f *FakeRootfsClient) Prepare(ctx context.Context, prepareOpts *rootfs.Prep
if ok {
return nil, fmt.Errorf("mounts already exist")
}
f.MountList[prepareOpts.Name] = []*mount.Mount{}
f.MountList[prepareOpts.Name] = []*mount.Mount{{
Type: "bind",
Source: prepareOpts.Name,
// TODO(random-liu): Fake options based on Readonly option.
}}
return &rootfs.MountResponse{
Mounts: f.MountList[prepareOpts.Name],
}, nil