Merge pull request #698 from nalind/kpod-updates
kpod: avoid digging into unpublished formats
This commit is contained in:
commit
9dbd60a0df
4 changed files with 68 additions and 155 deletions
|
@ -6,8 +6,8 @@ import (
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/kubernetes-incubator/cri-o/libkpod/image"
|
|
||||||
libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image"
|
libkpodimage "github.com/kubernetes-incubator/cri-o/libkpod/image"
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,7 @@ import (
|
||||||
type imageOutputParams struct {
|
type imageOutputParams struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Digest string
|
Digest digest.Digest
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
Size string
|
Size string
|
||||||
}
|
}
|
||||||
|
@ -132,16 +132,14 @@ func outputHeader(truncate, digests bool) {
|
||||||
|
|
||||||
func outputImages(store storage.Store, images []storage.Image, format string, hasTemplate, truncate, digests, quiet bool) error {
|
func outputImages(store storage.Store, images []storage.Image, format string, hasTemplate, truncate, digests, quiet bool) error {
|
||||||
for _, img := range images {
|
for _, img := range images {
|
||||||
imageMetadata, err := image.ParseMetadata(img)
|
createdTime := img.Created.Format("Jan 2, 2006 15:04")
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
name := ""
|
||||||
|
if len(img.Names) > 0 {
|
||||||
|
name = img.Names[0]
|
||||||
}
|
}
|
||||||
createdTime := imageMetadata.CreatedTime.Format("Jan 2, 2006 15:04")
|
|
||||||
digest := ""
|
digest, size, _ := libkpodimage.DigestAndSize(store, img)
|
||||||
if len(imageMetadata.Blobs) > 0 {
|
|
||||||
digest = string(imageMetadata.Blobs[0].Digest)
|
|
||||||
}
|
|
||||||
size, _ := libkpodimage.Size(store, img)
|
|
||||||
|
|
||||||
if quiet {
|
if quiet {
|
||||||
fmt.Printf("%-64s\n", img.ID)
|
fmt.Printf("%-64s\n", img.ID)
|
||||||
|
@ -151,14 +149,13 @@ func outputImages(store storage.Store, images []storage.Image, format string, ha
|
||||||
|
|
||||||
params := imageOutputParams{
|
params := imageOutputParams{
|
||||||
ID: img.ID,
|
ID: img.ID,
|
||||||
Name: img.Names[0],
|
Name: name,
|
||||||
Digest: digest,
|
Digest: digest,
|
||||||
CreatedAt: createdTime,
|
CreatedAt: createdTime,
|
||||||
Size: libkpodimage.FormattedSize(size),
|
Size: libkpodimage.FormattedSize(size),
|
||||||
}
|
}
|
||||||
if hasTemplate {
|
if hasTemplate {
|
||||||
err = outputUsingTemplate(format, params)
|
if err := outputUsingTemplate(format, params); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
is "github.com/containers/image/storage"
|
is "github.com/containers/image/storage"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
"github.com/kubernetes-incubator/cri-o/libkpod/common"
|
"github.com/kubernetes-incubator/cri-o/libkpod/common"
|
||||||
|
digest "github.com/opencontainers/go-digest"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,13 +42,13 @@ func ParseFilter(store storage.Store, filter string) (*FilterParams, error) {
|
||||||
params.label = pair[1]
|
params.label = pair[1]
|
||||||
case "before":
|
case "before":
|
||||||
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
||||||
params.beforeImage, _ = getCreatedTime(img)
|
params.beforeImage = img.Created
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("no such id: %s", pair[0])
|
return nil, fmt.Errorf("no such id: %s", pair[0])
|
||||||
}
|
}
|
||||||
case "since":
|
case "since":
|
||||||
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
if img, err := findImageInSlice(images, pair[1]); err == nil {
|
||||||
params.sinceImage, _ = getCreatedTime(img)
|
params.sinceImage = img.Created
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("no such id: %s``", pair[0])
|
return nil, fmt.Errorf("no such id: %s``", pair[0])
|
||||||
}
|
}
|
||||||
|
@ -123,11 +124,7 @@ func matchesBeforeImage(image storage.Image, name string, params *FilterParams)
|
||||||
if params.beforeImage.IsZero() {
|
if params.beforeImage.IsZero() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
createdTime, err := getCreatedTime(image)
|
if image.Created.Before(params.beforeImage) {
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if createdTime.Before(params.beforeImage) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -139,11 +136,7 @@ func matchesSinceImage(image storage.Image, name string, params *FilterParams) b
|
||||||
if params.sinceImage.IsZero() {
|
if params.sinceImage.IsZero() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
createdTime, err := getCreatedTime(image)
|
if image.Created.After(params.sinceImage) {
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if createdTime.After(params.beforeImage) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -219,43 +212,32 @@ func findImageInSlice(images []storage.Image, ref string) (storage.Image, error)
|
||||||
return storage.Image{}, errors.New("could not find image")
|
return storage.Image{}, errors.New("could not find image")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the size of the image in the given store
|
// DigestAndSize returns the size of the image in the given store and the
|
||||||
func Size(store storage.Store, img storage.Image) (int64, error) {
|
// digest of its manifest, if it has one, or "" if it doesn't.
|
||||||
|
func DigestAndSize(store storage.Store, img storage.Image) (digest.Digest, int64, error) {
|
||||||
is.Transport.SetStore(store)
|
is.Transport.SetStore(store)
|
||||||
storeRef, err := is.Transport.ParseStoreReference(store, "@"+img.ID)
|
storeRef, err := is.Transport.ParseStoreReference(store, "@"+img.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return "", -1, errors.Wrapf(err, "error parsing image reference %q", "@"+img.ID)
|
||||||
}
|
}
|
||||||
imgRef, err := storeRef.NewImage(nil)
|
imgRef, err := storeRef.NewImage(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return "", -1, errors.Wrapf(err, "error reading image %q", img.ID)
|
||||||
}
|
}
|
||||||
defer imgRef.Close()
|
defer imgRef.Close()
|
||||||
imgSize, err := imgRef.Size()
|
imgSize, err := imgRef.Size()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return "", -1, errors.Wrapf(err, "error reading size of image %q", img.ID)
|
||||||
}
|
}
|
||||||
return imgSize, nil
|
manifest, _, err := imgRef.Manifest()
|
||||||
}
|
|
||||||
|
|
||||||
// GetTopLayerID returns the ID of the top layer of the image
|
|
||||||
func GetTopLayerID(img storage.Image) (string, error) {
|
|
||||||
metadata, err := ParseMetadata(img)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", -1, errors.Wrapf(err, "error reading manifest for image %q", img.ID)
|
||||||
}
|
}
|
||||||
// Get the digest of the first blob
|
manifestDigest := digest.Digest("")
|
||||||
digest := string(metadata.Blobs[0].Digest)
|
if len(manifest) > 0 {
|
||||||
// Return the first layer associated with the given digest
|
manifestDigest = digest.Canonical.FromBytes(manifest)
|
||||||
return metadata.Layers[digest][0], nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCreatedTime(image storage.Image) (time.Time, error) {
|
|
||||||
metadata, err := ParseMetadata(image)
|
|
||||||
if err != nil {
|
|
||||||
return time.Time{}, err
|
|
||||||
}
|
}
|
||||||
return metadata.CreatedTime, nil
|
return manifestDigest, imgSize, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImagesMatchingFilter returns a slice of all images in the store that match the provided FilterParams.
|
// GetImagesMatchingFilter returns a slice of all images in the store that match the provided FilterParams.
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/containers/image/docker/reference"
|
||||||
"github.com/containers/storage"
|
"github.com/containers/storage"
|
||||||
|
"github.com/kubernetes-incubator/cri-o/cmd/kpod/docker"
|
||||||
"github.com/kubernetes-incubator/cri-o/libkpod/driver"
|
"github.com/kubernetes-incubator/cri-o/libkpod/driver"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
@ -15,13 +16,14 @@ import (
|
||||||
// nolint
|
// nolint
|
||||||
type ImageData struct {
|
type ImageData struct {
|
||||||
ID string
|
ID string
|
||||||
Names []string
|
Tags []string
|
||||||
Digests []digest.Digest
|
Digests []string
|
||||||
|
Digest digest.Digest
|
||||||
Parent string
|
Parent string
|
||||||
Comment string
|
Comment string
|
||||||
Created *time.Time
|
Created *time.Time
|
||||||
Container string
|
Container string
|
||||||
ContainerConfig containerConfig
|
ContainerConfig docker.Config
|
||||||
Author string
|
Author string
|
||||||
Config ociv1.ImageConfig
|
Config ociv1.ImageConfig
|
||||||
Architecture string
|
Architecture string
|
||||||
|
@ -32,30 +34,30 @@ type ImageData struct {
|
||||||
RootFS ociv1.RootFS
|
RootFS ociv1.RootFS
|
||||||
}
|
}
|
||||||
|
|
||||||
type containerConfig struct {
|
// ParseImageNames parses the names we've stored with an image into a list of
|
||||||
Hostname string
|
// tagged references and a list of references which contain digests.
|
||||||
Domainname string
|
func ParseImageNames(names []string) (tags, digests []string, err error) {
|
||||||
User string
|
for _, name := range names {
|
||||||
AttachStdin bool
|
if named, err := reference.ParseNamed(name); err == nil {
|
||||||
AttachStdout bool
|
if digested, ok := named.(reference.Digested); ok {
|
||||||
AttachStderr bool
|
canonical, err := reference.WithDigest(named, digested.Digest())
|
||||||
Tty bool
|
if err == nil {
|
||||||
OpenStdin bool
|
digests = append(digests, canonical.String())
|
||||||
StdinOnce bool
|
}
|
||||||
Env []string
|
} else {
|
||||||
Cmd []string
|
if reference.IsNameOnly(named) {
|
||||||
ArgsEscaped bool
|
named = reference.TagNameOnly(named)
|
||||||
Image digest.Digest
|
}
|
||||||
Volumes map[string]interface{}
|
if tagged, ok := named.(reference.Tagged); ok {
|
||||||
WorkingDir string
|
namedTagged, err := reference.WithTag(named, tagged.Tag())
|
||||||
Entrypoint []string
|
if err == nil {
|
||||||
Labels interface{}
|
tags = append(tags, namedTagged.String())
|
||||||
OnBuild []string
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
type rootFS struct {
|
}
|
||||||
Type string
|
}
|
||||||
Layers []string
|
return tags, digests, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetImageData gets the ImageData for a container with the given name in the given store.
|
// GetImageData gets the ImageData for a container with the given name in the given store.
|
||||||
|
@ -69,33 +71,10 @@ func GetImageData(store storage.Store, name string) (*ImageData, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "error reading image %q", name)
|
return nil, errors.Wrapf(err, "error reading image %q", name)
|
||||||
}
|
}
|
||||||
digests, err := getDigests(*img)
|
|
||||||
|
tags, digests, err := ParseImageNames(img.Names)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrapf(err, "error parsing image names for %q", name)
|
||||||
}
|
|
||||||
|
|
||||||
var bigData interface{}
|
|
||||||
ctrConfig := containerConfig{}
|
|
||||||
container := ""
|
|
||||||
if len(digests) > 0 {
|
|
||||||
bd, err := store.ImageBigData(img.ID, string(digests[len(digests)-1]))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(bd, &bigData)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
container = (bigData.(map[string]interface{})["container"]).(string)
|
|
||||||
cc, err := json.MarshalIndent((bigData.(map[string]interface{})["container_config"]).(map[string]interface{}), "", " ")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(cc, &ctrConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
driverName, err := driver.GetDriverName(store)
|
driverName, err := driver.GetDriverName(store)
|
||||||
|
@ -103,10 +82,8 @@ func GetImageData(store storage.Store, name string) (*ImageData, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
topLayerID, err := GetTopLayerID(*img)
|
topLayerID := img.TopLayer
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
driverMetadata, err := driver.GetDriverMetadata(store, topLayerID)
|
driverMetadata, err := driver.GetDriverMetadata(store, topLayerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -121,20 +98,21 @@ func GetImageData(store storage.Store, name string) (*ImageData, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
virtualSize, err := Size(store, *img)
|
digest, virtualSize, err := DigestAndSize(store, *img)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ImageData{
|
return &ImageData{
|
||||||
ID: img.ID,
|
ID: img.ID,
|
||||||
Names: img.Names,
|
Tags: tags,
|
||||||
Digests: digests,
|
Digests: digests,
|
||||||
|
Digest: digest,
|
||||||
Parent: string(cid.Docker.Parent),
|
Parent: string(cid.Docker.Parent),
|
||||||
Comment: cid.OCIv1.History[0].Comment,
|
Comment: cid.OCIv1.History[0].Comment,
|
||||||
Created: cid.OCIv1.Created,
|
Created: cid.OCIv1.Created,
|
||||||
Container: container,
|
Container: cid.Docker.Container,
|
||||||
ContainerConfig: ctrConfig,
|
ContainerConfig: cid.Docker.ContainerConfig,
|
||||||
Author: cid.OCIv1.Author,
|
Author: cid.OCIv1.Author,
|
||||||
Config: cid.OCIv1.Config,
|
Config: cid.OCIv1.Config,
|
||||||
Architecture: cid.OCIv1.Architecture,
|
Architecture: cid.OCIv1.Architecture,
|
||||||
|
@ -148,15 +126,3 @@ func GetImageData(store storage.Store, name string) (*ImageData, error) {
|
||||||
RootFS: cid.OCIv1.RootFS,
|
RootFS: cid.OCIv1.RootFS,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDigests(img storage.Image) ([]digest.Digest, error) {
|
|
||||||
metadata, err := ParseMetadata(img)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
digests := []digest.Digest{}
|
|
||||||
for _, blob := range metadata.Blobs {
|
|
||||||
digests = append(digests, blob.Digest)
|
|
||||||
}
|
|
||||||
return digests, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
package image
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/containers/image/types"
|
|
||||||
"github.com/containers/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Metadata stores all of the metadata for an image
|
|
||||||
type Metadata struct {
|
|
||||||
Tag string `json:"tag"`
|
|
||||||
CreatedTime time.Time `json:"created-time"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
Blobs []types.BlobInfo `json:"blob-list"`
|
|
||||||
Layers map[string][]string `json:"layers"`
|
|
||||||
SignatureSizes []string `json:"signature-sizes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseMetadata takes an image, parses the json stored in it's metadata
|
|
||||||
// field, and converts it to a Metadata struct
|
|
||||||
func ParseMetadata(image storage.Image) (Metadata, error) {
|
|
||||||
var m Metadata
|
|
||||||
|
|
||||||
dec := json.NewDecoder(strings.NewReader(image.Metadata))
|
|
||||||
if err := dec.Decode(&m); err != nil {
|
|
||||||
return Metadata{}, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue