mirror of
https://github.com/docker/cli.git
synced 2026-09-24 15:30:10 -05:00
Windows: Graph driver implementation
Signed-off-by: John Howard <jhoward@microsoft.com> Upstream-commit: 52f4d09ffb376ffaa6677cb1e0413c6a97f53f24 Component: engine
This commit is contained in:
@@ -37,6 +37,22 @@ type Graph struct {
|
||||
imageMutex imageMutex // protect images in driver.
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
ID string `json:"id"`
|
||||
Parent string `json:"parent,omitempty"`
|
||||
Comment string `json:"comment,omitempty"`
|
||||
Created time.Time `json:"created"`
|
||||
Container string `json:"container,omitempty"`
|
||||
ContainerConfig runconfig.Config `json:"container_config,omitempty"`
|
||||
DockerVersion string `json:"docker_version,omitempty"`
|
||||
Author string `json:"author,omitempty"`
|
||||
Config *runconfig.Config `json:"config,omitempty"`
|
||||
Architecture string `json:"architecture,omitempty"`
|
||||
OS string `json:"os,omitempty"`
|
||||
Size int64
|
||||
graph Graph
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrDigestNotSet is used when request the digest for a layer
|
||||
// but the layer has no digest value or content to compute the
|
||||
@@ -79,6 +95,13 @@ func (graph *Graph) restore() error {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
|
||||
baseIds, err := graph.restoreBaseImages()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ids = append(ids, baseIds...)
|
||||
|
||||
graph.idIndex = truncindex.NewTruncIndex(ids)
|
||||
logrus.Debugf("Restored %d elements", len(ids))
|
||||
return nil
|
||||
@@ -100,7 +123,7 @@ func (graph *Graph) Exists(id string) bool {
|
||||
}
|
||||
|
||||
// Get returns the image with the given id, or an error if the image doesn't exist.
|
||||
func (graph *Graph) Get(name string) (*image.Image, error) {
|
||||
func (graph *Graph) Get(name string) (*Image, error) {
|
||||
id, err := graph.idIndex.Get(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find image: %v", err)
|
||||
@@ -128,8 +151,8 @@ func (graph *Graph) Get(name string) (*image.Image, error) {
|
||||
}
|
||||
|
||||
// Create creates a new image and registers it in the graph.
|
||||
func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*image.Image, error) {
|
||||
img := &image.Image{
|
||||
func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, containerImage, comment, author string, containerConfig, config *runconfig.Config) (*Image, error) {
|
||||
img := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: comment,
|
||||
Created: time.Now().UTC(),
|
||||
@@ -153,7 +176,7 @@ func (graph *Graph) Create(layerData archive.ArchiveReader, containerID, contain
|
||||
}
|
||||
|
||||
// Register imports a pre-existing image into the graph.
|
||||
func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader) (err error) {
|
||||
func (graph *Graph) Register(img *Image, layerData archive.ArchiveReader) (err error) {
|
||||
if err := image.ValidateID(img.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -197,9 +220,10 @@ func (graph *Graph) Register(img *image.Image, layerData archive.ArchiveReader)
|
||||
}
|
||||
|
||||
// Create root filesystem in the driver
|
||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||
if err := createRootFilesystemInDriver(graph, img, layerData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Apply the diff/layer
|
||||
if err := graph.storeImage(img, layerData, tmp); err != nil {
|
||||
return err
|
||||
@@ -303,9 +327,9 @@ func (graph *Graph) Delete(name string) error {
|
||||
}
|
||||
|
||||
// Map returns a list of all images in the graph, addressable by ID.
|
||||
func (graph *Graph) Map() (map[string]*image.Image, error) {
|
||||
images := make(map[string]*image.Image)
|
||||
err := graph.walkAll(func(image *image.Image) {
|
||||
func (graph *Graph) Map() (map[string]*Image, error) {
|
||||
images := make(map[string]*Image)
|
||||
err := graph.walkAll(func(image *Image) {
|
||||
images[image.ID] = image
|
||||
})
|
||||
if err != nil {
|
||||
@@ -316,7 +340,7 @@ func (graph *Graph) Map() (map[string]*image.Image, error) {
|
||||
|
||||
// walkAll iterates over each image in the graph, and passes it to a handler.
|
||||
// The walking order is undetermined.
|
||||
func (graph *Graph) walkAll(handler func(*image.Image)) error {
|
||||
func (graph *Graph) walkAll(handler func(*Image)) error {
|
||||
files, err := ioutil.ReadDir(graph.root)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -336,9 +360,9 @@ func (graph *Graph) walkAll(handler func(*image.Image)) error {
|
||||
// If an image of id ID has 3 children images, then the value for key ID
|
||||
// will be a list of 3 images.
|
||||
// If an image has no children, it will not have an entry in the table.
|
||||
func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
|
||||
byParent := make(map[string][]*image.Image)
|
||||
err := graph.walkAll(func(img *image.Image) {
|
||||
func (graph *Graph) ByParent() (map[string][]*Image, error) {
|
||||
byParent := make(map[string][]*Image)
|
||||
err := graph.walkAll(func(img *Image) {
|
||||
parent, err := graph.Get(img.Parent)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -346,7 +370,7 @@ func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
|
||||
if children, exists := byParent[parent.ID]; exists {
|
||||
byParent[parent.ID] = append(children, img)
|
||||
} else {
|
||||
byParent[parent.ID] = []*image.Image{img}
|
||||
byParent[parent.ID] = []*Image{img}
|
||||
}
|
||||
})
|
||||
return byParent, err
|
||||
@@ -354,13 +378,13 @@ func (graph *Graph) ByParent() (map[string][]*image.Image, error) {
|
||||
|
||||
// Heads returns all heads in the graph, keyed by id.
|
||||
// A head is an image which is not the parent of another image in the graph.
|
||||
func (graph *Graph) Heads() (map[string]*image.Image, error) {
|
||||
heads := make(map[string]*image.Image)
|
||||
func (graph *Graph) Heads() (map[string]*Image, error) {
|
||||
heads := make(map[string]*Image)
|
||||
byParent, err := graph.ByParent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = graph.walkAll(func(image *image.Image) {
|
||||
err = graph.walkAll(func(image *Image) {
|
||||
// If it's not in the byParent lookup table, then
|
||||
// it's not a parent -> so it's a head!
|
||||
if _, exists := byParent[image.ID]; !exists {
|
||||
@@ -374,33 +398,8 @@ func (graph *Graph) imageRoot(id string) string {
|
||||
return filepath.Join(graph.root, id)
|
||||
}
|
||||
|
||||
// storeImage stores file system layer data for the given image to the
|
||||
// graph's storage driver. Image metadata is stored in a file
|
||||
// at the specified root directory.
|
||||
func (graph *Graph) storeImage(img *image.Image, layerData archive.ArchiveReader, root string) (err error) {
|
||||
// Store the layer. If layerData is not nil, unpack it into the new layer
|
||||
if layerData != nil {
|
||||
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return json.NewEncoder(f).Encode(img)
|
||||
}
|
||||
|
||||
// loadImage fetches the image with the given id from the graph.
|
||||
func (graph *Graph) loadImage(id string) (*image.Image, error) {
|
||||
func (graph *Graph) loadImage(id string) (*Image, error) {
|
||||
root := graph.imageRoot(id)
|
||||
|
||||
// Open the JSON file to decode by streaming
|
||||
@@ -410,7 +409,7 @@ func (graph *Graph) loadImage(id string) (*image.Image, error) {
|
||||
}
|
||||
defer jsonSource.Close()
|
||||
|
||||
img := &image.Image{}
|
||||
img := &Image{}
|
||||
dec := json.NewDecoder(jsonSource)
|
||||
|
||||
// Decode the JSON data
|
||||
@@ -488,7 +487,13 @@ func jsonPath(root string) string {
|
||||
return filepath.Join(root, "json")
|
||||
}
|
||||
|
||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||
func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
|
||||
return graph.driver.Diff(img.ID, img.Parent)
|
||||
// Build an Image object from raw json data
|
||||
func NewImgJSON(src []byte) (*Image, error) {
|
||||
ret := &Image{}
|
||||
|
||||
// FIXME: Is there a cleaner way to "purify" the input json?
|
||||
if err := json.Unmarshal(src, ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ func TestInterruptedRegister(t *testing.T) {
|
||||
graph, _ := tempGraph(t)
|
||||
defer nukeGraph(graph)
|
||||
badArchive, w := io.Pipe() // Use a pipe reader as a fake archive which never yields data
|
||||
image := &image.Image{
|
||||
image := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: "testing",
|
||||
Created: time.Now(),
|
||||
@@ -128,7 +128,7 @@ func TestRegister(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
image := &image.Image{
|
||||
image := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: "testing",
|
||||
Created: time.Now(),
|
||||
@@ -232,19 +232,19 @@ func TestByParent(t *testing.T) {
|
||||
|
||||
graph, _ := tempGraph(t)
|
||||
defer nukeGraph(graph)
|
||||
parentImage := &image.Image{
|
||||
parentImage := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: "parent",
|
||||
Created: time.Now(),
|
||||
Parent: "",
|
||||
}
|
||||
childImage1 := &image.Image{
|
||||
childImage1 := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: "child1",
|
||||
Created: time.Now(),
|
||||
Parent: parentImage.ID,
|
||||
}
|
||||
childImage2 := &image.Image{
|
||||
childImage2 := &Image{
|
||||
ID: stringid.GenerateRandomID(),
|
||||
Comment: "child2",
|
||||
Created: time.Now(),
|
||||
@@ -264,7 +264,7 @@ func TestByParent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func createTestImage(graph *Graph, t *testing.T) *image.Image {
|
||||
func createTestImage(graph *Graph, t *testing.T) *Image {
|
||||
archive, err := fakeTar()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// +build !windows
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// setupInitLayer populates a directory with mountpoints suitable
|
||||
// for bind-mounting dockerinit into the container. The mountpoint is simply an
|
||||
// empty file at /.dockerinit
|
||||
//
|
||||
// This extra layer is used by all containers as the top-most ro layer. It protects
|
||||
// the container from unwanted side-effects on the rw layer.
|
||||
func SetupInitLayer(initLayer string) error {
|
||||
for pth, typ := range map[string]string{
|
||||
"/dev/pts": "dir",
|
||||
"/dev/shm": "dir",
|
||||
"/proc": "dir",
|
||||
"/sys": "dir",
|
||||
"/.dockerinit": "file",
|
||||
"/.dockerenv": "file",
|
||||
"/etc/resolv.conf": "file",
|
||||
"/etc/hosts": "file",
|
||||
"/etc/hostname": "file",
|
||||
"/dev/console": "file",
|
||||
"/etc/mtab": "/proc/mounts",
|
||||
} {
|
||||
parts := strings.Split(pth, "/")
|
||||
prev := "/"
|
||||
for _, p := range parts[1:] {
|
||||
prev = filepath.Join(prev, p)
|
||||
syscall.Unlink(filepath.Join(initLayer, prev))
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := system.MkdirAll(filepath.Join(initLayer, filepath.Dir(pth)), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
switch typ {
|
||||
case "dir":
|
||||
if err := system.MkdirAll(filepath.Join(initLayer, pth), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
case "file":
|
||||
f, err := os.OpenFile(filepath.Join(initLayer, pth), os.O_CREATE, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
default:
|
||||
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layer is ready to use, if it wasn't before.
|
||||
return nil
|
||||
}
|
||||
|
||||
func createRootFilesystemInDriver(graph *Graph, img *Image, layerData archive.ArchiveReader) error {
|
||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (graph *Graph) restoreBaseImages() ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// storeImage stores file system layer data for the given image to the
|
||||
// graph's storage driver. Image metadata is stored in a file
|
||||
// at the specified root directory.
|
||||
func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root string) (err error) {
|
||||
// Store the layer. If layerData is not nil, unpack it into the new layer
|
||||
if layerData != nil {
|
||||
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return json.NewEncoder(f).Encode(img)
|
||||
}
|
||||
|
||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||
func (graph *Graph) TarLayer(img *Image) (arch archive.Archive, err error) {
|
||||
return graph.driver.Diff(img.ID, img.Parent)
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
// +build windows
|
||||
|
||||
package graph
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/graphdriver/windows"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
)
|
||||
|
||||
// setupInitLayer populates a directory with mountpoints suitable
|
||||
// for bind-mounting dockerinit into the container. T
|
||||
func SetupInitLayer(initLayer string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func createRootFilesystemInDriver(graph *Graph, img *Image, layerData archive.ArchiveReader) error {
|
||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||
if img.Container != "" && layerData == nil {
|
||||
logrus.Debugf("Copying from container %s.", img.Container)
|
||||
|
||||
var ids []string
|
||||
if img.Parent != "" {
|
||||
parentImg, err := graph.Get(img.Parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids, err = graph.ParentLayerIds(parentImg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := wd.CopyDiff(img.Container, img.ID, wd.LayerIdsToPaths(ids)); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to copy image rootfs %s: %s", graph.driver, img.Container, err)
|
||||
}
|
||||
} else if img.Parent == "" {
|
||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// This fallback allows the use of VFS during daemon development.
|
||||
if err := graph.driver.Create(img.ID, img.Parent); err != nil {
|
||||
return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, img.ID, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (graph *Graph) restoreBaseImages() ([]string, error) {
|
||||
// TODO Windows. This needs implementing (@swernli)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ParentLayerIds returns a list of all parent image IDs for the given image.
|
||||
func (graph *Graph) ParentLayerIds(img *Image) (ids []string, err error) {
|
||||
for i := img; i != nil && err == nil; i, err = graph.GetParent(i) {
|
||||
ids = append(ids, i.ID)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// storeImage stores file system layer data for the given image to the
|
||||
// graph's storage driver. Image metadata is stored in a file
|
||||
// at the specified root directory.
|
||||
func (graph *Graph) storeImage(img *Image, layerData archive.ArchiveReader, root string) (err error) {
|
||||
|
||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||
// Store the layer. If layerData is not nil and this isn't a base image,
|
||||
// unpack it into the new layer
|
||||
if layerData != nil && img.Parent != "" {
|
||||
var ids []string
|
||||
if img.Parent != "" {
|
||||
parentImg, err := graph.Get(img.Parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ids, err = graph.ParentLayerIds(parentImg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if img.Size, err = wd.Import(img.ID, layerData, wd.LayerIdsToPaths(ids)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return json.NewEncoder(f).Encode(img)
|
||||
} else {
|
||||
// We keep this functionality here so that we can still work with the
|
||||
// VFS driver during development. This will not be used for actual running
|
||||
// of Windows containers. Without this code, it would not be possible to
|
||||
// docker pull using the VFS driver.
|
||||
|
||||
// Store the layer. If layerData is not nil, unpack it into the new layer
|
||||
if layerData != nil {
|
||||
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, layerData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := graph.saveSize(root, int(img.Size)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
return json.NewEncoder(f).Encode(img)
|
||||
}
|
||||
}
|
||||
|
||||
// TarLayer returns a tar archive of the image's filesystem layer.
|
||||
func (graph *Graph) TarLayer(img *Image) (arch archive.Archive, err error) {
|
||||
if wd, ok := graph.driver.(*windows.WindowsGraphDriver); ok {
|
||||
var ids []string
|
||||
if img.Parent != "" {
|
||||
parentImg, err := graph.Get(img.Parent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ids, err = graph.ParentLayerIds(parentImg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return wd.Export(img.ID, wd.LayerIdsToPaths(ids))
|
||||
} else {
|
||||
// We keep this functionality here so that we can still work with the VFS
|
||||
// driver during development. VFS is not supported (and just will not work)
|
||||
// for Windows containers.
|
||||
return graph.driver.Diff(img.ID, img.Parent)
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
|
||||
// WalkHistory calls the handler function for each image in the
|
||||
// provided images lineage starting from immediate parent.
|
||||
func (graph *Graph) WalkHistory(img *image.Image, handler func(image.Image) error) (err error) {
|
||||
func (graph *Graph) WalkHistory(img *Image, handler func(Image) error) (err error) {
|
||||
currentImg := img
|
||||
for currentImg != nil {
|
||||
if handler != nil {
|
||||
@@ -29,7 +28,7 @@ func (graph *Graph) WalkHistory(img *image.Image, handler func(image.Image) erro
|
||||
|
||||
// depth returns the number of parents for a
|
||||
// current image
|
||||
func (graph *Graph) depth(img *image.Image) (int, error) {
|
||||
func (graph *Graph) depth(img *Image) (int, error) {
|
||||
var (
|
||||
count = 0
|
||||
parent = img
|
||||
@@ -54,7 +53,7 @@ const MaxImageDepth = 127
|
||||
// CheckDepth returns an error if the depth of an image, as returned
|
||||
// by ImageDepth, is too large to support creating a container from it
|
||||
// on this daemon.
|
||||
func (graph *Graph) CheckDepth(img *image.Image) error {
|
||||
func (graph *Graph) CheckDepth(img *Image) error {
|
||||
// We add 2 layers to the depth because the container's rw and
|
||||
// init layer add to the restriction
|
||||
depth, err := graph.depth(img)
|
||||
@@ -86,7 +85,7 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||
|
||||
history := []*types.ImageHistory{}
|
||||
|
||||
err = s.graph.WalkHistory(foundImage, func(img image.Image) error {
|
||||
err = s.graph.WalkHistory(foundImage, func(img Image) error {
|
||||
history = append(history, &types.ImageHistory{
|
||||
ID: img.ID,
|
||||
Created: img.Created.Unix(),
|
||||
@@ -101,14 +100,14 @@ func (s *TagStore) History(name string) ([]*types.ImageHistory, error) {
|
||||
return history, err
|
||||
}
|
||||
|
||||
func (graph *Graph) GetParent(img *image.Image) (*image.Image, error) {
|
||||
func (graph *Graph) GetParent(img *Image) (*Image, error) {
|
||||
if img.Parent == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return graph.Get(img.Parent)
|
||||
}
|
||||
|
||||
func (graph *Graph) GetParentsSize(img *image.Image, size int64) int64 {
|
||||
func (graph *Graph) GetParentsSize(img *Image, size int64) int64 {
|
||||
parentImage, err := graph.GetParent(img)
|
||||
if err != nil || parentImage == nil {
|
||||
return size
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/parsers/filters"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
@@ -32,7 +31,7 @@ func (r ByCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
||||
|
||||
func (s *TagStore) Images(config *ImagesConfig) ([]*types.Image, error) {
|
||||
var (
|
||||
allImages map[string]*image.Image
|
||||
allImages map[string]*Image
|
||||
err error
|
||||
filtTagged = true
|
||||
filtLabel = false
|
||||
|
||||
@@ -98,7 +98,7 @@ func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
||||
logrus.Debugf("Error reading embedded tar", err)
|
||||
return err
|
||||
}
|
||||
img, err := image.NewImgJSON(imageJson)
|
||||
img, err := NewImgJSON(imageJson)
|
||||
if err != nil {
|
||||
logrus.Debugf("Error unmarshalling json", err)
|
||||
return err
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/utils"
|
||||
@@ -124,7 +123,7 @@ func TestManifestTarsumCache(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img := &image.Image{ID: testManifestImageID}
|
||||
img := &Image{ID: testManifestImageID}
|
||||
if err := store.graph.Register(img, archive); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -190,7 +189,7 @@ func TestManifestDigestCheck(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img := &image.Image{ID: testManifestImageID}
|
||||
img := &Image{ID: testManifestImageID}
|
||||
if err := store.graph.Register(img, archive); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/progressreader"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
@@ -387,7 +386,7 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
|
||||
imgJSON []byte
|
||||
imgSize int
|
||||
err error
|
||||
img *image.Image
|
||||
img *Image
|
||||
)
|
||||
retries := 5
|
||||
for j := 1; j <= retries; j++ {
|
||||
@@ -399,7 +398,7 @@ func (s *TagStore) pullImage(r *registry.Session, out io.Writer, imgID, endpoint
|
||||
time.Sleep(time.Duration(j) * 500 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
img, err = image.NewImgJSON(imgJSON)
|
||||
img, err = NewImgJSON(imgJSON)
|
||||
layersDownloaded = true
|
||||
if err != nil && j == retries {
|
||||
out.Write(sf.FormatProgress(stringid.TruncateID(id), "Error pulling dependent layers", nil))
|
||||
@@ -540,7 +539,7 @@ func (s *TagStore) pullV2Tag(r *registry.Session, out io.Writer, endpoint *regis
|
||||
// downloadInfo is used to pass information from download to extractor
|
||||
type downloadInfo struct {
|
||||
imgJSON []byte
|
||||
img *image.Image
|
||||
img *Image
|
||||
digest digest.Digest
|
||||
tmpFile *os.File
|
||||
length int64
|
||||
@@ -556,7 +555,7 @@ func (s *TagStore) pullV2Tag(r *registry.Session, out io.Writer, endpoint *regis
|
||||
imgJSON = []byte(manifest.History[i].V1Compatibility)
|
||||
)
|
||||
|
||||
img, err := image.NewImgJSON(imgJSON)
|
||||
img, err := NewImgJSON(imgJSON)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to parse json: %s", err)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progressreader"
|
||||
"github.com/docker/docker/pkg/streamformatter"
|
||||
@@ -349,7 +348,7 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
|
||||
}
|
||||
|
||||
layersSeen := make(map[string]bool)
|
||||
layers := []*image.Image{}
|
||||
layers := []*Image{}
|
||||
for ; layer != nil; layer, err = s.graph.GetParent(layer) {
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -445,7 +444,7 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
|
||||
}
|
||||
|
||||
// PushV2Image pushes the image content to the v2 registry, first buffering the contents to disk
|
||||
func (s *TagStore) pushV2Image(r *registry.Session, img *image.Image, endpoint *registry.Endpoint, imageName string, sf *streamformatter.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (digest.Digest, error) {
|
||||
func (s *TagStore) pushV2Image(r *registry.Session, img *Image, endpoint *registry.Endpoint, imageName string, sf *streamformatter.StreamFormatter, out io.Writer, auth *registry.RequestAuthorization) (digest.Digest, error) {
|
||||
out.Write(sf.FormatProgress(stringid.TruncateID(img.ID), "Buffering to Disk", nil))
|
||||
|
||||
image, err := s.graph.Get(img.ID)
|
||||
|
||||
@@ -3,6 +3,7 @@ package graph
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -58,17 +59,21 @@ func (s *TagStore) Lookup(name string) (*types.ImageInspect, error) {
|
||||
// ImageTarLayer return the tarLayer of the image
|
||||
func (s *TagStore) ImageTarLayer(name string, dest io.Writer) error {
|
||||
if image, err := s.LookupImage(name); err == nil && image != nil {
|
||||
fs, err := s.graph.TarLayer(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fs.Close()
|
||||
// On Windows, the base layer cannot be exported
|
||||
if runtime.GOOS != "windows" || image.Parent != "" {
|
||||
|
||||
written, err := io.Copy(dest, fs)
|
||||
if err != nil {
|
||||
return err
|
||||
fs, err := s.graph.TarLayer(image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fs.Close()
|
||||
|
||||
written, err := io.Copy(dest, fs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Debugf("rendered layer for %s of [%d] size", image.ID, written)
|
||||
}
|
||||
logrus.Debugf("rendered layer for %s of [%d] size", image.ID, written)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("No such image: %s", name)
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/graph/tags"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/registry"
|
||||
@@ -126,7 +125,7 @@ func (store *TagStore) reload() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||
func (store *TagStore) LookupImage(name string) (*Image, error) {
|
||||
// FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
|
||||
// (so we can pass all errors here)
|
||||
repoName, ref := parsers.ParseRepositoryTag(name)
|
||||
@@ -135,7 +134,7 @@ func (store *TagStore) LookupImage(name string) (*image.Image, error) {
|
||||
}
|
||||
var (
|
||||
err error
|
||||
img *image.Image
|
||||
img *Image
|
||||
)
|
||||
|
||||
img, err = store.GetImage(repoName, ref)
|
||||
@@ -330,7 +329,7 @@ func (store *TagStore) Get(repoName string) (Repository, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (store *TagStore) GetImage(repoName, refOrID string) (*image.Image, error) {
|
||||
func (store *TagStore) GetImage(repoName, refOrID string) (*Image, error) {
|
||||
repo, err := store.Get(repoName)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/docker/docker/daemon/events"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
_ "github.com/docker/docker/daemon/graphdriver/vfs" // import the vfs driver so it is used in the tests
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/trust"
|
||||
"github.com/docker/docker/utils"
|
||||
)
|
||||
@@ -80,7 +79,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img := &image.Image{ID: testOfficialImageID}
|
||||
img := &Image{ID: testOfficialImageID}
|
||||
if err := graph.Register(img, officialArchive); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -91,7 +90,7 @@ func mkTestTagStore(root string, t *testing.T) *TagStore {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
img = &image.Image{ID: testPrivateImageID}
|
||||
img = &Image{ID: testPrivateImageID}
|
||||
if err := graph.Register(img, privateArchive); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user