diff --git a/cri/v1alpha2/cri.go b/cri/v1alpha2/cri.go index ac72fe76f..06dbf8dee 100644 --- a/cri/v1alpha2/cri.go +++ b/cri/v1alpha2/cri.go @@ -33,6 +33,7 @@ import ( // NOTE: "golang.org/x/net/context" is compatible with standard "context" in golang1.7+. "github.com/cri-o/ocicni/pkg/ocicni" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -250,7 +251,8 @@ func (c *CriManager) RunPodSandbox(ctx context.Context, r *runtime.RunPodSandbox return nil, err } sandboxMeta := &SandboxMeta{ - ID: id, + ID: id, + ContainerLogMap: make(map[string]string), } if err := c.SandboxStore.Put(sandboxMeta); err != nil { return nil, err @@ -499,28 +501,26 @@ func (c *CriManager) RemovePodSandbox(ctx context.Context, r *runtime.RemovePodS // Remove all containers in the sandbox. for _, container := range containers { - err = c.ContainerMgr.Remove(ctx, container.ID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}) - if err != nil { + if err := c.ContainerMgr.Remove(ctx, container.ID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}); err != nil { return nil, fmt.Errorf("failed to remove container %q of sandbox %q: %v", container.ID, podSandboxID, err) } + logrus.Infof("success to remove container %q of sandbox %q", container.ID, podSandboxID) } // Remove the sandbox container. - err = c.ContainerMgr.Remove(ctx, podSandboxID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}) - if err != nil { + if err := c.ContainerMgr.Remove(ctx, podSandboxID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}); err != nil { return nil, fmt.Errorf("failed to remove sandbox %q: %v", podSandboxID, err) } // Cleanup the sandbox root directory. sandboxRootDir := path.Join(c.SandboxBaseDir, podSandboxID) - err = os.RemoveAll(sandboxRootDir) - if err != nil { + + if err := os.RemoveAll(sandboxRootDir); err != nil { return nil, fmt.Errorf("failed to remove root directory %q: %v", sandboxRootDir, err) } - err = c.SandboxStore.Remove(podSandboxID) - if err != nil { + if err := c.SandboxStore.Remove(podSandboxID); err != nil { return nil, fmt.Errorf("failed to remove meta %q: %v", sandboxRootDir, err) } @@ -765,6 +765,11 @@ func (c *CriManager) CreateContainer(ctx context.Context, r *runtime.CreateConta // Get container log. if config.GetLogPath() != "" { logPath := filepath.Join(sandboxConfig.GetLogDirectory(), config.GetLogPath()) + sandboxMeta.ContainerLogMap[containerID] = logPath + if err := c.SandboxStore.Put(sandboxMeta); err != nil { + return nil, err + } + if err := c.ContainerMgr.AttachCRILog(ctx, containerID, logPath); err != nil { return nil, err } @@ -825,8 +830,7 @@ func (c *CriManager) RemoveContainer(ctx context.Context, r *runtime.RemoveConta containerID := r.GetContainerId() - err := c.ContainerMgr.Remove(ctx, containerID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}) - if err != nil { + if err := c.ContainerMgr.Remove(ctx, containerID, &apitypes.ContainerRemoveOptions{Volumes: true, Force: true}); err != nil { return nil, fmt.Errorf("failed to remove container %q: %v", containerID, err) } @@ -1128,7 +1132,42 @@ func (c *CriManager) UpdateContainerResources(ctx context.Context, r *runtime.Up // to either create a new log file and return nil, or return an error. // Once it returns error, new container log file MUST NOT be created. func (c *CriManager) ReopenContainerLog(ctx context.Context, r *runtime.ReopenContainerLogRequest) (*runtime.ReopenContainerLogResponse, error) { - return nil, fmt.Errorf("ReopenContainerLog Not Implemented Yet") + containerID := r.GetContainerId() + + container, err := c.ContainerMgr.Get(ctx, containerID) + if err != nil { + return nil, fmt.Errorf("failed to get container %q with error: %v", containerID, err) + } + if !container.IsRunning() { + return nil, errors.Wrap(errtypes.ErrPreCheckFailed, "container is not running") + } + + // get the container's podSandbox id. + podSandboxID, ok := container.Config.Labels[sandboxIDLabelKey] + if !ok { + return nil, fmt.Errorf("failed to get the sandboxId of container %q", containerID) + } + + // get logPath of container + res, err := c.SandboxStore.Get(podSandboxID) + if err != nil { + return nil, fmt.Errorf("failed to get metadata of %q from SandboxStore: %v", podSandboxID, err) + } + sandboxMeta, ok := res.(*SandboxMeta) + if !ok { + return nil, fmt.Errorf("failed to type asseration for sandboxMeta: %v", res) + } + logPath, ok := sandboxMeta.ContainerLogMap[containerID] + if !ok { + logrus.Warnf("log path of container: %q is empty", containerID) + return &runtime.ReopenContainerLogResponse{}, nil + } + + if err := c.ContainerMgr.AttachCRILog(ctx, container.Name, logPath); err != nil { + return nil, err + } + + return &runtime.ReopenContainerLogResponse{}, nil } // ExecSync executes a command in the container, and returns the stdout output. diff --git a/cri/v1alpha2/cri_types.go b/cri/v1alpha2/cri_types.go index 11e17a7e6..26e10f769 100644 --- a/cri/v1alpha2/cri_types.go +++ b/cri/v1alpha2/cri_types.go @@ -20,6 +20,9 @@ type SandboxMeta struct { // NetNS is the sandbox's network namespace NetNS string + + // ContainerLogMap store the mapping of container id and CRI logPath. + ContainerLogMap map[string]string } // Key returns sandbox's id. diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index fdc298202..f55fb0971 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -973,6 +973,9 @@ func (mgr *ContainerManager) AttachContainerIO(ctx context.Context, name string, // AttachCRILog adds cri log to a container. func (mgr *ContainerManager) AttachCRILog(ctx context.Context, name string, logPath string) error { + if logPath == "" { + return errors.Wrap(errtypes.ErrInvalidParam, "logPath cannot be empty") + } c, err := mgr.container(name) if err != nil { return err diff --git a/hack/testing/run_daemon_cri_integration.sh b/hack/testing/run_daemon_cri_integration.sh index 85b3aec24..1ece50324 100755 --- a/hack/testing/run_daemon_cri_integration.sh +++ b/hack/testing/run_daemon_cri_integration.sh @@ -20,7 +20,6 @@ export PATH="${GOPATH}/bin:${PATH}" # CRI_SKIP skips the test to skip. DEFAULT_CRI_SKIP="seccomp localhost" DEFAULT_CRI_SKIP="${DEFAULT_CRI_SKIP}|should error on create with wrong options" -DEFAULT_CRI_SKIP="${DEFAULT_CRI_SKIP}|runtime should support reopening container log" CRI_SKIP="${CRI_SKIP:-"${DEFAULT_CRI_SKIP}"}" # CRI_FOCUS focuses the test to run. diff --git a/pkg/errtypes/errors.go b/pkg/errtypes/errors.go index cb8510c5a..a2d594fff 100644 --- a/pkg/errtypes/errors.go +++ b/pkg/errtypes/errors.go @@ -34,6 +34,9 @@ var ( // ErrNotModified represents that the resource is not modified ErrNotModified = errorType{codeNotModified, "not modified"} + + // ErrPreCheckFailed represents that failed to pre check. + ErrPreCheckFailed = errorType{codePreCheckFailed, "pre check failed"} ) const ( @@ -47,6 +50,7 @@ const ( codeNotImplemented codeInUse codeNotModified + codePreCheckFailed // volume error code codeVolumeExisted @@ -88,11 +92,16 @@ func IsInUse(err error) bool { return checkError(err, codeInUse) } -// IsNotModified checks the error is not modified erro or not. +// IsNotModified checks the error is not modified error or not. func IsNotModified(err error) bool { return checkError(err, codeNotModified) } +// IsPreCheckFailed checks the error is failed to pre check or not. +func IsPreCheckFailed(err error) bool { + return checkError(err, codePreCheckFailed) +} + func checkError(err error, code int) bool { err = causeError(err)