-
Notifications
You must be signed in to change notification settings - Fork 231
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
img inspect
command: dump the JSON for the image config to stdout (#…
…324) * inspect CLI: dump the JSON for the image config to stdout This CLI mimics `docker inspect`: it will print the OCI image config to stdout as raw JSON. This can be used with `jq` or other tools to extract useful metadata about an image. Similar to `img pull`, `img inspect` only takes _one_ image (unlike `docker inspect` which can take multiple and outputs an array). I felt it was more important to act like img than it was to act like Docker. * inspect: update help output to note incompatibility with docker inspect
- Loading branch information
Showing
4 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package client | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/containerd/containerd/content" | ||
"github.com/containerd/containerd/images" | ||
"github.com/docker/distribution/reference" | ||
ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
// InspectImage returns the metadata about a given image. | ||
func (c *Client) InspectImage(ctx context.Context, name string) (*ocispec.Image, error) { | ||
// Parse the image name and tag for the src image. | ||
named, err := reference.ParseNormalizedNamed(name) | ||
if err != nil { | ||
return nil, fmt.Errorf("parsing image name %q failed: %v", name, err) | ||
} | ||
|
||
// Add the latest lag if they did not provide one. | ||
named = reference.TagNameOnly(named) | ||
name = named.String() | ||
|
||
// Create the worker opts. | ||
opt, err := c.createWorkerOpt(false) | ||
if err != nil { | ||
return nil, fmt.Errorf("creating worker opt failed: %v", err) | ||
} | ||
|
||
if opt.ImageStore == nil { | ||
return nil, errors.New("image store is nil") | ||
} | ||
|
||
// Get the source image. | ||
image, err := opt.ImageStore.Get(ctx, name) | ||
if err != nil { | ||
return nil, fmt.Errorf("getting image %s from image store failed: %v", name, err) | ||
} | ||
|
||
var result ocispec.Image | ||
if err := images.Walk(ctx, images.Handlers( | ||
images.ChildrenHandler(opt.ContentStore), | ||
inspectHandler(opt.ContentStore, &result), | ||
), image.Target); err != nil { | ||
return nil, fmt.Errorf("error reading image %s: %v", name, err) | ||
} | ||
|
||
return &result, nil | ||
} | ||
|
||
func inspectHandler(provider content.Provider, result *ocispec.Image) images.Handler { | ||
return images.HandlerFunc(func( | ||
ctx context.Context, | ||
desc ocispec.Descriptor, | ||
) ([]ocispec.Descriptor, error) { | ||
// We only want the image config | ||
if desc.MediaType != images.MediaTypeDockerSchema2Config && | ||
desc.MediaType != ocispec.MediaTypeImageConfig { | ||
return nil, nil | ||
} | ||
|
||
p, err := content.ReadBlob(ctx, provider, desc) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return nil, json.Unmarshal(p, result) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/containerd/containerd/namespaces" | ||
"github.com/genuinetools/img/client" | ||
"github.com/moby/buildkit/identity" | ||
"github.com/moby/buildkit/session" | ||
) | ||
|
||
const inspectUsageShortHelp = `Return the JSON-encoded OCI image config. The output format is not compatible with "docker inspect".` | ||
const inspectUsageLongHelp = `Return the JSON-encoded OCI image config. The output format is not compatible with "docker inspect".` | ||
|
||
func newInspectCommand() *cobra.Command { | ||
inspect := &inspectCommand{} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "inspect NAME[:TAG]", | ||
DisableFlagsInUseLine: true, | ||
SilenceUsage: true, | ||
Short: inspectUsageShortHelp, | ||
Long: inspectUsageLongHelp, | ||
Args: inspect.ValidateArgs, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
return inspect.Run(args) | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
type inspectCommand struct { | ||
image string | ||
} | ||
|
||
func (cmd *inspectCommand) ValidateArgs(c *cobra.Command, args []string) error { | ||
if len(args) < 1 { | ||
return fmt.Errorf("must pass an image to inspect") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (cmd *inspectCommand) Run(args []string) (err error) { | ||
reexec() | ||
|
||
// Get the specified image and target. | ||
cmd.image = args[0] | ||
|
||
// Create the context. | ||
id := identity.NewID() | ||
ctx := session.NewContext(context.Background(), id) | ||
ctx = namespaces.WithNamespace(ctx, "buildkit") | ||
|
||
// Create the client. | ||
c, err := client.New(stateDir, backend, nil) | ||
if err != nil { | ||
return err | ||
} | ||
defer c.Close() | ||
|
||
image, err := c.InspectImage(ctx, cmd.image) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmted, err := json.MarshalIndent(image, "", "\t") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println(string(fmted)) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"reflect" | ||
"testing" | ||
|
||
ocispec "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
func TestInspectImage(t *testing.T) { | ||
runBuild(t, "inspectthing", withDockerfile(` | ||
FROM busybox | ||
ENTRYPOINT ["echo"] | ||
`)) | ||
|
||
out := run(t, "inspect", "inspectthing") | ||
|
||
var image ocispec.Image | ||
if err := json.Unmarshal([]byte(out), &image); err != nil { | ||
t.Fatalf("error decoding JSON: %s", err) | ||
} | ||
|
||
if !reflect.DeepEqual(image.Config.Entrypoint, []string{"echo"}) { | ||
t.Fatalf("expected entrypoint to be set: %#v", image) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters