mirror of https://github.com/docker/docs.git
Move some image related methods & struct to smaller files
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
parent
e3079b4704
commit
d5baf8ddcf
277
daemon/daemon.go
277
daemon/daemon.go
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
containerd "github.com/docker/containerd/api/grpc/types"
|
containerd "github.com/docker/containerd/api/grpc/types"
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/docker/docker/builder"
|
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
"github.com/docker/docker/daemon/events"
|
"github.com/docker/docker/daemon/events"
|
||||||
"github.com/docker/docker/daemon/exec"
|
"github.com/docker/docker/daemon/exec"
|
||||||
|
|
@ -41,7 +40,6 @@ import (
|
||||||
"github.com/docker/docker/distribution/xfer"
|
"github.com/docker/docker/distribution/xfer"
|
||||||
"github.com/docker/docker/dockerversion"
|
"github.com/docker/docker/dockerversion"
|
||||||
"github.com/docker/docker/image"
|
"github.com/docker/docker/image"
|
||||||
"github.com/docker/docker/image/tarexport"
|
|
||||||
"github.com/docker/docker/layer"
|
"github.com/docker/docker/layer"
|
||||||
"github.com/docker/docker/libcontainerd"
|
"github.com/docker/docker/libcontainerd"
|
||||||
"github.com/docker/docker/migrate/v1"
|
"github.com/docker/docker/migrate/v1"
|
||||||
|
|
@ -80,15 +78,6 @@ var (
|
||||||
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.")
|
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
|
||||||
type ErrImageDoesNotExist struct {
|
|
||||||
RefOrID string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ErrImageDoesNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("no such id: %s", e.RefOrID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Daemon holds information about the Docker daemon.
|
// Daemon holds information about the Docker daemon.
|
||||||
type Daemon struct {
|
type Daemon struct {
|
||||||
ID string
|
ID string
|
||||||
|
|
@ -1008,221 +997,6 @@ func isBrokenPipe(e error) bool {
|
||||||
return e == syscall.EPIPE
|
return e == syscall.EPIPE
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportImage exports a list of images to the given output stream. The
|
|
||||||
// exported images are archived into a tar when written to the output
|
|
||||||
// stream. All images with the given tag and all versions containing
|
|
||||||
// the same tag are exported. names is the set of tags to export, and
|
|
||||||
// outStream is the writer which the images are written to.
|
|
||||||
func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
|
||||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
|
||||||
return imageExporter.Save(names, outStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LookupImage looks up an image by name and returns it as an ImageInspect
|
|
||||||
// structure.
|
|
||||||
func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
|
||||||
img, err := daemon.GetImage(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("No such image: %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
refs := daemon.referenceStore.References(img.ID())
|
|
||||||
repoTags := []string{}
|
|
||||||
repoDigests := []string{}
|
|
||||||
for _, ref := range refs {
|
|
||||||
switch ref.(type) {
|
|
||||||
case reference.NamedTagged:
|
|
||||||
repoTags = append(repoTags, ref.String())
|
|
||||||
case reference.Canonical:
|
|
||||||
repoDigests = append(repoDigests, ref.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var size int64
|
|
||||||
var layerMetadata map[string]string
|
|
||||||
layerID := img.RootFS.ChainID()
|
|
||||||
if layerID != "" {
|
|
||||||
l, err := daemon.layerStore.Get(layerID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer layer.ReleaseAndLog(daemon.layerStore, l)
|
|
||||||
size, err = l.Size()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
layerMetadata, err = l.Metadata()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
comment := img.Comment
|
|
||||||
if len(comment) == 0 && len(img.History) > 0 {
|
|
||||||
comment = img.History[len(img.History)-1].Comment
|
|
||||||
}
|
|
||||||
|
|
||||||
imageInspect := &types.ImageInspect{
|
|
||||||
ID: img.ID().String(),
|
|
||||||
RepoTags: repoTags,
|
|
||||||
RepoDigests: repoDigests,
|
|
||||||
Parent: img.Parent.String(),
|
|
||||||
Comment: comment,
|
|
||||||
Created: img.Created.Format(time.RFC3339Nano),
|
|
||||||
Container: img.Container,
|
|
||||||
ContainerConfig: &img.ContainerConfig,
|
|
||||||
DockerVersion: img.DockerVersion,
|
|
||||||
Author: img.Author,
|
|
||||||
Config: img.Config,
|
|
||||||
Architecture: img.Architecture,
|
|
||||||
Os: img.OS,
|
|
||||||
Size: size,
|
|
||||||
VirtualSize: size, // TODO: field unused, deprecate
|
|
||||||
RootFS: rootFSToAPIType(img.RootFS),
|
|
||||||
}
|
|
||||||
|
|
||||||
imageInspect.GraphDriver.Name = daemon.GraphDriverName()
|
|
||||||
|
|
||||||
imageInspect.GraphDriver.Data = layerMetadata
|
|
||||||
|
|
||||||
return imageInspect, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadImage uploads a set of images into the repository. This is the
|
|
||||||
// complement of ImageExport. The input stream is an uncompressed tar
|
|
||||||
// ball containing images and metadata.
|
|
||||||
func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
|
|
||||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
|
||||||
return imageExporter.Load(inTar, outStream, quiet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImageHistory returns a slice of ImageHistory structures for the specified image
|
|
||||||
// name by walking the image lineage.
|
|
||||||
func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
|
|
||||||
img, err := daemon.GetImage(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
history := []*types.ImageHistory{}
|
|
||||||
|
|
||||||
layerCounter := 0
|
|
||||||
rootFS := *img.RootFS
|
|
||||||
rootFS.DiffIDs = nil
|
|
||||||
|
|
||||||
for _, h := range img.History {
|
|
||||||
var layerSize int64
|
|
||||||
|
|
||||||
if !h.EmptyLayer {
|
|
||||||
if len(img.RootFS.DiffIDs) <= layerCounter {
|
|
||||||
return nil, fmt.Errorf("too many non-empty layers in History section")
|
|
||||||
}
|
|
||||||
|
|
||||||
rootFS.Append(img.RootFS.DiffIDs[layerCounter])
|
|
||||||
l, err := daemon.layerStore.Get(rootFS.ChainID())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
layerSize, err = l.DiffSize()
|
|
||||||
layer.ReleaseAndLog(daemon.layerStore, l)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
layerCounter++
|
|
||||||
}
|
|
||||||
|
|
||||||
history = append([]*types.ImageHistory{{
|
|
||||||
ID: "<missing>",
|
|
||||||
Created: h.Created.Unix(),
|
|
||||||
CreatedBy: h.CreatedBy,
|
|
||||||
Comment: h.Comment,
|
|
||||||
Size: layerSize,
|
|
||||||
}}, history...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in image IDs and tags
|
|
||||||
histImg := img
|
|
||||||
id := img.ID()
|
|
||||||
for _, h := range history {
|
|
||||||
h.ID = id.String()
|
|
||||||
|
|
||||||
var tags []string
|
|
||||||
for _, r := range daemon.referenceStore.References(id) {
|
|
||||||
if _, ok := r.(reference.NamedTagged); ok {
|
|
||||||
tags = append(tags, r.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Tags = tags
|
|
||||||
|
|
||||||
id = histImg.Parent
|
|
||||||
if id == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
histImg, err = daemon.GetImage(id.String())
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return history, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImageID returns an image ID corresponding to the image referred to by
|
|
||||||
// refOrID.
|
|
||||||
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
|
||||||
id, ref, err := reference.ParseIDOrReference(refOrID)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if id != "" {
|
|
||||||
if _, err := daemon.imageStore.Get(image.ID(id)); err != nil {
|
|
||||||
return "", ErrImageDoesNotExist{refOrID}
|
|
||||||
}
|
|
||||||
return image.ID(id), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if id, err := daemon.referenceStore.Get(ref); err == nil {
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
if tagged, ok := ref.(reference.NamedTagged); ok {
|
|
||||||
if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil {
|
|
||||||
for _, namedRef := range daemon.referenceStore.References(id) {
|
|
||||||
if namedRef.Name() == ref.Name() {
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search based on ID
|
|
||||||
if id, err := daemon.imageStore.Search(refOrID); err == nil {
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", ErrImageDoesNotExist{refOrID}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
|
||||||
func (daemon *Daemon) GetImage(refOrID string) (*image.Image, error) {
|
|
||||||
imgID, err := daemon.GetImageID(refOrID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return daemon.imageStore.Get(imgID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetImageOnBuild looks up a Docker image referenced by `name`.
|
|
||||||
func (daemon *Daemon) GetImageOnBuild(name string) (builder.Image, error) {
|
|
||||||
img, err := daemon.GetImage(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return img, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GraphDriverName returns the name of the graph driver used by the layer.Store
|
// GraphDriverName returns the name of the graph driver used by the layer.Store
|
||||||
func (daemon *Daemon) GraphDriverName() string {
|
func (daemon *Daemon) GraphDriverName() string {
|
||||||
return daemon.layerStore.DriverName()
|
return daemon.layerStore.DriverName()
|
||||||
|
|
@ -1243,57 +1017,6 @@ func (daemon *Daemon) GetRemappedUIDGID() (int, int) {
|
||||||
return uid, gid
|
return uid, gid
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCachedImage returns the most recent created image that is a child
|
|
||||||
// of the image with imgID, that had the same config when it was
|
|
||||||
// created. nil is returned if a child cannot be found. An error is
|
|
||||||
// returned if the parent image cannot be found.
|
|
||||||
func (daemon *Daemon) GetCachedImage(imgID image.ID, config *containertypes.Config) (*image.Image, error) {
|
|
||||||
// Loop on the children of the given image and check the config
|
|
||||||
getMatch := func(siblings []image.ID) (*image.Image, error) {
|
|
||||||
var match *image.Image
|
|
||||||
for _, id := range siblings {
|
|
||||||
img, err := daemon.imageStore.Get(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to find image %q", id)
|
|
||||||
}
|
|
||||||
|
|
||||||
if runconfig.Compare(&img.ContainerConfig, config) {
|
|
||||||
// check for the most up to date match
|
|
||||||
if match == nil || match.Created.Before(img.Created) {
|
|
||||||
match = img
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return match, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// In this case, this is `FROM scratch`, which isn't an actual image.
|
|
||||||
if imgID == "" {
|
|
||||||
images := daemon.imageStore.Map()
|
|
||||||
var siblings []image.ID
|
|
||||||
for id, img := range images {
|
|
||||||
if img.Parent == imgID {
|
|
||||||
siblings = append(siblings, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getMatch(siblings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// find match from child images
|
|
||||||
siblings := daemon.imageStore.Children(imgID)
|
|
||||||
return getMatch(siblings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCachedImageOnBuild returns a reference to a cached image whose parent equals `parent`
|
|
||||||
// and runconfig equals `cfg`. A cache miss is expected to return an empty ID and a nil error.
|
|
||||||
func (daemon *Daemon) GetCachedImageOnBuild(imgID string, cfg *containertypes.Config) (string, error) {
|
|
||||||
cache, err := daemon.GetCachedImage(image.ID(imgID), cfg)
|
|
||||||
if cache == nil || err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return cache.ID().String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// tempDir returns the default directory to use for temporary files.
|
// tempDir returns the default directory to use for temporary files.
|
||||||
func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
|
func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
|
||||||
var tmpDir string
|
var tmpDir string
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/docker/docker/builder"
|
||||||
|
"github.com/docker/docker/image"
|
||||||
|
"github.com/docker/docker/reference"
|
||||||
|
"github.com/docker/docker/runconfig"
|
||||||
|
containertypes "github.com/docker/engine-api/types/container"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
|
||||||
|
type ErrImageDoesNotExist struct {
|
||||||
|
RefOrID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrImageDoesNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("no such id: %s", e.RefOrID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageID returns an image ID corresponding to the image referred to by
|
||||||
|
// refOrID.
|
||||||
|
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
|
||||||
|
id, ref, err := reference.ParseIDOrReference(refOrID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if id != "" {
|
||||||
|
if _, err := daemon.imageStore.Get(image.ID(id)); err != nil {
|
||||||
|
return "", ErrImageDoesNotExist{refOrID}
|
||||||
|
}
|
||||||
|
return image.ID(id), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if id, err := daemon.referenceStore.Get(ref); err == nil {
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
if tagged, ok := ref.(reference.NamedTagged); ok {
|
||||||
|
if id, err := daemon.imageStore.Search(tagged.Tag()); err == nil {
|
||||||
|
for _, namedRef := range daemon.referenceStore.References(id) {
|
||||||
|
if namedRef.Name() == ref.Name() {
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search based on ID
|
||||||
|
if id, err := daemon.imageStore.Search(refOrID); err == nil {
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", ErrImageDoesNotExist{refOrID}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||||
|
func (daemon *Daemon) GetImage(refOrID string) (*image.Image, error) {
|
||||||
|
imgID, err := daemon.GetImageID(refOrID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return daemon.imageStore.Get(imgID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetImageOnBuild looks up a Docker image referenced by `name`.
|
||||||
|
func (daemon *Daemon) GetImageOnBuild(name string) (builder.Image, error) {
|
||||||
|
img, err := daemon.GetImage(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return img, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCachedImage returns the most recent created image that is a child
|
||||||
|
// of the image with imgID, that had the same config when it was
|
||||||
|
// created. nil is returned if a child cannot be found. An error is
|
||||||
|
// returned if the parent image cannot be found.
|
||||||
|
func (daemon *Daemon) GetCachedImage(imgID image.ID, config *containertypes.Config) (*image.Image, error) {
|
||||||
|
// Loop on the children of the given image and check the config
|
||||||
|
getMatch := func(siblings []image.ID) (*image.Image, error) {
|
||||||
|
var match *image.Image
|
||||||
|
for _, id := range siblings {
|
||||||
|
img, err := daemon.imageStore.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to find image %q", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if runconfig.Compare(&img.ContainerConfig, config) {
|
||||||
|
// check for the most up to date match
|
||||||
|
if match == nil || match.Created.Before(img.Created) {
|
||||||
|
match = img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// In this case, this is `FROM scratch`, which isn't an actual image.
|
||||||
|
if imgID == "" {
|
||||||
|
images := daemon.imageStore.Map()
|
||||||
|
var siblings []image.ID
|
||||||
|
for id, img := range images {
|
||||||
|
if img.Parent == imgID {
|
||||||
|
siblings = append(siblings, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getMatch(siblings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find match from child images
|
||||||
|
siblings := daemon.imageStore.Children(imgID)
|
||||||
|
return getMatch(siblings)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCachedImageOnBuild returns a reference to a cached image whose parent equals `parent`
|
||||||
|
// and runconfig equals `cfg`. A cache miss is expected to return an empty ID and a nil error.
|
||||||
|
func (daemon *Daemon) GetCachedImageOnBuild(imgID string, cfg *containertypes.Config) (string, error) {
|
||||||
|
cache, err := daemon.GetCachedImage(image.ID(imgID), cfg)
|
||||||
|
if cache == nil || err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return cache.ID().String(), nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/docker/docker/image/tarexport"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExportImage exports a list of images to the given output stream. The
|
||||||
|
// exported images are archived into a tar when written to the output
|
||||||
|
// stream. All images with the given tag and all versions containing
|
||||||
|
// the same tag are exported. names is the set of tags to export, and
|
||||||
|
// outStream is the writer which the images are written to.
|
||||||
|
func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
||||||
|
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
||||||
|
return imageExporter.Save(names, outStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadImage uploads a set of images into the repository. This is the
|
||||||
|
// complement of ImageExport. The input stream is an uncompressed tar
|
||||||
|
// ball containing images and metadata.
|
||||||
|
func (daemon *Daemon) LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error {
|
||||||
|
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStore, daemon.referenceStore, daemon)
|
||||||
|
return imageExporter.Load(inTar, outStream, quiet)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/docker/docker/layer"
|
||||||
|
"github.com/docker/docker/reference"
|
||||||
|
"github.com/docker/engine-api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImageHistory returns a slice of ImageHistory structures for the specified image
|
||||||
|
// name by walking the image lineage.
|
||||||
|
func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
|
||||||
|
img, err := daemon.GetImage(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
history := []*types.ImageHistory{}
|
||||||
|
|
||||||
|
layerCounter := 0
|
||||||
|
rootFS := *img.RootFS
|
||||||
|
rootFS.DiffIDs = nil
|
||||||
|
|
||||||
|
for _, h := range img.History {
|
||||||
|
var layerSize int64
|
||||||
|
|
||||||
|
if !h.EmptyLayer {
|
||||||
|
if len(img.RootFS.DiffIDs) <= layerCounter {
|
||||||
|
return nil, fmt.Errorf("too many non-empty layers in History section")
|
||||||
|
}
|
||||||
|
|
||||||
|
rootFS.Append(img.RootFS.DiffIDs[layerCounter])
|
||||||
|
l, err := daemon.layerStore.Get(rootFS.ChainID())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
layerSize, err = l.DiffSize()
|
||||||
|
layer.ReleaseAndLog(daemon.layerStore, l)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
layerCounter++
|
||||||
|
}
|
||||||
|
|
||||||
|
history = append([]*types.ImageHistory{{
|
||||||
|
ID: "<missing>",
|
||||||
|
Created: h.Created.Unix(),
|
||||||
|
CreatedBy: h.CreatedBy,
|
||||||
|
Comment: h.Comment,
|
||||||
|
Size: layerSize,
|
||||||
|
}}, history...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in image IDs and tags
|
||||||
|
histImg := img
|
||||||
|
id := img.ID()
|
||||||
|
for _, h := range history {
|
||||||
|
h.ID = id.String()
|
||||||
|
|
||||||
|
var tags []string
|
||||||
|
for _, r := range daemon.referenceStore.References(id) {
|
||||||
|
if _, ok := r.(reference.NamedTagged); ok {
|
||||||
|
tags = append(tags, r.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h.Tags = tags
|
||||||
|
|
||||||
|
id = histImg.Parent
|
||||||
|
if id == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
histImg, err = daemon.GetImage(id.String())
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return history, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
package daemon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/docker/layer"
|
||||||
|
"github.com/docker/docker/reference"
|
||||||
|
"github.com/docker/engine-api/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LookupImage looks up an image by name and returns it as an ImageInspect
|
||||||
|
// structure.
|
||||||
|
func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||||
|
img, err := daemon.GetImage(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("No such image: %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
refs := daemon.referenceStore.References(img.ID())
|
||||||
|
repoTags := []string{}
|
||||||
|
repoDigests := []string{}
|
||||||
|
for _, ref := range refs {
|
||||||
|
switch ref.(type) {
|
||||||
|
case reference.NamedTagged:
|
||||||
|
repoTags = append(repoTags, ref.String())
|
||||||
|
case reference.Canonical:
|
||||||
|
repoDigests = append(repoDigests, ref.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var size int64
|
||||||
|
var layerMetadata map[string]string
|
||||||
|
layerID := img.RootFS.ChainID()
|
||||||
|
if layerID != "" {
|
||||||
|
l, err := daemon.layerStore.Get(layerID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer layer.ReleaseAndLog(daemon.layerStore, l)
|
||||||
|
size, err = l.Size()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
layerMetadata, err = l.Metadata()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comment := img.Comment
|
||||||
|
if len(comment) == 0 && len(img.History) > 0 {
|
||||||
|
comment = img.History[len(img.History)-1].Comment
|
||||||
|
}
|
||||||
|
|
||||||
|
imageInspect := &types.ImageInspect{
|
||||||
|
ID: img.ID().String(),
|
||||||
|
RepoTags: repoTags,
|
||||||
|
RepoDigests: repoDigests,
|
||||||
|
Parent: img.Parent.String(),
|
||||||
|
Comment: comment,
|
||||||
|
Created: img.Created.Format(time.RFC3339Nano),
|
||||||
|
Container: img.Container,
|
||||||
|
ContainerConfig: &img.ContainerConfig,
|
||||||
|
DockerVersion: img.DockerVersion,
|
||||||
|
Author: img.Author,
|
||||||
|
Config: img.Config,
|
||||||
|
Architecture: img.Architecture,
|
||||||
|
Os: img.OS,
|
||||||
|
Size: size,
|
||||||
|
VirtualSize: size, // TODO: field unused, deprecate
|
||||||
|
RootFS: rootFSToAPIType(img.RootFS),
|
||||||
|
}
|
||||||
|
|
||||||
|
imageInspect.GraphDriver.Name = daemon.GraphDriverName()
|
||||||
|
|
||||||
|
imageInspect.GraphDriver.Data = layerMetadata
|
||||||
|
|
||||||
|
return imageInspect, nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue