diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index b3a5efc4e2..e860dc7073 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -1476,6 +1476,10 @@ func getEntityType(cmd *cobra.Command, args []string, o any) any { if networks, _ := getNetworks(cmd, args[0], completeDefault); len(networks) > 0 { return &entities.NetworkInspectReport{} } + // artifact logic + if artifacts, _ := getArtifacts(cmd, args[0]); len(artifacts) > 0 { + return &entities.ArtifactInspectReport{} + } return o } @@ -1641,7 +1645,7 @@ func AutocompleteImageSort(_ *cobra.Command, _ []string, _ string) ([]string, co // AutocompleteInspectType - Autocomplete inspect type options. func AutocompleteInspectType(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) { - types := []string{AllType, ContainerType, ImageType, NetworkType, PodType, VolumeType} + types := []string{AllType, ArtifactType, ContainerType, ImageType, NetworkType, PodType, VolumeType} return types, cobra.ShellCompDirectiveNoFileComp } diff --git a/cmd/podman/common/inspect.go b/cmd/podman/common/inspect.go index 12a5af5a92..b3dee58c50 100644 --- a/cmd/podman/common/inspect.go +++ b/cmd/podman/common/inspect.go @@ -3,6 +3,8 @@ package common const ( // AllType can be of type ImageType or ContainerType. AllType = "all" + // ArtifactType is the artifact type. + ArtifactType = "artifact" // ContainerType is the container type. ContainerType = "container" // ImageType is the image type. diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index ed15fcdef4..425327dba0 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -12,6 +12,7 @@ var ( inspectDescription = `Displays the low-level information on an object identified by name or ID. For more inspection options, see: + podman artifact inspect podman container inspect podman image inspect podman network inspect @@ -20,7 +21,7 @@ var ( // Command: podman _inspect_ Object_ID inspectCmd = &cobra.Command{ - Use: "inspect [options] {CONTAINER|IMAGE|POD|NETWORK|VOLUME} [...]", + Use: "inspect [options] {ARTIFACT|CONTAINER|IMAGE|POD|NETWORK|VOLUME} [...]", Short: "Display the configuration of object denoted by ID", RunE: inspectExec, Long: inspectDescription, @@ -28,6 +29,7 @@ var ( ValidArgsFunction: common.AutocompleteInspect, Example: `podman inspect fedora podman inspect --type image fedora + podman inspect --type artifact quay.io/myimage/myartifact:latest podman inspect CtrID ImgID podman inspect --format "imageId: {{.Id}} size: {{.Size}}" fedora`, } diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index c4ff61c546..cbba736a61 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -151,9 +151,18 @@ func (i *inspector) inspect(namesOrIDs []string) error { for i := range volumeData { data = append(data, volumeData[i]) } + case common.ArtifactType: + for _, name := range namesOrIDs { + artifactData, err := i.imageEngine.ArtifactInspect(ctx, name, entities.ArtifactInspectOptions{}) + if err != nil { + errs = append(errs, err) + continue + } + data = append(data, artifactData) + } default: - return fmt.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, or %q", i.options.Type, - common.ImageType, common.ContainerType, common.PodType, common.NetworkType, common.VolumeType, common.AllType) + return fmt.Errorf("invalid type %q: must be %q, %q, %q, %q, %q, %q, or %q", i.options.Type, + common.ImageType, common.ContainerType, common.PodType, common.NetworkType, common.VolumeType, common.ArtifactType, common.AllType) } // Always print an empty array if data == nil { @@ -236,6 +245,11 @@ func (i *inspector) inspectAll(ctx context.Context, namesOrIDs []string) ([]any, data = append(data, podData[0]) continue } + artifactData, err := i.imageEngine.ArtifactInspect(ctx, name, entities.ArtifactInspectOptions{}) + if err == nil { + data = append(data, artifactData) + continue + } if len(errs) > 0 { allErrs = append(allErrs, fmt.Errorf("no such object: %q", name)) continue diff --git a/docs/source/markdown/podman-inspect.1.md.in b/docs/source/markdown/podman-inspect.1.md.in index 587b6d3e5e..c88a1dba54 100644 --- a/docs/source/markdown/podman-inspect.1.md.in +++ b/docs/source/markdown/podman-inspect.1.md.in @@ -1,19 +1,20 @@ % podman-inspect 1 ## NAME -podman\-inspect - Display a container, image, volume, network, or pod's configuration +podman\-inspect - Display artifact, container, image, volume, network, or pod's configuration ## SYNOPSIS **podman inspect** [*options*] *name* [...] ## DESCRIPTION -This displays the low-level information on containers and images identified by name or ID. By default, this renders -all results in a JSON array. If the inspect type is all, the order of inspection is: containers, images, volumes, network, pods. +This displays the low-level information on artifacts, containers, and images identified by name or ID. By default, this renders +all results in a JSON array. If the inspect type is all, the order of inspection is: containers, images, volumes, network, pods, artifacts. If a container has the same name as an image, then the container JSON is returned, and so on. If a format is specified, the given template is executed for each result. For more inspection options, see also +[podman-artifact-inspect(1)](podman-artifact-inspect.1.md), [podman-container-inspect(1)](podman-container-inspect.1.md), [podman-image-inspect(1)](podman-image-inspect.1.md), [podman-network-inspect(1)](podman-network-inspect.1.md), @@ -35,7 +36,7 @@ In addition to normal output, display the total file size if the type is a conta #### **--type**, **-t**=*type* -Return JSON for the specified type. Type can be 'container', 'image', 'volume', 'network', 'pod', or 'all' (default: all) +Return JSON for the specified type. Type can be 'artifact', 'container', 'image', 'volume', 'network', 'pod', or 'all' (default: all) (Only meaningful when invoked as *podman inspect*) ## EXAMPLES @@ -164,8 +165,22 @@ Inspect the specified network for the `Name` format specifier: myNetwork ``` +Inspect the specified artifact: +``` +# podman inspect quay.io/myimage/myartifact:latest --type artifact +{ + "Manifest": { + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + ... + }, + "Name": "quay.io/myimage/myartifact:latest", + "Digest": "sha256:..." +} +``` + ## SEE ALSO -**[podman(1)](podman.1.md)**, **[podman-container-inspect(1)](podman-container-inspect.1.md)**, **[podman-image-inspect(1)](podman-image-inspect.1.md)**, **[podman-network-inspect(1)](podman-network-inspect.1.md)**, **[podman-pod-inspect(1)](podman-pod-inspect.1.md)**, **[podman-volume-inspect(1)](podman-volume-inspect.1.md)** +**[podman(1)](podman.1.md)**, **[podman-artifact-inspect(1)](podman-artifact-inspect.1.md)**, **[podman-container-inspect(1)](podman-container-inspect.1.md)**, **[podman-image-inspect(1)](podman-image-inspect.1.md)**, **[podman-network-inspect(1)](podman-network-inspect.1.md)**, **[podman-pod-inspect(1)](podman-pod-inspect.1.md)**, **[podman-volume-inspect(1)](podman-volume-inspect.1.md)** ## HISTORY July 2017, Originally compiled by Dan Walsh diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 492068c231..8f46dd081a 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -367,7 +367,7 @@ the exit codes follow the `chroot` standard, see below: | [podman-import(1)](podman-import.1.md) | Import a tarball and save it as a filesystem image. | | [podman-info(1)](podman-info.1.md) | Display Podman related system information. | | [podman-init(1)](podman-init.1.md) | Initialize one or more containers | -| [podman-inspect(1)](podman-inspect.1.md) | Display a container, image, volume, network, or pod's configuration. | +| [podman-inspect(1)](podman-inspect.1.md) | Display artifact, container, image, volume, network, or pod's configuration. | | [podman-kill(1)](podman-kill.1.md) | Kill the main process in one or more containers. | | [podman-load(1)](podman-load.1.md) | Load image(s) from a tar archive into container storage. | | [podman-login(1)](podman-login.1.md) | Log in to a container registry. | diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go index 61f3f50f9d..7451ad57c6 100644 --- a/test/e2e/inspect_test.go +++ b/test/e2e/inspect_test.go @@ -597,4 +597,46 @@ var _ = Describe("Podman inspect", func() { Expect(session.OutputToString()).To(ContainSubstring(commandNotFound)) }) + It("podman inspect artifact", func() { + artifactFile, err := createArtifactFile(1024) + Expect(err).ToNot(HaveOccurred()) + + artifactName := "localhost/test/myartifact" + add := podmanTest.Podman([]string{"artifact", "add", artifactName, artifactFile}) + add.WaitWithDefaultTimeout() + Expect(add).Should(ExitCleanly()) + + // Test explicit artifact type + inspect := podmanTest.Podman([]string{"inspect", "--type", "artifact", artifactName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(ExitCleanly()) + Expect(inspect.OutputToString()).To(BeValidJSON()) + + // Test fallback to artifact when no other object type matches + inspect = podmanTest.Podman([]string{"inspect", artifactName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(ExitCleanly()) + Expect(inspect.OutputToString()).To(BeValidJSON()) + + // Verify that the output contains artifact-specific fields + Expect(inspect.OutputToString()).To(ContainSubstring("Manifest")) + Expect(inspect.OutputToString()).To(ContainSubstring("Digest")) + + // Test format with artifact-specific fields + inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.Name}}", artifactName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(ExitCleanly()) + Expect(inspect.OutputToString()).To(Equal(artifactName)) + + inspect2 := podmanTest.Podman([]string{"inspect", "--format", "{{.Digest}}", artifactName}) + inspect2.WaitWithDefaultTimeout() + Expect(inspect2).Should(ExitCleanly()) + Expect(inspect2.OutputToString()).To(ContainSubstring("sha256:")) + + // Clean up + rm := podmanTest.Podman([]string{"artifact", "rm", artifactName}) + rm.WaitWithDefaultTimeout() + Expect(rm).Should(ExitCleanly()) + }) + })