Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -40,7 +40,7 @@ type importExportBackend interface {
|
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 | 42 |
type registryBackend interface {
|
| 43 |
- PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 43 |
+ PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 44 | 44 |
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
| 45 | 45 |
SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error) |
| 46 | 46 |
} |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"io" |
| 8 | 8 |
"net/http" |
| 9 |
+ "runtime" |
|
| 9 | 10 |
"strconv" |
| 10 | 11 |
"strings" |
| 11 | 12 |
|
| ... | ... |
@@ -17,6 +18,7 @@ import ( |
| 17 | 17 |
"github.com/docker/docker/api/types/versions" |
| 18 | 18 |
"github.com/docker/docker/pkg/ioutils" |
| 19 | 19 |
"github.com/docker/docker/pkg/streamformatter" |
| 20 |
+ "github.com/docker/docker/pkg/system" |
|
| 20 | 21 |
"github.com/docker/docker/registry" |
| 21 | 22 |
"golang.org/x/net/context" |
| 22 | 23 |
) |
| ... | ... |
@@ -85,6 +87,41 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite |
| 85 | 85 |
) |
| 86 | 86 |
defer output.Close() |
| 87 | 87 |
|
| 88 |
+ // TODO @jhowardmsft LCOW Support: Eventually we will need an API change |
|
| 89 |
+ // so that platform comes from (for example) r.Form.Get("platform"). For
|
|
| 90 |
+ // the initial implementation, we assume that the platform is the |
|
| 91 |
+ // runtime OS of the host. It will also need a validation function such |
|
| 92 |
+ // as below which should be called after getting it from the API. |
|
| 93 |
+ // |
|
| 94 |
+ // Ensures the requested platform is valid and normalized |
|
| 95 |
+ //func validatePlatform(req string) (string, error) {
|
|
| 96 |
+ // req = strings.ToLower(req) |
|
| 97 |
+ // if req == "" {
|
|
| 98 |
+ // req = runtime.GOOS // default to host platform |
|
| 99 |
+ // } |
|
| 100 |
+ // valid := []string{runtime.GOOS}
|
|
| 101 |
+ // |
|
| 102 |
+ // if runtime.GOOS == "windows" && system.LCOWSupported() {
|
|
| 103 |
+ // valid = append(valid, "linux") |
|
| 104 |
+ // } |
|
| 105 |
+ // |
|
| 106 |
+ // for _, item := range valid {
|
|
| 107 |
+ // if req == item {
|
|
| 108 |
+ // return req, nil |
|
| 109 |
+ // } |
|
| 110 |
+ // } |
|
| 111 |
+ // return "", fmt.Errorf("invalid platform requested: %s", req)
|
|
| 112 |
+ //} |
|
| 113 |
+ // |
|
| 114 |
+ // And in the call-site: |
|
| 115 |
+ // if platform, err = validatePlatform(platform); err != nil {
|
|
| 116 |
+ // return err |
|
| 117 |
+ // } |
|
| 118 |
+ platform := runtime.GOOS |
|
| 119 |
+ if platform == "windows" && system.LCOWSupported() {
|
|
| 120 |
+ platform = "linux" |
|
| 121 |
+ } |
|
| 122 |
+ |
|
| 88 | 123 |
w.Header().Set("Content-Type", "application/json")
|
| 89 | 124 |
|
| 90 | 125 |
if image != "" { //pull
|
| ... | ... |
@@ -106,12 +143,13 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite |
| 106 | 106 |
} |
| 107 | 107 |
} |
| 108 | 108 |
|
| 109 |
- err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output) |
|
| 109 |
+ err = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output) |
|
| 110 | 110 |
} else { //import
|
| 111 | 111 |
src := r.Form.Get("fromSrc")
|
| 112 | 112 |
// 'err' MUST NOT be defined within this block, we need any error |
| 113 | 113 |
// generated from the download to be available to the output |
| 114 | 114 |
// stream processing below |
| 115 |
+ // TODO @jhowardmsft LCOW Support: This will need extending for the platform too. |
|
| 115 | 116 |
err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"]) |
| 116 | 117 |
} |
| 117 | 118 |
if err != nil {
|
| ... | ... |
@@ -129,7 +129,12 @@ func (daemon *Daemon) pullForBuilder(ctx context.Context, name string, authConfi |
| 129 | 129 |
pullRegistryAuth = &resolvedConfig |
| 130 | 130 |
} |
| 131 | 131 |
|
| 132 |
- if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
|
|
| 132 |
+ // TODO @jhowardmsft LCOW Support: For now, use the runtime operating system of the host. |
|
| 133 |
+ // When it gets to the builder part, this will need revisiting. There would have to be |
|
| 134 |
+ // some indication from the user either through CLI flag to build, or through an explicit |
|
| 135 |
+ // mechanism in a dockerfile such as a parser directive extension or an addition to |
|
| 136 |
+ // the FROM statement syntax. |
|
| 137 |
+ if err := daemon.pullImageWithReference(ctx, ref, runtime.GOOS, nil, pullRegistryAuth, output); err != nil {
|
|
| 133 | 138 |
return nil, err |
| 134 | 139 |
} |
| 135 | 140 |
return daemon.GetImage(name) |
| ... | ... |
@@ -30,7 +30,7 @@ type Backend interface {
|
| 30 | 30 |
FindNetwork(idName string) (libnetwork.Network, error) |
| 31 | 31 |
SetupIngress(clustertypes.NetworkCreateRequest, string) (<-chan struct{}, error)
|
| 32 | 32 |
ReleaseIngress() (<-chan struct{}, error)
|
| 33 |
- PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 33 |
+ PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error |
|
| 34 | 34 |
CreateManagedContainer(config types.ContainerCreateConfig) (container.ContainerCreateCreatedBody, error) |
| 35 | 35 |
ContainerStart(name string, hostConfig *container.HostConfig, checkpoint string, checkpointDir string) error |
| 36 | 36 |
ContainerStop(name string, seconds *int) error |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"fmt" |
| 8 | 8 |
"io" |
| 9 | 9 |
"os" |
| 10 |
+ "runtime" |
|
| 10 | 11 |
"strings" |
| 11 | 12 |
"syscall" |
| 12 | 13 |
"time" |
| ... | ... |
@@ -20,6 +21,7 @@ import ( |
| 20 | 20 |
containerpkg "github.com/docker/docker/container" |
| 21 | 21 |
"github.com/docker/docker/daemon/cluster/convert" |
| 22 | 22 |
executorpkg "github.com/docker/docker/daemon/cluster/executor" |
| 23 |
+ "github.com/docker/docker/pkg/system" |
|
| 23 | 24 |
"github.com/docker/libnetwork" |
| 24 | 25 |
"github.com/docker/swarmkit/agent/exec" |
| 25 | 26 |
"github.com/docker/swarmkit/api" |
| ... | ... |
@@ -88,7 +90,13 @@ func (c *containerAdapter) pullImage(ctx context.Context) error {
|
| 88 | 88 |
pr, pw := io.Pipe() |
| 89 | 89 |
metaHeaders := map[string][]string{}
|
| 90 | 90 |
go func() {
|
| 91 |
- err := c.backend.PullImage(ctx, c.container.image(), "", metaHeaders, authConfig, pw) |
|
| 91 |
+ // TODO @jhowardmsft LCOW Support: This will need revisiting as |
|
| 92 |
+ // the stack is built up to include LCOW support for swarm. |
|
| 93 |
+ platform := runtime.GOOS |
|
| 94 |
+ if platform == "windows" && system.LCOWSupported() {
|
|
| 95 |
+ platform = "linux" |
|
| 96 |
+ } |
|
| 97 |
+ err := c.backend.PullImage(ctx, c.container.image(), "", platform, metaHeaders, authConfig, pw) |
|
| 92 | 98 |
pw.CloseWithError(err) |
| 93 | 99 |
}() |
| 94 | 100 |
|
| ... | ... |
@@ -18,7 +18,7 @@ import ( |
| 18 | 18 |
|
| 19 | 19 |
// PullImage initiates a pull operation. image is the repository name to pull, and |
| 20 | 20 |
// tag may be either empty, or indicate a specific tag to pull. |
| 21 |
-func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 21 |
+func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 22 | 22 |
// Special case: "pull -a" may send an image name with a |
| 23 | 23 |
// trailing :. This is ugly, but let's not break API |
| 24 | 24 |
// compatibility. |
| ... | ... |
@@ -43,10 +43,10 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHead |
| 43 | 43 |
} |
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 |
- return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream) |
|
| 46 |
+ return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream) |
|
| 47 | 47 |
} |
| 48 | 48 |
|
| 49 |
-func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 49 |
+func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
|
|
| 50 | 50 |
// Include a buffer so that slow client connections don't affect |
| 51 | 51 |
// transfer performance. |
| 52 | 52 |
progressChan := make(chan progress.Progress, 100) |
| ... | ... |
@@ -60,11 +60,10 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference. |
| 60 | 60 |
close(writesDone) |
| 61 | 61 |
}() |
| 62 | 62 |
|
| 63 |
- // ------------------------------------------------------------------------------ |
|
| 64 |
- // TODO @jhowardmsft LCOW. For now, use just the store for the host OS. This will |
|
| 65 |
- // need some work to complete - we won't know the platform until after metadata |
|
| 66 |
- // is pulled from the repository. This affects plugin as well to complete. |
|
| 67 |
- // ------------------------------------------------------------------------------ |
|
| 63 |
+ // Default to the host OS platform in case it hasn't been populated with an explicit value. |
|
| 64 |
+ if platform == "" {
|
|
| 65 |
+ platform = runtime.GOOS |
|
| 66 |
+ } |
|
| 68 | 67 |
|
| 69 | 68 |
imagePullConfig := &distribution.ImagePullConfig{
|
| 70 | 69 |
Config: distribution.Config{
|
| ... | ... |
@@ -73,12 +72,13 @@ func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference. |
| 73 | 73 |
ProgressOutput: progress.ChanOutput(progressChan), |
| 74 | 74 |
RegistryService: daemon.RegistryService, |
| 75 | 75 |
ImageEventLogger: daemon.LogImageEvent, |
| 76 |
- MetadataStore: daemon.stores[runtime.GOOS].distributionMetadataStore, |
|
| 77 |
- ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[runtime.GOOS].imageStore), |
|
| 78 |
- ReferenceStore: daemon.stores[runtime.GOOS].referenceStore, |
|
| 76 |
+ MetadataStore: daemon.stores[platform].distributionMetadataStore, |
|
| 77 |
+ ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore), |
|
| 78 |
+ ReferenceStore: daemon.stores[platform].referenceStore, |
|
| 79 | 79 |
}, |
| 80 | 80 |
DownloadManager: daemon.downloadManager, |
| 81 | 81 |
Schema2Types: distribution.ImageTypes, |
| 82 |
+ Platform: platform, |
|
| 82 | 83 |
} |
| 83 | 84 |
|
| 84 | 85 |
err := distribution.Pull(ctx, ref, imagePullConfig) |
| ... | ... |
@@ -59,6 +59,9 @@ type ImagePullConfig struct {
|
| 59 | 59 |
// Schema2Types is the valid schema2 configuration types allowed |
| 60 | 60 |
// by the pull operation. |
| 61 | 61 |
Schema2Types []string |
| 62 |
+ // Platform is the requested platform of the image being pulled to ensure it can be validated |
|
| 63 |
+ // when the host platform supports multiple image operating systems. |
|
| 64 |
+ Platform string |
|
| 62 | 65 |
} |
| 63 | 66 |
|
| 64 | 67 |
// ImagePushConfig stores push configuration. |