mirror of
https://github.com/docker/cli.git
synced 2026-01-13 18:22:35 +03:00
Merge pull request #34859 from Microsoft/jjh/singleimagestore
LCOW: Coalesce daemon stores, allow dual LCOW and WCOW mode Upstream-commit: bb6ce897378b4ebd0131fd835b01ad5f9af3ebb9 Component: engine
This commit is contained in:
@@ -17,7 +17,7 @@ import (
|
||||
// ImageComponent provides an interface for working with images
|
||||
type ImageComponent interface {
|
||||
SquashImage(from string, to string) (string, error)
|
||||
TagImageWithReference(image.ID, string, reference.Named) error
|
||||
TagImageWithReference(image.ID, reference.Named) error
|
||||
}
|
||||
|
||||
// Builder defines interface for running a build
|
||||
|
||||
@@ -3,11 +3,9 @@ package build
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -35,12 +33,7 @@ func NewTagger(backend ImageComponent, stdout io.Writer, names []string) (*Tagge
|
||||
// TagImages creates image tags for the imageID
|
||||
func (bt *Tagger) TagImages(imageID image.ID) error {
|
||||
for _, rt := range bt.repoAndTags {
|
||||
// TODO @jhowardmsft LCOW support. Will need revisiting.
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
if err := bt.imageComponent.TagImageWithReference(imageID, platform, rt); err != nil {
|
||||
if err := bt.imageComponent.TagImageWithReference(imageID, rt); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(bt.stdout, "Successfully tagged %s\n", reference.FamiliarString(rt))
|
||||
|
||||
@@ -44,7 +44,7 @@ type Backend interface {
|
||||
// ContainerCreateWorkdir creates the workdir
|
||||
ContainerCreateWorkdir(containerID string) error
|
||||
|
||||
CreateImage(config []byte, parent string, platform string) (Image, error)
|
||||
CreateImage(config []byte, parent string) (Image, error)
|
||||
|
||||
ImageCacheBuilder
|
||||
}
|
||||
@@ -79,7 +79,7 @@ type Result struct {
|
||||
// ImageCacheBuilder represents a generator for stateful image cache.
|
||||
type ImageCacheBuilder interface {
|
||||
// MakeImageCache creates a stateful image cache.
|
||||
MakeImageCache(cacheFrom []string, platform string) ImageCache
|
||||
MakeImageCache(cacheFrom []string) ImageCache
|
||||
}
|
||||
|
||||
// ImageCache abstracts an image cache.
|
||||
@@ -102,6 +102,6 @@ type Image interface {
|
||||
type ReleaseableLayer interface {
|
||||
Release() error
|
||||
Mount() (containerfs.ContainerFS, error)
|
||||
Commit(platform string) (ReleaseableLayer, error)
|
||||
Commit() (ReleaseableLayer, error)
|
||||
DiffID() layer.DiffID
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
|
||||
PathCache: bm.pathCache,
|
||||
IDMappings: bm.idMappings,
|
||||
}
|
||||
return newBuilder(ctx, builderOptions, os).build(source, dockerfile)
|
||||
return newBuilder(ctx, builderOptions).build(source, dockerfile)
|
||||
}
|
||||
|
||||
func (bm *BuildManager) initializeClientSession(ctx context.Context, cancel func(), options *types.ImageBuildOptions) (builder.Source, error) {
|
||||
@@ -190,7 +190,7 @@ type Builder struct {
|
||||
}
|
||||
|
||||
// newBuilder creates a new Dockerfile builder from an optional dockerfile and a Options.
|
||||
func newBuilder(clientCtx context.Context, options builderOptions, os string) *Builder {
|
||||
func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
|
||||
config := options.Options
|
||||
if config == nil {
|
||||
config = new(types.ImageBuildOptions)
|
||||
@@ -207,7 +207,7 @@ func newBuilder(clientCtx context.Context, options builderOptions, os string) *B
|
||||
idMappings: options.IDMappings,
|
||||
imageSources: newImageSources(clientCtx, options),
|
||||
pathCache: options.PathCache,
|
||||
imageProber: newImageProber(options.Backend, config.CacheFrom, os, config.NoCache),
|
||||
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),
|
||||
containerManager: newContainerManager(options.Backend),
|
||||
}
|
||||
|
||||
@@ -357,7 +357,10 @@ func addNodesForLabelOption(dockerfile *parser.Node, labels map[string]string) {
|
||||
// coming from the query parameter of the same name.
|
||||
//
|
||||
// TODO: Remove?
|
||||
func BuildFromConfig(config *container.Config, changes []string) (*container.Config, error) {
|
||||
func BuildFromConfig(config *container.Config, changes []string, os string) (*container.Config, error) {
|
||||
if !system.IsOSSupported(os) {
|
||||
return nil, errdefs.InvalidParameter(system.ErrNotSupportedOperatingSystem)
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return config, nil
|
||||
}
|
||||
@@ -367,14 +370,9 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con
|
||||
return nil, errdefs.InvalidParameter(err)
|
||||
}
|
||||
|
||||
os := runtime.GOOS
|
||||
if dockerfile.OS != "" {
|
||||
os = dockerfile.OS
|
||||
}
|
||||
|
||||
b := newBuilder(context.Background(), builderOptions{
|
||||
Options: &types.ImageBuildOptions{NoCache: true},
|
||||
}, os)
|
||||
})
|
||||
|
||||
// ensure that the commands are valid
|
||||
for _, n := range dockerfile.AST.Children {
|
||||
@@ -400,6 +398,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con
|
||||
// We make mutations to the configuration, ensure we have a copy
|
||||
dispatchRequest.state.runConfig = copyRunConfig(config)
|
||||
dispatchRequest.state.imageID = config.Image
|
||||
dispatchRequest.state.operatingSystem = os
|
||||
for _, cmd := range commands {
|
||||
err := dispatch(dispatchRequest, cmd)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,7 +28,7 @@ func newContainerManager(docker builder.ExecBackend) *containerManager {
|
||||
}
|
||||
|
||||
// Create a container
|
||||
func (c *containerManager) Create(runConfig *container.Config, hostConfig *container.HostConfig, platform string) (container.ContainerCreateCreatedBody, error) {
|
||||
func (c *containerManager) Create(runConfig *container.Config, hostConfig *container.HostConfig) (container.ContainerCreateCreatedBody, error) {
|
||||
container, err := c.backend.ContainerCreate(types.ContainerCreateConfig{
|
||||
Config: runConfig,
|
||||
HostConfig: hostConfig,
|
||||
|
||||
@@ -156,7 +156,9 @@ func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
|
||||
return err
|
||||
}
|
||||
state := d.state
|
||||
state.beginStage(cmd.Name, image)
|
||||
if err := state.beginStage(cmd.Name, image); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(state.runConfig.OnBuild) > 0 {
|
||||
triggers := state.runConfig.OnBuild
|
||||
state.runConfig.OnBuild = nil
|
||||
@@ -261,8 +263,8 @@ func dispatchOnbuild(d dispatchRequest, c *instructions.OnbuildCommand) error {
|
||||
func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
|
||||
runConfig := d.state.runConfig
|
||||
var err error
|
||||
optionsOS := system.ParsePlatform(d.builder.options.Platform).OS
|
||||
runConfig.WorkingDir, err = normalizeWorkdir(optionsOS, runConfig.WorkingDir, c.Path)
|
||||
baseImageOS := system.ParsePlatform(d.state.operatingSystem).OS
|
||||
runConfig.WorkingDir, err = normalizeWorkdir(baseImageOS, runConfig.WorkingDir, c.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -278,7 +280,7 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
|
||||
}
|
||||
|
||||
comment := "WORKDIR " + runConfig.WorkingDir
|
||||
runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment, optionsOS))
|
||||
runConfigWithCommentCmd := copyRunConfig(runConfig, withCmdCommentString(comment, baseImageOS))
|
||||
containerID, err := d.builder.probeAndCreate(d.state, runConfigWithCommentCmd)
|
||||
if err != nil || containerID == "" {
|
||||
return err
|
||||
@@ -290,10 +292,10 @@ func dispatchWorkdir(d dispatchRequest, c *instructions.WorkdirCommand) error {
|
||||
return d.builder.commitContainer(d.state, containerID, runConfigWithCommentCmd)
|
||||
}
|
||||
|
||||
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, platform string) []string {
|
||||
func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container.Config, os string) []string {
|
||||
result := cmd.CmdLine
|
||||
if cmd.PrependShell && result != nil {
|
||||
result = append(getShell(runConfig, platform), result...)
|
||||
result = append(getShell(runConfig, os), result...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -309,10 +311,11 @@ func resolveCmdLine(cmd instructions.ShellDependantCmdLine, runConfig *container
|
||||
// RUN [ "echo", "hi" ] # echo hi
|
||||
//
|
||||
func dispatchRun(d dispatchRequest, c *instructions.RunCommand) error {
|
||||
|
||||
if !system.IsOSSupported(d.state.operatingSystem) {
|
||||
return system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
stateRunConfig := d.state.runConfig
|
||||
optionsOS := system.ParsePlatform(d.builder.options.Platform).OS
|
||||
cmdFromArgs := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, optionsOS)
|
||||
cmdFromArgs := resolveCmdLine(c.ShellDependantCmdLine, stateRunConfig, d.state.operatingSystem)
|
||||
buildArgs := d.state.buildArgs.FilterAllowed(stateRunConfig.Env)
|
||||
|
||||
saveCmd := cmdFromArgs
|
||||
|
||||
@@ -31,7 +31,7 @@ func newBuilderWithMockBackend() *Builder {
|
||||
Options: &types.ImageBuildOptions{Platform: runtime.GOOS},
|
||||
Backend: mockBackend,
|
||||
}),
|
||||
imageProber: newImageProber(mockBackend, nil, runtime.GOOS, false),
|
||||
imageProber: newImageProber(mockBackend, nil, false),
|
||||
containerManager: newContainerManager(mockBackend),
|
||||
}
|
||||
return b
|
||||
@@ -427,10 +427,10 @@ func TestRunWithBuildArgs(t *testing.T) {
|
||||
}
|
||||
|
||||
mockBackend := b.docker.(*MockBackend)
|
||||
mockBackend.makeImageCacheFunc = func(_ []string, _ string) builder.ImageCache {
|
||||
mockBackend.makeImageCacheFunc = func(_ []string) builder.ImageCache {
|
||||
return imageCache
|
||||
}
|
||||
b.imageProber = newImageProber(mockBackend, nil, runtime.GOOS, false)
|
||||
b.imageProber = newImageProber(mockBackend, nil, false)
|
||||
mockBackend.getImageFunc = func(_ string) (builder.Image, builder.ReleaseableLayer, error) {
|
||||
return &mockImage{
|
||||
id: "abcdef",
|
||||
|
||||
@@ -21,6 +21,7 @@ package dockerfile
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -104,13 +105,14 @@ func dispatch(d dispatchRequest, cmd instructions.Command) (err error) {
|
||||
|
||||
// dispatchState is a data object which is modified by dispatchers
|
||||
type dispatchState struct {
|
||||
runConfig *container.Config
|
||||
maintainer string
|
||||
cmdSet bool
|
||||
imageID string
|
||||
baseImage builder.Image
|
||||
stageName string
|
||||
buildArgs *buildArgs
|
||||
runConfig *container.Config
|
||||
maintainer string
|
||||
cmdSet bool
|
||||
imageID string
|
||||
baseImage builder.Image
|
||||
stageName string
|
||||
buildArgs *buildArgs
|
||||
operatingSystem string
|
||||
}
|
||||
|
||||
func newDispatchState(baseArgs *buildArgs) *dispatchState {
|
||||
@@ -210,9 +212,16 @@ func (s *dispatchState) hasFromImage() bool {
|
||||
return s.imageID != "" || (s.baseImage != nil && s.baseImage.ImageID() == "")
|
||||
}
|
||||
|
||||
func (s *dispatchState) beginStage(stageName string, image builder.Image) {
|
||||
func (s *dispatchState) beginStage(stageName string, image builder.Image) error {
|
||||
s.stageName = stageName
|
||||
s.imageID = image.ImageID()
|
||||
s.operatingSystem = image.OperatingSystem()
|
||||
if s.operatingSystem == "" { // In case it isn't set
|
||||
s.operatingSystem = runtime.GOOS
|
||||
}
|
||||
if !system.IsOSSupported(s.operatingSystem) {
|
||||
return system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
|
||||
if image.RunConfig() != nil {
|
||||
// copy avoids referencing the same instance when 2 stages have the same base
|
||||
@@ -224,12 +233,13 @@ func (s *dispatchState) beginStage(stageName string, image builder.Image) {
|
||||
s.setDefaultPath()
|
||||
s.runConfig.OpenStdin = false
|
||||
s.runConfig.StdinOnce = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the default PATH to runConfig.ENV if one exists for the operating system and there
|
||||
// is no PATH set. Note that Windows containers on Windows won't have one as it's set by HCS
|
||||
func (s *dispatchState) setDefaultPath() {
|
||||
defaultPath := system.DefaultPathEnv(s.baseImage.OperatingSystem())
|
||||
defaultPath := system.DefaultPathEnv(s.operatingSystem)
|
||||
if defaultPath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ type imageProber struct {
|
||||
cacheBusted bool
|
||||
}
|
||||
|
||||
func newImageProber(cacheBuilder builder.ImageCacheBuilder, cacheFrom []string, platform string, noCache bool) ImageProber {
|
||||
func newImageProber(cacheBuilder builder.ImageCacheBuilder, cacheFrom []string, noCache bool) ImageProber {
|
||||
if noCache {
|
||||
return &nopProber{}
|
||||
}
|
||||
|
||||
reset := func() builder.ImageCache {
|
||||
return cacheBuilder.MakeImageCache(cacheFrom, platform)
|
||||
return cacheBuilder.MakeImageCache(cacheFrom)
|
||||
}
|
||||
return &imageProber{cache: reset(), reset: reset}
|
||||
}
|
||||
|
||||
@@ -125,8 +125,7 @@ func (b *Builder) commitContainer(dispatchState *dispatchState, id string, conta
|
||||
}
|
||||
|
||||
func (b *Builder) exportImage(state *dispatchState, imageMount *imageMount, runConfig *container.Config) error {
|
||||
optionsPlatform := system.ParsePlatform(b.options.Platform)
|
||||
newLayer, err := imageMount.Layer().Commit(optionsPlatform.OS)
|
||||
newLayer, err := imageMount.Layer().Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -154,7 +153,7 @@ func (b *Builder) exportImage(state *dispatchState, imageMount *imageMount, runC
|
||||
return errors.Wrap(err, "failed to encode image config")
|
||||
}
|
||||
|
||||
exportedImage, err := b.docker.CreateImage(config, state.imageID, parentImage.OS)
|
||||
exportedImage, err := b.docker.CreateImage(config, state.imageID)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to export image")
|
||||
}
|
||||
@@ -502,15 +501,13 @@ func (b *Builder) probeAndCreate(dispatchState *dispatchState, runConfig *contai
|
||||
}
|
||||
// Set a log config to override any default value set on the daemon
|
||||
hostConfig := &container.HostConfig{LogConfig: defaultLogConfig}
|
||||
optionsPlatform := system.ParsePlatform(b.options.Platform)
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig, optionsPlatform.OS)
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig)
|
||||
return container.ID, err
|
||||
}
|
||||
|
||||
func (b *Builder) create(runConfig *container.Config) (string, error) {
|
||||
hostConfig := hostConfigFromOptions(b.options)
|
||||
optionsPlatform := system.ParsePlatform(b.options.Platform)
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig, optionsPlatform.OS)
|
||||
container, err := b.containerManager.Create(runConfig, hostConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type MockBackend struct {
|
||||
containerCreateFunc func(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error)
|
||||
commitFunc func(string, *backend.ContainerCommitConfig) (string, error)
|
||||
getImageFunc func(string) (builder.Image, builder.ReleaseableLayer, error)
|
||||
makeImageCacheFunc func(cacheFrom []string, platform string) builder.ImageCache
|
||||
makeImageCacheFunc func(cacheFrom []string) builder.ImageCache
|
||||
}
|
||||
|
||||
func (m *MockBackend) ContainerAttachRaw(cID string, stdin io.ReadCloser, stdout, stderr io.Writer, stream bool, attached chan struct{}) error {
|
||||
@@ -73,14 +73,14 @@ func (m *MockBackend) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
||||
return &mockImage{id: "theid"}, &mockLayer{}, nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) MakeImageCache(cacheFrom []string, platform string) builder.ImageCache {
|
||||
func (m *MockBackend) MakeImageCache(cacheFrom []string) builder.ImageCache {
|
||||
if m.makeImageCacheFunc != nil {
|
||||
return m.makeImageCacheFunc(cacheFrom, platform)
|
||||
return m.makeImageCacheFunc(cacheFrom)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockBackend) CreateImage(config []byte, parent string, platform string) (builder.Image, error) {
|
||||
func (m *MockBackend) CreateImage(config []byte, parent string) (builder.Image, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ func (l *mockLayer) Mount() (containerfs.ContainerFS, error) {
|
||||
return containerfs.NewLocalContainerFS("mountPath"), nil
|
||||
}
|
||||
|
||||
func (l *mockLayer) Commit(string) (builder.ReleaseableLayer, error) {
|
||||
func (l *mockLayer) Commit() (builder.ReleaseableLayer, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package daemon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"github.com/docker/docker/pkg/containerfs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -55,7 +55,7 @@ func (rl *releaseableLayer) Mount() (containerfs.ContainerFS, error) {
|
||||
return mountPath, nil
|
||||
}
|
||||
|
||||
func (rl *releaseableLayer) Commit(os string) (builder.ReleaseableLayer, error) {
|
||||
func (rl *releaseableLayer) Commit() (builder.ReleaseableLayer, error) {
|
||||
var chainID layer.ChainID
|
||||
if rl.roLayer != nil {
|
||||
chainID = rl.roLayer.ChainID()
|
||||
@@ -67,7 +67,7 @@ func (rl *releaseableLayer) Commit(os string) (builder.ReleaseableLayer, error)
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
newLayer, err := rl.layerStore.Register(stream, chainID, layer.OS(os))
|
||||
newLayer, err := rl.layerStore.Register(stream, chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func newReleasableLayerForImage(img *image.Image, layerStore layer.Store) (build
|
||||
}
|
||||
|
||||
// TODO: could this use the regular daemon PullImage ?
|
||||
func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, platform string) (*image.Image, error) {
|
||||
func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, os string) (*image.Image, error) {
|
||||
ref, err := reference.ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -161,7 +161,7 @@ func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfi
|
||||
pullRegistryAuth = &resolvedConfig
|
||||
}
|
||||
|
||||
if err := daemon.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
|
||||
if err := daemon.pullImageWithReference(ctx, ref, os, nil, pullRegistryAuth, output); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return daemon.GetImage(name)
|
||||
@@ -172,7 +172,10 @@ func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfi
|
||||
// leaking of layers.
|
||||
func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ReleaseableLayer, error) {
|
||||
if refOrID == "" {
|
||||
layer, err := newReleasableLayerForImage(nil, daemon.stores[opts.OS].layerStore)
|
||||
if !system.IsOSSupported(opts.OS) {
|
||||
return nil, nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
layer, err := newReleasableLayerForImage(nil, daemon.layerStores[opts.OS])
|
||||
return nil, layer, err
|
||||
}
|
||||
|
||||
@@ -183,7 +186,10 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
||||
}
|
||||
// TODO: shouldn't we error out if error is different from "not found" ?
|
||||
if image != nil {
|
||||
layer, err := newReleasableLayerForImage(image, daemon.stores[opts.OS].layerStore)
|
||||
if !system.IsOSSupported(image.OperatingSystem()) {
|
||||
return nil, nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
layer, err := newReleasableLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
|
||||
return image, layer, err
|
||||
}
|
||||
}
|
||||
@@ -192,29 +198,29 @@ func (daemon *Daemon) GetImageAndReleasableLayer(ctx context.Context, refOrID st
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
layer, err := newReleasableLayerForImage(image, daemon.stores[opts.OS].layerStore)
|
||||
if !system.IsOSSupported(image.OperatingSystem()) {
|
||||
return nil, nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
layer, err := newReleasableLayerForImage(image, daemon.layerStores[image.OperatingSystem()])
|
||||
return image, layer, err
|
||||
}
|
||||
|
||||
// CreateImage creates a new image by adding a config and ID to the image store.
|
||||
// This is similar to LoadImage() except that it receives JSON encoded bytes of
|
||||
// an image instead of a tar archive.
|
||||
func (daemon *Daemon) CreateImage(config []byte, parent string, platform string) (builder.Image, error) {
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
id, err := daemon.stores[platform].imageStore.Create(config)
|
||||
func (daemon *Daemon) CreateImage(config []byte, parent string) (builder.Image, error) {
|
||||
id, err := daemon.imageStore.Create(config)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create image")
|
||||
}
|
||||
|
||||
if parent != "" {
|
||||
if err := daemon.stores[platform].imageStore.SetParent(id, image.ID(parent)); err != nil {
|
||||
if err := daemon.imageStore.SetParent(id, image.ID(parent)); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to set parent %s", parent)
|
||||
}
|
||||
}
|
||||
|
||||
return daemon.stores[platform].imageStore.Get(id)
|
||||
return daemon.imageStore.Get(id)
|
||||
}
|
||||
|
||||
// IDMappings returns uid/gid mappings for the builder
|
||||
|
||||
@@ -7,12 +7,12 @@ import (
|
||||
)
|
||||
|
||||
// MakeImageCache creates a stateful image cache.
|
||||
func (daemon *Daemon) MakeImageCache(sourceRefs []string, platform string) builder.ImageCache {
|
||||
func (daemon *Daemon) MakeImageCache(sourceRefs []string) builder.ImageCache {
|
||||
if len(sourceRefs) == 0 {
|
||||
return cache.NewLocal(daemon.stores[platform].imageStore)
|
||||
return cache.NewLocal(daemon.imageStore)
|
||||
}
|
||||
|
||||
cache := cache.New(daemon.stores[platform].imageStore)
|
||||
cache := cache.New(daemon.imageStore)
|
||||
|
||||
for _, ref := range sourceRefs {
|
||||
img, err := daemon.GetImage(ref)
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -149,12 +150,15 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
||||
daemon.containerPause(container)
|
||||
defer daemon.containerUnpause(container)
|
||||
}
|
||||
if !system.IsOSSupported(container.OS) {
|
||||
return "", system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
|
||||
if c.MergeConfigs && c.Config == nil {
|
||||
c.Config = container.Config
|
||||
}
|
||||
|
||||
newConfig, err := dockerfile.BuildFromConfig(c.Config, c.Changes)
|
||||
newConfig, err := dockerfile.BuildFromConfig(c.Config, c.Changes, container.OS)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -180,17 +184,17 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
||||
parent = new(image.Image)
|
||||
parent.RootFS = image.NewRootFS()
|
||||
} else {
|
||||
parent, err = daemon.stores[container.OS].imageStore.Get(container.ImageID)
|
||||
parent, err = daemon.imageStore.Get(container.ImageID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
l, err := daemon.stores[container.OS].layerStore.Register(rwTar, parent.RootFS.ChainID(), layer.OS(container.OS))
|
||||
l, err := daemon.layerStores[container.OS].Register(rwTar, parent.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.stores[container.OS].layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.layerStores[container.OS], l)
|
||||
|
||||
containerConfig := c.ContainerConfig
|
||||
if containerConfig == nil {
|
||||
@@ -209,13 +213,13 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
||||
return "", err
|
||||
}
|
||||
|
||||
id, err := daemon.stores[container.OS].imageStore.Create(config)
|
||||
id, err := daemon.imageStore.Create(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if container.ImageID != "" {
|
||||
if err := daemon.stores[container.OS].imageStore.SetParent(id, container.ImageID); err != nil {
|
||||
if err := daemon.imageStore.SetParent(id, container.ImageID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@@ -234,7 +238,7 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if err := daemon.TagImageWithReference(id, container.OS, newTag); err != nil {
|
||||
if err := daemon.TagImageWithReference(id, newTag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
imageRef = reference.FamiliarString(newTag)
|
||||
@@ -251,13 +255,14 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
|
||||
}
|
||||
|
||||
func (daemon *Daemon) exportContainerRw(container *container.Container) (arch io.ReadCloser, err error) {
|
||||
rwlayer, err := daemon.stores[container.OS].layerStore.GetRWLayer(container.ID)
|
||||
// Note: Indexing by OS is safe as only called from `Commit` which has already performed validation
|
||||
rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
daemon.stores[container.OS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -278,7 +283,7 @@ func (daemon *Daemon) exportContainerRw(container *container.Container) (arch io
|
||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
archive.Close()
|
||||
err = rwlayer.Unmount()
|
||||
daemon.stores[container.OS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
|
||||
return err
|
||||
}),
|
||||
nil
|
||||
|
||||
@@ -257,7 +257,7 @@ func (daemon *Daemon) generateSecurityOpt(hostConfig *containertypes.HostConfig)
|
||||
func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
||||
var layerID layer.ChainID
|
||||
if container.ImageID != "" {
|
||||
img, err := daemon.stores[container.OS].imageStore.Get(container.ImageID)
|
||||
img, err := daemon.imageStore.Get(container.ImageID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -270,7 +270,9 @@ func (daemon *Daemon) setRWLayer(container *container.Container) error {
|
||||
StorageOpt: container.HostConfig.StorageOpt,
|
||||
}
|
||||
|
||||
rwLayer, err := daemon.stores[container.OS].layerStore.CreateRWLayer(container.ID, layerID, rwLayerOpts)
|
||||
// Indexing by OS is safe here as validation of OS has already been performed in create() (the only
|
||||
// caller), and guaranteed non-nil
|
||||
rwLayer, err := daemon.layerStores[container.OS].CreateRWLayer(container.ID, layerID, rwLayerOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -69,50 +69,46 @@ var (
|
||||
errSystemNotSupported = errors.New("the Docker daemon is not supported on this platform")
|
||||
)
|
||||
|
||||
type daemonStore struct {
|
||||
graphDriver string
|
||||
imageRoot string
|
||||
imageStore image.Store
|
||||
layerStore layer.Store
|
||||
distributionMetadataStore dmetadata.Store
|
||||
}
|
||||
|
||||
// Daemon holds information about the Docker daemon.
|
||||
type Daemon struct {
|
||||
ID string
|
||||
repository string
|
||||
containers container.Store
|
||||
containersReplica container.ViewDB
|
||||
execCommands *exec.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
trustKey libtrust.PrivateKey
|
||||
idIndex *truncindex.TruncIndex
|
||||
configStore *config.Config
|
||||
statsCollector *stats.Collector
|
||||
defaultLogConfig containertypes.LogConfig
|
||||
RegistryService registry.Service
|
||||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
volumes *store.VolumeStore
|
||||
discoveryWatcher discovery.Reloader
|
||||
root string
|
||||
seccompEnabled bool
|
||||
apparmorEnabled bool
|
||||
shutdown bool
|
||||
idMappings *idtools.IDMappings
|
||||
stores map[string]daemonStore // By container target platform
|
||||
referenceStore refstore.Store
|
||||
PluginStore *plugin.Store // todo: remove
|
||||
pluginManager *plugin.Manager
|
||||
linkIndex *linkIndex
|
||||
containerd libcontainerd.Client
|
||||
containerdRemote libcontainerd.Remote
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
genericResources []swarm.GenericResource
|
||||
metricsPluginListener net.Listener
|
||||
ID string
|
||||
repository string
|
||||
containers container.Store
|
||||
containersReplica container.ViewDB
|
||||
execCommands *exec.Store
|
||||
downloadManager *xfer.LayerDownloadManager
|
||||
uploadManager *xfer.LayerUploadManager
|
||||
trustKey libtrust.PrivateKey
|
||||
idIndex *truncindex.TruncIndex
|
||||
configStore *config.Config
|
||||
statsCollector *stats.Collector
|
||||
defaultLogConfig containertypes.LogConfig
|
||||
RegistryService registry.Service
|
||||
EventsService *events.Events
|
||||
netController libnetwork.NetworkController
|
||||
volumes *store.VolumeStore
|
||||
discoveryWatcher discovery.Reloader
|
||||
root string
|
||||
seccompEnabled bool
|
||||
apparmorEnabled bool
|
||||
shutdown bool
|
||||
idMappings *idtools.IDMappings
|
||||
graphDrivers map[string]string // By operating system
|
||||
referenceStore refstore.Store
|
||||
imageStore image.Store
|
||||
imageRoot string
|
||||
layerStores map[string]layer.Store // By operating system
|
||||
distributionMetadataStore dmetadata.Store
|
||||
PluginStore *plugin.Store // todo: remove
|
||||
pluginManager *plugin.Manager
|
||||
linkIndex *linkIndex
|
||||
containerd libcontainerd.Client
|
||||
containerdRemote libcontainerd.Remote
|
||||
defaultIsolation containertypes.Isolation // Default isolation mode on Windows
|
||||
clusterProvider cluster.Provider
|
||||
cluster Cluster
|
||||
genericResources []swarm.GenericResource
|
||||
metricsPluginListener net.Listener
|
||||
|
||||
machineMemory uint64
|
||||
|
||||
@@ -159,11 +155,14 @@ func (daemon *Daemon) restore() error {
|
||||
logrus.Errorf("Failed to load container %v: %v", id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !system.IsOSSupported(container.OS) {
|
||||
logrus.Errorf("Failed to load container %v: %s (%q)", id, system.ErrNotSupportedOperatingSystem, container.OS)
|
||||
continue
|
||||
}
|
||||
// Ignore the container if it does not support the current driver being used by the graph
|
||||
currentDriverForContainerOS := daemon.stores[container.OS].graphDriver
|
||||
currentDriverForContainerOS := daemon.graphDrivers[container.OS]
|
||||
if (container.Driver == "" && currentDriverForContainerOS == "aufs") || container.Driver == currentDriverForContainerOS {
|
||||
rwlayer, err := daemon.stores[container.OS].layerStore.GetRWLayer(container.ID)
|
||||
rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to load container mount %v: %v", id, err)
|
||||
continue
|
||||
@@ -706,11 +705,12 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
// lcow. Unix platforms however run a single graphdriver for all containers, and it can
|
||||
// be set through an environment variable, a daemon start parameter, or chosen through
|
||||
// initialization of the layerstore through driver priority order for example.
|
||||
d.stores = make(map[string]daemonStore)
|
||||
d.graphDrivers = make(map[string]string)
|
||||
d.layerStores = make(map[string]layer.Store)
|
||||
if runtime.GOOS == "windows" {
|
||||
d.stores["windows"] = daemonStore{graphDriver: "windowsfilter"}
|
||||
d.graphDrivers[runtime.GOOS] = "windowsfilter"
|
||||
if system.LCOWSupported() {
|
||||
d.stores["linux"] = daemonStore{graphDriver: "lcow"}
|
||||
d.graphDrivers["linux"] = "lcow"
|
||||
}
|
||||
} else {
|
||||
driverName := os.Getenv("DOCKER_DRIVER")
|
||||
@@ -719,7 +719,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
} else {
|
||||
logrus.Infof("Setting the storage driver from the $DOCKER_DRIVER environment variable (%s)", driverName)
|
||||
}
|
||||
d.stores[runtime.GOOS] = daemonStore{graphDriver: driverName} // May still be empty. Layerstore init determines instead.
|
||||
d.graphDrivers[runtime.GOOS] = driverName // May still be empty. Layerstore init determines instead.
|
||||
}
|
||||
|
||||
d.RegistryService = registryService
|
||||
@@ -750,12 +750,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
return nil, errors.Wrap(err, "couldn't create plugin manager")
|
||||
}
|
||||
|
||||
var graphDrivers []string
|
||||
for operatingSystem, ds := range d.stores {
|
||||
ls, err := layer.NewStoreFromOptions(layer.StoreOptions{
|
||||
StorePath: config.Root,
|
||||
for operatingSystem, gd := range d.graphDrivers {
|
||||
d.layerStores[operatingSystem], err = layer.NewStoreFromOptions(layer.StoreOptions{
|
||||
Root: config.Root,
|
||||
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
|
||||
GraphDriver: ds.graphDriver,
|
||||
GraphDriver: gd,
|
||||
GraphDriverOptions: config.GraphOptions,
|
||||
IDMappings: idMappings,
|
||||
PluginGetter: d.PluginStore,
|
||||
@@ -765,40 +764,37 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds.graphDriver = ls.DriverName() // As layerstore may set the driver
|
||||
ds.layerStore = ls
|
||||
d.stores[operatingSystem] = ds
|
||||
graphDrivers = append(graphDrivers, ls.DriverName())
|
||||
}
|
||||
|
||||
// Configure and validate the kernels security support
|
||||
if err := configureKernelSecuritySupport(config, graphDrivers); err != nil {
|
||||
// As layerstore initialization may set the driver
|
||||
for os := range d.graphDrivers {
|
||||
d.graphDrivers[os] = d.layerStores[os].DriverName()
|
||||
}
|
||||
|
||||
// Configure and validate the kernels security support. Note this is a Linux/FreeBSD
|
||||
// operation only, so it is safe to pass *just* the runtime OS graphdriver.
|
||||
if err := configureKernelSecuritySupport(config, d.graphDrivers[runtime.GOOS]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logrus.Debugf("Max Concurrent Downloads: %d", *config.MaxConcurrentDownloads)
|
||||
lsMap := make(map[string]layer.Store)
|
||||
for operatingSystem, ds := range d.stores {
|
||||
lsMap[operatingSystem] = ds.layerStore
|
||||
}
|
||||
d.downloadManager = xfer.NewLayerDownloadManager(lsMap, *config.MaxConcurrentDownloads)
|
||||
d.downloadManager = xfer.NewLayerDownloadManager(d.layerStores, *config.MaxConcurrentDownloads)
|
||||
logrus.Debugf("Max Concurrent Uploads: %d", *config.MaxConcurrentUploads)
|
||||
d.uploadManager = xfer.NewLayerUploadManager(*config.MaxConcurrentUploads)
|
||||
for operatingSystem, ds := range d.stores {
|
||||
imageRoot := filepath.Join(config.Root, "image", ds.graphDriver)
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(imageRoot, "imagedb"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var is image.Store
|
||||
is, err = image.NewImageStore(ifs, operatingSystem, ds.layerStore)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ds.imageRoot = imageRoot
|
||||
ds.imageStore = is
|
||||
d.stores[operatingSystem] = ds
|
||||
d.imageRoot = filepath.Join(config.Root, "image", d.graphDrivers[runtime.GOOS])
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(d.imageRoot, "imagedb"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lgrMap := make(map[string]image.LayerGetReleaser)
|
||||
for os, ls := range d.layerStores {
|
||||
lgrMap[os] = ls
|
||||
}
|
||||
d.imageStore, err = image.NewImageStore(ifs, lgrMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Configure the volumes driver
|
||||
@@ -830,30 +826,25 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
// operating systems, the list of graphdrivers available isn't user configurable.
|
||||
// For backwards compatibility, we just put it under the windowsfilter
|
||||
// directory regardless.
|
||||
refStoreLocation := filepath.Join(d.stores[runtime.GOOS].imageRoot, `repositories.json`)
|
||||
refStoreLocation := filepath.Join(d.imageRoot, `repositories.json`)
|
||||
rs, err := refstore.NewReferenceStore(refStoreLocation)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create reference store repository: %s", err)
|
||||
}
|
||||
d.referenceStore = rs
|
||||
|
||||
for platform, ds := range d.stores {
|
||||
dms, err := dmetadata.NewFSMetadataStore(filepath.Join(ds.imageRoot, "distribution"), platform)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.distributionMetadataStore, err = dmetadata.NewFSMetadataStore(filepath.Join(d.imageRoot, "distribution"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ds.distributionMetadataStore = dms
|
||||
d.stores[platform] = ds
|
||||
|
||||
// No content-addressability migration on Windows as it never supported pre-CA
|
||||
if runtime.GOOS != "windows" {
|
||||
migrationStart := time.Now()
|
||||
if err := v1.Migrate(config.Root, ds.graphDriver, ds.layerStore, ds.imageStore, rs, dms); err != nil {
|
||||
logrus.Errorf("Graph migration failed: %q. Your old graph data was found to be too inconsistent for upgrading to content-addressable storage. Some of the old data was probably not upgraded. We recommend starting over with a clean storage directory if possible.", err)
|
||||
}
|
||||
logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
|
||||
// No content-addressability migration on Windows as it never supported pre-CA
|
||||
if runtime.GOOS != "windows" {
|
||||
migrationStart := time.Now()
|
||||
if err := v1.Migrate(config.Root, d.graphDrivers[runtime.GOOS], d.layerStores[runtime.GOOS], d.imageStore, rs, d.distributionMetadataStore); err != nil {
|
||||
logrus.Errorf("Graph migration failed: %q. Your old graph data was found to be too inconsistent for upgrading to content-addressable storage. Some of the old data was probably not upgraded. We recommend starting over with a clean storage directory if possible.", err)
|
||||
}
|
||||
logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
|
||||
}
|
||||
|
||||
// Discovery is only enabled when the daemon is launched with an address to advertise. When
|
||||
@@ -922,13 +913,13 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
|
||||
engineMemory.Set(float64(info.MemTotal))
|
||||
|
||||
gd := ""
|
||||
for platform, ds := range d.stores {
|
||||
for os, driver := range d.graphDrivers {
|
||||
if len(gd) > 0 {
|
||||
gd += ", "
|
||||
}
|
||||
gd += ds.graphDriver
|
||||
if len(d.stores) > 1 {
|
||||
gd = fmt.Sprintf("%s (%s)", gd, platform)
|
||||
gd += driver
|
||||
if len(d.graphDrivers) > 1 {
|
||||
gd = fmt.Sprintf("%s (%s)", gd, os)
|
||||
}
|
||||
}
|
||||
logrus.WithFields(logrus.Fields{
|
||||
@@ -1009,7 +1000,7 @@ func (daemon *Daemon) Shutdown() error {
|
||||
logrus.Errorf("Stop container error: %v", err)
|
||||
return
|
||||
}
|
||||
if mountid, err := daemon.stores[c.OS].layerStore.GetMountID(c.ID); err == nil {
|
||||
if mountid, err := daemon.layerStores[c.OS].GetMountID(c.ID); err == nil {
|
||||
daemon.cleanupMountsByID(mountid)
|
||||
}
|
||||
logrus.Debugf("container stopped %s", c.ID)
|
||||
@@ -1022,10 +1013,10 @@ func (daemon *Daemon) Shutdown() error {
|
||||
}
|
||||
}
|
||||
|
||||
for platform, ds := range daemon.stores {
|
||||
if ds.layerStore != nil {
|
||||
if err := ds.layerStore.Cleanup(); err != nil {
|
||||
logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, platform)
|
||||
for os, ls := range daemon.layerStores {
|
||||
if ls != nil {
|
||||
if err := ls.Cleanup(); err != nil {
|
||||
logrus.Errorf("Error during layer Store.Cleanup(): %v %s", err, os)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1107,8 +1098,8 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
|
||||
}
|
||||
|
||||
// GraphDriverName returns the name of the graph driver used by the layer.Store
|
||||
func (daemon *Daemon) GraphDriverName(platform string) string {
|
||||
return daemon.stores[platform].layerStore.DriverName()
|
||||
func (daemon *Daemon) GraphDriverName(os string) string {
|
||||
return daemon.layerStores[os].DriverName()
|
||||
}
|
||||
|
||||
// prepareTempDir prepares and returns the default directory to use
|
||||
|
||||
@@ -814,22 +814,14 @@ func overlaySupportsSelinux() (bool, error) {
|
||||
}
|
||||
|
||||
// configureKernelSecuritySupport configures and validates security support for the kernel
|
||||
func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
|
||||
func configureKernelSecuritySupport(config *config.Config, driverName string) error {
|
||||
if config.EnableSelinuxSupport {
|
||||
if !selinuxEnabled() {
|
||||
logrus.Warn("Docker could not enable SELinux on the host system")
|
||||
return nil
|
||||
}
|
||||
|
||||
overlayFound := false
|
||||
for _, d := range driverNames {
|
||||
if d == "overlay" || d == "overlay2" {
|
||||
overlayFound = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if overlayFound {
|
||||
if driverName == "overlay" || driverName == "overlay2" {
|
||||
// If driver is overlay or overlay2, make sure kernel
|
||||
// supports selinux with overlay.
|
||||
supported, err := overlaySupportsSelinux()
|
||||
@@ -838,7 +830,7 @@ func configureKernelSecuritySupport(config *config.Config, driverNames []string)
|
||||
}
|
||||
|
||||
if !supported {
|
||||
logrus.Warnf("SELinux is not supported with the %v graph driver on this kernel", driverNames)
|
||||
logrus.Warnf("SELinux is not supported with the %v graph driver on this kernel", driverName)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -262,7 +262,7 @@ func ensureServicesInstalled(services []string) error {
|
||||
}
|
||||
|
||||
// configureKernelSecuritySupport configures and validate security support for the kernel
|
||||
func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
|
||||
func configureKernelSecuritySupport(config *config.Config, driverName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
||||
return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err)
|
||||
}
|
||||
}
|
||||
if !system.IsOSSupported(container.OS) {
|
||||
return fmt.Errorf("cannot remove %s: %s ", container.ID, system.ErrNotSupportedOperatingSystem)
|
||||
}
|
||||
|
||||
// stop collection of stats for the container regardless
|
||||
// if stats are currently getting collected.
|
||||
@@ -118,7 +121,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
|
||||
// When container creation fails and `RWLayer` has not been created yet, we
|
||||
// do not call `ReleaseRWLayer`
|
||||
if container.RWLayer != nil {
|
||||
metadata, err := daemon.stores[container.OS].layerStore.ReleaseRWLayer(container.RWLayer)
|
||||
metadata, err := daemon.layerStores[container.OS].ReleaseRWLayer(container.RWLayer)
|
||||
layer.LogReleaseMetadata(metadata)
|
||||
if err != nil && err != layer.ErrMountDoesNotExist && !os.IsNotExist(errors.Cause(err)) {
|
||||
e := errors.Wrapf(err, "driver %q failed to remove root filesystem for %s", daemon.GraphDriverName(container.OS), container.ID)
|
||||
|
||||
@@ -15,12 +15,12 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (daemon *Daemon) getLayerRefs(platform string) map[layer.ChainID]int {
|
||||
tmpImages := daemon.stores[platform].imageStore.Map()
|
||||
func (daemon *Daemon) getLayerRefs() map[layer.ChainID]int {
|
||||
tmpImages := daemon.imageStore.Map()
|
||||
layerRefs := map[layer.ChainID]int{}
|
||||
for id, img := range tmpImages {
|
||||
dgst := digest.Digest(id)
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.stores[platform].imageStore.Children(id)) != 0 {
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
||||
}
|
||||
|
||||
// Get all top images with extra attributes
|
||||
// TODO @jhowardmsft LCOW. This may need revisiting
|
||||
allImages, err := daemon.Images(filters.NewArgs(), false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
||||
@@ -96,9 +95,9 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
||||
|
||||
// Get total layers size on disk
|
||||
var allLayersSize int64
|
||||
for platform := range daemon.stores {
|
||||
layerRefs := daemon.getLayerRefs(platform)
|
||||
allLayers := daemon.stores[platform].layerStore.Map()
|
||||
layerRefs := daemon.getLayerRefs()
|
||||
for _, ls := range daemon.layerStores {
|
||||
allLayers := ls.Map()
|
||||
for _, l := range allLayers {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
@@ -109,10 +108,10 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, er
|
||||
if _, ok := layerRefs[l.ChainID()]; ok {
|
||||
allLayersSize += size
|
||||
} else {
|
||||
logrus.Warnf("found leaked image layer %v platform %s", l.ChainID(), platform)
|
||||
logrus.Warnf("found leaked image layer %v", l.ChainID())
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("failed to get diff size for layer %v %s", l.ChainID(), platform)
|
||||
logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// ContainerExport writes the contents of the container to the given
|
||||
@@ -47,13 +48,16 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
|
||||
}
|
||||
|
||||
func (daemon *Daemon) containerExport(container *container.Container) (arch io.ReadCloser, err error) {
|
||||
rwlayer, err := daemon.stores[container.OS].layerStore.GetRWLayer(container.ID)
|
||||
if !system.IsOSSupported(container.OS) {
|
||||
return nil, fmt.Errorf("cannot export %s: %s ", container.ID, system.ErrNotSupportedOperatingSystem)
|
||||
}
|
||||
rwlayer, err := daemon.layerStores[container.OS].GetRWLayer(container.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
daemon.stores[container.OS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -74,7 +78,7 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
|
||||
arch = ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
err := archive.Close()
|
||||
rwlayer.Unmount()
|
||||
daemon.stores[container.OS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
daemon.layerStores[container.OS].ReleaseRWLayer(rwlayer)
|
||||
return err
|
||||
})
|
||||
daemon.LogContainerEvent(container, "export")
|
||||
|
||||
@@ -15,12 +15,14 @@ func (daemon *Daemon) getSize(containerID string) (int64, int64) {
|
||||
err error
|
||||
)
|
||||
|
||||
rwlayer, err := daemon.stores[runtime.GOOS].layerStore.GetRWLayer(containerID)
|
||||
// Safe to index by runtime.GOOS as Unix hosts don't support multiple
|
||||
// container operating systems.
|
||||
rwlayer, err := daemon.layerStores[runtime.GOOS].GetRWLayer(containerID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Failed to compute size of container rootfs %v: %v", containerID, err)
|
||||
return sizeRw, sizeRootfs
|
||||
}
|
||||
defer daemon.stores[runtime.GOOS].layerStore.ReleaseRWLayer(rwlayer)
|
||||
defer daemon.layerStores[runtime.GOOS].ReleaseRWLayer(rwlayer)
|
||||
|
||||
sizeRw, err = rwlayer.Size()
|
||||
if err != nil {
|
||||
|
||||
@@ -931,8 +931,6 @@ func parseStorageOpt(storageOpt map[string]string) (*storageOptions, error) {
|
||||
return nil, err
|
||||
}
|
||||
options.size = uint64(size)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unknown storage option: %s", key)
|
||||
}
|
||||
}
|
||||
return &options, nil
|
||||
|
||||
@@ -2,7 +2,6 @@ package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/errdefs"
|
||||
@@ -38,32 +37,27 @@ func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error)
|
||||
return "", "", errImageDoesNotExist{ref}
|
||||
}
|
||||
id := image.IDFromDigest(digested.Digest())
|
||||
for platform := range daemon.stores {
|
||||
if _, err = daemon.stores[platform].imageStore.Get(id); err == nil {
|
||||
return id, platform, nil
|
||||
}
|
||||
if img, err := daemon.imageStore.Get(id); err == nil {
|
||||
return id, img.OperatingSystem(), nil
|
||||
}
|
||||
return "", "", errImageDoesNotExist{ref}
|
||||
}
|
||||
|
||||
if digest, err := daemon.referenceStore.Get(namedRef); err == nil {
|
||||
// Search the image stores to get the operating system, defaulting to host OS.
|
||||
imageOS := runtime.GOOS
|
||||
id := image.IDFromDigest(digest)
|
||||
for os := range daemon.stores {
|
||||
if img, err := daemon.stores[os].imageStore.Get(id); err == nil {
|
||||
imageOS = img.OperatingSystem()
|
||||
break
|
||||
}
|
||||
if img, err := daemon.imageStore.Get(id); err == nil {
|
||||
return id, img.OperatingSystem(), nil
|
||||
}
|
||||
return id, imageOS, nil
|
||||
}
|
||||
|
||||
// Search based on ID
|
||||
for os := range daemon.stores {
|
||||
if id, err := daemon.stores[os].imageStore.Search(refOrID); err == nil {
|
||||
return id, os, nil
|
||||
if id, err := daemon.imageStore.Search(refOrID); err == nil {
|
||||
img, err := daemon.imageStore.Get(id)
|
||||
if err != nil {
|
||||
return "", "", errImageDoesNotExist{ref}
|
||||
}
|
||||
return id, img.OperatingSystem(), nil
|
||||
}
|
||||
|
||||
return "", "", errImageDoesNotExist{ref}
|
||||
@@ -71,9 +65,9 @@ func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error)
|
||||
|
||||
// GetImage returns an image corresponding to the image referred to by refOrID.
|
||||
func (daemon *Daemon) GetImage(refOrID string) (*image.Image, error) {
|
||||
imgID, os, err := daemon.GetImageIDAndOS(refOrID)
|
||||
imgID, _, err := daemon.GetImageIDAndOS(refOrID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return daemon.stores[os].imageStore.Get(imgID)
|
||||
return daemon.imageStore.Get(imgID)
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -66,10 +67,13 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
start := time.Now()
|
||||
records := []types.ImageDeleteResponseItem{}
|
||||
|
||||
imgID, os, err := daemon.GetImageIDAndOS(imageRef)
|
||||
imgID, operatingSystem, err := daemon.GetImageIDAndOS(imageRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !system.IsOSSupported(operatingSystem) {
|
||||
return nil, errors.Errorf("unable to delete image: %q", system.ErrNotSupportedOperatingSystem)
|
||||
}
|
||||
|
||||
repoRefs := daemon.referenceStore.References(imgID.Digest())
|
||||
|
||||
@@ -95,7 +99,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsedRef, err = daemon.removeImageRef(os, parsedRef)
|
||||
parsedRef, err = daemon.removeImageRef(parsedRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -123,7 +127,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
remainingRefs := []reference.Named{}
|
||||
for _, repoRef := range repoRefs {
|
||||
if _, repoRefIsCanonical := repoRef.(reference.Canonical); repoRefIsCanonical && parsedRef.Name() == repoRef.Name() {
|
||||
if _, err := daemon.removeImageRef(os, repoRef); err != nil {
|
||||
if _, err := daemon.removeImageRef(repoRef); err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
@@ -153,12 +157,12 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
if !force {
|
||||
c |= conflictSoft &^ conflictActiveReference
|
||||
}
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, os, c); conflict != nil {
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
|
||||
return nil, conflict
|
||||
}
|
||||
|
||||
for _, repoRef := range repoRefs {
|
||||
parsedRef, err := daemon.removeImageRef(os, repoRef)
|
||||
parsedRef, err := daemon.removeImageRef(repoRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -171,7 +175,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
|
||||
}
|
||||
}
|
||||
|
||||
if err := daemon.imageDeleteHelper(imgID, os, &records, force, prune, removedRepositoryRef); err != nil {
|
||||
if err := daemon.imageDeleteHelper(imgID, &records, force, prune, removedRepositoryRef); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -232,7 +236,7 @@ func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Contai
|
||||
// repositoryRef must not be an image ID but a repository name followed by an
|
||||
// optional tag or digest reference. If tag or digest is omitted, the default
|
||||
// tag is used. Returns the resolved image reference and an error.
|
||||
func (daemon *Daemon) removeImageRef(platform string, ref reference.Named) (reference.Named, error) {
|
||||
func (daemon *Daemon) removeImageRef(ref reference.Named) (reference.Named, error) {
|
||||
ref = reference.TagNameOnly(ref)
|
||||
|
||||
// Ignore the boolean value returned, as far as we're concerned, this
|
||||
@@ -248,11 +252,11 @@ func (daemon *Daemon) removeImageRef(platform string, ref reference.Named) (refe
|
||||
// on the first encountered error. Removed references are logged to this
|
||||
// daemon's event service. An "Untagged" types.ImageDeleteResponseItem is added to the
|
||||
// given list of records.
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, platform string, records *[]types.ImageDeleteResponseItem) error {
|
||||
func (daemon *Daemon) removeAllReferencesToImageID(imgID image.ID, records *[]types.ImageDeleteResponseItem) error {
|
||||
imageRefs := daemon.referenceStore.References(imgID.Digest())
|
||||
|
||||
for _, imageRef := range imageRefs {
|
||||
parsedRef, err := daemon.removeImageRef(platform, imageRef)
|
||||
parsedRef, err := daemon.removeImageRef(imageRef)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -299,15 +303,15 @@ func (idc *imageDeleteConflict) Conflict() {}
|
||||
// conflict is encountered, it will be returned immediately without deleting
|
||||
// the image. If quiet is true, any encountered conflicts will be ignored and
|
||||
// the function will return nil immediately without deleting the image.
|
||||
func (daemon *Daemon) imageDeleteHelper(imgID image.ID, platform string, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
|
||||
func (daemon *Daemon) imageDeleteHelper(imgID image.ID, records *[]types.ImageDeleteResponseItem, force, prune, quiet bool) error {
|
||||
// First, determine if this image has any conflicts. Ignore soft conflicts
|
||||
// if force is true.
|
||||
c := conflictHard
|
||||
if !force {
|
||||
c |= conflictSoft
|
||||
}
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, platform, c); conflict != nil {
|
||||
if quiet && (!daemon.imageIsDangling(imgID, platform) || conflict.used) {
|
||||
if conflict := daemon.checkImageDeleteConflict(imgID, c); conflict != nil {
|
||||
if quiet && (!daemon.imageIsDangling(imgID) || conflict.used) {
|
||||
// Ignore conflicts UNLESS the image is "dangling" or not being used in
|
||||
// which case we want the user to know.
|
||||
return nil
|
||||
@@ -318,18 +322,18 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, platform string, records
|
||||
return conflict
|
||||
}
|
||||
|
||||
parent, err := daemon.stores[platform].imageStore.GetParent(imgID)
|
||||
parent, err := daemon.imageStore.GetParent(imgID)
|
||||
if err != nil {
|
||||
// There may be no parent
|
||||
parent = ""
|
||||
}
|
||||
|
||||
// Delete all repository tag/digest references to this image.
|
||||
if err := daemon.removeAllReferencesToImageID(imgID, platform, records); err != nil {
|
||||
if err := daemon.removeAllReferencesToImageID(imgID, records); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
removedLayers, err := daemon.stores[platform].imageStore.Delete(imgID)
|
||||
removedLayers, err := daemon.imageStore.Delete(imgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -349,7 +353,7 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, platform string, records
|
||||
// either running or stopped).
|
||||
// Do not force prunings, but do so quietly (stopping on any encountered
|
||||
// conflicts).
|
||||
return daemon.imageDeleteHelper(parent, platform, records, false, true, true)
|
||||
return daemon.imageDeleteHelper(parent, records, false, true, true)
|
||||
}
|
||||
|
||||
// checkImageDeleteConflict determines whether there are any conflicts
|
||||
@@ -358,9 +362,9 @@ func (daemon *Daemon) imageDeleteHelper(imgID image.ID, platform string, records
|
||||
// using the image. A soft conflict is any tags/digest referencing the given
|
||||
// image or any stopped container using the image. If ignoreSoftConflicts is
|
||||
// true, this function will not check for soft conflict conditions.
|
||||
func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, platform string, mask conflictType) *imageDeleteConflict {
|
||||
func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType) *imageDeleteConflict {
|
||||
// Check if the image has any descendant images.
|
||||
if mask&conflictDependentChild != 0 && len(daemon.stores[platform].imageStore.Children(imgID)) > 0 {
|
||||
if mask&conflictDependentChild != 0 && len(daemon.imageStore.Children(imgID)) > 0 {
|
||||
return &imageDeleteConflict{
|
||||
hard: true,
|
||||
imgID: imgID,
|
||||
@@ -411,6 +415,6 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, platform string,
|
||||
// imageIsDangling returns whether the given image is "dangling" which means
|
||||
// that there are no repository references to the given image and it has no
|
||||
// child images.
|
||||
func (daemon *Daemon) imageIsDangling(imgID image.ID, platform string) bool {
|
||||
return !(len(daemon.referenceStore.References(imgID.Digest())) > 0 || len(daemon.stores[platform].imageStore.Children(imgID)) > 0)
|
||||
func (daemon *Daemon) imageIsDangling(imgID image.ID) bool {
|
||||
return !(len(daemon.referenceStore.References(imgID.Digest())) > 0 || len(daemon.imageStore.Children(imgID)) > 0)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,8 @@ package daemon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/docker/image/tarexport"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// ExportImage exports a list of images to the given output stream. The
|
||||
@@ -14,12 +12,7 @@ import (
|
||||
// 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 {
|
||||
// TODO @jhowardmsft LCOW. This will need revisiting later.
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
imageExporter := tarexport.NewTarExporter(daemon.stores[platform].imageStore, daemon.stores[platform].layerStore, daemon.referenceStore, daemon)
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStores, daemon.referenceStore, daemon)
|
||||
return imageExporter.Save(names, outStream)
|
||||
}
|
||||
|
||||
@@ -27,11 +20,6 @@ func (daemon *Daemon) ExportImage(names []string, outStream io.Writer) error {
|
||||
// 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 {
|
||||
// TODO @jhowardmsft LCOW. This will need revisiting later.
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
imageExporter := tarexport.NewTarExporter(daemon.stores[platform].imageStore, daemon.stores[platform].layerStore, daemon.referenceStore, daemon)
|
||||
imageExporter := tarexport.NewTarExporter(daemon.imageStore, daemon.layerStores, daemon.referenceStore, daemon)
|
||||
return imageExporter.Load(inTar, outStream, quiet)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package daemon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
@@ -19,12 +18,6 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the image OS isn't set, assume it's the host OS
|
||||
platform := img.OS
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
}
|
||||
|
||||
history := []*image.HistoryResponseItem{}
|
||||
|
||||
layerCounter := 0
|
||||
@@ -40,12 +33,12 @@ func (daemon *Daemon) ImageHistory(name string) ([]*image.HistoryResponseItem, e
|
||||
}
|
||||
|
||||
rootFS.Append(img.RootFS.DiffIDs[layerCounter])
|
||||
l, err := daemon.stores[platform].layerStore.Get(rootFS.ChainID())
|
||||
l, err := daemon.layerStores[img.OperatingSystem()].Get(rootFS.ChainID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
layerSize, err = l.DiffSize()
|
||||
layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution/reference"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
@@ -17,13 +17,9 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "no such image: %s", name)
|
||||
}
|
||||
|
||||
// If the image OS isn't set, assume it's the host OS
|
||||
platform := img.OS
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
|
||||
refs := daemon.referenceStore.References(img.ID().Digest())
|
||||
repoTags := []string{}
|
||||
repoDigests := []string{}
|
||||
@@ -40,11 +36,11 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||
var layerMetadata map[string]string
|
||||
layerID := img.RootFS.ChainID()
|
||||
if layerID != "" {
|
||||
l, err := daemon.stores[platform].layerStore.Get(layerID)
|
||||
l, err := daemon.layerStores[img.OperatingSystem()].Get(layerID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
|
||||
size, err = l.Size()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -61,7 +57,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||
comment = img.History[len(img.History)-1].Comment
|
||||
}
|
||||
|
||||
lastUpdated, err := daemon.stores[platform].imageStore.GetLastUpdated(img.ID())
|
||||
lastUpdated, err := daemon.imageStore.GetLastUpdated(img.ID())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -79,7 +75,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||
Author: img.Author,
|
||||
Config: img.Config,
|
||||
Architecture: img.Architecture,
|
||||
Os: platform,
|
||||
Os: img.OperatingSystem(),
|
||||
OsVersion: img.OSVersion,
|
||||
Size: size,
|
||||
VirtualSize: size, // TODO: field unused, deprecate
|
||||
@@ -89,7 +85,7 @@ func (daemon *Daemon) LookupImage(name string) (*types.ImageInspect, error) {
|
||||
},
|
||||
}
|
||||
|
||||
imageInspect.GraphDriver.Name = daemon.GraphDriverName(platform)
|
||||
imageInspect.GraphDriver.Name = daemon.GraphDriverName(img.OperatingSystem())
|
||||
imageInspect.GraphDriver.Data = layerMetadata
|
||||
|
||||
return imageInspect, nil
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
|
||||
// PullImage initiates a pull operation. image is the repository name to pull, and
|
||||
// tag may be either empty, or indicate a specific tag to pull.
|
||||
func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
func (daemon *Daemon) PullImage(ctx context.Context, image, tag, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
// Special case: "pull -a" may send an image name with a
|
||||
// trailing :. This is ugly, but let's not break API
|
||||
// compatibility.
|
||||
@@ -44,10 +44,10 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string
|
||||
}
|
||||
}
|
||||
|
||||
return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream)
|
||||
return daemon.pullImageWithReference(ctx, ref, os, metaHeaders, authConfig, outStream)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
||||
// Include a buffer so that slow client connections don't affect
|
||||
// transfer performance.
|
||||
progressChan := make(chan progress.Progress, 100)
|
||||
@@ -62,8 +62,8 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
|
||||
}()
|
||||
|
||||
// Default to the host OS platform in case it hasn't been populated with an explicit value.
|
||||
if platform == "" {
|
||||
platform = runtime.GOOS
|
||||
if os == "" {
|
||||
os = runtime.GOOS
|
||||
}
|
||||
|
||||
imagePullConfig := &distribution.ImagePullConfig{
|
||||
@@ -73,13 +73,13 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.stores[platform].distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore),
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
},
|
||||
DownloadManager: daemon.downloadManager,
|
||||
Schema2Types: distribution.ImageTypes,
|
||||
Platform: platform,
|
||||
OS: os,
|
||||
}
|
||||
|
||||
err := distribution.Pull(ctx, ref, imagePullConfig)
|
||||
|
||||
@@ -2,7 +2,6 @@ package daemon
|
||||
|
||||
import (
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/docker/distribution/reference"
|
||||
@@ -10,7 +9,6 @@ import (
|
||||
"github.com/docker/docker/distribution"
|
||||
progressutils "github.com/docker/docker/distribution/utils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
@@ -41,12 +39,6 @@ func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHead
|
||||
close(writesDone)
|
||||
}()
|
||||
|
||||
// TODO @jhowardmsft LCOW Support. This will require revisiting. For now, hard-code.
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
|
||||
imagePushConfig := &distribution.ImagePushConfig{
|
||||
Config: distribution.Config{
|
||||
MetaHeaders: metaHeaders,
|
||||
@@ -54,12 +46,12 @@ func (daemon *Daemon) PushImage(ctx context.Context, image, tag string, metaHead
|
||||
ProgressOutput: progress.ChanOutput(progressChan),
|
||||
RegistryService: daemon.RegistryService,
|
||||
ImageEventLogger: daemon.LogImageEvent,
|
||||
MetadataStore: daemon.stores[platform].distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore),
|
||||
MetadataStore: daemon.distributionMetadataStore,
|
||||
ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
|
||||
ReferenceStore: daemon.referenceStore,
|
||||
},
|
||||
ConfigMediaType: schema2.MediaTypeImageConfig,
|
||||
LayerStore: distribution.NewLayerProviderFromStore(daemon.stores[platform].layerStore),
|
||||
LayerStores: distribution.NewLayerProvidersFromStores(daemon.layerStores),
|
||||
TrustKey: daemon.trustKey,
|
||||
UploadManager: daemon.uploadManager,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
// TagImage creates the tag specified by newTag, pointing to the image named
|
||||
// imageName (alternatively, imageName can also be an image ID).
|
||||
func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
||||
imageID, os, err := daemon.GetImageIDAndOS(imageName)
|
||||
imageID, _, err := daemon.GetImageIDAndOS(imageName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -23,16 +23,16 @@ func (daemon *Daemon) TagImage(imageName, repository, tag string) error {
|
||||
}
|
||||
}
|
||||
|
||||
return daemon.TagImageWithReference(imageID, os, newTag)
|
||||
return daemon.TagImageWithReference(imageID, newTag)
|
||||
}
|
||||
|
||||
// TagImageWithReference adds the given reference to the image ID provided.
|
||||
func (daemon *Daemon) TagImageWithReference(imageID image.ID, os string, newTag reference.Named) error {
|
||||
func (daemon *Daemon) TagImageWithReference(imageID image.ID, newTag reference.Named) error {
|
||||
if err := daemon.referenceStore.AddTag(newTag, imageID.Digest(), true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := daemon.stores[os].imageStore.SetLastUpdated(imageID); err != nil {
|
||||
if err := daemon.imageStore.SetLastUpdated(imageID); err != nil {
|
||||
return err
|
||||
}
|
||||
daemon.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
|
||||
|
||||
@@ -3,7 +3,6 @@ package daemon
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
@@ -36,12 +35,7 @@ func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created }
|
||||
|
||||
// Map returns a map of all images in the ImageStore
|
||||
func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
||||
// TODO @jhowardmsft LCOW. This can be removed when imagestores are coalesced
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
return daemon.stores[platform].imageStore.Map()
|
||||
return daemon.imageStore.Map()
|
||||
}
|
||||
|
||||
// Images returns a filtered list of images. filterArgs is a JSON-encoded set
|
||||
@@ -50,13 +44,6 @@ func (daemon *Daemon) Map() map[image.ID]*image.Image {
|
||||
// named all controls whether all images in the graph are filtered, or just
|
||||
// the heads.
|
||||
func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) {
|
||||
|
||||
// TODO @jhowardmsft LCOW. This can be removed when imagestores are coalesced
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
|
||||
var (
|
||||
allImages map[image.ID]*image.Image
|
||||
err error
|
||||
@@ -75,9 +62,9 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
}
|
||||
}
|
||||
if danglingOnly {
|
||||
allImages = daemon.stores[platform].imageStore.Heads()
|
||||
allImages = daemon.imageStore.Heads()
|
||||
} else {
|
||||
allImages = daemon.stores[platform].imageStore.Map()
|
||||
allImages = daemon.imageStore.Map()
|
||||
}
|
||||
|
||||
var beforeFilter, sinceFilter *image.Image
|
||||
@@ -127,10 +114,17 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
}
|
||||
}
|
||||
|
||||
// Skip any images with an unsupported operating system to avoid a potential
|
||||
// panic when indexing through the layerstore. Don't error as we want to list
|
||||
// the other images. This should never happen, but here as a safety precaution.
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
continue
|
||||
}
|
||||
|
||||
layerID := img.RootFS.ChainID()
|
||||
var size int64
|
||||
if layerID != "" {
|
||||
l, err := daemon.stores[platform].layerStore.Get(layerID)
|
||||
l, err := daemon.layerStores[img.OperatingSystem()].Get(layerID)
|
||||
if err != nil {
|
||||
// The layer may have been deleted between the call to `Map()` or
|
||||
// `Heads()` and the call to `Get()`, so we just ignore this error
|
||||
@@ -141,7 +135,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
}
|
||||
|
||||
size, err = l.Size()
|
||||
layer.ReleaseAndLog(daemon.stores[platform].layerStore, l)
|
||||
layer.ReleaseAndLog(daemon.layerStores[img.OperatingSystem()], l)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -171,7 +165,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
}
|
||||
}
|
||||
if newImage.RepoDigests == nil && newImage.RepoTags == nil {
|
||||
if all || len(daemon.stores[platform].imageStore.Children(id)) == 0 {
|
||||
if all || len(daemon.imageStore.Children(id)) == 0 {
|
||||
|
||||
if imageFilters.Contains("dangling") && !danglingOnly {
|
||||
//dangling=false case, so dangling image is not needed
|
||||
@@ -193,7 +187,7 @@ func (daemon *Daemon) Images(imageFilters filters.Args, all bool, withExtraAttrs
|
||||
// lazily init variables
|
||||
if imagesMap == nil {
|
||||
allContainers = daemon.List()
|
||||
allLayers = daemon.stores[platform].layerStore.Map()
|
||||
allLayers = daemon.layerStores[img.OperatingSystem()].Map()
|
||||
imagesMap = make(map[*image.Image]*types.ImageSummary)
|
||||
layerRefs = make(map[layer.ChainID]int)
|
||||
}
|
||||
@@ -261,19 +255,14 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
||||
img *image.Image
|
||||
err error
|
||||
)
|
||||
for _, ds := range daemon.stores {
|
||||
if img, err = ds.imageStore.Get(image.ID(id)); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if img, err = daemon.imageStore.Get(image.ID(id)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var parentImg *image.Image
|
||||
var parentChainID layer.ChainID
|
||||
if len(parent) != 0 {
|
||||
parentImg, err = daemon.stores[img.OperatingSystem()].imageStore.Get(image.ID(parent))
|
||||
parentImg, err = daemon.imageStore.Get(image.ID(parent))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting specified parent layer")
|
||||
}
|
||||
@@ -283,11 +272,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
||||
parentImg = &image.Image{RootFS: rootFS}
|
||||
}
|
||||
|
||||
l, err := daemon.stores[img.OperatingSystem()].layerStore.Get(img.RootFS.ChainID())
|
||||
l, err := daemon.layerStores[img.OperatingSystem()].Get(img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error getting image layer")
|
||||
}
|
||||
defer daemon.stores[img.OperatingSystem()].layerStore.Release(l)
|
||||
defer daemon.layerStores[img.OperatingSystem()].Release(l)
|
||||
|
||||
ts, err := l.TarStreamFrom(parentChainID)
|
||||
if err != nil {
|
||||
@@ -295,11 +284,11 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
newL, err := daemon.stores[img.OperatingSystem()].layerStore.Register(ts, parentChainID, layer.OS(img.OperatingSystem()))
|
||||
newL, err := daemon.layerStores[img.OperatingSystem()].Register(ts, parentChainID)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error registering layer")
|
||||
}
|
||||
defer daemon.stores[img.OperatingSystem()].layerStore.Release(newL)
|
||||
defer daemon.layerStores[img.OperatingSystem()].Release(newL)
|
||||
|
||||
newImage := *img
|
||||
newImage.RootFS = nil
|
||||
@@ -334,7 +323,7 @@ func (daemon *Daemon) SquashImage(id, parent string) (string, error) {
|
||||
return "", errors.Wrap(err, "error marshalling image config")
|
||||
}
|
||||
|
||||
newImgID, err := daemon.stores[img.OperatingSystem()].imageStore.Create(b)
|
||||
newImgID, err := daemon.imageStore.Create(b)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error creating new image after squash")
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func (daemon *Daemon) ImportImage(src string, repository, os string, tag string,
|
||||
}
|
||||
}
|
||||
|
||||
config, err := dockerfile.BuildFromConfig(&container.Config{}, changes)
|
||||
config, err := dockerfile.BuildFromConfig(&container.Config{}, changes, os)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -91,11 +91,11 @@ func (daemon *Daemon) ImportImage(src string, repository, os string, tag string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l, err := daemon.stores[os].layerStore.Register(inflatedLayerData, "", layer.OS(os))
|
||||
l, err := daemon.layerStores[os].Register(inflatedLayerData, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer layer.ReleaseAndLog(daemon.stores[os].layerStore, l)
|
||||
defer layer.ReleaseAndLog(daemon.layerStores[os], l)
|
||||
|
||||
created := time.Now().UTC()
|
||||
imgConfig, err := json.Marshal(&image.Image{
|
||||
@@ -120,14 +120,14 @@ func (daemon *Daemon) ImportImage(src string, repository, os string, tag string,
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := daemon.stores[os].imageStore.Create(imgConfig)
|
||||
id, err := daemon.imageStore.Create(imgConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// FIXME: connect with commit code and call refstore directly
|
||||
if newRef != nil {
|
||||
if err := daemon.TagImageWithReference(id, os, newRef); err != nil {
|
||||
if err := daemon.TagImageWithReference(id, newRef); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,32 +78,26 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
|
||||
securityOptions = append(securityOptions, "name=userns")
|
||||
}
|
||||
|
||||
imageCount := 0
|
||||
var ds [][2]string
|
||||
drivers := ""
|
||||
for p, ds := range daemon.stores {
|
||||
imageCount += len(ds.imageStore.Map())
|
||||
drivers += daemon.GraphDriverName(p)
|
||||
if len(daemon.stores) > 1 {
|
||||
drivers += fmt.Sprintf(" (%s) ", p)
|
||||
for os, gd := range daemon.graphDrivers {
|
||||
ds = append(ds, daemon.layerStores[os].DriverStatus()...)
|
||||
drivers += gd
|
||||
if len(daemon.graphDrivers) > 1 {
|
||||
drivers += fmt.Sprintf(" (%s) ", os)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO @jhowardmsft LCOW support. For now, hard-code the platform shown for the driver status
|
||||
p := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
p = "linux"
|
||||
}
|
||||
|
||||
drivers = strings.TrimSpace(drivers)
|
||||
|
||||
v := &types.Info{
|
||||
ID: daemon.ID,
|
||||
Containers: cRunning + cPaused + cStopped,
|
||||
ContainersRunning: cRunning,
|
||||
ContainersPaused: cPaused,
|
||||
ContainersStopped: cStopped,
|
||||
Images: imageCount,
|
||||
Images: len(daemon.imageStore.Map()),
|
||||
Driver: drivers,
|
||||
DriverStatus: daemon.stores[p].layerStore.DriverStatus(),
|
||||
DriverStatus: ds,
|
||||
Plugins: daemon.showPluginsInfo(),
|
||||
IPv4Forwarding: !sysInfo.IPv4ForwardingDisabled,
|
||||
BridgeNfIptables: !sysInfo.BridgeNFCallIPTablesDisabled,
|
||||
|
||||
@@ -323,7 +323,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
|
||||
if psFilters.Contains("ancestor") {
|
||||
ancestorFilter = true
|
||||
psFilters.WalkValues("ancestor", func(ancestor string) error {
|
||||
id, os, err := daemon.GetImageIDAndOS(ancestor)
|
||||
id, _, err := daemon.GetImageIDAndOS(ancestor)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error while looking up for image %v", ancestor)
|
||||
return nil
|
||||
@@ -333,7 +333,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis
|
||||
return nil
|
||||
}
|
||||
// Then walk down the graph and put the imageIds in imagesFilter
|
||||
populateImageFilterByParents(imagesFilter, id, daemon.stores[os].imageStore.Children)
|
||||
populateImageFilterByParents(imagesFilter, id, daemon.imageStore.Children)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -138,9 +138,12 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
max := len(img.RootFS.DiffIDs)
|
||||
for i := 1; i <= max; i++ {
|
||||
img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
|
||||
layerPath, err := layer.GetLayerPath(daemon.stores[c.OS].layerStore, img.RootFS.ChainID())
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return nil, fmt.Errorf("cannot get layerpath for ImageID %s: %s ", img.RootFS.ChainID(), system.ErrNotSupportedOperatingSystem)
|
||||
}
|
||||
layerPath, err := layer.GetLayerPath(daemon.layerStores[img.OperatingSystem()], img.RootFS.ChainID())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.stores[c.OS].layerStore, img.RootFS.ChainID(), err)
|
||||
return nil, fmt.Errorf("failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStores[img.OperatingSystem()], img.RootFS.ChainID(), err)
|
||||
}
|
||||
// Reverse order, expecting parent most first
|
||||
s.Windows.LayerFolders = append([]string{layerPath}, s.Windows.LayerFolders...)
|
||||
@@ -210,15 +213,18 @@ func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
|
||||
NetworkSharedContainerName: networkSharedContainerID,
|
||||
}
|
||||
|
||||
if img.OS == "windows" {
|
||||
switch img.OS {
|
||||
case "windows":
|
||||
if err := daemon.createSpecWindowsFields(c, &s, isHyperV); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// TODO @jhowardmsft LCOW Support. Modify this check when running in dual-mode
|
||||
if system.LCOWSupported() && img.OS == "linux" {
|
||||
daemon.createSpecLinuxFields(c, &s)
|
||||
case "linux":
|
||||
if !system.LCOWSupported() {
|
||||
return nil, fmt.Errorf("Linux containers on Windows are not supported")
|
||||
}
|
||||
daemon.createSpecLinuxFields(c, &s)
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported platform %q", img.OS)
|
||||
}
|
||||
|
||||
return (*specs.Spec)(&s), nil
|
||||
|
||||
@@ -3,7 +3,6 @@ package daemon
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -14,7 +13,6 @@ import (
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/docker/docker/pkg/directory"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/docker/docker/volume"
|
||||
"github.com/docker/libnetwork"
|
||||
@@ -162,12 +160,6 @@ func (daemon *Daemon) VolumesPrune(ctx context.Context, pruneFilters filters.Arg
|
||||
|
||||
// ImagesPrune removes unused images
|
||||
func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (*types.ImagesPruneReport, error) {
|
||||
// TODO @jhowardmsft LCOW Support: This will need revisiting later.
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
|
||||
if !atomic.CompareAndSwapInt32(&daemon.pruneRunning, 0, 1) {
|
||||
return nil, errPruneRunning
|
||||
}
|
||||
@@ -197,9 +189,9 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
||||
|
||||
var allImages map[image.ID]*image.Image
|
||||
if danglingOnly {
|
||||
allImages = daemon.stores[platform].imageStore.Heads()
|
||||
allImages = daemon.imageStore.Heads()
|
||||
} else {
|
||||
allImages = daemon.stores[platform].imageStore.Map()
|
||||
allImages = daemon.imageStore.Map()
|
||||
}
|
||||
allContainers := daemon.List()
|
||||
imageRefs := map[string]bool{}
|
||||
@@ -213,7 +205,12 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
||||
}
|
||||
|
||||
// Filter intermediary images and get their unique size
|
||||
allLayers := daemon.stores[platform].layerStore.Map()
|
||||
allLayers := make(map[layer.ChainID]layer.Layer)
|
||||
for _, ls := range daemon.layerStores {
|
||||
for k, v := range ls.Map() {
|
||||
allLayers[k] = v
|
||||
}
|
||||
}
|
||||
topImages := map[image.ID]*image.Image{}
|
||||
for id, img := range allImages {
|
||||
select {
|
||||
@@ -221,7 +218,7 @@ func (daemon *Daemon) ImagesPrune(ctx context.Context, pruneFilters filters.Args
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
dgst := digest.Digest(id)
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.stores[platform].imageStore.Children(id)) != 0 {
|
||||
if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
|
||||
continue
|
||||
}
|
||||
if !until.IsZero() && img.Created.After(until) {
|
||||
|
||||
@@ -222,7 +222,7 @@ func (daemon *Daemon) Cleanup(container *container.Container) {
|
||||
if err := daemon.conditionalUnmountOnCleanup(container); err != nil {
|
||||
// FIXME: remove once reference counting for graphdrivers has been refactored
|
||||
// Ensure that all the mounts are gone
|
||||
if mountid, err := daemon.stores[container.OS].layerStore.GetMountID(container.ID); err == nil {
|
||||
if mountid, err := daemon.layerStores[container.OS].GetMountID(container.ID); err == nil {
|
||||
daemon.cleanupMountsByID(mountid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,9 @@ type ImagePullConfig struct {
|
||||
// Schema2Types is the valid schema2 configuration types allowed
|
||||
// by the pull operation.
|
||||
Schema2Types []string
|
||||
// Platform is the requested platform of the image being pulled to ensure it can be validated
|
||||
// when the host platform supports multiple image operating systems.
|
||||
Platform string
|
||||
// OS is the requested operating system of the image being pulled to ensure it can be validated
|
||||
// when the host OS supports multiple image operating systems.
|
||||
OS string
|
||||
}
|
||||
|
||||
// ImagePushConfig stores push configuration.
|
||||
@@ -71,8 +71,8 @@ type ImagePushConfig struct {
|
||||
// ConfigMediaType is the configuration media type for
|
||||
// schema2 manifests.
|
||||
ConfigMediaType string
|
||||
// LayerStore manages layers.
|
||||
LayerStore PushLayerProvider
|
||||
// LayerStores (indexed by operating system) manages layers.
|
||||
LayerStores map[string]PushLayerProvider
|
||||
// TrustKey is the private key for legacy signatures. This is typically
|
||||
// an ephemeral key, since these signatures are no longer verified.
|
||||
TrustKey libtrust.PrivateKey
|
||||
@@ -86,7 +86,7 @@ type ImagePushConfig struct {
|
||||
type ImageConfigStore interface {
|
||||
Put([]byte) (digest.Digest, error)
|
||||
Get(digest.Digest) ([]byte, error)
|
||||
RootFSAndOSFromConfig([]byte) (*image.RootFS, layer.OS, error)
|
||||
RootFSAndOSFromConfig([]byte) (*image.RootFS, string, error)
|
||||
}
|
||||
|
||||
// PushLayerProvider provides layers to be pushed by ChainID.
|
||||
@@ -112,7 +112,7 @@ type RootFSDownloadManager interface {
|
||||
// returns the final rootfs.
|
||||
// Given progress output to track download progress
|
||||
// Returns function to release download resources
|
||||
Download(ctx context.Context, initialRootFS image.RootFS, os layer.OS, layers []xfer.DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error)
|
||||
Download(ctx context.Context, initialRootFS image.RootFS, os string, layers []xfer.DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error)
|
||||
}
|
||||
|
||||
type imageConfigStore struct {
|
||||
@@ -140,7 +140,7 @@ func (s *imageConfigStore) Get(d digest.Digest) ([]byte, error) {
|
||||
return img.RawJSON(), nil
|
||||
}
|
||||
|
||||
func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, layer.OS, error) {
|
||||
func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
||||
var unmarshalledConfig image.Image
|
||||
if err := json.Unmarshal(c, &unmarshalledConfig); err != nil {
|
||||
return nil, "", err
|
||||
@@ -154,24 +154,29 @@ func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, layer
|
||||
return nil, "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
|
||||
}
|
||||
|
||||
os := ""
|
||||
if runtime.GOOS == "windows" {
|
||||
os = unmarshalledConfig.OS
|
||||
os := unmarshalledConfig.OS
|
||||
if os == "" {
|
||||
os = runtime.GOOS
|
||||
}
|
||||
return unmarshalledConfig.RootFS, layer.OS(os), nil
|
||||
if !system.IsOSSupported(os) {
|
||||
return nil, "", system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
return unmarshalledConfig.RootFS, os, nil
|
||||
}
|
||||
|
||||
type storeLayerProvider struct {
|
||||
ls layer.Store
|
||||
}
|
||||
|
||||
// NewLayerProviderFromStore returns a layer provider backed by
|
||||
// NewLayerProvidersFromStores returns layer providers backed by
|
||||
// an instance of LayerStore. Only getting layers as gzipped
|
||||
// tars is supported.
|
||||
func NewLayerProviderFromStore(ls layer.Store) PushLayerProvider {
|
||||
return &storeLayerProvider{
|
||||
ls: ls,
|
||||
func NewLayerProvidersFromStores(lss map[string]layer.Store) map[string]PushLayerProvider {
|
||||
plps := make(map[string]PushLayerProvider)
|
||||
for os, ls := range lss {
|
||||
plps[os] = &storeLayerProvider{ls: ls}
|
||||
}
|
||||
return plps
|
||||
}
|
||||
|
||||
func (p *storeLayerProvider) Get(lid layer.ChainID) (PushLayer, error) {
|
||||
|
||||
@@ -26,17 +26,15 @@ type Store interface {
|
||||
type FSMetadataStore struct {
|
||||
sync.RWMutex
|
||||
basePath string
|
||||
platform string
|
||||
}
|
||||
|
||||
// NewFSMetadataStore creates a new filesystem-based metadata store.
|
||||
func NewFSMetadataStore(basePath, platform string) (*FSMetadataStore, error) {
|
||||
func NewFSMetadataStore(basePath string) (*FSMetadataStore, error) {
|
||||
if err := os.MkdirAll(basePath, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &FSMetadataStore{
|
||||
basePath: basePath,
|
||||
platform: platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package metadata
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/layer"
|
||||
@@ -17,7 +16,7 @@ func TestV1IDService(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir, runtime.GOOS)
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create metadata store: %v", err)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/docker/layer"
|
||||
@@ -20,7 +19,7 @@ func TestV2MetadataService(t *testing.T) {
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir, runtime.GOOS)
|
||||
metadataStore, err := NewFSMetadataStore(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("could not create metadata store: %v", err)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ type Puller interface {
|
||||
// Pull tries to pull the image referenced by `tag`
|
||||
// Pull returns an error if any, as well as a boolean that determines whether to retry Pull on the next configured endpoint.
|
||||
//
|
||||
Pull(ctx context.Context, ref reference.Named, platform string) error
|
||||
Pull(ctx context.Context, ref reference.Named, os string) error
|
||||
}
|
||||
|
||||
// newPuller returns a Puller interface that will pull from either a v1 or v2
|
||||
@@ -115,12 +115,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
|
||||
continue
|
||||
}
|
||||
|
||||
// Make sure we default the platform if it hasn't been supplied
|
||||
if imagePullConfig.Platform == "" {
|
||||
imagePullConfig.Platform = runtime.GOOS
|
||||
// Make sure we default the OS if it hasn't been supplied
|
||||
if imagePullConfig.OS == "" {
|
||||
imagePullConfig.OS = runtime.GOOS
|
||||
}
|
||||
|
||||
if err := puller.Pull(ctx, ref, imagePullConfig.Platform); err != nil {
|
||||
if err := puller.Pull(ctx, ref, imagePullConfig.OS); err != nil {
|
||||
// Was this pull cancelled? If so, don't try to fall
|
||||
// back.
|
||||
fallback := false
|
||||
|
||||
@@ -36,7 +36,7 @@ type v1Puller struct {
|
||||
session *registry.Session
|
||||
}
|
||||
|
||||
func (p *v1Puller) Pull(ctx context.Context, ref reference.Named, platform string) error {
|
||||
func (p *v1Puller) Pull(ctx context.Context, ref reference.Named, os string) error {
|
||||
if _, isCanonical := ref.(reference.Canonical); isCanonical {
|
||||
// Allowing fallback, because HTTPS v1 is before HTTP v2
|
||||
return fallbackError{err: ErrNoSupport{Err: errors.New("Cannot pull by digest with v1 registry")}}
|
||||
|
||||
@@ -62,7 +62,7 @@ type v2Puller struct {
|
||||
confirmedV2 bool
|
||||
}
|
||||
|
||||
func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, platform string) (err error) {
|
||||
func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, os string) (err error) {
|
||||
// TODO(tiborvass): was ReceiveTimeout
|
||||
p.repo, p.confirmedV2, err = NewV2Repository(ctx, p.repoInfo, p.endpoint, p.config.MetaHeaders, p.config.AuthConfig, "pull")
|
||||
if err != nil {
|
||||
@@ -70,7 +70,7 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, platform strin
|
||||
return err
|
||||
}
|
||||
|
||||
if err = p.pullV2Repository(ctx, ref, platform); err != nil {
|
||||
if err = p.pullV2Repository(ctx, ref, os); err != nil {
|
||||
if _, ok := err.(fallbackError); ok {
|
||||
return err
|
||||
}
|
||||
@@ -85,10 +85,10 @@ func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, platform strin
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named, platform string) (err error) {
|
||||
func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named, os string) (err error) {
|
||||
var layersDownloaded bool
|
||||
if !reference.IsNameOnly(ref) {
|
||||
layersDownloaded, err = p.pullV2Tag(ctx, ref, platform)
|
||||
layersDownloaded, err = p.pullV2Tag(ctx, ref, os)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named, pl
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pulledNew, err := p.pullV2Tag(ctx, tagRef, platform)
|
||||
pulledNew, err := p.pullV2Tag(ctx, tagRef, os)
|
||||
if err != nil {
|
||||
// Since this is the pull-all-tags case, don't
|
||||
// allow an error pulling a particular tag to
|
||||
@@ -488,9 +488,9 @@ func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Reference, unv
|
||||
descriptors = append(descriptors, layerDescriptor)
|
||||
}
|
||||
|
||||
// The v1 manifest itself doesn't directly contain a platform. However,
|
||||
// The v1 manifest itself doesn't directly contain an OS. However,
|
||||
// the history does, but unfortunately that's a string, so search through
|
||||
// all the history until hopefully we find one which indicates the os.
|
||||
// all the history until hopefully we find one which indicates the OS.
|
||||
// supertest2014/nyan is an example of a registry image with schemav1.
|
||||
configOS := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
@@ -514,7 +514,7 @@ func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Reference, unv
|
||||
return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configOS, requestedOS)
|
||||
}
|
||||
|
||||
resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, layer.OS(configOS), descriptors, p.config.ProgressOutput)
|
||||
resultRootFS, release, err := p.config.DownloadManager.Download(ctx, *rootFS, configOS, descriptors, p.config.ProgressOutput)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
@@ -588,7 +588,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||
downloadedRootFS *image.RootFS // rootFS from registered layers
|
||||
configRootFS *image.RootFS // rootFS from configuration
|
||||
release func() // release resources from rootFS download
|
||||
configOS layer.OS // for LCOW when registering downloaded layers
|
||||
configOS string // for LCOW when registering downloaded layers
|
||||
)
|
||||
|
||||
// https://github.com/docker/docker/issues/24766 - Err on the side of caution,
|
||||
@@ -615,7 +615,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||
|
||||
// Early bath if the requested OS doesn't match that of the configuration.
|
||||
// This avoids doing the download, only to potentially fail later.
|
||||
if !strings.EqualFold(string(configOS), requestedOS) {
|
||||
if !strings.EqualFold(configOS, requestedOS) {
|
||||
return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configOS, requestedOS)
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||
rootFS image.RootFS
|
||||
)
|
||||
downloadRootFS := *image.NewRootFS()
|
||||
rootFS, release, err = p.config.DownloadManager.Download(ctx, downloadRootFS, layer.OS(requestedOS), descriptors, p.config.ProgressOutput)
|
||||
rootFS, release, err = p.config.DownloadManager.Download(ctx, downloadRootFS, requestedOS, descriptors, p.config.ProgressOutput)
|
||||
if err != nil {
|
||||
// Intentionally do not cancel the config download here
|
||||
// as the error from config download (if there is one)
|
||||
@@ -698,7 +698,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
|
||||
return imageID, manifestDigest, nil
|
||||
}
|
||||
|
||||
func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, layer.OS, error) {
|
||||
func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, string, error) {
|
||||
select {
|
||||
case configJSON := <-configChan:
|
||||
rootfs, os, err := s.RootFSAndOSFromConfig(configJSON)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -210,7 +211,10 @@ func (p *v1Pusher) imageListForTag(imgID image.ID, dependenciesSeen map[layer.Ch
|
||||
|
||||
topLayerID := img.RootFS.ChainID()
|
||||
|
||||
pl, err := p.config.LayerStore.Get(topLayerID)
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
pl, err := p.config.LayerStores[img.OperatingSystem()].Get(topLayerID)
|
||||
*referencedLayers = append(*referencedLayers, pl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get top layer from image: %v", err)
|
||||
|
||||
@@ -118,12 +118,12 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id
|
||||
return fmt.Errorf("could not find image from tag %s: %v", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
rootfs, _, err := p.config.ImageStore.RootFSAndOSFromConfig(imgConfig)
|
||||
rootfs, os, err := p.config.ImageStore.RootFSAndOSFromConfig(imgConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get rootfs for image %s: %s", reference.FamiliarString(ref), err)
|
||||
}
|
||||
|
||||
l, err := p.config.LayerStore.Get(rootfs.ChainID())
|
||||
l, err := p.config.LayerStores[os].Get(rootfs.ChainID())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get top layer from image: %v", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/docker/docker/pkg/archive"
|
||||
"github.com/docker/docker/pkg/ioutils"
|
||||
"github.com/docker/docker/pkg/progress"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
@@ -95,7 +96,7 @@ type DownloadDescriptorWithRegistered interface {
|
||||
// Download method is called to get the layer tar data. Layers are then
|
||||
// registered in the appropriate order. The caller must call the returned
|
||||
// release function once it is done with the returned RootFS object.
|
||||
func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS image.RootFS, os layer.OS, layers []DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error) {
|
||||
func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS image.RootFS, os string, layers []DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error) {
|
||||
var (
|
||||
topLayer layer.Layer
|
||||
topDownload *downloadTransfer
|
||||
@@ -105,9 +106,13 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
||||
downloadsByKey = make(map[string]*downloadTransfer)
|
||||
)
|
||||
|
||||
// Assume that the operating system is the host OS if blank
|
||||
// Assume that the operating system is the host OS if blank, and validate it
|
||||
// to ensure we don't cause a panic by an invalid index into the layerstores.
|
||||
if os == "" {
|
||||
os = layer.OS(runtime.GOOS)
|
||||
os = runtime.GOOS
|
||||
}
|
||||
if !system.IsOSSupported(os) {
|
||||
return image.RootFS{}, nil, system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
|
||||
rootFS := initialRootFS
|
||||
@@ -121,20 +126,20 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
||||
if err == nil {
|
||||
getRootFS := rootFS
|
||||
getRootFS.Append(diffID)
|
||||
l, err := ldm.layerStores[string(os)].Get(getRootFS.ChainID())
|
||||
l, err := ldm.layerStores[os].Get(getRootFS.ChainID())
|
||||
if err == nil {
|
||||
// Layer already exists.
|
||||
logrus.Debugf("Layer already exists: %s", descriptor.ID())
|
||||
progress.Update(progressOutput, descriptor.ID(), "Already exists")
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(os)], topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[os], topLayer)
|
||||
}
|
||||
topLayer = l
|
||||
missingLayer = false
|
||||
rootFS.Append(diffID)
|
||||
// Register this repository as a source of this layer.
|
||||
withRegistered, hasRegistered := descriptor.(DownloadDescriptorWithRegistered)
|
||||
if hasRegistered {
|
||||
if hasRegistered { // As layerstore may set the driver
|
||||
withRegistered.Registered(diffID)
|
||||
}
|
||||
continue
|
||||
@@ -171,7 +176,7 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
||||
if topDownload == nil {
|
||||
return rootFS, func() {
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(os)], topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[os], topLayer)
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
@@ -182,7 +187,7 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
||||
|
||||
defer func() {
|
||||
if topLayer != nil {
|
||||
layer.ReleaseAndLog(ldm.layerStores[string(os)], topLayer)
|
||||
layer.ReleaseAndLog(ldm.layerStores[os], topLayer)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -218,11 +223,11 @@ func (ldm *LayerDownloadManager) Download(ctx context.Context, initialRootFS ima
|
||||
// complete before the registration step, and registers the downloaded data
|
||||
// on top of parentDownload's resulting layer. Otherwise, it registers the
|
||||
// layer on top of the ChainID given by parentLayer.
|
||||
func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor, parentLayer layer.ChainID, parentDownload *downloadTransfer, os layer.OS) DoFunc {
|
||||
func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor, parentLayer layer.ChainID, parentDownload *downloadTransfer, os string) DoFunc {
|
||||
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
|
||||
d := &downloadTransfer{
|
||||
Transfer: NewTransfer(),
|
||||
layerStore: ldm.layerStores[string(os)],
|
||||
layerStore: ldm.layerStores[os],
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -341,9 +346,9 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
|
||||
src = fs.Descriptor()
|
||||
}
|
||||
if ds, ok := d.layerStore.(layer.DescribableStore); ok {
|
||||
d.layer, err = ds.RegisterWithDescriptor(inflatedLayerData, parentLayer, os, src)
|
||||
d.layer, err = ds.RegisterWithDescriptor(inflatedLayerData, parentLayer, src)
|
||||
} else {
|
||||
d.layer, err = d.layerStore.Register(inflatedLayerData, parentLayer, os)
|
||||
d.layer, err = d.layerStore.Register(inflatedLayerData, parentLayer)
|
||||
}
|
||||
if err != nil {
|
||||
select {
|
||||
@@ -382,11 +387,11 @@ func (ldm *LayerDownloadManager) makeDownloadFunc(descriptor DownloadDescriptor,
|
||||
// parentDownload. This function does not log progress output because it would
|
||||
// interfere with the progress reporting for sourceDownload, which has the same
|
||||
// Key.
|
||||
func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor DownloadDescriptor, sourceDownload *downloadTransfer, parentDownload *downloadTransfer, os layer.OS) DoFunc {
|
||||
func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor DownloadDescriptor, sourceDownload *downloadTransfer, parentDownload *downloadTransfer, os string) DoFunc {
|
||||
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
|
||||
d := &downloadTransfer{
|
||||
Transfer: NewTransfer(),
|
||||
layerStore: ldm.layerStores[string(os)],
|
||||
layerStore: ldm.layerStores[os],
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -440,9 +445,9 @@ func (ldm *LayerDownloadManager) makeDownloadFuncFromDownload(descriptor Downloa
|
||||
src = fs.Descriptor()
|
||||
}
|
||||
if ds, ok := d.layerStore.(layer.DescribableStore); ok {
|
||||
d.layer, err = ds.RegisterWithDescriptor(layerReader, parentLayer, os, src)
|
||||
d.layer, err = ds.RegisterWithDescriptor(layerReader, parentLayer, src)
|
||||
} else {
|
||||
d.layer, err = d.layerStore.Register(layerReader, parentLayer, os)
|
||||
d.layer, err = d.layerStore.Register(layerReader, parentLayer)
|
||||
}
|
||||
if err != nil {
|
||||
d.err = fmt.Errorf("failed to register layer: %v", err)
|
||||
|
||||
@@ -26,7 +26,7 @@ type mockLayer struct {
|
||||
diffID layer.DiffID
|
||||
chainID layer.ChainID
|
||||
parent layer.Layer
|
||||
os layer.OS
|
||||
os string
|
||||
}
|
||||
|
||||
func (ml *mockLayer) TarStream() (io.ReadCloser, error) {
|
||||
@@ -57,10 +57,6 @@ func (ml *mockLayer) DiffSize() (size int64, err error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (ml *mockLayer) OS() layer.OS {
|
||||
return ml.os
|
||||
}
|
||||
|
||||
func (ml *mockLayer) Metadata() (map[string]string, error) {
|
||||
return make(map[string]string), nil
|
||||
}
|
||||
@@ -91,7 +87,7 @@ func (ls *mockLayerStore) Map() map[layer.ChainID]layer.Layer {
|
||||
return layers
|
||||
}
|
||||
|
||||
func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID, os layer.OS) (layer.Layer, error) {
|
||||
func (ls *mockLayerStore) Register(reader io.Reader, parentID layer.ChainID) (layer.Layer, error) {
|
||||
return ls.RegisterWithDescriptor(reader, parentID, distribution.Descriptor{})
|
||||
}
|
||||
|
||||
@@ -293,13 +289,13 @@ func TestSuccessfulDownload(t *testing.T) {
|
||||
firstDescriptor := descriptors[0].(*mockDownloadDescriptor)
|
||||
|
||||
// Pre-register the first layer to simulate an already-existing layer
|
||||
l, err := layerStore.Register(firstDescriptor.mockTarStream(), "", layer.OS(runtime.GOOS))
|
||||
l, err := layerStore.Register(firstDescriptor.mockTarStream(), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
firstDescriptor.diffID = l.DiffID()
|
||||
|
||||
rootFS, releaseFunc, err := ldm.Download(context.Background(), *image.NewRootFS(), layer.OS(runtime.GOOS), descriptors, progress.ChanOutput(progressChan))
|
||||
rootFS, releaseFunc, err := ldm.Download(context.Background(), *image.NewRootFS(), runtime.GOOS, descriptors, progress.ChanOutput(progressChan))
|
||||
if err != nil {
|
||||
t.Fatalf("download error: %v", err)
|
||||
}
|
||||
@@ -339,7 +335,6 @@ func TestCancelledDownload(t *testing.T) {
|
||||
lsMap := make(map[string]layer.Store)
|
||||
lsMap[runtime.GOOS] = layerStore
|
||||
ldm := NewLayerDownloadManager(lsMap, maxDownloadConcurrency, func(m *LayerDownloadManager) { m.waitDuration = time.Millisecond })
|
||||
|
||||
progressChan := make(chan progress.Progress)
|
||||
progressDone := make(chan struct{})
|
||||
|
||||
@@ -357,7 +352,7 @@ func TestCancelledDownload(t *testing.T) {
|
||||
}()
|
||||
|
||||
descriptors := downloadDescriptors(nil)
|
||||
_, _, err := ldm.Download(ctx, *image.NewRootFS(), layer.OS(runtime.GOOS), descriptors, progress.ChanOutput(progressChan))
|
||||
_, _, err := ldm.Download(ctx, *image.NewRootFS(), runtime.GOOS, descriptors, progress.ChanOutput(progressChan))
|
||||
if err != context.Canceled {
|
||||
t.Fatal("expected download to be cancelled")
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package image
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -43,21 +42,19 @@ type imageMeta struct {
|
||||
|
||||
type store struct {
|
||||
sync.RWMutex
|
||||
ls LayerGetReleaser
|
||||
lss map[string]LayerGetReleaser
|
||||
images map[ID]*imageMeta
|
||||
fs StoreBackend
|
||||
digestSet *digestset.Set
|
||||
os string
|
||||
}
|
||||
|
||||
// NewImageStore returns new store object for given layer store
|
||||
func NewImageStore(fs StoreBackend, os string, ls LayerGetReleaser) (Store, error) {
|
||||
// NewImageStore returns new store object for given set of layer stores
|
||||
func NewImageStore(fs StoreBackend, lss map[string]LayerGetReleaser) (Store, error) {
|
||||
is := &store{
|
||||
ls: ls,
|
||||
lss: lss,
|
||||
images: make(map[ID]*imageMeta),
|
||||
fs: fs,
|
||||
digestSet: digestset.NewSet(),
|
||||
os: os,
|
||||
}
|
||||
|
||||
// load all current images and retain layers
|
||||
@@ -77,7 +74,10 @@ func (is *store) restore() error {
|
||||
}
|
||||
var l layer.Layer
|
||||
if chainID := img.RootFS.ChainID(); chainID != "" {
|
||||
l, err = is.ls.Get(chainID)
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
l, err = is.lss[img.OperatingSystem()].Get(chainID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -118,14 +118,6 @@ func (is *store) Create(config []byte) (ID, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// TODO @jhowardmsft - LCOW Support. This will need revisiting when coalescing the image stores.
|
||||
// Integrity check - ensure we are creating something for the correct platform
|
||||
if system.LCOWSupported() {
|
||||
if strings.ToLower(img.OperatingSystem()) != strings.ToLower(is.os) {
|
||||
return "", fmt.Errorf("cannot create entry for operating system %q in image store for operating system %q", img.OperatingSystem(), is.os)
|
||||
}
|
||||
}
|
||||
|
||||
// Must reject any config that references diffIDs from the history
|
||||
// which aren't among the rootfs layers.
|
||||
rootFSLayers := make(map[layer.DiffID]struct{})
|
||||
@@ -160,7 +152,10 @@ func (is *store) Create(config []byte) (ID, error) {
|
||||
|
||||
var l layer.Layer
|
||||
if layerID != "" {
|
||||
l, err = is.ls.Get(layerID)
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return "", system.ErrNotSupportedOperatingSystem
|
||||
}
|
||||
l, err = is.lss[img.OperatingSystem()].Get(layerID)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "failed to get layer %s", layerID)
|
||||
}
|
||||
@@ -229,6 +224,13 @@ func (is *store) Delete(id ID) ([]layer.Metadata, error) {
|
||||
if imageMeta == nil {
|
||||
return nil, fmt.Errorf("unrecognized image ID %s", id.String())
|
||||
}
|
||||
img, err := is.Get(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unrecognized image %s, %v", id.String(), err)
|
||||
}
|
||||
if !system.IsOSSupported(img.OperatingSystem()) {
|
||||
return nil, fmt.Errorf("unsupported image operating system %q", img.OperatingSystem())
|
||||
}
|
||||
for id := range imageMeta.children {
|
||||
is.fs.DeleteMetadata(id.Digest(), "parent")
|
||||
}
|
||||
@@ -243,7 +245,7 @@ func (is *store) Delete(id ID) ([]layer.Metadata, error) {
|
||||
is.fs.Delete(id.Digest())
|
||||
|
||||
if imageMeta.layer != nil {
|
||||
return is.ls.Release(imageMeta.layer)
|
||||
return is.lss[img.OperatingSystem()].Release(imageMeta.layer)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ func TestRestore(t *testing.T) {
|
||||
err = fs.SetMetadata(id2, "parent", []byte(id1))
|
||||
assert.NoError(t, err)
|
||||
|
||||
is, err := NewImageStore(fs, runtime.GOOS, &mockLayerGetReleaser{})
|
||||
mlgrMap := make(map[string]LayerGetReleaser)
|
||||
mlgrMap[runtime.GOOS] = &mockLayerGetReleaser{}
|
||||
is, err := NewImageStore(fs, mlgrMap)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, is.Map(), 2)
|
||||
@@ -143,7 +145,9 @@ func TestParentReset(t *testing.T) {
|
||||
func defaultImageStore(t *testing.T) (Store, func()) {
|
||||
fsBackend, cleanup := defaultFSStoreBackend(t)
|
||||
|
||||
store, err := NewImageStore(fsBackend, runtime.GOOS, &mockLayerGetReleaser{})
|
||||
mlgrMap := make(map[string]LayerGetReleaser)
|
||||
mlgrMap[runtime.GOOS] = &mockLayerGetReleaser{}
|
||||
store, err := NewImageStore(fsBackend, mlgrMap)
|
||||
assert.NoError(t, err)
|
||||
|
||||
return store, cleanup
|
||||
|
||||
@@ -90,11 +90,11 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
||||
}
|
||||
|
||||
// On Windows, validate the platform, defaulting to windows if not present.
|
||||
os := layer.OS(img.OS)
|
||||
os := img.OS
|
||||
if os == "" {
|
||||
os = runtime.GOOS
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
if os == "" {
|
||||
os = "windows"
|
||||
}
|
||||
if (os != "windows") && (os != "linux") {
|
||||
return fmt.Errorf("configuration for this image has an unsupported operating system: %s", os)
|
||||
}
|
||||
@@ -107,14 +107,14 @@ func (l *tarexporter) Load(inTar io.ReadCloser, outStream io.Writer, quiet bool)
|
||||
}
|
||||
r := rootFS
|
||||
r.Append(diffID)
|
||||
newLayer, err := l.ls.Get(r.ChainID())
|
||||
newLayer, err := l.lss[os].Get(r.ChainID())
|
||||
if err != nil {
|
||||
newLayer, err = l.loadLayer(layerPath, rootFS, diffID.String(), os, m.LayerSources[diffID], progressOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer layer.ReleaseAndLog(l.ls, newLayer)
|
||||
defer layer.ReleaseAndLog(l.lss[os], newLayer)
|
||||
if expected, actual := diffID, newLayer.DiffID(); expected != actual {
|
||||
return fmt.Errorf("invalid diffID for layer %d: expected %q, got %q", i, expected, actual)
|
||||
}
|
||||
@@ -176,7 +176,7 @@ func (l *tarexporter) setParentID(id, parentID image.ID) error {
|
||||
return l.is.SetParent(id, parentID)
|
||||
}
|
||||
|
||||
func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, os layer.OS, foreignSrc distribution.Descriptor, progressOutput progress.Output) (layer.Layer, error) {
|
||||
func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string, os string, foreignSrc distribution.Descriptor, progressOutput progress.Output) (layer.Layer, error) {
|
||||
// We use system.OpenSequential to use sequential file access on Windows, avoiding
|
||||
// depleting the standby list. On Linux, this equates to a regular os.Open.
|
||||
rawTar, err := system.OpenSequential(filename)
|
||||
@@ -205,10 +205,10 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS, id string,
|
||||
}
|
||||
defer inflatedLayerData.Close()
|
||||
|
||||
if ds, ok := l.ls.(layer.DescribableStore); ok {
|
||||
return ds.RegisterWithDescriptor(inflatedLayerData, rootFS.ChainID(), os, foreignSrc)
|
||||
if ds, ok := l.lss[os].(layer.DescribableStore); ok {
|
||||
return ds.RegisterWithDescriptor(inflatedLayerData, rootFS.ChainID(), foreignSrc)
|
||||
}
|
||||
return l.ls.Register(inflatedLayerData, rootFS.ChainID(), os)
|
||||
return l.lss[os].Register(inflatedLayerData, rootFS.ChainID())
|
||||
}
|
||||
|
||||
func (l *tarexporter) setLoadedTag(ref reference.Named, imgID digest.Digest, outStream io.Writer) error {
|
||||
@@ -302,6 +302,9 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
|
||||
if err := checkCompatibleOS(img.OS); err != nil {
|
||||
return err
|
||||
}
|
||||
if img.OS == "" {
|
||||
img.OS = runtime.GOOS
|
||||
}
|
||||
|
||||
var parentID image.ID
|
||||
if img.Parent != "" {
|
||||
@@ -335,7 +338,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, "", distribution.Descriptor{}, progressOutput)
|
||||
newLayer, err := l.loadLayer(layerPath, *rootFS, oldID, img.OS, distribution.Descriptor{}, progressOutput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -356,7 +359,7 @@ func (l *tarexporter) legacyLoadImage(oldID, sourceDir string, loadedMap map[str
|
||||
return err
|
||||
}
|
||||
|
||||
metadata, err := l.ls.Release(newLayer)
|
||||
metadata, err := l.lss[img.OS].Release(newLayer)
|
||||
layer.LogReleaseMetadata(metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -409,19 +412,18 @@ func checkValidParent(img, parent *image.Image) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func checkCompatibleOS(os string) error {
|
||||
// TODO @jhowardmsft LCOW - revisit for simultaneous platforms
|
||||
platform := runtime.GOOS
|
||||
if system.LCOWSupported() {
|
||||
platform = "linux"
|
||||
}
|
||||
// always compatible if the OS matches; also match an empty OS
|
||||
if os == platform || os == "" {
|
||||
func checkCompatibleOS(imageOS string) error {
|
||||
// always compatible if the images OS matches the host OS; also match an empty image OS
|
||||
if imageOS == runtime.GOOS || imageOS == "" {
|
||||
return nil
|
||||
}
|
||||
// for compatibility, only fail if the image or runtime OS is Windows
|
||||
if os == "windows" || platform == "windows" {
|
||||
return fmt.Errorf("cannot load %s image on %s", os, platform)
|
||||
// On non-Windows hosts, for compatibility, fail if the image is Windows.
|
||||
if runtime.GOOS != "windows" && imageOS == "windows" {
|
||||
return fmt.Errorf("cannot load %s image on %s", imageOS, runtime.GOOS)
|
||||
}
|
||||
// Finally, check the image OS is supported for the platform.
|
||||
if err := system.ValidatePlatform(system.ParsePlatform(imageOS)); err != nil {
|
||||
return fmt.Errorf("cannot load %s image on %s: %s", imageOS, runtime.GOOS, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
@@ -153,7 +154,11 @@ func (l *tarexporter) takeLayerReference(id image.ID, imgDescr *imageDescriptor)
|
||||
if topLayerID == "" {
|
||||
return nil
|
||||
}
|
||||
layer, err := l.ls.Get(topLayerID)
|
||||
os := img.OS
|
||||
if os == "" {
|
||||
os = runtime.GOOS
|
||||
}
|
||||
layer, err := l.lss[os].Get(topLayerID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -165,7 +170,11 @@ func (l *tarexporter) takeLayerReference(id image.ID, imgDescr *imageDescriptor)
|
||||
func (l *tarexporter) releaseLayerReferences(imgDescr map[image.ID]*imageDescriptor) error {
|
||||
for _, descr := range imgDescr {
|
||||
if descr.layerRef != nil {
|
||||
l.ls.Release(descr.layerRef)
|
||||
os := descr.image.OS
|
||||
if os == "" {
|
||||
os = runtime.GOOS
|
||||
}
|
||||
l.lss[os].Release(descr.layerRef)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -356,11 +365,15 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
|
||||
|
||||
// serialize filesystem
|
||||
layerPath := filepath.Join(outDir, legacyLayerFileName)
|
||||
l, err := s.ls.Get(id)
|
||||
operatingSystem := legacyImg.OS
|
||||
if operatingSystem == "" {
|
||||
operatingSystem = runtime.GOOS
|
||||
}
|
||||
l, err := s.lss[operatingSystem].Get(id)
|
||||
if err != nil {
|
||||
return distribution.Descriptor{}, err
|
||||
}
|
||||
defer layer.ReleaseAndLog(s.ls, l)
|
||||
defer layer.ReleaseAndLog(s.lss[operatingSystem], l)
|
||||
|
||||
if oldPath, exists := s.diffIDPaths[l.DiffID()]; exists {
|
||||
relPath, err := filepath.Rel(outDir, oldPath)
|
||||
|
||||
@@ -25,7 +25,7 @@ type manifestItem struct {
|
||||
|
||||
type tarexporter struct {
|
||||
is image.Store
|
||||
ls layer.Store
|
||||
lss map[string]layer.Store
|
||||
rs refstore.Store
|
||||
loggerImgEvent LogImageEvent
|
||||
}
|
||||
@@ -37,10 +37,10 @@ type LogImageEvent interface {
|
||||
}
|
||||
|
||||
// NewTarExporter returns new Exporter for tar packages
|
||||
func NewTarExporter(is image.Store, ls layer.Store, rs refstore.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
func NewTarExporter(is image.Store, lss map[string]layer.Store, rs refstore.Store, loggerImgEvent LogImageEvent) image.Exporter {
|
||||
return &tarexporter{
|
||||
is: is,
|
||||
ls: ls,
|
||||
lss: lss,
|
||||
rs: rs,
|
||||
loggerImgEvent: loggerImgEvent,
|
||||
}
|
||||
|
||||
@@ -55,10 +55,6 @@ func (el *emptyLayer) Metadata() (map[string]string, error) {
|
||||
return make(map[string]string), nil
|
||||
}
|
||||
|
||||
func (el *emptyLayer) OS() OS {
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the layer is an EmptyLayer
|
||||
func IsEmpty(diffID DiffID) bool {
|
||||
return diffID == DigestSHA256EmptyTar
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
package layer
|
||||
|
||||
// SetOS writes the "os" file to the layer filestore
|
||||
func (fm *fileMetadataTransaction) SetOS(os OS) error {
|
||||
import "runtime"
|
||||
|
||||
// setOS writes the "os" file to the layer filestore
|
||||
func (fm *fileMetadataTransaction) setOS(os string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetOS reads the "os" file from the layer filestore
|
||||
func (fms *fileMetadataStore) GetOS(layer ChainID) (OS, error) {
|
||||
return "", nil
|
||||
// getOS reads the "os" file from the layer filestore
|
||||
func (fms *fileMetadataStore) getOS(layer ChainID) (string, error) {
|
||||
return runtime.GOOS, nil
|
||||
}
|
||||
|
||||
@@ -7,16 +7,16 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetOS writes the "os" file to the layer filestore
|
||||
func (fm *fileMetadataTransaction) SetOS(os OS) error {
|
||||
// setOS writes the "os" file to the layer filestore
|
||||
func (fm *fileMetadataTransaction) setOS(os string) error {
|
||||
if os == "" {
|
||||
return nil
|
||||
}
|
||||
return fm.ws.WriteFile("os", []byte(os), 0644)
|
||||
}
|
||||
|
||||
// GetOS reads the "os" file from the layer filestore
|
||||
func (fms *fileMetadataStore) GetOS(layer ChainID) (OS, error) {
|
||||
// getOS reads the "os" file from the layer filestore
|
||||
func (fms *fileMetadataStore) getOS(layer ChainID) (string, error) {
|
||||
contentBytes, err := ioutil.ReadFile(fms.getLayerFilename(layer, "os"))
|
||||
if err != nil {
|
||||
// For backwards compatibility, the os file may not exist. Default to "windows" if missing.
|
||||
@@ -31,5 +31,5 @@ func (fms *fileMetadataStore) GetOS(layer ChainID) (OS, error) {
|
||||
return "", fmt.Errorf("invalid operating system value: %s", content)
|
||||
}
|
||||
|
||||
return OS(content), nil
|
||||
return content, nil
|
||||
}
|
||||
|
||||
@@ -65,14 +65,6 @@ func (id ChainID) String() string {
|
||||
return string(id)
|
||||
}
|
||||
|
||||
// OS is the operating system of a layer
|
||||
type OS string
|
||||
|
||||
// String returns a string rendition of layers target operating system
|
||||
func (id OS) String() string {
|
||||
return string(id)
|
||||
}
|
||||
|
||||
// DiffID is the hash of an individual layer tar.
|
||||
type DiffID digest.Digest
|
||||
|
||||
@@ -108,9 +100,6 @@ type Layer interface {
|
||||
// Parent returns the next layer in the layer chain.
|
||||
Parent() Layer
|
||||
|
||||
// OS returns the operating system of the layer
|
||||
OS() OS
|
||||
|
||||
// Size returns the size of the entire layer chain. The size
|
||||
// is calculated from the total size of all files in the layers.
|
||||
Size() (int64, error)
|
||||
@@ -191,7 +180,7 @@ type CreateRWLayerOpts struct {
|
||||
// Store represents a backend for managing both
|
||||
// read-only and read-write layers.
|
||||
type Store interface {
|
||||
Register(io.Reader, ChainID, OS) (Layer, error)
|
||||
Register(io.Reader, ChainID) (Layer, error)
|
||||
Get(ChainID) (Layer, error)
|
||||
Map() map[ChainID]Layer
|
||||
Release(Layer) ([]Metadata, error)
|
||||
@@ -209,7 +198,7 @@ type Store interface {
|
||||
// DescribableStore represents a layer store capable of storing
|
||||
// descriptors for layers.
|
||||
type DescribableStore interface {
|
||||
RegisterWithDescriptor(io.Reader, ChainID, OS, distribution.Descriptor) (Layer, error)
|
||||
RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
|
||||
}
|
||||
|
||||
// MetadataTransaction represents functions for setting layer metadata
|
||||
@@ -220,7 +209,7 @@ type MetadataTransaction interface {
|
||||
SetDiffID(DiffID) error
|
||||
SetCacheID(string) error
|
||||
SetDescriptor(distribution.Descriptor) error
|
||||
SetOS(OS) error
|
||||
setOS(string) error
|
||||
TarSplitWriter(compressInput bool) (io.WriteCloser, error)
|
||||
|
||||
Commit(ChainID) error
|
||||
@@ -241,7 +230,7 @@ type MetadataStore interface {
|
||||
GetDiffID(ChainID) (DiffID, error)
|
||||
GetCacheID(ChainID) (string, error)
|
||||
GetDescriptor(ChainID) (distribution.Descriptor, error)
|
||||
GetOS(ChainID) (OS, error)
|
||||
getOS(ChainID) (string, error)
|
||||
TarSplitReader(ChainID) (io.ReadCloser, error)
|
||||
|
||||
SetMountID(string, string) error
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/docker/distribution"
|
||||
@@ -28,23 +27,21 @@ import (
|
||||
const maxLayerDepth = 125
|
||||
|
||||
type layerStore struct {
|
||||
store MetadataStore
|
||||
driver graphdriver.Driver
|
||||
store MetadataStore
|
||||
driver graphdriver.Driver
|
||||
useTarSplit bool
|
||||
|
||||
layerMap map[ChainID]*roLayer
|
||||
layerL sync.Mutex
|
||||
|
||||
mounts map[string]*mountedLayer
|
||||
mountL sync.Mutex
|
||||
|
||||
useTarSplit bool
|
||||
|
||||
os string
|
||||
os string
|
||||
}
|
||||
|
||||
// StoreOptions are the options used to create a new Store instance
|
||||
type StoreOptions struct {
|
||||
StorePath string
|
||||
Root string
|
||||
MetadataStorePathTemplate string
|
||||
GraphDriver string
|
||||
GraphDriverOptions []string
|
||||
@@ -57,7 +54,7 @@ type StoreOptions struct {
|
||||
// NewStoreFromOptions creates a new Store instance
|
||||
func NewStoreFromOptions(options StoreOptions) (Store, error) {
|
||||
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
|
||||
Root: options.StorePath,
|
||||
Root: options.Root,
|
||||
DriverOptions: options.GraphDriverOptions,
|
||||
UIDMaps: options.IDMappings.UIDs(),
|
||||
GIDMaps: options.IDMappings.GIDs(),
|
||||
@@ -66,7 +63,7 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error initializing graphdriver: %v", err)
|
||||
}
|
||||
logrus.Debugf("Using graph driver %s", driver)
|
||||
logrus.Debugf("Initialized graph driver %s", driver)
|
||||
|
||||
fms, err := NewFSMetadataStore(fmt.Sprintf(options.MetadataStorePathTemplate, driver))
|
||||
if err != nil {
|
||||
@@ -80,6 +77,9 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
|
||||
// metadata store and graph driver. The metadata store will be used to restore
|
||||
// the Store.
|
||||
func NewStoreFromGraphDriver(store MetadataStore, driver graphdriver.Driver, os string) (Store, error) {
|
||||
if !system.IsOSSupported(os) {
|
||||
return nil, fmt.Errorf("failed to initialize layer store as operating system '%s' is not supported", os)
|
||||
}
|
||||
caps := graphdriver.Capabilities{}
|
||||
if capDriver, ok := driver.(graphdriver.CapabilityDriver); ok {
|
||||
caps = capDriver.Capabilities()
|
||||
@@ -150,11 +150,15 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
|
||||
return nil, fmt.Errorf("failed to get descriptor for %s: %s", layer, err)
|
||||
}
|
||||
|
||||
os, err := ls.store.GetOS(layer)
|
||||
os, err := ls.store.getOS(layer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get operating system for %s: %s", layer, err)
|
||||
}
|
||||
|
||||
if os != ls.os {
|
||||
return nil, fmt.Errorf("failed to load layer with os %s into layerstore for %s", os, ls.os)
|
||||
}
|
||||
|
||||
cl = &roLayer{
|
||||
chainID: layer,
|
||||
diffID: diff,
|
||||
@@ -163,7 +167,6 @@ func (ls *layerStore) loadLayer(layer ChainID) (*roLayer, error) {
|
||||
layerStore: ls,
|
||||
references: map[Layer]struct{}{},
|
||||
descriptor: descriptor,
|
||||
os: os,
|
||||
}
|
||||
|
||||
if parent != "" {
|
||||
@@ -259,11 +262,11 @@ func (ls *layerStore) applyTar(tx MetadataTransaction, ts io.Reader, parent stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ls *layerStore) Register(ts io.Reader, parent ChainID, os OS) (Layer, error) {
|
||||
return ls.registerWithDescriptor(ts, parent, os, distribution.Descriptor{})
|
||||
func (ls *layerStore) Register(ts io.Reader, parent ChainID) (Layer, error) {
|
||||
return ls.registerWithDescriptor(ts, parent, distribution.Descriptor{})
|
||||
}
|
||||
|
||||
func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, os OS, descriptor distribution.Descriptor) (Layer, error) {
|
||||
func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, descriptor distribution.Descriptor) (Layer, error) {
|
||||
// err is used to hold the error which will always trigger
|
||||
// cleanup of creates sources but may not be an error returned
|
||||
// to the caller (already exists).
|
||||
@@ -271,13 +274,6 @@ func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, os OS
|
||||
var pid string
|
||||
var p *roLayer
|
||||
|
||||
// Integrity check - ensure we are creating something for the correct operating system
|
||||
if system.LCOWSupported() {
|
||||
if strings.ToLower(ls.os) != strings.ToLower(string(os)) {
|
||||
return nil, fmt.Errorf("cannot create entry for operating system %q in layer store for operating system %q", os, ls.os)
|
||||
}
|
||||
}
|
||||
|
||||
if string(parent) != "" {
|
||||
p = ls.get(parent)
|
||||
if p == nil {
|
||||
@@ -306,7 +302,6 @@ func (ls *layerStore) registerWithDescriptor(ts io.Reader, parent ChainID, os OS
|
||||
layerStore: ls,
|
||||
references: map[Layer]struct{}{},
|
||||
descriptor: descriptor,
|
||||
os: os,
|
||||
}
|
||||
|
||||
if err = ls.driver.Create(layer.cacheID, pid, nil); err != nil {
|
||||
|
||||
@@ -6,6 +6,6 @@ import (
|
||||
"github.com/docker/distribution"
|
||||
)
|
||||
|
||||
func (ls *layerStore) RegisterWithDescriptor(ts io.Reader, parent ChainID, os OS, descriptor distribution.Descriptor) (Layer, error) {
|
||||
return ls.registerWithDescriptor(ts, parent, os, descriptor)
|
||||
func (ls *layerStore) RegisterWithDescriptor(ts io.Reader, parent ChainID, descriptor distribution.Descriptor) (Layer, error) {
|
||||
return ls.registerWithDescriptor(ts, parent, descriptor)
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func createLayer(ls Store, parent ChainID, layerFunc layerInit) (Layer, error) {
|
||||
}
|
||||
defer ts.Close()
|
||||
|
||||
layer, err := ls.Register(ts, parent, OS(runtime.GOOS))
|
||||
layer, err := ls.Register(ts, parent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -498,7 +498,7 @@ func TestTarStreamStability(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer1, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS))
|
||||
layer1, err := ls.Register(bytes.NewReader(tar1), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -517,7 +517,7 @@ func TestTarStreamStability(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer2, err := ls.Register(bytes.NewReader(tar2), layer1.ChainID(), OS(runtime.GOOS))
|
||||
layer2, err := ls.Register(bytes.NewReader(tar2), layer1.ChainID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -685,12 +685,12 @@ func TestRegisterExistingLayer(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar1), layer1.ChainID(), OS(runtime.GOOS))
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar1), layer1.ChainID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer2b, err := ls.Register(bytes.NewReader(tar1), layer1.ChainID(), OS(runtime.GOOS))
|
||||
layer2b, err := ls.Register(bytes.NewReader(tar1), layer1.ChainID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -725,12 +725,12 @@ func TestTarStreamVerification(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer1, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS))
|
||||
layer1, err := ls.Register(bytes.NewReader(tar1), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer2, err := ls.Register(bytes.NewReader(tar2), "", OS(runtime.GOOS))
|
||||
layer2, err := ls.Register(bytes.NewReader(tar2), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
package layer
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func graphDiffSize(ls Store, l Layer) (int64, error) {
|
||||
cl := getCachedLayer(l)
|
||||
|
||||
@@ -28,7 +28,6 @@ func GetLayerPath(s Store, layer ChainID) (string, error) {
|
||||
if layerGetter, ok := ls.driver.(Getter); ok {
|
||||
return layerGetter.GetLayerPath(rl.cacheID)
|
||||
}
|
||||
|
||||
path, err := ls.driver.Get(rl.cacheID, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// CreateRWLayerByGraphID creates a RWLayer in the layer store using
|
||||
// the provided name with the given graphID. To get the RWLayer
|
||||
// after migration the layer may be retrieved by the given name.
|
||||
func (ls *layerStore) CreateRWLayerByGraphID(name string, graphID string, parent ChainID) (err error) {
|
||||
func (ls *layerStore) CreateRWLayerByGraphID(name, graphID string, parent ChainID) (err error) {
|
||||
ls.mountL.Lock()
|
||||
defer ls.mountL.Unlock()
|
||||
m, ok := ls.mounts[name]
|
||||
|
||||
@@ -110,14 +110,14 @@ func TestLayerMigration(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer1b, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS))
|
||||
layer1b, err := ls.Register(bytes.NewReader(tar1), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertReferences(t, layer1a, layer1b)
|
||||
// Attempt register, should be same
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID(), OS(runtime.GOOS))
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -238,7 +238,7 @@ func TestLayerMigrationNoTarsplit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer1b, err := ls.Register(bytes.NewReader(tar1), "", OS(runtime.GOOS))
|
||||
layer1b, err := ls.Register(bytes.NewReader(tar1), "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -246,7 +246,7 @@ func TestLayerMigrationNoTarsplit(t *testing.T) {
|
||||
assertReferences(t, layer1a, layer1b)
|
||||
|
||||
// Attempt register, should be same
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID(), OS(runtime.GOOS))
|
||||
layer2a, err := ls.Register(bytes.NewReader(tar2), layer1a.ChainID())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ type roLayer struct {
|
||||
size int64
|
||||
layerStore *layerStore
|
||||
descriptor distribution.Descriptor
|
||||
os OS
|
||||
|
||||
referenceCount int
|
||||
references map[Layer]struct{}
|
||||
@@ -143,7 +142,11 @@ func storeLayer(tx MetadataTransaction, layer *roLayer) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.SetOS(layer.os)
|
||||
if err := tx.setOS(layer.layerStore.os); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newVerifiedReadCloser(rc io.ReadCloser, dgst digest.Digest) (io.ReadCloser, error) {
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package layer
|
||||
|
||||
func (rl *roLayer) OS() OS {
|
||||
return ""
|
||||
}
|
||||
@@ -7,10 +7,3 @@ var _ distribution.Describable = &roLayer{}
|
||||
func (rl *roLayer) Descriptor() distribution.Descriptor {
|
||||
return rl.descriptor
|
||||
}
|
||||
|
||||
func (rl *roLayer) OS() OS {
|
||||
if rl.os == "" {
|
||||
return "windows"
|
||||
}
|
||||
return rl.os
|
||||
}
|
||||
|
||||
@@ -87,14 +87,15 @@ func TestMigrateContainers(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ls := &mockMounter{}
|
||||
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(tmpdir, "imagedb"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
is, err := image.NewImageStore(ifs, runtime.GOOS, ls)
|
||||
ls := &mockMounter{}
|
||||
mmMap := make(map[string]image.LayerGetReleaser)
|
||||
mmMap[runtime.GOOS] = ls
|
||||
is, err := image.NewImageStore(ifs, mmMap)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -165,19 +166,20 @@ func TestMigrateImages(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ls := &mockRegistrar{}
|
||||
|
||||
ifs, err := image.NewFSStoreBackend(filepath.Join(tmpdir, "imagedb"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
is, err := image.NewImageStore(ifs, runtime.GOOS, ls)
|
||||
ls := &mockRegistrar{}
|
||||
mrMap := make(map[string]image.LayerGetReleaser)
|
||||
mrMap[runtime.GOOS] = ls
|
||||
is, err := image.NewImageStore(ifs, mrMap)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ms, err := metadata.NewFSMetadataStore(filepath.Join(tmpdir, "distribution"), runtime.GOOS)
|
||||
ms, err := metadata.NewFSMetadataStore(filepath.Join(tmpdir, "distribution"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -430,10 +432,6 @@ func (l *mockLayer) DiffSize() (int64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (l *mockLayer) OS() layer.OS {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (l *mockLayer) Metadata() (map[string]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -7,4 +7,7 @@ import (
|
||||
var (
|
||||
// ErrNotSupportedPlatform means the platform is not supported.
|
||||
ErrNotSupportedPlatform = errors.New("platform and architecture is not supported")
|
||||
|
||||
// ErrNotSupportedOperatingSystem means the operating system is not supported.
|
||||
ErrNotSupportedOperatingSystem = errors.New("operating system is not supported")
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ var lcowSupported = false
|
||||
// 2. Remove the getenv check when image-store is coalesced as shouldn't be needed anymore.
|
||||
func InitLCOW(experimental bool) {
|
||||
v := GetOSVersion()
|
||||
if experimental && v.Build > 16270 && os.Getenv("LCOW_SUPPORTED") != "" {
|
||||
if experimental && v.Build > 16278 && os.Getenv("LCOW_SUPPORTED") != "" {
|
||||
lcowSupported = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,3 +56,14 @@ func ParsePlatform(in string) *specs.Platform {
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// IsOSSupported determines if an operating system is supported by the host
|
||||
func IsOSSupported(os string) bool {
|
||||
if runtime.GOOS == os {
|
||||
return true
|
||||
}
|
||||
if LCOWSupported() && os == "linux" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
@@ -145,7 +146,7 @@ func (s *tempConfigStore) Get(d digest.Digest) ([]byte, error) {
|
||||
return s.config, nil
|
||||
}
|
||||
|
||||
func (s *tempConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, layer.OS, error) {
|
||||
func (s *tempConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
||||
return configToRootFS(c)
|
||||
}
|
||||
|
||||
@@ -440,7 +441,8 @@ func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header
|
||||
pm: pm,
|
||||
plugin: p,
|
||||
}
|
||||
ls := &pluginLayerProvider{
|
||||
lss := make(map[string]distribution.PushLayerProvider)
|
||||
lss[runtime.GOOS] = &pluginLayerProvider{
|
||||
pm: pm,
|
||||
plugin: p,
|
||||
}
|
||||
@@ -463,7 +465,7 @@ func (pm *Manager) Push(ctx context.Context, name string, metaHeader http.Header
|
||||
RequireSchema2: true,
|
||||
},
|
||||
ConfigMediaType: schema2.MediaTypePluginConfig,
|
||||
LayerStore: ls,
|
||||
LayerStores: lss,
|
||||
UploadManager: uploadManager,
|
||||
}
|
||||
|
||||
@@ -532,7 +534,7 @@ func (s *pluginConfigStore) Get(d digest.Digest) ([]byte, error) {
|
||||
return ioutil.ReadAll(rwc)
|
||||
}
|
||||
|
||||
func (s *pluginConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, layer.OS, error) {
|
||||
func (s *pluginConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
||||
return configToRootFS(c)
|
||||
}
|
||||
|
||||
|
||||
@@ -126,8 +126,7 @@ type downloadManager struct {
|
||||
configDigest digest.Digest
|
||||
}
|
||||
|
||||
func (dm *downloadManager) Download(ctx context.Context, initialRootFS image.RootFS, os layer.OS, layers []xfer.DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error) {
|
||||
// TODO @jhowardmsft LCOW: May need revisiting.
|
||||
func (dm *downloadManager) Download(ctx context.Context, initialRootFS image.RootFS, os string, layers []xfer.DownloadDescriptor, progressOutput progress.Output) (image.RootFS, func(), error) {
|
||||
for _, l := range layers {
|
||||
b, err := dm.blobStore.New()
|
||||
if err != nil {
|
||||
@@ -179,6 +178,6 @@ func (dm *downloadManager) Put(dt []byte) (digest.Digest, error) {
|
||||
func (dm *downloadManager) Get(d digest.Digest) ([]byte, error) {
|
||||
return nil, fmt.Errorf("digest not found")
|
||||
}
|
||||
func (dm *downloadManager) RootFSAndOSFromConfig(c []byte) (*image.RootFS, layer.OS, error) {
|
||||
func (dm *downloadManager) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
||||
return configToRootFS(c)
|
||||
}
|
||||
|
||||
@@ -375,12 +375,9 @@ func isEqualPrivilege(a, b types.PluginPrivilege) bool {
|
||||
return reflect.DeepEqual(a.Value, b.Value)
|
||||
}
|
||||
|
||||
func configToRootFS(c []byte) (*image.RootFS, layer.OS, error) {
|
||||
// TODO @jhowardmsft LCOW - Will need to revisit this. For now, calculate the operating system.
|
||||
os := layer.OS(runtime.GOOS)
|
||||
if system.LCOWSupported() {
|
||||
os = "linux"
|
||||
}
|
||||
func configToRootFS(c []byte) (*image.RootFS, string, error) {
|
||||
// TODO @jhowardmsft LCOW - Will need to revisit this.
|
||||
os := runtime.GOOS
|
||||
var pluginConfig types.PluginConfig
|
||||
if err := json.Unmarshal(c, &pluginConfig); err != nil {
|
||||
return nil, "", err
|
||||
|
||||
Reference in New Issue
Block a user