Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

RemoveContainer in Runtime interface #28627

Merged
merged 1 commit into from
Jul 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/kubelet/container/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ type Runtime interface {
// stream the log. Set 'follow' to false and specify the number of lines (e.g.
// "100" or "all") to tail the log.
GetContainerLogs(pod *api.Pod, containerID ContainerID, logOptions *api.PodLogOptions, stdout, stderr io.Writer) (err error)
// Delete a container. If the container is still running, an error is returned.
DeleteContainer(containerID ContainerID) error
// ContainerCommandRunner encapsulates the command runner interfaces for testability.
ContainerCommandRunner
// ContainerAttach encapsulates the attaching to containers for testability
Expand Down
8 changes: 8 additions & 0 deletions pkg/kubelet/container/testing/fake_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,14 @@ func (f *FakeRuntime) GarbageCollect(gcPolicy ContainerGCPolicy, ready bool) err
return f.Err
}

func (f *FakeRuntime) DeleteContainer(containerID ContainerID) error {
f.Lock()
defer f.Unlock()

f.CalledFunctions = append(f.CalledFunctions, "DeleteContainer")
return f.Err
}

func (f *FakeRuntime) ImageStats() (*ImageStats, error) {
f.Lock()
defer f.Unlock()
Expand Down
5 changes: 5 additions & 0 deletions pkg/kubelet/container/testing/runtime_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ func (r *Mock) GarbageCollect(gcPolicy ContainerGCPolicy, ready bool) error {
return args.Error(0)
}

func (r *Mock) DeleteContainer(containerID ContainerID) error {
args := r.Called(containerID)
return args.Error(0)
}

func (r *Mock) ImageStats() (*ImageStats, error) {
args := r.Called()
return args.Get(0).(*ImageStats), args.Error(1)
Expand Down
42 changes: 33 additions & 9 deletions pkg/kubelet/dockertools/container_gc.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,7 @@ func (cgc *containerGC) removeOldestN(containers []containerGCInfo, toRemove int
// Remove from oldest to newest (last to first).
numToKeep := len(containers) - toRemove
for i := numToKeep; i < len(containers); i++ {
err := cgc.client.RemoveContainer(containers[i].id, dockertypes.ContainerRemoveOptions{RemoveVolumes: true})
if err != nil {
glog.Warningf("Failed to remove dead container %q: %v", containers[i].name, err)
}
symlinkPath := LogSymlink(cgc.containerLogsDir, containers[i].podNameWithNamespace, containers[i].containerName, containers[i].id)
err = os.Remove(symlinkPath)
if err != nil && !os.IsNotExist(err) {
glog.Warningf("Failed to remove container %q log symlink %q: %v", containers[i].name, symlinkPath, err)
}
cgc.removeContainer(containers[i].id, containers[i].podNameWithNamespace, containers[i].containerName)
}

// Assume we removed the containers so that we're not too aggressive.
Expand Down Expand Up @@ -253,6 +245,38 @@ func (cgc *containerGC) GarbageCollect(gcPolicy kubecontainer.ContainerGCPolicy,
return nil
}

func (cgc *containerGC) removeContainer(id string, podNameWithNamespace string, containerName string) {
glog.V(4).Infof("Removing container %q name %q", id, containerName)
err := cgc.client.RemoveContainer(id, dockertypes.ContainerRemoveOptions{RemoveVolumes: true})
if err != nil {
glog.Warningf("Failed to remove container %q: %v", id, err)
}
symlinkPath := LogSymlink(cgc.containerLogsDir, podNameWithNamespace, containerName, id)
err = os.Remove(symlinkPath)
if err != nil && !os.IsNotExist(err) {
glog.Warningf("Failed to remove container %q log symlink %q: %v", id, symlinkPath, err)
}
}

func (cgc *containerGC) deleteContainer(id string) error {
containerInfo, err := cgc.client.InspectContainer(id)
if err != nil {
glog.Warningf("Failed to inspect container %q: %v", id, err)
return err
}
if containerInfo.State.Running {
return fmt.Errorf("container %q is still running", id)
}

containerName, _, err := ParseDockerName(containerInfo.Name)
if err != nil {
return err
}

cgc.removeContainer(id, containerName.PodFullName, containerName.ContainerName)
return nil
}

func (cgc *containerGC) isPodDeleted(podUID types.UID) bool {
_, found := cgc.podGetter.GetPodByUID(podUID)
return !found
Expand Down
22 changes: 22 additions & 0 deletions pkg/kubelet/dockertools/container_gc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ func verifyStringArrayEqualsAnyOrder(t *testing.T, actual, expected []string) {
}
}

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{
Expand Down
4 changes: 4 additions & 0 deletions pkg/kubelet/dockertools/docker_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2354,6 +2354,10 @@ func getIPCMode(pod *api.Pod) string {
return ipcMode
}

func (dm *DockerManager) DeleteContainer(containerID kubecontainer.ContainerID) error {
return dm.containerGC.deleteContainer(containerID.ID)
}

// GetNetNS returns the network namespace path for the given container
func (dm *DockerManager) GetNetNS(containerID kubecontainer.ContainerID) (string, error) {
inspectResult, err := dm.client.InspectContainer(containerID.ID)
Expand Down
4 changes: 4 additions & 0 deletions pkg/kubelet/rkt/rkt.go
Original file line number Diff line number Diff line change
Expand Up @@ -1837,6 +1837,10 @@ func podDetailsFromServiceFile(serviceFilePath string) (string, string, string,
return "", "", "", false, fmt.Errorf("failed to parse pod from file %s", serviceFilePath)
}

func (r *Runtime) DeleteContainer(containerID kubecontainer.ContainerID) error {
return fmt.Errorf("unimplemented")
}

// GarbageCollect collects the pods/containers.
// After one GC iteration:
// - The deleted pods will be removed.
Expand Down