123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /*
- Copyright 2014 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 dockertools
- import (
- "fmt"
- "reflect"
- "sort"
- "testing"
- "time"
- "github.com/stretchr/testify/assert"
- "k8s.io/kubernetes/pkg/api"
- kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
- "k8s.io/kubernetes/pkg/types"
- )
- func newTestContainerGC(t *testing.T) (*containerGC, *FakeDockerClient) {
- fakeDocker := new(FakeDockerClient)
- fakePodGetter := newFakePodGetter()
- gc := NewContainerGC(fakeDocker, fakePodGetter, "")
- return gc, fakeDocker
- }
- // Makes a stable time object, lower id is earlier time.
- func makeTime(id int) time.Time {
- var zero time.Time
- return zero.Add(time.Duration(id) * time.Second)
- }
- // Makes a container with the specified properties.
- func makeContainer(id, uid, name string, running bool, created time.Time) *FakeContainer {
- return &FakeContainer{
- Name: fmt.Sprintf("/k8s_%s_bar_new_%s_42", name, uid),
- Running: running,
- ID: id,
- CreatedAt: created,
- }
- }
- // Makes a container with unidentified name and specified properties.
- func makeUndefinedContainer(id string, running bool, created time.Time) *FakeContainer {
- return &FakeContainer{
- Name: "/k8s_unidentified",
- Running: running,
- ID: id,
- CreatedAt: created,
- }
- }
- func addPods(podGetter podGetter, podUIDs ...types.UID) {
- fakePodGetter := podGetter.(*fakePodGetter)
- for _, uid := range podUIDs {
- fakePodGetter.pods[uid] = &api.Pod{
- ObjectMeta: api.ObjectMeta{
- Name: "pod" + string(uid),
- Namespace: "test",
- UID: uid,
- },
- }
- }
- }
- func verifyStringArrayEqualsAnyOrder(t *testing.T, actual, expected []string) {
- act := make([]string, len(actual))
- exp := make([]string, len(expected))
- copy(act, actual)
- copy(exp, expected)
- sort.StringSlice(act).Sort()
- sort.StringSlice(exp).Sort()
- if !reflect.DeepEqual(exp, act) {
- t.Errorf("Expected(sorted): %#v, Actual(sorted): %#v", exp, act)
- }
- }
- func TestDeleteContainerSkipRunningContainer(t *testing.T) {
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers([]*FakeContainer{
- makeContainer("1876", "foo", "POD", true, makeTime(0)),
- })
- addPods(gc.podGetter, "foo")
- assert.Error(t, gc.deleteContainer("1876"))
- assert.Len(t, fakeDocker.Removed, 0)
- }
- func TestDeleteContainerRemoveDeadContainer(t *testing.T) {
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers([]*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- })
- addPods(gc.podGetter, "foo")
- assert.Nil(t, gc.deleteContainer("1876"))
- assert.Len(t, fakeDocker.Removed, 1)
- }
- func TestGarbageCollectZeroMaxContainers(t *testing.T) {
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers([]*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- })
- addPods(gc.podGetter, "foo")
- assert.Nil(t, gc.GarbageCollect(kubecontainer.ContainerGCPolicy{MinAge: time.Minute, MaxPerPodContainer: 1, MaxContainers: 0}, true))
- assert.Len(t, fakeDocker.Removed, 1)
- }
- func TestGarbageCollectNoMaxPerPodContainerLimit(t *testing.T) {
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers([]*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- makeContainer("2876", "foo1", "POD", false, makeTime(1)),
- makeContainer("3876", "foo2", "POD", false, makeTime(2)),
- makeContainer("4876", "foo3", "POD", false, makeTime(3)),
- makeContainer("5876", "foo4", "POD", false, makeTime(4)),
- })
- addPods(gc.podGetter, "foo", "foo1", "foo2", "foo3", "foo4")
- assert.Nil(t, gc.GarbageCollect(kubecontainer.ContainerGCPolicy{MinAge: time.Minute, MaxPerPodContainer: -1, MaxContainers: 4}, true))
- assert.Len(t, fakeDocker.Removed, 1)
- }
- func TestGarbageCollectNoMaxLimit(t *testing.T) {
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers([]*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- makeContainer("2876", "foo1", "POD", false, makeTime(0)),
- makeContainer("3876", "foo2", "POD", false, makeTime(0)),
- makeContainer("4876", "foo3", "POD", false, makeTime(0)),
- makeContainer("5876", "foo4", "POD", false, makeTime(0)),
- })
- addPods(gc.podGetter, "foo", "foo1", "foo2", "foo3", "foo4")
- assert.Len(t, fakeDocker.Removed, 0)
- }
- func TestGarbageCollect(t *testing.T) {
- tests := []struct {
- containers []*FakeContainer
- expectedRemoved []string
- }{
- // Don't remove containers started recently.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, time.Now()),
- makeContainer("2876", "foo", "POD", false, time.Now()),
- makeContainer("3876", "foo", "POD", false, time.Now()),
- },
- },
- // Remove oldest containers.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- makeContainer("2876", "foo", "POD", false, makeTime(1)),
- makeContainer("3876", "foo", "POD", false, makeTime(2)),
- },
- expectedRemoved: []string{"1876"},
- },
- // Only remove non-running containers.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", true, makeTime(0)),
- makeContainer("2876", "foo", "POD", false, makeTime(1)),
- makeContainer("3876", "foo", "POD", false, makeTime(2)),
- makeContainer("4876", "foo", "POD", false, makeTime(3)),
- },
- expectedRemoved: []string{"2876"},
- },
- // Less than maxContainerCount doesn't delete any.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- },
- },
- // maxContainerCount applies per (UID,container) pair.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- makeContainer("2876", "foo", "POD", false, makeTime(1)),
- makeContainer("3876", "foo", "POD", false, makeTime(2)),
- makeContainer("1076", "foo", "bar", false, makeTime(0)),
- makeContainer("2076", "foo", "bar", false, makeTime(1)),
- makeContainer("3076", "foo", "bar", false, makeTime(2)),
- makeContainer("1176", "foo2", "POD", false, makeTime(0)),
- makeContainer("2176", "foo2", "POD", false, makeTime(1)),
- makeContainer("3176", "foo2", "POD", false, makeTime(2)),
- },
- expectedRemoved: []string{"1076", "1176", "1876"},
- },
- // Remove non-running unidentified Kubernetes containers.
- {
- containers: []*FakeContainer{
- makeUndefinedContainer("1876", true, makeTime(0)),
- makeUndefinedContainer("2876", false, makeTime(0)),
- makeContainer("3876", "foo", "POD", false, makeTime(0)),
- },
- expectedRemoved: []string{"2876"},
- },
- // Max limit applied and tries to keep from every pod.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(0)),
- makeContainer("2876", "foo", "POD", false, makeTime(1)),
- makeContainer("3876", "foo1", "POD", false, makeTime(0)),
- makeContainer("4876", "foo1", "POD", false, makeTime(1)),
- makeContainer("5876", "foo2", "POD", false, makeTime(0)),
- makeContainer("6876", "foo2", "POD", false, makeTime(1)),
- makeContainer("7876", "foo3", "POD", false, makeTime(0)),
- makeContainer("8876", "foo3", "POD", false, makeTime(1)),
- makeContainer("9876", "foo4", "POD", false, makeTime(0)),
- makeContainer("10876", "foo4", "POD", false, makeTime(1)),
- },
- expectedRemoved: []string{"1876", "3876", "5876", "7876", "9876"},
- },
- // If more pods than limit allows, evicts oldest pod.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(1)),
- makeContainer("2876", "foo", "POD", false, makeTime(2)),
- makeContainer("3876", "foo1", "POD", false, makeTime(1)),
- makeContainer("4876", "foo1", "POD", false, makeTime(2)),
- makeContainer("5876", "foo2", "POD", false, makeTime(0)),
- makeContainer("6876", "foo3", "POD", false, makeTime(1)),
- makeContainer("7876", "foo4", "POD", false, makeTime(0)),
- makeContainer("8876", "foo5", "POD", false, makeTime(1)),
- makeContainer("9876", "foo6", "POD", false, makeTime(2)),
- makeContainer("10876", "foo7", "POD", false, makeTime(1)),
- },
- expectedRemoved: []string{"1876", "3876", "5876", "7876"},
- },
- // Containers for deleted pods should be GC'd.
- {
- containers: []*FakeContainer{
- makeContainer("1876", "foo", "POD", false, makeTime(1)),
- makeContainer("2876", "foo", "POD", false, makeTime(2)),
- makeContainer("3876", "deleted", "POD", false, makeTime(1)),
- makeContainer("4876", "deleted", "POD", false, makeTime(2)),
- makeContainer("5876", "deleted", "POD", false, time.Now()), // Deleted pods still respect MinAge.
- },
- expectedRemoved: []string{"3876", "4876"},
- },
- }
- for i, test := range tests {
- t.Logf("Running test case with index %d", i)
- gc, fakeDocker := newTestContainerGC(t)
- fakeDocker.SetFakeContainers(test.containers)
- addPods(gc.podGetter, "foo", "foo1", "foo2", "foo3", "foo4", "foo5", "foo6", "foo7")
- assert.Nil(t, gc.GarbageCollect(kubecontainer.ContainerGCPolicy{MinAge: time.Hour, MaxPerPodContainer: 2, MaxContainers: 6}, true))
- verifyStringArrayEqualsAnyOrder(t, fakeDocker.Removed, test.expectedRemoved)
- }
- }
|