2016-08-30 00:40:28 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 The Kubernetes Authors.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package dockershim
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-10-14 18:52:18 +00:00
|
|
|
"path/filepath"
|
2016-08-30 00:40:28 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
|
|
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
2016-10-14 18:52:18 +00:00
|
|
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
2016-08-30 00:40:28 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// A helper to create a basic config.
|
2016-09-15 20:08:51 +00:00
|
|
|
func makeContainerConfig(sConfig *runtimeApi.PodSandboxConfig, name, image string, attempt uint32, labels, annotations map[string]string) *runtimeApi.ContainerConfig {
|
2016-08-30 00:40:28 +00:00
|
|
|
return &runtimeApi.ContainerConfig{
|
|
|
|
Metadata: &runtimeApi.ContainerMetadata{
|
|
|
|
Name: &name,
|
|
|
|
Attempt: &attempt,
|
|
|
|
},
|
2016-09-15 20:08:51 +00:00
|
|
|
Image: &runtimeApi.ImageSpec{Image: &image},
|
|
|
|
Labels: labels,
|
|
|
|
Annotations: annotations,
|
2016-08-30 00:40:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestListContainers creates several containers and then list them to check
|
|
|
|
// whether the correct metadatas, states, and labels are returned.
|
|
|
|
func TestListContainers(t *testing.T) {
|
2016-09-27 22:13:27 +00:00
|
|
|
ds, _, _ := newTestDockerService()
|
2016-08-30 00:40:28 +00:00
|
|
|
podName, namespace := "foo", "bar"
|
|
|
|
containerName, image := "sidecar", "logger"
|
|
|
|
|
|
|
|
configs := []*runtimeApi.ContainerConfig{}
|
|
|
|
sConfigs := []*runtimeApi.PodSandboxConfig{}
|
|
|
|
for i := 0; i < 3; i++ {
|
|
|
|
s := makeSandboxConfig(fmt.Sprintf("%s%d", podName, i),
|
|
|
|
fmt.Sprintf("%s%d", namespace, i), fmt.Sprintf("%d", i), 0)
|
2016-09-15 20:08:51 +00:00
|
|
|
labels := map[string]string{"abc.xyz": fmt.Sprintf("label%d", i)}
|
2016-10-13 21:40:41 +00:00
|
|
|
annotations := map[string]string{"foo.bar.baz": fmt.Sprintf("annotation%d", i)}
|
2016-08-30 00:40:28 +00:00
|
|
|
c := makeContainerConfig(s, fmt.Sprintf("%s%d", containerName, i),
|
2016-09-15 20:08:51 +00:00
|
|
|
fmt.Sprintf("%s:v%d", image, i), uint32(i), labels, annotations)
|
2016-08-30 00:40:28 +00:00
|
|
|
sConfigs = append(sConfigs, s)
|
|
|
|
configs = append(configs, c)
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := []*runtimeApi.Container{}
|
2016-11-01 19:58:04 +00:00
|
|
|
state := runtimeApi.ContainerState_CONTAINER_RUNNING
|
2016-10-06 21:52:40 +00:00
|
|
|
var createdAt int64 = 0
|
2016-08-30 00:40:28 +00:00
|
|
|
for i := range configs {
|
|
|
|
// We don't care about the sandbox id; pass a bogus one.
|
|
|
|
sandboxID := fmt.Sprintf("sandboxid%d", i)
|
|
|
|
id, err := ds.CreateContainer(sandboxID, configs[i], sConfigs[i])
|
|
|
|
assert.NoError(t, err)
|
|
|
|
err = ds.StartContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
imageRef := "" // FakeDockerClient doesn't populate ImageRef yet.
|
|
|
|
// Prepend to the expected list because ListContainers returns
|
|
|
|
// the most recent containers first.
|
|
|
|
expected = append([]*runtimeApi.Container{{
|
2016-10-02 03:55:06 +00:00
|
|
|
Metadata: configs[i].Metadata,
|
|
|
|
Id: &id,
|
|
|
|
PodSandboxId: &sandboxID,
|
|
|
|
State: &state,
|
2016-10-06 21:52:40 +00:00
|
|
|
CreatedAt: &createdAt,
|
2016-10-02 03:55:06 +00:00
|
|
|
Image: configs[i].Image,
|
|
|
|
ImageRef: &imageRef,
|
|
|
|
Labels: configs[i].Labels,
|
|
|
|
Annotations: configs[i].Annotations,
|
2016-08-30 00:40:28 +00:00
|
|
|
}}, expected...)
|
|
|
|
}
|
|
|
|
containers, err := ds.ListContainers(nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Len(t, containers, len(expected))
|
|
|
|
assert.Equal(t, expected, containers)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestContainerStatus tests the basic lifecycle operations and verify that
|
|
|
|
// the status returned reflects the operations performed.
|
|
|
|
func TestContainerStatus(t *testing.T) {
|
2016-10-01 00:08:32 +00:00
|
|
|
ds, fDocker, fClock := newTestDockerService()
|
2016-08-30 00:40:28 +00:00
|
|
|
sConfig := makeSandboxConfig("foo", "bar", "1", 0)
|
2016-09-15 20:08:51 +00:00
|
|
|
labels := map[string]string{"abc.xyz": "foo"}
|
|
|
|
annotations := map[string]string{"foo.bar.baz": "abc"}
|
|
|
|
config := makeContainerConfig(sConfig, "pause", "iamimage", 0, labels, annotations)
|
2016-08-30 00:40:28 +00:00
|
|
|
|
|
|
|
var defaultTime time.Time
|
2016-10-11 21:50:55 +00:00
|
|
|
dt := defaultTime.UnixNano()
|
2016-08-30 00:40:28 +00:00
|
|
|
ct, st, ft := dt, dt, dt
|
2016-11-01 19:58:04 +00:00
|
|
|
state := runtimeApi.ContainerState_CONTAINER_CREATED
|
2016-08-30 00:40:28 +00:00
|
|
|
// The following variables are not set in FakeDockerClient.
|
2016-10-08 04:35:18 +00:00
|
|
|
imageRef := DockerImageIDPrefix + ""
|
2016-08-30 00:40:28 +00:00
|
|
|
exitCode := int32(0)
|
2016-09-23 19:32:21 +00:00
|
|
|
var reason, message string
|
2016-08-30 00:40:28 +00:00
|
|
|
|
|
|
|
expected := &runtimeApi.ContainerStatus{
|
2016-09-15 20:08:51 +00:00
|
|
|
State: &state,
|
|
|
|
CreatedAt: &ct,
|
|
|
|
StartedAt: &st,
|
|
|
|
FinishedAt: &ft,
|
|
|
|
Metadata: config.Metadata,
|
|
|
|
Image: config.Image,
|
|
|
|
ImageRef: &imageRef,
|
|
|
|
ExitCode: &exitCode,
|
|
|
|
Reason: &reason,
|
2016-09-23 19:32:21 +00:00
|
|
|
Message: &message,
|
2016-09-15 20:08:51 +00:00
|
|
|
Mounts: []*runtimeApi.Mount{},
|
|
|
|
Labels: config.Labels,
|
|
|
|
Annotations: config.Annotations,
|
2016-08-30 00:40:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the container.
|
2016-09-25 05:43:39 +00:00
|
|
|
fClock.SetTime(time.Now().Add(-1 * time.Hour))
|
2016-10-11 21:50:55 +00:00
|
|
|
*expected.CreatedAt = fClock.Now().UnixNano()
|
2016-10-01 00:08:32 +00:00
|
|
|
const sandboxId = "sandboxid"
|
|
|
|
id, err := ds.CreateContainer(sandboxId, config, sConfig)
|
|
|
|
|
|
|
|
// Check internal labels
|
|
|
|
c, err := fDocker.InspectContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, c.Config.Labels[containerTypeLabelKey], containerTypeLabelContainer)
|
|
|
|
assert.Equal(t, c.Config.Labels[sandboxIDLabelKey], sandboxId)
|
|
|
|
|
2016-08-30 00:40:28 +00:00
|
|
|
// Set the id manually since we don't know the id until it's created.
|
|
|
|
expected.Id = &id
|
|
|
|
assert.NoError(t, err)
|
|
|
|
status, err := ds.ContainerStatus(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, expected, status)
|
|
|
|
|
|
|
|
// Advance the clock and start the container.
|
|
|
|
fClock.SetTime(time.Now())
|
2016-10-11 21:50:55 +00:00
|
|
|
*expected.StartedAt = fClock.Now().UnixNano()
|
2016-11-01 19:58:04 +00:00
|
|
|
*expected.State = runtimeApi.ContainerState_CONTAINER_RUNNING
|
2016-08-30 00:40:28 +00:00
|
|
|
|
|
|
|
err = ds.StartContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
status, err = ds.ContainerStatus(id)
|
|
|
|
assert.Equal(t, expected, status)
|
|
|
|
|
|
|
|
// Advance the clock and stop the container.
|
2016-09-25 05:43:39 +00:00
|
|
|
fClock.SetTime(time.Now().Add(1 * time.Hour))
|
2016-10-11 21:50:55 +00:00
|
|
|
*expected.FinishedAt = fClock.Now().UnixNano()
|
2016-11-01 19:58:04 +00:00
|
|
|
*expected.State = runtimeApi.ContainerState_CONTAINER_EXITED
|
2016-08-30 00:40:28 +00:00
|
|
|
*expected.Reason = "Completed"
|
|
|
|
|
|
|
|
err = ds.StopContainer(id, 0)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
status, err = ds.ContainerStatus(id)
|
|
|
|
assert.Equal(t, expected, status)
|
|
|
|
|
|
|
|
// Remove the container.
|
|
|
|
err = ds.RemoveContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
status, err = ds.ContainerStatus(id)
|
|
|
|
assert.Error(t, err, fmt.Sprintf("status of container: %+v", status))
|
|
|
|
}
|
2016-10-14 18:52:18 +00:00
|
|
|
|
|
|
|
// TestContainerLogPath tests the container log creation logic.
|
|
|
|
func TestContainerLogPath(t *testing.T) {
|
|
|
|
ds, fDocker, _ := newTestDockerService()
|
|
|
|
podLogPath := "/pod/1"
|
|
|
|
containerLogPath := "0"
|
|
|
|
kubeletContainerLogPath := filepath.Join(podLogPath, containerLogPath)
|
|
|
|
sConfig := makeSandboxConfig("foo", "bar", "1", 0)
|
|
|
|
sConfig.LogDirectory = &podLogPath
|
|
|
|
config := makeContainerConfig(sConfig, "pause", "iamimage", 0, nil, nil)
|
|
|
|
config.LogPath = &containerLogPath
|
|
|
|
|
|
|
|
const sandboxId = "sandboxid"
|
|
|
|
id, err := ds.CreateContainer(sandboxId, config, sConfig)
|
|
|
|
|
|
|
|
// Check internal container log label
|
|
|
|
c, err := fDocker.InspectContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, c.Config.Labels[containerLogPathLabelKey], kubeletContainerLogPath)
|
|
|
|
|
|
|
|
// Set docker container log path
|
|
|
|
dockerContainerLogPath := "/docker/container/log"
|
|
|
|
c.LogPath = dockerContainerLogPath
|
|
|
|
|
|
|
|
// Verify container log symlink creation
|
|
|
|
fakeOS := ds.os.(*containertest.FakeOS)
|
|
|
|
fakeOS.SymlinkFn = func(oldname, newname string) error {
|
|
|
|
assert.Equal(t, dockerContainerLogPath, oldname)
|
|
|
|
assert.Equal(t, kubeletContainerLogPath, newname)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
err = ds.StartContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
err = ds.StopContainer(id, 0)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Verify container log symlink deletion
|
|
|
|
err = ds.RemoveContainer(id)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, fakeOS.Removes, []string{kubeletContainerLogPath})
|
|
|
|
}
|