diff options
82 files changed, 645 insertions, 430 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index cbe8bc757..18cb889ad 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -30,7 +30,7 @@ env: PRIOR_UBUNTU_NAME: "ubuntu-2004" # Google-cloud VM Images - IMAGE_SUFFIX: "c6233039174893568" + IMAGE_SUFFIX: "c6524344056676352" FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "prior-fedora-${IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "ubuntu-${IMAGE_SUFFIX}" @@ -177,9 +177,8 @@ familiar container cli commands. For more details, see the [Container Tools Guide](https://github.com/containers/buildah/tree/master/docs/containertools). ## Podman Former API (Varlink) -Podman formerly offered a [Varlink-based API](https://github.com/containers/podman/blob/master/docs/tutorials/varlink_remote_client.md) -for remote management of containers. However, this API was replaced by the REST API. -Varlink support has been removed as of the 3.0 release. +Podman formerly offered a Varlink-based API for remote management of containers. However, this API +was replaced by the REST API. Varlink support has been removed as of the 3.0 release. For more details, you can see [this blog](https://podman.io/blogs/2020/01/17/podman-new-api.html). ## Static Binary Builds diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go index a74363684..87bb947ed 100644 --- a/cmd/podman/system/prune.go +++ b/cmd/podman/system/prune.go @@ -11,8 +11,9 @@ import ( "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/cmd/podman/utils" "github.com/containers/podman/v2/cmd/podman/validate" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" + "github.com/docker/go-units" "github.com/spf13/cobra" ) @@ -80,7 +81,7 @@ Are you sure you want to continue? [y/N] `, volumeString) } } - pruneOptions.Filters, err = lpfilters.ParseFilterArgumentsIntoFilters(filters) + pruneOptions.Filters, err = dfilters.ParseFilterArgumentsIntoFilters(filters) if err != nil { return err } @@ -90,7 +91,7 @@ Are you sure you want to continue? [y/N] `, volumeString) return err } // Print container prune results - err = utils.PrintContainerPruneResults(response.ContainerPruneReport, true) + err = utils.PrintContainerPruneResults(response.ContainerPruneReports, true) if err != nil { return err } @@ -101,11 +102,17 @@ Are you sure you want to continue? [y/N] `, volumeString) } // Print Volume prune results if pruneOptions.Volume { - err = utils.PrintVolumePruneResults(response.VolumePruneReport, true) + err = utils.PrintVolumePruneResults(response.VolumePruneReports, true) if err != nil { return err } } // Print Images prune results - return utils.PrintImagePruneResults(response.ImagePruneReport, true) + err = utils.PrintImagePruneResults(response.ImagePruneReports, true) + if err != nil { + return err + } + + fmt.Printf("Total reclaimed space: %s\n", units.HumanSize((float64)(response.ReclaimedSpace))) + return nil } diff --git a/cmd/podman/utils/utils.go b/cmd/podman/utils/utils.go index 2ca2c4c92..f42243f69 100644 --- a/cmd/podman/utils/utils.go +++ b/cmd/podman/utils/utils.go @@ -5,6 +5,7 @@ import ( "os" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" ) // IsDir returns true if the specified path refers to a directory. @@ -41,21 +42,21 @@ func PrintPodPruneResults(podPruneReports []*entities.PodPruneReport, heading bo return errs.PrintErrors() } -func PrintContainerPruneResults(containerPruneReport *entities.ContainerPruneReport, heading bool) error { +func PrintContainerPruneResults(containerPruneReports []*reports.PruneReport, heading bool) error { var errs OutputErrors - if heading && (len(containerPruneReport.ID) > 0 || len(containerPruneReport.Err) > 0) { + if heading && (len(containerPruneReports) > 0) { fmt.Println("Deleted Containers") } - for k := range containerPruneReport.ID { - fmt.Println(k) - } - for _, v := range containerPruneReport.Err { - errs = append(errs, v) + for _, v := range containerPruneReports { + fmt.Println(v.Id) + if v.Err != nil { + errs = append(errs, v.Err) + } } return errs.PrintErrors() } -func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, heading bool) error { +func PrintVolumePruneResults(volumePruneReport []*reports.PruneReport, heading bool) error { var errs OutputErrors if heading && len(volumePruneReport) > 0 { fmt.Println("Deleted Volumes") @@ -70,18 +71,16 @@ func PrintVolumePruneResults(volumePruneReport []*entities.VolumePruneReport, he return errs.PrintErrors() } -func PrintImagePruneResults(imagePruneReport *entities.ImagePruneReport, heading bool) error { - if heading && (len(imagePruneReport.Report.Id) > 0 || len(imagePruneReport.Report.Err) > 0) { +func PrintImagePruneResults(imagePruneReports []*reports.PruneReport, heading bool) error { + if heading { fmt.Println("Deleted Images") } - for _, i := range imagePruneReport.Report.Id { - fmt.Println(i) - } - for _, e := range imagePruneReport.Report.Err { - fmt.Fprint(os.Stderr, e.Error()+"\n") - } - if imagePruneReport.Size > 0 { - fmt.Fprintf(os.Stdout, "Size: %d\n", imagePruneReport.Size) + for _, r := range imagePruneReports { + fmt.Println(r.Id) + if r.Err != nil { + fmt.Fprint(os.Stderr, r.Err.Error()+"\n") + } } + return nil } diff --git a/docs/source/_static/api.html b/docs/source/_static/api.html index 8b9d66e0d..11fbb85a0 100644 --- a/docs/source/_static/api.html +++ b/docs/source/_static/api.html @@ -18,7 +18,7 @@ </style> </head> <body> - <redoc spec-url='https://storage.googleapis.com/libpod-master-releases/swagger-latest-master.yaml'></redoc> + <redoc spec-url='https://storage.googleapis.com/libpod-master-releases/swagger-latest-master.yaml' sort-props-alphabetically></redoc> <script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script> </body> </html> @@ -14,7 +14,7 @@ require ( github.com/containers/common v0.31.2 github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.9.0 - github.com/containers/psgo v1.5.1 + github.com/containers/psgo v1.5.2 github.com/containers/storage v1.24.4 github.com/coreos/go-systemd/v22 v22.1.0 github.com/cri-o/ocicni v0.2.1-0.20201125151022-df072ea5421c @@ -29,7 +29,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/godbus/dbus/v5 v5.0.3 github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf - github.com/google/uuid v1.1.2 + github.com/google/uuid v1.1.3 github.com/gorilla/mux v1.8.0 github.com/gorilla/schema v1.2.0 github.com/hashicorp/go-multierror v1.1.0 @@ -114,8 +114,8 @@ github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDpl github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.0.3 h1:vYgl+RZ9Q3DPMuTfxmN+qp0X2Bj52uuY2vnt6GzVe1c= github.com/containers/ocicrypt v1.0.3/go.mod h1:CUBa+8MRNL/VkpxYIpaMtgn1WgXGyvPQj8jcy0EVG6g= -github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA= -github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= +github.com/containers/psgo v1.5.2 h1:3aoozst/GIwsrr/5jnFy3FrJay98uujPCu9lTuSZ/Cw= +github.com/containers/psgo v1.5.2/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= github.com/containers/storage v1.23.7/go.mod h1:cUT2zHjtx+WlVri30obWmM2gpqpi8jfPsmIzP1TVpEI= github.com/containers/storage v1.24.1/go.mod h1:0xJL06Dmd+ZYXIUdnBUPN0JnhHGgwMkLvnnAonJfWJU= github.com/containers/storage v1.24.3 h1:8UB4S62l4hrU6Yw3dbsLCJtLg7Ofo39IN2HdckBIX4E= @@ -266,6 +266,8 @@ github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.3 h1:twObb+9XcuH5B9V1TBCvvvZoO6iEdILi2a76PYn5rJI= +github.com/google/uuid v1.1.3/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 05b149e03..cefe12209 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -529,14 +529,37 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { } } + // Hostname handling: + // If we have a UTS namespace, set Hostname in the OCI spec. + // Set the HOSTNAME environment variable unless explicitly overridden by + // the user (already present in OCI spec). If we don't have a UTS ns, + // set it to the host's hostname instead. + hostname := c.Hostname() + foundUTS := false for _, i := range c.config.Spec.Linux.Namespaces { if i.Type == spec.UTSNamespace && i.Path == "" { - hostname := c.Hostname() + foundUTS = true g.SetHostname(hostname) - g.AddProcessEnv("HOSTNAME", hostname) break } } + if !foundUTS { + tmpHostname, err := os.Hostname() + if err != nil { + return nil, err + } + hostname = tmpHostname + } + needEnv := true + for _, checkEnv := range g.Config.Process.Env { + if strings.SplitN(checkEnv, "=", 2)[0] == "HOSTNAME" { + needEnv = false + break + } + } + if needEnv { + g.AddProcessEnv("HOSTNAME", hostname) + } if c.config.UTSNsCtr != "" { if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil { diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index 71c638017..8b7e448b1 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -84,7 +84,11 @@ func (e EventJournalD) Read(ctx context.Context, options ReadOptions) error { 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 { @@ -112,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(): diff --git a/libpod/filters/helpers.go b/libpod/filters/helpers.go deleted file mode 100644 index 859db3a9a..000000000 --- a/libpod/filters/helpers.go +++ /dev/null @@ -1,20 +0,0 @@ -package lpfilters - -import ( - "net/url" - "strings" - - "github.com/pkg/errors" -) - -func ParseFilterArgumentsIntoFilters(filters []string) (url.Values, error) { - parsedFilters := make(url.Values) - for _, f := range filters { - t := strings.SplitN(f, "=", 2) - if len(t) < 2 { - return parsedFilters, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) - } - parsedFilters.Add(t[0], t[1]) - } - return parsedFilters, nil -} 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/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/utils.go b/libpod/image/utils.go index 727c73a71..5e7fed5c6 100644 --- a/libpod/image/utils.go +++ b/libpod/image/utils.go @@ -45,7 +45,8 @@ func findImageInRepotags(search imageParts, images []*Image) (*storage.Image, er } } if len(candidates) == 0 { - return nil, errors.Errorf("unable to find a name and tag match for %s in repotags", searchName) + + 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 diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go index 863e82efd..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 } 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 c99086b33..e7cb5a802 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -193,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 { @@ -1185,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 } @@ -1212,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 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_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 3e4185db1..dd957527d 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -159,6 +159,34 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, rawIm g.AddMount(devPts) } + // Add default sysctls from containers.conf + defaultSysctls, err := util.ValidateSysctls(r.config.Sysctls()) + if err != nil { + return nil, err + } + for sysctlKey, sysctlVal := range defaultSysctls { + // Ignore mqueue sysctls if not sharing IPC + if !p.config.UsePodIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") { + logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace for pod is unused", sysctlKey, sysctlVal) + + continue + } + + // Ignore net sysctls if host network or not sharing network + if (p.config.InfraContainer.HostNetwork || !p.config.UsePodNet) && strings.HasPrefix(sysctlKey, "net.") { + logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace for pod is unused", sysctlKey, sysctlVal) + continue + } + + // Ignore uts sysctls if not sharing UTS + if !p.config.UsePodUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { + logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace for pod is unused", sysctlKey, sysctlVal) + continue + } + + g.AddLinuxSysctl(sysctlKey, sysctlVal) + } + containerName := p.ID()[:IDTruncLength] + "-infra" options = append(options, r.WithPod(p)) options = append(options, WithRootFSFromImage(imgID, imgName, rawImageName)) diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go index 10c32a119..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, filterFuncs []VolumeFilter) (map[string]error, error) { - reports := make(map[string]error) +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/util.go b/libpod/util.go index 8faf665e7..bf9bf2542 100644 --- a/libpod/util.go +++ b/libpod/util.go @@ -153,6 +153,10 @@ func queryPackageVersion(cmdArg ...string) string { 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) } @@ -172,7 +176,10 @@ func packageVersion(program string) string { if out := dpkgVersion(program); out != unknownPackage { return out } - return pacmanVersion(program) + if out := pacmanVersion(program); out != unknownPackage { + return out + } + return equeryVersion(program) } func programVersion(mountProgram string) (string, error) { 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 diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json index 8e001f6b2..d304de536 100644 --- a/nix/nixpkgs.json +++ b/nix/nixpkgs.json @@ -1,9 +1,9 @@ { "url": "https://github.com/nixos/nixpkgs", - "rev": "6ea2fd15d881006b41ea5bbed0f76bffcd85f9f9", - "date": "2020-12-20T13:26:58+10:00", - "path": "/nix/store/kyw1ackbp9qh1jzlzwmjvi5i3541ym5z-nixpkgs", - "sha256": "0kgqmw4ki10b37530jh912sn49x3gay5cnmfr8yz2yp8nvkrk236", + "rev": "4a75203f0270f96cbc87f5dfa5d5185690237d87", + "date": "2020-12-29T03:18:48+01:00", + "path": "/nix/store/scswsm6r4jnhp9ki0f6s81kpj5x6jkn7-nixpkgs", + "sha256": "0h70fm9aa7s06wkalbadw70z5rscbs3p6nblb47z523nhlzgjxk9", "fetchSubmodules": false, "deepClone": false, "leaveDotGit": false diff --git a/pkg/api/handlers/compat/containers.go b/pkg/api/handlers/compat/containers.go index 7a3e5dd84..0f89c859e 100644 --- a/pkg/api/handlers/compat/containers.go +++ b/pkg/api/handlers/compat/containers.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "sort" "strconv" "strings" "syscall" @@ -13,6 +14,8 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/api/handlers/utils" + "github.com/containers/podman/v2/pkg/domain/filters" + "github.com/containers/podman/v2/pkg/ps" "github.com/containers/podman/v2/pkg/signal" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -78,10 +81,6 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) { } func ListContainers(w http.ResponseWriter, r *http.Request) { - var ( - containers []*libpod.Container - err error - ) runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { @@ -97,22 +96,48 @@ func ListContainers(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusBadRequest, errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } - if query.All { - containers, err = runtime.GetAllContainers() - } else { - containers, err = runtime.GetRunningContainers() + + filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters)) + all := query.All || query.Limit > 0 + if len(query.Filters) > 0 { + for k, v := range query.Filters { + generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) + if err != nil { + utils.InternalServerError(w, err) + return + } + filterFuncs = append(filterFuncs, generatedFunc) + } } + + // Docker thinks that if status is given as an input, then we should override + // the all setting and always deal with all containers. + if len(query.Filters["status"]) > 0 { + all = true + } + if !all { + runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime) + if err != nil { + utils.InternalServerError(w, err) + return + } + filterFuncs = append(filterFuncs, runningOnly) + } + + containers, err := runtime.GetContainers(filterFuncs...) if err != nil { utils.InternalServerError(w, err) return } if _, found := r.URL.Query()["limit"]; found && query.Limit > 0 { - last := query.Limit - if len(containers) > last { - containers = containers[len(containers)-last:] + // Sort the libpod containers + sort.Sort(ps.SortCreateTime{SortContainers: containers}) + // we should perform the lopping before we start getting + // the expensive information on containers + if len(containers) > query.Limit { + containers = containers[:query.Limit] } } - // TODO filters still need to be applied var list = make([]*handlers.Container, len(containers)) for i, ctnr := range containers { api, err := LibpodToContainer(ctnr, query.Size) diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go index 2cfeebcce..b3d26b8f4 100644 --- a/pkg/api/handlers/compat/containers_prune.go +++ b/pkg/api/handlers/compat/containers_prune.go @@ -4,19 +4,14 @@ import ( "net/http" "github.com/containers/podman/v2/libpod" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/api/handlers/utils" - "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/docker/docker/api/types" + "github.com/containers/podman/v2/pkg/domain/entities/reports" + "github.com/containers/podman/v2/pkg/domain/filters" "github.com/gorilla/schema" "github.com/pkg/errors" ) func PruneContainers(w http.ResponseWriter, r *http.Request) { - var ( - delContainers []string - space int64 - ) runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) @@ -29,7 +24,7 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) { } filterFuncs := make([]libpod.ContainerFilter, 0, len(query.Filters)) for k, v := range query.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime) + generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { utils.InternalServerError(w, err) return @@ -49,36 +44,21 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) { return } - prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs) + report, err := runtime.PruneContainers(filterFuncs) if err != nil { utils.InternalServerError(w, err) return } - for ctrID, size := range prunedContainers { - if pruneErrors[ctrID] == nil { - space += size - delContainers = append(delContainers, ctrID) - } - } - report := types.ContainersPruneReport{ - ContainersDeleted: delContainers, - SpaceReclaimed: uint64(space), - } utils.WriteResponse(w, http.StatusOK, report) } func PruneContainersHelper(w http.ResponseWriter, r *http.Request, filterFuncs []libpod.ContainerFilter) ( - *entities.ContainerPruneReport, error) { + []*reports.PruneReport, error) { runtime := r.Context().Value("runtime").(*libpod.Runtime) - prunedContainers, pruneErrors, err := runtime.PruneContainers(filterFuncs) + reports, err := runtime.PruneContainers(filterFuncs) if err != nil { utils.InternalServerError(w, err) return nil, err } - - report := &entities.ContainerPruneReport{ - Err: pruneErrors, - ID: prunedContainers, - } - return report, nil + return reports, nil } diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index dc72500e4..9d7503aba 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -99,21 +99,23 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { filters = append(filters, fmt.Sprintf("%s=%s", k, val)) } } - pruneCids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters) + imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, filters) if err != nil { utils.InternalServerError(w, err) return } - for _, p := range pruneCids { + reclaimedSpace := uint64(0) + for _, p := range imagePruneReports { idr = append(idr, types.ImageDeleteResponseItem{ - Deleted: p, + Deleted: p.Id, }) + reclaimedSpace = reclaimedSpace + p.Size } // FIXME/TODO to do this exactly correct, pruneimages needs to return idrs and space-reclaimed, then we are golden ipr := types.ImagesPruneReport{ ImagesDeleted: idr, - SpaceReclaimed: 1, // TODO we cannot supply this right now + SpaceReclaimed: reclaimedSpace, } utils.WriteResponse(w, http.StatusOK, handlers.ImagesPruneReport{ImagesPruneReport: ipr}) } diff --git a/pkg/api/handlers/compat/resize.go b/pkg/api/handlers/compat/resize.go index bdc051d73..cc8c6ef0a 100644 --- a/pkg/api/handlers/compat/resize.go +++ b/pkg/api/handlers/compat/resize.go @@ -20,8 +20,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) { // /containers/{id}/resize query := struct { - height uint16 `schema:"h"` - width uint16 `schema:"w"` + Height uint16 `schema:"h"` + Width uint16 `schema:"w"` }{ // override any golang type defaults } @@ -33,8 +33,8 @@ func ResizeTTY(w http.ResponseWriter, r *http.Request) { } sz := remotecommand.TerminalSize{ - Width: query.width, - Height: query.height, + Width: query.Width, + Height: query.Height, } var status int diff --git a/pkg/api/handlers/compat/volumes.go b/pkg/api/handlers/compat/volumes.go index f49f06b17..1188d8f84 100644 --- a/pkg/api/handlers/compat/volumes.go +++ b/pkg/api/handlers/compat/volumes.go @@ -269,9 +269,9 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) { return } prunedIds := make([]string, 0, len(pruned)) - for k := range pruned { + for _, v := range pruned { // XXX: This drops any pruning per-volume error messages on the floor - prunedIds = append(prunedIds, k) + prunedIds = append(prunedIds, v.Id) } pruneResponse := docker_api_types.VolumesPruneReport{ VolumesDeleted: prunedIds, diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 0b8712f16..979a8adc4 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -156,12 +156,12 @@ func PruneImages(w http.ResponseWriter, r *http.Request) { } } - cids, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters) + imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, libpodFilters) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) return } - utils.WriteResponse(w, http.StatusOK, cids) + utils.WriteResponse(w, http.StatusOK, imagePruneReports) } func ExportImage(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index 5e2727e95..bacba006d 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -115,10 +115,10 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { } } - writer := channel.NewWriter(make(chan []byte, 1)) + writer := channel.NewWriter(make(chan []byte)) defer writer.Close() - stderr := channel.NewWriter(make(chan []byte, 1)) + stderr := channel.NewWriter(make(chan []byte)) defer stderr.Close() images := make([]string, 0, len(imagesToPull)) diff --git a/pkg/api/handlers/libpod/system.go b/pkg/api/handlers/libpod/system.go index b157dfc7b..130e563ae 100644 --- a/pkg/api/handlers/libpod/system.go +++ b/pkg/api/handlers/libpod/system.go @@ -38,35 +38,28 @@ func SystemPrune(w http.ResponseWriter, r *http.Request) { systemPruneReport.PodPruneReport = podPruneReport // We could parallelize this, should we? - containerPruneReport, err := compat.PruneContainersHelper(w, r, nil) + containerPruneReports, err := compat.PruneContainersHelper(w, r, nil) if err != nil { utils.InternalServerError(w, err) return } - systemPruneReport.ContainerPruneReport = containerPruneReport + systemPruneReport.ContainerPruneReports = containerPruneReports - results, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil) + imagePruneReports, err := runtime.ImageRuntime().PruneImages(r.Context(), query.All, nil) if err != nil { utils.InternalServerError(w, err) return } - report := entities.ImagePruneReport{ - Report: entities.Report{ - Id: results, - Err: nil, - }, - } - - systemPruneReport.ImagePruneReport = &report + systemPruneReport.ImagePruneReports = imagePruneReports if query.Volumes { - volumePruneReport, err := pruneVolumesHelper(r) + volumePruneReports, err := pruneVolumesHelper(r) if err != nil { utils.InternalServerError(w, err) return } - systemPruneReport.VolumePruneReport = volumePruneReport + systemPruneReport.VolumePruneReports = volumePruneReports } utils.WriteResponse(w, http.StatusOK, systemPruneReport) } diff --git a/pkg/api/handlers/libpod/volumes.go b/pkg/api/handlers/libpod/volumes.go index b02a6a8ce..6f9537515 100644 --- a/pkg/api/handlers/libpod/volumes.go +++ b/pkg/api/handlers/libpod/volumes.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/domain/infra/abi/parse" "github.com/gorilla/schema" @@ -178,7 +179,7 @@ func PruneVolumes(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, reports) } -func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) { +func pruneVolumesHelper(r *http.Request) ([]*reports.PruneReport, error) { var ( runtime = r.Context().Value("runtime").(*libpod.Runtime) decoder = r.Context().Value("decoder").(*schema.Decoder) @@ -199,17 +200,10 @@ func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) return nil, err } - pruned, err := runtime.PruneVolumes(r.Context(), filterFuncs) + reports, err := runtime.PruneVolumes(r.Context(), filterFuncs) if err != nil { return nil, err } - reports := make([]*entities.VolumePruneReport, 0, len(pruned)) - for k, v := range pruned { - reports = append(reports, &entities.VolumePruneReport{ - Err: v, - Id: k, - }) - } return reports, nil } func RemoveVolume(w http.ResponseWriter, r *http.Request) { diff --git a/pkg/api/handlers/utils/pods.go b/pkg/api/handlers/utils/pods.go index 7506dbfd1..0fe3a308b 100644 --- a/pkg/api/handlers/utils/pods.go +++ b/pkg/api/handlers/utils/pods.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/containers/podman/v2/libpod" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/gorilla/schema" ) @@ -31,7 +31,7 @@ func GetPods(w http.ResponseWriter, r *http.Request) ([]*entities.ListPodsReport filters := make([]libpod.PodFilter, 0, len(query.Filters)) for k, v := range query.Filters { - f, err := lpfilters.GeneratePodFilterFunc(k, v) + f, err := dfilters.GeneratePodFilterFunc(k, v) if err != nil { return nil, err } diff --git a/pkg/api/server/swagger.go b/pkg/api/server/swagger.go index 6d349bb7d..45253e01a 100644 --- a/pkg/api/server/swagger.go +++ b/pkg/api/server/swagger.go @@ -4,6 +4,7 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" ) // No such image @@ -170,7 +171,7 @@ type ok struct { // swagger:response VolumePruneResponse type swagVolumePruneResponse struct { // in:body - Body []entities.VolumePruneReport + Body []reports.PruneReport } // Volume create response diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 650aa9ac5..1081a0e61 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -12,6 +12,7 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -49,11 +50,11 @@ func List(ctx context.Context, options *ListOptions) ([]entities.ListContainer, // used for more granular selection of containers. The main error returned indicates if there were runtime // errors like finding containers. Errors specific to the removal of a container are in the PruneContainerResponse // structure. -func Prune(ctx context.Context, options *PruneOptions) (*entities.ContainerPruneReport, error) { +func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) { if options == nil { options = new(PruneOptions) } - var reports *entities.ContainerPruneReport + var reports []*reports.PruneReport conn, err := bindings.GetClient(ctx) if err != nil { return nil, err diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index 9beb493c8..ecdd1f553 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -12,6 +12,7 @@ import ( "github.com/containers/podman/v2/pkg/auth" "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/pkg/errors" ) @@ -163,9 +164,9 @@ func Export(ctx context.Context, nameOrIDs []string, w io.Writer, options *Expor // Prune removes unused images from local storage. The optional filters can be used to further // define which images should be pruned. -func Prune(ctx context.Context, options *PruneOptions) ([]string, error) { +func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) { var ( - deleted []string + deleted []*reports.PruneReport ) if options == nil { options = new(PruneOptions) @@ -182,7 +183,8 @@ func Prune(ctx context.Context, options *PruneOptions) ([]string, error) { if err != nil { return deleted, err } - return deleted, response.Process(&deleted) + err = response.Process(&deleted) + return deleted, err } // Tag adds an additional name to locally-stored image. Both the tag and repo parameters are required. diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 2ab5e45d0..fa601e7e5 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -8,6 +8,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings/containers" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/specgen" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -533,8 +534,8 @@ var _ = Describe("Podman containers ", func() { // Prune container should return no errors and one pruned container ID. pruneResponse, err := containers.Prune(bt.conn, nil) Expect(err).To(BeNil()) - Expect(len(pruneResponse.Err)).To(Equal(0)) - Expect(len(pruneResponse.ID)).To(Equal(1)) + Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0)) + Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1)) }) It("podman prune stopped containers with filters", func() { @@ -558,8 +559,8 @@ var _ = Describe("Podman containers ", func() { } pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filtersIncorrect)) Expect(err).To(BeNil()) - Expect(len(pruneResponse.Err)).To(Equal(0)) - Expect(len(pruneResponse.ID)).To(Equal(0)) + Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(0)) + Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0)) // Valid filter params container should be pruned now. filters := map[string][]string{ @@ -567,8 +568,8 @@ var _ = Describe("Podman containers ", func() { } pruneResponse, err = containers.Prune(bt.conn, new(containers.PruneOptions).WithFilters(filters)) Expect(err).To(BeNil()) - Expect(len(pruneResponse.Err)).To(Equal(0)) - Expect(len(pruneResponse.ID)).To(Equal(1)) + Expect(len(reports.PruneReportsErrs(pruneResponse))).To(Equal(0)) + Expect(len(reports.PruneReportsIds(pruneResponse))).To(Equal(1)) }) It("podman prune running containers", func() { @@ -585,7 +586,7 @@ var _ = Describe("Podman containers ", func() { // Prune. Should return no error no prune response ID. pruneResponse, err := containers.Prune(bt.conn, nil) Expect(err).To(BeNil()) - Expect(len(pruneResponse.ID)).To(Equal(0)) + Expect(len(pruneResponse)).To(Equal(0)) }) It("podman inspect bogus container", func() { diff --git a/pkg/bindings/test/images_test.go b/pkg/bindings/test/images_test.go index e178f4219..c6b9c20f9 100644 --- a/pkg/bindings/test/images_test.go +++ b/pkg/bindings/test/images_test.go @@ -9,6 +9,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/bindings/images" + dreports "github.com/containers/podman/v2/pkg/domain/entities/reports" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -355,7 +356,7 @@ var _ = Describe("Podman images", func() { results, err := images.Prune(bt.conn, options) Expect(err).NotTo(HaveOccurred()) Expect(len(results)).To(BeNumerically(">", 0)) - Expect(results).To(ContainElement("docker.io/library/alpine:latest")) + Expect(dreports.PruneReportsIds(results)).To(ContainElement("docker.io/library/alpine:latest")) }) // TODO: we really need to extent to pull tests once we have a more sophisticated CI. diff --git a/pkg/bindings/test/system_test.go b/pkg/bindings/test/system_test.go index 25fda5575..44067b61d 100644 --- a/pkg/bindings/test/system_test.go +++ b/pkg/bindings/test/system_test.go @@ -10,6 +10,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings/system" "github.com/containers/podman/v2/pkg/bindings/volumes" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -80,12 +81,12 @@ var _ = Describe("Podman system", func() { systemPruneResponse, err := system.Prune(bt.conn, options) Expect(err).To(BeNil()) Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1)) - Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1)) - Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)). + Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1)) + Expect(len(systemPruneResponse.ImagePruneReports)). To(BeNumerically(">", 0)) - Expect(systemPruneResponse.ImagePruneReport.Report.Id). + Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)). To(ContainElement("docker.io/library/alpine:latest")) - Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0)) + Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0)) }) It("podman system prune running alpine container", func() { @@ -114,14 +115,14 @@ var _ = Describe("Podman system", func() { systemPruneResponse, err := system.Prune(bt.conn, options) Expect(err).To(BeNil()) Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(1)) - Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1)) - Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)). + Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1)) + Expect(len(systemPruneResponse.ImagePruneReports)). To(BeNumerically(">", 0)) // Alpine image should not be pruned as used by running container - Expect(systemPruneResponse.ImagePruneReport.Report.Id). + Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)). ToNot(ContainElement("docker.io/library/alpine:latest")) // Though unused volume is available it should not be pruned as flag set to false. - Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0)) + Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0)) }) It("podman system prune running alpine container volume prune", func() { @@ -149,14 +150,14 @@ var _ = Describe("Podman system", func() { systemPruneResponse, err := system.Prune(bt.conn, options) Expect(err).To(BeNil()) Expect(len(systemPruneResponse.PodPruneReport)).To(Equal(0)) - Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1)) - Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)). + Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1)) + Expect(len(systemPruneResponse.ImagePruneReports)). To(BeNumerically(">", 0)) // Alpine image should not be pruned as used by running container - Expect(systemPruneResponse.ImagePruneReport.Report.Id). + Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)). ToNot(ContainElement("docker.io/library/alpine:latest")) // Volume should be pruned now as flag set true - Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1)) + Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1)) }) It("podman system prune running alpine container volume prune --filter", func() { @@ -197,14 +198,14 @@ var _ = Describe("Podman system", func() { // This check **should** be "Equal(0)" since we are passing label // filters however the Prune function doesn't seem to pass filters // to each component. - Expect(len(systemPruneResponse.ContainerPruneReport.ID)).To(Equal(1)) - Expect(len(systemPruneResponse.ImagePruneReport.Report.Id)). + Expect(len(systemPruneResponse.ContainerPruneReports)).To(Equal(1)) + Expect(len(systemPruneResponse.ImagePruneReports)). To(BeNumerically(">", 0)) // Alpine image should not be pruned as used by running container - Expect(systemPruneResponse.ImagePruneReport.Report.Id). + Expect(reports.PruneReportsIds(systemPruneResponse.ImagePruneReports)). ToNot(ContainElement("docker.io/library/alpine:latest")) // Volume shouldn't be pruned because the PruneOptions filters doesn't match - Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(0)) + Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(0)) // Fix filter and re prune f["label"] = []string{"label1=value1"} @@ -213,6 +214,6 @@ var _ = Describe("Podman system", func() { Expect(err).To(BeNil()) // Volume should be pruned because the PruneOptions filters now match - Expect(len(systemPruneResponse.VolumePruneReport)).To(Equal(1)) + Expect(len(systemPruneResponse.VolumePruneReports)).To(Equal(1)) }) }) diff --git a/pkg/bindings/test/volumes_test.go b/pkg/bindings/test/volumes_test.go index e0d854b66..1f1da3cfa 100644 --- a/pkg/bindings/test/volumes_test.go +++ b/pkg/bindings/test/volumes_test.go @@ -10,6 +10,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/bindings/volumes" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -166,7 +167,7 @@ var _ = Describe("Podman volumes", func() { session.Wait(45) vols, err = volumes.Prune(connText, nil) Expect(err).To(BeNil()) - Expect(len(vols)).To(BeNumerically("==", 1)) + Expect(len(reports.PruneReportsIds(vols))).To(BeNumerically("==", 1)) _, err = volumes.Inspect(connText, "homer", nil) Expect(err).To(BeNil()) diff --git a/pkg/bindings/volumes/volumes.go b/pkg/bindings/volumes/volumes.go index 626f52d39..fe081eb46 100644 --- a/pkg/bindings/volumes/volumes.go +++ b/pkg/bindings/volumes/volumes.go @@ -7,6 +7,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" jsoniter "github.com/json-iterator/go" ) @@ -77,9 +78,9 @@ func List(ctx context.Context, options *ListOptions) ([]*entities.VolumeListRepo } // Prune removes unused volumes from the local filesystem. -func Prune(ctx context.Context, options *PruneOptions) ([]*entities.VolumePruneReport, error) { +func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport, error) { var ( - pruned []*entities.VolumePruneReport + pruned []*reports.PruneReport ) conn, err := bindings.GetClient(ctx) if err != nil { diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index b8d49d067..05b9b774e 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -390,13 +390,6 @@ type ContainerPruneOptions struct { Filters url.Values `json:"filters" schema:"filters"` } -// ContainerPruneReport describes the results after pruning the -// stopped containers. -type ContainerPruneReport struct { - ID map[string]int64 - Err map[string]error -} - // ContainerPortOptions describes the options to obtain // port information on containers type ContainerPortOptions struct { diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 80127ea45..7d38a97f2 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -6,6 +6,7 @@ import ( "github.com/containers/common/pkg/config" "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/specgen" "github.com/spf13/cobra" ) @@ -35,7 +36,7 @@ type ContainerEngine interface { ContainerMount(ctx context.Context, nameOrIDs []string, options ContainerMountOptions) ([]*ContainerMountReport, error) ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) ContainerPort(ctx context.Context, nameOrID string, options ContainerPortOptions) ([]*ContainerPortReport, error) - ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error) + ContainerPrune(ctx context.Context, options ContainerPruneOptions) ([]*reports.PruneReport, error) ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error) ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) @@ -85,6 +86,6 @@ type ContainerEngine interface { VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error) VolumeInspect(ctx context.Context, namesOrIds []string, opts InspectOptions) ([]*VolumeInspectReport, []error, error) VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error) - VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*VolumePruneReport, error) + VolumePrune(ctx context.Context, options VolumePruneOptions) ([]*reports.PruneReport, error) VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error) } diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index 7f33d8e9d..26a136f13 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -4,6 +4,7 @@ import ( "context" "github.com/containers/common/pkg/config" + "github.com/containers/podman/v2/pkg/domain/entities/reports" ) type ImageEngine interface { @@ -17,7 +18,7 @@ type ImageEngine interface { List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error) Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error) Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error) - Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error) + Prune(ctx context.Context, opts ImagePruneOptions) ([]*reports.PruneReport, error) Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error) Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error) diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 67910a34c..d5f88502a 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -247,11 +247,6 @@ type ImagePruneOptions struct { Filter []string `json:"filter" schema:"filter"` } -type ImagePruneReport struct { - Report Report - Size int64 -} - type ImageTagOptions struct{} type ImageUntagOptions struct{} diff --git a/pkg/domain/entities/reports/prune.go b/pkg/domain/entities/reports/prune.go new file mode 100644 index 000000000..5494ac3ae --- /dev/null +++ b/pkg/domain/entities/reports/prune.go @@ -0,0 +1,40 @@ +package reports + +type PruneReport struct { + Id string //nolint + Err error + Size uint64 +} + +func PruneReportsIds(r []*PruneReport) []string { + ids := make([]string, 0, len(r)) + for _, v := range r { + if v == nil || v.Id == "" { + continue + } + ids = append(ids, v.Id) + } + return ids +} + +func PruneReportsErrs(r []*PruneReport) []error { + errs := make([]error, 0, len(r)) + for _, v := range r { + if v == nil || v.Err == nil { + continue + } + errs = append(errs, v.Err) + } + return errs +} + +func PruneReportsSize(r []*PruneReport) uint64 { + size := uint64(0) + for _, v := range r { + if v == nil { + continue + } + size = size + v.Size + } + return size +} diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index d5118f6a8..99fa947f0 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -4,6 +4,7 @@ import ( "time" "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/docker/docker/api/types" "github.com/spf13/cobra" ) @@ -24,10 +25,11 @@ type SystemPruneOptions struct { // SystemPruneReport provides report after system prune is executed. type SystemPruneReport struct { - PodPruneReport []*PodPruneReport - *ContainerPruneReport - *ImagePruneReport - VolumePruneReport []*VolumePruneReport + PodPruneReport []*PodPruneReport + ContainerPruneReports []*reports.PruneReport + ImagePruneReports []*reports.PruneReport + VolumePruneReports []*reports.PruneReport + ReclaimedSpace uint64 } // SystemMigrateOptions describes the options needed for the diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go index e6b29e374..06438f5e9 100644 --- a/pkg/domain/entities/volumes.go +++ b/pkg/domain/entities/volumes.go @@ -116,11 +116,6 @@ type VolumePruneOptions struct { Filters url.Values `json:"filters" schema:"filters"` } -type VolumePruneReport struct { - Err error - Id string //nolint -} - type VolumeListOptions struct { Filter map[string][]string } diff --git a/libpod/filters/containers.go b/pkg/domain/filters/containers.go index 505429de6..ce6c12b71 100644 --- a/libpod/filters/containers.go +++ b/pkg/domain/filters/containers.go @@ -1,4 +1,4 @@ -package lpfilters +package filters import ( "strconv" @@ -233,7 +233,6 @@ func GenerateContainerFilterFuncs(filter string, filterValues []string, r *libpo } return false }, nil - } return nil, errors.Errorf("%s is an invalid filter", filter) } diff --git a/libpod/filters/pods.go b/pkg/domain/filters/pods.go index 17b3f3ca9..7e6b7f2cc 100644 --- a/libpod/filters/pods.go +++ b/pkg/domain/filters/pods.go @@ -1,4 +1,4 @@ -package lpfilters +package filters import ( "strconv" diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index efb4f866f..9d7c2daea 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -16,12 +16,13 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/libpod/events" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/libpod/logs" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/checkpoint" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/domain/infra/abi/terminal" parallelctr "github.com/containers/podman/v2/pkg/parallel/ctr" "github.com/containers/podman/v2/pkg/ps" @@ -204,28 +205,16 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin return reports, nil } -func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { +func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) ([]*reports.PruneReport, error) { filterFuncs := make([]libpod.ContainerFilter, 0, len(options.Filters)) for k, v := range options.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) + generatedFunc, err := dfilters.GenerateContainerFilterFuncs(k, v, ic.Libpod) if err != nil { return nil, err } filterFuncs = append(filterFuncs, generatedFunc) } - return ic.pruneContainersHelper(filterFuncs) -} - -func (ic *ContainerEngine) pruneContainersHelper(filterFuncs []libpod.ContainerFilter) (*entities.ContainerPruneReport, error) { - prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs) - if err != nil { - return nil, err - } - report := entities.ContainerPruneReport{ - ID: prunedContainers, - Err: pruneErrors, - } - return &report, nil + return ic.Libpod.PruneContainers(filterFuncs) } func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 394ba359c..19f081abb 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -24,6 +24,7 @@ import ( "github.com/containers/podman/v2/libpod/image" libpodImage "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" domainUtils "github.com/containers/podman/v2/pkg/domain/utils" "github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/util" @@ -49,19 +50,12 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo return &entities.BoolReport{Value: err == nil}, nil } -func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) { - results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter) +func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) { + reports, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter) if err != nil { return nil, err } - - report := entities.ImagePruneReport{ - Report: entities.Report{ - Id: results, - Err: nil, - }, - } - return &report, nil + return reports, err } func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) { diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 4135e8882..cbc74a2f2 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -226,7 +226,19 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, err } - specGen, err := kube.ToSpecGen(ctx, container, container.Image, newImage, volumes, pod.ID(), podName, podInfraID, configMaps, seccompPaths, ctrRestartPolicy, p.NetNS.IsHost()) + specgenOpts := kube.CtrSpecGenOptions{ + Container: container, + Image: newImage, + Volumes: volumes, + PodID: pod.ID(), + PodName: podName, + PodInfraID: podInfraID, + ConfigMaps: configMaps, + SeccompPaths: seccompPaths, + RestartPolicy: ctrRestartPolicy, + NetNSIsHost: p.NetNS.IsHost(), + } + specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 11374e513..f108b770c 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -5,8 +5,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + dfilters "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/signal" "github.com/containers/podman/v2/pkg/specgen" "github.com/containers/podman/v2/pkg/specgen/generate" @@ -288,7 +288,7 @@ func (ic *ContainerEngine) PodPs(ctx context.Context, options entities.PodPSOpti filters := make([]libpod.PodFilter, 0, len(options.Filters)) for k, v := range options.Filters { - f, err := lpfilters.GeneratePodFilterFunc(k, v) + f, err := dfilters.GeneratePodFilterFunc(k, v) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 5f6c95d4f..67c018122 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -16,6 +16,7 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/util" "github.com/containers/podman/v2/utils" @@ -170,6 +171,7 @@ func checkInput() error { // nolint:deadcode,unused func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) { var systemPruneReport = new(entities.SystemPruneReport) var filters []string + reclaimedSpace := (uint64)(0) found := true for found { found = false @@ -186,42 +188,26 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys containerPruneOptions := entities.ContainerPruneOptions{} containerPruneOptions.Filters = (url.Values)(options.Filters) - containerPruneReport, err := ic.ContainerPrune(ctx, containerPruneOptions) + containerPruneReports, err := ic.ContainerPrune(ctx, containerPruneOptions) if err != nil { return nil, err } - if len(containerPruneReport.ID) > 0 { - found = true - } - if systemPruneReport.ContainerPruneReport == nil { - systemPruneReport.ContainerPruneReport = containerPruneReport - } else { - for name, val := range containerPruneReport.ID { - systemPruneReport.ContainerPruneReport.ID[name] = val - } - } + reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(containerPruneReports) + systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...) for k, v := range options.Filters { filters = append(filters, fmt.Sprintf("%s=%s", k, v[0])) } - results, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters) + imagePruneReports, err := ic.Libpod.ImageRuntime().PruneImages(ctx, options.All, filters) + reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(imagePruneReports) if err != nil { return nil, err } - if len(results) > 0 { + if len(imagePruneReports) > 0 { found = true } - if systemPruneReport.ImagePruneReport == nil { - systemPruneReport.ImagePruneReport = &entities.ImagePruneReport{ - Report: entities.Report{ - Id: results, - Err: nil, - }, - } - } else { - systemPruneReport.ImagePruneReport.Report.Id = append(systemPruneReport.ImagePruneReport.Report.Id, results...) - } + systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...) if options.Volume { volumePruneOptions := entities.VolumePruneOptions{} volumePruneOptions.Filters = (url.Values)(options.Filters) @@ -232,9 +218,11 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys if len(volumePruneReport) > 0 { found = true } - systemPruneReport.VolumePruneReport = append(systemPruneReport.VolumePruneReport, volumePruneReport...) + reclaimedSpace = reclaimedSpace + reports.PruneReportsSize(volumePruneReport) + systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...) } } + systemPruneReport.ReclaimedSpace = reclaimedSpace return systemPruneReport, nil } diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go index 515e52754..3c9dd9fc0 100644 --- a/pkg/domain/infra/abi/volumes.go +++ b/pkg/domain/infra/abi/volumes.go @@ -6,6 +6,7 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/domain/filters" "github.com/containers/podman/v2/pkg/domain/infra/abi/parse" "github.com/pkg/errors" @@ -127,7 +128,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin return reports, errs, nil } -func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) { +func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.VolumePruneOptions) ([]*reports.PruneReport, error) { filterFuncs, err := filters.GenerateVolumeFilters(options.Filters) if err != nil { return nil, err @@ -135,19 +136,12 @@ func (ic *ContainerEngine) VolumePrune(ctx context.Context, options entities.Vol return ic.pruneVolumesHelper(ctx, filterFuncs) } -func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*entities.VolumePruneReport, error) { +func (ic *ContainerEngine) pruneVolumesHelper(ctx context.Context, filterFuncs []libpod.VolumeFilter) ([]*reports.PruneReport, error) { pruned, err := ic.Libpod.PruneVolumes(ctx, filterFuncs) if err != nil { return nil, err } - reports := make([]*entities.VolumePruneReport, 0, len(pruned)) - for k, v := range pruned { - reports = append(reports, &entities.VolumePruneReport{ - Err: v, - Id: k, - }) - } - return reports, nil + return pruned, nil } func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) { diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 0db985dff..3366cb425 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -18,6 +18,7 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/errorhandling" "github.com/containers/podman/v2/pkg/specgen" "github.com/containers/podman/v2/pkg/util" @@ -196,7 +197,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, return reports, nil } -func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { +func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) { options := new(containers.PruneOptions).WithFilters(opts.Filters) return containers.Prune(ic.ClientCtx, options) } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 10bf9682c..fba60235e 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -16,6 +16,7 @@ import ( "github.com/containers/image/v5/docker/reference" images "github.com/containers/podman/v2/pkg/bindings/images" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/containers/podman/v2/pkg/domain/utils" utils2 "github.com/containers/podman/v2/utils" "github.com/pkg/errors" @@ -90,26 +91,18 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti return &history, nil } -func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) { +func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) ([]*reports.PruneReport, error) { filters := make(map[string][]string, len(opts.Filter)) for _, filter := range opts.Filter { f := strings.Split(filter, "=") filters[f[0]] = f[1:] } options := new(images.PruneOptions).WithAll(opts.All).WithFilters(filters) - results, err := images.Prune(ir.ClientCtx, options) + reports, err := images.Prune(ir.ClientCtx, options) if err != nil { return nil, err } - - report := entities.ImagePruneReport{ - Report: entities.Report{ - Id: results, - Err: nil, - }, - Size: 0, - } - return &report, nil + return reports, nil } func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.ImagePullOptions) (*entities.ImagePullReport, error) { diff --git a/pkg/domain/infra/tunnel/volumes.go b/pkg/domain/infra/tunnel/volumes.go index e6ad4e0c5..10e8d7da8 100644 --- a/pkg/domain/infra/tunnel/volumes.go +++ b/pkg/domain/infra/tunnel/volumes.go @@ -5,6 +5,7 @@ import ( "github.com/containers/podman/v2/pkg/bindings/volumes" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/entities/reports" "github.com/pkg/errors" ) @@ -69,7 +70,7 @@ func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []strin return reports, errs, nil } -func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) { +func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*reports.PruneReport, error) { options := new(volumes.PruneOptions).WithFilters(opts.Filters) return volumes.Prune(ic.ClientCtx, options) } diff --git a/pkg/ps/ps.go b/pkg/ps/ps.go index 6c26e8708..9e0dcb728 100644 --- a/pkg/ps/ps.go +++ b/pkg/ps/ps.go @@ -11,8 +11,8 @@ import ( "github.com/containers/podman/v2/libpod" "github.com/containers/podman/v2/libpod/define" - lpfilters "github.com/containers/podman/v2/libpod/filters" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/domain/filters" psdefine "github.com/containers/podman/v2/pkg/ps/define" "github.com/containers/storage" "github.com/pkg/errors" @@ -27,7 +27,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp all := options.All || options.Last > 0 if len(options.Filters) > 0 { for k, v := range options.Filters { - generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, v, runtime) + generatedFunc, err := filters.GenerateContainerFilterFuncs(k, v, runtime) if err != nil { return nil, err } @@ -41,7 +41,7 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp all = true } if !all { - runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime) + runningOnly, err := filters.GenerateContainerFilterFuncs("status", []string{define.ContainerStateRunning.String()}, runtime) if err != nil { return nil, err } diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index b5956029e..e5b09dcd8 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -47,30 +47,53 @@ func ToPodGen(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec) return p, nil } -func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newImage *image.Image, volumes map[string]*KubeVolume, podID, podName, infraID string, configMaps []v1.ConfigMap, seccompPaths *KubeSeccompPaths, restartPolicy string, hostNet bool) (*specgen.SpecGenerator, error) { - s := specgen.NewSpecGenerator(iid, false) +type CtrSpecGenOptions struct { + // Container as read from the pod yaml + Container v1.Container + // Image available to use (pulled or found local) + Image *image.Image + // Volumes for all containers + Volumes map[string]*KubeVolume + // PodID of the parent pod + PodID string + // PodName of the parent pod + PodName string + // PodInfraID as the infrastructure container id + PodInfraID string + // ConfigMaps the configuration maps for environment variables + ConfigMaps []v1.ConfigMap + // SeccompPaths for finding the seccomp profile path + SeccompPaths *KubeSeccompPaths + // RestartPolicy defines the restart policy of the container + RestartPolicy string + // NetNSIsHost tells the container to use the host netns + NetNSIsHost bool +} + +func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) { + s := specgen.NewSpecGenerator(opts.Container.Image, false) - // podName should be non-empty for Deployment objects to be able to create + // pod name should be non-empty for Deployment objects to be able to create // multiple pods having containers with unique names - if len(podName) < 1 { - return nil, errors.Errorf("kubeContainerToCreateConfig got empty podName") + if len(opts.PodName) < 1 { + return nil, errors.Errorf("got empty pod name on container creation when playing kube") } - s.Name = fmt.Sprintf("%s-%s", podName, containerYAML.Name) + s.Name = fmt.Sprintf("%s-%s", opts.PodName, opts.Container.Name) - s.Terminal = containerYAML.TTY + s.Terminal = opts.Container.TTY - s.Pod = podID + s.Pod = opts.PodID - setupSecurityContext(s, containerYAML) + setupSecurityContext(s, opts.Container) // Since we prefix the container name with pod name to work-around the uniqueness requirement, // the seccomp profile should reference the actual container name from the YAML // but apply to the containers with the prefixed name - s.SeccompProfilePath = seccompPaths.FindForContainer(containerYAML.Name) + s.SeccompProfilePath = opts.SeccompPaths.FindForContainer(opts.Container.Name) s.ResourceLimits = &spec.LinuxResources{} - milliCPU, err := quantityToInt64(containerYAML.Resources.Limits.Cpu()) + milliCPU, err := quantityToInt64(opts.Container.Resources.Limits.Cpu()) if err != nil { return nil, errors.Wrap(err, "Failed to set CPU quota") } @@ -82,12 +105,12 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI } } - limit, err := quantityToInt64(containerYAML.Resources.Limits.Memory()) + limit, err := quantityToInt64(opts.Container.Resources.Limits.Memory()) if err != nil { return nil, errors.Wrap(err, "Failed to set memory limit") } - memoryRes, err := quantityToInt64(containerYAML.Resources.Requests.Memory()) + memoryRes, err := quantityToInt64(opts.Container.Resources.Requests.Memory()) if err != nil { return nil, errors.Wrap(err, "Failed to set memory reservation") } @@ -107,7 +130,7 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI // TODO: We don't understand why specgen does not take of this, but // integration tests clearly pointed out that it was required. s.Command = []string{} - imageData, err := newImage.Inspect(ctx) + imageData, err := opts.Image.Inspect(ctx) if err != nil { return nil, err } @@ -134,26 +157,26 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI } } // If only the yaml.Command is specified, set it as the entrypoint and drop the image Cmd - if len(containerYAML.Command) != 0 { - entrypoint = containerYAML.Command + if len(opts.Container.Command) != 0 { + entrypoint = opts.Container.Command cmd = []string{} } // Only override the cmd field if yaml.Args is specified // Keep the image entrypoint, or the yaml.command if specified - if len(containerYAML.Args) != 0 { - cmd = containerYAML.Args + if len(opts.Container.Args) != 0 { + cmd = opts.Container.Args } s.Command = append(entrypoint, cmd...) // FIXME, // we are currently ignoring imageData.Config.ExposedPorts - if containerYAML.WorkingDir != "" { - s.WorkDir = containerYAML.WorkingDir + if opts.Container.WorkingDir != "" { + s.WorkDir = opts.Container.WorkingDir } annotations := make(map[string]string) - if infraID != "" { - annotations[ann.SandboxID] = infraID + if opts.PodInfraID != "" { + annotations[ann.SandboxID] = opts.PodInfraID annotations[ann.ContainerType] = ann.ContainerTypeContainer } s.Annotations = annotations @@ -165,13 +188,13 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI envs[keyval[0]] = keyval[1] } - for _, env := range containerYAML.Env { - value := envVarValue(env, configMaps) + for _, env := range opts.Container.Env { + value := envVarValue(env, opts.ConfigMaps) envs[env.Name] = value } - for _, envFrom := range containerYAML.EnvFrom { - cmEnvs := envVarsFromConfigMap(envFrom, configMaps) + for _, envFrom := range opts.Container.EnvFrom { + cmEnvs := envVarsFromConfigMap(envFrom, opts.ConfigMaps) for k, v := range cmEnvs { envs[k] = v @@ -179,8 +202,8 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI } s.Env = envs - for _, volume := range containerYAML.VolumeMounts { - volumeSource, exists := volumes[volume.Name] + for _, volume := range opts.Container.VolumeMounts { + volumeSource, exists := opts.Volumes[volume.Name] if !exists { return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) } @@ -212,9 +235,9 @@ func ToSpecGen(ctx context.Context, containerYAML v1.Container, iid string, newI } } - s.RestartPolicy = restartPolicy + s.RestartPolicy = opts.RestartPolicy - if hostNet { + if opts.NetNSIsHost { s.NetNS.NSMode = specgen.Host } diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index 036c7b7a1..3cd5a3c9c 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -364,7 +364,9 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt // namespaces? g.SetHostname(hostname) } - g.AddProcessEnv("HOSTNAME", hostname) + if _, ok := s.Env["HOSTNAME"]; !ok && s.Hostname != "" { + g.AddProcessEnv("HOSTNAME", hostname) + } // User switch s.UserNS.NSMode { diff --git a/pkg/specgen/generate/security.go b/pkg/specgen/generate/security.go index 0c97dc496..9fceec7b3 100644 --- a/pkg/specgen/generate/security.go +++ b/pkg/specgen/generate/security.go @@ -172,12 +172,16 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, // Clear default Seccomp profile from Generator for unconfined containers // and privileged containers which do not specify a seccomp profile. - if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) { + if s.SeccompProfilePath == "unconfined" || (s.Privileged && (s.SeccompProfilePath == "" || s.SeccompProfilePath == config.SeccompOverridePath || s.SeccompProfilePath == config.SeccompDefaultPath)) { configSpec.Linux.Seccomp = nil } g.SetRootReadonly(s.ReadOnlyFilesystem) + noUseIPC := s.IpcNS.NSMode == specgen.FromContainer || s.IpcNS.NSMode == specgen.FromPod || s.IpcNS.NSMode == specgen.Host + noUseNet := s.NetNS.NSMode == specgen.FromContainer || s.NetNS.NSMode == specgen.FromPod || s.NetNS.NSMode == specgen.Host + noUseUTS := s.UtsNS.NSMode == specgen.FromContainer || s.UtsNS.NSMode == specgen.FromPod || s.UtsNS.NSMode == specgen.Host + // Add default sysctls defaultSysctls, err := util.ValidateSysctls(rtc.Sysctls()) if err != nil { @@ -186,20 +190,20 @@ func securityConfigureGenerator(s *specgen.SpecGenerator, g *generate.Generator, for sysctlKey, sysctlVal := range defaultSysctls { // Ignore mqueue sysctls if --ipc=host - if s.IpcNS.IsHost() && strings.HasPrefix(sysctlKey, "fs.mqueue.") { + if noUseIPC && strings.HasPrefix(sysctlKey, "fs.mqueue.") { logrus.Infof("Sysctl %s=%s ignored in containers.conf, since IPC Namespace set to host", sysctlKey, sysctlVal) continue } // Ignore net sysctls if --net=host - if s.NetNS.IsHost() && strings.HasPrefix(sysctlKey, "net.") { + if noUseNet && strings.HasPrefix(sysctlKey, "net.") { logrus.Infof("Sysctl %s=%s ignored in containers.conf, since Network Namespace set to host", sysctlKey, sysctlVal) continue } // Ignore uts sysctls if --uts=host - if s.UtsNS.IsHost() && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { + if noUseUTS && (strings.HasPrefix(sysctlKey, "kernel.domainname") || strings.HasPrefix(sysctlKey, "kernel.hostname")) { logrus.Infof("Sysctl %s=%s ignored in containers.conf, since UTS Namespace set to host", sysctlKey, sysctlVal) continue } diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index 52a214883..fb921cd72 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -11,6 +11,11 @@ import ( // is set to the unit's (unique) name. const EnvVariable = "PODMAN_SYSTEMD_UNIT" +// minTimeoutStopSec is the minimal stop timeout for generated systemd units. +// Once exceeded, processes of the services are killed and the cgroup(s) are +// cleaned up. +const minTimeoutStopSec = 60 + // RestartPolicies includes all valid restart policies to be used in a unit // file. var RestartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"} diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index d84125fc7..cfa02dc9d 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -55,6 +55,8 @@ type containerInfo struct { ExecStartPre string // ExecStart of the unit. ExecStart string + // TimeoutStopSec of the unit. + TimeoutStopSec uint // ExecStop of the unit. ExecStop string // ExecStopPost of the unit. @@ -74,6 +76,7 @@ After={{- range $index, $value := .BoundToServices -}}{{if $index}} {{end}}{{ $v [Service] Environment={{.EnvVariable}}=%n Restart={{.RestartPolicy}} +TimeoutStopSec={{.TimeoutStopSec}} {{- if .ExecStartPre}} ExecStartPre={{.ExecStartPre}} {{- end}} @@ -81,7 +84,6 @@ ExecStart={{.ExecStart}} ExecStop={{.ExecStop}} ExecStopPost={{.ExecStopPost}} PIDFile={{.PIDFile}} -KillMode=none Type=forking [Install] @@ -255,6 +257,8 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst info.ExecStopPost = "{{.Executable}} rm --ignore -f --cidfile {{.ContainerIDFile}}" } + info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout + if info.PodmanVersion == "" { info.PodmanVersion = version.Version.String() } diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index d27062ef3..b9fb8fee6 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/stretchr/testify/assert" ) func TestValidateRestartPolicyContainer(t *testing.T) { @@ -48,11 +49,11 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=82 ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 -ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 -ExecStopPost=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 +ExecStop=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 +ExecStopPost=/usr/bin/podman stop -t 22 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid -KillMode=none Type=forking [Install] @@ -71,11 +72,11 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStart=/usr/bin/podman start foobar ExecStop=/usr/bin/podman stop -t 10 foobar ExecStopPost=/usr/bin/podman stop -t 10 foobar PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid -KillMode=none Type=forking [Install] @@ -96,11 +97,11 @@ After=a.service b.service c.service pod.service [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStart=/usr/bin/podman start foobar ExecStop=/usr/bin/podman stop -t 10 foobar ExecStopPost=/usr/bin/podman stop -t 10 foobar PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid -KillMode=none Type=forking [Install] @@ -119,12 +120,12 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon -d --replace --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN "foo=arg \"with \" space" -ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42 +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id PIDFile=%t/jadda-jadda.pid -KillMode=none Type=forking [Install] @@ -143,12 +144,12 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN -ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42 +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id PIDFile=%t/jadda-jadda.pid -KillMode=none Type=forking [Install] @@ -167,12 +168,12 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --pod-id-file /tmp/pod-foobar.pod-id-file --replace -d --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN -ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42 +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id PIDFile=%t/jadda-jadda.pid -KillMode=none Type=forking [Install] @@ -191,12 +192,12 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/jadda-jadda.pid %t/jadda-jadda.ctr-id ExecStart=/usr/bin/podman run --conmon-pidfile %t/jadda-jadda.pid --cidfile %t/jadda-jadda.ctr-id --cgroups=no-conmon --replace --detach --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN -ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 42 +ExecStop=/usr/bin/podman stop --ignore --cidfile %t/jadda-jadda.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/jadda-jadda.ctr-id PIDFile=%t/jadda-jadda.pid -KillMode=none Type=forking [Install] @@ -215,12 +216,12 @@ After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id ExecStart=/usr/bin/podman run --conmon-pidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id --cgroups=no-conmon -d awesome-image:latest ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.ctr-id PIDFile=%t/container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid -KillMode=none Type=forking [Install] @@ -242,7 +243,7 @@ WantedBy=multi-user.target default.target ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 10, + StopTimeout: 22, PodmanVersion: "CI", EnvVariable: EnvVariable, }, @@ -302,7 +303,7 @@ WantedBy=multi-user.target default.target ContainerNameOrID: "jadda-jadda", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 42, + StopTimeout: 10, PodmanVersion: "CI", CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN", "foo=arg \"with \" space"}, EnvVariable: EnvVariable, @@ -318,7 +319,7 @@ WantedBy=multi-user.target default.target ContainerNameOrID: "jadda-jadda", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 42, + StopTimeout: 10, PodmanVersion: "CI", CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"}, EnvVariable: EnvVariable, @@ -334,7 +335,7 @@ WantedBy=multi-user.target default.target ContainerNameOrID: "jadda-jadda", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 42, + StopTimeout: 10, PodmanVersion: "CI", CreateCommand: []string{"I'll get stripped", "container", "run", "-d", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"}, EnvVariable: EnvVariable, @@ -353,7 +354,7 @@ WantedBy=multi-user.target default.target ContainerNameOrID: "jadda-jadda", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 42, + StopTimeout: 10, PodmanVersion: "CI", CreateCommand: []string{"I'll get stripped", "container", "run", "--detach", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"}, EnvVariable: EnvVariable, @@ -390,9 +391,7 @@ WantedBy=multi-user.target default.target t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr) return } - if got != test.want { - t.Errorf("CreateContainerSystemdUnit() = \n%v\n---------> want\n%v", got, test.want) - } + assert.Equal(t, test.want, got) }) } } diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index 3c57b03fb..fc582e42a 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -60,6 +60,8 @@ type podInfo struct { ExecStartPre2 string // ExecStart of the unit. ExecStart string + // TimeoutStopSec of the unit. + TimeoutStopSec uint // ExecStop of the unit. ExecStop string // ExecStopPost of the unit. @@ -72,6 +74,7 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ [Service] Environment={{.EnvVariable}}=%n Restart={{.RestartPolicy}} +TimeoutStopSec={{.TimeoutStopSec}} {{- if .ExecStartPre1}} ExecStartPre={{.ExecStartPre1}} {{- end}} @@ -82,7 +85,6 @@ ExecStart={{.ExecStart}} ExecStop={{.ExecStop}} ExecStopPost={{.ExecStopPost}} PIDFile={{.PIDFile}} -KillMode=none Type=forking [Install] @@ -298,6 +300,8 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) info.ExecStop = "{{.Executable}} pod stop --ignore --pod-id-file {{.PodIDFile}} {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}}" info.ExecStopPost = "{{.Executable}} pod rm --ignore -f --pod-id-file {{.PodIDFile}}" } + info.TimeoutStopSec = minTimeoutStopSec + info.StopTimeout + if info.PodmanVersion == "" { info.PodmanVersion = version.Version.String() } diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 7f1f63b7e..6d925ecd2 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/stretchr/testify/assert" ) func TestValidateRestartPolicyPod(t *testing.T) { @@ -50,11 +51,11 @@ Before=container-1.service container-2.service [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always +TimeoutStopSec=102 ExecStart=/usr/bin/podman start jadda-jadda-infra -ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra -ExecStopPost=/usr/bin/podman stop -t 10 jadda-jadda-infra +ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra +ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid -KillMode=none Type=forking [Install] @@ -75,13 +76,13 @@ Before=container-1.service container-2.service [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure +TimeoutStopSec=70 ExecStartPre=/bin/rm -f %t/pod-123abc.pid %t/pod-123abc.pod-id ExecStartPre=/usr/bin/podman pod create --infra-conmon-pidfile %t/pod-123abc.pid --pod-id-file %t/pod-123abc.pod-id --name foo "bar=arg with space" --replace ExecStart=/usr/bin/podman pod start --pod-id-file %t/pod-123abc.pod-id ExecStop=/usr/bin/podman pod stop --ignore --pod-id-file %t/pod-123abc.pod-id -t 10 ExecStopPost=/usr/bin/podman pod rm --ignore -f --pod-id-file %t/pod-123abc.pod-id PIDFile=%t/pod-123abc.pid -KillMode=none Type=forking [Install] @@ -102,7 +103,7 @@ WantedBy=multi-user.target default.target InfraNameOrID: "jadda-jadda-infra", RestartPolicy: "always", PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", - StopTimeout: 10, + StopTimeout: 42, PodmanVersion: "CI", RequiredServices: []string{"container-1", "container-2"}, }, @@ -139,9 +140,7 @@ WantedBy=multi-user.target default.target t.Errorf("CreatePodSystemdUnit() error = \n%v, wantErr \n%v", err, test.wantErr) return } - if got != test.want { - t.Errorf("CreatePodSystemdUnit() = \n%v\n---------> want\n%v", got, test.want) - } + assert.Equal(t, test.want, got) }) } } diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at index bc6efc20d..decdc4754 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -203,6 +203,15 @@ t GET 'containers/json?limit=0&all=1' 200 \ .[0].Id~[0-9a-f]\\{64\\} \ .[1].Id~[0-9a-f]\\{64\\} +t GET containers/json?limit=2 200 length=2 + +# Filter with two ids should return both container +t GET "containers/json?filters=%7B%22id%22%3A%5B%22${cid}%22%2C%22${cid_top}%22%5D%7D&all=1" 200 length=2 +# Filter with two ids and status running should return only 1 container +t GET "containers/json?filters=%7B%22id%22%3A%5B%22${cid}%22%2C%22${cid_top}%22%5D%2C%22status%22%3A%5B%22running%22%5D%7D&all=1" 200 \ + length=1 \ + .[0].Id=${cid_top} + t POST containers/${cid_top}/stop "" 204 t DELETE containers/$cid 204 diff --git a/test/apiv2/45-system.at b/test/apiv2/45-system.at index 7d14fd4b3..44cd05a13 100644 --- a/test/apiv2/45-system.at +++ b/test/apiv2/45-system.at @@ -58,10 +58,10 @@ t GET libpod/system/df 200 '.Volumes | length=3' # -G --data-urlencode 'volumes=true&filters={"label":["testlabel1=testonly"]}' # only foo3 should be pruned because of filter -t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo3 +t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1=testonly%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo3 # only foo2 should be pruned because of filter -t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReport[0].Id=foo2 +t POST 'libpod/system/prune?volumes=true&filters=%7B%22label%22:%5B%22testlabel1%22%5D%7D' params='' 200 .VolumePruneReports[0].Id=foo2 # foo1, the last remaining volume should be pruned without any filters applied -t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReport[0].Id=foo1 +t POST 'libpod/system/prune?volumes=true' params='' 200 .VolumePruneReports[0].Id=foo1 # TODO add other system prune tests for pods / images diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go index f61f52589..18737105e 100644 --- a/test/e2e/exec_test.go +++ b/test/e2e/exec_test.go @@ -119,6 +119,21 @@ var _ = Describe("Podman exec", func() { Expect(session.ExitCode()).To(Equal(100)) }) + It("podman exec --privileged", func() { + hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) + Expect(hostCap.ExitCode()).To(Equal(0)) + + setup := podmanTest.RunTopContainer("test-privileged") + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) + }) + It("podman exec terminal doesn't hang", func() { setup := podmanTest.Podman([]string{"run", "-dti", "--name", "test1", fedoraMinimal, "sleep", "+Inf"}) setup.WaitWithDefaultTimeout() diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go index 765844265..3f059300b 100644 --- a/test/e2e/generate_systemd_test.go +++ b/test/e2e/generate_systemd_test.go @@ -74,6 +74,9 @@ var _ = Describe("Podman generate systemd", func() { found, _ := session.GrepString(" stop -t 1234 ") Expect(found).To(BeTrue()) + + found, _ = session.GrepString("TimeoutStopSec=1294") + Expect(found).To(BeTrue()) }) It("podman generate systemd", func() { diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index a034ec2d1..287830102 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -177,8 +177,7 @@ var _ = Describe("Podman pod stats", func() { It("podman stats on net=host post", func() { // --net=host not supported for rootless pods at present - // problem with sysctls being passed to containers of the pod. - SkipIfCgroupV1("Bug: Error: sysctl net.ipv4.ping_group_range is not allowed in the hosts network namespace: OCI runtime error") + SkipIfRootlessCgroupsV1("Pause stats not supported in cgroups v1") podName := "testPod" podCreate := podmanTest.Podman([]string{"pod", "create", "--net=host", "--name", podName}) podCreate.WaitWithDefaultTimeout() diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go index 760de55b6..48f9ea76e 100644 --- a/test/e2e/run_privileged_test.go +++ b/test/e2e/run_privileged_test.go @@ -16,22 +16,22 @@ import ( // know about at compile time. That is: the kernel may have more caps // available than we are aware of, leading to host=FFF... and ctr=3FF... // because the latter is all we request. Accept that. -func containerCapMatchesHost(ctr_cap string, host_cap string) { +func containerCapMatchesHost(ctrCap string, hostCap string) { if isRootless() { return } - ctr_cap_n, err := strconv.ParseUint(ctr_cap, 16, 64) - Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctr_cap) + ctrCap_n, err := strconv.ParseUint(ctrCap, 16, 64) + Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", ctrCap) - host_cap_n, err := strconv.ParseUint(host_cap, 16, 64) - Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", host_cap) + hostCap_n, err := strconv.ParseUint(hostCap, 16, 64) + Expect(err).NotTo(HaveOccurred(), "Error parsing %q as hex", hostCap) // host caps can never be zero (except rootless). // and host caps must always be a superset (inclusive) of container - Expect(host_cap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", host_cap) - Expect(host_cap_n).To(BeNumerically(">=", ctr_cap_n), "host cap %q should never be less than container cap %q", host_cap, ctr_cap) - host_cap_masked := host_cap_n & (1<<len(capability.List()) - 1) - Expect(ctr_cap_n).To(Equal(host_cap_masked), "container cap %q is not a subset of host cap %q", ctr_cap, host_cap) + Expect(hostCap_n).To(BeNumerically(">", 0), "host cap %q should be nonzero", hostCap) + Expect(hostCap_n).To(BeNumerically(">=", ctrCap_n), "host cap %q should never be less than container cap %q", hostCap, ctrCap) + hostCap_masked := hostCap_n & (1<<len(capability.List()) - 1) + Expect(ctrCap_n).To(Equal(hostCap_masked), "container cap %q is not a subset of host cap %q", ctrCap, hostCap) } var _ = Describe("Podman privileged container tests", func() { @@ -68,38 +68,38 @@ var _ = Describe("Podman privileged container tests", func() { }) It("podman privileged CapEff", func() { - host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) - Expect(host_cap.ExitCode()).To(Equal(0)) + hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) + Expect(hostCap.ExitCode()).To(Equal(0)) session := podmanTest.Podman([]string{"run", "--privileged", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString()) + containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) }) It("podman cap-add CapEff", func() { // Get caps of current process - host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) - Expect(host_cap.ExitCode()).To(Equal(0)) + hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) + Expect(hostCap.ExitCode()).To(Equal(0)) session := podmanTest.Podman([]string{"run", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString()) + containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) }) It("podman cap-add CapEff with --user", func() { // Get caps of current process - host_cap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) - Expect(host_cap.ExitCode()).To(Equal(0)) + hostCap := SystemExec("awk", []string{"/^CapEff/ { print $2 }", "/proc/self/status"}) + Expect(hostCap.ExitCode()).To(Equal(0)) session := podmanTest.Podman([]string{"run", "--user=bin", "--cap-add", "all", "busybox", "awk", "/^CapEff/ { print $2 }", "/proc/self/status"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - containerCapMatchesHost(session.OutputToString(), host_cap.OutputToString()) + containerCapMatchesHost(session.OutputToString(), hostCap.OutputToString()) }) It("podman cap-drop CapEff", func() { @@ -110,6 +110,15 @@ var _ = Describe("Podman privileged container tests", func() { Expect("0000000000000000").To(Equal(capEff[1])) }) + It("podman privileged should disable seccomp by default", func() { + hostSeccomp := SystemExec("grep", []string{"-Ei", "^Seccomp:\\s+0$", "/proc/self/status"}) + Expect(hostSeccomp.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "grep", "-Ei", "^Seccomp:\\s+0$", "/proc/self/status"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman non-privileged should have very few devices", func() { session := podmanTest.Podman([]string{"run", "-t", "busybox", "ls", "-l", "/dev"}) session.WaitWithDefaultTimeout() diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 4888a676b..92d7d222e 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -1415,4 +1415,12 @@ WORKDIR /madethis` Expect(session.ExitCode()).To(Equal(0)) Expect(session.ErrorToString()).To(ContainSubstring("Trying to pull")) }) + + It("podman run container with hostname and hostname environment variable", func() { + hostnameEnv := "test123" + session := podmanTest.Podman([]string{"run", "--hostname", "testctr", "--env", fmt.Sprintf("HOSTNAME=%s", hostnameEnv), ALPINE, "printenv", "HOSTNAME"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(hostnameEnv)) + }) }) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 48294943b..49ab3b8ed 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -13,10 +13,10 @@ import ( var _ = Describe("Podman systemd", func() { var ( - tempdir string - err error - podmanTest *PodmanTestIntegration - systemd_unit_file string + tempdir string + err error + podmanTest *PodmanTestIntegration + systemdUnitFile string ) BeforeEach(func() { @@ -27,7 +27,7 @@ var _ = Describe("Podman systemd", func() { podmanTest = PodmanTestCreate(tempdir) podmanTest.Setup() podmanTest.SeedImages() - systemd_unit_file = `[Unit] + systemdUnitFile = `[Unit] Description=redis container [Service] Restart=always @@ -50,7 +50,7 @@ WantedBy=multi-user.target SkipIfRootless("rootless can not write to /etc") SkipIfContainerized("test does not have systemd as pid 1") - sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemd_unit_file), 0644) + sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemdUnitFile), 0644) Expect(sys_file).To(BeNil()) defer func() { stop := SystemExec("bash", []string{"-c", "systemctl stop redis"}) @@ -131,6 +131,21 @@ WantedBy=multi-user.target Expect(conData[0].Config.SystemdMode).To(BeTrue()) }) + It("podman create container with --uidmap and conmon PidFile accessible", func() { + ctrName := "testCtrUidMap" + run := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:1:1000", "--name", ctrName, ALPINE, "top"}) + run.WaitWithDefaultTimeout() + Expect(run.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"inspect", "--format", "{{.ConmonPidFile}}", ctrName}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + pidFile := strings.TrimSuffix(session.OutputToString(), "\n") + _, err := ioutil.ReadFile(pidFile) + Expect(err).To(BeNil()) + }) + It("podman create container with systemd=always triggers systemd mode", func() { ctrName := "testCtr" run := podmanTest.Podman([]string{"create", "--name", ctrName, "--systemd", "always", ALPINE}) diff --git a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go index c46468930..1a60b96c4 100644 --- a/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go +++ b/vendor/github.com/containers/psgo/internal/capabilities/capabilities.go @@ -13,7 +13,7 @@ // limitations under the License. // Package capabilities provides a mapping from common kernel bit masks to the -// alphanumerical represenation of kernel capabilities. See capabilities(7) +// alphanumerical representation of kernel capabilities. See capabilities(7) // for additional information. package capabilities diff --git a/vendor/github.com/containers/psgo/internal/dev/tty.go b/vendor/github.com/containers/psgo/internal/dev/tty.go index b7d6f28ac..863767f75 100644 --- a/vendor/github.com/containers/psgo/internal/dev/tty.go +++ b/vendor/github.com/containers/psgo/internal/dev/tty.go @@ -113,8 +113,9 @@ func TTYs() (*[]TTY, error) { } s := fi.Sys().(*syscall.Stat_t) t := TTY{ - Minor: minDevNum(s.Rdev), - Major: majDevNum(s.Rdev), + // Rdev is type uint32 on mips arch so we have to cast to uint64 + Minor: minDevNum(uint64(s.Rdev)), + Major: majDevNum(uint64(s.Rdev)), Path: dev, } ttys = append(ttys, t) diff --git a/vendor/github.com/containers/psgo/internal/proc/status.go b/vendor/github.com/containers/psgo/internal/proc/status.go index 29d059361..df31139f8 100644 --- a/vendor/github.com/containers/psgo/internal/proc/status.go +++ b/vendor/github.com/containers/psgo/internal/proc/status.go @@ -24,7 +24,7 @@ import ( "github.com/pkg/errors" ) -// Status is a direct translation of a `/proc/[pid]/status`, wich provides much +// Status is a direct translation of a `/proc/[pid]/status`, which provides much // of the information in /proc/[pid]/stat and /proc/[pid]/statm in a format // that's easier for humans to parse. type Status struct { diff --git a/vendor/github.com/containers/psgo/internal/process/process.go b/vendor/github.com/containers/psgo/internal/process/process.go index b46a39f46..a581921d5 100644 --- a/vendor/github.com/containers/psgo/internal/process/process.go +++ b/vendor/github.com/containers/psgo/internal/process/process.go @@ -31,9 +31,9 @@ type Process struct { Pid string // Stat contains data from /proc/$pid/stat. Stat proc.Stat - // Status containes data from /proc/$pid/status. + // Status contains data from /proc/$pid/status. Status proc.Status - // CmdLine containes data from /proc/$pid/cmdline. + // CmdLine contains data from /proc/$pid/cmdline. CmdLine []string // Label containers data from /proc/$pid/attr/current. Label string diff --git a/vendor/github.com/containers/psgo/psgo.go b/vendor/github.com/containers/psgo/psgo.go index c75fc3815..7c74fd716 100644 --- a/vendor/github.com/containers/psgo/psgo.go +++ b/vendor/github.com/containers/psgo/psgo.go @@ -482,7 +482,7 @@ func JoinNamespaceAndProcessInfoByPidsWithOptions(pids []string, descriptors []s // catch race conditions continue } - return nil, errors.Wrapf(err, "error extracing PID namespace") + return nil, errors.Wrapf(err, "error extracting PID namespace") } if _, exists := nsMap[ns]; !exists { nsMap[ns] = true @@ -759,7 +759,7 @@ func processVSZ(p *process.Process, ctx *psContext) (string, error) { } // parseCAP parses cap (a string bit mask) and returns the associated set of -// capabilities. If all capabilties are set, "full" is returned. If no +// capabilities. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func parseCAP(cap string) (string, error) { mask, err := strconv.ParseUint(cap, 16, 64) @@ -777,36 +777,36 @@ func parseCAP(cap string) (string, error) { return strings.Join(caps, ","), nil } -// processCAPAMB returns the set of ambient capabilties associated with -// process p. If all capabilties are set, "full" is returned. If no +// processCAPAMB returns the set of ambient capabilities associated with +// process p. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func processCAPAMB(p *process.Process, ctx *psContext) (string, error) { return parseCAP(p.Status.CapAmb) } -// processCAPINH returns the set of inheritable capabilties associated with -// process p. If all capabilties are set, "full" is returned. If no +// processCAPINH returns the set of inheritable capabilities associated with +// process p. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func processCAPINH(p *process.Process, ctx *psContext) (string, error) { return parseCAP(p.Status.CapInh) } -// processCAPPRM returns the set of permitted capabilties associated with -// process p. If all capabilties are set, "full" is returned. If no +// processCAPPRM returns the set of permitted capabilities associated with +// process p. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func processCAPPRM(p *process.Process, ctx *psContext) (string, error) { return parseCAP(p.Status.CapPrm) } -// processCAPEFF returns the set of effective capabilties associated with -// process p. If all capabilties are set, "full" is returned. If no +// processCAPEFF returns the set of effective capabilities associated with +// process p. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func processCAPEFF(p *process.Process, ctx *psContext) (string, error) { return parseCAP(p.Status.CapEff) } -// processCAPBND returns the set of bounding capabilties associated with -// process p. If all capabilties are set, "full" is returned. If no +// processCAPBND returns the set of bounding capabilities associated with +// process p. If all capabilities are set, "full" is returned. If no // capability is enabled, "none" is returned. func processCAPBND(p *process.Process, ctx *psContext) (string, error) { return parseCAP(p.Status.CapBnd) diff --git a/vendor/github.com/google/uuid/uuid.go b/vendor/github.com/google/uuid/uuid.go index 524404cc5..daf3639c1 100644 --- a/vendor/github.com/google/uuid/uuid.go +++ b/vendor/github.com/google/uuid/uuid.go @@ -35,6 +35,12 @@ const ( var rander = rand.Reader // random function +type invalidLengthError struct{ len int } + +func (err *invalidLengthError) Error() string { + return fmt.Sprintf("invalid UUID length: %d", err.len) +} + // Parse decodes s into a UUID or returns an error. Both the standard UUID // forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the @@ -68,7 +74,7 @@ func Parse(s string) (UUID, error) { } return uuid, nil default: - return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) + return uuid, &invalidLengthError{len(s)} } // s is now at least 36 bytes long // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx @@ -112,7 +118,7 @@ func ParseBytes(b []byte) (UUID, error) { } return uuid, nil default: - return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) + return uuid, &invalidLengthError{len(b)} } // s is now at least 36 bytes long // it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx diff --git a/vendor/modules.txt b/vendor/modules.txt index 9688f84e3..39771fbe8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -163,7 +163,7 @@ github.com/containers/ocicrypt/keywrap/pgp github.com/containers/ocicrypt/keywrap/pkcs7 github.com/containers/ocicrypt/spec github.com/containers/ocicrypt/utils -# github.com/containers/psgo v1.5.1 +# github.com/containers/psgo v1.5.2 github.com/containers/psgo github.com/containers/psgo/internal/capabilities github.com/containers/psgo/internal/cgroups @@ -318,7 +318,7 @@ github.com/golang/protobuf/ptypes/timestamp github.com/google/gofuzz # github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/shlex -# github.com/google/uuid v1.1.2 +# github.com/google/uuid v1.1.3 github.com/google/uuid # github.com/gorilla/mux v1.8.0 github.com/gorilla/mux |