Use new metadata store.
Signed-off-by: Lantao Liu <lantaol@google.com>
This commit is contained in:
parent
4317e6119a
commit
7b16a35287
@ -32,7 +32,7 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateContainer creates a new container in the given PodSandbox.
|
// CreateContainer creates a new container in the given PodSandbox.
|
||||||
@ -58,7 +58,7 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
// the same container.
|
// the same container.
|
||||||
id := generateID()
|
id := generateID()
|
||||||
name := makeContainerName(config.GetMetadata(), sandboxConfig.GetMetadata())
|
name := makeContainerName(config.GetMetadata(), sandboxConfig.GetMetadata())
|
||||||
if err := c.containerNameIndex.Reserve(name, id); err != nil {
|
if err = c.containerNameIndex.Reserve(name, id); err != nil {
|
||||||
return nil, fmt.Errorf("failed to reserve container name %q: %v", name, err)
|
return nil, fmt.Errorf("failed to reserve container name %q: %v", name, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -68,8 +68,8 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create initial container metadata.
|
// Create initial internal container metadata.
|
||||||
meta := metadata.ContainerMetadata{
|
meta := containerstore.Metadata{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: name,
|
Name: name,
|
||||||
SandboxID: sandboxID,
|
SandboxID: sandboxID,
|
||||||
@ -78,18 +78,18 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
|
|
||||||
// Prepare container image snapshot. For container, the image should have
|
// Prepare container image snapshot. For container, the image should have
|
||||||
// been pulled before creating the container, so do not ensure the image.
|
// been pulled before creating the container, so do not ensure the image.
|
||||||
image := config.GetImage().GetImage()
|
imageRef := config.GetImage().GetImage()
|
||||||
imageMeta, err := c.localResolve(ctx, image)
|
image, err := c.localResolve(ctx, imageRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to resolve image %q: %v", image, err)
|
return nil, fmt.Errorf("failed to resolve image %q: %v", imageRef, err)
|
||||||
}
|
}
|
||||||
if imageMeta == nil {
|
if image == nil {
|
||||||
return nil, fmt.Errorf("image %q not found", image)
|
return nil, fmt.Errorf("image %q not found", imageRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate container runtime spec.
|
// Generate container runtime spec.
|
||||||
mounts := c.generateContainerMounts(getSandboxRootDir(c.rootDir, sandboxID), config)
|
mounts := c.generateContainerMounts(getSandboxRootDir(c.rootDir, sandboxID), config)
|
||||||
spec, err := c.generateContainerSpec(id, sandbox.Pid, config, sandboxConfig, imageMeta.Config, mounts)
|
spec, err := c.generateContainerSpec(id, sandbox.Pid, config, sandboxConfig, image.Config, mounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate container %q spec: %v", id, err)
|
return nil, fmt.Errorf("failed to generate container %q spec: %v", id, err)
|
||||||
}
|
}
|
||||||
@ -101,12 +101,12 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
|
|
||||||
// Prepare container rootfs.
|
// Prepare container rootfs.
|
||||||
if config.GetLinux().GetSecurityContext().GetReadonlyRootfs() {
|
if config.GetLinux().GetSecurityContext().GetReadonlyRootfs() {
|
||||||
if _, err := c.snapshotService.View(ctx, id, imageMeta.ChainID); err != nil {
|
if _, err := c.snapshotService.View(ctx, id, image.ChainID); err != nil {
|
||||||
return nil, fmt.Errorf("failed to view container rootfs %q: %v", imageMeta.ChainID, err)
|
return nil, fmt.Errorf("failed to view container rootfs %q: %v", image.ChainID, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if _, err := c.snapshotService.Prepare(ctx, id, imageMeta.ChainID); err != nil {
|
if _, err := c.snapshotService.Prepare(ctx, id, image.ChainID); err != nil {
|
||||||
return nil, fmt.Errorf("failed to prepare container rootfs %q: %v", imageMeta.ChainID, err)
|
return nil, fmt.Errorf("failed to prepare container rootfs %q: %v", image.ChainID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -116,18 +116,18 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
meta.ImageRef = imageMeta.ID
|
meta.ImageRef = image.ID
|
||||||
|
|
||||||
// Create container root directory.
|
// Create container root directory.
|
||||||
containerRootDir := getContainerRootDir(c.rootDir, id)
|
containerRootDir := getContainerRootDir(c.rootDir, id)
|
||||||
if err := c.os.MkdirAll(containerRootDir, 0755); err != nil {
|
if err = c.os.MkdirAll(containerRootDir, 0755); err != nil {
|
||||||
return nil, fmt.Errorf("failed to create container root directory %q: %v",
|
return nil, fmt.Errorf("failed to create container root directory %q: %v",
|
||||||
containerRootDir, err)
|
containerRootDir, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
// Cleanup the container root directory.
|
// Cleanup the container root directory.
|
||||||
if err := c.os.RemoveAll(containerRootDir); err != nil {
|
if err = c.os.RemoveAll(containerRootDir); err != nil {
|
||||||
glog.Errorf("Failed to remove container root directory %q: %v",
|
glog.Errorf("Failed to remove container root directory %q: %v",
|
||||||
containerRootDir, err)
|
containerRootDir, err)
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
Container: containers.Container{
|
Container: containers.Container{
|
||||||
ID: id,
|
ID: id,
|
||||||
// TODO(random-liu): Checkpoint metadata into container labels.
|
// TODO(random-liu): Checkpoint metadata into container labels.
|
||||||
Image: imageMeta.ID,
|
Image: image.ID,
|
||||||
Runtime: defaultRuntime,
|
Runtime: defaultRuntime,
|
||||||
Spec: &prototypes.Any{
|
Spec: &prototypes.Any{
|
||||||
TypeUrl: runtimespec.Version,
|
TypeUrl: runtimespec.Version,
|
||||||
@ -158,12 +158,23 @@ func (c *criContainerdService) CreateContainer(ctx context.Context, r *runtime.C
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Update container CreatedAt.
|
container, err := containerstore.NewContainer(meta, containerstore.Status{CreatedAt: time.Now().UnixNano()})
|
||||||
meta.CreatedAt = time.Now().UnixNano()
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create internal container object for %q: %v",
|
||||||
|
id, err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
// Cleanup container checkpoint on error.
|
||||||
|
if err := container.Delete(); err != nil {
|
||||||
|
glog.Errorf("Failed to cleanup container checkpoint for %q: %v", id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Add container into container store.
|
// Add container into container store.
|
||||||
if err := c.containerStore.Create(meta); err != nil {
|
if err := c.containerStore.Add(container); err != nil {
|
||||||
return nil, fmt.Errorf("failed to add container metadata %+v into store: %v",
|
return nil, fmt.Errorf("failed to add container %q into store: %v", id, err)
|
||||||
meta, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &runtime.CreateContainerResponse{ContainerId: id}, nil
|
return &runtime.CreateContainerResponse{ContainerId: id}, nil
|
||||||
|
@ -32,9 +32,11 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string,
|
func checkMount(t *testing.T, mounts []runtimespec.Mount, src, dest, typ string,
|
||||||
@ -443,64 +445,66 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
testSandboxID := "test-sandbox-id"
|
testSandboxID := "test-sandbox-id"
|
||||||
testSandboxPid := uint32(4321)
|
testSandboxPid := uint32(4321)
|
||||||
config, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
|
config, sandboxConfig, imageConfig, specCheck := getCreateContainerTestData()
|
||||||
testSandboxMetadata := &metadata.SandboxMetadata{
|
testSandbox := &sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testSandboxID,
|
ID: testSandboxID,
|
||||||
Name: "test-sandbox-name",
|
Name: "test-sandbox-name",
|
||||||
Config: sandboxConfig,
|
Config: sandboxConfig,
|
||||||
Pid: testSandboxPid,
|
Pid: testSandboxPid,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testContainerName := makeContainerName(config.Metadata, sandboxConfig.Metadata)
|
testContainerName := makeContainerName(config.Metadata, sandboxConfig.Metadata)
|
||||||
// Use an image id to avoid image name resolution.
|
// Use an image id to avoid image name resolution.
|
||||||
// TODO(random-liu): Change this to image name after we have complete image
|
// TODO(random-liu): Change this to image name after we have complete image
|
||||||
// management unit test framework.
|
// management unit test framework.
|
||||||
testImage := config.GetImage().GetImage()
|
testImageRef := config.GetImage().GetImage()
|
||||||
testChainID := "test-chain-id"
|
testChainID := "test-chain-id"
|
||||||
testImageMetadata := metadata.ImageMetadata{
|
testImage := imagestore.Image{
|
||||||
ID: testImage,
|
ID: testImageRef,
|
||||||
ChainID: testChainID,
|
ChainID: testChainID,
|
||||||
Config: imageConfig,
|
Config: imageConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
sandboxMetadata *metadata.SandboxMetadata
|
sandbox *sandboxstore.Sandbox
|
||||||
reserveNameErr bool
|
reserveNameErr bool
|
||||||
imageMetadataErr bool
|
imageStoreErr bool
|
||||||
prepareSnapshotErr error
|
prepareSnapshotErr error
|
||||||
createRootDirErr error
|
createRootDirErr error
|
||||||
expectErr bool
|
expectErr bool
|
||||||
expectMeta *metadata.ContainerMetadata
|
expectedMeta containerstore.Metadata
|
||||||
}{
|
}{
|
||||||
"should return error if sandbox does not exist": {
|
"should return error if sandbox does not exist": {
|
||||||
sandboxMetadata: nil,
|
sandbox: nil,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if name is reserved": {
|
"should return error if name is reserved": {
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
reserveNameErr: true,
|
reserveNameErr: true,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if fail to create root directory": {
|
"should return error if fail to create root directory": {
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
createRootDirErr: errors.New("random error"),
|
createRootDirErr: errors.New("random error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if image is not pulled": {
|
"should return error if image is not pulled": {
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
imageMetadataErr: true,
|
imageStoreErr: true,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if prepare snapshot fails": {
|
"should return error if prepare snapshot fails": {
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
prepareSnapshotErr: errors.New("random error"),
|
prepareSnapshotErr: errors.New("random error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should be able to create container successfully": {
|
"should be able to create container successfully": {
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
expectMeta: &metadata.ContainerMetadata{
|
expectedMeta: containerstore.Metadata{
|
||||||
Name: testContainerName,
|
Name: testContainerName,
|
||||||
SandboxID: testSandboxID,
|
SandboxID: testSandboxID,
|
||||||
ImageRef: testImage,
|
ImageRef: testImageRef,
|
||||||
Config: config,
|
Config: config,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -510,14 +514,14 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
fake := c.containerService.(*servertesting.FakeContainersClient)
|
fake := c.containerService.(*servertesting.FakeContainersClient)
|
||||||
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
||||||
fakeOS := c.os.(*ostesting.FakeOS)
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
if test.sandboxMetadata != nil {
|
if test.sandbox != nil {
|
||||||
assert.NoError(t, c.sandboxStore.Create(*test.sandboxMetadata))
|
assert.NoError(t, c.sandboxStore.Add(*test.sandbox))
|
||||||
}
|
}
|
||||||
if test.reserveNameErr {
|
if test.reserveNameErr {
|
||||||
assert.NoError(t, c.containerNameIndex.Reserve(testContainerName, "random id"))
|
assert.NoError(t, c.containerNameIndex.Reserve(testContainerName, "random id"))
|
||||||
}
|
}
|
||||||
if !test.imageMetadataErr {
|
if !test.imageStoreErr {
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(testImageMetadata))
|
c.imageStore.Add(testImage)
|
||||||
}
|
}
|
||||||
if test.prepareSnapshotErr != nil {
|
if test.prepareSnapshotErr != nil {
|
||||||
fakeSnapshotClient.InjectError("prepare", test.prepareSnapshotErr)
|
fakeSnapshotClient.InjectError("prepare", test.prepareSnapshotErr)
|
||||||
@ -554,9 +558,7 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
listResp, err := fake.List(context.Background(), &containers.ListContainersRequest{})
|
listResp, err := fake.List(context.Background(), &containers.ListContainersRequest{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Empty(t, listResp.Containers, "containerd container should be cleaned up")
|
assert.Empty(t, listResp.Containers, "containerd container should be cleaned up")
|
||||||
metas, err := c.containerStore.List()
|
assert.Empty(t, c.containerStore.List(), "container metadata should not be created")
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Empty(t, metas, "container metadata should not be created")
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
@ -571,7 +573,7 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
createOpts, ok := containersCalls[0].Argument.(*containers.CreateContainerRequest)
|
createOpts, ok := containersCalls[0].Argument.(*containers.CreateContainerRequest)
|
||||||
assert.True(t, ok, "should create containerd container")
|
assert.True(t, ok, "should create containerd container")
|
||||||
assert.Equal(t, id, createOpts.Container.ID, "container id should be correct")
|
assert.Equal(t, id, createOpts.Container.ID, "container id should be correct")
|
||||||
assert.Equal(t, testImage, createOpts.Container.Image, "test image should be correct")
|
assert.Equal(t, testImageRef, createOpts.Container.Image, "test image should be correct")
|
||||||
assert.Equal(t, id, createOpts.Container.RootFS, "rootfs should be correct")
|
assert.Equal(t, id, createOpts.Container.RootFS, "rootfs should be correct")
|
||||||
spec := &runtimespec.Spec{}
|
spec := &runtimespec.Spec{}
|
||||||
assert.NoError(t, json.Unmarshal(createOpts.Container.Spec.Value, spec))
|
assert.NoError(t, json.Unmarshal(createOpts.Container.Spec.Value, spec))
|
||||||
@ -586,12 +588,11 @@ func TestCreateContainer(t *testing.T) {
|
|||||||
Parent: testChainID,
|
Parent: testChainID,
|
||||||
}, prepareOpts, "prepare request should be correct")
|
}, prepareOpts, "prepare request should be correct")
|
||||||
|
|
||||||
meta, err := c.containerStore.Get(id)
|
container, err := c.containerStore.Get(id)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
require.NotNil(t, meta)
|
test.expectedMeta.ID = id
|
||||||
test.expectMeta.ID = id
|
assert.Equal(t, test.expectedMeta, container.Metadata, "container metadata should be created")
|
||||||
// TODO(random-liu): Use fake clock to test CreatedAt.
|
assert.Equal(t, runtime.ContainerState_CONTAINER_CREATED, container.Status.Get().State(),
|
||||||
test.expectMeta.CreatedAt = meta.CreatedAt
|
"container should be in created state")
|
||||||
assert.Equal(t, test.expectMeta, meta, "container metadata should be created")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,15 +45,16 @@ func (c *criContainerdService) ExecSync(ctx context.Context, r *runtime.ExecSync
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Get container metadata from our container store.
|
// Get container from our container store.
|
||||||
meta, err := c.containerStore.Get(r.GetContainerId())
|
cntr, err := c.containerStore.Get(r.GetContainerId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
||||||
}
|
}
|
||||||
id := meta.ID
|
id := cntr.ID
|
||||||
|
|
||||||
if meta.State() != runtime.ContainerState_CONTAINER_RUNNING {
|
state := cntr.Status.Get().State()
|
||||||
return nil, fmt.Errorf("container %q is in %s state", id, criContainerStateToString(meta.State()))
|
if state != runtime.ContainerState_CONTAINER_RUNNING {
|
||||||
|
return nil, fmt.Errorf("container %q is in %s state", id, criContainerStateToString(state))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get exec process spec.
|
// Get exec process spec.
|
||||||
|
@ -17,14 +17,12 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListContainers lists all containers matching the filter.
|
// ListContainers lists all containers matching the filter.
|
||||||
@ -36,33 +34,31 @@ func (c *criContainerdService) ListContainers(ctx context.Context, r *runtime.Li
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// List all container metadata from store.
|
// List all containers from store.
|
||||||
metas, err := c.containerStore.List()
|
containersInStore := c.containerStore.List()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list metadata from container store: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var containers []*runtime.Container
|
var containers []*runtime.Container
|
||||||
for _, meta := range metas {
|
for _, container := range containersInStore {
|
||||||
containers = append(containers, toCRIContainer(meta))
|
containers = append(containers, toCRIContainer(container))
|
||||||
}
|
}
|
||||||
|
|
||||||
containers = c.filterCRIContainers(containers, r.GetFilter())
|
containers = c.filterCRIContainers(containers, r.GetFilter())
|
||||||
return &runtime.ListContainersResponse{Containers: containers}, nil
|
return &runtime.ListContainersResponse{Containers: containers}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toCRIContainer converts container metadata into CRI container.
|
// toCRIContainer converts internal container object into CRI container.
|
||||||
func toCRIContainer(meta *metadata.ContainerMetadata) *runtime.Container {
|
func toCRIContainer(container containerstore.Container) *runtime.Container {
|
||||||
|
status := container.Status.Get()
|
||||||
return &runtime.Container{
|
return &runtime.Container{
|
||||||
Id: meta.ID,
|
Id: container.ID,
|
||||||
PodSandboxId: meta.SandboxID,
|
PodSandboxId: container.SandboxID,
|
||||||
Metadata: meta.Config.GetMetadata(),
|
Metadata: container.Config.GetMetadata(),
|
||||||
Image: meta.Config.GetImage(),
|
Image: container.Config.GetImage(),
|
||||||
ImageRef: meta.ImageRef,
|
ImageRef: container.ImageRef,
|
||||||
State: meta.State(),
|
State: status.State(),
|
||||||
CreatedAt: meta.CreatedAt,
|
CreatedAt: status.CreatedAt,
|
||||||
Labels: meta.Config.GetLabels(),
|
Labels: container.Config.GetLabels(),
|
||||||
Annotations: meta.Config.GetAnnotations(),
|
Annotations: container.Config.GetAnnotations(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,9 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToCRIContainer(t *testing.T) {
|
func TestToCRIContainer(t *testing.T) {
|
||||||
@ -40,12 +39,15 @@ func TestToCRIContainer(t *testing.T) {
|
|||||||
Annotations: map[string]string{"c": "d"},
|
Annotations: map[string]string{"c": "d"},
|
||||||
}
|
}
|
||||||
createdAt := time.Now().UnixNano()
|
createdAt := time.Now().UnixNano()
|
||||||
meta := &metadata.ContainerMetadata{
|
container, err := containerstore.NewContainer(
|
||||||
|
containerstore.Metadata{
|
||||||
ID: "test-id",
|
ID: "test-id",
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
SandboxID: "test-sandbox-id",
|
SandboxID: "test-sandbox-id",
|
||||||
Config: config,
|
Config: config,
|
||||||
ImageRef: "test-image-ref",
|
ImageRef: "test-image-ref",
|
||||||
|
},
|
||||||
|
containerstore.Status{
|
||||||
Pid: 1234,
|
Pid: 1234,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
@ -53,7 +55,9 @@ func TestToCRIContainer(t *testing.T) {
|
|||||||
ExitCode: 1,
|
ExitCode: 1,
|
||||||
Reason: "test-reason",
|
Reason: "test-reason",
|
||||||
Message: "test-message",
|
Message: "test-message",
|
||||||
}
|
},
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
expect := &runtime.Container{
|
expect := &runtime.Container{
|
||||||
Id: "test-id",
|
Id: "test-id",
|
||||||
PodSandboxId: "test-sandbox-id",
|
PodSandboxId: "test-sandbox-id",
|
||||||
@ -65,7 +69,7 @@ func TestToCRIContainer(t *testing.T) {
|
|||||||
Labels: config.GetLabels(),
|
Labels: config.GetLabels(),
|
||||||
Annotations: config.GetAnnotations(),
|
Annotations: config.GetAnnotations(),
|
||||||
}
|
}
|
||||||
c := toCRIContainer(meta)
|
c := toCRIContainer(container)
|
||||||
assert.Equal(t, expect, c)
|
assert.Equal(t, expect, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,44 +151,68 @@ func TestFilterContainers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// containerForTest is a helper type for test.
|
||||||
|
type containerForTest struct {
|
||||||
|
metadata containerstore.Metadata
|
||||||
|
status containerstore.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c containerForTest) toContainer() (containerstore.Container, error) {
|
||||||
|
return containerstore.NewContainer(c.metadata, c.status)
|
||||||
|
}
|
||||||
|
|
||||||
func TestListContainers(t *testing.T) {
|
func TestListContainers(t *testing.T) {
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
|
|
||||||
createdAt := time.Now().UnixNano()
|
createdAt := time.Now().UnixNano()
|
||||||
startedAt := time.Now().UnixNano()
|
startedAt := time.Now().UnixNano()
|
||||||
finishedAt := time.Now().UnixNano()
|
finishedAt := time.Now().UnixNano()
|
||||||
containersInStore := []metadata.ContainerMetadata{
|
containersInStore := []containerForTest{
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "1",
|
ID: "1",
|
||||||
Name: "name-1",
|
Name: "name-1",
|
||||||
SandboxID: "s-1",
|
SandboxID: "s-1",
|
||||||
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-1"}},
|
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-1"}},
|
||||||
CreatedAt: createdAt,
|
},
|
||||||
|
status: containerstore.Status{CreatedAt: createdAt},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "2",
|
ID: "2",
|
||||||
Name: "name-2",
|
Name: "name-2",
|
||||||
SandboxID: "s-1",
|
SandboxID: "s-1",
|
||||||
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-2"}},
|
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-2"}},
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
StartedAt: startedAt,
|
StartedAt: startedAt,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "3",
|
ID: "3",
|
||||||
Name: "name-3",
|
Name: "name-3",
|
||||||
SandboxID: "s-1",
|
SandboxID: "s-1",
|
||||||
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-3"}},
|
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-3"}},
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
StartedAt: startedAt,
|
StartedAt: startedAt,
|
||||||
FinishedAt: finishedAt,
|
FinishedAt: finishedAt,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "4",
|
ID: "4",
|
||||||
Name: "name-4",
|
Name: "name-4",
|
||||||
SandboxID: "s-2",
|
SandboxID: "s-2",
|
||||||
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-4"}},
|
Config: &runtime.ContainerConfig{Metadata: &runtime.ContainerMetadata{Name: "name-4"}},
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
filter := &runtime.ContainerFilter{
|
filter := &runtime.ContainerFilter{
|
||||||
PodSandboxId: "s-1",
|
PodSandboxId: "s-1",
|
||||||
@ -215,7 +243,9 @@ func TestListContainers(t *testing.T) {
|
|||||||
|
|
||||||
// Inject test metadata
|
// Inject test metadata
|
||||||
for _, cntr := range containersInStore {
|
for _, cntr := range containersInStore {
|
||||||
c.containerStore.Create(cntr)
|
container, err := cntr.toContainer()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(container))
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.ListContainers(context.Background(), &runtime.ListContainersRequest{Filter: filter})
|
resp, err := c.ListContainers(context.Background(), &runtime.ListContainersRequest{Filter: filter})
|
||||||
|
@ -25,7 +25,8 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RemoveContainer removes the container.
|
// RemoveContainer removes the container.
|
||||||
@ -37,31 +38,29 @@ func (c *criContainerdService) RemoveContainer(ctx context.Context, r *runtime.R
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
id := r.GetContainerId()
|
container, err := c.containerStore.Get(r.GetContainerId())
|
||||||
|
if err != nil {
|
||||||
|
if err != store.ErrNotExist {
|
||||||
|
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
||||||
|
}
|
||||||
|
// Do not return error if container metadata doesn't exist.
|
||||||
|
glog.V(5).Infof("RemoveContainer called for container %q that does not exist", r.GetContainerId())
|
||||||
|
return &runtime.RemoveContainerResponse{}, nil
|
||||||
|
}
|
||||||
|
id := container.ID
|
||||||
|
|
||||||
// Set removing state to prevent other start/remove operations against this container
|
// Set removing state to prevent other start/remove operations against this container
|
||||||
// while it's being removed.
|
// while it's being removed.
|
||||||
if err := c.setContainerRemoving(id); err != nil {
|
if err := setContainerRemoving(container); err != nil {
|
||||||
if !metadata.IsNotExistError(err) {
|
return nil, fmt.Errorf("failed to set removing state for container %q: %v", id, err)
|
||||||
return nil, fmt.Errorf("failed to set removing state for container %q: %v",
|
|
||||||
id, err)
|
|
||||||
}
|
|
||||||
// Do not return error if container metadata doesn't exist.
|
|
||||||
glog.V(5).Infof("RemoveContainer called for container %q that does not exist", id)
|
|
||||||
return &runtime.RemoveContainerResponse{}, nil
|
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr == nil {
|
if retErr != nil {
|
||||||
// Cleanup all index after successfully remove the container.
|
|
||||||
c.containerNameIndex.ReleaseByKey(id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Reset removing if remove failed.
|
// Reset removing if remove failed.
|
||||||
if err := c.resetContainerRemoving(id); err != nil {
|
if err := resetContainerRemoving(container); err != nil {
|
||||||
// TODO(random-liu): Deal with update failure. Actually Removing doesn't need to
|
// TODO(random-liu): Do not checkpoint `Removing` state.
|
||||||
// be checkpointed, we only need it to have the same lifecycle with container metadata.
|
glog.Errorf("failed to reset removing state for container %q: %v", id, err)
|
||||||
glog.Errorf("failed to reset removing state for container %q: %v",
|
}
|
||||||
id, err)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -78,13 +77,17 @@ func (c *criContainerdService) RemoveContainer(ctx context.Context, r *runtime.R
|
|||||||
glog.V(5).Infof("Remove called for snapshot %q that does not exist", id)
|
glog.V(5).Infof("Remove called for snapshot %q that does not exist", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup container root directory.
|
|
||||||
containerRootDir := getContainerRootDir(c.rootDir, id)
|
containerRootDir := getContainerRootDir(c.rootDir, id)
|
||||||
if err := c.os.RemoveAll(containerRootDir); err != nil {
|
if err := c.os.RemoveAll(containerRootDir); err != nil {
|
||||||
return nil, fmt.Errorf("failed to remove container root directory %q: %v",
|
return nil, fmt.Errorf("failed to remove container root directory %q: %v",
|
||||||
containerRootDir, err)
|
containerRootDir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete container checkpoint.
|
||||||
|
if err := container.Delete(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to delete container checkpoint for %q: %v", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Delete containerd container.
|
// Delete containerd container.
|
||||||
if _, err := c.containerService.Delete(ctx, &containers.DeleteContainerRequest{ID: id}); err != nil {
|
if _, err := c.containerService.Delete(ctx, &containers.DeleteContainerRequest{ID: id}); err != nil {
|
||||||
if !isContainerdGRPCNotFoundError(err) {
|
if !isContainerdGRPCNotFoundError(err) {
|
||||||
@ -93,35 +96,34 @@ func (c *criContainerdService) RemoveContainer(ctx context.Context, r *runtime.R
|
|||||||
glog.V(5).Infof("Remove called for containerd container %q that does not exist", id, err)
|
glog.V(5).Infof("Remove called for containerd container %q that does not exist", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete container metadata.
|
c.containerStore.Delete(id)
|
||||||
if err := c.containerStore.Delete(id); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to delete container metadata for %q: %v", id, err)
|
c.containerNameIndex.ReleaseByKey(id)
|
||||||
}
|
|
||||||
|
|
||||||
return &runtime.RemoveContainerResponse{}, nil
|
return &runtime.RemoveContainerResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setContainerRemoving sets the container into removing state. In removing state, the
|
// setContainerRemoving sets the container into removing state. In removing state, the
|
||||||
// container will not be started or removed again.
|
// container will not be started or removed again.
|
||||||
func (c *criContainerdService) setContainerRemoving(id string) error {
|
func setContainerRemoving(container containerstore.Container) error {
|
||||||
return c.containerStore.Update(id, func(meta metadata.ContainerMetadata) (metadata.ContainerMetadata, error) {
|
return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||||
// Do not remove container if it's still running.
|
// Do not remove container if it's still running.
|
||||||
if meta.State() == runtime.ContainerState_CONTAINER_RUNNING {
|
if status.State() == runtime.ContainerState_CONTAINER_RUNNING {
|
||||||
return meta, fmt.Errorf("container %q is still running", id)
|
return status, fmt.Errorf("container is still running")
|
||||||
}
|
}
|
||||||
if meta.Removing {
|
if status.Removing {
|
||||||
return meta, fmt.Errorf("container is already in removing state")
|
return status, fmt.Errorf("container is already in removing state")
|
||||||
}
|
}
|
||||||
meta.Removing = true
|
status.Removing = true
|
||||||
return meta, nil
|
return status, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// resetContainerRemoving resets the container removing state on remove failure. So
|
// resetContainerRemoving resets the container removing state on remove failure. So
|
||||||
// that we could remove the container again.
|
// that we could remove the container again.
|
||||||
func (c *criContainerdService) resetContainerRemoving(id string) error {
|
func resetContainerRemoving(container containerstore.Container) error {
|
||||||
return c.containerStore.Update(id, func(meta metadata.ContainerMetadata) (metadata.ContainerMetadata, error) {
|
return container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||||
meta.Removing = false
|
status.Removing = false
|
||||||
return meta, nil
|
return status, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -25,13 +25,13 @@ import (
|
|||||||
snapshotapi "github.com/containerd/containerd/api/services/snapshot"
|
snapshotapi "github.com/containerd/containerd/api/services/snapshot"
|
||||||
"github.com/containerd/containerd/api/types/mount"
|
"github.com/containerd/containerd/api/types/mount"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestSetContainerRemoving tests setContainerRemoving sets removing
|
// TestSetContainerRemoving tests setContainerRemoving sets removing
|
||||||
@ -39,20 +39,18 @@ import (
|
|||||||
func TestSetContainerRemoving(t *testing.T) {
|
func TestSetContainerRemoving(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
metadata *metadata.ContainerMetadata
|
status containerstore.Status
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
"should return error when container is in running state": {
|
"should return error when container is in running state": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when container is in removing state": {
|
"should return error when container is in removing state": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
FinishedAt: time.Now().UnixNano(),
|
FinishedAt: time.Now().UnixNano(),
|
||||||
@ -61,8 +59,7 @@ func TestSetContainerRemoving(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should not return error when container is not running and removing": {
|
"should not return error when container is not running and removing": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
FinishedAt: time.Now().UnixNano(),
|
FinishedAt: time.Now().UnixNano(),
|
||||||
@ -71,19 +68,18 @@ func TestSetContainerRemoving(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Logf("TestCase %q", desc)
|
t.Logf("TestCase %q", desc)
|
||||||
c := newTestCRIContainerdService()
|
container, err := containerstore.NewContainer(
|
||||||
if test.metadata != nil {
|
containerstore.Metadata{ID: testID},
|
||||||
assert.NoError(t, c.containerStore.Create(*test.metadata))
|
test.status,
|
||||||
}
|
)
|
||||||
err := c.setContainerRemoving(testID)
|
assert.NoError(t, err)
|
||||||
meta, getErr := c.containerStore.Get(testID)
|
err = setContainerRemoving(container)
|
||||||
assert.NoError(t, getErr)
|
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, test.metadata, meta, "metadata should not be updated")
|
assert.Equal(t, test.status, container.Status.Get(), "metadata should not be updated")
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, meta.Removing, "removing should be set")
|
assert.True(t, container.Status.Get().Removing, "removing should be set")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,15 +87,14 @@ func TestSetContainerRemoving(t *testing.T) {
|
|||||||
func TestRemoveContainer(t *testing.T) {
|
func TestRemoveContainer(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testName := "test-name"
|
testName := "test-name"
|
||||||
testContainerMetadata := &metadata.ContainerMetadata{
|
testContainerStatus := &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
FinishedAt: time.Now().UnixNano(),
|
FinishedAt: time.Now().UnixNano(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
metadata *metadata.ContainerMetadata
|
status *containerstore.Status
|
||||||
removeSnapshotErr error
|
removeSnapshotErr error
|
||||||
deleteContainerErr error
|
deleteContainerErr error
|
||||||
removeDirErr error
|
removeDirErr error
|
||||||
@ -107,16 +102,14 @@ func TestRemoveContainer(t *testing.T) {
|
|||||||
expectUnsetRemoving bool
|
expectUnsetRemoving bool
|
||||||
}{
|
}{
|
||||||
"should return error when container is still running": {
|
"should return error when container is still running": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when there is ongoing removing": {
|
"should return error when there is ongoing removing": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
FinishedAt: time.Now().UnixNano(),
|
FinishedAt: time.Now().UnixNano(),
|
||||||
@ -124,40 +117,40 @@ func TestRemoveContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should not return error if container metadata does not exist": {
|
"should not return error if container does not exist": {
|
||||||
metadata: nil,
|
status: nil,
|
||||||
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
||||||
deleteContainerErr: servertesting.ContainerNotExistError,
|
deleteContainerErr: servertesting.ContainerNotExistError,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
"should not return error if snapshot does not exist": {
|
"should not return error if snapshot does not exist": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
"should return error if remove snapshot fails": {
|
"should return error if remove snapshot fails": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
removeSnapshotErr: errors.New("random error"),
|
removeSnapshotErr: errors.New("random error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should not return error if containerd container does not exist": {
|
"should not return error if containerd container does not exist": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
deleteContainerErr: servertesting.ContainerNotExistError,
|
deleteContainerErr: servertesting.ContainerNotExistError,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
"should return error if delete containerd container fails": {
|
"should return error if delete containerd container fails": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
deleteContainerErr: errors.New("random error"),
|
deleteContainerErr: errors.New("random error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if remove container root fails": {
|
"should return error if remove container root fails": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
removeDirErr: errors.New("random error"),
|
removeDirErr: errors.New("random error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectUnsetRemoving: true,
|
expectUnsetRemoving: true,
|
||||||
},
|
},
|
||||||
"should be able to remove container successfully": {
|
"should be able to remove container successfully": {
|
||||||
metadata: testContainerMetadata,
|
status: testContainerStatus,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
@ -166,9 +159,14 @@ func TestRemoveContainer(t *testing.T) {
|
|||||||
fake := c.containerService.(*servertesting.FakeContainersClient)
|
fake := c.containerService.(*servertesting.FakeContainersClient)
|
||||||
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
||||||
fakeOS := c.os.(*ostesting.FakeOS)
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
if test.metadata != nil {
|
if test.status != nil {
|
||||||
assert.NoError(t, c.containerNameIndex.Reserve(testName, testID))
|
assert.NoError(t, c.containerNameIndex.Reserve(testName, testID))
|
||||||
assert.NoError(t, c.containerStore.Create(*test.metadata))
|
container, err := containerstore.NewContainer(
|
||||||
|
containerstore.Metadata{ID: testID},
|
||||||
|
*test.status,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(container))
|
||||||
}
|
}
|
||||||
fakeOS.RemoveAllFn = func(path string) error {
|
fakeOS.RemoveAllFn = func(path string) error {
|
||||||
assert.Equal(t, getContainerRootDir(c.rootDir, testID), path)
|
assert.Equal(t, getContainerRootDir(c.rootDir, testID), path)
|
||||||
@ -202,19 +200,16 @@ func TestRemoveContainer(t *testing.T) {
|
|||||||
if !test.expectUnsetRemoving {
|
if !test.expectUnsetRemoving {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
meta, err := c.containerStore.Get(testID)
|
container, err := c.containerStore.Get(testID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
require.NotNil(t, meta)
|
|
||||||
// Also covers resetContainerRemoving.
|
// Also covers resetContainerRemoving.
|
||||||
assert.False(t, meta.Removing, "removing state should be unset")
|
assert.False(t, container.Status.Get().Removing, "removing state should be unset")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, resp)
|
assert.NotNil(t, resp)
|
||||||
meta, err := c.containerStore.Get(testID)
|
_, err = c.containerStore.Get(testID)
|
||||||
assert.Error(t, err)
|
assert.Equal(t, store.ErrNotExist, err)
|
||||||
assert.True(t, metadata.IsNotExistError(err))
|
|
||||||
assert.Nil(t, meta, "container metadata should be removed")
|
|
||||||
assert.NoError(t, c.containerNameIndex.Reserve(testName, testID),
|
assert.NoError(t, c.containerNameIndex.Reserve(testName, testID),
|
||||||
"container name should be released")
|
"container name should be released")
|
||||||
mountsResp, err := fakeSnapshotClient.Mounts(context.Background(), &snapshotapi.MountsRequest{Key: testID})
|
mountsResp, err := fakeSnapshotClient.Mounts(context.Background(), &snapshotapi.MountsRequest{Key: testID})
|
||||||
@ -229,6 +224,5 @@ func TestRemoveContainer(t *testing.T) {
|
|||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, resp, "remove should be idempotent")
|
assert.NotNil(t, resp, "remove should be idempotent")
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/server/agents"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/server/agents"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StartContainer starts the container.
|
// StartContainer starts the container.
|
||||||
@ -50,12 +50,12 @@ func (c *criContainerdService) StartContainer(ctx context.Context, r *runtime.St
|
|||||||
id := container.ID
|
id := container.ID
|
||||||
|
|
||||||
var startErr error
|
var startErr error
|
||||||
// start container in one transaction to avoid race with event monitor.
|
// update container status in one transaction to avoid race with event monitor.
|
||||||
if err := c.containerStore.Update(id, func(meta metadata.ContainerMetadata) (metadata.ContainerMetadata, error) {
|
if err := container.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||||
// Always apply metadata change no matter startContainer fails or not. Because startContainer
|
// Always apply status change no matter startContainer fails or not. Because startContainer
|
||||||
// may change container state no matter it fails or succeeds.
|
// may change container state no matter it fails or succeeds.
|
||||||
startErr = c.startContainer(ctx, id, &meta)
|
startErr = c.startContainer(ctx, id, container.Metadata, &status)
|
||||||
return meta, nil
|
return status, nil
|
||||||
}); startErr != nil {
|
}); startErr != nil {
|
||||||
return nil, startErr
|
return nil, startErr
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -65,36 +65,36 @@ func (c *criContainerdService) StartContainer(ctx context.Context, r *runtime.St
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startContainer actually starts the container. The function needs to be run in one transaction. Any updates
|
// startContainer actually starts the container. The function needs to be run in one transaction. Any updates
|
||||||
// to the metadata passed in will be applied to container store no matter the function returns error or not.
|
// to the status passed in will be applied no matter the function returns error or not.
|
||||||
func (c *criContainerdService) startContainer(ctx context.Context, id string, meta *metadata.ContainerMetadata) (retErr error) {
|
func (c *criContainerdService) startContainer(ctx context.Context, id string, meta containerstore.Metadata, status *containerstore.Status) (retErr error) {
|
||||||
config := meta.Config
|
config := meta.Config
|
||||||
// Return error if container is not in created state.
|
// Return error if container is not in created state.
|
||||||
if meta.State() != runtime.ContainerState_CONTAINER_CREATED {
|
if status.State() != runtime.ContainerState_CONTAINER_CREATED {
|
||||||
return fmt.Errorf("container %q is in %s state", id, criContainerStateToString(meta.State()))
|
return fmt.Errorf("container %q is in %s state", id, criContainerStateToString(status.State()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not start the container when there is a removal in progress.
|
// Do not start the container when there is a removal in progress.
|
||||||
if meta.Removing {
|
if status.Removing {
|
||||||
return fmt.Errorf("container %q is in removing state", id)
|
return fmt.Errorf("container %q is in removing state", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
// Set container to exited if fail to start.
|
// Set container to exited if fail to start.
|
||||||
meta.Pid = 0
|
status.Pid = 0
|
||||||
meta.FinishedAt = time.Now().UnixNano()
|
status.FinishedAt = time.Now().UnixNano()
|
||||||
meta.ExitCode = errorStartExitCode
|
status.ExitCode = errorStartExitCode
|
||||||
meta.Reason = errorStartReason
|
status.Reason = errorStartReason
|
||||||
meta.Message = retErr.Error()
|
status.Message = retErr.Error()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Get sandbox config from sandbox store.
|
// Get sandbox config from sandbox store.
|
||||||
sandboxMeta, err := c.sandboxStore.Get(meta.SandboxID)
|
sandbox, err := c.sandboxStore.Get(meta.SandboxID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sandbox %q not found: %v", meta.SandboxID, err)
|
return fmt.Errorf("sandbox %q not found: %v", meta.SandboxID, err)
|
||||||
}
|
}
|
||||||
sandboxConfig := sandboxMeta.Config
|
sandboxConfig := sandbox.Config
|
||||||
sandboxID := meta.SandboxID
|
sandboxID := meta.SandboxID
|
||||||
// Make sure sandbox is running.
|
// Make sure sandbox is running.
|
||||||
sandboxInfo, err := c.taskService.Info(ctx, &execution.InfoRequest{ContainerID: sandboxID})
|
sandboxInfo, err := c.taskService.Info(ctx, &execution.InfoRequest{ContainerID: sandboxID})
|
||||||
@ -137,12 +137,12 @@ func (c *criContainerdService) startContainer(ctx context.Context, id string, me
|
|||||||
if config.GetLogPath() != "" {
|
if config.GetLogPath() != "" {
|
||||||
// Only generate container log when log path is specified.
|
// Only generate container log when log path is specified.
|
||||||
logPath := filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath())
|
logPath := filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath())
|
||||||
if err := c.agentFactory.NewContainerLogger(logPath, agents.Stdout, stdoutPipe).Start(); err != nil {
|
if err = c.agentFactory.NewContainerLogger(logPath, agents.Stdout, stdoutPipe).Start(); err != nil {
|
||||||
return fmt.Errorf("failed to start container stdout logger: %v", err)
|
return fmt.Errorf("failed to start container stdout logger: %v", err)
|
||||||
}
|
}
|
||||||
// Only redirect stderr when there is no tty.
|
// Only redirect stderr when there is no tty.
|
||||||
if !config.GetTty() {
|
if !config.GetTty() {
|
||||||
if err := c.agentFactory.NewContainerLogger(logPath, agents.Stderr, stderrPipe).Start(); err != nil {
|
if err = c.agentFactory.NewContainerLogger(logPath, agents.Stderr, stderrPipe).Start(); err != nil {
|
||||||
return fmt.Errorf("failed to start container stderr logger: %v", err)
|
return fmt.Errorf("failed to start container stderr logger: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ func (c *criContainerdService) startContainer(ctx context.Context, id string, me
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update container start timestamp.
|
// Update container start timestamp.
|
||||||
meta.Pid = createResp.Pid
|
status.Pid = createResp.Pid
|
||||||
meta.StartedAt = time.Now().UnixNano()
|
status.StartedAt = time.Now().UnixNano()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -27,27 +27,29 @@ import (
|
|||||||
"github.com/containerd/containerd/api/types/mount"
|
"github.com/containerd/containerd/api/types/mount"
|
||||||
"github.com/containerd/containerd/api/types/task"
|
"github.com/containerd/containerd/api/types/task"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStartContainer(t *testing.T) {
|
func TestStartContainer(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testSandboxID := "test-sandbox-id"
|
testSandboxID := "test-sandbox-id"
|
||||||
testMetadata := &metadata.ContainerMetadata{
|
testMetadata := containerstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
SandboxID: testSandboxID,
|
SandboxID: testSandboxID,
|
||||||
CreatedAt: time.Now().UnixNano(),
|
|
||||||
}
|
}
|
||||||
testSandboxMetadata := &metadata.SandboxMetadata{
|
testStatus := &containerstore.Status{CreatedAt: time.Now().UnixNano()}
|
||||||
|
testSandbox := &sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testSandboxID,
|
ID: testSandboxID,
|
||||||
Name: "test-sandbox-name",
|
Name: "test-sandbox-name",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testSandboxContainer := &task.Task{
|
testSandboxContainer := &task.Task{
|
||||||
ID: testSandboxID,
|
ID: testSandboxID,
|
||||||
@ -56,8 +58,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
testMounts := []*mount.Mount{{Type: "bind", Source: "test-source"}}
|
testMounts := []*mount.Mount{{Type: "bind", Source: "test-source"}}
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
containerMetadata *metadata.ContainerMetadata
|
status *containerstore.Status
|
||||||
sandboxMetadata *metadata.SandboxMetadata
|
sandbox *sandboxstore.Sandbox
|
||||||
sandboxContainerdContainer *task.Task
|
sandboxContainerdContainer *task.Task
|
||||||
snapshotMountsErr bool
|
snapshotMountsErr bool
|
||||||
prepareFIFOErr error
|
prepareFIFOErr error
|
||||||
@ -67,50 +69,44 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectCalls []string
|
expectCalls []string
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
"should return error when container metadata does not exist": {
|
"should return error when container does not exist": {
|
||||||
containerMetadata: nil,
|
status: nil,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when container is not in created state": {
|
"should return error when container is not in created state": {
|
||||||
containerMetadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
Name: "test-name",
|
|
||||||
SandboxID: testSandboxID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when container is in removing state": {
|
"should return error when container is in removing state": {
|
||||||
containerMetadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
Name: "test-name",
|
|
||||||
SandboxID: testSandboxID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
Removing: true,
|
Removing: true,
|
||||||
},
|
},
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when sandbox does not exist": {
|
"should return error when sandbox does not exist": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: nil,
|
sandbox: nil,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when sandbox is not running": {
|
"should return error when sandbox is not running": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: &task.Task{
|
sandboxContainerdContainer: &task.Task{
|
||||||
ID: testSandboxID,
|
ID: testSandboxID,
|
||||||
Pid: uint32(4321),
|
Pid: uint32(4321),
|
||||||
@ -121,8 +117,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when snapshot mounts fails": {
|
"should return error when snapshot mounts fails": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
snapshotMountsErr: true,
|
snapshotMountsErr: true,
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
@ -130,8 +126,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when fail to open streaming pipes": {
|
"should return error when fail to open streaming pipes": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
prepareFIFOErr: errors.New("open error"),
|
prepareFIFOErr: errors.New("open error"),
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
@ -139,8 +135,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when fail to create container": {
|
"should return error when fail to create container": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
createContainerErr: errors.New("create error"),
|
createContainerErr: errors.New("create error"),
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
@ -148,8 +144,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error when fail to start container": {
|
"should return error when fail to start container": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
startContainerErr: errors.New("start error"),
|
startContainerErr: errors.New("start error"),
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
@ -158,8 +154,8 @@ func TestStartContainer(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should be able to start container successfully": {
|
"should be able to start container successfully": {
|
||||||
containerMetadata: testMetadata,
|
status: testStatus,
|
||||||
sandboxMetadata: testSandboxMetadata,
|
sandbox: testSandbox,
|
||||||
sandboxContainerdContainer: testSandboxContainer,
|
sandboxContainerdContainer: testSandboxContainer,
|
||||||
expectStateChange: true,
|
expectStateChange: true,
|
||||||
expectCalls: []string{"info", "create", "start"},
|
expectCalls: []string{"info", "create", "start"},
|
||||||
@ -171,11 +167,16 @@ func TestStartContainer(t *testing.T) {
|
|||||||
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
||||||
fakeOS := c.os.(*ostesting.FakeOS)
|
fakeOS := c.os.(*ostesting.FakeOS)
|
||||||
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
||||||
if test.containerMetadata != nil {
|
if test.status != nil {
|
||||||
assert.NoError(t, c.containerStore.Create(*test.containerMetadata))
|
cntr, err := containerstore.NewContainer(
|
||||||
|
testMetadata,
|
||||||
|
*test.status,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(cntr))
|
||||||
}
|
}
|
||||||
if test.sandboxMetadata != nil {
|
if test.sandbox != nil {
|
||||||
assert.NoError(t, c.sandboxStore.Create(*test.sandboxMetadata))
|
assert.NoError(t, c.sandboxStore.Add(*test.sandbox))
|
||||||
}
|
}
|
||||||
if test.sandboxContainerdContainer != nil {
|
if test.sandboxContainerdContainer != nil {
|
||||||
fake.SetFakeTasks([]task.Task{*test.sandboxContainerdContainer})
|
fake.SetFakeTasks([]task.Task{*test.sandboxContainerdContainer})
|
||||||
@ -206,35 +207,39 @@ func TestStartContainer(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, resp)
|
assert.NotNil(t, resp)
|
||||||
}
|
}
|
||||||
// Check container state.
|
// Skip following validation if no container is injected initially.
|
||||||
meta, err := c.containerStore.Get(testID)
|
if test.status == nil {
|
||||||
if !test.expectStateChange {
|
|
||||||
// Do not check the error, because container may not exist
|
|
||||||
// in the test case.
|
|
||||||
assert.Equal(t, meta, test.containerMetadata)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Check container state.
|
||||||
|
cntr, err := c.containerStore.Get(testID)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
require.NotNil(t, meta)
|
status := cntr.Status.Get()
|
||||||
|
if !test.expectStateChange {
|
||||||
|
assert.Equal(t, testMetadata, cntr.Metadata)
|
||||||
|
assert.Equal(t, *test.status, status)
|
||||||
|
continue
|
||||||
|
}
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
t.Logf("container state should be in exited state when fail to start")
|
t.Logf("container state should be in exited state when fail to start")
|
||||||
assert.Equal(t, runtime.ContainerState_CONTAINER_EXITED, meta.State())
|
assert.Equal(t, runtime.ContainerState_CONTAINER_EXITED, status.State())
|
||||||
assert.Zero(t, meta.Pid)
|
assert.Zero(t, status.Pid)
|
||||||
assert.EqualValues(t, errorStartExitCode, meta.ExitCode)
|
assert.EqualValues(t, errorStartExitCode, status.ExitCode)
|
||||||
assert.Equal(t, errorStartReason, meta.Reason)
|
assert.Equal(t, errorStartReason, status.Reason)
|
||||||
assert.NotEmpty(t, meta.Message)
|
assert.NotEmpty(t, status.Message)
|
||||||
_, err := fake.Info(context.Background(), &execution.InfoRequest{ContainerID: testID})
|
_, err := fake.Info(context.Background(), &execution.InfoRequest{ContainerID: testID})
|
||||||
assert.True(t, isContainerdGRPCNotFoundError(err),
|
assert.True(t, isContainerdGRPCNotFoundError(err),
|
||||||
"containerd task should be cleaned up when fail to start")
|
"containerd task should be cleaned up when fail to start")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
t.Logf("container state should be running when start successfully")
|
t.Logf("container state should be running when start successfully")
|
||||||
assert.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, meta.State())
|
assert.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, status.State())
|
||||||
info, err := fake.Info(context.Background(), &execution.InfoRequest{ContainerID: testID})
|
info, err := fake.Info(context.Background(), &execution.InfoRequest{ContainerID: testID})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
pid := info.Task.Pid
|
pid := info.Task.Pid
|
||||||
assert.Equal(t, pid, meta.Pid)
|
assert.Equal(t, pid, status.Pid)
|
||||||
assert.Equal(t, task.StatusRunning, info.Task.Status)
|
assert.Equal(t, task.StatusRunning, info.Task.Status)
|
||||||
|
// Check runtime spec
|
||||||
calls := fake.GetCalledDetails()
|
calls := fake.GetCalledDetails()
|
||||||
createOpts, ok := calls[1].Argument.(*execution.CreateRequest)
|
createOpts, ok := calls[1].Argument.(*execution.CreateRequest)
|
||||||
assert.True(t, ok, "2nd call should be create")
|
assert.True(t, ok, "2nd call should be create")
|
||||||
|
@ -21,10 +21,9 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStatus inspects the container and returns the status.
|
// ContainerStatus inspects the container and returns the status.
|
||||||
@ -36,22 +35,23 @@ func (c *criContainerdService) ContainerStatus(ctx context.Context, r *runtime.C
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
meta, err := c.containerStore.Get(r.GetContainerId())
|
container, err := c.containerStore.Get(r.GetContainerId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &runtime.ContainerStatusResponse{
|
return &runtime.ContainerStatusResponse{
|
||||||
Status: toCRIContainerStatus(meta),
|
Status: toCRIContainerStatus(container),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toCRIContainerStatus converts container metadata to CRI container status.
|
// toCRIContainerStatus converts internal container object to CRI container status.
|
||||||
func toCRIContainerStatus(meta *metadata.ContainerMetadata) *runtime.ContainerStatus {
|
func toCRIContainerStatus(container containerstore.Container) *runtime.ContainerStatus {
|
||||||
state := meta.State()
|
meta := container.Metadata
|
||||||
reason := meta.Reason
|
status := container.Status.Get()
|
||||||
if state == runtime.ContainerState_CONTAINER_EXITED && reason == "" {
|
reason := status.Reason
|
||||||
if meta.ExitCode == 0 {
|
if status.State() == runtime.ContainerState_CONTAINER_EXITED && reason == "" {
|
||||||
|
if status.ExitCode == 0 {
|
||||||
reason = completeExitReason
|
reason = completeExitReason
|
||||||
} else {
|
} else {
|
||||||
reason = errorExitReason
|
reason = errorExitReason
|
||||||
@ -60,15 +60,15 @@ func toCRIContainerStatus(meta *metadata.ContainerMetadata) *runtime.ContainerSt
|
|||||||
return &runtime.ContainerStatus{
|
return &runtime.ContainerStatus{
|
||||||
Id: meta.ID,
|
Id: meta.ID,
|
||||||
Metadata: meta.Config.GetMetadata(),
|
Metadata: meta.Config.GetMetadata(),
|
||||||
State: state,
|
State: status.State(),
|
||||||
CreatedAt: meta.CreatedAt,
|
CreatedAt: status.CreatedAt,
|
||||||
StartedAt: meta.StartedAt,
|
StartedAt: status.StartedAt,
|
||||||
FinishedAt: meta.FinishedAt,
|
FinishedAt: status.FinishedAt,
|
||||||
ExitCode: meta.ExitCode,
|
ExitCode: status.ExitCode,
|
||||||
Image: meta.Config.GetImage(),
|
Image: meta.Config.GetImage(),
|
||||||
ImageRef: meta.ImageRef,
|
ImageRef: meta.ImageRef,
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
Message: meta.Message,
|
Message: status.Message,
|
||||||
Labels: meta.Config.GetLabels(),
|
Labels: meta.Config.GetLabels(),
|
||||||
Annotations: meta.Config.GetAnnotations(),
|
Annotations: meta.Config.GetAnnotations(),
|
||||||
Mounts: meta.Config.GetMounts(),
|
Mounts: meta.Config.GetMounts(),
|
||||||
|
@ -22,13 +22,12 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getContainerStatusTestData() (*metadata.ContainerMetadata, *runtime.ContainerStatus) {
|
func getContainerStatusTestData() (*containerstore.Metadata, *containerstore.Status, *runtime.ContainerStatus) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
config := &runtime.ContainerConfig{
|
config := &runtime.ContainerConfig{
|
||||||
Metadata: &runtime.ContainerMetadata{
|
Metadata: &runtime.ContainerMetadata{
|
||||||
@ -47,17 +46,18 @@ func getContainerStatusTestData() (*metadata.ContainerMetadata, *runtime.Contain
|
|||||||
createdAt := time.Now().UnixNano()
|
createdAt := time.Now().UnixNano()
|
||||||
startedAt := time.Now().UnixNano()
|
startedAt := time.Now().UnixNano()
|
||||||
|
|
||||||
metadata := &metadata.ContainerMetadata{
|
metadata := &containerstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: "test-long-name",
|
Name: "test-long-name",
|
||||||
SandboxID: "test-sandbox-id",
|
SandboxID: "test-sandbox-id",
|
||||||
Config: config,
|
Config: config,
|
||||||
ImageRef: "test-image-ref",
|
ImageRef: "test-image-ref",
|
||||||
|
}
|
||||||
|
status := &containerstore.Status{
|
||||||
Pid: 1234,
|
Pid: 1234,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
StartedAt: startedAt,
|
StartedAt: startedAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := &runtime.ContainerStatus{
|
expected := &runtime.ContainerStatus{
|
||||||
Id: testID,
|
Id: testID,
|
||||||
Metadata: config.GetMetadata(),
|
Metadata: config.GetMetadata(),
|
||||||
@ -72,7 +72,7 @@ func getContainerStatusTestData() (*metadata.ContainerMetadata, *runtime.Contain
|
|||||||
Mounts: config.GetMounts(),
|
Mounts: config.GetMounts(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata, expected
|
return metadata, status, expected
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestToCRIContainerStatus(t *testing.T) {
|
func TestToCRIContainerStatus(t *testing.T) {
|
||||||
@ -110,19 +110,21 @@ func TestToCRIContainerStatus(t *testing.T) {
|
|||||||
expectedReason: errorExitReason,
|
expectedReason: errorExitReason,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
meta, expected := getContainerStatusTestData()
|
metadata, status, expected := getContainerStatusTestData()
|
||||||
// Update metadata with test case.
|
// Update status with test case.
|
||||||
meta.FinishedAt = test.finishedAt
|
status.FinishedAt = test.finishedAt
|
||||||
meta.ExitCode = test.exitCode
|
status.ExitCode = test.exitCode
|
||||||
meta.Reason = test.reason
|
status.Reason = test.reason
|
||||||
meta.Message = test.message
|
status.Message = test.message
|
||||||
|
container, err := containerstore.NewContainer(*metadata, *status)
|
||||||
|
assert.NoError(t, err)
|
||||||
// Set expectation based on test case.
|
// Set expectation based on test case.
|
||||||
expected.State = test.expectedState
|
expected.State = test.expectedState
|
||||||
expected.Reason = test.expectedReason
|
expected.Reason = test.expectedReason
|
||||||
expected.FinishedAt = test.finishedAt
|
expected.FinishedAt = test.finishedAt
|
||||||
expected.ExitCode = test.exitCode
|
expected.ExitCode = test.exitCode
|
||||||
expected.Message = test.message
|
expected.Message = test.message
|
||||||
assert.Equal(t, expected, toCRIContainerStatus(meta), desc)
|
assert.Equal(t, expected, toCRIContainerStatus(container), desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,14 +153,16 @@ func TestContainerStatus(t *testing.T) {
|
|||||||
} {
|
} {
|
||||||
t.Logf("TestCase %q", desc)
|
t.Logf("TestCase %q", desc)
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
meta, expected := getContainerStatusTestData()
|
metadata, status, expected := getContainerStatusTestData()
|
||||||
// Update metadata with test case.
|
// Update status with test case.
|
||||||
meta.FinishedAt = test.finishedAt
|
status.FinishedAt = test.finishedAt
|
||||||
meta.Reason = test.reason
|
status.Reason = test.reason
|
||||||
|
container, err := containerstore.NewContainer(*metadata, *status)
|
||||||
|
assert.NoError(t, err)
|
||||||
if test.exist {
|
if test.exist {
|
||||||
assert.NoError(t, c.containerStore.Create(*meta))
|
assert.NoError(t, c.containerStore.Add(container))
|
||||||
}
|
}
|
||||||
resp, err := c.ContainerStatus(context.Background(), &runtime.ContainerStatusRequest{ContainerId: meta.ID})
|
resp, err := c.ContainerStatus(context.Background(), &runtime.ContainerStatusRequest{ContainerId: container.ID})
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Nil(t, resp)
|
assert.Nil(t, resp)
|
||||||
|
@ -27,7 +27,8 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -50,12 +51,12 @@ func (c *criContainerdService) StopContainer(ctx context.Context, r *runtime.Sto
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
// Get container config from container store.
|
// Get container config from container store.
|
||||||
meta, err := c.containerStore.Get(r.GetContainerId())
|
container, err := c.containerStore.Get(r.GetContainerId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
return nil, fmt.Errorf("an error occurred when try to find container %q: %v", r.GetContainerId(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.stopContainer(ctx, meta, time.Duration(r.GetTimeout())*time.Second); err != nil {
|
if err := c.stopContainer(ctx, container, time.Duration(r.GetTimeout())*time.Second); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,32 +64,33 @@ func (c *criContainerdService) StopContainer(ctx context.Context, r *runtime.Sto
|
|||||||
}
|
}
|
||||||
|
|
||||||
// stopContainer stops a container based on the container metadata.
|
// stopContainer stops a container based on the container metadata.
|
||||||
func (c *criContainerdService) stopContainer(ctx context.Context, meta *metadata.ContainerMetadata, timeout time.Duration) error {
|
func (c *criContainerdService) stopContainer(ctx context.Context, container containerstore.Container, timeout time.Duration) error {
|
||||||
id := meta.ID
|
id := container.ID
|
||||||
|
|
||||||
// Return without error if container is not running. This makes sure that
|
// Return without error if container is not running. This makes sure that
|
||||||
// stop only takes real action after the container is started.
|
// stop only takes real action after the container is started.
|
||||||
if meta.State() != runtime.ContainerState_CONTAINER_RUNNING {
|
state := container.Status.Get().State()
|
||||||
|
if state != runtime.ContainerState_CONTAINER_RUNNING {
|
||||||
glog.V(2).Infof("Container to stop %q is not running, current state %q",
|
glog.V(2).Infof("Container to stop %q is not running, current state %q",
|
||||||
id, criContainerStateToString(meta.State()))
|
id, criContainerStateToString(state))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeout > 0 {
|
if timeout > 0 {
|
||||||
stopSignal := unix.SIGTERM
|
stopSignal := unix.SIGTERM
|
||||||
imageMeta, err := c.imageMetadataStore.Get(meta.ImageRef)
|
image, err := c.imageStore.Get(container.ImageRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// NOTE(random-liu): It's possible that the container is stopped,
|
// NOTE(random-liu): It's possible that the container is stopped,
|
||||||
// deleted and image is garbage collected before this point. However,
|
// deleted and image is garbage collected before this point. However,
|
||||||
// the chance is really slim, even it happens, it's still fine to return
|
// the chance is really slim, even it happens, it's still fine to return
|
||||||
// an error here.
|
// an error here.
|
||||||
return fmt.Errorf("failed to get image metadata %q: %v", meta.ImageRef, err)
|
return fmt.Errorf("failed to get image metadata %q: %v", container.ImageRef, err)
|
||||||
}
|
}
|
||||||
if imageMeta.Config.StopSignal != "" {
|
if image.Config.StopSignal != "" {
|
||||||
stopSignal, err = signal.ParseSignal(imageMeta.Config.StopSignal)
|
stopSignal, err = signal.ParseSignal(image.Config.StopSignal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse stop signal %q: %v",
|
return fmt.Errorf("failed to parse stop signal %q: %v",
|
||||||
imageMeta.Config.StopSignal, err)
|
image.Config.StopSignal, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glog.V(2).Infof("Stop container %q with signal %v", id, stopSignal)
|
glog.V(2).Infof("Stop container %q with signal %v", id, stopSignal)
|
||||||
@ -140,10 +142,10 @@ func (c *criContainerdService) waitContainerStop(ctx context.Context, id string,
|
|||||||
defer timeoutTimer.Stop()
|
defer timeoutTimer.Stop()
|
||||||
for {
|
for {
|
||||||
// Poll once before waiting for stopCheckPollInterval.
|
// Poll once before waiting for stopCheckPollInterval.
|
||||||
meta, err := c.containerStore.Get(id)
|
container, err := c.containerStore.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !metadata.IsNotExistError(err) {
|
if err != store.ErrNotExist {
|
||||||
return fmt.Errorf("failed to get container %q metadata: %v", id, err)
|
return fmt.Errorf("failed to get container %q: %v", id, err)
|
||||||
}
|
}
|
||||||
// Do not return error here because container was removed means
|
// Do not return error here because container was removed means
|
||||||
// it is already stopped.
|
// it is already stopped.
|
||||||
@ -151,7 +153,7 @@ func (c *criContainerdService) waitContainerStop(ctx context.Context, id string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// TODO(random-liu): Use channel with event handler instead of polling.
|
// TODO(random-liu): Use channel with event handler instead of polling.
|
||||||
if meta.State() == runtime.ContainerState_CONTAINER_EXITED {
|
if container.Status.Get().State() == runtime.ContainerState_CONTAINER_EXITED {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
|
@ -29,21 +29,21 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWaitContainerStop(t *testing.T) {
|
func TestWaitContainerStop(t *testing.T) {
|
||||||
id := "test-id"
|
id := "test-id"
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
metadata *metadata.ContainerMetadata
|
status *containerstore.Status
|
||||||
cancel bool
|
cancel bool
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
expectErr bool
|
expectErr bool
|
||||||
}{
|
}{
|
||||||
"should return error if timeout exceeds": {
|
"should return error if timeout exceeds": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: id,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
@ -51,8 +51,7 @@ func TestWaitContainerStop(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should return error if context is cancelled": {
|
"should return error if context is cancelled": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: id,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
@ -61,13 +60,12 @@ func TestWaitContainerStop(t *testing.T) {
|
|||||||
expectErr: true,
|
expectErr: true,
|
||||||
},
|
},
|
||||||
"should not return error if container is removed before timeout": {
|
"should not return error if container is removed before timeout": {
|
||||||
metadata: nil,
|
status: nil,
|
||||||
timeout: time.Hour,
|
timeout: time.Hour,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
},
|
},
|
||||||
"should not return error if container is stopped before timeout": {
|
"should not return error if container is stopped before timeout": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{
|
||||||
ID: id,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
FinishedAt: time.Now().UnixNano(),
|
FinishedAt: time.Now().UnixNano(),
|
||||||
@ -77,8 +75,13 @@ func TestWaitContainerStop(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
if test.metadata != nil {
|
if test.status != nil {
|
||||||
assert.NoError(t, c.containerStore.Create(*test.metadata))
|
container, err := containerstore.NewContainer(
|
||||||
|
containerstore.Metadata{ID: id},
|
||||||
|
*test.status,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(container))
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if test.cancel {
|
if test.cancel {
|
||||||
@ -94,15 +97,14 @@ func TestWaitContainerStop(t *testing.T) {
|
|||||||
func TestStopContainer(t *testing.T) {
|
func TestStopContainer(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testPid := uint32(1234)
|
testPid := uint32(1234)
|
||||||
testMetadata := metadata.ContainerMetadata{
|
testImageID := "test-image-id"
|
||||||
ID: testID,
|
testStatus := containerstore.Status{
|
||||||
Pid: testPid,
|
Pid: testPid,
|
||||||
ImageRef: "test-image-id",
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
CreatedAt: time.Now().UnixNano(),
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
}
|
}
|
||||||
testImageMetadata := metadata.ImageMetadata{
|
testImage := imagestore.Image{
|
||||||
ID: "test-image-id",
|
ID: testImageID,
|
||||||
Config: &imagespec.ImageConfig{},
|
Config: &imagespec.ImageConfig{},
|
||||||
}
|
}
|
||||||
testContainer := task.Task{
|
testContainer := task.Task{
|
||||||
@ -111,7 +113,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
Status: task.StatusRunning,
|
Status: task.StatusRunning,
|
||||||
}
|
}
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
metadata *metadata.ContainerMetadata
|
status *containerstore.Status
|
||||||
containerdContainer *task.Task
|
containerdContainer *task.Task
|
||||||
stopSignal string
|
stopSignal string
|
||||||
stopErr error
|
stopErr error
|
||||||
@ -120,20 +122,17 @@ func TestStopContainer(t *testing.T) {
|
|||||||
expectCalls []servertesting.CalledDetail
|
expectCalls []servertesting.CalledDetail
|
||||||
}{
|
}{
|
||||||
"should return error when container does not exist": {
|
"should return error when container does not exist": {
|
||||||
metadata: nil,
|
status: nil,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []servertesting.CalledDetail{},
|
expectCalls: []servertesting.CalledDetail{},
|
||||||
},
|
},
|
||||||
"should not return error when container is not running": {
|
"should not return error when container is not running": {
|
||||||
metadata: &metadata.ContainerMetadata{
|
status: &containerstore.Status{CreatedAt: time.Now().UnixNano()},
|
||||||
ID: testID,
|
|
||||||
CreatedAt: time.Now().UnixNano(),
|
|
||||||
},
|
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
expectCalls: []servertesting.CalledDetail{},
|
expectCalls: []servertesting.CalledDetail{},
|
||||||
},
|
},
|
||||||
"should not return error if containerd task does not exist": {
|
"should not return error if containerd task does not exist": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
// Since it's hard to inject event during `StopContainer` is running,
|
// Since it's hard to inject event during `StopContainer` is running,
|
||||||
// we only test the case that first stop returns error, but container
|
// we only test the case that first stop returns error, but container
|
||||||
@ -166,7 +165,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"should not return error if containerd task process already finished": {
|
"should not return error if containerd task process already finished": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
stopErr: errors.New("os: process already finished"),
|
stopErr: errors.New("os: process already finished"),
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
@ -194,7 +193,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"should return error if graceful stop returns random error": {
|
"should return error if graceful stop returns random error": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
stopErr: errors.New("random stop error"),
|
stopErr: errors.New("random stop error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
@ -210,7 +209,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"should not return error if containerd task is gracefully stopped": {
|
"should not return error if containerd task is gracefully stopped": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
// deleted by the event monitor.
|
// deleted by the event monitor.
|
||||||
@ -230,7 +229,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"should use stop signal specified in image config if not empty": {
|
"should use stop signal specified in image config if not empty": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
stopSignal: "SIGHUP",
|
stopSignal: "SIGHUP",
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
@ -251,7 +250,7 @@ func TestStopContainer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"should directly kill container if timeout is 0": {
|
"should directly kill container if timeout is 0": {
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainer,
|
containerdContainer: &testContainer,
|
||||||
noTimeout: true,
|
noTimeout: true,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
@ -279,16 +278,24 @@ func TestStopContainer(t *testing.T) {
|
|||||||
defer fake.Stop()
|
defer fake.Stop()
|
||||||
c.taskService = fake
|
c.taskService = fake
|
||||||
|
|
||||||
// Inject metadata.
|
// Inject the container.
|
||||||
if test.metadata != nil {
|
if test.status != nil {
|
||||||
assert.NoError(t, c.containerStore.Create(*test.metadata))
|
cntr, err := containerstore.NewContainer(
|
||||||
|
containerstore.Metadata{
|
||||||
|
ID: testID,
|
||||||
|
ImageRef: testImageID,
|
||||||
|
},
|
||||||
|
*test.status,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(cntr))
|
||||||
}
|
}
|
||||||
// Inject containerd task.
|
// Inject containerd task.
|
||||||
if test.containerdContainer != nil {
|
if test.containerdContainer != nil {
|
||||||
fake.SetFakeTasks([]task.Task{*test.containerdContainer})
|
fake.SetFakeTasks([]task.Task{*test.containerdContainer})
|
||||||
}
|
}
|
||||||
testImageMetadata.Config.StopSignal = test.stopSignal
|
testImage.Config.StopSignal = test.stopSignal
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(testImageMetadata))
|
c.imageStore.Add(testImage)
|
||||||
if test.stopErr != nil {
|
if test.stopErr != nil {
|
||||||
fake.InjectError("kill", test.stopErr)
|
fake.InjectError("kill", test.stopErr)
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"github.com/jpillora/backoff"
|
"github.com/jpillora/backoff"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -87,12 +87,12 @@ func (c *criContainerdService) handleEvent(e *task.Event) {
|
|||||||
// fine to leave out that case for now.
|
// fine to leave out that case for now.
|
||||||
// TODO(random-liu): [P2] Handle containerd-shim exit.
|
// TODO(random-liu): [P2] Handle containerd-shim exit.
|
||||||
case task.Event_EXIT:
|
case task.Event_EXIT:
|
||||||
meta, err := c.containerStore.Get(e.ID)
|
cntr, err := c.containerStore.Get(e.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to get container %q metadata: %v", e.ID, err)
|
glog.Errorf("Failed to get container %q: %v", e.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if e.Pid != meta.Pid {
|
if e.Pid != cntr.Status.Get().Pid {
|
||||||
// Non-init process died, ignore the event.
|
// Non-init process died, ignore the event.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -103,16 +103,16 @@ func (c *criContainerdService) handleEvent(e *task.Event) {
|
|||||||
glog.Errorf("Failed to delete container %q: %v", e.ID, err)
|
glog.Errorf("Failed to delete container %q: %v", e.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = c.containerStore.Update(e.ID, func(meta metadata.ContainerMetadata) (metadata.ContainerMetadata, error) {
|
err = cntr.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||||
// If FinishedAt has been set (e.g. with start failure), keep as
|
// If FinishedAt has been set (e.g. with start failure), keep as
|
||||||
// it is.
|
// it is.
|
||||||
if meta.FinishedAt != 0 {
|
if status.FinishedAt != 0 {
|
||||||
return meta, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
meta.Pid = 0
|
status.Pid = 0
|
||||||
meta.FinishedAt = e.ExitedAt.UnixNano()
|
status.FinishedAt = e.ExitedAt.UnixNano()
|
||||||
meta.ExitCode = int32(e.ExitStatus)
|
status.ExitCode = int32(e.ExitStatus)
|
||||||
return meta, nil
|
return status, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Failed to update container %q state: %v", e.ID, err)
|
glog.Errorf("Failed to update container %q state: %v", e.ID, err)
|
||||||
@ -120,11 +120,15 @@ func (c *criContainerdService) handleEvent(e *task.Event) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
case task.Event_OOM:
|
case task.Event_OOM:
|
||||||
err := c.containerStore.Update(e.ID, func(meta metadata.ContainerMetadata) (metadata.ContainerMetadata, error) {
|
cntr, err := c.containerStore.Get(e.ID)
|
||||||
meta.Reason = oomExitReason
|
if err != nil {
|
||||||
return meta, nil
|
glog.Errorf("Failed to get container %q: %v", e.ID, err)
|
||||||
|
}
|
||||||
|
err = cntr.Status.Update(func(status containerstore.Status) (containerstore.Status, error) {
|
||||||
|
status.Reason = oomExitReason
|
||||||
|
return status, nil
|
||||||
})
|
})
|
||||||
if err != nil && !metadata.IsNotExistError(err) {
|
if err != nil {
|
||||||
glog.Errorf("Failed to update container %q oom: %v", e.ID, err)
|
glog.Errorf("Failed to update container %q oom: %v", e.ID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHandleEvent(t *testing.T) {
|
func TestHandleEvent(t *testing.T) {
|
||||||
@ -36,11 +36,13 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
testPid := uint32(1234)
|
testPid := uint32(1234)
|
||||||
testCreatedAt := time.Now().UnixNano()
|
testCreatedAt := time.Now().UnixNano()
|
||||||
testStartedAt := time.Now().UnixNano()
|
testStartedAt := time.Now().UnixNano()
|
||||||
// Container metadata in running state.
|
testMetadata := containerstore.Metadata{
|
||||||
testMetadata := metadata.ContainerMetadata{
|
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
SandboxID: "test-sandbox-id",
|
SandboxID: "test-sandbox-id",
|
||||||
|
}
|
||||||
|
// Container status in running state.
|
||||||
|
testStatus := containerstore.Status{
|
||||||
Pid: testPid,
|
Pid: testPid,
|
||||||
CreatedAt: testCreatedAt,
|
CreatedAt: testCreatedAt,
|
||||||
StartedAt: testStartedAt,
|
StartedAt: testStartedAt,
|
||||||
@ -53,17 +55,14 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
ExitStatus: 1,
|
ExitStatus: 1,
|
||||||
ExitedAt: testExitedAt,
|
ExitedAt: testExitedAt,
|
||||||
}
|
}
|
||||||
testFinishedMetadata := metadata.ContainerMetadata{
|
testFinishedStatus := containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
Name: "test-name",
|
|
||||||
SandboxID: "test-sandbox-id",
|
|
||||||
Pid: 0,
|
Pid: 0,
|
||||||
CreatedAt: testCreatedAt,
|
CreatedAt: testCreatedAt,
|
||||||
StartedAt: testStartedAt,
|
StartedAt: testStartedAt,
|
||||||
FinishedAt: testExitedAt.UnixNano(),
|
FinishedAt: testExitedAt.UnixNano(),
|
||||||
ExitCode: 1,
|
ExitCode: 1,
|
||||||
}
|
}
|
||||||
assert.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, testMetadata.State())
|
assert.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, testStatus.State())
|
||||||
testContainerdContainer := task.Task{
|
testContainerdContainer := task.Task{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Pid: testPid,
|
Pid: testPid,
|
||||||
@ -72,12 +71,12 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
|
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
event *task.Event
|
event *task.Event
|
||||||
metadata *metadata.ContainerMetadata
|
status *containerstore.Status
|
||||||
containerdContainer *task.Task
|
containerdContainer *task.Task
|
||||||
containerdErr error
|
containerdErr error
|
||||||
expected *metadata.ContainerMetadata
|
expected *containerstore.Status
|
||||||
}{
|
}{
|
||||||
"should not update state when no corresponding metadata for event": {
|
"should not update state when no corresponding container for event": {
|
||||||
event: &testExitEvent,
|
event: &testExitEvent,
|
||||||
expected: nil,
|
expected: nil,
|
||||||
},
|
},
|
||||||
@ -89,16 +88,16 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
ExitStatus: 1,
|
ExitStatus: 1,
|
||||||
ExitedAt: testExitedAt,
|
ExitedAt: testExitedAt,
|
||||||
},
|
},
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainerdContainer,
|
containerdContainer: &testContainerdContainer,
|
||||||
expected: &testMetadata,
|
expected: &testStatus,
|
||||||
},
|
},
|
||||||
"should not update state when fail to delete containerd task": {
|
"should not update state when fail to delete containerd task": {
|
||||||
event: &testExitEvent,
|
event: &testExitEvent,
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainerdContainer,
|
containerdContainer: &testContainerdContainer,
|
||||||
containerdErr: fmt.Errorf("random error"),
|
containerdErr: fmt.Errorf("random error"),
|
||||||
expected: &testMetadata,
|
expected: &testStatus,
|
||||||
},
|
},
|
||||||
"should not update state for irrelevant events": {
|
"should not update state for irrelevant events": {
|
||||||
event: &task.Event{
|
event: &task.Event{
|
||||||
@ -106,31 +105,28 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
Type: task.Event_PAUSED,
|
Type: task.Event_PAUSED,
|
||||||
Pid: testPid,
|
Pid: testPid,
|
||||||
},
|
},
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainerdContainer,
|
containerdContainer: &testContainerdContainer,
|
||||||
expected: &testMetadata,
|
expected: &testStatus,
|
||||||
},
|
},
|
||||||
"should update state when containerd task is already deleted": {
|
"should update state when containerd task is already deleted": {
|
||||||
event: &testExitEvent,
|
event: &testExitEvent,
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
expected: &testFinishedMetadata,
|
expected: &testFinishedStatus,
|
||||||
},
|
},
|
||||||
"should update state when delete containerd task successfully": {
|
"should update state when delete containerd task successfully": {
|
||||||
event: &testExitEvent,
|
event: &testExitEvent,
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
containerdContainer: &testContainerdContainer,
|
containerdContainer: &testContainerdContainer,
|
||||||
expected: &testFinishedMetadata,
|
expected: &testFinishedStatus,
|
||||||
},
|
},
|
||||||
"should update exit reason when container is oom killed": {
|
"should update exit reason when container is oom killed": {
|
||||||
event: &task.Event{
|
event: &task.Event{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Type: task.Event_OOM,
|
Type: task.Event_OOM,
|
||||||
},
|
},
|
||||||
metadata: &testMetadata,
|
status: &testStatus,
|
||||||
expected: &metadata.ContainerMetadata{
|
expected: &containerstore.Status{
|
||||||
ID: testID,
|
|
||||||
Name: "test-name",
|
|
||||||
SandboxID: "test-sandbox-id",
|
|
||||||
Pid: testPid,
|
Pid: testPid,
|
||||||
CreatedAt: testCreatedAt,
|
CreatedAt: testCreatedAt,
|
||||||
StartedAt: testStartedAt,
|
StartedAt: testStartedAt,
|
||||||
@ -148,10 +144,14 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
if test.event != nil {
|
if test.event != nil {
|
||||||
fakeEvents.Events <- test.event
|
fakeEvents.Events <- test.event
|
||||||
}
|
}
|
||||||
// Inject metadata.
|
// Inject internal container object.
|
||||||
if test.metadata != nil {
|
if test.status != nil {
|
||||||
// Make sure that original data will not be changed.
|
cntr, err := containerstore.NewContainer( // nolint: vetshadow
|
||||||
assert.NoError(t, c.containerStore.Create(*test.metadata))
|
testMetadata,
|
||||||
|
*test.status,
|
||||||
|
)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(cntr))
|
||||||
}
|
}
|
||||||
// Inject containerd task.
|
// Inject containerd task.
|
||||||
if test.containerdContainer != nil {
|
if test.containerdContainer != nil {
|
||||||
@ -161,8 +161,12 @@ func TestHandleEvent(t *testing.T) {
|
|||||||
if test.containerdErr != nil {
|
if test.containerdErr != nil {
|
||||||
fake.InjectError("delete", test.containerdErr)
|
fake.InjectError("delete", test.containerdErr)
|
||||||
}
|
}
|
||||||
c.handleEventStream(e)
|
assert.NoError(t, c.handleEventStream(e))
|
||||||
got, _ := c.containerStore.Get(testID)
|
if test.expected == nil {
|
||||||
assert.Equal(t, test.expected, got)
|
continue
|
||||||
|
}
|
||||||
|
got, err := c.containerStore.Get(testID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, *test.expected, got.Status.Get())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -328,7 +329,7 @@ func getRepoDigestAndTag(namedRef reference.Named, digest imagedigest.Digest, sc
|
|||||||
|
|
||||||
// localResolve resolves image reference locally and returns corresponding image metadata. It returns
|
// localResolve resolves image reference locally and returns corresponding image metadata. It returns
|
||||||
// nil without error if the reference doesn't exist.
|
// nil without error if the reference doesn't exist.
|
||||||
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
|
func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*imagestore.Image, error) {
|
||||||
_, err := imagedigest.Parse(ref)
|
_, err := imagedigest.Parse(ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ref is not image id, try to resolve it locally.
|
// ref is not image id, try to resolve it locally.
|
||||||
@ -336,7 +337,7 @@ func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*m
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid image reference %q: %v", ref, err)
|
return nil, fmt.Errorf("invalid image reference %q: %v", ref, err)
|
||||||
}
|
}
|
||||||
image, err := c.imageStoreService.Get(ctx, normalized.String())
|
imageInContainerd, err := c.imageStoreService.Get(ctx, normalized.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if containerdmetadata.IsNotFound(err) {
|
if containerdmetadata.IsNotFound(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -344,21 +345,21 @@ func (c *criContainerdService) localResolve(ctx context.Context, ref string) (*m
|
|||||||
return nil, fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
|
return nil, fmt.Errorf("an error occurred when getting image %q from containerd image store: %v",
|
||||||
normalized.String(), err)
|
normalized.String(), err)
|
||||||
}
|
}
|
||||||
desc, err := image.Config(ctx, c.contentStoreService)
|
desc, err := imageInContainerd.Config(ctx, c.contentStoreService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get image config descriptor: %v", err)
|
return nil, fmt.Errorf("failed to get image config descriptor: %v", err)
|
||||||
}
|
}
|
||||||
ref = desc.Digest.String()
|
ref = desc.Digest.String()
|
||||||
}
|
}
|
||||||
imageID := ref
|
imageID := ref
|
||||||
meta, err := c.imageMetadataStore.Get(imageID)
|
image, err := c.imageStore.Get(imageID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if metadata.IsNotExistError(err) {
|
if err == store.ErrNotExist {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed to get image %q metadata: %v", imageID, err)
|
return nil, fmt.Errorf("failed to get image %q metadata: %v", imageID, err)
|
||||||
}
|
}
|
||||||
return meta, nil
|
return &image, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getUserFromImage gets uid or user name of the image user.
|
// getUserFromImage gets uid or user name of the image user.
|
||||||
@ -382,13 +383,13 @@ func getUserFromImage(user string) (*int64, string) {
|
|||||||
|
|
||||||
// ensureImageExists returns corresponding metadata of the image reference, if image is not
|
// ensureImageExists returns corresponding metadata of the image reference, if image is not
|
||||||
// pulled yet, the function will pull the image.
|
// pulled yet, the function will pull the image.
|
||||||
func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string) (*metadata.ImageMetadata, error) {
|
func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string) (*imagestore.Image, error) {
|
||||||
meta, err := c.localResolve(ctx, ref)
|
image, err := c.localResolve(ctx, ref)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to resolve image %q: %v", ref, err)
|
return nil, fmt.Errorf("failed to resolve image %q: %v", ref, err)
|
||||||
}
|
}
|
||||||
if meta != nil {
|
if image != nil {
|
||||||
return meta, nil
|
return image, nil
|
||||||
}
|
}
|
||||||
// Pull image to ensure the image exists
|
// Pull image to ensure the image exists
|
||||||
resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}})
|
resp, err := c.PullImage(ctx, &runtime.PullImageRequest{Image: &runtime.ImageSpec{Image: ref}})
|
||||||
@ -396,10 +397,10 @@ func (c *criContainerdService) ensureImageExists(ctx context.Context, ref string
|
|||||||
return nil, fmt.Errorf("failed to pull image %q: %v", ref, err)
|
return nil, fmt.Errorf("failed to pull image %q: %v", ref, err)
|
||||||
}
|
}
|
||||||
imageID := resp.GetImageRef()
|
imageID := resp.GetImageRef()
|
||||||
meta, err = c.imageMetadataStore.Get(imageID)
|
newImage, err := c.imageStore.Get(imageID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// It's still possible that someone removed the image right after it is pulled.
|
// 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 nil, fmt.Errorf("failed to get image %q metadata after pulling: %v", imageID, err)
|
||||||
}
|
}
|
||||||
return meta, nil
|
return &newImage, nil
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,11 @@ limitations under the License.
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListImages lists existing images.
|
// ListImages lists existing images.
|
||||||
@ -37,12 +35,10 @@ func (c *criContainerdService) ListImages(ctx context.Context, r *runtime.ListIm
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
imageMetadataA, err := c.imageMetadataStore.List()
|
imagesInStore := c.imageStore.List()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list image metadata from store: %v", err)
|
|
||||||
}
|
|
||||||
var images []*runtime.Image
|
var images []*runtime.Image
|
||||||
for _, image := range imageMetadataA {
|
for _, image := range imagesInStore {
|
||||||
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
|
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
|
||||||
// doesn't exist?
|
// doesn't exist?
|
||||||
images = append(images, toCRIImage(image))
|
images = append(images, toCRIImage(image))
|
||||||
@ -51,8 +47,8 @@ func (c *criContainerdService) ListImages(ctx context.Context, r *runtime.ListIm
|
|||||||
return &runtime.ListImagesResponse{Images: images}, nil
|
return &runtime.ListImagesResponse{Images: images}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toCRIImage converts image metadata to CRI image type.
|
// toCRIImage converts image to CRI image type.
|
||||||
func toCRIImage(image *metadata.ImageMetadata) *runtime.Image {
|
func toCRIImage(image imagestore.Image) *runtime.Image {
|
||||||
runtimeImage := &runtime.Image{
|
runtimeImage := &runtime.Image{
|
||||||
Id: image.ID,
|
Id: image.ID,
|
||||||
RepoTags: image.RepoTags,
|
RepoTags: image.RepoTags,
|
||||||
|
@ -25,12 +25,12 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListImages(t *testing.T) {
|
func TestListImages(t *testing.T) {
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
imagesInStore := []metadata.ImageMetadata{
|
imagesInStore := []imagestore.Image{
|
||||||
{
|
{
|
||||||
ID: "test-id-1",
|
ID: "test-id-1",
|
||||||
ChainID: "test-chainid-1",
|
ChainID: "test-chainid-1",
|
||||||
@ -87,7 +87,7 @@ func TestListImages(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, i := range imagesInStore {
|
for _, i := range imagesInStore {
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(i))
|
c.imageStore.Add(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := c.ListImages(context.Background(), &runtime.ListImagesRequest{})
|
resp, err := c.ListImages(context.Background(), &runtime.ListImagesRequest{})
|
||||||
|
@ -37,7 +37,7 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
// For image management:
|
// For image management:
|
||||||
@ -87,60 +87,41 @@ func (c *criContainerdService) PullImage(ctx context.Context, r *runtime.PullIma
|
|||||||
r.GetImage().GetImage(), retRes.GetImageRef())
|
r.GetImage().GetImage(), retRes.GetImageRef())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
image := r.GetImage().GetImage()
|
imageRef := r.GetImage().GetImage()
|
||||||
|
|
||||||
// TODO(mikebrow): add truncIndex for image id
|
// TODO(mikebrow): add truncIndex for image id
|
||||||
imageID, repoTag, repoDigest, err := c.pullImage(ctx, image, r.GetAuth())
|
imageID, repoTag, repoDigest, err := c.pullImage(ctx, imageRef, r.GetAuth())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to pull image %q: %v", image, err)
|
return nil, fmt.Errorf("failed to pull image %q: %v", imageRef, err)
|
||||||
}
|
}
|
||||||
glog.V(4).Infof("Pulled image %q with image id %q, repo tag %q, repo digest %q", image, imageID,
|
glog.V(4).Infof("Pulled image %q with image id %q, repo tag %q, repo digest %q", imageRef, imageID,
|
||||||
repoTag, repoDigest)
|
repoTag, repoDigest)
|
||||||
|
|
||||||
_, err = c.imageMetadataStore.Get(imageID)
|
|
||||||
if err != nil && !metadata.IsNotExistError(err) {
|
|
||||||
return nil, fmt.Errorf("failed to get image %q metadata: %v", imageID, err)
|
|
||||||
}
|
|
||||||
// There is a known race here because the image metadata could be created after `Get`.
|
|
||||||
// TODO(random-liu): [P1] Do not use metadata store. Use simple in-memory data structure to
|
|
||||||
// maintain the id -> information index. And use the container image store as backup and
|
|
||||||
// recover in-memory state during startup.
|
|
||||||
if err == nil {
|
|
||||||
// Update existing image metadata.
|
|
||||||
if err := c.imageMetadataStore.Update(imageID, func(m metadata.ImageMetadata) (metadata.ImageMetadata, error) {
|
|
||||||
updateImageMetadata(&m, repoTag, repoDigest)
|
|
||||||
return m, nil
|
|
||||||
}); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to update image %q metadata: %v", imageID, err)
|
|
||||||
}
|
|
||||||
return &runtime.PullImageResponse{ImageRef: imageID}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get image information.
|
// Get image information.
|
||||||
chainID, size, config, err := c.getImageInfo(ctx, image)
|
chainID, size, config, err := c.getImageInfo(ctx, imageRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get image %q information: %v", image, err)
|
return nil, fmt.Errorf("failed to get image %q information: %v", imageRef, err)
|
||||||
}
|
}
|
||||||
|
image := imagestore.Image{
|
||||||
// NOTE(random-liu): the actual state in containerd is the source of truth, even we maintain
|
|
||||||
// in-memory image metadata, it's only for in-memory indexing. The image could be removed
|
|
||||||
// by someone else anytime, before/during/after we create the metadata. We should always
|
|
||||||
// check the actual state in containerd before using the image or returning status of the
|
|
||||||
// image.
|
|
||||||
|
|
||||||
// Create corresponding image metadata.
|
|
||||||
newMeta := metadata.ImageMetadata{
|
|
||||||
ID: imageID,
|
ID: imageID,
|
||||||
ChainID: chainID.String(),
|
ChainID: chainID.String(),
|
||||||
Size: size,
|
Size: size,
|
||||||
Config: config,
|
Config: config,
|
||||||
}
|
}
|
||||||
// Add the image reference used into repo tags. Note if the image is pulled with
|
|
||||||
// repo digest, it will also be added in to repo tags, which is fine.
|
if repoDigest != "" {
|
||||||
updateImageMetadata(&newMeta, repoTag, repoDigest)
|
image.RepoDigests = []string{repoDigest}
|
||||||
if err := c.imageMetadataStore.Create(newMeta); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create image %q metadata: %v", imageID, err)
|
|
||||||
}
|
}
|
||||||
|
if repoTag != "" {
|
||||||
|
image.RepoTags = []string{repoTag}
|
||||||
|
}
|
||||||
|
c.imageStore.Add(image)
|
||||||
|
|
||||||
|
// NOTE(random-liu): the actual state in containerd is the source of truth, even we maintain
|
||||||
|
// in-memory image store, it's only for in-memory indexing. The image could be removed
|
||||||
|
// by someone else anytime, before/during/after we create the metadata. We should always
|
||||||
|
// check the actual state in containerd before using the image or returning status of the
|
||||||
|
// image.
|
||||||
return &runtime.PullImageResponse{ImageRef: imageID}, err
|
return &runtime.PullImageResponse{ImageRef: imageID}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,29 +374,3 @@ func (c *criContainerdService) waitForResourcesDownloading(ctx context.Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertToStringSlice is a helper function to insert a string into the string slice
|
|
||||||
// if the string is not in the slice yet.
|
|
||||||
func insertToStringSlice(ss []string, s string) []string {
|
|
||||||
found := false
|
|
||||||
for _, str := range ss {
|
|
||||||
if s == str {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
ss = append(ss, s)
|
|
||||||
}
|
|
||||||
return ss
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateImageMetadata updates existing image meta with new repoTag and repoDigest.
|
|
||||||
func updateImageMetadata(meta *metadata.ImageMetadata, repoTag, repoDigest string) {
|
|
||||||
if repoTag != "" {
|
|
||||||
meta.RepoTags = insertToStringSlice(meta.RepoTags, repoTag)
|
|
||||||
}
|
|
||||||
if repoDigest != "" {
|
|
||||||
meta.RepoDigests = insertToStringSlice(meta.RepoDigests, repoDigest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,59 +24,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestUpdateImageMetadata(t *testing.T) {
|
|
||||||
meta := metadata.ImageMetadata{
|
|
||||||
ID: "test-id",
|
|
||||||
ChainID: "test-chain-id",
|
|
||||||
Size: 1234,
|
|
||||||
}
|
|
||||||
for desc, test := range map[string]struct {
|
|
||||||
repoTags []string
|
|
||||||
repoDigests []string
|
|
||||||
repoTag string
|
|
||||||
repoDigest string
|
|
||||||
expectedRepoTags []string
|
|
||||||
expectedRepoDigests []string
|
|
||||||
}{
|
|
||||||
"Add duplicated repo tag and digest": {
|
|
||||||
repoTags: []string{"a", "b"},
|
|
||||||
repoDigests: []string{"c", "d"},
|
|
||||||
repoTag: "a",
|
|
||||||
repoDigest: "c",
|
|
||||||
expectedRepoTags: []string{"a", "b"},
|
|
||||||
expectedRepoDigests: []string{"c", "d"},
|
|
||||||
},
|
|
||||||
"Add new repo tag and digest": {
|
|
||||||
repoTags: []string{"a", "b"},
|
|
||||||
repoDigests: []string{"c", "d"},
|
|
||||||
repoTag: "e",
|
|
||||||
repoDigest: "f",
|
|
||||||
expectedRepoTags: []string{"a", "b", "e"},
|
|
||||||
expectedRepoDigests: []string{"c", "d", "f"},
|
|
||||||
},
|
|
||||||
"Add empty repo tag and digest": {
|
|
||||||
repoTags: []string{"a", "b"},
|
|
||||||
repoDigests: []string{"c", "d"},
|
|
||||||
repoTag: "",
|
|
||||||
repoDigest: "",
|
|
||||||
expectedRepoTags: []string{"a", "b"},
|
|
||||||
expectedRepoDigests: []string{"c", "d"},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Logf("TestCase %q", desc)
|
|
||||||
m := meta
|
|
||||||
m.RepoTags = test.repoTags
|
|
||||||
m.RepoDigests = test.repoDigests
|
|
||||||
updateImageMetadata(&m, test.repoTag, test.repoDigest)
|
|
||||||
assert.Equal(t, test.expectedRepoTags, m.RepoTags)
|
|
||||||
assert.Equal(t, test.expectedRepoDigests, m.RepoDigests)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResources(t *testing.T) {
|
func TestResources(t *testing.T) {
|
||||||
const threads = 10
|
const threads = 10
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
@ -19,13 +19,10 @@ package server
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
containerdmetadata "github.com/containerd/containerd/metadata"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
containerdmetadata "github.com/containerd/containerd/metadata"
|
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RemoveImage removes the image.
|
// RemoveImage removes the image.
|
||||||
@ -41,29 +38,25 @@ func (c *criContainerdService) RemoveImage(ctx context.Context, r *runtime.Remov
|
|||||||
glog.V(2).Infof("RemoveImage %q returns successfully", r.GetImage().GetImage())
|
glog.V(2).Infof("RemoveImage %q returns successfully", r.GetImage().GetImage())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
|
image, err := c.localResolve(ctx, r.GetImage().GetImage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
|
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
|
||||||
}
|
}
|
||||||
if meta == nil {
|
if image == nil {
|
||||||
// return empty without error when image not found.
|
// return empty without error when image not found.
|
||||||
return &runtime.RemoveImageResponse{}, nil
|
return &runtime.RemoveImageResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include all image references, including RepoTag, RepoDigest and id.
|
// Include all image references, including RepoTag, RepoDigest and id.
|
||||||
for _, ref := range append(append(meta.RepoTags, meta.RepoDigests...), meta.ID) {
|
for _, ref := range append(append(image.RepoTags, image.RepoDigests...), image.ID) {
|
||||||
// TODO(random-liu): Containerd should schedule a garbage collection immediately,
|
// TODO(random-liu): Containerd should schedule a garbage collection immediately,
|
||||||
// and we may want to wait for the garbage collection to be over here.
|
// and we may want to wait for the garbage collection to be over here.
|
||||||
err = c.imageStoreService.Delete(ctx, ref)
|
err = c.imageStoreService.Delete(ctx, ref)
|
||||||
if err == nil || containerdmetadata.IsNotFound(err) {
|
if err == nil || containerdmetadata.IsNotFound(err) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, meta.ID, err)
|
return nil, fmt.Errorf("failed to delete image reference %q for image %q: %v", ref, image.ID, err)
|
||||||
}
|
|
||||||
if err = c.imageMetadataStore.Delete(meta.ID); err != nil {
|
|
||||||
if metadata.IsNotExistError(err) {
|
|
||||||
return &runtime.RemoveImageResponse{}, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("an error occurred when delete image %q matadata: %v", meta.ID, err)
|
|
||||||
}
|
}
|
||||||
|
c.imageStore.Delete(image.ID)
|
||||||
return &runtime.RemoveImageResponse{}, nil
|
return &runtime.RemoveImageResponse{}, nil
|
||||||
}
|
}
|
||||||
|
@ -35,28 +35,28 @@ func (c *criContainerdService) ImageStatus(ctx context.Context, r *runtime.Image
|
|||||||
r.GetImage().GetImage(), retRes.GetImage())
|
r.GetImage().GetImage(), retRes.GetImage())
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
meta, err := c.localResolve(ctx, r.GetImage().GetImage())
|
image, err := c.localResolve(ctx, r.GetImage().GetImage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
|
return nil, fmt.Errorf("can not resolve %q locally: %v", r.GetImage().GetImage(), err)
|
||||||
}
|
}
|
||||||
if meta == nil {
|
if image == nil {
|
||||||
// return empty without error when image not found.
|
// return empty without error when image not found.
|
||||||
return &runtime.ImageStatusResponse{}, nil
|
return &runtime.ImageStatusResponse{}, nil
|
||||||
}
|
}
|
||||||
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
|
// TODO(random-liu): [P0] Make sure corresponding snapshot exists. What if snapshot
|
||||||
// doesn't exist?
|
// doesn't exist?
|
||||||
runtimeImage := &runtime.Image{
|
runtimeImage := &runtime.Image{
|
||||||
Id: meta.ID,
|
Id: image.ID,
|
||||||
RepoTags: meta.RepoTags,
|
RepoTags: image.RepoTags,
|
||||||
RepoDigests: meta.RepoDigests,
|
RepoDigests: image.RepoDigests,
|
||||||
Size_: uint64(meta.Size),
|
Size_: uint64(image.Size),
|
||||||
}
|
}
|
||||||
uid, username := getUserFromImage(meta.Config.User)
|
uid, username := getUserFromImage(image.Config.User)
|
||||||
if uid != nil {
|
if uid != nil {
|
||||||
runtimeImage.Uid = &runtime.Int64Value{Value: *uid}
|
runtimeImage.Uid = &runtime.Int64Value{Value: *uid}
|
||||||
}
|
}
|
||||||
runtimeImage.Username = username
|
runtimeImage.Username = username
|
||||||
|
|
||||||
// TODO(mikebrow): write a ImageMetadata to runtim.Image converter
|
// TODO(mikebrow): write a ImageMetadata to runtime.Image converter
|
||||||
return &runtime.ImageStatusResponse{Image: runtimeImage}, nil
|
return &runtime.ImageStatusResponse{Image: runtimeImage}, nil
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,12 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestImageStatus(t *testing.T) {
|
func TestImageStatus(t *testing.T) {
|
||||||
testID := "sha256:d848ce12891bf78792cda4a23c58984033b0c397a55e93a1556202222ecc5ed4"
|
testID := "sha256:d848ce12891bf78792cda4a23c58984033b0c397a55e93a1556202222ecc5ed4"
|
||||||
meta := metadata.ImageMetadata{
|
image := imagestore.Image{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
ChainID: "test-chain-id",
|
ChainID: "test-chain-id",
|
||||||
RepoTags: []string{"a", "b"},
|
RepoTags: []string{"a", "b"},
|
||||||
@ -57,7 +57,7 @@ func TestImageStatus(t *testing.T) {
|
|||||||
require.NotNil(t, resp)
|
require.NotNil(t, resp)
|
||||||
assert.Nil(t, resp.GetImage())
|
assert.Nil(t, resp.GetImage())
|
||||||
|
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(meta))
|
c.imageStore.Add(image)
|
||||||
|
|
||||||
t.Logf("should return correct image status for exist image")
|
t.Logf("should return correct image status for exist image")
|
||||||
resp, err = c.ImageStatus(context.Background(), &runtime.ImageStatusRequest{
|
resp, err = c.ImageStatus(context.Background(), &runtime.ImageStatusRequest{
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
"github.com/containerd/containerd/api/types/task"
|
"github.com/containerd/containerd/api/types/task"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListPodSandbox returns a list of Sandbox.
|
// ListPodSandbox returns a list of Sandbox.
|
||||||
@ -39,11 +39,8 @@ func (c *criContainerdService) ListPodSandbox(ctx context.Context, r *runtime.Li
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// List all sandbox metadata from store.
|
// List all sandboxes from store.
|
||||||
sandboxesInStore, err := c.sandboxStore.List()
|
sandboxesInStore := c.sandboxStore.List()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list metadata from sandbox store: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.taskService.List(ctx, &execution.ListRequest{})
|
resp, err := c.taskService.List(ctx, &execution.ListRequest{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -68,7 +65,7 @@ func (c *criContainerdService) ListPodSandbox(ctx context.Context, r *runtime.Li
|
|||||||
state = runtime.PodSandboxState_SANDBOX_READY
|
state = runtime.PodSandboxState_SANDBOX_READY
|
||||||
}
|
}
|
||||||
|
|
||||||
sandboxes = append(sandboxes, toCRISandbox(sandboxInStore, state))
|
sandboxes = append(sandboxes, toCRISandbox(sandboxInStore.Metadata, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
sandboxes = c.filterCRISandboxes(sandboxes, r.GetFilter())
|
sandboxes = c.filterCRISandboxes(sandboxes, r.GetFilter())
|
||||||
@ -76,7 +73,7 @@ func (c *criContainerdService) ListPodSandbox(ctx context.Context, r *runtime.Li
|
|||||||
}
|
}
|
||||||
|
|
||||||
// toCRISandbox converts sandbox metadata into CRI pod sandbox.
|
// toCRISandbox converts sandbox metadata into CRI pod sandbox.
|
||||||
func toCRISandbox(meta *metadata.SandboxMetadata, state runtime.PodSandboxState) *runtime.PodSandbox {
|
func toCRISandbox(meta sandboxstore.Metadata, state runtime.PodSandboxState) *runtime.PodSandbox {
|
||||||
return &runtime.PodSandbox{
|
return &runtime.PodSandbox{
|
||||||
Id: meta.ID,
|
Id: meta.ID,
|
||||||
Metadata: meta.Config.GetMetadata(),
|
Metadata: meta.Config.GetMetadata(),
|
||||||
|
@ -27,8 +27,8 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToCRISandbox(t *testing.T) {
|
func TestToCRISandbox(t *testing.T) {
|
||||||
@ -43,7 +43,7 @@ func TestToCRISandbox(t *testing.T) {
|
|||||||
Annotations: map[string]string{"c": "d"},
|
Annotations: map[string]string{"c": "d"},
|
||||||
}
|
}
|
||||||
createdAt := time.Now().UnixNano()
|
createdAt := time.Now().UnixNano()
|
||||||
meta := &metadata.SandboxMetadata{
|
meta := sandboxstore.Metadata{
|
||||||
ID: "test-id",
|
ID: "test-id",
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
Config: config,
|
Config: config,
|
||||||
@ -137,22 +137,28 @@ func TestListPodSandbox(t *testing.T) {
|
|||||||
|
|
||||||
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
||||||
|
|
||||||
sandboxesInStore := []metadata.SandboxMetadata{
|
sandboxesInStore := []sandboxstore.Sandbox{
|
||||||
{
|
{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: "1",
|
ID: "1",
|
||||||
Name: "name-1",
|
Name: "name-1",
|
||||||
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-1"}},
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-1"}},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: "2",
|
ID: "2",
|
||||||
Name: "name-2",
|
Name: "name-2",
|
||||||
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-2"}},
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-2"}},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: "3",
|
ID: "3",
|
||||||
Name: "name-3",
|
Name: "name-3",
|
||||||
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-3"}},
|
Config: &runtime.PodSandboxConfig{Metadata: &runtime.PodSandboxMetadata{Name: "name-3"}},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
sandboxesInContainerd := []task.Task{
|
sandboxesInContainerd := []task.Task{
|
||||||
// Running container with corresponding metadata
|
// Running container with corresponding metadata
|
||||||
@ -194,7 +200,7 @@ func TestListPodSandbox(t *testing.T) {
|
|||||||
|
|
||||||
// Inject test metadata
|
// Inject test metadata
|
||||||
for _, s := range sandboxesInStore {
|
for _, s := range sandboxesInStore {
|
||||||
c.sandboxStore.Create(s)
|
assert.NoError(t, c.sandboxStore.Add(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject fake containerd tasks
|
// Inject fake containerd tasks
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RemovePodSandbox removes the sandbox. If there are running containers in the
|
// RemovePodSandbox removes the sandbox. If there are running containers in the
|
||||||
@ -41,7 +41,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
|
|||||||
|
|
||||||
sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId())
|
sandbox, err := c.sandboxStore.Get(r.GetPodSandboxId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !metadata.IsNotExistError(err) {
|
if err != store.ErrNotExist {
|
||||||
return nil, fmt.Errorf("an error occurred when try to find sandbox %q: %v",
|
return nil, fmt.Errorf("an error occurred when try to find sandbox %q: %v",
|
||||||
r.GetPodSandboxId(), err)
|
r.GetPodSandboxId(), err)
|
||||||
}
|
}
|
||||||
@ -76,10 +76,7 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
|
|||||||
// not rely on this behavior.
|
// not rely on this behavior.
|
||||||
// TODO(random-liu): Introduce an intermediate state to avoid container creation after
|
// TODO(random-liu): Introduce an intermediate state to avoid container creation after
|
||||||
// this point.
|
// this point.
|
||||||
cntrs, err := c.containerStore.List()
|
cntrs := c.containerStore.List()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list all containers: %v", err)
|
|
||||||
}
|
|
||||||
for _, cntr := range cntrs {
|
for _, cntr := range cntrs {
|
||||||
if cntr.SandboxID != id {
|
if cntr.SandboxID != id {
|
||||||
continue
|
continue
|
||||||
@ -107,15 +104,12 @@ func (c *criContainerdService) RemovePodSandbox(ctx context.Context, r *runtime.
|
|||||||
glog.V(5).Infof("Remove called for sandbox container %q that does not exist", id, err)
|
glog.V(5).Infof("Remove called for sandbox container %q that does not exist", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove sandbox metadata from metadata store. Note that once the sandbox
|
// Remove sandbox from sandbox store. Note that once the sandbox is successfully
|
||||||
// metadata is successfully deleted:
|
// deleted:
|
||||||
// 1) ListPodSandbox will not include this sandbox.
|
// 1) ListPodSandbox will not include this sandbox.
|
||||||
// 2) PodSandboxStatus and StopPodSandbox will return error.
|
// 2) PodSandboxStatus and StopPodSandbox will return error.
|
||||||
// 3) On-going operations which have held the metadata reference will not be
|
// 3) On-going operations which have held the reference will not be affected.
|
||||||
// affected.
|
c.sandboxStore.Delete(id)
|
||||||
if err := c.sandboxStore.Delete(id); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to delete sandbox metadata for %q: %v", id, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the sandbox name reserved for the sandbox.
|
// Release the sandbox name reserved for the sandbox.
|
||||||
c.sandboxNameIndex.ReleaseByKey(id)
|
c.sandboxNameIndex.ReleaseByKey(id)
|
||||||
|
@ -27,21 +27,25 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
"github.com/kubernetes-incubator/cri-containerd/pkg/store"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRemovePodSandbox(t *testing.T) {
|
func TestRemovePodSandbox(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testName := "test-name"
|
testName := "test-name"
|
||||||
testMetadata := metadata.SandboxMetadata{
|
testSandbox := sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
sandboxTasks []task.Task
|
sandboxTasks []task.Task
|
||||||
injectMetadata bool
|
injectSandbox bool
|
||||||
removeSnapshotErr error
|
removeSnapshotErr error
|
||||||
deleteContainerErr error
|
deleteContainerErr error
|
||||||
taskInfoErr error
|
taskInfoErr error
|
||||||
@ -51,58 +55,58 @@ func TestRemovePodSandbox(t *testing.T) {
|
|||||||
expectCalls []string
|
expectCalls []string
|
||||||
}{
|
}{
|
||||||
"should not return error if sandbox does not exist": {
|
"should not return error if sandbox does not exist": {
|
||||||
injectMetadata: false,
|
injectSandbox: false,
|
||||||
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
||||||
deleteContainerErr: servertesting.ContainerNotExistError,
|
deleteContainerErr: servertesting.ContainerNotExistError,
|
||||||
expectErr: false,
|
expectErr: false,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
},
|
},
|
||||||
"should not return error if snapshot does not exist": {
|
"should not return error if snapshot does not exist": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
removeSnapshotErr: servertesting.SnapshotNotExistError,
|
||||||
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should return error if remove snapshot fails": {
|
"should return error if remove snapshot fails": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
removeSnapshotErr: fmt.Errorf("arbitrary error"),
|
removeSnapshotErr: fmt.Errorf("arbitrary error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should return error when sandbox container task is not deleted": {
|
"should return error when sandbox container task is not deleted": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
sandboxTasks: []task.Task{{ID: testID}},
|
sandboxTasks: []task.Task{{ID: testID}},
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should return error when arbitrary containerd error is injected": {
|
"should return error when arbitrary containerd error is injected": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
taskInfoErr: fmt.Errorf("arbitrary error"),
|
taskInfoErr: fmt.Errorf("arbitrary error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should return error when error fs error is injected": {
|
"should return error when error fs error is injected": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
injectFSErr: fmt.Errorf("fs error"),
|
injectFSErr: fmt.Errorf("fs error"),
|
||||||
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should not return error if sandbox container does not exist": {
|
"should not return error if sandbox container does not exist": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
deleteContainerErr: servertesting.ContainerNotExistError,
|
deleteContainerErr: servertesting.ContainerNotExistError,
|
||||||
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should return error if delete sandbox container fails": {
|
"should return error if delete sandbox container fails": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
deleteContainerErr: fmt.Errorf("arbitrary error"),
|
deleteContainerErr: fmt.Errorf("arbitrary error"),
|
||||||
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
"should be able to successfully delete": {
|
"should be able to successfully delete": {
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
expectRemoved: getSandboxRootDir(testRootDir, testID),
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
},
|
},
|
||||||
@ -114,9 +118,9 @@ func TestRemovePodSandbox(t *testing.T) {
|
|||||||
fakeExecutionClient := c.taskService.(*servertesting.FakeExecutionClient)
|
fakeExecutionClient := c.taskService.(*servertesting.FakeExecutionClient)
|
||||||
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
fakeSnapshotClient := WithFakeSnapshotClient(c)
|
||||||
fakeExecutionClient.SetFakeTasks(test.sandboxTasks)
|
fakeExecutionClient.SetFakeTasks(test.sandboxTasks)
|
||||||
if test.injectMetadata {
|
if test.injectSandbox {
|
||||||
c.sandboxNameIndex.Reserve(testName, testID)
|
c.sandboxNameIndex.Reserve(testName, testID)
|
||||||
c.sandboxStore.Create(testMetadata)
|
assert.NoError(t, c.sandboxStore.Add(testSandbox))
|
||||||
}
|
}
|
||||||
if test.removeSnapshotErr == nil {
|
if test.removeSnapshotErr == nil {
|
||||||
fakeSnapshotClient.SetFakeMounts(testID, []*mount.Mount{
|
fakeSnapshotClient.SetFakeMounts(testID, []*mount.Mount{
|
||||||
@ -157,10 +161,8 @@ func TestRemovePodSandbox(t *testing.T) {
|
|||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
assert.NoError(t, c.sandboxNameIndex.Reserve(testName, testID),
|
assert.NoError(t, c.sandboxNameIndex.Reserve(testName, testID),
|
||||||
"sandbox name should be released")
|
"sandbox name should be released")
|
||||||
meta, err := c.sandboxStore.Get(testID)
|
_, err = c.sandboxStore.Get(testID)
|
||||||
assert.Error(t, err)
|
assert.Equal(t, store.ErrNotExist, err, "sandbox should be removed")
|
||||||
assert.True(t, metadata.IsNotExistError(err))
|
|
||||||
assert.Nil(t, meta, "sandbox metadata should be removed")
|
|
||||||
mountsResp, err := fakeSnapshotClient.Mounts(context.Background(), &snapshotapi.MountsRequest{Key: testID})
|
mountsResp, err := fakeSnapshotClient.Mounts(context.Background(), &snapshotapi.MountsRequest{Key: testID})
|
||||||
assert.Equal(t, servertesting.SnapshotNotExistError, err, "snapshot should be removed")
|
assert.Equal(t, servertesting.SnapshotNotExistError, err, "snapshot should be removed")
|
||||||
assert.Nil(t, mountsResp)
|
assert.Nil(t, mountsResp)
|
||||||
@ -178,38 +180,49 @@ func TestRemovePodSandbox(t *testing.T) {
|
|||||||
func TestRemoveContainersInSandbox(t *testing.T) {
|
func TestRemoveContainersInSandbox(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testName := "test-name"
|
testName := "test-name"
|
||||||
testMetadata := metadata.SandboxMetadata{
|
testSandbox := sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: testName,
|
Name: testName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testContainersMetadata := []*metadata.ContainerMetadata{
|
testContainers := []containerForTest{
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "test-cid-1",
|
ID: "test-cid-1",
|
||||||
Name: "test-cname-1",
|
Name: "test-cname-1",
|
||||||
SandboxID: testID,
|
SandboxID: testID,
|
||||||
FinishedAt: time.Now().UnixNano(),
|
},
|
||||||
|
status: containerstore.Status{FinishedAt: time.Now().UnixNano()},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
|
|
||||||
ID: "test-cid-2",
|
ID: "test-cid-2",
|
||||||
Name: "test-cname-2",
|
Name: "test-cname-2",
|
||||||
SandboxID: testID,
|
SandboxID: testID,
|
||||||
FinishedAt: time.Now().UnixNano(),
|
},
|
||||||
|
status: containerstore.Status{FinishedAt: time.Now().UnixNano()},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "test-cid-3",
|
ID: "test-cid-3",
|
||||||
Name: "test-cname-3",
|
Name: "test-cname-3",
|
||||||
SandboxID: "other-sandbox-id",
|
SandboxID: "other-sandbox-id",
|
||||||
FinishedAt: time.Now().UnixNano(),
|
},
|
||||||
|
status: containerstore.Status{FinishedAt: time.Now().UnixNano()},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
WithFakeSnapshotClient(c)
|
WithFakeSnapshotClient(c)
|
||||||
assert.NoError(t, c.sandboxNameIndex.Reserve(testName, testID))
|
assert.NoError(t, c.sandboxNameIndex.Reserve(testName, testID))
|
||||||
assert.NoError(t, c.sandboxStore.Create(testMetadata))
|
assert.NoError(t, c.sandboxStore.Add(testSandbox))
|
||||||
for _, cntr := range testContainersMetadata {
|
for _, tc := range testContainers {
|
||||||
assert.NoError(t, c.containerNameIndex.Reserve(cntr.Name, cntr.ID))
|
assert.NoError(t, c.containerNameIndex.Reserve(tc.metadata.Name, tc.metadata.ID))
|
||||||
assert.NoError(t, c.containerStore.Create(*cntr))
|
cntr, err := tc.toContainer()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(cntr))
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := c.RemovePodSandbox(context.Background(), &runtime.RemovePodSandboxRequest{
|
res, err := c.RemovePodSandbox(context.Background(), &runtime.RemovePodSandboxRequest{
|
||||||
@ -218,12 +231,11 @@ func TestRemoveContainersInSandbox(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
|
|
||||||
meta, err := c.sandboxStore.Get(testID)
|
_, err = c.sandboxStore.Get(testID)
|
||||||
assert.Error(t, err)
|
assert.Equal(t, store.ErrNotExist, err, "sandbox metadata should be removed")
|
||||||
assert.True(t, metadata.IsNotExistError(err))
|
|
||||||
assert.Nil(t, meta, "sandbox metadata should be removed")
|
|
||||||
|
|
||||||
cntrs, err := c.containerStore.List()
|
cntrs := c.containerStore.List()
|
||||||
assert.NoError(t, err)
|
assert.Len(t, cntrs, 1)
|
||||||
assert.Equal(t, testContainersMetadata[2:], cntrs, "container metadata should be removed")
|
assert.Equal(t, testContainers[2].metadata, cntrs[0].Metadata, "container should be removed")
|
||||||
|
assert.Equal(t, testContainers[2].status, cntrs[0].Status.Get(), "container should be removed")
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure
|
// RunPodSandbox creates and starts a pod-level sandbox. Runtimes should ensure
|
||||||
@ -65,22 +65,23 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Create initial sandbox metadata.
|
// Create initial internal sandbox object.
|
||||||
meta := metadata.SandboxMetadata{
|
sandbox := sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: name,
|
Name: name,
|
||||||
Config: config,
|
Config: config,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure sandbox container image snapshot.
|
// Ensure sandbox container image snapshot.
|
||||||
imageMeta, err := c.ensureImageExists(ctx, c.sandboxImage)
|
image, err := c.ensureImageExists(ctx, c.sandboxImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get sandbox image %q: %v", defaultSandboxImage, err)
|
return nil, fmt.Errorf("failed to get sandbox image %q: %v", defaultSandboxImage, err)
|
||||||
}
|
}
|
||||||
|
rootfsMounts, err := c.snapshotService.View(ctx, id, image.ChainID)
|
||||||
rootfsMounts, err := c.snapshotService.View(ctx, id, imageMeta.ChainID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to prepare sandbox rootfs %q: %v", imageMeta.ChainID, err)
|
return nil, fmt.Errorf("failed to prepare sandbox rootfs %q: %v", image.ChainID, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
@ -99,7 +100,7 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create sandbox container.
|
// Create sandbox container.
|
||||||
spec, err := c.generateSandboxContainerSpec(id, config, imageMeta.Config)
|
spec, err := c.generateSandboxContainerSpec(id, config, image.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate sandbox container spec: %v", err)
|
return nil, fmt.Errorf("failed to generate sandbox container spec: %v", err)
|
||||||
}
|
}
|
||||||
@ -112,7 +113,7 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
|
|||||||
Container: containers.Container{
|
Container: containers.Container{
|
||||||
ID: id,
|
ID: id,
|
||||||
// TODO(random-liu): Checkpoint metadata into container labels.
|
// TODO(random-liu): Checkpoint metadata into container labels.
|
||||||
Image: imageMeta.ID,
|
Image: image.ID,
|
||||||
Runtime: defaultRuntime,
|
Runtime: defaultRuntime,
|
||||||
Spec: &prototypes.Any{
|
Spec: &prototypes.Any{
|
||||||
TypeUrl: runtimespec.Version,
|
TypeUrl: runtimespec.Version,
|
||||||
@ -205,19 +206,19 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
meta.Pid = createResp.Pid
|
sandbox.Pid = createResp.Pid
|
||||||
meta.NetNS = getNetworkNamespace(createResp.Pid)
|
sandbox.NetNS = getNetworkNamespace(createResp.Pid)
|
||||||
if !config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetHostNetwork() {
|
if !config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetHostNetwork() {
|
||||||
// Setup network for sandbox.
|
// Setup network for sandbox.
|
||||||
// TODO(random-liu): [P2] Replace with permanent network namespace.
|
// TODO(random-liu): [P2] Replace with permanent network namespace.
|
||||||
podName := config.GetMetadata().GetName()
|
podName := config.GetMetadata().GetName()
|
||||||
if err = c.netPlugin.SetUpPod(meta.NetNS, config.GetMetadata().GetNamespace(), podName, id); err != nil {
|
if err = c.netPlugin.SetUpPod(sandbox.NetNS, config.GetMetadata().GetNamespace(), podName, id); err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup network for sandbox %q: %v", id, err)
|
return nil, fmt.Errorf("failed to setup network for sandbox %q: %v", id, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil {
|
if retErr != nil {
|
||||||
// Teardown network if an error is returned.
|
// Teardown network if an error is returned.
|
||||||
if err := c.netPlugin.TearDownPod(meta.NetNS, config.GetMetadata().GetNamespace(), podName, id); err != nil {
|
if err := c.netPlugin.TearDownPod(sandbox.NetNS, config.GetMetadata().GetNamespace(), podName, id); err != nil {
|
||||||
glog.Errorf("failed to destroy network for sandbox %q: %v", id, err)
|
glog.Errorf("failed to destroy network for sandbox %q: %v", id, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,10 +232,9 @@ func (c *criContainerdService) RunPodSandbox(ctx context.Context, r *runtime.Run
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add sandbox into sandbox store.
|
// Add sandbox into sandbox store.
|
||||||
meta.CreatedAt = time.Now().UnixNano()
|
sandbox.CreatedAt = time.Now().UnixNano()
|
||||||
if err := c.sandboxStore.Create(meta); err != nil {
|
if err := c.sandboxStore.Add(sandbox); err != nil {
|
||||||
return nil, fmt.Errorf("failed to add sandbox metadata %+v into store: %v",
|
return nil, fmt.Errorf("failed to add sandbox %+v into store: %v", sandbox, err)
|
||||||
meta, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil
|
return &runtime.RunPodSandboxResponse{PodSandboxId: id}, nil
|
||||||
|
@ -33,9 +33,9 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) {
|
func getRunPodSandboxTestData() (*runtime.PodSandboxConfig, *imagespec.ImageConfig, func(*testing.T, string, *runtimespec.Spec)) {
|
||||||
@ -290,13 +290,13 @@ func TestRunPodSandbox(t *testing.T) {
|
|||||||
return nopReadWriteCloser{}, nil
|
return nopReadWriteCloser{}, nil
|
||||||
}
|
}
|
||||||
testChainID := "test-sandbox-chain-id"
|
testChainID := "test-sandbox-chain-id"
|
||||||
imageMetadata := metadata.ImageMetadata{
|
image := imagestore.Image{
|
||||||
ID: testSandboxImage,
|
ID: testSandboxImage,
|
||||||
ChainID: testChainID,
|
ChainID: testChainID,
|
||||||
Config: imageConfig,
|
Config: imageConfig,
|
||||||
}
|
}
|
||||||
// Insert sandbox image metadata.
|
// Insert sandbox image.
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(imageMetadata))
|
c.imageStore.Add(image)
|
||||||
expectContainersClientCalls := []string{"create"}
|
expectContainersClientCalls := []string{"create"}
|
||||||
expectSnapshotClientCalls := []string{"view"}
|
expectSnapshotClientCalls := []string{"view"}
|
||||||
expectExecutionClientCalls := []string{"create", "start"}
|
expectExecutionClientCalls := []string{"create", "start"}
|
||||||
@ -349,25 +349,25 @@ func TestRunPodSandbox(t *testing.T) {
|
|||||||
startID := calls[1].Argument.(*execution.StartRequest).ContainerID
|
startID := calls[1].Argument.(*execution.StartRequest).ContainerID
|
||||||
assert.Equal(t, id, startID, "start id should be correct")
|
assert.Equal(t, id, startID, "start id should be correct")
|
||||||
|
|
||||||
meta, err := c.sandboxStore.Get(id)
|
sandbox, err := c.sandboxStore.Get(id)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, id, meta.ID, "metadata id should be correct")
|
assert.Equal(t, id, sandbox.ID, "sandbox id should be correct")
|
||||||
err = c.sandboxNameIndex.Reserve(meta.Name, "random-id")
|
err = c.sandboxNameIndex.Reserve(sandbox.Name, "random-id")
|
||||||
assert.Error(t, err, "metadata name should be reserved")
|
assert.Error(t, err, "sandbox name should be reserved")
|
||||||
assert.Equal(t, config, meta.Config, "metadata config should be correct")
|
assert.Equal(t, config, sandbox.Config, "sandbox config should be correct")
|
||||||
// TODO(random-liu): [P2] Add clock interface and use fake clock.
|
// TODO(random-liu): [P2] Add clock interface and use fake clock.
|
||||||
assert.NotZero(t, meta.CreatedAt, "metadata CreatedAt should be set")
|
assert.NotZero(t, sandbox.CreatedAt, "sandbox CreatedAt should be set")
|
||||||
info, err := fakeExecutionClient.Info(context.Background(), &execution.InfoRequest{ContainerID: id})
|
info, err := fakeExecutionClient.Info(context.Background(), &execution.InfoRequest{ContainerID: id})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
pid := info.Task.Pid
|
pid := info.Task.Pid
|
||||||
assert.Equal(t, meta.NetNS, getNetworkNamespace(pid), "metadata network namespace should be correct")
|
assert.Equal(t, sandbox.NetNS, getNetworkNamespace(pid), "sandbox network namespace should be correct")
|
||||||
|
|
||||||
expectedCNICalls := []string{"SetUpPod"}
|
expectedCNICalls := []string{"SetUpPod"}
|
||||||
assert.Equal(t, expectedCNICalls, fakeCNIPlugin.GetCalledNames(), "expect SetUpPod should be called")
|
assert.Equal(t, expectedCNICalls, fakeCNIPlugin.GetCalledNames(), "expect SetUpPod should be called")
|
||||||
calls = fakeCNIPlugin.GetCalledDetails()
|
calls = fakeCNIPlugin.GetCalledDetails()
|
||||||
pluginArgument := calls[0].Argument.(servertesting.CNIPluginArgument)
|
pluginArgument := calls[0].Argument.(servertesting.CNIPluginArgument)
|
||||||
expectedPluginArgument := servertesting.CNIPluginArgument{
|
expectedPluginArgument := servertesting.CNIPluginArgument{
|
||||||
NetnsPath: meta.NetNS,
|
NetnsPath: sandbox.NetNS,
|
||||||
Namespace: config.GetMetadata().GetNamespace(),
|
Namespace: config.GetMetadata().GetNamespace(),
|
||||||
Name: config.GetMetadata().GetName(),
|
Name: config.GetMetadata().GetName(),
|
||||||
ContainerID: id,
|
ContainerID: id,
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PodSandboxStatus returns the status of the PodSandbox.
|
// PodSandboxStatus returns the status of the PodSandbox.
|
||||||
@ -66,11 +66,11 @@ func (c *criContainerdService) PodSandboxStatus(ctx context.Context, r *runtime.
|
|||||||
glog.V(4).Infof("GetContainerNetworkStatus returns error: %v", err)
|
glog.V(4).Infof("GetContainerNetworkStatus returns error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &runtime.PodSandboxStatusResponse{Status: toCRISandboxStatus(sandbox, state, ip)}, nil
|
return &runtime.PodSandboxStatusResponse{Status: toCRISandboxStatus(sandbox.Metadata, state, ip)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toCRISandboxStatus converts sandbox metadata into CRI pod sandbox status.
|
// toCRISandboxStatus converts sandbox metadata into CRI pod sandbox status.
|
||||||
func toCRISandboxStatus(meta *metadata.SandboxMetadata, state runtime.PodSandboxState, ip string) *runtime.PodSandboxStatus {
|
func toCRISandboxStatus(meta sandboxstore.Metadata, state runtime.PodSandboxState, ip string) *runtime.PodSandboxStatus {
|
||||||
nsOpts := meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions()
|
nsOpts := meta.Config.GetLinux().GetSecurityContext().GetNamespaceOptions()
|
||||||
return &runtime.PodSandboxStatus{
|
return &runtime.PodSandboxStatus{
|
||||||
Id: meta.ID,
|
Id: meta.ID,
|
||||||
|
@ -21,16 +21,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containerd/containerd/api/types/task"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/containerd/containerd/api/types/task"
|
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Variables used in the following test.
|
// Variables used in the following test.
|
||||||
@ -41,7 +39,7 @@ const (
|
|||||||
sandboxStatusTestNetNS = "test-netns"
|
sandboxStatusTestNetNS = "test-netns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getSandboxStatusTestData() (*metadata.SandboxMetadata, *runtime.PodSandboxStatus) {
|
func getSandboxStatusTestData() (*sandboxstore.Sandbox, *runtime.PodSandboxStatus) {
|
||||||
config := &runtime.PodSandboxConfig{
|
config := &runtime.PodSandboxConfig{
|
||||||
Metadata: &runtime.PodSandboxMetadata{
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
@ -64,12 +62,14 @@ func getSandboxStatusTestData() (*metadata.SandboxMetadata, *runtime.PodSandboxS
|
|||||||
|
|
||||||
createdAt := time.Now().UnixNano()
|
createdAt := time.Now().UnixNano()
|
||||||
|
|
||||||
metadata := &metadata.SandboxMetadata{
|
sandbox := &sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: sandboxStatusTestID,
|
ID: sandboxStatusTestID,
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
Config: config,
|
Config: config,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
NetNS: sandboxStatusTestNetNS,
|
NetNS: sandboxStatusTestNetNS,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedStatus := &runtime.PodSandboxStatus{
|
expectedStatus := &runtime.PodSandboxStatus{
|
||||||
@ -90,13 +90,13 @@ func getSandboxStatusTestData() (*metadata.SandboxMetadata, *runtime.PodSandboxS
|
|||||||
Annotations: config.GetAnnotations(),
|
Annotations: config.GetAnnotations(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata, expectedStatus
|
return sandbox, expectedStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPodSandboxStatus(t *testing.T) {
|
func TestPodSandboxStatus(t *testing.T) {
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
sandboxTasks []task.Task
|
sandboxTasks []task.Task
|
||||||
injectMetadata bool
|
injectSandbox bool
|
||||||
injectErr error
|
injectErr error
|
||||||
injectIP bool
|
injectIP bool
|
||||||
injectCNIErr error
|
injectCNIErr error
|
||||||
@ -106,7 +106,7 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
expectedCNICalls []string
|
expectedCNICalls []string
|
||||||
}{
|
}{
|
||||||
"sandbox status without metadata": {
|
"sandbox status without metadata": {
|
||||||
injectMetadata: false,
|
injectSandbox: false,
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
expectCalls: []string{},
|
expectCalls: []string{},
|
||||||
expectedCNICalls: []string{},
|
expectedCNICalls: []string{},
|
||||||
@ -117,7 +117,7 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
Pid: 1,
|
Pid: 1,
|
||||||
Status: task.StatusRunning,
|
Status: task.StatusRunning,
|
||||||
}},
|
}},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
||||||
@ -128,14 +128,14 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
Pid: 1,
|
Pid: 1,
|
||||||
Status: task.StatusStopped,
|
Status: task.StatusStopped,
|
||||||
}},
|
}},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
||||||
},
|
},
|
||||||
"sandbox status with non-existing sandbox container": {
|
"sandbox status with non-existing sandbox container": {
|
||||||
sandboxTasks: []task.Task{},
|
sandboxTasks: []task.Task{},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
expectState: runtime.PodSandboxState_SANDBOX_NOTREADY,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
||||||
@ -146,7 +146,7 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
Pid: 1,
|
Pid: 1,
|
||||||
Status: task.StatusRunning,
|
Status: task.StatusRunning,
|
||||||
}},
|
}},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
injectErr: errors.New("arbitrary error"),
|
injectErr: errors.New("arbitrary error"),
|
||||||
expectErr: true,
|
expectErr: true,
|
||||||
@ -159,7 +159,7 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
Pid: 1,
|
Pid: 1,
|
||||||
Status: task.StatusRunning,
|
Status: task.StatusRunning,
|
||||||
}},
|
}},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
injectIP: true,
|
injectIP: true,
|
||||||
@ -171,7 +171,7 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
Pid: 1,
|
Pid: 1,
|
||||||
Status: task.StatusRunning,
|
Status: task.StatusRunning,
|
||||||
}},
|
}},
|
||||||
injectMetadata: true,
|
injectSandbox: true,
|
||||||
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
expectState: runtime.PodSandboxState_SANDBOX_READY,
|
||||||
expectCalls: []string{"info"},
|
expectCalls: []string{"info"},
|
||||||
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
expectedCNICalls: []string{"GetContainerNetworkStatus"},
|
||||||
@ -179,14 +179,14 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Logf("TestCase %q", desc)
|
t.Logf("TestCase %q", desc)
|
||||||
metadata, expect := getSandboxStatusTestData()
|
sandbox, expect := getSandboxStatusTestData()
|
||||||
expect.Network.Ip = ""
|
expect.Network.Ip = ""
|
||||||
c := newTestCRIContainerdService()
|
c := newTestCRIContainerdService()
|
||||||
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
fake := c.taskService.(*servertesting.FakeExecutionClient)
|
||||||
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
|
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
|
||||||
fake.SetFakeTasks(test.sandboxTasks)
|
fake.SetFakeTasks(test.sandboxTasks)
|
||||||
if test.injectMetadata {
|
if test.injectSandbox {
|
||||||
assert.NoError(t, c.sandboxStore.Create(*metadata))
|
assert.NoError(t, c.sandboxStore.Add(*sandbox))
|
||||||
}
|
}
|
||||||
if test.injectErr != nil {
|
if test.injectErr != nil {
|
||||||
fake.InjectError("info", test.injectErr)
|
fake.InjectError("info", test.injectErr)
|
||||||
@ -195,8 +195,8 @@ func TestPodSandboxStatus(t *testing.T) {
|
|||||||
fakeCNIPlugin.InjectError("GetContainerNetworkStatus", test.injectCNIErr)
|
fakeCNIPlugin.InjectError("GetContainerNetworkStatus", test.injectCNIErr)
|
||||||
}
|
}
|
||||||
if test.injectIP {
|
if test.injectIP {
|
||||||
fakeCNIPlugin.SetFakePodNetwork(metadata.NetNS, metadata.Config.GetMetadata().GetNamespace(),
|
fakeCNIPlugin.SetFakePodNetwork(sandbox.NetNS, sandbox.Config.GetMetadata().GetNamespace(),
|
||||||
metadata.Config.GetMetadata().GetName(), sandboxStatusTestID, sandboxStatusTestIP)
|
sandbox.Config.GetMetadata().GetName(), sandboxStatusTestID, sandboxStatusTestIP)
|
||||||
expect.Network.Ip = sandboxStatusTestIP
|
expect.Network.Ip = sandboxStatusTestIP
|
||||||
}
|
}
|
||||||
res, err := c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{
|
res, err := c.PodSandboxStatus(context.Background(), &runtime.PodSandboxStatusRequest{
|
||||||
|
@ -50,10 +50,7 @@ func (c *criContainerdService) StopPodSandbox(ctx context.Context, r *runtime.St
|
|||||||
// and container may still be so production should not rely on this behavior.
|
// and container may still be so production should not rely on this behavior.
|
||||||
// TODO(random-liu): Delete the sandbox container before this after permanent network namespace
|
// TODO(random-liu): Delete the sandbox container before this after permanent network namespace
|
||||||
// is introduced, so that no container will be started after that.
|
// is introduced, so that no container will be started after that.
|
||||||
containers, err := c.containerStore.List()
|
containers := c.containerStore.List()
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to list all containers: %v", err)
|
|
||||||
}
|
|
||||||
for _, container := range containers {
|
for _, container := range containers {
|
||||||
if container.SandboxID != id {
|
if container.SandboxID != id {
|
||||||
continue
|
continue
|
||||||
|
@ -30,14 +30,16 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStopPodSandbox(t *testing.T) {
|
func TestStopPodSandbox(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testSandbox := metadata.SandboxMetadata{
|
testSandbox := sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
Config: &runtime.PodSandboxConfig{
|
Config: &runtime.PodSandboxConfig{
|
||||||
@ -47,6 +49,7 @@ func TestStopPodSandbox(t *testing.T) {
|
|||||||
Namespace: "test-ns",
|
Namespace: "test-ns",
|
||||||
}},
|
}},
|
||||||
NetNS: "test-netns",
|
NetNS: "test-netns",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testContainer := task.Task{
|
testContainer := task.Task{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
@ -136,7 +139,7 @@ func TestStopPodSandbox(t *testing.T) {
|
|||||||
fake.SetFakeTasks(test.sandboxTasks)
|
fake.SetFakeTasks(test.sandboxTasks)
|
||||||
|
|
||||||
if test.injectSandbox {
|
if test.injectSandbox {
|
||||||
assert.NoError(t, c.sandboxStore.Create(testSandbox))
|
assert.NoError(t, c.sandboxStore.Add(testSandbox))
|
||||||
}
|
}
|
||||||
if test.injectErr != nil {
|
if test.injectErr != nil {
|
||||||
fake.InjectError("delete", test.injectErr)
|
fake.InjectError("delete", test.injectErr)
|
||||||
@ -170,7 +173,8 @@ func TestStopPodSandbox(t *testing.T) {
|
|||||||
|
|
||||||
func TestStopContainersInSandbox(t *testing.T) {
|
func TestStopContainersInSandbox(t *testing.T) {
|
||||||
testID := "test-id"
|
testID := "test-id"
|
||||||
testSandbox := metadata.SandboxMetadata{
|
testSandbox := sandboxstore.Sandbox{
|
||||||
|
Metadata: sandboxstore.Metadata{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
Name: "test-name",
|
Name: "test-name",
|
||||||
Config: &runtime.PodSandboxConfig{
|
Config: &runtime.PodSandboxConfig{
|
||||||
@ -180,29 +184,43 @@ func TestStopContainersInSandbox(t *testing.T) {
|
|||||||
Namespace: "test-ns",
|
Namespace: "test-ns",
|
||||||
}},
|
}},
|
||||||
NetNS: "test-netns",
|
NetNS: "test-netns",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testContainers := []metadata.ContainerMetadata{
|
testContainers := []containerForTest{
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "test-cid-1",
|
ID: "test-cid-1",
|
||||||
Name: "test-cname-1",
|
Name: "test-cname-1",
|
||||||
SandboxID: testID,
|
SandboxID: testID,
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
Pid: 2,
|
Pid: 2,
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "test-cid-2",
|
ID: "test-cid-2",
|
||||||
Name: "test-cname-2",
|
Name: "test-cname-2",
|
||||||
SandboxID: testID,
|
SandboxID: testID,
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
Pid: 3,
|
Pid: 3,
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
|
metadata: containerstore.Metadata{
|
||||||
ID: "test-cid-3",
|
ID: "test-cid-3",
|
||||||
Name: "test-cname-3",
|
Name: "test-cname-3",
|
||||||
SandboxID: "other-sandbox-id",
|
SandboxID: "other-sandbox-id",
|
||||||
|
},
|
||||||
|
status: containerstore.Status{
|
||||||
Pid: 4,
|
Pid: 4,
|
||||||
StartedAt: time.Now().UnixNano(),
|
StartedAt: time.Now().UnixNano(),
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
testContainerdContainers := []task.Task{
|
testContainerdContainers := []task.Task{
|
||||||
{
|
{
|
||||||
@ -232,9 +250,11 @@ func TestStopContainersInSandbox(t *testing.T) {
|
|||||||
defer fake.Stop()
|
defer fake.Stop()
|
||||||
c.taskService = fake
|
c.taskService = fake
|
||||||
fake.SetFakeTasks(testContainerdContainers)
|
fake.SetFakeTasks(testContainerdContainers)
|
||||||
assert.NoError(t, c.sandboxStore.Create(testSandbox))
|
c.sandboxStore.Add(testSandbox)
|
||||||
for _, cntr := range testContainers {
|
for _, tc := range testContainers {
|
||||||
assert.NoError(t, c.containerStore.Create(cntr))
|
cntr, err := tc.toContainer()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NoError(t, c.containerStore.Add(cntr))
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
|
fakeCNIPlugin := c.netPlugin.(*servertesting.FakeCNIPlugin)
|
||||||
@ -257,8 +277,7 @@ func TestStopContainersInSandbox(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, res)
|
assert.NotNil(t, res)
|
||||||
|
|
||||||
cntrs, err := c.containerStore.List()
|
cntrs := c.containerStore.List()
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Len(t, cntrs, 3)
|
assert.Len(t, cntrs, 3)
|
||||||
expectedStates := map[string]runtime.ContainerState{
|
expectedStates := map[string]runtime.ContainerState{
|
||||||
"test-cid-1": runtime.ContainerState_CONTAINER_EXITED,
|
"test-cid-1": runtime.ContainerState_CONTAINER_EXITED,
|
||||||
@ -268,6 +287,6 @@ func TestStopContainersInSandbox(t *testing.T) {
|
|||||||
for id, expected := range expectedStates {
|
for id, expected := range expectedStates {
|
||||||
cntr, err := c.containerStore.Get(id)
|
cntr, err := c.containerStore.Get(id)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, expected, cntr.State())
|
assert.Equal(t, expected, cntr.Status.Get().State())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,12 @@ import (
|
|||||||
healthapi "google.golang.org/grpc/health/grpc_health_v1"
|
healthapi "google.golang.org/grpc/health/grpc_health_v1"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata/store"
|
|
||||||
osinterface "github.com/kubernetes-incubator/cri-containerd/pkg/os"
|
osinterface "github.com/kubernetes-incubator/cri-containerd/pkg/os"
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/server/agents"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/server/agents"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// k8sContainerdNamespace is the namespace we use to connect containerd.
|
// k8sContainerdNamespace is the namespace we use to connect containerd.
|
||||||
@ -57,19 +58,19 @@ type criContainerdService struct {
|
|||||||
// sandboxImage is the image to use for sandbox container.
|
// sandboxImage is the image to use for sandbox container.
|
||||||
// TODO(random-liu): Make this configurable via flag.
|
// TODO(random-liu): Make this configurable via flag.
|
||||||
sandboxImage string
|
sandboxImage string
|
||||||
// sandboxStore stores all sandbox metadata.
|
// sandboxStore stores all resources associated with sandboxes.
|
||||||
sandboxStore metadata.SandboxStore
|
sandboxStore *sandboxstore.Store
|
||||||
// imageMetadataStore stores all image metadata.
|
|
||||||
imageMetadataStore metadata.ImageMetadataStore
|
|
||||||
// sandboxNameIndex stores all sandbox names and make sure each name
|
// sandboxNameIndex stores all sandbox names and make sure each name
|
||||||
// is unique.
|
// is unique.
|
||||||
sandboxNameIndex *registrar.Registrar
|
sandboxNameIndex *registrar.Registrar
|
||||||
// containerStore stores all container metadata.
|
// containerStore stores all resources associated with containers.
|
||||||
containerStore metadata.ContainerStore
|
containerStore *containerstore.Store
|
||||||
// containerNameIndex stores all container names and make sure each
|
// containerNameIndex stores all container names and make sure each
|
||||||
// name is unique.
|
// name is unique.
|
||||||
containerNameIndex *registrar.Registrar
|
containerNameIndex *registrar.Registrar
|
||||||
// containerService is containerd tasks client.
|
// imageStore stores all resources associated with images.
|
||||||
|
imageStore *imagestore.Store
|
||||||
|
// containerService is containerd containers client.
|
||||||
containerService containers.ContainersClient
|
containerService containers.ContainersClient
|
||||||
// taskService is containerd tasks client.
|
// taskService is containerd tasks client.
|
||||||
taskService execution.TasksClient
|
taskService execution.TasksClient
|
||||||
@ -96,7 +97,7 @@ type criContainerdService struct {
|
|||||||
|
|
||||||
// NewCRIContainerdService returns a new instance of CRIContainerdService
|
// NewCRIContainerdService returns a new instance of CRIContainerdService
|
||||||
func NewCRIContainerdService(containerdEndpoint, rootDir, networkPluginBinDir, networkPluginConfDir string) (CRIContainerdService, error) {
|
func NewCRIContainerdService(containerdEndpoint, rootDir, networkPluginBinDir, networkPluginConfDir string) (CRIContainerdService, error) {
|
||||||
// TODO(random-liu): [P2] Recover from runtime state and metadata store.
|
// TODO(random-liu): [P2] Recover from runtime state and checkpoint.
|
||||||
|
|
||||||
client, err := containerd.New(containerdEndpoint, containerd.WithDefaultNamespace(k8sContainerdNamespace))
|
client, err := containerd.New(containerdEndpoint, containerd.WithDefaultNamespace(k8sContainerdNamespace))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -107,9 +108,9 @@ func NewCRIContainerdService(containerdEndpoint, rootDir, networkPluginBinDir, n
|
|||||||
os: osinterface.RealOS{},
|
os: osinterface.RealOS{},
|
||||||
rootDir: rootDir,
|
rootDir: rootDir,
|
||||||
sandboxImage: defaultSandboxImage,
|
sandboxImage: defaultSandboxImage,
|
||||||
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
|
sandboxStore: sandboxstore.NewStore(),
|
||||||
containerStore: metadata.NewContainerStore(store.NewMetadataStore()),
|
containerStore: containerstore.NewStore(),
|
||||||
imageMetadataStore: metadata.NewImageMetadataStore(store.NewMetadataStore()),
|
imageStore: imagestore.NewStore(),
|
||||||
sandboxNameIndex: registrar.NewRegistrar(),
|
sandboxNameIndex: registrar.NewRegistrar(),
|
||||||
containerNameIndex: registrar.NewRegistrar(),
|
containerNameIndex: registrar.NewRegistrar(),
|
||||||
containerService: client.ContainerService(),
|
containerService: client.ContainerService(),
|
||||||
|
@ -29,12 +29,13 @@ import (
|
|||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
"k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||||
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata"
|
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/metadata/store"
|
|
||||||
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
ostesting "github.com/kubernetes-incubator/cri-containerd/pkg/os/testing"
|
||||||
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
|
"github.com/kubernetes-incubator/cri-containerd/pkg/registrar"
|
||||||
agentstesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/agents/testing"
|
agentstesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/agents/testing"
|
||||||
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
servertesting "github.com/kubernetes-incubator/cri-containerd/pkg/server/testing"
|
||||||
|
containerstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/container"
|
||||||
|
imagestore "github.com/kubernetes-incubator/cri-containerd/pkg/store/image"
|
||||||
|
sandboxstore "github.com/kubernetes-incubator/cri-containerd/pkg/store/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
type nopReadWriteCloser struct{}
|
type nopReadWriteCloser struct{}
|
||||||
@ -58,10 +59,10 @@ func newTestCRIContainerdService() *criContainerdService {
|
|||||||
os: ostesting.NewFakeOS(),
|
os: ostesting.NewFakeOS(),
|
||||||
rootDir: testRootDir,
|
rootDir: testRootDir,
|
||||||
sandboxImage: testSandboxImage,
|
sandboxImage: testSandboxImage,
|
||||||
sandboxStore: metadata.NewSandboxStore(store.NewMetadataStore()),
|
sandboxStore: sandboxstore.NewStore(),
|
||||||
imageMetadataStore: metadata.NewImageMetadataStore(store.NewMetadataStore()),
|
imageStore: imagestore.NewStore(),
|
||||||
sandboxNameIndex: registrar.NewRegistrar(),
|
sandboxNameIndex: registrar.NewRegistrar(),
|
||||||
containerStore: metadata.NewContainerStore(store.NewMetadataStore()),
|
containerStore: containerstore.NewStore(),
|
||||||
containerNameIndex: registrar.NewRegistrar(),
|
containerNameIndex: registrar.NewRegistrar(),
|
||||||
taskService: servertesting.NewFakeExecutionClient(),
|
taskService: servertesting.NewFakeExecutionClient(),
|
||||||
containerService: servertesting.NewFakeContainersClient(),
|
containerService: servertesting.NewFakeContainersClient(),
|
||||||
@ -88,11 +89,11 @@ func TestSandboxOperations(t *testing.T) {
|
|||||||
return nopReadWriteCloser{}, nil
|
return nopReadWriteCloser{}, nil
|
||||||
}
|
}
|
||||||
// Insert sandbox image metadata.
|
// Insert sandbox image metadata.
|
||||||
assert.NoError(t, c.imageMetadataStore.Create(metadata.ImageMetadata{
|
c.imageStore.Add(imagestore.Image{
|
||||||
ID: testSandboxImage,
|
ID: testSandboxImage,
|
||||||
ChainID: "test-chain-id",
|
ChainID: "test-chain-id",
|
||||||
Config: &imagespec.ImageConfig{Entrypoint: []string{"/pause"}},
|
Config: &imagespec.ImageConfig{Entrypoint: []string{"/pause"}},
|
||||||
}))
|
})
|
||||||
|
|
||||||
config := &runtime.PodSandboxConfig{
|
config := &runtime.PodSandboxConfig{
|
||||||
Metadata: &runtime.PodSandboxMetadata{
|
Metadata: &runtime.PodSandboxMetadata{
|
||||||
|
Loading…
Reference in New Issue
Block a user