From a1fe1dc791633998bcc82b5f0734a5da68d2bb41 Mon Sep 17 00:00:00 2001 From: John Howard Date: Wed, 17 May 2017 13:33:33 -0700 Subject: [PATCH] LCOW: pull goes to correct stores Signed-off-by: John Howard --- api/server/router/image/backend.go | 2 +- api/server/router/image/image_routes.go | 40 +++++++++++++++++++- daemon/build.go | 7 +++- daemon/cluster/executor/backend.go | 2 +- daemon/cluster/executor/container/adapter.go | 10 ++++- daemon/image_pull.go | 22 +++++------ distribution/config.go | 3 ++ 7 files changed, 70 insertions(+), 16 deletions(-) diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go index 3b9ed96147..b791c7af1c 100644 --- a/api/server/router/image/backend.go +++ b/api/server/router/image/backend.go @@ -40,7 +40,7 @@ type importExportBackend interface { } type registryBackend interface { - PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error + PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) } diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index 465182caa1..e0012dfdb9 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "net/http" + "runtime" "strconv" "strings" @@ -17,6 +18,7 @@ import ( "github.com/docker/docker/api/types/versions" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/streamformatter" + "github.com/docker/docker/pkg/system" "github.com/docker/docker/registry" "golang.org/x/net/context" ) @@ -85,6 +87,41 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite ) defer output.Close() + // TODO @jhowardmsft LCOW Support: Eventually we will need an API change + // so that platform comes from (for example) r.Form.Get("platform"). For + // the initial implementation, we assume that the platform is the + // runtime OS of the host. It will also need a validation function such + // as below which should be called after getting it from the API. + // + // Ensures the requested platform is valid and normalized + //func validatePlatform(req string) (string, error) { + // req = strings.ToLower(req) + // if req == "" { + // req = runtime.GOOS // default to host platform + // } + // valid := []string{runtime.GOOS} + // + // if runtime.GOOS == "windows" && system.LCOWSupported() { + // valid = append(valid, "linux") + // } + // + // for _, item := range valid { + // if req == item { + // return req, nil + // } + // } + // return "", fmt.Errorf("invalid platform requested: %s", req) + //} + // + // And in the call-site: + // if platform, err = validatePlatform(platform); err != nil { + // return err + // } + platform := runtime.GOOS + if platform == "windows" && system.LCOWSupported() { + platform = "linux" + } + w.Header().Set("Content-Type", "application/json") if image != "" { //pull @@ -106,12 +143,13 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite } } - err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output) + err = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output) } else { //import src := r.Form.Get("fromSrc") // 'err' MUST NOT be defined within this block, we need any error // generated from the download to be available to the output // stream processing below + // TODO @jhowardmsft LCOW Support: This will need extending for the platform too. err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"]) } if err != nil { diff --git a/daemon/build.go b/daemon/build.go index a9cce776bd..09e499fc11 100644 --- a/daemon/build.go +++ b/daemon/build.go @@ -129,7 +129,12 @@ func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfi pullRegistryAuth = &resolvedConfig } - if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil { + // TODO @jhowardmsft LCOW Support: For now, use the runtime operating system of the host. + // When it gets to the builder part, this will need revisiting. There would have to be + // some indication from the user either through CLI flag to build, or through an explicit + // mechanism in a dockerfile such as a parser directive extension or an addition to + // the FROM statement syntax. + if err := daemon.pullImageWithReference(ctx, ref, runtime.GOOS, nil, pullRegistryAuth, output); err != nil { return nil, err } return daemon.GetImage(name) diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go index 2578a93c5a..fbe9006561 100644 --- a/daemon/cluster/executor/backend.go +++ b/daemon/cluster/executor/backend.go @@ -30,7 +30,7 @@ type Backend interface { FindNetwork(idName string) (libnetwork.Network, error) SetupIngress(clustertypes.NetworkCreateRequest, string) (<-chan struct{}, error) ReleaseIngress() (<-chan struct{}, error) - PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error + PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error ContainerStop(name string, seconds *int) error diff --git a/daemon/cluster/executor/container/adapter.go b/daemon/cluster/executor/container/adapter.go index 67d42c706e..75a085ef1d 100644 --- a/daemon/cluster/executor/container/adapter.go +++ b/daemon/cluster/executor/container/adapter.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "runtime" "strings" "syscall" "time" @@ -20,6 +21,7 @@ import ( containerpkg "github.com/docker/docker/container" "github.com/docker/docker/daemon/cluster/convert" executorpkg "github.com/docker/docker/daemon/cluster/executor" + "github.com/docker/docker/pkg/system" "github.com/docker/libnetwork" "github.com/docker/swarmkit/agent/exec" "github.com/docker/swarmkit/api" @@ -88,7 +90,13 @@ func (c *containerAdapter) pullImage(ctx context.Context) error { pr, pw := io.Pipe() metaHeaders := map[string][]string{} go func() { - err := c.backend.PullImage(ctx, c.container.image(), "", metaHeaders, authConfig, pw) + // TODO @jhowardmsft LCOW Support: This will need revisiting as + // the stack is built up to include LCOW support for swarm. + platform := runtime.GOOS + if platform == "windows" && system.LCOWSupported() { + platform = "linux" + } + err := c.backend.PullImage(ctx, c.container.image(), "", platform, metaHeaders, authConfig, pw) pw.CloseWithError(err) }() diff --git a/daemon/image_pull.go b/daemon/image_pull.go index 79bd5b588e..abc81ec67c 100644 --- a/daemon/image_pull.go +++ b/daemon/image_pull.go @@ -18,7 +18,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 string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { +func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform 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. @@ -43,10 +43,10 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead } } - return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream) + return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream) } -func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { +func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform 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) @@ -60,11 +60,10 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference. close(writesDone) }() - // ------------------------------------------------------------------------------ - // TODO @jhowardmsft LCOW. For now, use just the store for the host OS. This will - // need some work to complete - we won't know the platform until after metadata - // is pulled from the repository. This affects plugin as well to complete. - // ------------------------------------------------------------------------------ + // Default to the host OS platform in case it hasn't been populated with an explicit value. + if platform == "" { + platform = runtime.GOOS + } imagePullConfig := &distribution.ImagePullConfig{ Config: distribution.Config{ @@ -73,12 +72,13 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference. ProgressOutput: progress.ChanOutput(progressChan), RegistryService: daemon.RegistryService, ImageEventLogger: daemon.LogImageEvent, - MetadataStore: daemon.stores[runtime.GOOS].distributionMetadataStore, - ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[runtime.GOOS].imageStore), - ReferenceStore: daemon.stores[runtime.GOOS].referenceStore, + MetadataStore: daemon.stores[platform].distributionMetadataStore, + ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore), + ReferenceStore: daemon.stores[platform].referenceStore, }, DownloadManager: daemon.downloadManager, Schema2Types: distribution.ImageTypes, + Platform: platform, } err := distribution.Pull(ctx, ref, imagePullConfig) diff --git a/distribution/config.go b/distribution/config.go index cad19cd160..1c10533f69 100644 --- a/distribution/config.go +++ b/distribution/config.go @@ -59,6 +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 } // ImagePushConfig stores push configuration.