Merge pull request #698 from nalind/kpod-updates

kpod: avoid digging into unpublished formats
This commit is contained in:
Mrunal Patel 2017-07-27 10:20:46 -07:00 committed by GitHub
commit 9dbd60a0df
4 changed files with 68 additions and 155 deletions

View file

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

View file

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

View file

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

View file

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