podman rmi --ignore

Add an `--ignore` flag to `podman image rm` to instruct ignoring image
if a specified image does not exist and to not throw an error.  Other
commands (e.g., `podman container rm`) already support this flag.

Such an `--ignore` flag can come in handy in clean-up scripcts such as
the teardown phases in the Podman tests.

Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
This commit is contained in:
Valentin Rothberg 2022-03-17 14:51:54 +01:00
parent c2eae35c60
commit 95dad4d8a4
10 changed files with 51 additions and 2 deletions

View File

@ -56,6 +56,7 @@ func init() {
func imageRemoveFlagSet(flags *pflag.FlagSet) { func imageRemoveFlagSet(flags *pflag.FlagSet) {
flags.BoolVarP(&imageOpts.All, "all", "a", false, "Remove all images") flags.BoolVarP(&imageOpts.All, "all", "a", false, "Remove all images")
flags.BoolVarP(&imageOpts.Ignore, "ignore", "i", false, "Ignore errors if a specified image does not exist")
flags.BoolVarP(&imageOpts.Force, "force", "f", false, "Force Removal of the image") flags.BoolVarP(&imageOpts.Force, "force", "f", false, "Force Removal of the image")
} }

View File

@ -24,6 +24,10 @@ Remove all images in the local storage.
This option will cause podman to remove all containers that are using the image before removing the image from the system. This option will cause podman to remove all containers that are using the image before removing the image from the system.
#### **--ignore**, **-i**
If a specified image does not exist in the local storage, ignore it and do not throw an error.
Remove an image by its short ID Remove an image by its short ID
``` ```
@ -43,6 +47,16 @@ Remove all images and containers.
``` ```
$ podman rmi -a -f $ podman rmi -a -f
``` ```
Remove an absent image with and without the `--ignore` flag.
```
$ podman rmi --ignore nothing
$ podman rmi nothing
Error: nothing: image not known
```
## Exit Status ## Exit Status
**0** All specified images removed **0** All specified images removed

View File

@ -613,6 +613,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
query := struct { query := struct {
All bool `schema:"all"` All bool `schema:"all"`
Force bool `schema:"force"` Force bool `schema:"force"`
Ignore bool `schema:"ignore"`
Images []string `schema:"images"` Images []string `schema:"images"`
}{} }{}
@ -621,7 +622,7 @@ func ImagesBatchRemove(w http.ResponseWriter, r *http.Request) {
return return
} }
opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force} opts := entities.ImageRemoveOptions{All: query.All, Force: query.Force, Ignore: query.Ignore}
imageEngine := abi.ImageEngine{Libpod: runtime} imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts) rmReport, rmErrors := imageEngine.Remove(r.Context(), query.Images, opts)
strErrs := errorhandling.ErrorsToStrings(rmErrors) strErrs := errorhandling.ErrorsToStrings(rmErrors)

View File

@ -944,6 +944,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// name: force // name: force
// description: Force image removal (including containers using the images). // description: Force image removal (including containers using the images).
// type: boolean // type: boolean
// - in: query
// name: ignore
// description: Ignore if a specified image does not exist and do not throw an error.
// type: boolean
// produces: // produces:
// - application/json // - application/json
// responses: // responses:

View File

@ -11,6 +11,8 @@ type RemoveOptions struct {
All *bool All *bool
// Forces removes all containers based on the image // Forces removes all containers based on the image
Force *bool Force *bool
// Ignore if a specified image does not exist and do not throw an error.
Ignore *bool
} }
//go:generate go run ../generator/generator.go DiffOptions //go:generate go run ../generator/generator.go DiffOptions

View File

@ -46,3 +46,18 @@ func (o *RemoveOptions) GetForce() bool {
} }
return *o.Force return *o.Force
} }
// WithIgnore set field Ignore to given value
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
o.Ignore = &value
return o
}
// GetIgnore returns value of field Ignore
func (o *RemoveOptions) GetIgnore() bool {
if o.Ignore == nil {
var z bool
return z
}
return *o.Ignore
}

View File

@ -90,6 +90,8 @@ type ImageRemoveOptions struct {
All bool All bool
// Foce will force image removal including containers using the images. // Foce will force image removal including containers using the images.
Force bool Force bool
// Ignore if a specified image does not exist and do not throw an error.
Ignore bool
// Confirms if given name is a manifest list and removes it, otherwise returns error. // Confirms if given name is a manifest list and removes it, otherwise returns error.
LookupManifest bool LookupManifest bool
} }

View File

@ -578,6 +578,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie
libimageOptions := &libimage.RemoveImagesOptions{} libimageOptions := &libimage.RemoveImagesOptions{}
libimageOptions.Filters = []string{"readonly=false"} libimageOptions.Filters = []string{"readonly=false"}
libimageOptions.Force = opts.Force libimageOptions.Force = opts.Force
libimageOptions.Ignore = opts.Ignore
libimageOptions.LookupManifest = opts.LookupManifest libimageOptions.LookupManifest = opts.LookupManifest
if !opts.All { if !opts.All {
libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false") libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false")

View File

@ -28,7 +28,7 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrID string) (*entities.Boo
} }
func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) { func (ir *ImageEngine) Remove(ctx context.Context, imagesArg []string, opts entities.ImageRemoveOptions) (*entities.ImageRemoveReport, []error) {
options := new(images.RemoveOptions).WithForce(opts.Force).WithAll(opts.All) options := new(images.RemoveOptions).WithForce(opts.Force).WithIgnore(opts.Ignore).WithAll(opts.All)
return images.Remove(ir.ClientCtx, imagesArg, options) return images.Remove(ir.ClientCtx, imagesArg, options)
} }

View File

@ -303,4 +303,13 @@ Deleted: $pauseID"
run_podman image exists $IMAGE run_podman image exists $IMAGE
} }
@test "podman rmi --ignore" {
random_image_name=$(random_string)
random_image_name=${random_image_name,,} # name must be lowercase
run_podman 1 rmi $random_image_name
is "$output" "Error: $random_image_name: image not known.*"
run_podman rmi --ignore $random_image_name
is "$output" ""
}
# vim: filetype=sh # vim: filetype=sh