summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES.md12
-rw-r--r--changelog.txt36
-rw-r--r--cmd/podman/exec.go2
-rw-r--r--cmd/podman/exists.go4
-rw-r--r--cmd/podman/libpodruntime/runtime.go16
-rw-r--r--cmd/podman/pause.go5
-rw-r--r--cmd/podman/unpause.go5
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--libpod/container.go20
-rw-r--r--libpod/container_inspect.go2
-rw-r--r--libpod/container_internal.go3
-rw-r--r--libpod/oci.go2
-rw-r--r--libpod/oci_linux.go3
-rw-r--r--libpod/options.go9
-rw-r--r--libpod/runtime.go8
-rw-r--r--libpod/runtime_ctr.go8
-rw-r--r--libpod/runtime_pod_linux.go22
-rw-r--r--libpod/stats.go7
-rw-r--r--pkg/adapter/runtime.go14
-rw-r--r--pkg/adapter/runtime_remote.go6
-rw-r--r--pkg/cgroups/cgroups.go2
-rw-r--r--pkg/cgroups/cpu.go2
-rw-r--r--version/version.go2
25 files changed, 170 insertions, 26 deletions
diff --git a/Makefile b/Makefile
index 6780b0967..1f98fe8e3 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ export GO111MODULE=off
GO ?= go
DESTDIR ?=
-EPOCH_TEST_COMMIT ?= 5b7086abda91f4301af3bfb642d416a22349c276
+EPOCH_TEST_COMMIT ?= 55e028a12ee003e057c65e376fe4b723d28ae52e
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
diff --git a/README.md b/README.md
index ad9c3270b..e22c35d4f 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Libpod provides a library for applications looking to use the Container Pod concept,
popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes.
-* [Latest Version: 1.4.0](https://github.com/containers/libpod/releases/latest)
+* [Latest Version: 1.4.4](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
## Overview and scope
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e825e9a5c..69244bb09 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,17 @@
# Release Notes
+## 1.4.4
+### Bugfixes
+- Fixed a bug where rootless Podman would attempt to use the entire root configuration if no rootless configuration was present for the user, breaking rootless Podman for new installations
+- Fixed a bug where rootless Podman's pause process would block SIGTERM, preventing graceful system shutdown and hanging until the system's init send SIGKILL
+- Fixed a bug where running Podman as root with `sudo -E` would not work after running rootless Podman at least once
+- Fixed a bug where options for `tmpfs` volumes added with the `--tmpfs` flag were being ignored
+- Fixed a bug where images with no layers could not properly be displayed and removed by Podman
+- Fixed a bug where locks were not properly freed on failure to create a container or pod
+
+### Misc
+- Updated containers/storage to v1.12.13
+
## 1.4.3
### Features
- Podman now has greatly improved support for containers using multiple OCI runtimes. Containers now remember if they were created with a different runtime using `--runtime` and will always use that runtime
diff --git a/changelog.txt b/changelog.txt
index 3bc7720a8..51ac92979 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,39 @@
+- Changelog for v1.4.4 (2019-07-02)
+ * Fix release notes
+ * Ensure locks are freed when ctr/pod creation fails
+ * Update release notes for 1.4.4
+ * stats: use runtime.NumCPU when percpu counters are not available
+ * cgroups: fix times conversion
+ * Update to containers/storage v1.12.13
+ * rootless: do not join namespace if it has already euid == 0
+ * Exclude SIGTERM from blocked signals for pause process.
+ * Remove umount command from remote client.
+ * rootless: enable linger if /run/user/UID not exists
+ * Makefile: set GO111MODULE=off
+ * libpod removal from main (phase 2)
+ * runtime: do not attempt to use global conf file
+ * runtime: use GetRootlessUID() to get rootless uid
+ * Remove refs to crio/conmon
+ * Handle images which contain no layers
+ * Add tests that we don't hit errors with layerless images
+ * stats: fix cgroup path for rootless containers
+ * pkg, cgroups: add initial support for cgroup v2
+ * util: drop IsCgroup2UnifiedMode and use it from cgroups
+ * vendor: drop github.com/containerd/cgroups
+ * libpod: use pkg/cgroups instead of containerd/cgroups
+ * pkg: new package cgroups
+ * Remove unnecessary blackfriday dependency
+ * libpod: fix hang on container start and attach
+ * podman: clarify the format of --detach-keys argument
+ * libpod: specify a detach keys sequence in libpod.conf
+ * Fix parsing of the --tmpfs option
+ * Fix crash for when remote host IP or Username is not set in conf file & conf file exists.
+ * Bump gitvalidation epoch
+ * Bump to v1.4.4-dev
+ * Cirrus: More tests to verify cache_images
+ * Update release notes for 1.4.3 release
+ * remove libpod from main
+
- Changelog for v1.4.3 (2019-06-25)
* Update 'generate kube' tests to verify YAML
* Use a different method to retrieve YAML output in tests
diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go
index accb15936..bf8de69fc 100644
--- a/cmd/podman/exec.go
+++ b/cmd/podman/exec.go
@@ -60,7 +60,7 @@ func execCmd(c *cliconfig.ExecValues) error {
argStart = 0
}
cmd := args[argStart:]
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index 3d001f3d1..1e052e25f 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -107,7 +107,7 @@ func containerExistsCmd(c *cliconfig.ContainerExistsValues) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one container at a time")
}
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -126,7 +126,7 @@ func podExistsCmd(c *cliconfig.PodExistsValues) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one pod at a time")
}
- runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go
index 2d511f7f8..570288837 100644
--- a/cmd/podman/libpodruntime/runtime.go
+++ b/cmd/podman/libpodruntime/runtime.go
@@ -15,20 +15,25 @@ import (
// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers
func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, true)
+ return getRuntime(ctx, c, false, true, false)
}
// GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber
func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, true, false)
+ return getRuntime(ctx, c, true, false, false)
}
// GetRuntime generates a new libpod runtime configured by command line options
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
- return getRuntime(ctx, c, false, false)
+ return getRuntime(ctx, c, false, false, false)
}
-func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool, migrate bool) (*libpod.Runtime, error) {
+// GetRuntimeNoStore generates a new libpod runtime configured by command line options
+func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) {
+ return getRuntime(ctx, c, false, false, true)
+}
+
+func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber, migrate, noStore bool) (*libpod.Runtime, error) {
options := []libpod.RuntimeOption{}
storageOpts := storage.StoreOptions{}
storageSet := false
@@ -89,6 +94,9 @@ func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool,
options = append(options, libpod.WithStorageConfig(storageOpts))
}
+ if !storageSet && noStore {
+ options = append(options, libpod.WithNoStore())
+ }
// TODO CLI flags for image config?
// TODO CLI flag for signature policy?
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index 4bef20867..ee5fd352d 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -1,11 +1,10 @@
package main
import (
- "os"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -39,7 +38,7 @@ func init() {
}
func pauseCmd(c *cliconfig.PauseValues) error {
- if os.Geteuid() != 0 {
+ if rootless.IsRootless() && !remoteclient {
return errors.New("pause is not supported for rootless containers")
}
diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go
index 55bfe584e..8126ebfbd 100644
--- a/cmd/podman/unpause.go
+++ b/cmd/podman/unpause.go
@@ -1,11 +1,10 @@
package main
import (
- "os"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -38,7 +37,7 @@ func init() {
}
func unpauseCmd(c *cliconfig.UnpauseValues) error {
- if os.Geteuid() != 0 {
+ if rootless.IsRootless() && !remoteclient {
return errors.New("unpause is not supported for rootless containers")
}
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 8e13f86de..ce5901f69 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -39,7 +39,7 @@
%global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7})
Name: podman
-Version: 1.4.4
+Version: 1.4.5
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/libpod/container.go b/libpod/container.go
index 713386477..bfbc47d76 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -168,6 +168,8 @@ type ContainerState struct {
OOMKilled bool `json:"oomKilled,omitempty"`
// PID is the PID of a running container
PID int `json:"pid,omitempty"`
+ // ConmonPID is the PID of the container's conmon
+ ConmonPID int `json:"conmonPid,omitempty"`
// ExecSessions contains active exec sessions for container
// Exec session ID is mapped to PID of exec process
ExecSessions map[string]*ExecSession `json:"execSessions,omitempty"`
@@ -849,7 +851,7 @@ func (c *Container) OOMKilled() (bool, error) {
return c.state.OOMKilled, nil
}
-// PID returns the PID of the container
+// PID returns the PID of the container.
// If the container is not running, a pid of 0 will be returned. No error will
// occur.
func (c *Container) PID() (int, error) {
@@ -865,6 +867,22 @@ func (c *Container) PID() (int, error) {
return c.state.PID, nil
}
+// ConmonPID Returns the PID of the container's conmon process.
+// If the container is not running, a PID of 0 will be returned. No error will
+// occur.
+func (c *Container) ConmonPID() (int, error) {
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return -1, err
+ }
+ }
+
+ return c.state.ConmonPID, nil
+}
+
// ExecSessions retrieves active exec sessions running in the container
func (c *Container) ExecSessions() ([]string, error) {
if !c.batched {
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 6085f1210..938a5b210 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -145,6 +145,7 @@ type InspectContainerState struct {
OOMKilled bool `json:"OOMKilled"`
Dead bool `json:"Dead"`
Pid int `json:"Pid"`
+ ConmonPid int `json:"ConmonPid,omitempty"`
ExitCode int32 `json:"ExitCode"`
Error string `json:"Error"` // TODO
StartedAt time.Time `json:"StartedAt"`
@@ -261,6 +262,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
OOMKilled: runtimeInfo.OOMKilled,
Dead: runtimeInfo.State.String() == "bad state",
Pid: runtimeInfo.PID,
+ ConmonPid: runtimeInfo.ConmonPID,
ExitCode: runtimeInfo.ExitCode,
Error: "", // can't get yet
StartedAt: runtimeInfo.StartedTime,
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 43d2b6e61..cb6c35049 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -452,6 +452,7 @@ func (c *Container) teardownStorage() error {
// It does not save the results - assumes the database will do that for us
func resetState(state *ContainerState) error {
state.PID = 0
+ state.ConmonPID = 0
state.Mountpoint = ""
state.Mounted = false
if state.State != define.ContainerStateExited {
@@ -1043,6 +1044,8 @@ func (c *Container) stop(timeout uint) error {
return err
}
+ c.state.PID = 0
+ c.state.ConmonPID = 0
c.state.StoppedByUser = true
if err := c.save(); err != nil {
return errors.Wrapf(err, "error saving container %s state after stopping", c.ID())
diff --git a/libpod/oci.go b/libpod/oci.go
index efb5e42cc..fdd783100 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -234,6 +234,8 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRuntime bool) erro
// Alright, it exists. Transition to Stopped state.
ctr.state.State = define.ContainerStateStopped
+ ctr.state.PID = 0
+ ctr.state.ConmonPID = 0
// Read the exit file to get our stopped time and exit code.
return ctr.handleExitFile(exitFile, info)
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 7d9f47ae2..24502ef4f 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -446,6 +446,9 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
return errors.Wrapf(define.ErrInternal, "container create failed")
}
ctr.state.PID = ss.si.Pid
+ if cmd.Process != nil {
+ ctr.state.ConmonPID = cmd.Process.Pid
+ }
case <-time.After(ContainerCreateTimeout):
return errors.Wrapf(define.ErrInternal, "container creation timeout")
}
diff --git a/libpod/options.go b/libpod/options.go
index 0f23a6c97..78634e953 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -300,6 +300,15 @@ func WithTmpDir(dir string) RuntimeOption {
}
}
+// WithNoStore sets a bool on the runtime that we do not need
+// any containers storage.
+func WithNoStore() RuntimeOption {
+ return func(rt *Runtime) error {
+ rt.noStore = true
+ return nil
+ }
+}
+
// WithMaxLogSize sets the maximum size of container logs.
// Positive sizes are limits in bytes, -1 is unlimited.
func WithMaxLogSize(limit int64) RuntimeOption {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index ca10f9243..6c61e15d3 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -125,6 +125,9 @@ type Runtime struct {
// mechanism to read and write even logs
eventer events.Eventer
+
+ // noStore indicates whether we need to interact with a store or not
+ noStore bool
}
// RuntimeConfig contains configuration options used to set up the runtime
@@ -844,11 +847,14 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
var store storage.Store
if os.Geteuid() != 0 {
logrus.Debug("Not configuring container store")
+ } else if runtime.noStore {
+ logrus.Debug("No store required. Not opening container store.")
} else {
store, err = storage.GetStore(runtime.config.StorageConfig)
if err != nil {
return err
}
+ err = nil
defer func() {
if err != nil && store != nil {
@@ -1181,6 +1187,8 @@ func (r *Runtime) Shutdown(force bool) error {
}
var lastError error
+ // If no store was requested, it can bew nil and there is no need to
+ // attempt to shut it down
if r.store != nil {
if _, err := r.store.Shutdown(force); err != nil {
lastError = errors.Wrapf(err, "Error shutting down container storage")
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 0d0f700a6..9daac161c 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -132,6 +132,14 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container, restore bo
ctr.config.LockID = ctr.lock.ID()
logrus.Debugf("Allocated lock %d for container %s", ctr.lock.ID(), ctr.ID())
+ defer func() {
+ if err != nil {
+ if err2 := ctr.lock.Free(); err2 != nil {
+ logrus.Errorf("Error freeing lock for container after creation failed: %v", err2)
+ }
+ }
+ }()
+
ctr.valid = true
ctr.state.State = config2.ContainerStateConfigured
ctr.runtime = r
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index e9ce130da..d667d3a25 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -19,7 +19,7 @@ import (
)
// NewPod makes a new, empty pod
-func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod, error) {
+func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (_ *Pod, Err error) {
r.lock.Lock()
defer r.lock.Unlock()
@@ -60,6 +60,14 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod,
pod.lock = lock
pod.config.LockID = pod.lock.ID()
+ defer func() {
+ if Err != nil {
+ if err := pod.lock.Free(); err != nil {
+ logrus.Errorf("Error freeing pod lock after failed creation: %v", err)
+ }
+ }
+ }()
+
pod.valid = true
// Check CGroup parent sanity, and set it if it was not set
@@ -113,15 +121,17 @@ func (r *Runtime) NewPod(ctx context.Context, options ...PodCreateOption) (*Pod,
if err := r.state.AddPod(pod); err != nil {
return nil, errors.Wrapf(err, "error adding pod to state")
}
+ defer func() {
+ if Err != nil {
+ if err := r.removePod(ctx, pod, true, true); err != nil {
+ logrus.Errorf("Error removing pod after pause container creation failure: %v", err)
+ }
+ }
+ }()
if pod.HasInfraContainer() {
ctr, err := r.createInfraContainer(ctx, pod)
if err != nil {
- // Tear down pod, as it is assumed a the pod will contain
- // a pause container, and it does not.
- if err2 := r.removePod(ctx, pod, true, true); err2 != nil {
- logrus.Errorf("Error removing pod after pause container creation failure: %v", err2)
- }
return nil, errors.Wrapf(err, "error adding Infra Container")
}
pod.state.InfraContainerID = ctr.ID()
diff --git a/libpod/stats.go b/libpod/stats.go
index da383e9d9..eb5ed95c4 100644
--- a/libpod/stats.go
+++ b/libpod/stats.go
@@ -3,6 +3,7 @@
package libpod
import (
+ "runtime"
"strings"
"syscall"
"time"
@@ -105,7 +106,11 @@ func calculateCPUPercent(stats *cgroups.Metrics, previousCPU, previousSystem uin
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
// at 100% utilization should be 400% utilization), and multiplies that by 100 to get a percentage
- cpuPercent = (cpuDelta / systemDelta) * float64(len(stats.CPU.Usage.PerCPU)) * 100
+ nCPUS := len(stats.CPU.Usage.PerCPU)
+ if nCPUS == 0 {
+ nCPUS = runtime.NumCPU()
+ }
+ cpuPercent = (cpuDelta / systemDelta) * float64(nCPUS) * 100
}
return cpuPercent
}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index dd77b3a3e..8ef88f36b 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -58,12 +58,26 @@ type Volume struct {
// VolumeFilter is for filtering volumes on the client
type VolumeFilter func(*Volume) bool
+// GetRuntimeNoStore returns a localruntime struct wit an embedded runtime but
+// without a configured storage.
+func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
+ runtime, err := libpodruntime.GetRuntimeNoStore(ctx, c)
+ if err != nil {
+ return nil, err
+ }
+ return getRuntime(runtime)
+}
+
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
runtime, err := libpodruntime.GetRuntime(ctx, c)
if err != nil {
return nil, err
}
+ return getRuntime(runtime)
+}
+
+func getRuntime(runtime *libpod.Runtime) (*LocalRuntime, error) {
return &LocalRuntime{
Runtime: runtime,
}, nil
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 3be89233d..800ed7569 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -50,6 +50,12 @@ type LocalRuntime struct {
*RemoteRuntime
}
+// GetRuntimeNoStore returns a LocalRuntime struct with the actual runtime embedded in it
+// The nostore is ignored
+func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
+ return GetRuntime(ctx, c)
+}
+
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
var (
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
index 426bda559..d6c19212b 100644
--- a/pkg/cgroups/cgroups.go
+++ b/pkg/cgroups/cgroups.go
@@ -30,7 +30,7 @@ type CgroupControl struct {
additionalControllers []controller
}
-// CPUUsage keeps stats for the CPU usage
+// CPUUsage keeps stats for the CPU usage (unit: nanoseconds)
type CPUUsage struct {
Kernel uint64
Total uint64
diff --git a/pkg/cgroups/cpu.go b/pkg/cgroups/cpu.go
index 3f969fd3c..8640d490e 100644
--- a/pkg/cgroups/cpu.go
+++ b/pkg/cgroups/cpu.go
@@ -85,12 +85,14 @@ func (c *cpuHandler) Stat(ctr *CgroupControl, m *Metrics) error {
if err != nil {
return err
}
+ usage.Kernel *= 1000
}
if val, found := values["system_usec"]; found {
usage.Total, err = strconv.ParseUint(cleanString(val[0]), 10, 0)
if err != nil {
return err
}
+ usage.Total *= 1000
}
// FIXME: How to read usage.PerCPU?
} else {
diff --git a/version/version.go b/version/version.go
index f19d56c31..286f66093 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,7 +4,7 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "1.4.4-dev"
+const Version = "1.4.5-dev"
// RemoteAPIVersion is the version for the remote
// client API. It is used to determine compatibility