summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state_linux.go2
-rw-r--r--libpod/container_api.go2
-rw-r--r--libpod/container_config.go2
-rw-r--r--libpod/container_inspect.go7
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_internal_linux.go9
-rw-r--r--libpod/container_log.go2
-rw-r--r--libpod/container_top_unsupported.go2
-rw-r--r--libpod/container_validate.go2
-rw-r--r--libpod/define/container_inspect.go13
-rw-r--r--libpod/define/info.go11
-rw-r--r--libpod/events/events.go3
-rw-r--r--libpod/events/journal_linux.go23
-rw-r--r--libpod/events/logfile.go12
-rw-r--r--libpod/filters/containers.go208
-rw-r--r--libpod/filters/pods.go139
-rw-r--r--libpod/image/df.go2
-rw-r--r--libpod/image/image.go2
-rw-r--r--libpod/image/parts.go2
-rw-r--r--libpod/image/prune.go23
-rw-r--r--libpod/image/search.go2
-rw-r--r--libpod/image/utils.go58
-rw-r--r--libpod/info.go17
-rw-r--r--libpod/kube.go4
-rw-r--r--libpod/logs/log.go22
-rw-r--r--libpod/network/create_test.go2
-rw-r--r--libpod/network/netconflist.go6
-rw-r--r--libpod/network/netconflist_test.go6
-rw-r--r--libpod/networking_linux.go7
-rw-r--r--libpod/oci.go2
-rw-r--r--libpod/oci_attach_linux.go2
-rw-r--r--libpod/oci_conmon_exec_linux.go2
-rw-r--r--libpod/oci_conmon_linux.go53
-rw-r--r--libpod/options.go5
-rw-r--r--libpod/pod_top_linux.go2
-rw-r--r--libpod/reset.go37
-rw-r--r--libpod/rootless_cni_linux.go4
-rw-r--r--libpod/runtime_ctr.go27
-rw-r--r--libpod/runtime_img.go2
-rw-r--r--libpod/runtime_volume.go27
-rw-r--r--libpod/runtime_volume_linux.go2
-rw-r--r--libpod/state_test.go6
-rw-r--r--libpod/util.go39
-rw-r--r--libpod/volume.go14
44 files changed, 341 insertions, 477 deletions
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
index e39b151f7..65efd5703 100644
--- a/libpod/boltdb_state_linux.go
+++ b/libpod/boltdb_state_linux.go
@@ -28,7 +28,7 @@ func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) er
newState.NetNS = ns
} else {
if ctr.ensureState(define.ContainerStateRunning, define.ContainerStatePaused) {
- return errors.Wrapf(err, "error joning network namespace of container %s", ctr.ID())
+ return errors.Wrapf(err, "error joining network namespace of container %s", ctr.ID())
}
logrus.Errorf("error joining network namespace for container %s: %v", ctr.ID(), err)
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 1b33f16b4..c3e1a23d2 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -571,7 +571,7 @@ func (c *Container) Cleanup(ctx context.Context) error {
// Batch starts a batch operation on the given container
// All commands in the passed function will execute under the same lock and
-// without syncronyzing state after each operation
+// without synchronizing state after each operation
// This will result in substantial performance benefits when running numerous
// commands on the same container
// Note that the container passed into the Batch function cannot be removed
diff --git a/libpod/container_config.go b/libpod/container_config.go
index c95be9b55..93ac8807d 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -151,7 +151,7 @@ type ContainerRootFSConfig struct {
// ContainerSecurityConfig is an embedded sub-config providing security configuration
// to the container.
type ContainerSecurityConfig struct {
- // Pirivileged is whether the container is privileged. Privileged
+ // Privileged is whether the container is privileged. Privileged
// containers have lessened security and increased access to the system.
// Note that this does NOT directly correspond to Podman's --privileged
// flag - most of the work of that flag is done in creating the OCI spec
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 2ce3e8e68..51474471b 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -8,6 +8,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/driver"
"github.com/containers/podman/v2/pkg/util"
+ units "github.com/docker/go-units"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/runtime-tools/validate"
@@ -124,8 +125,6 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data)
HostnamePath: hostnamePath,
HostsPath: hostsPath,
StaticDir: config.StaticDir,
- LogPath: config.LogPath,
- LogTag: config.LogTag,
OCIRuntime: config.OCIRuntime,
ConmonPidFile: config.ConmonPidFile,
Name: config.Name,
@@ -354,6 +353,10 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
logConfig := new(define.InspectLogConfig)
logConfig.Type = c.config.LogDriver
+ logConfig.Path = c.config.LogPath
+ logConfig.Size = units.HumanSize(float64(c.config.LogSize))
+ logConfig.Tag = c.config.LogTag
+
hostConfig.LogConfig = logConfig
restartPolicy := new(define.InspectRestartPolicy)
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index c751d775d..540230c26 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -884,9 +884,9 @@ func (c *Container) startDependencies(ctx context.Context) error {
// getAllDependencies is a precursor to starting dependencies.
// To start a container with all of its dependencies, we need to recursively find all dependencies
// a container has, as well as each of those containers' dependencies, and so on
-// To do so, keep track of containers already visisted (so there aren't redundant state lookups),
+// To do so, keep track of containers already visited (so there aren't redundant state lookups),
// and recursively search until we have reached the leafs of every dependency node.
-// Since we need to start all dependencies for our original container to successfully start, we propegate any errors
+// Since we need to start all dependencies for our original container to successfully start, we propagate any errors
// in looking up dependencies.
// Note: this function is currently meant as a robust solution to a narrow problem: start an infra-container when
// a container in the pod is run. It has not been tested for performance past one level, so expansion of recursive start
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 1bf044f9d..05b149e03 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -424,11 +424,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
if c.config.User != "" {
- if rootless.IsRootless() {
- if err := util.CheckRootlessUIDRange(execUser.Uid); err != nil {
- return nil, err
- }
- }
// User and Group must go together
g.SetProcessUID(uint32(execUser.Uid))
g.SetProcessGID(uint32(execUser.Gid))
@@ -1664,7 +1659,7 @@ func (c *Container) getHosts() string {
// generateGroupEntry generates an entry or entries into /etc/group as
// required by container configuration.
-// Generatlly speaking, we will make an entry under two circumstances:
+// Generally speaking, we will make an entry under two circumstances:
// 1. The container is started as a specific user:group, and that group is both
// numeric, and does not already exist in /etc/group.
// 2. It is requested that Libpod add the group that launched Podman to
@@ -1942,7 +1937,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
needGroup = false
}
- // Next, check if we already made the files. If we didn, don't need to
+ // Next, check if we already made the files. If we didn't, don't need to
// do anything more.
if needPasswd {
passwdPath := filepath.Join(c.config.StaticDir, "passwd")
diff --git a/libpod/container_log.go b/libpod/container_log.go
index 03cb09052..e58503bd3 100644
--- a/libpod/container_log.go
+++ b/libpod/container_log.go
@@ -23,7 +23,7 @@ func (r *Runtime) Log(ctx context.Context, containers []*Container, options *log
return nil
}
-// ReadLog reads a containers log based on the input options and returns loglines over a channel.
+// ReadLog reads a containers log based on the input options and returns log lines over a channel.
func (c *Container) ReadLog(ctx context.Context, options *logs.LogOptions, logChannel chan *logs.LogLine) error {
switch c.LogDriver() {
case define.NoLogging:
diff --git a/libpod/container_top_unsupported.go b/libpod/container_top_unsupported.go
index f911837d2..866fe106f 100644
--- a/libpod/container_top_unsupported.go
+++ b/libpod/container_top_unsupported.go
@@ -14,7 +14,7 @@ func (c *Container) Top(descriptors []string) ([]string, error) {
// the container. The output data can be controlled via the `descriptors`
// argument which expects format descriptors and supports all AIXformat
// descriptors of ps (1) plus some additional ones to for instance inspect the
-// set of effective capabilities. Eeach element in the returned string slice
+// set of effective capabilities. Each element in the returned string slice
// is a tab-separated string.
//
// For more details, please refer to github.com/containers/psgo.
diff --git a/libpod/container_validate.go b/libpod/container_validate.go
index fa809436e..57bb929dd 100644
--- a/libpod/container_validate.go
+++ b/libpod/container_validate.go
@@ -88,7 +88,7 @@ func (c *Container) validate() error {
return errors.Wrapf(define.ErrInvalidArg, "cannot add to /etc/hosts if using image's /etc/hosts")
}
- // Check named volume, overlay volume and image volume destination conflits
+ // Check named volume, overlay volume and image volume destination conflist
destinations := make(map[string]bool)
for _, vol := range c.config.NamedVolumes {
// Don't check if they already exist.
diff --git a/libpod/define/container_inspect.go b/libpod/define/container_inspect.go
index 775965477..c61f7c159 100644
--- a/libpod/define/container_inspect.go
+++ b/libpod/define/container_inspect.go
@@ -82,10 +82,15 @@ type InspectRestartPolicy struct {
}
// InspectLogConfig holds information about a container's configured log driver
-// and is presently unused. It is retained for Docker compatibility.
type InspectLogConfig struct {
Type string `json:"Type"`
Config map[string]string `json:"Config"` //idk type, TODO
+ // Path specifies a path to the log file
+ Path string `json:"Path"`
+ // Tag specifies a custom log tag for the container
+ Tag string `json:"Tag"`
+ // Size specifies a maximum size of the container log
+ Size string `json:"Size"`
}
// InspectBlkioWeightDevice holds information about the relative weight
@@ -152,7 +157,7 @@ type InspectMount struct {
// "volume" and "bind".
Type string `json:"Type"`
// The name of the volume. Empty for bind mounts.
- Name string `json:"Name,omptempty"`
+ Name string `json:"Name,omitempty"`
// The source directory for the volume.
Source string `json:"Source"`
// The destination directory for the volume. Specified as a path within
@@ -547,7 +552,7 @@ type InspectBasicNetworkConfig struct {
// GlobalIPv6PrefixLen is the length of the subnet mask of this network.
GlobalIPv6PrefixLen int `json:"GlobalIPv6PrefixLen"`
// SecondaryIPv6Addresses is a list of extra IPv6 Addresses that the
- // container has been assigned in this networ.
+ // container has been assigned in this network.
SecondaryIPv6Addresses []string `json:"SecondaryIPv6Addresses,omitempty"`
// MacAddress is the MAC address for the interface in this network.
MacAddress string `json:"MacAddress"`
@@ -620,8 +625,6 @@ type InspectContainerData struct {
StaticDir string `json:"StaticDir"`
OCIConfigPath string `json:"OCIConfigPath,omitempty"`
OCIRuntime string `json:"OCIRuntime,omitempty"`
- LogPath string `json:"LogPath"`
- LogTag string `json:"LogTag"`
ConmonPidFile string `json:"ConmonPidFile"`
Name string `json:"Name"`
RestartCount int32 `json:"RestartCount"`
diff --git a/libpod/define/info.go b/libpod/define/info.go
index f0e05801c..00146da48 100644
--- a/libpod/define/info.go
+++ b/libpod/define/info.go
@@ -12,6 +12,15 @@ type Info struct {
}
//HostInfo describes the libpod host
+type SecurityInfo struct {
+ AppArmorEnabled bool `json:"apparmorEnabled"`
+ DefaultCapabilities string `json:"capabilities"`
+ Rootless bool `json:"rootless"`
+ SECCOMPEnabled bool `json:"seccompEnabled"`
+ SELinuxEnabled bool `json:"selinuxEnabled"`
+}
+
+//HostInfo describes the libpod host
type HostInfo struct {
Arch string `json:"arch"`
BuildahVersion string `json:"buildahVersion"`
@@ -29,8 +38,8 @@ type HostInfo struct {
OCIRuntime *OCIRuntimeInfo `json:"ociRuntime"`
OS string `json:"os"`
RemoteSocket *RemoteSocket `json:"remoteSocket,omitempty"`
- Rootless bool `json:"rootless"`
RuntimeInfo map[string]interface{} `json:"runtimeInfo,omitempty"`
+ Security SecurityInfo `json:"security"`
Slirp4NetNS SlirpInfo `json:"slirp4netns,omitempty"`
SwapFree int64 `json:"swapFree"`
SwapTotal int64 `json:"swapTotal"`
diff --git a/libpod/events/events.go b/libpod/events/events.go
index 4e7267af3..aa0401b62 100644
--- a/libpod/events/events.go
+++ b/libpod/events/events.go
@@ -216,8 +216,5 @@ func (e EventLogFile) getTail(options ReadOptions) (*tail.Tail, error) {
reopen = false
}
stream := options.Stream
- if len(options.Until) > 0 {
- stream = false
- }
return tail.TailFile(e.options.LogFilePath, tail.Config{ReOpen: reopen, Follow: stream, Location: &seek, Logger: tail.DiscardingLogger, Poll: true})
}
diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go
index 9a514e302..8b7e448b1 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -8,6 +8,7 @@ import (
"strconv"
"time"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/coreos/go-systemd/v22/journal"
"github.com/coreos/go-systemd/v22/sdjournal"
"github.com/pkg/errors"
@@ -72,11 +73,22 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return errors.Wrapf(err, "failed to generate event options")
}
+ var untilTime time.Time
+ if len(options.Until) > 0 {
+ untilTime, err = util.ParseInputTime(options.Until)
+ if err != nil {
+ return err
+ }
+ }
j, err := sdjournal.NewJournal()
if err != nil {
return err
}
-
+ defer func() {
+ if err := j.Close(); err != nil {
+ logrus.Errorf("Unable to close journal :%v", err)
+ }
+ }()
// match only podman journal entries
podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"}
if err := j.AddMatch(podmanJournal.String()); err != nil {
@@ -104,7 +116,6 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return errors.Wrap(err, "failed to get journal cursor")
}
-
for {
select {
case <-ctx.Done():
@@ -122,10 +133,14 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error {
return errors.Wrap(err, "failed to get journal cursor")
}
if prevCursor == newCursor {
- if len(options.Until) > 0 || !options.Stream {
+ if !options.Stream || (len(options.Until) > 0 && time.Now().After(untilTime)) {
break
}
- _ = j.Wait(sdjournal.IndefiniteWait)
+ t := sdjournal.IndefiniteWait
+ if len(options.Until) > 0 {
+ t = time.Until(untilTime)
+ }
+ _ = j.Wait(t)
continue
}
prevCursor = newCursor
diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go
index 57e38b815..05ae3ce52 100644
--- a/libpod/events/logfile.go
+++ b/libpod/events/logfile.go
@@ -4,7 +4,9 @@ import (
"context"
"fmt"
"os"
+ "time"
+ "github.com/containers/podman/v2/pkg/util"
"github.com/containers/storage"
"github.com/pkg/errors"
)
@@ -51,6 +53,16 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
if err != nil {
return err
}
+ if len(options.Until) > 0 {
+ untilTime, err := util.ParseInputTime(options.Until)
+ if err != nil {
+ return err
+ }
+ go func() {
+ time.Sleep(time.Until(untilTime))
+ t.Stop()
+ }()
+ }
funcDone := make(chan bool)
copy := true
go func() {
diff --git a/libpod/filters/containers.go b/libpod/filters/containers.go
deleted file mode 100644
index 2520c4f30..000000000
--- a/libpod/filters/containers.go
+++ /dev/null
@@ -1,208 +0,0 @@
-package lpfilters
-
-import (
- "strconv"
- "strings"
- "time"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/timetype"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/pkg/errors"
-)
-
-// GenerateContainerFilterFuncs return ContainerFilter functions based of filter.
-func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
- switch filter {
- case "id":
- // we only have to match one ID
- return func(c *libpod.Container) bool {
- return util.StringMatchRegexSlice(c.ID(), filterValues)
- }, nil
- case "label":
- // we have to match that all given labels exits on that container
- return func(c *libpod.Container) bool {
- labels := c.Labels()
- for _, filterValue := range filterValues {
- matched := false
- filterArray := strings.SplitN(filterValue, "=", 2)
- filterKey := filterArray[0]
- if len(filterArray) > 1 {
- filterValue = filterArray[1]
- } else {
- filterValue = ""
- }
- for labelKey, labelValue := range labels {
- if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
- matched = true
- break
- }
- }
- if !matched {
- return false
- }
- }
- return true
- }, nil
- case "name":
- // we only have to match one name
- return func(c *libpod.Container) bool {
- return util.StringMatchRegexSlice(c.Name(), filterValues)
- }, nil
- case "exited":
- var exitCodes []int32
- for _, exitCode := range filterValues {
- ec, err := strconv.ParseInt(exitCode, 10, 32)
- if err != nil {
- return nil, errors.Wrapf(err, "exited code out of range %q", ec)
- }
- exitCodes = append(exitCodes, int32(ec))
- }
- return func(c *libpod.Container) bool {
- ec, exited, err := c.ExitCode()
- if err == nil && exited {
- for _, exitCode := range exitCodes {
- if ec == exitCode {
- return true
- }
- }
- }
- return false
- }, nil
- case "status":
- for _, filterValue := range filterValues {
- if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
- return nil, errors.Errorf("%s is not a valid status", filterValue)
- }
- }
- return func(c *libpod.Container) bool {
- status, err := c.State()
- if err != nil {
- return false
- }
- state := status.String()
- if status == define.ContainerStateConfigured {
- state = "created"
- } else if status == define.ContainerStateStopped {
- state = "exited"
- }
- for _, filterValue := range filterValues {
- if filterValue == "stopped" {
- filterValue = "exited"
- }
- if state == filterValue {
- return true
- }
- }
- return false
- }, nil
- case "ancestor":
- // This needs to refine to match docker
- // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
- return func(c *libpod.Container) bool {
- for _, filterValue := range filterValues {
- containerConfig := c.Config()
- if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
- return true
- }
- }
- return false
- }, nil
- case "before":
- var createTime time.Time
- for _, filterValue := range filterValues {
- ctr, err := r.LookupContainer(filterValue)
- if err != nil {
- return nil, err
- }
- containerConfig := ctr.Config()
- if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
- createTime = containerConfig.CreatedTime
- }
- }
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.After(cc.CreatedTime)
- }, nil
- case "since":
- var createTime time.Time
- for _, filterValue := range filterValues {
- ctr, err := r.LookupContainer(filterValue)
- if err != nil {
- return nil, err
- }
- containerConfig := ctr.Config()
- if createTime.IsZero() || createTime.After(containerConfig.CreatedTime) {
- createTime = containerConfig.CreatedTime
- }
- }
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.Before(cc.CreatedTime)
- }, nil
- case "volume":
- //- volume=(<volume-name>|<mount-point-destination>)
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- var dest string
- for _, filterValue := range filterValues {
- arr := strings.SplitN(filterValue, ":", 2)
- source := arr[0]
- if len(arr) == 2 {
- dest = arr[1]
- }
- for _, mount := range containerConfig.Spec.Mounts {
- if dest != "" && (mount.Source == source && mount.Destination == dest) {
- return true
- }
- if dest == "" && mount.Source == source {
- return true
- }
- }
- for _, vname := range containerConfig.NamedVolumes {
- if dest != "" && (vname.Name == source && vname.Dest == dest) {
- return true
- }
- if dest == "" && vname.Name == source {
- return true
- }
- }
- }
- return false
- }, nil
- case "health":
- return func(c *libpod.Container) bool {
- hcStatus, err := c.HealthCheckStatus()
- if err != nil {
- return false
- }
- for _, filterValue := range filterValues {
- if hcStatus == filterValue {
- return true
- }
- }
- return false
- }, nil
- case "until":
- if len(filterValues) != 1 {
- return nil, errors.Errorf("specify exactly one timestamp for %s", filter)
- }
- ts, err := timetype.GetTimestamp(filterValues[0], time.Now())
- if err != nil {
- return nil, err
- }
- seconds, nanoseconds, err := timetype.ParseTimestamps(ts, 0)
- if err != nil {
- return nil, err
- }
- until := time.Unix(seconds, nanoseconds)
- return func(c *libpod.Container) bool {
- if !until.IsZero() && c.CreatedTime().After((until)) {
- return true
- }
- return false
- }, nil
- }
- return nil, errors.Errorf("%s is an invalid filter", filter)
-}
diff --git a/libpod/filters/pods.go b/libpod/filters/pods.go
deleted file mode 100644
index 17b3f3ca9..000000000
--- a/libpod/filters/pods.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package lpfilters
-
-import (
- "strconv"
- "strings"
-
- "github.com/containers/podman/v2/libpod"
- "github.com/containers/podman/v2/libpod/define"
- "github.com/containers/podman/v2/pkg/util"
- "github.com/pkg/errors"
-)
-
-// GeneratePodFilterFunc takes a filter and filtervalue (key, value)
-// and generates a libpod function that can be used to filter
-// pods
-func GeneratePodFilterFunc(filter string, filterValues []string) (
- func(pod *libpod.Pod) bool, error) {
- switch filter {
- case "ctr-ids":
- return func(p *libpod.Pod) bool {
- ctrIds, err := p.AllContainersByID()
- if err != nil {
- return false
- }
- for _, id := range ctrIds {
- return util.StringMatchRegexSlice(id, filterValues)
- }
- return false
- }, nil
- case "ctr-names":
- return func(p *libpod.Pod) bool {
- ctrs, err := p.AllContainers()
- if err != nil {
- return false
- }
- for _, ctr := range ctrs {
- return util.StringMatchRegexSlice(ctr.Name(), filterValues)
- }
- return false
- }, nil
- case "ctr-number":
- return func(p *libpod.Pod) bool {
- ctrIds, err := p.AllContainersByID()
- if err != nil {
- return false
- }
- for _, filterValue := range filterValues {
- fVint, err2 := strconv.Atoi(filterValue)
- if err2 != nil {
- return false
- }
- if len(ctrIds) == fVint {
- return true
- }
- }
- return false
- }, nil
- case "ctr-status":
- for _, filterValue := range filterValues {
- if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
- return nil, errors.Errorf("%s is not a valid status", filterValue)
- }
- }
- return func(p *libpod.Pod) bool {
- ctrStatuses, err := p.Status()
- if err != nil {
- return false
- }
- for _, ctrStatus := range ctrStatuses {
- state := ctrStatus.String()
- if ctrStatus == define.ContainerStateConfigured {
- state = "created"
- } else if ctrStatus == define.ContainerStateStopped {
- state = "exited"
- }
- for _, filterValue := range filterValues {
- if filterValue == "stopped" {
- filterValue = "exited"
- }
- if state == filterValue {
- return true
- }
- }
- }
- return false
- }, nil
- case "id":
- return func(p *libpod.Pod) bool {
- return util.StringMatchRegexSlice(p.ID(), filterValues)
- }, nil
- case "name":
- return func(p *libpod.Pod) bool {
- return util.StringMatchRegexSlice(p.Name(), filterValues)
- }, nil
- case "status":
- for _, filterValue := range filterValues {
- if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created", "degraded"}) {
- return nil, errors.Errorf("%s is not a valid pod status", filterValue)
- }
- }
- return func(p *libpod.Pod) bool {
- status, err := p.GetPodStatus()
- if err != nil {
- return false
- }
- for _, filterValue := range filterValues {
- if strings.ToLower(status) == filterValue {
- return true
- }
- }
- return false
- }, nil
- case "label":
- return func(p *libpod.Pod) bool {
- labels := p.Labels()
- for _, filterValue := range filterValues {
- matched := false
- filterArray := strings.SplitN(filterValue, "=", 2)
- filterKey := filterArray[0]
- if len(filterArray) > 1 {
- filterValue = filterArray[1]
- } else {
- filterValue = ""
- }
- for labelKey, labelValue := range labels {
- if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
- matched = true
- break
- }
- }
- if !matched {
- return false
- }
- }
- return true
- }, nil
- }
- return nil, errors.Errorf("%s is an invalid filter", filter)
-}
diff --git a/libpod/image/df.go b/libpod/image/df.go
index 84cf7af9e..231d28df4 100644
--- a/libpod/image/df.go
+++ b/libpod/image/df.go
@@ -51,7 +51,7 @@ func (ir *Runtime) DiskUsage(ctx context.Context, images []*Image) ([]DiskUsageS
return stats, nil
}
-// diskUsageForImage returns the disk-usage statistics for the spcified image.
+// diskUsageForImage returns the disk-usage statistics for the specified image.
func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) (*DiskUsageStat, error) {
stat := DiskUsageStat{
ID: image.ID(),
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 5c3f3b9e4..a9082b2c6 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -497,7 +497,7 @@ func (ir *Runtime) getLocalImage(inputName string) (string, *storage.Image, erro
return inputName, repoImage, nil
}
- return "", nil, errors.Wrapf(ErrNoSuchImage, err.Error())
+ return "", nil, err
}
// ID returns the image ID as a string
diff --git a/libpod/image/parts.go b/libpod/image/parts.go
index d6c98783b..08421320c 100644
--- a/libpod/image/parts.go
+++ b/libpod/image/parts.go
@@ -50,7 +50,7 @@ func decompose(input string) (imageParts, error) {
// suspiciousRefNameTagValuesForSearch returns a "tag" value used in a previous implementation.
// This exists only to preserve existing behavior in heuristic code; it’s dubious that that behavior is correct,
-// gespecially for the tag value.
+// especially for the tag value.
func (ip *imageParts) suspiciousRefNameTagValuesForSearch() (string, string, string) {
registry := reference.Domain(ip.unnormalizedRef)
imageName := reference.Path(ip.unnormalizedRef)
diff --git a/libpod/image/prune.go b/libpod/image/prune.go
index b38265a7e..3c06a89c2 100644
--- a/libpod/image/prune.go
+++ b/libpod/image/prune.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/timetype"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -110,7 +111,8 @@ func (ir *Runtime) GetPruneImages(ctx context.Context, all bool, filterFuncs []I
// PruneImages prunes dangling and optionally all unused images from the local
// image store
-func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]string, error) {
+func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
filterFuncs := make([]ImageFilter, 0, len(filter))
for _, f := range filter {
filterSplit := strings.SplitN(f, "=", 2)
@@ -125,7 +127,6 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
filterFuncs = append(filterFuncs, generatedFunc)
}
- pruned := []string{}
prev := 0
for {
toPrune, err := ir.GetPruneImages(ctx, all, filterFuncs)
@@ -143,6 +144,13 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
if err != nil {
return nil, err
}
+ nameOrID := img.ID()
+ s, err := img.Size(ctx)
+ imgSize := *s
+ if err != nil {
+ logrus.Warnf("Failed to collect image size for: %s, %s", nameOrID, err)
+ imgSize = 0
+ }
if err := img.Remove(ctx, false); err != nil {
if errors.Cause(err) == storage.ErrImageUsedByContainer {
logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage (e.g., Buildah, CRI-O, etc.) maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", img.ID(), err)
@@ -151,13 +159,18 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
return nil, errors.Wrap(err, "failed to prune image")
}
defer img.newImageEvent(events.Prune)
- nameOrID := img.ID()
+
if len(repotags) > 0 {
nameOrID = repotags[0]
}
- pruned = append(pruned, nameOrID)
+
+ preports = append(preports, &reports.PruneReport{
+ Id: nameOrID,
+ Err: nil,
+ Size: uint64(imgSize),
+ })
}
}
- return pruned, nil
+ return preports, nil
}
diff --git a/libpod/image/search.go b/libpod/image/search.go
index b9acf4a20..6020fbca9 100644
--- a/libpod/image/search.go
+++ b/libpod/image/search.go
@@ -26,7 +26,7 @@ const (
type SearchResult struct {
// Index is the image index (e.g., "docker.io" or "quay.io")
Index string
- // Name is the canoncical name of the image (e.g., "docker.io/library/alpine").
+ // Name is the canonical name of the image (e.g., "docker.io/library/alpine").
Name string
// Description of the image.
Description string
diff --git a/libpod/image/utils.go b/libpod/image/utils.go
index 7429a7f10..5e7fed5c6 100644
--- a/libpod/image/utils.go
+++ b/libpod/image/utils.go
@@ -20,7 +20,11 @@ import (
// a match on name:tag
func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, error) {
_, searchName, searchSuspiciousTagValueForSearch := search.suspiciousRefNameTagValuesForSearch()
- var results []*storage.Image
+ type Candidate struct {
+ name string
+ image *Image
+ }
+ var candidates []Candidate
for _, image := range images {
for _, name := range image.Names() {
d, err := decompose(name)
@@ -29,23 +33,53 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er
continue
}
_, dName, dSuspiciousTagValueForSearch := d.suspiciousRefNameTagValuesForSearch()
- if dName == searchName && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
- results = append(results, image.image)
+ if dSuspiciousTagValueForSearch != searchSuspiciousTagValueForSearch {
continue
}
- // account for registry:/somedir/image
- if strings.HasSuffix(dName, "/"+searchName) && dSuspiciousTagValueForSearch == searchSuspiciousTagValueForSearch {
- results = append(results, image.image)
- continue
+ if dName == searchName || strings.HasSuffix(dName, "/"+searchName) {
+ candidates = append(candidates, Candidate{
+ name: name,
+ image: image,
+ })
}
}
}
- if len(results) == 0 {
- return &storage.Image{}, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName)
- } else if len(results) > 1 {
- return &storage.Image{}, errors.Wrapf(define.ErrMultipleImages, searchName)
+ if len(candidates) == 0 {
+
+ return nil, errors.Wrapf(define.ErrNoSuchImage, "unable to find a name and tag match for %s in repotags", searchName)
+ }
+
+ // If more then one candidate and the candidates all have same name
+ // and only one is read/write return it.
+ // Othewise return error with the list of candidates
+ if len(candidates) > 1 {
+ var (
+ rwImage *Image
+ rwImageCnt int
+ )
+ names := make(map[string]bool)
+ for _, c := range candidates {
+ names[c.name] = true
+ if !c.image.IsReadOnly() {
+ rwImageCnt++
+ rwImage = c.image
+ }
+ }
+ // If only one name used and have read/write image return it
+ if len(names) == 1 && rwImageCnt == 1 {
+ return rwImage.image, nil
+ }
+ keys := []string{}
+ for k := range names {
+ keys = append(keys, k)
+ }
+ if rwImageCnt > 1 {
+ return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/write images %s", strings.Join(keys, ","))
+ } else {
+ return nil, errors.Wrapf(define.ErrMultipleImages, "found multiple read/only images %s", strings.Join(keys, ","))
+ }
}
- return results[0], nil
+ return candidates[0].image.image, nil
}
// getCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters, inheriting some from sc.
diff --git a/libpod/info.go b/libpod/info.go
index 2f64a107e..1b3550abd 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,6 +13,8 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/common/pkg/apparmor"
+ "github.com/containers/common/pkg/seccomp"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/linkmode"
"github.com/containers/podman/v2/pkg/cgroups"
@@ -20,6 +22,7 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/system"
+ "github.com/opencontainers/selinux/go-selinux"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -98,10 +101,16 @@ func (r *Runtime) hostInfo() (*define.HostInfo, error) {
MemFree: mi.MemFree,
MemTotal: mi.MemTotal,
OS: runtime.GOOS,
- Rootless: rootless.IsRootless(),
- Slirp4NetNS: define.SlirpInfo{},
- SwapFree: mi.SwapFree,
- SwapTotal: mi.SwapTotal,
+ Security: define.SecurityInfo{
+ AppArmorEnabled: apparmor.IsEnabled(),
+ DefaultCapabilities: strings.Join(r.config.Containers.DefaultCapabilities, ","),
+ Rootless: rootless.IsRootless(),
+ SECCOMPEnabled: seccomp.IsEnabled(),
+ SELinuxEnabled: selinux.GetEnabled(),
+ },
+ Slirp4NetNS: define.SlirpInfo{},
+ SwapFree: mi.SwapFree,
+ SwapTotal: mi.SwapTotal,
}
// CGroups version
diff --git a/libpod/kube.go b/libpod/kube.go
index bf041112a..753c58099 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -403,7 +403,7 @@ func libpodEnvVarsToKubeEnvVars(envs []string) ([]v1.EnvVar, error) {
// libpodMountsToKubeVolumeMounts converts the containers mounts to a struct kube understands
func libpodMountsToKubeVolumeMounts(c *Container) ([]v1.VolumeMount, []v1.Volume, error) {
- // TjDO when named volumes are supported in play kube, also parse named volumes here
+ // TODO when named volumes are supported in play kube, also parse named volumes here
_, mounts := c.sortUserVolumes(c.config.Spec)
vms := make([]v1.VolumeMount, 0, len(mounts))
vos := make([]v1.Volume, 0, len(mounts))
@@ -524,7 +524,7 @@ func capAddDrop(caps *specs.LinuxCapabilities) (*v1.Capabilities, error) {
defaultCaps = append(defaultCaps, g.Config.Process.Capabilities.Inheritable...)
defaultCaps = append(defaultCaps, g.Config.Process.Capabilities.Permitted...)
- // Combine all the container's capabilities into a slic
+ // Combine all the container's capabilities into a slice
containerCaps := append(caps.Ambient, caps.Bounding...)
containerCaps = append(containerCaps, caps.Effective...)
containerCaps = append(containerCaps, caps.Inheritable...)
diff --git a/libpod/logs/log.go b/libpod/logs/log.go
index a9554088b..2637c8524 100644
--- a/libpod/logs/log.go
+++ b/libpod/logs/log.go
@@ -73,7 +73,7 @@ func GetLogFile(path string, options *LogOptions) (*tail.Tail, []*LogLine, error
Whence: whence,
}
- t, err := tail.TailFile(path, tail.Config{MustExist: true, Poll: true, Follow: options.Follow, Location: &seek, Logger: tail.DiscardingLogger})
+ t, err := tail.TailFile(path, tail.Config{MustExist: true, Poll: true, Follow: options.Follow, Location: &seek, Logger: tail.DiscardingLogger, ReOpen: options.Follow})
return t, logTail, err
}
@@ -137,7 +137,7 @@ func getTailLog(path string, tail int) ([]*LogLine, error) {
nllCounter++
}
}
- // if we have enough loglines, we can hangup
+ // if we have enough log lines, we can hangup
if nllCounter >= tail {
break
}
@@ -161,7 +161,7 @@ func getTailLog(path string, tail int) ([]*LogLine, error) {
return tailLog, nil
}
-// String converts a logline to a string for output given whether a detail
+// String converts a log line to a string for output given whether a detail
// bool is specified.
func (l *LogLine) String(options *LogOptions) string {
var out string
@@ -210,3 +210,19 @@ func NewLogLine(line string) (*LogLine, error) {
func (l *LogLine) Partial() bool {
return l.ParseLogType == PartialLogType
}
+
+func (l *LogLine) Write(stdout io.Writer, stderr io.Writer, logOpts *LogOptions) {
+ switch l.Device {
+ case "stdout":
+ if stdout != nil {
+ fmt.Fprintln(stdout, l.String(logOpts))
+ }
+ case "stderr":
+ if stderr != nil {
+ fmt.Fprintln(stderr, l.String(logOpts))
+ }
+ default:
+ // Warn the user if the device type does not match. Most likely the file is corrupted.
+ logrus.Warnf("unknown Device type '%s' in log file from Container %s", l.Device, l.CID)
+ }
+}
diff --git a/libpod/network/create_test.go b/libpod/network/create_test.go
index 16188e497..0b828e635 100644
--- a/libpod/network/create_test.go
+++ b/libpod/network/create_test.go
@@ -61,7 +61,7 @@ func Test_validateBridgeOptions(t *testing.T) {
isIPv6: true,
},
{
- name: "IPv6 subnet, range and gateway without IPv6 option (PODMAN SUPPORTS IT UNLIKE DOCKEr)",
+ name: "IPv6 subnet, range and gateway without IPv6 option (PODMAN SUPPORTS IT UNLIKE DOCKER)",
subnet: net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
ipRange: net.IPNet{IP: net.ParseIP("2001:DB8:0:0:1::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff:ffff::"))},
gateway: net.ParseIP("2001:DB8::2"),
diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go
index d61b96ecb..bf7d03501 100644
--- a/libpod/network/netconflist.go
+++ b/libpod/network/netconflist.go
@@ -60,7 +60,7 @@ func NewHostLocalBridge(name string, isGateWay, isDefaultGW, ipMasq bool, mtu in
return &hostLocalBridge
}
-// NewIPAMHostLocalConf creates a new IPAMHostLocal configfuration
+// NewIPAMHostLocalConf creates a new IPAMHostLocal configuration
func NewIPAMHostLocalConf(routes []IPAMRoute, ipamRanges [][]IPAMLocalHostRangeConf) (IPAMHostLocalConf, error) {
ipamConf := IPAMHostLocalConf{
PluginType: "host-local",
@@ -95,6 +95,10 @@ func NewIPAMLocalHostRange(subnet *net.IPNet, ipRange *net.IPNet, gw net.IP) ([]
}
if gw != nil {
hostRange.Gateway = gw.String()
+ } else {
+ // Add first ip in subnet as gateway. It is not required
+ // by cni but should be included because of network inspect.
+ hostRange.Gateway = CalcGatewayIP(subnet).String()
}
ranges = append(ranges, hostRange)
return ranges, nil
diff --git a/libpod/network/netconflist_test.go b/libpod/network/netconflist_test.go
index 6bf1a9777..5ff733f0f 100644
--- a/libpod/network/netconflist_test.go
+++ b/libpod/network/netconflist_test.go
@@ -51,7 +51,8 @@ func TestNewIPAMLocalHostRange(t *testing.T) {
subnet: &net.IPNet{IP: net.IPv4(192, 168, 0, 0), Mask: net.IPv4Mask(255, 255, 255, 0)},
want: []IPAMLocalHostRangeConf{
{
- Subnet: "192.168.0.0/24",
+ Subnet: "192.168.0.0/24",
+ Gateway: "192.168.0.1",
},
},
},
@@ -74,7 +75,8 @@ func TestNewIPAMLocalHostRange(t *testing.T) {
subnet: &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
want: []IPAMLocalHostRangeConf{
{
- Subnet: "2001:db8::/48",
+ Subnet: "2001:db8::/48",
+ Gateway: "2001:db8::1",
},
},
},
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index bf27989bf..be6867399 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -247,6 +247,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) error {
func (r *Runtime) setupSlirp4netns(ctr *Container) error {
path := r.config.Engine.NetworkCmdPath
slirpOptions := r.config.Engine.NetworkCmdOptions
+ noPivotRoot := r.config.Engine.NoPivotRoot
if path == "" {
var err error
path, err = exec.LookPath("slirp4netns")
@@ -351,7 +352,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
if slirpFeatures.HasMTU {
cmdArgs = append(cmdArgs, "--mtu", "65520")
}
- if slirpFeatures.HasEnableSandbox {
+ if !noPivotRoot && slirpFeatures.HasEnableSandbox {
cmdArgs = append(cmdArgs, "--enable-sandbox")
}
if slirpFeatures.HasEnableSeccomp {
@@ -424,7 +425,7 @@ func (r *Runtime) setupSlirp4netns(ctr *Container) error {
}
// workaround for https://github.com/rootless-containers/slirp4netns/pull/153
- if slirpFeatures.HasEnableSandbox {
+ if !noPivotRoot && slirpFeatures.HasEnableSandbox {
cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
}
@@ -1155,7 +1156,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
return c.save()
}
-// ConnnectNetwork connects a container to a given network
+// ConnectNetwork connects a container to a given network
func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) error {
networks, err := c.networksByNameIndex()
if err != nil {
diff --git a/libpod/oci.go b/libpod/oci.go
index 924c32510..157c42c38 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -56,7 +56,7 @@ type OCIRuntime interface {
// a header prepended as follows: 1-byte STREAM (0, 1, 2 for STDIN,
// STDOUT, STDERR), 3 null (0x00) bytes, 4-byte big endian length.
// If a cancel channel is provided, it can be used to asynchronously
- // termninate the attach session. Detach keys, if given, will also cause
+ // terminate the attach session. Detach keys, if given, will also cause
// the attach session to be terminated if provided via the STDIN
// channel. If they are not provided, the default detach keys will be
// used instead. Detach keys of "" will disable detaching via keyboard.
diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go
index 149ee813b..fbc95510e 100644
--- a/libpod/oci_attach_linux.go
+++ b/libpod/oci_attach_linux.go
@@ -83,7 +83,7 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <-
// Attach to the given container's exec session
// attachFd and startFd must be open file descriptors
// attachFd must be the output side of the fd. attachFd is used for two things:
-// conmon will first send a nonse value across the pipe indicating it has set up its side of the console socket
+// conmon will first send a nonce value across the pipe indicating it has set up its side of the console socket
// this ensures attachToExec gets all of the output of the called process
// conmon will then send the exit code of the exec process, or an error in the exec session
// startFd must be the input side of the fd.
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index f8e7020f7..4546acefb 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -387,7 +387,7 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
finalEnv = append(finalEnv, fmt.Sprintf("%s=%s", k, v))
}
- processFile, err := prepareProcessExec(c, options.Cmd, finalEnv, options.Terminal, options.Cwd, options.User, sessionID)
+ processFile, err := prepareProcessExec(c, options, finalEnv, sessionID)
if err != nil {
return nil, nil, err
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 307b9bc54..e7cb5a802 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -47,7 +47,7 @@ import (
const (
// This is Conmon's STDIO_BUF_SIZE. I don't believe we have access to it
- // directly from the Go cose, so const it here
+ // directly from the Go code, so const it here
bufferSize = conmonConfig.BufSize
)
@@ -69,6 +69,7 @@ type ConmonOCIRuntime struct {
supportsKVM bool
supportsNoCgroups bool
sdNotify bool
+ enableKeyring bool
}
// Make a new Conmon-based OCI runtime with the given options.
@@ -107,6 +108,7 @@ func newConmonOCIRuntime(name string, paths []string, conmonPath string, runtime
runtime.noPivot = runtimeCfg.Engine.NoPivotRoot
runtime.reservePorts = runtimeCfg.Engine.EnablePortReservation
runtime.sdNotify = runtimeCfg.Engine.SDNotify
+ runtime.enableKeyring = runtimeCfg.Containers.EnableKeyring
// TODO: probe OCI runtime for feature and enable automatically if
// available.
@@ -191,6 +193,11 @@ func hasCurrentUserMapped(ctr *Container) bool {
// CreateContainer creates a container.
func (r *ConmonOCIRuntime) CreateContainer(ctr *Container, restoreOptions *ContainerCheckpointOptions) error {
+ // always make the run dir accessible to the current user so that the PID files can be read without
+ // being in the rootless user namespace.
+ if err := makeAccessible(ctr.state.RunDir, 0, 0); err != nil {
+ return err
+ }
if !hasCurrentUserMapped(ctr) {
for _, i := range []string{ctr.state.RunDir, ctr.runtime.config.Engine.TmpDir, ctr.config.StaticDir, ctr.state.Mountpoint, ctr.runtime.config.Engine.VolumePath} {
if err := makeAccessible(i, ctr.RootUID(), ctr.RootGID()); err != nil {
@@ -1021,6 +1028,9 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
args = append(args, "-i")
}
+ if !r.enableKeyring {
+ args = append(args, "--no-new-keyring")
+ }
if ctr.config.ConmonPidFile != "" {
args = append(args, "--conmon-pidfile", ctr.config.ConmonPidFile)
}
@@ -1180,26 +1190,36 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
// prepareProcessExec returns the path of the process.json used in runc exec -p
// caller is responsible to close the returned *os.File if needed.
-func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, sessionID string) (*os.File, error) {
+func prepareProcessExec(c *Container, options *ExecOptions, env []string, sessionID string) (*os.File, error) {
f, err := ioutil.TempFile(c.execBundlePath(sessionID), "exec-process-")
if err != nil {
return nil, err
}
- pspec := c.config.Spec.Process
+ pspec := new(spec.Process)
+ if err := JSONDeepCopy(c.config.Spec.Process, pspec); err != nil {
+ return nil, err
+ }
pspec.SelinuxLabel = c.config.ProcessLabel
- pspec.Args = cmd
+ pspec.Args = options.Cmd
+ for _, cap := range options.CapAdd {
+ pspec.Capabilities.Bounding = append(pspec.Capabilities.Bounding, cap)
+ pspec.Capabilities.Effective = append(pspec.Capabilities.Effective, cap)
+ pspec.Capabilities.Inheritable = append(pspec.Capabilities.Inheritable, cap)
+ pspec.Capabilities.Permitted = append(pspec.Capabilities.Permitted, cap)
+ pspec.Capabilities.Ambient = append(pspec.Capabilities.Ambient, cap)
+ }
// We need to default this to false else it will inherit terminal as true
// from the container.
pspec.Terminal = false
- if tty {
+ if options.Terminal {
pspec.Terminal = true
}
if len(env) > 0 {
pspec.Env = append(pspec.Env, env...)
}
- if cwd != "" {
- pspec.Cwd = cwd
+ if options.Cwd != "" {
+ pspec.Cwd = options.Cwd
}
@@ -1207,6 +1227,7 @@ func prepareProcessExec(c *Container, cmd, env []string, tty bool, cwd, user, se
var sgids []uint32
// if the user is empty, we should inherit the user that the container is currently running with
+ user := options.User
if user == "" {
user = c.config.User
addGroups = c.config.Groups
@@ -1413,7 +1434,7 @@ func startCommandGivenSelinux(cmd *exec.Cmd) error {
}
// moveConmonToCgroupAndSignal gets a container's cgroupParent and moves the conmon process to that cgroup
-// it then signals for conmon to start by sending nonse data down the start fd
+// it then signals for conmon to start by sending nonce data down the start fd
func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec.Cmd, startFd *os.File) error {
mustCreateCgroup := true
@@ -1433,6 +1454,14 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
}
if mustCreateCgroup {
+ // Usually rootless users are not allowed to configure cgroupfs.
+ // There are cases though, where it is allowed, e.g. if the cgroup
+ // is manually configured and chowned). Avoid detecting all
+ // such cases and simply use a lower log level.
+ logLevel := logrus.WarnLevel
+ if rootless.IsRootless() {
+ logLevel = logrus.InfoLevel
+ }
// TODO: This should be a switch - we are not guaranteed that
// there are only 2 valid cgroup managers
cgroupParent := ctr.CgroupParent()
@@ -1447,17 +1476,17 @@ func (r *ConmonOCIRuntime) moveConmonToCgroupAndSignal(ctr *Container, cmd *exec
logrus.Infof("Running conmon under slice %s and unitName %s", realCgroupParent, unitName)
if err := utils.RunUnderSystemdScope(cmd.Process.Pid, realCgroupParent, unitName); err != nil {
- logrus.Warnf("Failed to add conmon to systemd sandbox cgroup: %v", err)
+ logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to systemd sandbox cgroup: %v", err)
}
} else {
cgroupPath := filepath.Join(ctr.config.CgroupParent, "conmon")
control, err := cgroups.New(cgroupPath, &spec.LinuxResources{})
if err != nil {
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
} else if err := control.AddPid(cmd.Process.Pid); err != nil {
// we need to remove this defer and delete the cgroup once conmon exits
// maybe need a conmon monitor?
- logrus.Warnf("Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
+ logrus.StandardLogger().Logf(logLevel, "Failed to add conmon to cgroupfs sandbox cgroup: %v", err)
}
}
}
@@ -1564,7 +1593,7 @@ func readConmonPipeData(pipe *os.File, ociLog string) (int, error) {
return data, nil
}
-// writeConmonPipeData writes nonse data to a pipe
+// writeConmonPipeData writes nonce data to a pipe
func writeConmonPipeData(pipe *os.File) error {
someData := []byte{0}
_, err := pipe.Write(someData)
diff --git a/libpod/options.go b/libpod/options.go
index bd12c0c34..8100eee62 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -502,6 +502,7 @@ func WithEventsLogger(logger string) RuntimeOption {
}
rt.config.Engine.EventsLogger = logger
+ rt.config.Engine.EventsLogFilePath = filepath.Join(rt.config.Engine.TmpDir, "events", "events.log")
return nil
}
@@ -750,7 +751,7 @@ func WithStopTimeout(timeout uint) CtrCreateOption {
}
}
-// WithIDMappings sets the idmappsings for the container
+// WithIDMappings sets the idmappings for the container
func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
@@ -1592,7 +1593,7 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption {
volume.config.Options = make(map[string]string)
for key, value := range options {
switch key {
- case "type", "device", "o":
+ case "type", "device", "o", "UID", "GID":
volume.config.Options[key] = value
default:
return errors.Wrapf(define.ErrInvalidArg, "unrecognized volume option %q is not supported with local driver", key)
diff --git a/libpod/pod_top_linux.go b/libpod/pod_top_linux.go
index 0e42c62df..07e1a0d80 100644
--- a/libpod/pod_top_linux.go
+++ b/libpod/pod_top_linux.go
@@ -15,7 +15,7 @@ import (
// the pod. The output data can be controlled via the `descriptors`
// argument which expects format descriptors and supports all AIXformat
// descriptors of ps (1) plus some additional ones to for instance inspect the
-// set of effective capabilities. Eeach element in the returned string slice
+// set of effective capabilities. Each element in the returned string slice
// is a tab-separated string.
//
// For more details, please refer to github.com/containers/psgo.
diff --git a/libpod/reset.go b/libpod/reset.go
index 6d2842723..24efeed40 100644
--- a/libpod/reset.go
+++ b/libpod/reset.go
@@ -77,18 +77,35 @@ func (r *Runtime) Reset(ctx context.Context) error {
}
}
+ xdgRuntimeDir := filepath.Clean(os.Getenv("XDG_RUNTIME_DIR"))
_, prevError := r.store.Shutdown(true)
- if err := os.RemoveAll(r.store.GraphRoot()); err != nil {
+ graphRoot := filepath.Clean(r.store.GraphRoot())
+ if graphRoot == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime graph root dir %s, since it is the same as XDG_RUNTIME_DIR", graphRoot)
+ } else {
+ if err := os.RemoveAll(graphRoot); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
- if err := os.RemoveAll(r.store.RunRoot()); err != nil {
+ runRoot := filepath.Clean(r.store.RunRoot())
+ if runRoot == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime root dir %s, since it is the same as XDG_RUNTIME_DIR", runRoot)
+ } else {
+ if err := os.RemoveAll(runRoot); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
runtimeDir, err := util.GetRuntimeDir()
if err != nil {
@@ -98,13 +115,19 @@ func (r *Runtime) Reset(ctx context.Context) error {
if tempDir == runtimeDir {
tempDir = filepath.Join(tempDir, "containers")
}
- if err := os.RemoveAll(tempDir); err != nil {
+ if filepath.Clean(tempDir) == xdgRuntimeDir {
if prevError != nil {
logrus.Error(prevError)
}
- prevError = err
+ prevError = errors.Errorf("failed to remove runtime tmpdir %s, since it is the same as XDG_RUNTIME_DIR", tempDir)
+ } else {
+ if err := os.RemoveAll(tempDir); err != nil {
+ if prevError != nil {
+ logrus.Error(prevError)
+ }
+ prevError = err
+ }
}
-
if storageConfPath, err := storage.DefaultConfigFile(rootless.IsRootless()); err == nil {
if _, err = os.Stat(storageConfPath); err == nil {
fmt.Printf("A storage.conf file exists at %s\n", storageConfPath)
diff --git a/libpod/rootless_cni_linux.go b/libpod/rootless_cni_linux.go
index 2c2977f9f..ce8a87759 100644
--- a/libpod/rootless_cni_linux.go
+++ b/libpod/rootless_cni_linux.go
@@ -100,7 +100,7 @@ func DeallocRootlessCNI(ctx context.Context, c *Container) error {
}
var errs *multierror.Error
for _, nw := range networks {
- err := rootlessCNIInfraCallDelloc(infra, c.ID(), nw)
+ err := rootlessCNIInfraCallDealloc(infra, c.ID(), nw)
if err != nil {
errs = multierror.Append(errs, err)
}
@@ -154,7 +154,7 @@ func rootlessCNIInfraCallAlloc(infra *Container, id, nw, k8sPodName string) (*cn
return &cniRes, nil
}
-func rootlessCNIInfraCallDelloc(infra *Container, id, nw string) error {
+func rootlessCNIInfraCallDealloc(infra *Container, id, nw string) error {
logrus.Debugf("rootless CNI: dealloc %q, %q", id, nw)
_, err := rootlessCNIInfraExec(infra, "dealloc", id, nw)
return err
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 14b537ca2..f22e48746 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/libpod/shutdown"
"github.com/containers/podman/v2/pkg/cgroups"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
@@ -884,9 +885,8 @@ func (r *Runtime) GetExecSessionContainer(id string) (*Container, error) {
// PruneContainers removes stopped and exited containers from localstorage. A set of optional filters
// can be provided to be more granular.
-func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int64, map[string]error, error) {
- pruneErrors := make(map[string]error)
- prunedContainers := make(map[string]int64)
+func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
// We add getting the exited and stopped containers via a filter
containerStateFilter := func(c *Container) bool {
if c.PodID() != "" {
@@ -906,23 +906,28 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
filterFuncs = append(filterFuncs, containerStateFilter)
delContainers, err := r.GetContainers(filterFuncs...)
if err != nil {
- return nil, nil, err
+ return nil, err
}
for _, c := range delContainers {
- ctr := c
- size, err := ctr.RWSize()
+ report := new(reports.PruneReport)
+ report.Id = c.ID()
+ report.Err = nil
+ report.Size = 0
+ size, err := c.RWSize()
if err != nil {
- pruneErrors[ctr.ID()] = err
+ report.Err = err
+ preports = append(preports, report)
continue
}
- err = r.RemoveContainer(context.Background(), ctr, false, false)
+ err = r.RemoveContainer(context.Background(), c, false, false)
if err != nil {
- pruneErrors[ctr.ID()] = err
+ report.Err = err
} else {
- prunedContainers[ctr.ID()] = size
+ report.Size = (uint64)(size)
}
+ preports = append(preports, report)
}
- return prunedContainers, pruneErrors, nil
+ return preports, nil
}
// MountStorageContainer mounts the storage container's root filesystem
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index a2d9a875e..965333f77 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -230,7 +230,7 @@ func (r *Runtime) Import(ctx context.Context, source, reference, signaturePolicy
return newImage.ID(), nil
}
-// donwloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
+// downloadFromURL downloads an image in the format "https:/example.com/myimage.tar"
// and temporarily saves in it $TMPDIR/importxyz, which is deleted after the image is imported
func downloadFromURL(source string) (string, error) {
fmt.Printf("Downloading from %q\n", source)
diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go
index 055a243c0..9d985f905 100644
--- a/libpod/runtime_volume.go
+++ b/libpod/runtime_volume.go
@@ -5,6 +5,7 @@ import (
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
+ "github.com/containers/podman/v2/pkg/domain/entities/reports"
"github.com/pkg/errors"
)
@@ -133,22 +134,32 @@ func (r *Runtime) GetAllVolumes() ([]*Volume, error) {
}
// PruneVolumes removes unused volumes from the system
-func (r *Runtime) PruneVolumes(ctx context.Context) (map[string]error, error) {
- reports := make(map[string]error)
- vols, err := r.GetAllVolumes()
+func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) ([]*reports.PruneReport, error) {
+ preports := make([]*reports.PruneReport, 0)
+ vols, err := r.Volumes(filterFuncs...)
if err != nil {
return nil, err
}
for _, vol := range vols {
+ report := new(reports.PruneReport)
+ volSize, err := vol.Size()
+ if err != nil {
+ volSize = 0
+ }
+ report.Size = volSize
+ report.Id = vol.Name()
if err := r.RemoveVolume(ctx, vol, false); err != nil {
if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved {
- reports[vol.Name()] = err
+ report.Err = err
+ } else {
+ // We didn't remove the volume for some reason
+ continue
}
- continue
+ } else {
+ vol.newVolumeEvent(events.Prune)
}
- vol.newVolumeEvent(events.Prune)
- reports[vol.Name()] = nil
+ preports = append(preports, report)
}
- return reports, nil
+ return preports, nil
}
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index e1877b17d..9bf0fd108 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -58,7 +58,7 @@ func (r *Runtime) newVolume(ctx context.Context, options ...VolumeCreateOption)
// Validate options
for key := range volume.config.Options {
switch key {
- case "device", "o", "type":
+ case "device", "o", "type", "UID", "GID":
// Do nothing, valid keys
default:
return nil, errors.Wrapf(define.ErrInvalidArg, "invalid mount option %s for driver 'local'", key)
diff --git a/libpod/state_test.go b/libpod/state_test.go
index da28f3d3f..0709071ec 100644
--- a/libpod/state_test.go
+++ b/libpod/state_test.go
@@ -882,7 +882,7 @@ func TestRemoveContainer(t *testing.T) {
})
}
-func TestRemoveNonexistantContainerFails(t *testing.T) {
+func TestRemoveNonexistentContainerFails(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
testCtr, err := getTestCtr1(manager)
assert.NoError(t, err)
@@ -1513,7 +1513,7 @@ func TestGetNotExistPodWithPods(t *testing.T) {
err = state.AddPod(testPod2)
assert.NoError(t, err)
- _, err = state.Pod("notexist")
+ _, err = state.Pod("nonexistent")
assert.Error(t, err)
})
}
@@ -1748,7 +1748,7 @@ func TestHasPodEmptyIDErrors(t *testing.T) {
func TestHasPodNoSuchPod(t *testing.T) {
runForAllStates(t, func(t *testing.T, state State, manager lock.Manager) {
- exist, err := state.HasPod("notexist")
+ exist, err := state.HasPod("nonexistent")
assert.NoError(t, err)
assert.False(t, exist)
})
diff --git a/libpod/util.go b/libpod/util.go
index c26039c50..bf9bf2542 100644
--- a/libpod/util.go
+++ b/libpod/util.go
@@ -142,29 +142,44 @@ func JSONDeepCopy(from, to interface{}) error {
return json.Unmarshal(tmp, to)
}
-func dpkgVersion(path string) string {
+func queryPackageVersion(cmdArg ...string) string {
output := unknownPackage
- cmd := exec.Command("/usr/bin/dpkg", "-S", path)
- if outp, err := cmd.Output(); err == nil {
- output = string(outp)
+ if 1 < len(cmdArg) {
+ cmd := exec.Command(cmdArg[0], cmdArg[1:]...)
+ if outp, err := cmd.Output(); err == nil {
+ output = string(outp)
+ }
}
return strings.Trim(output, "\n")
}
+func equeryVersion(path string) string {
+ return queryPackageVersion("/usr/bin/equery", "b", path)
+}
+
+func pacmanVersion(path string) string {
+ return queryPackageVersion("/usr/bin/pacman", "-Qo", path)
+}
+
+func dpkgVersion(path string) string {
+ return queryPackageVersion("/usr/bin/dpkg", "-S", path)
+}
+
func rpmVersion(path string) string {
- output := unknownPackage
- cmd := exec.Command("/usr/bin/rpm", "-q", "-f", path)
- if outp, err := cmd.Output(); err == nil {
- output = string(outp)
- }
- return strings.Trim(output, "\n")
+ return queryPackageVersion("/usr/bin/rpm", "-q", "-f", path)
}
func packageVersion(program string) string {
if out := rpmVersion(program); out != unknownPackage {
return out
}
- return dpkgVersion(program)
+ if out := dpkgVersion(program); out != unknownPackage {
+ return out
+ }
+ if out := pacmanVersion(program); out != unknownPackage {
+ return out
+ }
+ return equeryVersion(program)
}
func programVersion(mountProgram string) (string, error) {
@@ -272,7 +287,7 @@ func writeHijackHeader(r *http.Request, conn io.Writer) {
fmt.Fprintf(conn,
"HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
} else {
- // Upraded
+ // Upgraded
fmt.Fprintf(conn,
"HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: %s\r\n\r\n",
proto)
diff --git a/libpod/volume.go b/libpod/volume.go
index 0535bf4db..ed08d375f 100644
--- a/libpod/volume.go
+++ b/libpod/volume.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "os"
+ "path/filepath"
"time"
"github.com/containers/podman/v2/libpod/define"
@@ -79,6 +81,18 @@ func (v *Volume) Name() string {
return v.config.Name
}
+// Returns the size on disk of volume
+func (v *Volume) Size() (uint64, error) {
+ var size uint64
+ err := filepath.Walk(v.config.MountPoint, func(path string, info os.FileInfo, err error) error {
+ if err == nil && !info.IsDir() {
+ size += (uint64)(info.Size())
+ }
+ return err
+ })
+ return size, err
+}
+
// Driver retrieves the volume's driver.
func (v *Volume) Driver() string {
return v.config.Driver