diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container.go b/pkg/kubelet/kuberuntime/kuberuntime_container.go index 43ee831a476..83727d56884 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_container.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_container.go @@ -97,6 +97,19 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb } m.recorder.Eventf(ref, api.EventTypeNormal, events.StartedContainer, "Started container with id %v", containerID) + // Symlink container logs to the legacy container log location for cluster logging + // support. + // TODO(random-liu): Remove this after cluster logging supports CRI container log path. + containerMeta := containerConfig.GetMetadata() + sandboxMeta := podSandboxConfig.GetMetadata() + legacySymlink := legacyLogSymlink(containerID, containerMeta.GetName(), sandboxMeta.GetName(), + sandboxMeta.GetNamespace()) + containerLog := filepath.Join(podSandboxConfig.GetLogDirectory(), containerConfig.GetLogPath()) + if err := m.osInterface.Symlink(containerLog, legacySymlink); err != nil { + glog.Errorf("Failed to create legacy symbolic link %q to container %q log %q: %v", + legacySymlink, containerID, containerLog, err) + } + // Step 4: execute the post start hook. if container.Lifecycle != nil && container.Lifecycle.PostStart != nil { kubeContainerID := kubecontainer.ContainerID{ @@ -112,8 +125,6 @@ func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandb } } - // TODO(random-liu): Add legacy container log location support. - return "", nil } @@ -696,7 +707,17 @@ func (m *kubeGenericRuntimeManager) ExecInContainer(containerID kubecontainer.Co // it will not write container logs anymore in that state. func (m *kubeGenericRuntimeManager) removeContainer(containerID string) error { glog.V(4).Infof("Removing container %q", containerID) - // Cleanup the container log. + // Remove the container log. + if err := m.removeContainerLog(containerID); err != nil { + return err + } + // Remove the container. + return m.runtimeService.RemoveContainer(containerID) +} + +// removeContainerLog removes the container log. +func (m *kubeGenericRuntimeManager) removeContainerLog(containerID string) error { + // Remove the container log. status, err := m.runtimeService.ContainerStatus(containerID) if err != nil { glog.Errorf("ContainerStatus for %q error: %v", containerID, err) @@ -710,8 +731,17 @@ func (m *kubeGenericRuntimeManager) removeContainer(containerID string) error { glog.Errorf("Failed to remove container %q log %q: %v", containerID, path, err) return err } - // Remove the container. - return m.runtimeService.RemoveContainer(containerID) + + // Remove the legacy container log symlink. + // TODO(random-liu): Remove this after cluster logging supports CRI container log path. + legacySymlink := legacyLogSymlink(containerID, labeledInfo.ContainerName, labeledInfo.PodName, + labeledInfo.PodNamespace) + if err := m.osInterface.Remove(legacySymlink); err != nil && !os.IsNotExist(err) { + glog.Errorf("Failed to remove container %q log legacy symbolic link %q: %v", + containerID, legacySymlink, err) + return err + } + return nil } // DeleteContainer removes a container. diff --git a/pkg/kubelet/kuberuntime/kuberuntime_container_test.go b/pkg/kubelet/kuberuntime/kuberuntime_container_test.go index a8858286c43..bcf3ef33324 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_container_test.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_container_test.go @@ -57,7 +57,8 @@ func TestRemoveContainer(t *testing.T) { assert.NoError(t, err) // Verify container log is removed expectedContainerLogPath := filepath.Join(podLogsRootDirectory, "12345678", "foo_0.log") - assert.Equal(t, fakeOS.Removes, []string{expectedContainerLogPath}) + expectedContainerLogSymlink := legacyLogSymlink(containerId, "foo", "bar", "new") + assert.Equal(t, fakeOS.Removes, []string{expectedContainerLogPath, expectedContainerLogSymlink}) // Verify container is removed fakeRuntime.AssertCalls([]string{"RemoveContainer"}) containers, err := fakeRuntime.ListContainers(&runtimeApi.ContainerFilter{Id: &containerId}) diff --git a/pkg/kubelet/kuberuntime/kuberuntime_gc.go b/pkg/kubelet/kuberuntime/kuberuntime_gc.go index ed28610501c..2fa766c8e5f 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_gc.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_gc.go @@ -18,6 +18,7 @@ package kuberuntime import ( "fmt" + "os" "path/filepath" "sort" "time" @@ -251,6 +252,18 @@ func (cgc *containerGC) evictPodLogsDirectories(allSourcesReady bool) error { } } } + + // Remove dead container log symlinks. + // TODO(random-liu): Remove this after cluster logging supports CRI container log path. + logSymlinks, _ := filepath.Glob(filepath.Join(legacyContainerLogsDir, fmt.Sprintf("*.%s", legacyLogSuffix))) + for _, logSymlink := range logSymlinks { + if _, err := osInterface.Stat(logSymlink); os.IsNotExist(err) { + err := osInterface.Remove(logSymlink) + if err != nil { + glog.Errorf("Failed to remove container log dead symlink %q: %v", logSymlink, err) + } + } + } return nil } diff --git a/pkg/kubelet/kuberuntime/legacy.go b/pkg/kubelet/kuberuntime/legacy.go new file mode 100644 index 00000000000..3805165634b --- /dev/null +++ b/pkg/kubelet/kuberuntime/legacy.go @@ -0,0 +1,41 @@ +/* +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 kuberuntime + +import ( + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" + "k8s.io/kubernetes/pkg/kubelet/dockertools" +) + +// This file implements the functions that are needed for backward +// compatibility. Therefore, it imports various kubernetes packages +// directly. + +const ( + // legacyContainerLogsDir is the legacy location of container logs. It is the same with + // kubelet.containerLogsDir. + legacyContainerLogsDir = "/var/log/containers" + // legacyLogSuffix is the legacy log suffix. + legacyLogSuffix = dockertools.LogSuffix +) + +// legacyLogSymlink composes the legacy container log path. It is only used for legacy cluster +// logging support. +func legacyLogSymlink(containerID string, containerName, podName, podNamespace string) string { + return dockertools.LogSymlink(legacyContainerLogsDir, kubecontainer.BuildPodFullName(podName, podNamespace), + containerName, containerID) +}