From d45a26d7e24719814bc321db6fa173110af30740 Mon Sep 17 00:00:00 2001 From: John Starks Date: Mon, 28 Mar 2016 18:14:05 -0700 Subject: [PATCH] Windows: Support non-base-layered images Previously, Windows only supported running with a OS-managed base image. With this change, Windows supports normal, Linux-like layered images, too. Signed-off-by: John Starks --- daemon/daemon_windows.go | 3 +-- daemon/oci_windows.go | 11 +++++++++-- distribution/pull_v2_windows.go | 3 ++- image/rootfs.go | 8 ++++++++ image/rootfs_unix.go | 5 ----- image/rootfs_windows.go | 21 ++++++++++++++++----- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/daemon/daemon_windows.go b/daemon/daemon_windows.go index b1ad26c11b..57244a5429 100644 --- a/daemon/daemon_windows.go +++ b/daemon/daemon_windows.go @@ -373,8 +373,7 @@ func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) erro } // layer is intentionally not released - rootFS := image.NewRootFS() - rootFS.BaseLayer = filepath.Base(info.Path) + rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path)) // Create history for base layer config, err := json.Marshal(&image.Image{ diff --git a/daemon/oci_windows.go b/daemon/oci_windows.go index 7da8ec4f99..39e5686526 100644 --- a/daemon/oci_windows.go +++ b/daemon/oci_windows.go @@ -5,6 +5,7 @@ import ( "syscall" "github.com/docker/docker/container" + "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/libcontainerd" "github.com/docker/docker/libcontainerd/windowsoci" @@ -88,9 +89,15 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e // s.Windows.LayerPaths var layerPaths []string - if img.RootFS != nil && img.RootFS.Type == "layers+base" { + if img.RootFS != nil && (img.RootFS.Type == image.TypeLayers || img.RootFS.Type == image.TypeLayersWithBase) { + // Get the layer path for each layer. + start := 1 + if img.RootFS.Type == image.TypeLayersWithBase { + // Include an empty slice to get the base layer ID. + start = 0 + } max := len(img.RootFS.DiffIDs) - for i := 0; i <= max; i++ { + for i := start; i <= max; i++ { img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i] path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID()) if err != nil { diff --git a/distribution/pull_v2_windows.go b/distribution/pull_v2_windows.go index de99fc9d48..d99434431f 100644 --- a/distribution/pull_v2_windows.go +++ b/distribution/pull_v2_windows.go @@ -20,8 +20,9 @@ func detectBaseLayer(is image.Store, m *schema1.Manifest, rootFS *image.RootFS) } // There must be an image that already references the baselayer. for _, img := range is.Map() { - if img.RootFS.BaseLayerID() == v1img.Parent { + if img.RootFS.Type == image.TypeLayersWithBase && img.RootFS.BaseLayerID() == v1img.Parent { rootFS.BaseLayer = img.RootFS.BaseLayer + rootFS.Type = image.TypeLayersWithBase return nil } } diff --git a/image/rootfs.go b/image/rootfs.go index b546696d6a..76eaae0c25 100644 --- a/image/rootfs.go +++ b/image/rootfs.go @@ -2,6 +2,14 @@ package image import "github.com/docker/docker/layer" +// TypeLayers is used for RootFS.Type for filesystems organized into layers. +const TypeLayers = "layers" + +// NewRootFS returns empty RootFS struct +func NewRootFS() *RootFS { + return &RootFS{Type: TypeLayers} +} + // Append appends a new diffID to rootfs func (r *RootFS) Append(id layer.DiffID) { r.DiffIDs = append(r.DiffIDs, id) diff --git a/image/rootfs_unix.go b/image/rootfs_unix.go index 99c1f8f4e9..83498f6c37 100644 --- a/image/rootfs_unix.go +++ b/image/rootfs_unix.go @@ -16,8 +16,3 @@ type RootFS struct { func (r *RootFS) ChainID() layer.ChainID { return layer.CreateChainID(r.DiffIDs) } - -// NewRootFS returns empty RootFS struct -func NewRootFS() *RootFS { - return &RootFS{Type: "layers"} -} diff --git a/image/rootfs_windows.go b/image/rootfs_windows.go index 883d238577..c5bd5828b5 100644 --- a/image/rootfs_windows.go +++ b/image/rootfs_windows.go @@ -10,6 +10,9 @@ import ( "github.com/docker/docker/layer" ) +// TypeLayersWithBase is used for RootFS.Type for Windows filesystems that have layers and a centrally-stored base layer. +const TypeLayersWithBase = "layers+base" + // RootFS describes images root filesystem // This is currently a placeholder that only supports layers. In the future // this can be made into an interface that supports different implementations. @@ -21,17 +24,25 @@ type RootFS struct { // BaseLayerID returns the 64 byte hex ID for the baselayer name. func (r *RootFS) BaseLayerID() string { + if r.Type != TypeLayersWithBase { + panic("tried to get base layer ID without a base layer") + } baseID := sha512.Sum384([]byte(r.BaseLayer)) return fmt.Sprintf("%x", baseID[:32]) } // ChainID returns the ChainID for the top layer in RootFS. func (r *RootFS) ChainID() layer.ChainID { - baseDiffID := digest.FromBytes([]byte(r.BaseLayerID())) - return layer.CreateChainID(append([]layer.DiffID{layer.DiffID(baseDiffID)}, r.DiffIDs...)) + ids := r.DiffIDs + if r.Type == TypeLayersWithBase { + // Add an extra ID for the base. + baseDiffID := layer.DiffID(digest.FromBytes([]byte(r.BaseLayerID()))) + ids = append([]layer.DiffID{baseDiffID}, ids...) + } + return layer.CreateChainID(ids) } -// NewRootFS returns empty RootFS struct -func NewRootFS() *RootFS { - return &RootFS{Type: "layers+base"} +// NewRootFSWithBaseLayer returns a RootFS struct with a base layer +func NewRootFSWithBaseLayer(baseLayer string) *RootFS { + return &RootFS{Type: TypeLayersWithBase, BaseLayer: baseLayer} }