aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers.go45
-rw-r--r--pkg/api/handlers/libpod/containers_stats.go12
-rw-r--r--pkg/api/server/register_containers.go4
-rw-r--r--pkg/domain/entities/pods.go37
-rw-r--r--pkg/domain/infra/abi/containers.go15
-rw-r--r--pkg/domain/infra/tunnel/containers.go17
-rw-r--r--pkg/machine/qemu/machine.go2
-rw-r--r--pkg/specgen/generate/container_create.go1
-rw-r--r--pkg/specgen/generate/pod_create.go8
-rw-r--r--pkg/specgen/podspecgen.go12
-rw-r--r--pkg/specgen/specgen.go4
-rw-r--r--pkg/util/utils.go6
-rw-r--r--pkg/util/utils_test.go15
13 files changed, 96 insertions, 82 deletions
diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go
index 2a0a0b725..95c09ff0e 100644
--- a/pkg/api/handlers/compat/containers.go
+++ b/pkg/api/handlers/compat/containers.go
@@ -403,22 +403,24 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
state.Status = define.ContainerStateCreated.String()
}
- state.Health = &types.Health{
- Status: inspect.State.Healthcheck.Status,
- FailingStreak: inspect.State.Healthcheck.FailingStreak,
- }
-
- log := inspect.State.Healthcheck.Log
+ if l.HasHealthCheck() && state.Status != "created" {
+ state.Health = &types.Health{
+ Status: inspect.State.Healthcheck.Status,
+ FailingStreak: inspect.State.Healthcheck.FailingStreak,
+ }
- for _, item := range log {
- res := &types.HealthcheckResult{}
- s, _ := time.Parse(time.RFC3339Nano, item.Start)
- e, _ := time.Parse(time.RFC3339Nano, item.End)
- res.Start = s
- res.End = e
- res.ExitCode = item.ExitCode
- res.Output = item.Output
- state.Health.Log = append(state.Health.Log, res)
+ log := inspect.State.Healthcheck.Log
+
+ for _, item := range log {
+ res := &types.HealthcheckResult{}
+ s, _ := time.Parse(time.RFC3339Nano, item.Start)
+ e, _ := time.Parse(time.RFC3339Nano, item.End)
+ res.Start = s
+ res.End = e
+ res.ExitCode = item.ExitCode
+ res.Output = item.Output
+ state.Health.Log = append(state.Health.Log, res)
+ }
}
formatCapabilities(inspect.HostConfig.CapDrop)
@@ -495,6 +497,17 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
exposedPorts[exposedPort] = struct{}{}
}
+ var healthcheck *container.HealthConfig
+ if inspect.Config.Healthcheck != nil {
+ healthcheck = &container.HealthConfig{
+ Test: inspect.Config.Healthcheck.Test,
+ Interval: inspect.Config.Healthcheck.Interval,
+ Timeout: inspect.Config.Healthcheck.Timeout,
+ StartPeriod: inspect.Config.Healthcheck.StartPeriod,
+ Retries: inspect.Config.Healthcheck.Retries,
+ }
+ }
+
config := container.Config{
Hostname: l.Hostname(),
Domainname: inspect.Config.DomainName,
@@ -508,7 +521,7 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
StdinOnce: inspect.Config.StdinOnce,
Env: inspect.Config.Env,
Cmd: l.Command(),
- Healthcheck: nil,
+ Healthcheck: healthcheck,
ArgsEscaped: false,
Image: imageName,
Volumes: nil,
diff --git a/pkg/api/handlers/libpod/containers_stats.go b/pkg/api/handlers/libpod/containers_stats.go
index 75c404d4f..22faab71f 100644
--- a/pkg/api/handlers/libpod/containers_stats.go
+++ b/pkg/api/handlers/libpod/containers_stats.go
@@ -7,8 +7,10 @@ import (
"github.com/containers/podman/v3/libpod"
"github.com/containers/podman/v3/pkg/api/handlers/utils"
+ "github.com/containers/podman/v3/pkg/cgroups"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/infra/abi"
+ "github.com/containers/podman/v3/pkg/rootless"
"github.com/gorilla/schema"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -20,6 +22,16 @@ func StatsContainer(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
+ // Check if service is running rootless (cheap check)
+ if rootless.IsRootless() {
+ // if so, then verify cgroup v2 available (more expensive check)
+ if isV2, _ := cgroups.IsCgroup2UnifiedMode(); !isV2 {
+ msg := "Container stats resource only available for cgroup v2"
+ utils.Error(w, msg, http.StatusConflict, errors.New(msg))
+ return
+ }
+ }
+
query := struct {
Containers []string `schema:"containers"`
Stream bool `schema:"stream"`
diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go
index 50e059ecc..89de84cce 100644
--- a/pkg/api/server/register_containers.go
+++ b/pkg/api/server/register_containers.go
@@ -1085,6 +1085,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// description: no error
// 404:
// $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/{name}/stats"), s.APIHandler(compat.StatsContainer)).Methods(http.MethodGet)
@@ -1113,6 +1115,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
// description: no error
// 404:
// $ref: "#/responses/NoSuchContainer"
+ // 409:
+ // $ref: "#/responses/ConflictError"
// 500:
// $ref: "#/responses/InternalError"
r.HandleFunc(VersionedPath("/libpod/containers/stats"), s.APIHandler(libpod.StatsContainer)).Methods(http.MethodGet)
diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go
index 68e335f8d..abd6ba6c6 100644
--- a/pkg/domain/entities/pods.go
+++ b/pkg/domain/entities/pods.go
@@ -7,8 +7,6 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/specgen"
- "github.com/containers/podman/v3/pkg/util"
- "github.com/opencontainers/runtime-spec/specs-go"
)
type PodKillOptions struct {
@@ -120,34 +118,12 @@ type PodCreateOptions struct {
Net *NetOptions
Share []string
Pid string
- Cpus float64
- CpusetCpus string
}
type PodCreateReport struct {
Id string //nolint
}
-func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU {
- cpu := &specs.LinuxCPU{}
- hasLimits := false
-
- if p.Cpus != 0 {
- period, quota := util.CoresToPeriodAndQuota(p.Cpus)
- cpu.Period = &period
- cpu.Quota = &quota
- hasLimits = true
- }
- if p.CpusetCpus != "" {
- cpu.Cpus = p.CpusetCpus
- hasLimits = true
- }
- if !hasLimits {
- return cpu
- }
- return cpu
-}
-
func setNamespaces(p *PodCreateOptions) ([4]specgen.Namespace, error) {
allNS := [4]specgen.Namespace{}
if p.Pid != "" {
@@ -204,19 +180,6 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error {
// Cgroup
s.CgroupParent = p.CGroupParent
- // Resource config
- cpuDat := p.CPULimits()
- if s.ResourceLimits == nil {
- s.ResourceLimits = &specs.LinuxResources{}
- s.ResourceLimits.CPU = &specs.LinuxCPU{}
- }
- if cpuDat != nil {
- s.ResourceLimits.CPU = cpuDat
- if p.Cpus != 0 {
- s.CPUPeriod = *cpuDat.Period
- s.CPUQuota = *cpuDat.Quota
- }
- }
return nil
}
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 2003879b8..33cd69b8a 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -119,6 +119,10 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := c.Pause()
+ if err != nil && options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Debugf("Container %s is not running", c.ID())
+ continue
+ }
report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
}
return report, nil
@@ -132,6 +136,10 @@ func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []st
report := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := c.Unpause()
+ if err != nil && options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Debugf("Container %s is not paused", c.ID())
+ continue
+ }
report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
}
return report, nil
@@ -220,9 +228,14 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
}
reports := make([]*entities.KillReport, 0, len(ctrs))
for _, con := range ctrs {
+ err := con.Kill(uint(sig))
+ if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Debugf("Container %s is not running", con.ID())
+ continue
+ }
reports = append(reports, &entities.KillReport{
Id: con.ID(),
- Err: con.Kill(uint(sig)),
+ Err: err,
RawInput: ctrMap[con.ID()],
})
}
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index 58f9c5fb0..1b01fa2ec 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -63,19 +63,27 @@ func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []stri
reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := containers.Pause(ic.ClientCtx, c.ID, nil)
+ if err != nil && options.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
+ logrus.Debugf("Container %s is not running", c.ID)
+ continue
+ }
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
}
func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ reports := []*entities.PauseUnpauseReport{}
ctrs, err := getContainersByContext(ic.ClientCtx, options.All, false, namesOrIds)
if err != nil {
return nil, err
}
- reports := make([]*entities.PauseUnpauseReport, 0, len(ctrs))
for _, c := range ctrs {
err := containers.Unpause(ic.ClientCtx, c.ID, nil)
+ if err != nil && options.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
+ logrus.Debugf("Container %s is not paused", c.ID)
+ continue
+ }
reports = append(reports, &entities.PauseUnpauseReport{Id: c.ID, Err: err})
}
return reports, nil
@@ -136,9 +144,14 @@ func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []strin
options := new(containers.KillOptions).WithSignal(opts.Signal)
reports := make([]*entities.KillReport, 0, len(ctrs))
for _, c := range ctrs {
+ err := containers.Kill(ic.ClientCtx, c.ID, options)
+ if err != nil && opts.All && errors.Cause(err).Error() == define.ErrCtrStateInvalid.Error() {
+ logrus.Debugf("Container %s is not running", c.ID)
+ continue
+ }
reports = append(reports, &entities.KillReport{
Id: c.ID,
- Err: containers.Kill(ic.ClientCtx, c.ID, options),
+ Err: err,
RawInput: ctrMap[c.ID],
})
}
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 42ae23c43..9cb04ff0a 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -482,6 +482,8 @@ func (v *MachineVM) SSH(name string, opts machine.SSHOptions) error {
}
cmd := exec.Command("ssh", args...)
+ logrus.Debugf("Executing: ssh %v\n", args)
+
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Stdin = os.Stdin
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 4e3a86ae4..2961ed849 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -354,6 +354,7 @@ func createContainerOptions(ctx context.Context, rt *libpod.Runtime, s *specgen.
options = append(options, libpod.WithLogDriver(s.LogConfiguration.Driver))
}
}
+
// Security options
if len(s.SelinuxOpts) > 0 {
options = append(options, libpod.WithSecLabels(s.SelinuxOpts))
diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go
index aab29499e..ec3ea077e 100644
--- a/pkg/specgen/generate/pod_create.go
+++ b/pkg/specgen/generate/pod_create.go
@@ -54,14 +54,6 @@ func createPodOptions(p *specgen.PodSpecGenerator, rt *libpod.Runtime) ([]libpod
if len(p.Name) > 0 {
options = append(options, libpod.WithPodName(p.Name))
}
- if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Period != nil && p.ResourceLimits.CPU.Quota != nil {
- if *p.ResourceLimits.CPU.Period != 0 || *p.ResourceLimits.CPU.Quota != 0 {
- options = append(options, libpod.WithPodCPUPAQ((*p.ResourceLimits.CPU.Period), (*p.ResourceLimits.CPU.Quota)))
- }
- }
- if p.ResourceLimits != nil && p.ResourceLimits.CPU != nil && p.ResourceLimits.CPU.Cpus != "" {
- options = append(options, libpod.WithPodCPUSetCPUs(p.ResourceLimits.CPU.Cpus))
- }
if len(p.Hostname) > 0 {
options = append(options, libpod.WithPodHostname(p.Hostname))
}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 02237afe9..b2d284f40 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -2,8 +2,6 @@ package specgen
import (
"net"
-
- spec "github.com/opencontainers/runtime-spec/specs-go"
)
// PodBasicConfig contains basic configuration options for pods.
@@ -167,16 +165,6 @@ type PodSpecGenerator struct {
PodBasicConfig
PodNetworkConfig
PodCgroupConfig
- PodResourceConfig
-}
-
-type PodResourceConfig struct {
- // ResourceLimits contains linux specific CPU data for the pod
- ResourceLimits *spec.LinuxResources `json:"resource_limits,omitempty"`
- // CPU period of the cpuset, determined by --cpus
- CPUPeriod uint64 `json:"cpu_period,omitempty"`
- // CPU quota of the cpuset, determined by --cpus
- CPUQuota int64 `json:"cpu_quota,omitempty"`
}
// NewPodSpecGenerator creates a new pod spec
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 7eec48a55..1e0a952de 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -473,10 +473,6 @@ type ContainerResourceConfig struct {
// that are used to configure cgroup v2.
// Optional.
CgroupConf map[string]string `json:"unified,omitempty"`
- // CPU period of the cpuset, determined by --cpus
- CPUPeriod uint64 `json:"cpu_period,omitempty"`
- // CPU quota of the cpuset, determined by --cpus
- CPUQuota int64 `json:"cpu_quota,omitempty"`
}
// ContainerHealthCheckConfig describes a container healthcheck with attributes
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 60aa64ac1..774590f44 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -3,6 +3,7 @@ package util
import (
"encoding/json"
"fmt"
+ "math"
"os"
"os/user"
"path/filepath"
@@ -530,9 +531,10 @@ func ParseInputTime(inputTime string) (time.Time, error) {
}
}
- unixTimestamp, err := strconv.ParseInt(inputTime, 10, 64)
+ unixTimestamp, err := strconv.ParseFloat(inputTime, 64)
if err == nil {
- return time.Unix(unixTimestamp, 0), nil
+ iPart, fPart := math.Modf(unixTimestamp)
+ return time.Unix(int64(iPart), int64(fPart*1_000_000_000)).UTC(), nil
}
// input might be a duration
diff --git a/pkg/util/utils_test.go b/pkg/util/utils_test.go
index cb737bd76..027acbdab 100644
--- a/pkg/util/utils_test.go
+++ b/pkg/util/utils_test.go
@@ -2,6 +2,7 @@ package util
import (
"testing"
+ "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -277,3 +278,17 @@ func TestPeriodAndQuotaToCores(t *testing.T) {
assert.Equal(t, PeriodAndQuotaToCores(period, quota), expectedCores)
}
+
+func TestParseInputTime(t *testing.T) {
+ tm, err := ParseInputTime("1.5")
+ if err != nil {
+ t.Errorf("expected error to be nil but was: %v", err)
+ }
+
+ expected, err := time.ParseInLocation(time.RFC3339Nano, "1970-01-01T00:00:01.500000000Z", time.UTC)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assert.Equal(t, expected, tm)
+}