diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | cmd/podman/containers_prune.go | 4 | ||||
-rw-r--r-- | cmd/podmanV2/containers/prune.go | 86 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 2 | ||||
-rwxr-xr-x | hack/swagger-check | 317 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 3 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_prune.go | 13 | ||||
-rw-r--r-- | pkg/api/server/register_containers.go | 12 | ||||
-rw-r--r-- | pkg/api/server/register_images.go | 2 | ||||
-rw-r--r-- | pkg/autoupdate/autoupdate.go | 25 | ||||
-rw-r--r-- | pkg/bindings/containers/containers.go | 10 | ||||
-rw-r--r-- | pkg/bindings/test/containers_test.go | 65 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 16 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 17 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 4 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/config.go | 4 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/containers.conf | 10 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/default.go | 3 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
22 files changed, 568 insertions, 38 deletions
@@ -397,6 +397,10 @@ install-podman-remote-%-docs: podman-remote docs $(MANPAGES) man-page-check: hack/man-page-checker +.PHONY: swagger-check +swagger-check: + hack/swagger-check + .PHONY: codespell codespell: codespell -S bin,vendor,.git,go.sum,changelog.txt,seccomp.json,.cirrus.yml,"*.xz,*.gz,*.tar,*.tgz,bin2img,*ico,*.png,*.1,*.5,copyimg,*.orig,apidoc.go" -L uint,iff,od,seeked,splitted,marge,ERRO,hist -w @@ -624,7 +628,7 @@ validate.completions: completions/bash/podman if [ -x /bin/zsh ]; then /bin/zsh completions/zsh/_podman; fi .PHONY: validate -validate: gofmt lint .gitvalidation validate.completions man-page-check +validate: gofmt lint .gitvalidation validate.completions man-page-check swagger-check .PHONY: build-all-new-commits build-all-new-commits: @@ -5,7 +5,7 @@ Libpod provides a library for applications looking to use the Container Pod concept, popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes. -* [Latest Version: 1.8.2](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 1.9.0](https://github.com/containers/libpod/releases/latest) * [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master) * [GoDoc: ![GoDoc](https://godoc.org/github.com/containers/libpod/libpod?status.svg)](https://godoc.org/github.com/containers/libpod/libpod) * Automated continuous release downloads (including remote-client): diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index cd9817e7e..3953a489d 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -19,12 +19,12 @@ var ( pruneContainersDescription = ` podman container prune - Removes all exited containers + Removes all stopped | exited containers ` _pruneContainersCommand = &cobra.Command{ Use: "prune", Args: noSubArgs, - Short: "Remove all stopped containers", + Short: "Remove all stopped | exited containers", Long: pruneContainersDescription, RunE: func(cmd *cobra.Command, args []string) error { pruneContainersCommand.InputArgs = args diff --git a/cmd/podmanV2/containers/prune.go b/cmd/podmanV2/containers/prune.go new file mode 100644 index 000000000..2d3af5d1d --- /dev/null +++ b/cmd/podmanV2/containers/prune.go @@ -0,0 +1,86 @@ +package containers + +import ( + "bufio" + "context" + "fmt" + "net/url" + "os" + "strings" + + "github.com/containers/libpod/cmd/podmanV2/registry" + "github.com/containers/libpod/cmd/podmanV2/utils" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + pruneDescription = fmt.Sprintf(`podman container prune + + Removes all stopped | exited containers`) + pruneCommand = &cobra.Command{ + Use: "prune [flags]", + Short: "Remove all stopped | exited containers", + Long: pruneDescription, + RunE: prune, + Example: `podman container prune`, + } + force bool + filter = []string{} +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: pruneCommand, + Parent: containerCmd, + }) + flags := pruneCommand.Flags() + flags.BoolVarP(&force, "force", "f", false, "Do not prompt for confirmation. The default is false") + flags.StringArrayVar(&filter, "filter", []string{}, "Provide filter values (e.g. 'label=<key>=<value>')") +} + +func prune(cmd *cobra.Command, args []string) error { + var ( + errs utils.OutputErrors + pruneOptions = entities.ContainerPruneOptions{} + ) + if len(args) > 0 { + return errors.Errorf("`%s` takes no arguments", cmd.CommandPath()) + } + if !force { + reader := bufio.NewReader(os.Stdin) + fmt.Println("WARNING! This will remove all stopped containers.") + fmt.Print("Are you sure you want to continue? [y/N] ") + answer, err := reader.ReadString('\n') + if err != nil { + return errors.Wrapf(err, "error reading input") + } + if strings.ToLower(answer)[0] != 'y' { + return nil + } + } + + // TODO Remove once filter refactor is finished and url.Values done. + for _, f := range filter { + t := strings.SplitN(f, "=", 2) + pruneOptions.Filters = make(url.Values) + if len(t) < 2 { + return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f) + } + pruneOptions.Filters.Add(t[0], t[1]) + } + responses, err := registry.ContainerEngine().ContainerPrune(context.Background(), pruneOptions) + + if err != nil { + return err + } + for k := range responses.ID { + fmt.Println(k) + } + for _, v := range responses.Err { + errs = append(errs, v) + } + return errs.PrintErrors() +} @@ -10,7 +10,7 @@ require ( github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921 github.com/containernetworking/plugins v0.8.5 github.com/containers/buildah v1.14.8 - github.com/containers/common v0.8.1 + github.com/containers/common v0.9.0 github.com/containers/conmon v2.0.14+incompatible github.com/containers/image/v5 v5.4.3 github.com/containers/psgo v1.4.0 @@ -67,6 +67,8 @@ github.com/containers/buildah v1.14.8 h1:JbMI0QSOmyZ30Mr2633uCXAj+Fajgh/EFS9xX/Y github.com/containers/buildah v1.14.8/go.mod h1:ytEjHJQnRXC1ygXMyc0FqYkjcoCydqBQkOdxbH563QU= github.com/containers/common v0.8.1 h1:1IUwAtZ4mC7GYRr4AC23cHf2oXCuoLzTUoSzIkSgnYw= github.com/containers/common v0.8.1/go.mod h1:VxDJbaA1k6N1TNv9Rt6bQEF4hyKVHNfOfGA5L91ADEs= +github.com/containers/common v0.9.0 h1:mN4P8VK6e7lqQSl7oywfEnhMtSzi8DhkE2QaJHJp88w= +github.com/containers/common v0.9.0/go.mod h1:9YGKPwu6NFYQG2NtSP9bRhNGA8mgd1mUCCkOU2tr+Pc= github.com/containers/conmon v2.0.14+incompatible h1:knU1O1QxXy5YxtjMQVKEyCajROaehizK9FHaICl+P5Y= github.com/containers/conmon v2.0.14+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.4.3 h1:zn2HR7uu4hpvT5QQHgjqonOzKDuM1I1UHUEmzZT5sbs= diff --git a/hack/swagger-check b/hack/swagger-check new file mode 100755 index 000000000..d564b6554 --- /dev/null +++ b/hack/swagger-check @@ -0,0 +1,317 @@ +#!/usr/bin/perl +# +# swagger-check - Look for inconsistencies between swagger and source code +# +package LibPod::SwaggerCheck; + +use v5.14; +use strict; +use warnings; + +use File::Find; + +(our $ME = $0) =~ s|.*/||; +(our $VERSION = '$Revision: 1.7 $ ') =~ tr/[0-9].//cd; + +# For debugging, show data structures using DumpTree($var) +#use Data::TreeDumper; $Data::TreeDumper::Displayaddress = 0; + +############################################################################### +# BEGIN user-customizable section + +our $Default_Dir = 'pkg/api/server'; + +# END user-customizable section +############################################################################### + +############################################################################### +# BEGIN boilerplate args checking, usage messages + +sub usage { + print <<"END_USAGE"; +Usage: $ME [OPTIONS] DIRECTORY-TO-CHECK + +$ME scans all .go files under the given DIRECTORY-TO-CHECK +(default: $Default_Dir), looking for lines of the form 'r.Handle(...)' +or 'r.HandleFunc(...)'. For each such line, we check for a preceding +swagger comment line and verify that the comment line matches the +declarations in the r.Handle() invocation. + +For example, the following would be a correctly-matching pair of lines: + + // swagger:operation GET /images/json compat getImages + r.Handle(VersionedPath("/images/json"), s.APIHandler(compat.GetImages)).Methods(http.MethodGet) + +...because http.MethodGet matches GET in the comment, the endpoint +is /images/json in both cases, the APIHandler() says "compat" so +that's the swagger tag, and the swagger operation name is the +same as the APIHandler but with a lower-case first letter. + +The following is an inconsistency as reported by this script: + +pkg/api/server/register_info.go: +- // swagger:operation GET /info libpod libpodGetInfo ++ // ................. ... ..... compat + r.Handle(VersionedPath("/info"), s.APIHandler(compat.GetInfo)).Methods(http.MethodGet) + +...because APIHandler() says 'compat' but the swagger comment +says 'libpod'. + +OPTIONS: + + --pedantic Compare operation names (the last part of swagger comment). + There are far too many of these inconsistencies to allow us + to enable this by default, but it still might be a useful + check in some circumstances. + + -v, --verbose show verbose progress indicators + -n, --dry-run make no actual changes + + --help display this message + --version display program name and version +END_USAGE + + exit; +} + +# Command-line options. Note that this operates directly on @ARGV ! +our $pedantic; +our $debug = 0; +our $force = 0; +our $verbose = 0; +our $NOT = ''; # print "blahing the blah$NOT\n" if $debug +sub handle_opts { + use Getopt::Long; + GetOptions( + 'pedantic' => \$pedantic, + + 'debug!' => \$debug, + 'dry-run|n!' => sub { $NOT = ' [NOT]' }, + 'force' => \$force, + 'verbose|v' => \$verbose, + + help => \&usage, + man => \&man, + version => sub { print "$ME version $VERSION\n"; exit 0 }, + ) or die "Try `$ME --help' for help\n"; +} + +# END boilerplate args checking, usage messages +############################################################################### + +############################## CODE BEGINS HERE ############################### + +my $exit_status = 0; + +# The term is "modulino". +__PACKAGE__->main() unless caller(); + +# Main code. +sub main { + # Note that we operate directly on @ARGV, not on function parameters. + # This is deliberate: it's because Getopt::Long only operates on @ARGV + # and there's no clean way to make it use @_. + handle_opts(); # will set package globals + + # Fetch command-line arguments. Barf if too many. + my $dir = shift(@ARGV) || $Default_Dir; + die "$ME: Too many arguments; try $ME --help\n" if @ARGV; + + # Find and act upon all matching files + find { wanted => sub { finder(@_) }, no_chdir => 1 }, $dir; + + exit $exit_status; +} + + +############ +# finder # File::Find action - looks for 'r.Handle' or 'r.HandleFunc' +############ +sub finder { + my $path = $File::Find::name; + return if $path =~ m|/\.|; # skip dotfiles + return unless $path =~ /\.go$/; # Only want .go files + + print $path, "\n" if $debug; + + # Read each .go file. Keep a running tally of all '// comment' lines; + # if we see a 'r.Handle()' or 'r.HandleFunc()' line, pass it + comments + # to analysis function. + open my $in, '<', $path + or die "$ME: Cannot read $path: $!\n"; + my @comments; + while (my $line = <$in>) { + if ($line =~ m!^\s*//!) { + push @comments, $line; + } + else { + # Not a comment line. If it's an r.Handle*() one, process it. + if ($line =~ m!^\s*r\.Handle(Func)?\(!) { + handle_handle($path, $line, @comments) + or $exit_status = 1; + } + + # Reset comments + @comments = (); + } + } + close $in; +} + + +################### +# handle_handle # Cross-check a 'r.Handle*' declaration against swagger +################### +# +# Returns false if swagger comment is inconsistent with function call, +# true if it matches or if there simply isn't a swagger comment. +# +sub handle_handle { + my $path = shift; # for error messages only + my $line = shift; # in: the r.Handle* line + my @comments = @_; # in: preceding comment lines + + # Preserve the original line, so we can show it in comments + my $line_orig = $line; + + # Strip off the 'r.Handle*(' and leading whitespace; preserve the latter + $line =~ s!^(\s*)r\.Handle(Func)?\(!! + or die "$ME: INTERNAL ERROR! Got '$line'!\n"; + my $indent = $1; + + # Some have VersionedPath, some don't. Doesn't seem to make a difference + # in terms of swagger, so let's just ignore it. + $line =~ s!^VersionedPath\(([^\)]+)\)!$1!; + $line =~ m!^"(/[^"]+)",! + or die "$ME: $path:$.: Cannot grok '$line'\n"; + my $endpoint = $1; + + # FIXME: in older code, '{name:..*}' meant 'nameOrID'. As of 2020-02 + # it looks like most of the '{name:..*}' entries are gone, except for one. +###FIXME-obsolete? $endpoint =~ s|\{name:\.\.\*\}|{nameOrID}|; + + # e.g. /auth, /containers/*/rename, /distribution, /monitor, /plugins + return 1 if $line =~ /\.UnsupportedHandler/; + + # + # Determine the HTTP METHOD (GET, POST, DELETE, HEAD) + # + my $method; + if ($line =~ /generic.VersionHandler/) { + $method = 'GET'; + } + elsif ($line =~ m!\.Methods\((.*)\)!) { + my $x = $1; + + if ($x =~ /Method(Post|Get|Delete|Head)/) { + $method = uc $1; + } + elsif ($x =~ /\"(HEAD|GET|POST)"/) { + $method = $1; + } + else { + die "$ME: $path:$.: Cannot grok $x\n"; + } + } + else { + warn "$ME: $path:$.: No Methods in '$line'\n"; + return 1; + } + + # + # Determine the SWAGGER TAG. Assume 'compat' unless we see libpod; but + # this can be overruled (see special case below) + # + my $tag = ($endpoint =~ /(libpod)/ ? $1 : 'compat'); + + # + # Determine the OPERATION. *** NOTE: This is mostly useless! *** + # In an ideal world the swagger comment would match actual function call; + # in reality there are over thirty mismatches. Use --pedantic to see. + # + my $operation = ''; + if ($line =~ /(generic|handlers|compat)\.(\w+)/) { + $operation = lcfirst $2; + if ($endpoint =~ m!/libpod/! && $operation !~ /^libpod/) { + $operation = 'libpod' . ucfirst $operation; + } + } + elsif ($line =~ /(libpod)\.(\w+)/) { + $operation = "$1$2"; + } + + # Special case: the following endpoints all get a custom tag + if ($endpoint =~ m!/(volumes|pods|manifests)/!) { + $tag = $1; + $operation =~ s/^libpod//; + $operation = lcfirst $operation; + } + + # Special case: anything related to 'events' gets a system tag + if ($endpoint =~ m!/events!) { + $tag = 'system'; + } + + # Special case: /changes is libpod even though it says compat + if ($endpoint =~ m!/changes!) { + $tag = 'libpod'; + } + + state $previous_path; # Previous path name, to avoid dups + + # + # Compare actual swagger comment to what we expect based on Handle call. + # + my $expect = " // swagger:operation $method $endpoint $tag $operation "; + my @actual = grep { /swagger:operation/ } @comments; + + return 1 if !@actual; # No swagger comment in file; oh well + + my $actual = $actual[0]; + + # By default, don't compare the operation: there are far too many + # mismatches here. + if (! $pedantic) { + $actual =~ s/\s+\S+\s*$//; + $expect =~ s/\s+\S+\s*$//; + } + + # (Ignore whitespace discrepancies) + (my $a_trimmed = $actual) =~ s/\s+/ /g; + + return 1 if $a_trimmed eq $expect; + + # Mismatch. Display it. Start with filename, if different from previous + print "\n"; + if (!$previous_path || $previous_path ne $path) { + print $path, ":\n"; + } + $previous_path = $path; + + # Show the actual line, prefixed with '-' ... + print "- $actual[0]"; + # ...then our generated ones, but use '...' as a way to ignore matches + print "+ $indent//"; + my @actual_split = split ' ', $actual; + my @expect_split = split ' ', $expect; + for my $i (1 .. $#actual_split) { + print " "; + if ($actual_split[$i] eq ($expect_split[$i]||'')) { + print "." x length($actual_split[$i]); + } + else { + # Show the difference. Use terminal highlights if available. + print "\e[1;37m" if -t *STDOUT; + print $expect_split[$i]; + print "\e[m" if -t *STDOUT; + } + } + print "\n"; + + # Show the r.Handle* code line itself + print " ", $line_orig; + + return; +} + +1; diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 207ac6477..9d3e69d56 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -887,8 +887,9 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int continue } err = r.RemoveContainer(context.Background(), ctr, false, false) - pruneErrors[ctr.ID()] = err if err != nil { + pruneErrors[ctr.ID()] = err + } else { prunedContainers[ctr.ID()] = size } } diff --git a/pkg/api/handlers/compat/containers_prune.go b/pkg/api/handlers/compat/containers_prune.go index a56c3903d..bf3aecd65 100644 --- a/pkg/api/handlers/compat/containers_prune.go +++ b/pkg/api/handlers/compat/containers_prune.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/containers/libpod/libpod" - "github.com/containers/libpod/pkg/api/handlers" "github.com/containers/libpod/pkg/api/handlers/utils" + "github.com/containers/libpod/pkg/domain/entities" "github.com/docker/docker/api/types" "github.com/gorilla/schema" "github.com/pkg/errors" @@ -40,14 +40,11 @@ func PruneContainers(w http.ResponseWriter, r *http.Request) { // Libpod response differs if utils.IsLibpodRequest(r) { - var response []handlers.LibpodContainersPruneReport - for ctrID, size := range prunedContainers { - response = append(response, handlers.LibpodContainersPruneReport{ID: ctrID, SpaceReclaimed: size}) + report := &entities.ContainerPruneReport{ + Err: pruneErrors, + ID: prunedContainers, } - for ctrID, err := range pruneErrors { - response = append(response, handlers.LibpodContainersPruneReport{ID: ctrID, PruneError: err.Error()}) - } - utils.WriteResponse(w, http.StatusOK, response) + utils.WriteResponse(w, http.StatusOK, report) return } for ctrID, size := range prunedContainers { diff --git a/pkg/api/server/register_containers.go b/pkg/api/server/register_containers.go index 8b9a9e312..378d1e06c 100644 --- a/pkg/api/server/register_containers.go +++ b/pkg/api/server/register_containers.go @@ -955,7 +955,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // "$ref": "#/responses/NoSuchContainer" // 500: // "$ref": "#/responses/InternalError" - r.HandleFunc(VersionedPath("/libpod/containers/{name:..*}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost) + r.HandleFunc(VersionedPath("/libpod/containers/{name}/pause"), s.APIHandler(compat.PauseContainer)).Methods(http.MethodPost) // swagger:operation POST /libpod/containers/{name}/restart libpod libpodRestartContainer // --- // tags: @@ -1282,7 +1282,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/export"), s.APIHandler(compat.ExportContainer)).Methods(http.MethodGet) - // swagger:operation GET /libpod/containers/{name}/checkout libpod libpodCheckpointContainer + // swagger:operation POST /libpod/containers/{name}/checkpoint libpod libpodCheckpointContainer // --- // tags: // - containers @@ -1323,7 +1323,7 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // 500: // $ref: "#/responses/InternalError" r.HandleFunc(VersionedPath("/libpod/containers/{name}/checkpoint"), s.APIHandler(libpod.Checkpoint)).Methods(http.MethodPost) - // swagger:operation GET /libpod/containers/{name} restore libpod libpodRestoreContainer + // swagger:operation POST /libpod/containers/{name}/restore libpod libpodRestoreContainer // --- // tags: // - containers @@ -1407,9 +1407,9 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error { // $ref: "#/responses/NoSuchContainer" // 500: // $ref: "#/responses/InternalError" - r.HandleFunc(VersionedPath("/containers/{name}/changes"), s.APIHandler(compat.Changes)) - r.HandleFunc("/containers/{name}/changes", s.APIHandler(compat.Changes)) - r.HandleFunc(VersionedPath("/libpod/containers/{name}/changes"), s.APIHandler(compat.Changes)) + r.HandleFunc(VersionedPath("/containers/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) + r.HandleFunc("/containers/{name}/changes", s.APIHandler(compat.Changes)).Methods(http.MethodGet) + r.HandleFunc(VersionedPath("/libpod/containers/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) // swagger:operation POST /libpod/containers/{name}/init libpod libpodInitContainer // --- // tags: diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index 7dd887037..6cc6f0cfa 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -1154,7 +1154,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // $ref: "#/responses/NoSuchContainer" // 500: // $ref: "#/responses/InternalError" - r.HandleFunc(VersionedPath("/libpod/images/{name}/changes"), s.APIHandler(compat.Changes)) + r.HandleFunc(VersionedPath("/libpod/images/{name}/changes"), s.APIHandler(compat.Changes)).Methods(http.MethodGet) return nil } diff --git a/pkg/autoupdate/autoupdate.go b/pkg/autoupdate/autoupdate.go index 7c243eb00..78d5ac474 100644 --- a/pkg/autoupdate/autoupdate.go +++ b/pkg/autoupdate/autoupdate.go @@ -201,18 +201,25 @@ func imageContainersMap(runtime *libpod.Runtime) (map[string][]*libpod.Container if state != define.ContainerStateRunning { continue } + // Only update containers with the specific label/policy set. labels := ctr.Labels() - if value, exists := labels[Label]; exists { - policy, err := LookupPolicy(value) - if err != nil { - errors = append(errors, err) - continue - } - if policy != PolicyNewImage { - continue - } + value, exists := labels[Label] + if !exists { + continue } + + policy, err := LookupPolicy(value) + if err != nil { + errors = append(errors, err) + continue + } + + // Skip non-image labels (could be explicitly disabled). + if policy != PolicyNewImage { + continue + } + // Now we know that `ctr` is configured for auto updates. id, _ := ctr.Image() imageMap[id] = append(imageMap[id], allContainers[i]) diff --git a/pkg/bindings/containers/containers.go b/pkg/bindings/containers/containers.go index 963f0ec57..e74a256c7 100644 --- a/pkg/bindings/containers/containers.go +++ b/pkg/bindings/containers/containers.go @@ -60,10 +60,8 @@ func List(ctx context.Context, filters map[string][]string, all *bool, last *int // 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, filters map[string][]string) ([]string, error) { - var ( - pruneResponse []string - ) +func Prune(ctx context.Context, filters map[string][]string) (*entities.ContainerPruneReport, error) { + var reports *entities.ContainerPruneReport conn, err := bindings.GetClient(ctx) if err != nil { return nil, err @@ -78,9 +76,9 @@ func Prune(ctx context.Context, filters map[string][]string) ([]string, error) { } response, err := conn.DoRequest(nil, http.MethodPost, "/containers/prune", params) if err != nil { - return pruneResponse, err + return nil, err } - return pruneResponse, response.Process(pruneResponse) + return reports, response.Process(&reports) } // Remove removes a container from local storage. The force bool designates diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index 0b1b9ecdd..e288dc368 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -531,4 +531,69 @@ var _ = Describe("Podman containers ", func() { Expect(err).ToNot(BeNil()) }) + It("podman prune stoped containers", func() { + // Start and stop a container to enter in exited state. + var name = "top" + _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil) + Expect(err).To(BeNil()) + err = containers.Stop(bt.conn, name, nil) + Expect(err).To(BeNil()) + + // 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)) + }) + + It("podman prune stoped containers with filters", func() { + // Start and stop a container to enter in exited state. + var name = "top" + _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil) + Expect(err).To(BeNil()) + err = containers.Stop(bt.conn, name, nil) + Expect(err).To(BeNil()) + + // Invalid filter keys should return error. + filtersIncorrect := map[string][]string{ + "status": {"dummy"}, + } + pruneResponse, err := containers.Prune(bt.conn, filtersIncorrect) + Expect(err).ToNot(BeNil()) + + // Mismatched filter params no container should be pruned. + filtersIncorrect = map[string][]string{ + "name": {"r"}, + } + pruneResponse, err = containers.Prune(bt.conn, filtersIncorrect) + Expect(err).To(BeNil()) + Expect(len(pruneResponse.Err)).To(Equal(0)) + Expect(len(pruneResponse.ID)).To(Equal(0)) + + // Valid filter params container should be pruned now. + filters := map[string][]string{ + "name": {"top"}, + } + pruneResponse, err = containers.Prune(bt.conn, filters) + Expect(err).To(BeNil()) + Expect(len(pruneResponse.Err)).To(Equal(0)) + Expect(len(pruneResponse.ID)).To(Equal(1)) + }) + + It("podman prune running containers", func() { + // Start the container. + var name = "top" + _, err := bt.RunTopContainer(&name, &bindings.PFalse, nil) + Expect(err).To(BeNil()) + + // Check if the container is running. + data, err := containers.Inspect(bt.conn, name, nil) + Expect(err).To(BeNil()) + Expect(data.State.Status).To(Equal("running")) + + // 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)) + }) }) diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index f21af9ce4..52327a905 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -2,6 +2,7 @@ package entities import ( "io" + "net/url" "os" "time" @@ -260,7 +261,7 @@ type ContainerRunOptions struct { } // ContainerRunReport describes the results of running -//a container +// a container type ContainerRunReport struct { ExitCode int Id string @@ -327,3 +328,16 @@ type ContainerUnmountReport struct { Err error Id string } + +// ContainerPruneOptions describes the options needed +// to prune a container from the CLI +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 +} diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 5fdb9a8a6..c3092a98a 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -13,6 +13,7 @@ type ContainerEngine interface { ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error) ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error) + ContainerPrune(ctx context.Context, options ContainerPruneOptions) (*ContainerPruneReport, error) ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error) ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index f464df3ac..fc62a6c29 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -19,6 +19,7 @@ import ( "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/libpod/logs" + "github.com/containers/libpod/pkg/api/handlers/utils" "github.com/containers/libpod/pkg/checkpoint" "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/infra/abi/terminal" @@ -173,6 +174,22 @@ 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) { + filterFuncs, err := utils.GenerateFilterFuncsFromMap(ic.Libpod, options.Filters) + if err != nil { + return nil, err + } + prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs) + if err != nil { + return nil, err + } + report := entities.ContainerPruneReport{ + ID: prunedContainers, + Err: pruneErrors, + } + return &report, nil +} + func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { var ( reports []*entities.KillReport diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 05b62efcf..679bb371b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -146,6 +146,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, return reports, nil } +func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { + return containers.Prune(ic.ClientCxt, options.Filters) +} + func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) { var ( reports []*entities.ContainerInspectReport diff --git a/vendor/github.com/containers/common/pkg/config/config.go b/vendor/github.com/containers/common/pkg/config/config.go index b65db2722..ef21f1d9f 100644 --- a/vendor/github.com/containers/common/pkg/config/config.go +++ b/vendor/github.com/containers/common/pkg/config/config.go @@ -271,6 +271,10 @@ type EngineConfig struct { // running containers without CGroups. RuntimeSupportsNoCgroups []string `toml:"runtime_supports_nocgroupv2"` + // RuntimeSupportsKVM is a list of OCI runtimes that support + // KVM separation for conatainers. + RuntimeSupportsKVM []string `toml:"runtime_supports_kvm"` + // SetOptions contains a subset of config options. It's used to indicate if // a given option has either been set by the user or by the parsed // configuration file. If not, the corresponding option might be diff --git a/vendor/github.com/containers/common/pkg/config/containers.conf b/vendor/github.com/containers/common/pkg/config/containers.conf index 067be429e..fbc691f1d 100644 --- a/vendor/github.com/containers/common/pkg/config/containers.conf +++ b/vendor/github.com/containers/common/pkg/config/containers.conf @@ -347,6 +347,14 @@ # # runtime_supports_json = ["crun", "runc", "kata"] +# List of the OCI runtimes that supports running containers without cgroups. +# +# runtime_supports_nocgroups = ["crun"] + +# List of the OCI runtimes that supports running containers with KVM Separation. +# +# runtime_supports_kvm = ["kata"] + # Paths to look for a valid OCI runtime (runc, runv, kata, etc) [engine.runtimes] # runc = [ @@ -376,6 +384,8 @@ # "/usr/local/sbin/kata-runtime", # "/sbin/kata-runtime", # "/bin/kata-runtime", +# "/usr/bin/kata-qemu", +# "/usr/bin/kata-fc", # ] # Number of seconds to wait for container to exit before sending kill signal. diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index 78bfd8a28..5f3af1f8d 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -246,6 +246,8 @@ func defaultConfigFromMemory() (*EngineConfig, error) { "/usr/local/sbin/kata-runtime", "/sbin/kata-runtime", "/bin/kata-runtime", + "/usr/bin/kata-qemu", + "/usr/bin/kata-fc", }, } c.ConmonEnvVars = []string{ @@ -267,6 +269,7 @@ func defaultConfigFromMemory() (*EngineConfig, error) { "runc", } c.RuntimeSupportsNoCgroups = []string{"crun"} + c.RuntimeSupportsKVM = []string{"kata", "kata-runtime", "kata-qemu", "kata-fc"} c.InitPath = DefaultInitPath c.NoPivotRoot = false diff --git a/vendor/modules.txt b/vendor/modules.txt index 535090e81..9aa167530 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -82,7 +82,7 @@ github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented github.com/containers/buildah/pkg/umask github.com/containers/buildah/util -# github.com/containers/common v0.8.1 +# github.com/containers/common v0.9.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/capabilities github.com/containers/common/pkg/cgroupv2 |