Hello community, here is the log from the commit of package cri-o for openSUSE:Factory checked in at 2018-04-11 14:03:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cri-o (Old) and /work/SRC/openSUSE:Factory/.cri-o.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cri-o" Wed Apr 11 14:03:40 2018 rev:7 rq:595521 version:1.9.11 Changes: -------- --- /work/SRC/openSUSE:Factory/cri-o/cri-o.changes 2018-03-16 10:45:20.452170052 +0100 +++ /work/SRC/openSUSE:Factory/.cri-o.new/cri-o.changes 2018-04-11 14:05:29.307214570 +0200 @@ -1,0 +2,14 @@ +Wed Apr 11 06:44:34 UTC 2018 - vrothb...@suse.com + +- Update cri-o to v1.9.11: + * oci: avoid race on container stop + * server/sandbox_stop: Pass context through StopAllPodSandboxes + * conmon: Add container ID to syslog + * Add logging support for base condition in debug + * Simplify filter block + * Specifying a filter with no filtering expressions is now idempotent + * Add methods for listing and fetching container stats + * Implement the stats for the image_fs_info command + * Return error for container exec + +------------------------------------------------------------------- Old: ---- cri-o-1.9.10.tar.xz New: ---- cri-o-1.9.11.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cri-o.spec ++++++ --- /var/tmp/diff_new_pack.541LYB/_old 2018-04-11 14:05:31.247144011 +0200 +++ /var/tmp/diff_new_pack.541LYB/_new 2018-04-11 14:05:31.247144011 +0200 @@ -31,7 +31,7 @@ %define name_source2 sysconfig.crio %define name_source3 crio.conf Name: cri-o -Version: 1.9.10 +Version: 1.9.11 Release: 0 Summary: OCI-based implementation of Kubernetes Container Runtime Interface License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.541LYB/_old 2018-04-11 14:05:31.287142556 +0200 +++ /var/tmp/diff_new_pack.541LYB/_new 2018-04-11 14:05:31.287142556 +0200 @@ -2,8 +2,8 @@ <service name="tar_scm" mode="disabled"> <param name="url">https://github.com/kubernetes-incubator/cri-o</param> <param name="scm">git</param> -<param name="versionformat">1.9.10</param> -<param name="revision">v1.9.10</param> +<param name="versionformat">1.9.11</param> +<param name="revision">v1.9.11</param> </service> <service name="recompress" mode="disabled"> <param name="file">cri-o-*.tar</param> ++++++ cri-o-1.9.10.tar.xz -> cri-o-1.9.11.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/cmd/crio/main.go new/cri-o-1.9.11/cmd/crio/main.go --- old/cri-o-1.9.10/cmd/crio/main.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/cmd/crio/main.go 2018-04-09 20:22:42.000000000 +0200 @@ -164,11 +164,12 @@ continue } *signalled = true + ctx := context.Background() gserver.GracefulStop() - hserver.Shutdown(context.Background()) + hserver.Shutdown(ctx) sserver.StopStreamServer() sserver.StopExitMonitor() - if err := sserver.Shutdown(); err != nil { + if err := sserver.Shutdown(ctx); err != nil { logrus.Warnf("error shutting down main service %v", err) } return @@ -408,6 +409,7 @@ } app.Action = func(c *cli.Context) error { + ctx := context.Background() if c.GlobalBool("profile") { profilePort := c.GlobalInt("profile-port") profileEndpoint := fmt.Sprintf("localhost:%v", profilePort) @@ -454,7 +456,7 @@ s := grpc.NewServer() - service, err := server.New(config) + service, err := server.New(ctx, config) if err != nil { logrus.Fatal(err) } @@ -522,7 +524,7 @@ case <-serverCloseCh: } - service.Shutdown() + service.Shutdown(ctx) <-streamServerCloseCh logrus.Debug("closed stream server") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/conmon/conmon.c new/cri-o-1.9.11/conmon/conmon.c --- old/cri-o-1.9.10/conmon/conmon.c 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/conmon/conmon.c 2018-04-09 20:22:42.000000000 +0200 @@ -28,32 +28,6 @@ #include "cmsg.h" -#define pexit(fmt, ...) \ - do { \ - fprintf(stderr, "[conmon:e]: " fmt " %m\n", ##__VA_ARGS__); \ - syslog(LOG_ERR, "conmon <error>: " fmt ": %m\n", ##__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -#define nexit(fmt, ...) \ - do { \ - fprintf(stderr, "[conmon:e]: " fmt "\n", ##__VA_ARGS__); \ - syslog(LOG_ERR, "conmon <error>: " fmt " \n", ##__VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -#define nwarn(fmt, ...) \ - do { \ - fprintf(stderr, "[conmon:w]: " fmt "\n", ##__VA_ARGS__); \ - syslog(LOG_INFO, "conmon <nwarn>: " fmt " \n", ##__VA_ARGS__); \ - } while (0) - -#define ninfo(fmt, ...) \ - do { \ - fprintf(stderr, "[conmon:i]: " fmt "\n", ##__VA_ARGS__); \ - syslog(LOG_INFO, "conmon <ninfo>: " fmt " \n", ##__VA_ARGS__); \ - } while (0) - #define _cleanup_(x) __attribute__((cleanup(x))) static inline void freep(void *p) @@ -142,6 +116,33 @@ static int log_fd = -1; +#define pexit(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:e]: " fmt " %m\n", ##__VA_ARGS__); \ + syslog(LOG_ERR, "conmon %.20s <error>: " fmt ": %m\n", opt_cid, ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define nexit(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:e]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_ERR, "conmon %.20s <error>: " fmt " \n", opt_cid, ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define nwarn(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:w]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_INFO, "conmon %.20s <nwarn>: " fmt " \n", opt_cid, ##__VA_ARGS__); \ + } while (0) + +#define ninfo(fmt, ...) \ + do { \ + fprintf(stderr, "[conmon:i]: " fmt "\n", ##__VA_ARGS__); \ + syslog(LOG_INFO, "conmon %.20s <ninfo>: " fmt " \n", opt_cid, ##__VA_ARGS__); \ + } while (0) + + static ssize_t write_all(int fd, const void *buf, size_t count) { size_t remaining = count; @@ -1107,8 +1108,10 @@ exit(1); } - if (opt_cid == NULL) - nexit("Container ID not provided. Use --cid"); + if (opt_cid == NULL) { + fprintf(stderr, "Container ID not provided. Use --cid"); + exit(EXIT_FAILURE); + } if (!opt_exec && opt_cuuid == NULL) nexit("Container UUID not provided. Use --cuuid"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/lib/stats.go new/cri-o-1.9.11/lib/stats.go --- old/cri-o-1.9.10/lib/stats.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/lib/stats.go 2018-04-09 20:22:42.000000000 +0200 @@ -15,8 +15,8 @@ type ContainerStats struct { Container string CPU float64 - cpuNano uint64 - systemNano uint64 + CPUNano uint64 + SystemNano int64 MemUsage uint64 MemLimit uint64 MemPerc float64 @@ -29,8 +29,8 @@ // GetContainerStats gets the running stats for a given container func (c *ContainerServer) GetContainerStats(ctr *oci.Container, previousStats *ContainerStats) (*ContainerStats, error) { - previousCPU := previousStats.cpuNano - previousSystem := previousStats.systemNano + previousCPU := previousStats.CPUNano + previousSystem := previousStats.SystemNano libcontainerStats, err := c.LibcontainerStats(ctr) if err != nil { return nil, err @@ -38,6 +38,8 @@ cgroupStats := libcontainerStats.CgroupStats stats := new(ContainerStats) stats.Container = ctr.ID() + stats.CPUNano = cgroupStats.CpuStats.CpuUsage.TotalUsage + stats.SystemNano = time.Now().UnixNano() stats.CPU = calculateCPUPercent(libcontainerStats, previousCPU, previousSystem) stats.MemUsage = cgroupStats.MemoryStats.Usage.Usage stats.MemLimit = getMemLimit(cgroupStats.MemoryStats.Usage.Limit) @@ -84,11 +86,11 @@ return } -func calculateCPUPercent(stats *libcontainer.Stats, previousCPU, previousSystem uint64) float64 { +func calculateCPUPercent(stats *libcontainer.Stats, previousCPU uint64, previousSystem int64) float64 { var ( cpuPercent = 0.0 cpuDelta = float64(stats.CgroupStats.CpuStats.CpuUsage.TotalUsage - previousCPU) - systemDelta = float64(uint64(time.Now().UnixNano()) - previousSystem) + systemDelta = float64(uint64(time.Now().UnixNano()) - uint64(previousSystem)) ) if systemDelta > 0.0 && cpuDelta > 0.0 { // gets a ratio of container cpu usage total, multiplies it by the number of cores (4 cores running diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/oci/oci.go new/cri-o-1.9.11/oci/oci.go --- old/cri-o-1.9.10/oci/oci.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/oci/oci.go 2018-04-09 20:22:42.000000000 +0200 @@ -14,6 +14,7 @@ "time" "github.com/containerd/cgroups" + "github.com/kubernetes-incubator/cri-o/pkg/findprocess" "github.com/kubernetes-incubator/cri-o/utils" rspec "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" @@ -573,12 +574,18 @@ case <-chControl: return default: - // Check if the process is still around - err := unix.Kill(c.state.Pid, 0) - if err == unix.ESRCH { + process, err := findprocess.FindProcess(c.state.Pid) + if err != nil { + if err != findprocess.ErrNotFound { + logrus.Warnf("failed to find process %d for container %q: %v", c.state.Pid, c.ID(), err) + } close(done) return } + err = process.Release() + if err != nil { + logrus.Warnf("failed to release process %d for container %q: %v", c.state.Pid, c.ID(), err) + } time.Sleep(100 * time.Millisecond) } } @@ -607,15 +614,25 @@ defer c.opLock.Unlock() // Check if the process is around before sending a signal - err := unix.Kill(c.state.Pid, 0) - if err == unix.ESRCH { + process, err := findprocess.FindProcess(c.state.Pid) + if err == findprocess.ErrNotFound { c.state.Finished = time.Now() return nil } + if err != nil { + logrus.Warnf("failed to find process %d for container %q: %v", c.state.Pid, c.ID(), err) + } else { + err = process.Release() + if err != nil { + logrus.Warnf("failed to release process %d for container %q: %v", c.state.Pid, c.ID(), err) + } + } if timeout > 0 { if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "kill", c.id, c.GetStopSignal()); err != nil { - return fmt.Errorf("failed to stop container %s, %v", c.id, err) + if err := checkProcessGone(c); err != nil { + return fmt.Errorf("failed to stop container %q: %v", c.id, err) + } } err = waitContainerStop(ctx, c, time.Duration(timeout)*time.Second) if err == nil { @@ -625,12 +642,29 @@ } if err := utils.ExecCmdWithStdStreams(os.Stdin, os.Stdout, os.Stderr, r.Path(c), "kill", "--all", c.id, "KILL"); err != nil { - return fmt.Errorf("failed to stop container %s, %v", c.id, err) + if err := checkProcessGone(c); err != nil { + return fmt.Errorf("failed to stop container %q: %v", c.id, err) + } } return waitContainerStop(ctx, c, killContainerTimeout) } +func checkProcessGone(c *Container) error { + process, perr := findprocess.FindProcess(c.state.Pid) + if perr == findprocess.ErrNotFound { + c.state.Finished = time.Now() + return nil + } + if perr == nil { + err := process.Release() + if err != nil { + logrus.Warnf("failed to release process %d for container %q: %v", c.state.Pid, c.ID(), err) + } + } + return fmt.Errorf("failed to find process: %v", perr) +} + // DeleteContainer deletes a container. func (r *Runtime) DeleteContainer(c *Container) error { c.opLock.Lock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/pkg/findprocess/findprocess.go new/cri-o-1.9.11/pkg/findprocess/findprocess.go --- old/cri-o-1.9.10/pkg/findprocess/findprocess.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cri-o-1.9.11/pkg/findprocess/findprocess.go 2018-04-09 20:22:42.000000000 +0200 @@ -0,0 +1,26 @@ +// Package findprocess provides an os.FindProcess wrapper that +// portably detects non-existent processes. +package findprocess + +import ( + "errors" + "os" +) + +// ErrNotFound represents a target process that does not exist or is +// otherwise not available to the calling process. +var ErrNotFound = errors.New("process not found") + +// FindProcess wraps os.Findprocess [1] to return a public ErrNotFound +// if the process does not exist. The returned process will be nil if +// and only if the returned err is non-nil. +// +// [1]: https://golang.org/pkg/os/#FindProcess +func FindProcess(pid int) (process *os.Process, err error) { + process, err = findProcess(pid) + if err != nil { + process.Release() + process = nil + } + return process, err +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/pkg/findprocess/findprocess_test.go new/cri-o-1.9.11/pkg/findprocess/findprocess_test.go --- old/cri-o-1.9.10/pkg/findprocess/findprocess_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cri-o-1.9.11/pkg/findprocess/findprocess_test.go 2018-04-09 20:22:42.000000000 +0200 @@ -0,0 +1,41 @@ +package findprocess + +import ( + "os/exec" + "testing" +) + +func TestFindEngine(t *testing.T) { + cmd := exec.Command("sleep", "1") + err := cmd.Start() + if err != nil { + t.Fatal(err) + } + + process, err := FindProcess(cmd.Process.Pid) + if err != nil { + t.Fatal(err) + } + err = process.Release() + if err != nil { + t.Fatal(err) + } + + err = cmd.Wait() + if err != nil { + t.Fatal(err) + } + + process, err = FindProcess(cmd.Process.Pid) + if err == ErrNotFound { + return + } + if err == nil { + err = process.Release() + if err != nil { + t.Fatal(err) + } + t.Fatalf("found the reaped process %d", cmd.Process.Pid) + } + t.Fatal(err) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/pkg/findprocess/findprocess_unix.go new/cri-o-1.9.11/pkg/findprocess/findprocess_unix.go --- old/cri-o-1.9.10/pkg/findprocess/findprocess_unix.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cri-o-1.9.11/pkg/findprocess/findprocess_unix.go 2018-04-09 20:22:42.000000000 +0200 @@ -0,0 +1,23 @@ +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package findprocess + +import ( + "os" + "syscall" +) + +func findProcess(pid int) (process *os.Process, err error) { + process, err = os.FindProcess(pid) + if err != nil { + return process, err + } + err = process.Signal(syscall.Signal(0)) + if err == nil { + return process, nil + } + if err.Error() == "os: process already finished" { + return process, ErrNotFound + } + return process, err +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/pkg/findprocess/findprocess_windows.go new/cri-o-1.9.11/pkg/findprocess/findprocess_windows.go --- old/cri-o-1.9.10/pkg/findprocess/findprocess_windows.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cri-o-1.9.11/pkg/findprocess/findprocess_windows.go 2018-04-09 20:22:42.000000000 +0200 @@ -0,0 +1,14 @@ +package findprocess + +import ( + "os" +) + +func findProcess(pid int) (process *os.Process, err error) { + process, err := os.FindProcess(pid) + if err != nil { + // FIXME: is there an analog to POSIX's ESRCH we can check for? + return process, err + } + return process, nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/container_exec.go new/cri-o-1.9.11/server/container_exec.go --- old/cri-o-1.9.10/server/container_exec.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/container_exec.go 2018-04-09 20:22:42.000000000 +0200 @@ -30,7 +30,7 @@ resp, err = s.GetExec(req) if err != nil { - return nil, fmt.Errorf("unable to prepare exec endpoint") + return nil, fmt.Errorf("unable to prepare exec endpoint: %v", err) } return resp, nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/container_list.go new/cri-o-1.9.11/server/container_list.go --- old/cri-o-1.9.10/server/container_list.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/container_list.go 2018-04-09 20:22:42.000000000 +0200 @@ -28,6 +28,42 @@ return true } +// filterContainerList applies a protobuf-defined filter to retrieve only intended containers. Not matching +// the filter is not considered an error but will return an empty response. +func (s *Server) filterContainerList(filter *pb.ContainerFilter, origCtrList []*oci.Container) []*oci.Container { + // Filter using container id and pod id first. + if filter.Id != "" { + id, err := s.CtrIDIndex().Get(filter.Id) + if err != nil { + // If we don't find a container ID with a filter, it should not + // be considered an error. Log a warning and return an empty struct + logrus.Warn("unable to find container ID %s", filter.Id) + return []*oci.Container{} + } + c := s.ContainerServer.GetContainer(id) + if c != nil { + switch { + case filter.PodSandboxId == "": + return []*oci.Container{c} + case c.Sandbox() == filter.PodSandboxId: + return []*oci.Container{c} + default: + return []*oci.Container{} + } + } + } else { + if filter.PodSandboxId != "" { + pod := s.ContainerServer.GetSandbox(filter.PodSandboxId) + if pod == nil { + return []*oci.Container{} + } + return pod.Containers().List() + } + } + logrus.Debug("no filters were applied, returning full container list") + return origCtrList +} + // ListContainers lists all containers by filters. func (s *Server) ListContainers(ctx context.Context, req *pb.ListContainersRequest) (resp *pb.ListContainersResponse, err error) { const operation = "list_containers" @@ -45,39 +81,7 @@ } if filter != nil { - - // Filter using container id and pod id first. - if filter.Id != "" { - id, err := s.CtrIDIndex().Get(filter.Id) - if err != nil { - // If we don't find a container ID with a filter, it should not - // be considered an error. Log a warning and return an empty struct - logrus.Warn("unable to find container ID %s", filter.Id) - return &pb.ListContainersResponse{}, nil - } - c := s.ContainerServer.GetContainer(id) - if c != nil { - if filter.PodSandboxId != "" { - if c.Sandbox() == filter.PodSandboxId { - ctrList = []*oci.Container{c} - } else { - ctrList = []*oci.Container{} - } - - } else { - ctrList = []*oci.Container{c} - } - } - } else { - if filter.PodSandboxId != "" { - pod := s.ContainerServer.GetSandbox(filter.PodSandboxId) - if pod == nil { - ctrList = []*oci.Container{} - } else { - ctrList = pod.Containers().List() - } - } - } + ctrList = s.filterContainerList(filter, ctrList) } for _, ctr := range ctrList { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/container_stats.go new/cri-o-1.9.11/server/container_stats.go --- old/cri-o-1.9.10/server/container_stats.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/container_stats.go 2018-04-09 20:22:42.000000000 +0200 @@ -4,10 +4,32 @@ "fmt" "time" + "github.com/kubernetes-incubator/cri-o/lib" + "github.com/kubernetes-incubator/cri-o/oci" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" ) +func buildContainerStats(stats *lib.ContainerStats, container *oci.Container) *pb.ContainerStats { + return &pb.ContainerStats{ + Attributes: &pb.ContainerAttributes{ + Id: container.ID(), + Metadata: container.Metadata(), + Labels: container.Labels(), + Annotations: container.Annotations(), + }, + Cpu: &pb.CpuUsage{ + Timestamp: stats.SystemNano, + UsageCoreNanoSeconds: &pb.UInt64Value{Value: stats.CPUNano}, + }, + Memory: &pb.MemoryUsage{ + Timestamp: stats.SystemNano, + WorkingSetBytes: &pb.UInt64Value{Value: stats.MemUsage}, + }, + WritableLayer: nil, + } +} + // ContainerStats returns stats of the container. If the container does not // exist, the call returns an error. func (s *Server) ContainerStats(ctx context.Context, req *pb.ContainerStatsRequest) (resp *pb.ContainerStatsResponse, err error) { @@ -16,5 +38,16 @@ recordOperation(operation, time.Now()) recordError(operation, err) }() - return nil, fmt.Errorf("not implemented") + + container := s.GetContainer(req.ContainerId) + if container == nil { + return nil, fmt.Errorf("invalid container") + } + + stats, err := s.GetContainerStats(container, &lib.ContainerStats{}) + if err != nil { + return nil, err + } + + return &pb.ContainerStatsResponse{Stats: buildContainerStats(stats, container)}, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/container_stats_list.go new/cri-o-1.9.11/server/container_stats_list.go --- old/cri-o-1.9.10/server/container_stats_list.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/container_stats_list.go 2018-04-09 20:22:42.000000000 +0200 @@ -1,9 +1,10 @@ package server import ( - "fmt" "time" + "github.com/kubernetes-incubator/cri-o/lib" + "github.com/sirupsen/logrus" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" ) @@ -15,5 +16,34 @@ recordOperation(operation, time.Now()) recordError(operation, err) }() - return nil, fmt.Errorf("not implemented") + + ctrList, err := s.ContainerServer.ListContainers() + if err != nil { + return nil, err + } + filter := req.GetFilter() + if filter != nil { + cFilter := &pb.ContainerFilter{ + Id: req.Filter.Id, + PodSandboxId: req.Filter.PodSandboxId, + LabelSelector: req.Filter.LabelSelector, + } + ctrList = s.filterContainerList(cFilter, ctrList) + } + + var allStats []*pb.ContainerStats + + for _, container := range ctrList { + stats, err := s.GetContainerStats(container, &lib.ContainerStats{}) + if err != nil { + logrus.Warn("unable to get stats for container %s", container.ID()) + continue + } + response := buildContainerStats(stats, container) + allStats = append(allStats, response) + } + + return &pb.ListContainerStatsResponse{ + Stats: allStats, + }, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/image_fs_info.go new/cri-o-1.9.11/server/image_fs_info.go --- old/cri-o-1.9.10/server/image_fs_info.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/image_fs_info.go 2018-04-09 20:22:42.000000000 +0200 @@ -1,13 +1,42 @@ package server import ( - "fmt" + "path" "time" + "github.com/containers/storage" + crioStorage "github.com/kubernetes-incubator/cri-o/utils" "golang.org/x/net/context" pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime" ) +func getStorageFsInfo(store storage.Store) (*pb.FilesystemUsage, error) { + rootPath := store.GraphRoot() + storageDriver := store.GraphDriverName() + imagesPath := path.Join(rootPath, storageDriver+"-images") + + deviceName, err := crioStorage.GetDeviceNameFromPath(imagesPath) + + uuid, err := crioStorage.GetDeviceUUIDFromPath(deviceName) + if err != nil { + return nil, err + } + + bytesUsed, inodesUsed, err := crioStorage.GetDiskUsageStats(imagesPath) + if err != nil { + return nil, err + } + + usage := pb.FilesystemUsage{ + Timestamp: time.Now().UnixNano(), + StorageId: &pb.StorageIdentifier{uuid}, + UsedBytes: &pb.UInt64Value{bytesUsed}, + InodesUsed: &pb.UInt64Value{inodesUsed}, + } + + return &usage, nil +} + // ImageFsInfo returns information of the filesystem that is used to store images. func (s *Server) ImageFsInfo(ctx context.Context, req *pb.ImageFsInfoRequest) (resp *pb.ImageFsInfoResponse, err error) { const operation = "image_fs_info" @@ -16,5 +45,14 @@ recordError(operation, err) }() - return nil, fmt.Errorf("not implemented") + store := s.StorageImageServer().GetStore() + fsUsage, err := getStorageFsInfo(store) + + if err != nil { + return nil, err + } + + return &pb.ImageFsInfoResponse{ + ImageFilesystems: []*pb.FilesystemUsage{fsUsage}, + }, nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/sandbox_stop.go new/cri-o-1.9.11/server/sandbox_stop.go --- old/cri-o-1.9.10/server/sandbox_stop.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/sandbox_stop.go 2018-04-09 20:22:42.000000000 +0200 @@ -116,13 +116,13 @@ } // StopAllPodSandboxes removes all pod sandboxes -func (s *Server) StopAllPodSandboxes() { +func (s *Server) StopAllPodSandboxes(ctx context.Context) { logrus.Debugf("StopAllPodSandboxes") for _, sb := range s.ContainerServer.ListSandboxes() { pod := &pb.StopPodSandboxRequest{ PodSandboxId: sb.ID(), } - if _, err := s.StopPodSandbox(nil, pod); err != nil { + if _, err := s.StopPodSandbox(ctx, pod); err != nil { logrus.Warnf("could not StopPodSandbox %s: %v", sb.ID(), err) } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/server/server.go new/cri-o-1.9.11/server/server.go --- old/cri-o-1.9.10/server/server.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/server/server.go 2018-04-09 20:22:42.000000000 +0200 @@ -1,6 +1,7 @@ package server import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -146,11 +147,11 @@ } // cleanupSandboxesOnShutdown Remove all running Sandboxes on system shutdown -func (s *Server) cleanupSandboxesOnShutdown() { +func (s *Server) cleanupSandboxesOnShutdown(ctx context.Context) { _, err := os.Stat(shutdownFile) if err == nil || !os.IsNotExist(err) { logrus.Debugf("shutting down all sandboxes, on shutdown") - s.StopAllPodSandboxes() + s.StopAllPodSandboxes(ctx) err = os.Remove(shutdownFile) if err != nil { logrus.Warnf("Failed to remove %q", shutdownFile) @@ -160,12 +161,12 @@ } // Shutdown attempts to shut down the server's storage cleanly -func (s *Server) Shutdown() error { +func (s *Server) Shutdown(ctx context.Context) error { // why do this on clean shutdown! we want containers left running when crio // is down for whatever reason no?! // notice this won't trigger just on system halt but also on normal // crio.service restart!!! - s.cleanupSandboxesOnShutdown() + s.cleanupSandboxesOnShutdown(ctx) return s.ContainerServer.Shutdown() } @@ -187,7 +188,7 @@ } // New creates a new Server with options provided -func New(config *Config) (*Server, error) { +func New(ctx context.Context, config *Config) (*Server, error) { if err := os.MkdirAll("/var/run/crio", 0755); err != nil { return nil, err } @@ -245,7 +246,7 @@ } s.restore() - s.cleanupSandboxesOnShutdown() + s.cleanupSandboxesOnShutdown(ctx) bindAddress := net.ParseIP(config.StreamAddress) if bindAddress == nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/test/ctr.bats new/cri-o-1.9.11/test/ctr.bats --- old/cri-o-1.9.10/test/ctr.bats 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/test/ctr.bats 2018-04-09 20:22:42.000000000 +0200 @@ -882,11 +882,19 @@ run crictl start "$ctr_id" echo "$output" [ "$status" -eq 0 ] - run crictl inspect "$ctr_id" - echo "$output" - [ "$status" -eq 0 ] - [[ "$output" =~ "State: CONTAINER_EXITED" ]] - [[ "$output" =~ "Exit Code: 0" ]] + # Wait for container to exit + attempt=0 + while [ $attempt -le 100 ]; do + attempt=$((attempt+1)) + run crictl inspect "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + if [[ "$output" =~ "State: CONTAINER_EXITED" ]]; then + [[ "$output" =~ "Exit Code: 0" ]] + break + fi + sleep 1 + done run crictl create "$pod_id" "$TESTDATA"/container_config_resolvconf_ro.json "$TESTDATA"/sandbox_config.json echo "$output" @@ -895,10 +903,18 @@ run crictl start "$ctr_id" echo "$output" [ "$status" -eq 0 ] - run crictl inspect "$ctr_id" - echo "$output" - [ "$status" -eq 0 ] - [[ "$output" =~ "State: CONTAINER_EXITED" ]] + # Wait for container to exit + attempt=0 + while [ $attempt -le 100 ]; do + attempt=$((attempt+1)) + run crictl inspect "$ctr_id" + echo "$output" + [ "$status" -eq 0 ] + if [[ "$output" =~ "State: CONTAINER_EXITED" ]]; then + break + fi + sleep 1 + done cleanup_ctrs cleanup_pods diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/utils/filesystem.go new/cri-o-1.9.11/utils/filesystem.go --- old/cri-o-1.9.10/utils/filesystem.go 1970-01-01 01:00:00.000000000 +0100 +++ new/cri-o-1.9.11/utils/filesystem.go 2018-04-09 20:22:42.000000000 +0200 @@ -0,0 +1,109 @@ +package utils + +import ( + "fmt" + "golang.org/x/sys/unix" + "io/ioutil" + "os" + "path/filepath" + "strings" + "syscall" + + "github.com/docker/docker/pkg/mount" +) + +// GetDiskUsageStats accepts a path to a directory or file +// and returns the number of bytes and inodes used by the path +func GetDiskUsageStats(path string) (uint64, uint64, error) { + var dirSize, inodeCount uint64 + + err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + fileStat, error := os.Lstat(path) + if error != nil { + if fileStat.Mode()&os.ModeSymlink != 0 { + // Is a symlink; no error should be returned + return nil + } + return error + } + + dirSize += uint64(info.Size()) + inodeCount++ + + return nil + }) + + if err != nil { + return 0, 0, err + } + + return dirSize, inodeCount, err +} + +// GetDeviceUUIDFromPath accepts a path, and will find the device +// corresponding to the path and return the UUID of that device +func GetDeviceUUIDFromPath(devicePath string) (string, error) { + const dir = "/dev/disk/by-uuid" + + if _, err := os.Stat(dir); os.IsNotExist(err) { + return "", nil + } + + files, err := ioutil.ReadDir(dir) + if err != nil { + return "", err + } + + for _, file := range files { + path := filepath.Join(dir, file.Name()) + target, err := os.Readlink(path) + if err != nil { + continue + } + device, err := filepath.Abs(filepath.Join(dir, target)) + if err != nil { + return "", fmt.Errorf("failed to resolve the absolute path of %q", filepath.Join(dir, target)) + } + if strings.Compare(device, devicePath) == 0 { + return file.Name(), nil + } + } + + return "", fmt.Errorf("device path %s not found", devicePath) +} + +// GetStattFromPath is a helper function that returns the Stat_t +// object for a given path +func GetStattFromPath(path string) (syscall.Stat_t, error) { + statInfo := syscall.Stat_t{} + err := syscall.Lstat(path, &statInfo) + if err != nil { + return statInfo, err + } + return statInfo, nil +} + +// GetDeviceNameFromPath iterates through the mounts and matches +// the one that the provided path is on +func GetDeviceNameFromPath(path string) (string, error) { + statInfo, err := GetStattFromPath(path) + if err != nil { + return "", err + } + + mounts, err := mount.GetMounts() + if err != nil { + return "", err + } + + queryMajor := int(unix.Major(uint64(statInfo.Dev))) + queryMinor := int(unix.Minor(uint64(statInfo.Dev))) + + for _, mount := range mounts { + if mount.Minor == queryMinor && mount.Major == queryMajor { + return mount.Source, nil + } + } + + return "", fmt.Errorf("no match found") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cri-o-1.9.10/version/version.go new/cri-o-1.9.11/version/version.go --- old/cri-o-1.9.10/version/version.go 2018-03-12 17:46:45.000000000 +0100 +++ new/cri-o-1.9.11/version/version.go 2018-04-09 20:22:42.000000000 +0200 @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "1.9.10" +const Version = "1.9.11"