Windows: Graph remove custom interface and add central store

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>

Windows: add support for images stored in alternate location.

Signed-off-by: Stefan J. Wernli <swernli@microsoft.com>
This commit is contained in:
Stefan J. Wernli
2015-08-14 23:45:53 -07:00
committed by John Howard
parent 424fa59859
commit dfbb5520e3
16 changed files with 546 additions and 636 deletions
+78 -26
View File
@@ -77,11 +77,12 @@ func (r *retainedLayers) Exists(layerID string) bool {
// A Graph is a store for versioned filesystem images and the relationship between them.
type Graph struct {
root string
idIndex *truncindex.TruncIndex
driver graphdriver.Driver
imageMutex imageMutex // protect images in driver.
retained *retainedLayers
root string
idIndex *truncindex.TruncIndex
driver graphdriver.Driver
imageMutex imageMutex // protect images in driver.
retained *retainedLayers
tarSplitDisabled bool
}
// file names for ./graph/<ID>/
@@ -117,6 +118,12 @@ func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
driver: driver,
retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
}
// Windows does not currently support tarsplit functionality.
if runtime.GOOS == "windows" {
graph.tarSplitDisabled = true
}
if err := graph.restore(); err != nil {
return nil, err
}
@@ -141,12 +148,6 @@ func (graph *Graph) restore() error {
}
}
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
@@ -285,6 +286,13 @@ func (graph *Graph) Register(img *image.Image, layerData archive.Reader) (err er
return nil
}
func createRootFilesystemInDriver(graph *Graph, img *image.Image, layerData archive.Reader) 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
}
// TempLayerArchive creates a temporary archive of the given image's filesystem layer.
// The archive is stored on disk and will be automatically deleted as soon as has been read.
// If output is not nil, a human-readable progress bar will be written to it.
@@ -442,6 +450,16 @@ func (graph *Graph) Heads() map[string]*image.Image {
return heads
}
// TarLayer returns a tar archive of the image's filesystem layer.
func (graph *Graph) TarLayer(img *image.Image) (arch archive.Archive, err error) {
rdr, err := graph.assembleTarLayer(img)
if err != nil {
logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
return graph.driver.Diff(img.ID, img.Parent)
}
return rdr, nil
}
func (graph *Graph) imageRoot(id string) string {
return filepath.Join(graph.root, id)
}
@@ -535,30 +553,64 @@ func jsonPath(root string) string {
return filepath.Join(root, jsonFileName)
}
func (graph *Graph) disassembleAndApplyTarLayer(img *image.Image, layerData archive.Reader, root string) error {
// this is saving the tar-split metadata
mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
if err != 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.Image, layerData archive.Reader, root string) (err error) {
// Store the layer. If layerData is not nil, unpack it into the new layer
if layerData != nil {
if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
return err
}
}
if err := graph.saveSize(root, img.Size); err != nil {
return err
}
mfz := gzip.NewWriter(mf)
metaPacker := storage.NewJSONPacker(mfz)
defer mf.Close()
defer mfz.Close()
inflatedLayerData, err := archive.DecompressStream(layerData)
f, err := os.OpenFile(jsonPath(root), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
if err != nil {
return err
}
// we're passing nil here for the file putter, because the ApplyDiff will
// handle the extraction of the archive
rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
if err != nil {
return err
defer f.Close()
return json.NewEncoder(f).Encode(img)
}
func (graph *Graph) disassembleAndApplyTarLayer(img *image.Image, layerData archive.Reader, root string) (err error) {
var ar archive.Reader
if graph.tarSplitDisabled {
ar = layerData
} else {
// this is saving the tar-split metadata
mf, err := os.OpenFile(filepath.Join(root, tarDataFileName), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0600))
if err != nil {
return err
}
mfz := gzip.NewWriter(mf)
metaPacker := storage.NewJSONPacker(mfz)
defer mf.Close()
defer mfz.Close()
inflatedLayerData, err := archive.DecompressStream(layerData)
if err != nil {
return err
}
// we're passing nil here for the file putter, because the ApplyDiff will
// handle the extraction of the archive
rdr, err := asm.NewInputTarStream(inflatedLayerData, metaPacker, nil)
if err != nil {
return err
}
ar = archive.Reader(rdr)
}
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, archive.Reader(rdr)); err != nil {
if img.Size, err = graph.driver.ApplyDiff(img.ID, img.Parent, ar); err != nil {
return err
}
-120
View File
@@ -1,120 +0,0 @@
// +build !windows
package graph
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"syscall"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/image"
"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.Image, layerData archive.Reader) 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.Image, layerData archive.Reader, root string) (err error) {
// Store the layer. If layerData is not nil, unpack it into the new layer
if layerData != nil {
if err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
return err
}
}
if err := graph.saveSize(root, 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.Image) (arch archive.Archive, err error) {
rdr, err := graph.assembleTarLayer(img)
if err != nil {
logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
return graph.driver.Diff(img.ID, img.Parent)
}
return rdr, nil
}
-164
View File
@@ -1,164 +0,0 @@
// +build windows
package graph
import (
"encoding/json"
"fmt"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/graphdriver/windows"
"github.com/docker/docker/image"
"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.Image, layerData archive.Reader) 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.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.Image, layerData archive.Reader, 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, 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)
}
// 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 err := graph.disassembleAndApplyTarLayer(img, layerData, root); err != nil {
return err
}
}
if err := graph.saveSize(root, 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.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))
}
// 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.
rdr, err := graph.assembleTarLayer(img)
if err != nil {
logrus.Debugf("[graph] TarLayer with traditional differ: %s", img.ID)
return graph.driver.Diff(img.ID, img.Parent)
}
return rdr, nil
}