From fdfed9979f884b8505b549319473dd2fc2983efa Mon Sep 17 00:00:00 2001 From: Brent Baude Date: Thu, 17 Apr 2025 09:42:08 -0500 Subject: [PATCH] Add ability to set layer media type for artifacts in #25884, it was pointed out that the standard detection used to determine the artifact's file type can be wrong. in those cases, it would be handy for the user to be able to override the media type of the layer. as such, added a new option called `--file-type`, which is optional, and allows users to do just that. `podman artifact add --file-type text/yaml quay.io/artifact/config:latest ./config.yaml ` Fixes: #25884 Signed-off-by: Brent Baude --- cmd/podman/artifact/add.go | 12 ++++++++++-- docs/source/markdown/podman-artifact-add.1.md.in | 14 ++++++++++++++ pkg/domain/entities/artifact.go | 1 + pkg/domain/infra/abi/artifact.go | 1 + pkg/libartifact/store/store.go | 14 ++++++++++---- pkg/libartifact/types/config.go | 3 +++ test/e2e/artifact_test.go | 4 +++- 7 files changed, 42 insertions(+), 7 deletions(-) diff --git a/cmd/podman/artifact/add.go b/cmd/podman/artifact/add.go index 7b5e4214ed..899a35440d 100644 --- a/cmd/podman/artifact/add.go +++ b/cmd/podman/artifact/add.go @@ -19,8 +19,10 @@ var ( RunE: add, Args: cobra.MinimumNArgs(2), ValidArgsFunction: common.AutocompleteArtifactAdd, - Example: `podman artifact add quay.io/myimage/myartifact:latest /tmp/foobar.txt`, - Annotations: map[string]string{registry.EngineMode: registry.ABIMode}, + Example: `podman artifact add quay.io/myimage/myartifact:latest /tmp/foobar.txt +podman artifact add --file-type text/yaml quay.io/myimage/myartifact:latest /tmp/foobar.yaml +podman artifact add --append quay.io/myimage/myartifact:latest /tmp/foobar.tar.gz`, + Annotations: map[string]string{registry.EngineMode: registry.ABIMode}, } ) @@ -28,6 +30,7 @@ type artifactAddOptions struct { ArtifactType string Annotations []string Append bool + FileType string } var ( @@ -51,6 +54,10 @@ func init() { appendFlagName := "append" flags.BoolVarP(&addOpts.Append, appendFlagName, "a", false, "Append files to an existing artifact") + + fileTypeFlagName := "file-type" + flags.StringVarP(&addOpts.FileType, fileTypeFlagName, "", "", "Set file type to use for the artifact (layer)") + _ = addCmd.RegisterFlagCompletionFunc(fileTypeFlagName, completion.AutocompleteNone) } func add(cmd *cobra.Command, args []string) error { @@ -63,6 +70,7 @@ func add(cmd *cobra.Command, args []string) error { opts.Annotations = annots opts.ArtifactType = addOpts.ArtifactType opts.Append = addOpts.Append + opts.FileType = addOpts.FileType report, err := registry.ImageEngine().ArtifactAdd(registry.Context(), args[0], args[1:], opts) if err != nil { diff --git a/docs/source/markdown/podman-artifact-add.1.md.in b/docs/source/markdown/podman-artifact-add.1.md.in index 17231f6e7b..73004b1112 100644 --- a/docs/source/markdown/podman-artifact-add.1.md.in +++ b/docs/source/markdown/podman-artifact-add.1.md.in @@ -27,6 +27,10 @@ Note: Set annotations for each file being added. Append files to an existing artifact. This option cannot be used with the **--type** option. +#### **--file-type** + +Set the media type of the artifact file instead of allowing detection to determine the type + #### **--help** Print usage statement. @@ -55,6 +59,16 @@ Set an annotation for an artifact $ podman artifact add --annotation date=2025-01-30 quay.io/myartifact/myml:latest /tmp/foobar1.ml ``` +Append a file to an existing artifact +``` +$ podman artifact add --append quay.io/myartifact/tarballs:latest /tmp/foobar.tar.gz +``` + +Override the media type of the artifact being added +``` +$ podman artifact add --file-type text/yaml quay.io/myartifact/descriptors:latest /tmp/info.yaml +``` + ## SEE ALSO **[podman(1)](podman.1.md)**, **[podman-artifact(1)](podman-artifact.1.md)** diff --git a/pkg/domain/entities/artifact.go b/pkg/domain/entities/artifact.go index 5ce8acad74..0d699c8c6c 100644 --- a/pkg/domain/entities/artifact.go +++ b/pkg/domain/entities/artifact.go @@ -13,6 +13,7 @@ type ArtifactAddOptions struct { Annotations map[string]string ArtifactType string Append bool + FileType string } type ArtifactExtractOptions struct { diff --git a/pkg/domain/infra/abi/artifact.go b/pkg/domain/infra/abi/artifact.go index a867a1d2ff..fefa161f26 100644 --- a/pkg/domain/infra/abi/artifact.go +++ b/pkg/domain/infra/abi/artifact.go @@ -192,6 +192,7 @@ func (ir *ImageEngine) ArtifactAdd(ctx context.Context, name string, paths []str Annotations: opts.Annotations, ArtifactType: opts.ArtifactType, Append: opts.Append, + FileType: opts.FileType, } artifactDigest, err := artStore.Add(ctx, name, paths, &addOptions) diff --git a/pkg/libartifact/store/store.go b/pkg/libartifact/store/store.go index 46867c9d33..7e6061832b 100644 --- a/pkg/libartifact/store/store.go +++ b/pkg/libartifact/store/store.go @@ -251,20 +251,26 @@ func (as ArtifactStore) Add(ctx context.Context, dest string, paths []string, op // ImageDestination, in general, requires the caller to write a full image; here we may write only the added layers. // This works for the oci/layout transport we hard-code. for _, path := range paths { + mediaType := options.FileType // get the new artifact into the local store newBlobDigest, newBlobSize, err := layout.PutBlobFromLocalFile(ctx, imageDest, path) if err != nil { return nil, err } - detectedType, err := determineManifestType(path) - if err != nil { - return nil, err + + // If we did not receive an override for the layer's mediatype, use + // detection to determine it. + if len(mediaType) < 1 { + mediaType, err = determineManifestType(path) + if err != nil { + return nil, err + } } annotations := maps.Clone(options.Annotations) annotations[specV1.AnnotationTitle] = filepath.Base(path) newLayer := specV1.Descriptor{ - MediaType: detectedType, + MediaType: mediaType, Digest: newBlobDigest, Size: newBlobSize, Annotations: annotations, diff --git a/pkg/libartifact/types/config.go b/pkg/libartifact/types/config.go index cff62a3709..7591ffdef9 100644 --- a/pkg/libartifact/types/config.go +++ b/pkg/libartifact/types/config.go @@ -10,6 +10,9 @@ type AddOptions struct { ArtifactType string `json:",omitempty"` // append option is not compatible with ArtifactType option Append bool `json:",omitempty"` + // FileType describes the media type for the layer. It is an override + // for the standard detection + FileType string `json:",omitempty"` } // FilterBlobOptions options used to filter for a single blob in an artifact diff --git a/test/e2e/artifact_test.go b/test/e2e/artifact_test.go index f14540ea50..a7150fce05 100644 --- a/test/e2e/artifact_test.go +++ b/test/e2e/artifact_test.go @@ -88,6 +88,7 @@ var _ = Describe("Podman artifact", func() { }) It("podman artifact add with options", func() { + yamlType := "text/yaml" artifact1Name := "localhost/test/artifact1" artifact1File, err := createArtifactFile(1024) Expect(err).ToNot(HaveOccurred()) @@ -96,13 +97,14 @@ var _ = Describe("Podman artifact", func() { annotation1 := "color=blue" annotation2 := "flavor=lemon" - podmanTest.PodmanExitCleanly("artifact", "add", "--type", artifactType, "--annotation", annotation1, "--annotation", annotation2, artifact1Name, artifact1File) + podmanTest.PodmanExitCleanly("artifact", "add", "--file-type", yamlType, "--type", artifactType, "--annotation", annotation1, "--annotation", annotation2, artifact1Name, artifact1File) a := podmanTest.InspectArtifact(artifact1Name) Expect(a.Name).To(Equal(artifact1Name)) Expect(a.Manifest.ArtifactType).To(Equal(artifactType)) Expect(a.Manifest.Layers[0].Annotations["color"]).To(Equal("blue")) Expect(a.Manifest.Layers[0].Annotations["flavor"]).To(Equal("lemon")) + Expect(a.Manifest.Layers[0].MediaType).To(Equal(yamlType)) failSession := podmanTest.Podman([]string{"artifact", "add", "--annotation", "org.opencontainers.image.title=foobar", "foobar", artifact1File}) failSession.WaitWithDefaultTimeout()