Skip to content

Commit 9403c3d

Browse files
Merge pull request #24678 from rhatdan/manifest
Add podman manifest rm --ignore
2 parents c76c13f + 5181bec commit 9403c3d

File tree

11 files changed

+67
-19
lines changed

11 files changed

+67
-19
lines changed

cmd/podman/manifest/rm.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import (
66

77
"github.com/containers/podman/v5/cmd/podman/common"
88
"github.com/containers/podman/v5/cmd/podman/registry"
9+
"github.com/containers/podman/v5/pkg/domain/entities"
910
"github.com/containers/podman/v5/pkg/errorhandling"
1011
"github.com/spf13/cobra"
1112
)
1213

1314
var (
14-
rmCmd = &cobra.Command{
15-
Use: "rm LIST [LIST...]",
15+
rmOptions = entities.ImageRemoveOptions{}
16+
rmCmd = &cobra.Command{
17+
Use: "rm [options] LIST [LIST...]",
1618
Short: "Remove manifest list or image index from local storage",
1719
Long: "Remove manifest list or image index from local storage.",
1820
RunE: rm,
@@ -27,10 +29,13 @@ func init() {
2729
Command: rmCmd,
2830
Parent: manifestCmd,
2931
})
32+
33+
flags := rmCmd.Flags()
34+
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified manifest is missing")
3035
}
3136

3237
func rm(cmd *cobra.Command, args []string) error {
33-
report, rmErrors := registry.ImageEngine().ManifestRm(context.Background(), args)
38+
report, rmErrors := registry.ImageEngine().ManifestRm(context.Background(), args, rmOptions)
3439
if report != nil {
3540
for _, u := range report.Untagged {
3641
fmt.Println("Untagged: " + u)

docs/source/markdown/podman-manifest-rm.1.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,17 @@
44
podman\-manifest\-rm - Remove manifest list or image index from local storage
55

66
## SYNOPSIS
7-
**podman manifest rm** *list-or-index* [...]
7+
**podman manifest rm** [*options*] *list-or-index* [...]
88

99
## DESCRIPTION
1010
Removes one or more locally stored manifest lists.
1111

12+
## OPTIONS
13+
14+
#### **--ignore**, **-i**
15+
16+
If a specified manifest does not exist in the local storage, ignore it and do not throw an error.
17+
1218
## EXAMPLE
1319

1420
podman manifest rm `<list>`

pkg/api/handlers/compat/images_remove.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
2222
query := struct {
2323
Force bool `schema:"force"`
2424
NoPrune bool `schema:"noprune"`
25+
Ignore bool `schema:"ignore"`
2526
}{
2627
// This is where you can override the golang default value for one of fields
2728
}
@@ -42,6 +43,7 @@ func RemoveImage(w http.ResponseWriter, r *http.Request) {
4243
options := entities.ImageRemoveOptions{
4344
Force: query.Force,
4445
NoPrune: query.NoPrune,
46+
Ignore: query.Ignore,
4547
}
4648
report, rmerrors := imageEngine.Remove(r.Context(), []string{possiblyNormalizedName}, options)
4749
if len(rmerrors) > 0 && rmerrors[0] != nil {

pkg/api/handlers/libpod/images.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,7 @@ func ImagesRemove(w http.ResponseWriter, r *http.Request) {
668668
query := struct {
669669
Force bool `schema:"force"`
670670
LookupManifest bool `schema:"lookupManifest"`
671+
Ignore bool `schema:"ignore"`
671672
}{
672673
Force: false,
673674
}
@@ -677,7 +678,7 @@ func ImagesRemove(w http.ResponseWriter, r *http.Request) {
677678
return
678679
}
679680

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

pkg/api/handlers/libpod/manifests.go

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -745,20 +745,43 @@ func ManifestModify(w http.ResponseWriter, r *http.Request) {
745745

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

751-
name := utils.GetName(r)
752-
if _, err := runtime.LibimageRuntime().LookupManifestList(name); err != nil {
753-
utils.Error(w, http.StatusNotFound, err)
752+
query := struct {
753+
Ignore bool `schema:"ignore"`
754+
}{
755+
// Add defaults here once needed.
756+
}
757+
758+
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
759+
utils.Error(w, http.StatusBadRequest,
760+
fmt.Errorf("failed to parse parameters for %s: %w", r.URL.String(), err))
754761
return
755762
}
763+
opts := entities.ImageRemoveOptions{
764+
Ignore: query.Ignore,
765+
}
756766

757-
results, errs := imageEngine.ManifestRm(r.Context(), []string{name})
758-
errsString := errorhandling.ErrorsToStrings(errs)
759-
report := handlers.LibpodImagesRemoveReport{
760-
ImageRemoveReport: *results,
761-
Errors: errsString,
767+
name := utils.GetName(r)
768+
rmReport, rmErrors := imageEngine.ManifestRm(r.Context(), []string{name}, opts)
769+
// In contrast to batch-removal, where we're only setting the exit
770+
// code, we need to have another closer look at the errors here and set
771+
// the appropriate http status code.
772+
773+
switch rmReport.ExitCode {
774+
case 0:
775+
report := handlers.LibpodImagesRemoveReport{ImageRemoveReport: *rmReport, Errors: []string{}}
776+
utils.WriteResponse(w, http.StatusOK, report)
777+
case 1:
778+
// 404 - no such image
779+
utils.Error(w, http.StatusNotFound, errorhandling.JoinErrors(rmErrors))
780+
case 2:
781+
// 409 - conflict error (in use by containers)
782+
utils.Error(w, http.StatusConflict, errorhandling.JoinErrors(rmErrors))
783+
default:
784+
// 500 - internal error
785+
utils.Error(w, http.StatusInternalServerError, errorhandling.JoinErrors(rmErrors))
762786
}
763-
utils.WriteResponse(w, http.StatusOK, report)
764787
}

pkg/api/server/register_manifest.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ func (s *APIServer) registerManifestHandlers(r *mux.Router) error {
322322
// type: string
323323
// required: true
324324
// description: The name or ID of the list to be deleted
325+
// - in: query
326+
// name: ignore
327+
// description: Ignore if a specified manifest does not exist and do not throw an error.
328+
// type: boolean
325329
// responses:
326330
// 200:
327331
// $ref: "#/responses/imagesRemoveResponseLibpod"

pkg/domain/entities/engine_image.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type ImageEngine interface { //nolint:interfacebloat
4545
ManifestAddArtifact(ctx context.Context, name string, files []string, opts ManifestAddArtifactOptions) (string, error)
4646
ManifestAnnotate(ctx context.Context, names, image string, opts ManifestAnnotateOptions) (string, error)
4747
ManifestRemoveDigest(ctx context.Context, names, image string) (string, error)
48-
ManifestRm(ctx context.Context, names []string) (*ImageRemoveReport, []error)
48+
ManifestRm(ctx context.Context, names []string, imageRmOpts ImageRemoveOptions) (*ImageRemoveReport, []error)
4949
ManifestPush(ctx context.Context, name, destination string, imagePushOpts ImagePushOptions) (string, error)
5050
ManifestListClear(ctx context.Context, name string) (string, error)
5151
Sign(ctx context.Context, names []string, options SignOptions) (*SignReport, error)

pkg/domain/infra/abi/manifest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ func (ir *ImageEngine) ManifestRemoveDigest(ctx context.Context, name, image str
460460
}
461461

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

467467
// ManifestPush pushes a manifest list or image index to the destination

pkg/domain/infra/tunnel/manifest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,8 @@ func (ir *ImageEngine) ManifestRemoveDigest(ctx context.Context, name string, im
178178
}
179179

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

185185
// ManifestPush pushes a manifest list or image index to the destination

test/apiv2/15-manifest.at

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ t POST "/v4.0.0/libpod/manifests/xyz:latest/registry/localhost:$REGISTRY_PORT%2F
6666
# /v3.x cannot delete a manifest list
6767
t DELETE /v4.0.0/libpod/manifests/$id_abc 200
6868
t DELETE /v4.0.0/libpod/manifests/$id_xyz 200
69+
t GET /v4.0.0/libpod/manifests/$id_xyz/exists 404
70+
t DELETE /v4.0.0/libpod/manifests/$id_xyz 404
71+
t DELETE /v4.0.0/libpod/manifests/$id_xyz?ignore=true 200
6972

7073
# manifest add --artifact tests
7174
truncate -s 20M $WORKDIR/zeroes

test/system/012-manifest.bats

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ function validate_instance_compression {
9494
--tls-verify=false $mid \
9595
$manifest1
9696
run_podman manifest rm $manifest1
97+
run_podman 1 manifest rm $manifest1
98+
is "$output" "Error: $manifest1: image not known" "Missing manifest is reported"
99+
run_podman manifest rm --ignore $manifest1
100+
is "$output" "" "Missing manifest is ignored"
97101

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

0 commit comments

Comments
 (0)