Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add podman manifest rm --ignore #24678

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cmd/podman/manifest/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import (

"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/registry"
"github.com/containers/podman/v5/pkg/domain/entities"
"github.com/containers/podman/v5/pkg/errorhandling"
"github.com/spf13/cobra"
)

var (
rmCmd = &cobra.Command{
Use: "rm LIST [LIST...]",
rmOptions = entities.ImageRemoveOptions{}
rmCmd = &cobra.Command{
Use: "rm [options] LIST [LIST...]",
Short: "Remove manifest list or image index from local storage",
Long: "Remove manifest list or image index from local storage.",
RunE: rm,
Expand All @@ -27,10 +29,13 @@ func init() {
Command: rmCmd,
Parent: manifestCmd,
})

flags := rmCmd.Flags()
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified manifest is missing")
}

func rm(cmd *cobra.Command, args []string) error {
report, rmErrors := registry.ImageEngine().ManifestRm(context.Background(), args)
report, rmErrors := registry.ImageEngine().ManifestRm(context.Background(), args, rmOptions)
if report != nil {
for _, u := range report.Untagged {
fmt.Println("Untagged: " + u)
Expand Down
8 changes: 7 additions & 1 deletion docs/source/markdown/podman-manifest-rm.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
podman\-manifest\-rm - Remove manifest list or image index from local storage

## SYNOPSIS
**podman manifest rm** *list-or-index* [...]
**podman manifest rm** [*options*] *list-or-index* [...]

## DESCRIPTION
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be committing this if there is a corresponding .in file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes if we use .in the normal file should not be committed and added to the gitignore
Technically speaking there is no reason to use the .in file as it doesn't make use of the imports

Removes one or more locally stored manifest lists.

## OPTIONS

#### **--ignore**, **-i**

If a specified manifest does not exist in the local storage, ignore it and do not throw an error.

## EXAMPLE

podman manifest rm `<list>`
Expand Down
31 changes: 31 additions & 0 deletions docs/source/markdown/podman-manifest-rm.1.md.in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
% podman-manifest-rm 1

## NAME
podman\-manifest\-rm - Remove manifest list or image index from local storage

## SYNOPSIS
**podman manifest rm** *list-or-index* [...]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also must add [*options*] here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. the .in file should not have been checked in.


## DESCRIPTION
Removes one or more locally stored manifest lists.

## OPTIONS

#### **--ignore**, **-i**

If a specified manifest does not exist in the local storage, ignore it and do not throw an error.

## EXAMPLE

podman manifest rm `<list>`

podman manifest rm listid1 listid2

**storage.conf** (`/etc/containers/storage.conf`)

storage.conf is the storage configuration file for all tools using containers/storage

The storage configuration file specifies all of the available container storage options for tools using shared container storage.

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-manifest(1)](podman-manifest.1.md)**, **[containers-storage.conf(5)](https://github.com/containers/storage/blob/main/docs/containers-storage.conf.5.md)**
2 changes: 2 additions & 0 deletions pkg/api/handlers/compat/images_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
query := struct {
Force bool `schema:"force"`
NoPrune bool `schema:"noprune"`
Ignore bool `schema:"ignore"`
}{
// This is where you can override the golang default value for one of fields
}
Expand All @@ -42,6 +43,7 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
options := entities.ImageRemoveOptions{
Force: query.Force,
NoPrune: query.NoPrune,
Ignore: query.Ignore,
}
report, rmerrors := imageEngine.Remove(r.Context(), []string{possiblyNormalizedName}, options)
if len(rmerrors) > 0 && rmerrors[0] != nil {
Expand Down
3 changes: 2 additions & 1 deletion pkg/api/handlers/libpod/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ func ImagesRemove(w http.ResponseWriter, r *http.Request) {
query := struct {
Force bool `schema:"force"`
LookupManifest bool `schema:"lookupManifest"`
Ignore bool `schema:"ignore"`
}{
Force: false,
}
Expand All @@ -677,7 +678,7 @@ func ImagesRemove(w http.ResponseWriter, r *http.Request) {
return
}

opts := entities.ImageRemoveOptions{Force: query.Force, LookupManifest: query.LookupManifest}
opts := entities.ImageRemoveOptions{Force: query.Force, LookupManifest: query.LookupManifest, Ignore: query.Ignore}
imageEngine := abi.ImageEngine{Libpod: runtime}
rmReport, rmErrors := imageEngine.Remove(r.Context(), []string{utils.GetName(r)}, opts)

Expand Down
17 changes: 16 additions & 1 deletion pkg/api/handlers/libpod/manifests.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,16 +739,31 @@ func ManifestModify(w http.ResponseWriter, r *http.Request) {

// ManifestDelete removes a manifest list from storage
func ManifestDelete(w http.ResponseWriter, r *http.Request) {
decoder := r.Context().Value(api.DecoderKey).(*schema.Decoder)
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
imageEngine := abi.ImageEngine{Libpod: runtime}

query := struct {
Ignore bool `schema:"ignore"`
}{
// Add defaults here once needed.
}

if err := decoder.Decode(&query, r.URL.Query()); err != nil {
utils.Error(w, http.StatusBadRequest,
fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
return
}
opts := entities.ImageRemoveOptions{}
opts.Ignore = query.Ignore

name := utils.GetName(r)
if _, err := runtime.LibimageRuntime().LookupManifestList(name); err != nil {
utils.Error(w, http.StatusNotFound, err)
return
}

results, errs := imageEngine.ManifestRm(r.Context(), []string{name})
results, errs := imageEngine.ManifestRm(r.Context(), []string{name}, opts)
errsString := errorhandling.ErrorsToStrings(errs)
report := handlers.LibpodImagesRemoveReport{
ImageRemoveReport: *results,
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/server/register_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error {
// type: string
// required: true
// description: The name or ID of the list to be deleted
// - in: query
// name: ignore
// description: Ignore if a specified manifest does not exist and do not throw an error.
// type: boolean
// responses:
// 200:
// $ref: "#/responses/imagesRemoveResponseLibpod"
Expand Down
2 changes: 1 addition & 1 deletion pkg/domain/entities/engine_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type ImageEngine interface { //nolint:interfacebloat
ManifestAddArtifact(ctx context.Context, name string, files []string, opts ManifestAddArtifactOptions) (string, error)
ManifestAnnotate(ctx context.Context, names, image string, opts ManifestAnnotateOptions) (string, error)
ManifestRemoveDigest(ctx context.Context, names, image string) (string, error)
ManifestRm(ctx context.Context, names []string) (*ImageRemoveReport, []error)
ManifestRm(ctx context.Context, names []string, imageRmOpts ImageRemoveOptions) (*ImageRemoveReport, []error)
ManifestPush(ctx context.Context, name, destination string, imagePushOpts ImagePushOptions) (string, error)
ManifestListClear(ctx context.Context, name string) (string, error)
Sign(ctx context.Context, names []string, options SignOptions) (*SignReport, error)
Expand Down
4 changes: 2 additions & 2 deletions pkg/domain/infra/abi/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,8 +461,8 @@ func (ir *ImageEngine) ManifestRemoveDigest(ctx context.Context, name, image str
}

// ManifestRm removes the specified manifest list from storage
func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string) (report *entities.ImageRemoveReport, rmErrors []error) {
return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true})
func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string, opts entities.ImageRemoveOptions) (report *entities.ImageRemoveReport, rmErrors []error) {
return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true, Ignore: opts.Ignore})
}

// ManifestPush pushes a manifest list or image index to the destination
Expand Down
4 changes: 2 additions & 2 deletions pkg/domain/infra/tunnel/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ func (ir *ImageEngine) ManifestRemoveDigest(ctx context.Context, name string, im
}

// ManifestRm removes the specified manifest list from storage
func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string) (*entities.ImageRemoveReport, []error) {
return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true})
func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string, opts entities.ImageRemoveOptions) (report *entities.ImageRemoveReport, rmErrors []error) {
return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true, Ignore: opts.Ignore})
}

// ManifestPush pushes a manifest list or image index to the destination
Expand Down
3 changes: 3 additions & 0 deletions test/apiv2/15-manifest.at
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ t POST "/v4.0.0/libpod/manifests/xyz:latest/registry/localhost:$REGISTRY_PORT%2F
# /v3.x cannot delete a manifest list
t DELETE /v4.0.0/libpod/manifests/$id_abc 200
t DELETE /v4.0.0/libpod/manifests/$id_xyz 200
t GET /v4.0.0/libpod/manifests/$id_xyz/exists 404
t DELETE /v4.0.0/libpod/manifests/$id_xyz 404
t DELETE /v4.0.0/libpod/manifests/$id_xyz?ignore=true 200

# manifest add --artifact tests
truncate -s 20M $WORKDIR/zeroes
Expand Down
4 changes: 4 additions & 0 deletions test/system/012-manifest.bats
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ function validate_instance_compression {
--tls-verify=false $mid \
$manifest1
run_podman manifest rm $manifest1
run_podman 1 manifest rm $manifest1
is "$output" "Error: $manifest1: image not known" "Missing manifest is reported"
run_podman manifest rm --ignore $manifest1
is "$output" "" "Missing manifest is ignored"

# Default is to require TLS; also test explicit opts
for opt in '' '--insecure=false' '--tls-verify=true' "--authfile=$authfile"; do
Expand Down