mirror of
https://github.com/containers/podman.git
synced 2025-10-11 08:15:25 +08:00
Merge pull request #27142 from nothiaki/feat-artifact-rm-ignore
Feat artifact rm ignore
This commit is contained in:
@ -23,6 +23,7 @@ var (
|
|||||||
podman artifact rm quay.io/myimage/myartifact:latest
|
podman artifact rm quay.io/myimage/myartifact:latest
|
||||||
podman artifact rm -a
|
podman artifact rm -a
|
||||||
podman artifact rm c4dfb1609ee2 93fd78260bd1 c0ed59d05ff7
|
podman artifact rm c4dfb1609ee2 93fd78260bd1 c0ed59d05ff7
|
||||||
|
podman artifact rm -i c4dfb1609ee2
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ var (
|
|||||||
func rmFlags(cmd *cobra.Command) {
|
func rmFlags(cmd *cobra.Command) {
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all artifacts")
|
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all artifacts")
|
||||||
|
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore error if artifact does not exist")
|
||||||
}
|
}
|
||||||
func init() {
|
func init() {
|
||||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
|
@ -22,6 +22,9 @@ providing a name or digest of the artifact.
|
|||||||
|
|
||||||
Print usage statement.
|
Print usage statement.
|
||||||
|
|
||||||
|
#### **--ignore**, **-i**
|
||||||
|
|
||||||
|
Remove artifacts in the local store, ignoring errors when trying to remove artifacts that do not exist.
|
||||||
|
|
||||||
## EXAMPLES
|
## EXAMPLES
|
||||||
|
|
||||||
@ -49,6 +52,11 @@ Deleted: cee15f7c5ce3e86ae6ce60d84bebdc37ad34acfa9a2611cf47501469ac83a1ab
|
|||||||
Deleted: 72875f8f6f78d5b8ba98b2dd2c0a6f395fde8f05ff63a1df580d7a88f5afa97b
|
Deleted: 72875f8f6f78d5b8ba98b2dd2c0a6f395fde8f05ff63a1df580d7a88f5afa97b
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Remove artifacts ignoring the errors if the artifact does not exist.
|
||||||
|
```
|
||||||
|
$ podman artifact rm -i 3f78d5b8ba98b2
|
||||||
|
```
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
**[podman(1)](podman.1.md)**, **[podman-artifact(1)](podman-artifact.1.md)**
|
**[podman(1)](podman.1.md)**, **[podman-artifact(1)](podman-artifact.1.md)**
|
||||||
|
|
||||||
|
@ -169,6 +169,7 @@ func BatchRemoveArtifact(w http.ResponseWriter, r *http.Request) {
|
|||||||
query := struct {
|
query := struct {
|
||||||
All bool `schema:"all"`
|
All bool `schema:"all"`
|
||||||
Artifacts []string `schema:"artifacts"`
|
Artifacts []string `schema:"artifacts"`
|
||||||
|
Ignore bool `schema:"ignore"`
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||||
@ -191,11 +192,16 @@ func BatchRemoveArtifact(w http.ResponseWriter, r *http.Request) {
|
|||||||
removeOptions := entities.ArtifactRemoveOptions{
|
removeOptions := entities.ArtifactRemoveOptions{
|
||||||
Artifacts: query.Artifacts,
|
Artifacts: query.Artifacts,
|
||||||
All: query.All,
|
All: query.All,
|
||||||
|
Ignore: query.Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
artifacts, err := imageEngine.ArtifactRm(r.Context(), removeOptions)
|
artifacts, err := imageEngine.ArtifactRm(r.Context(), removeOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, libartifact_types.ErrArtifactNotExist) {
|
if errors.Is(err, libartifact_types.ErrArtifactNotExist) {
|
||||||
|
if removeOptions.Ignore {
|
||||||
|
utils.WriteResponse(w, http.StatusOK, artifacts)
|
||||||
|
return
|
||||||
|
}
|
||||||
utils.ArtifactNotFound(w, "", err)
|
utils.ArtifactNotFound(w, "", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,10 @@ func (s *APIServer) registerArtifactHandlers(r *mux.Router) error {
|
|||||||
// in: query
|
// in: query
|
||||||
// description: Remove all artifacts
|
// description: Remove all artifacts
|
||||||
// type: boolean
|
// type: boolean
|
||||||
|
// - name: ignore
|
||||||
|
// in: query
|
||||||
|
// description: Ignore errors if artifact does not exist
|
||||||
|
// type: boolean
|
||||||
// responses:
|
// responses:
|
||||||
// 200:
|
// 200:
|
||||||
// $ref: "#/responses/artifactRemoveResponse"
|
// $ref: "#/responses/artifactRemoveResponse"
|
||||||
|
@ -52,6 +52,8 @@ type RemoveOptions struct {
|
|||||||
All *bool
|
All *bool
|
||||||
// Artifacts is a list of Artifact IDs or names to remove
|
// Artifacts is a list of Artifact IDs or names to remove
|
||||||
Artifacts []string
|
Artifacts []string
|
||||||
|
// Ignore errors if IDs or names are not defined
|
||||||
|
Ignore *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddOptions are optional options for removing images
|
// AddOptions are optional options for removing images
|
||||||
|
@ -46,3 +46,18 @@ func (o *RemoveOptions) GetArtifacts() []string {
|
|||||||
}
|
}
|
||||||
return o.Artifacts
|
return o.Artifacts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
@ -96,6 +96,8 @@ type ArtifactRemoveOptions struct {
|
|||||||
All bool
|
All bool
|
||||||
// Artifacts is a list of Artifact IDs or names to remove
|
// Artifacts is a list of Artifact IDs or names to remove
|
||||||
Artifacts []string
|
Artifacts []string
|
||||||
|
// Ignore if a specified artifact does not exist and do not throw any error.
|
||||||
|
Ignore bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArtifactRemoveReport = entitiesTypes.ArtifactRemoveReport
|
type ArtifactRemoveReport = entitiesTypes.ArtifactRemoveReport
|
||||||
|
@ -4,6 +4,7 @@ package abi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/containers/podman/v5/pkg/domain/entities"
|
"github.com/containers/podman/v5/pkg/domain/entities"
|
||||||
"github.com/containers/podman/v5/pkg/libartifact/types"
|
"github.com/containers/podman/v5/pkg/libartifact/types"
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"go.podman.io/common/libimage"
|
"go.podman.io/common/libimage"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -124,6 +126,10 @@ func (ir *ImageEngine) ArtifactRm(ctx context.Context, opts entities.ArtifactRem
|
|||||||
for _, namesOrDigest := range namesOrDigests {
|
for _, namesOrDigest := range namesOrDigests {
|
||||||
artifactDigest, err := artStore.Remove(ctx, namesOrDigest)
|
artifactDigest, err := artStore.Remove(ctx, namesOrDigest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if opts.Ignore && errors.Is(err, types.ErrArtifactNotExist) {
|
||||||
|
logrus.Debugf("Artifact with name or digest %q does not exist, ignoring error as request", namesOrDigest)
|
||||||
|
continue
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
artifactDigests = append(artifactDigests, artifactDigest)
|
artifactDigests = append(artifactDigests, artifactDigest)
|
||||||
|
@ -57,6 +57,7 @@ func (ir *ImageEngine) ArtifactRm(_ context.Context, opts entities.ArtifactRemov
|
|||||||
removeOptions := artifacts.RemoveOptions{
|
removeOptions := artifacts.RemoveOptions{
|
||||||
All: &opts.All,
|
All: &opts.All,
|
||||||
Artifacts: opts.Artifacts,
|
Artifacts: opts.Artifacts,
|
||||||
|
Ignore: &opts.Ignore,
|
||||||
}
|
}
|
||||||
|
|
||||||
return artifacts.Remove(ir.ClientCtx, "", &removeOptions)
|
return artifacts.Remove(ir.ClientCtx, "", &removeOptions)
|
||||||
|
@ -527,6 +527,20 @@ class ArtifactTestCase(APITestCase):
|
|||||||
rjson = r.json()
|
rjson = r.json()
|
||||||
self.assertEqual(len(rjson), 0)
|
self.assertEqual(len(rjson), 0)
|
||||||
|
|
||||||
|
def test_remove_with_ignore(self):
|
||||||
|
# Test remove non existent artifacts with ignore
|
||||||
|
removeparameters: dict[str, str | list[str]] = {
|
||||||
|
"Artifacts": "fake_artifact",
|
||||||
|
"ignore": "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
url = self.uri("/artifacts/remove")
|
||||||
|
r = requests.delete(url, params=removeparameters)
|
||||||
|
rjson = r.json()
|
||||||
|
|
||||||
|
# Assert correct response code
|
||||||
|
self.assertEqual(r.status_code, 200, r.text)
|
||||||
|
|
||||||
def test_remove_absent_artifact_fails(self):
|
def test_remove_absent_artifact_fails(self):
|
||||||
ARTIFACT_NAME = "localhost/fake/artifact:latest"
|
ARTIFACT_NAME = "localhost/fake/artifact:latest"
|
||||||
url = self.uri("/artifacts/" + ARTIFACT_NAME)
|
url = self.uri("/artifacts/" + ARTIFACT_NAME)
|
||||||
|
@ -257,6 +257,22 @@ var _ = Describe("Podman artifact", func() {
|
|||||||
// There should be no artifacts in the store
|
// There should be no artifacts in the store
|
||||||
rmAll := podmanTest.PodmanExitCleanly("artifact", "ls", "--noheading")
|
rmAll := podmanTest.PodmanExitCleanly("artifact", "ls", "--noheading")
|
||||||
Expect(rmAll.OutputToString()).To(BeEmpty())
|
Expect(rmAll.OutputToString()).To(BeEmpty())
|
||||||
|
|
||||||
|
// Trying to remove an artifact that does not exist should pass with -i
|
||||||
|
podmanTest.PodmanExitCleanly("artifact", "rm", "-i", "foobar")
|
||||||
|
|
||||||
|
// Add an artifact to test remove with --ignore flag
|
||||||
|
artifact3File, err := createArtifactFile(4192)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
artifact3Name := "localhost/test/artifact3"
|
||||||
|
_ = podmanTest.PodmanExitCleanly("artifact", "add", artifact3Name, artifact3File)
|
||||||
|
|
||||||
|
// Trying to remove an existing artifact should also pass with -i
|
||||||
|
podmanTest.PodmanExitCleanly("artifact", "rm", "-i", artifact3Name)
|
||||||
|
|
||||||
|
// There should be no artifacts in the store at this point
|
||||||
|
rmAll = podmanTest.PodmanExitCleanly("artifact", "ls", "--noheading")
|
||||||
|
Expect(rmAll.OutputToString()).To(BeEmpty())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman artifact inspect with full or partial digest", func() {
|
It("podman artifact inspect with full or partial digest", func() {
|
||||||
|
Reference in New Issue
Block a user