Add artifact fallback to podman inspect command

This commit implements automatic artifact fallback for the podman inspect command
as requested in GitHub issue #27075.

Changes made:
- Add ArtifactType constant to cmd/podman/common/inspect.go
- Update AutocompleteInspectType to include artifact type in completions
- Add artifact case to main inspect switch statement for explicit --type artifact
- Implement artifact fallback in inspectAll function for automatic detection
- Update shell completion to recognize artifacts in getEntityType function
- Update command help text, usage, and examples to include artifacts
- Update podman-inspect.1.md man page with artifact documentation
- Add comprehensive e2e tests for artifact inspect functionality

The inspect command now automatically falls back to artifact inspection when
no container, image, volume, network, or pod matches the specified name.
Users can also explicitly use --type artifact for direct artifact inspection.

This maintains backward compatibility while extending functionality to support
the artifact object type seamlessly.

Examples:
  podman inspect myartifact                        # Auto-detects artifact
  podman inspect --type artifact myartifact       # Explicit artifact type
  podman inspect --format '{{.Name}}' myartifact  # Format support

Fixes: https://github.com/containers/podman/issues/27075
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh
2025-10-02 06:52:32 -04:00
parent e47ae6741a
commit 6405925f79
7 changed files with 89 additions and 10 deletions

View File

@ -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
}

View File

@ -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.

View File

@ -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`,
}

View File

@ -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

View File

@ -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 <dwalsh@redhat.com>

View File

@ -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. |

View File

@ -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())
})
})