Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -19,6 +19,7 @@ import ( |
| 19 | 19 |
"github.com/docker/docker/registry" |
| 20 | 20 |
"github.com/docker/libtrust" |
| 21 | 21 |
"github.com/opencontainers/go-digest" |
| 22 |
+ specs "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 22 | 23 |
"golang.org/x/net/context" |
| 23 | 24 |
) |
| 24 | 25 |
|
| ... | ... |
@@ -86,7 +87,8 @@ type ImagePushConfig struct {
|
| 86 | 86 |
type ImageConfigStore interface {
|
| 87 | 87 |
Put([]byte) (digest.Digest, error) |
| 88 | 88 |
Get(digest.Digest) ([]byte, error) |
| 89 |
- RootFSAndOSFromConfig([]byte) (*image.RootFS, string, error) |
|
| 89 |
+ RootFSFromConfig([]byte) (*image.RootFS, error) |
|
| 90 |
+ PlatformFromConfig([]byte) (*specs.Platform, error) |
|
| 90 | 91 |
} |
| 91 | 92 |
|
| 92 | 93 |
// PushLayerProvider provides layers to be pushed by ChainID. |
| ... | ... |
@@ -140,18 +142,26 @@ func (s *imageConfigStore) Get(d digest.Digest) ([]byte, error) {
|
| 140 | 140 |
return img.RawJSON(), nil |
| 141 | 141 |
} |
| 142 | 142 |
|
| 143 |
-func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
|
| 143 |
+func (s *imageConfigStore) RootFSFromConfig(c []byte) (*image.RootFS, error) {
|
|
| 144 | 144 |
var unmarshalledConfig image.Image |
| 145 | 145 |
if err := json.Unmarshal(c, &unmarshalledConfig); err != nil {
|
| 146 |
- return nil, "", err |
|
| 146 |
+ return nil, err |
|
| 147 |
+ } |
|
| 148 |
+ return unmarshalledConfig.RootFS, nil |
|
| 149 |
+} |
|
| 150 |
+ |
|
| 151 |
+func (s *imageConfigStore) PlatformFromConfig(c []byte) (*specs.Platform, error) {
|
|
| 152 |
+ var unmarshalledConfig image.Image |
|
| 153 |
+ if err := json.Unmarshal(c, &unmarshalledConfig); err != nil {
|
|
| 154 |
+ return nil, err |
|
| 147 | 155 |
} |
| 148 | 156 |
|
| 149 | 157 |
// fail immediately on Windows when downloading a non-Windows image |
| 150 | 158 |
// and vice versa. Exception on Windows if Linux Containers are enabled. |
| 151 | 159 |
if runtime.GOOS == "windows" && unmarshalledConfig.OS == "linux" && !system.LCOWSupported() {
|
| 152 |
- return nil, "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
|
|
| 160 |
+ return nil, fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
|
|
| 153 | 161 |
} else if runtime.GOOS != "windows" && unmarshalledConfig.OS == "windows" {
|
| 154 |
- return nil, "", fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
|
|
| 162 |
+ return nil, fmt.Errorf("image operating system %q cannot be used on this platform", unmarshalledConfig.OS)
|
|
| 155 | 163 |
} |
| 156 | 164 |
|
| 157 | 165 |
os := unmarshalledConfig.OS |
| ... | ... |
@@ -159,9 +169,9 @@ func (s *imageConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, strin |
| 159 | 159 |
os = runtime.GOOS |
| 160 | 160 |
} |
| 161 | 161 |
if !system.IsOSSupported(os) {
|
| 162 |
- return nil, "", system.ErrNotSupportedOperatingSystem |
|
| 162 |
+ return nil, system.ErrNotSupportedOperatingSystem |
|
| 163 | 163 |
} |
| 164 |
- return unmarshalledConfig.RootFS, os, nil |
|
| 164 |
+ return &specs.Platform{OS: os, OSVersion: unmarshalledConfig.OSVersion}, nil
|
|
| 165 | 165 |
} |
| 166 | 166 |
|
| 167 | 167 |
type storeLayerProvider struct {
|
| ... | ... |
@@ -30,6 +30,7 @@ import ( |
| 30 | 30 |
refstore "github.com/docker/docker/reference" |
| 31 | 31 |
"github.com/docker/docker/registry" |
| 32 | 32 |
digest "github.com/opencontainers/go-digest" |
| 33 |
+ specs "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 33 | 34 |
"github.com/pkg/errors" |
| 34 | 35 |
"github.com/sirupsen/logrus" |
| 35 | 36 |
"golang.org/x/net/context" |
| ... | ... |
@@ -584,11 +585,11 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s |
| 584 | 584 |
}() |
| 585 | 585 |
|
| 586 | 586 |
var ( |
| 587 |
- configJSON []byte // raw serialized image config |
|
| 588 |
- downloadedRootFS *image.RootFS // rootFS from registered layers |
|
| 589 |
- configRootFS *image.RootFS // rootFS from configuration |
|
| 590 |
- release func() // release resources from rootFS download |
|
| 591 |
- configOS string // for LCOW when registering downloaded layers |
|
| 587 |
+ configJSON []byte // raw serialized image config |
|
| 588 |
+ downloadedRootFS *image.RootFS // rootFS from registered layers |
|
| 589 |
+ configRootFS *image.RootFS // rootFS from configuration |
|
| 590 |
+ release func() // release resources from rootFS download |
|
| 591 |
+ configPlatform *specs.Platform // for LCOW when registering downloaded layers |
|
| 592 | 592 |
) |
| 593 | 593 |
|
| 594 | 594 |
// https://github.com/docker/docker/issues/24766 - Err on the side of caution, |
| ... | ... |
@@ -600,14 +601,16 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s |
| 600 | 600 |
// check to block Windows images being pulled on Linux is implemented, it |
| 601 | 601 |
// may be necessary to perform the same type of serialisation. |
| 602 | 602 |
if runtime.GOOS == "windows" {
|
| 603 |
- configJSON, configRootFS, configOS, err = receiveConfig(p.config.ImageStore, configChan, configErrChan) |
|
| 603 |
+ configJSON, configRootFS, configPlatform, err = receiveConfig(p.config.ImageStore, configChan, configErrChan) |
|
| 604 | 604 |
if err != nil {
|
| 605 | 605 |
return "", "", err |
| 606 | 606 |
} |
| 607 |
- |
|
| 608 | 607 |
if configRootFS == nil {
|
| 609 | 608 |
return "", "", errRootFSInvalid |
| 610 | 609 |
} |
| 610 |
+ if err := checkImageCompatibility(configPlatform.OS, configPlatform.OSVersion); err != nil {
|
|
| 611 |
+ return "", "", err |
|
| 612 |
+ } |
|
| 611 | 613 |
|
| 612 | 614 |
if len(descriptors) != len(configRootFS.DiffIDs) {
|
| 613 | 615 |
return "", "", errRootFSMismatch |
| ... | ... |
@@ -615,8 +618,8 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s |
| 615 | 615 |
|
| 616 | 616 |
// Early bath if the requested OS doesn't match that of the configuration. |
| 617 | 617 |
// This avoids doing the download, only to potentially fail later. |
| 618 |
- if !strings.EqualFold(configOS, requestedOS) {
|
|
| 619 |
- return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configOS, requestedOS)
|
|
| 618 |
+ if !strings.EqualFold(configPlatform.OS, requestedOS) {
|
|
| 619 |
+ return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configPlatform.OS, requestedOS)
|
|
| 620 | 620 |
} |
| 621 | 621 |
|
| 622 | 622 |
// Populate diff ids in descriptors to avoid downloading foreign layers |
| ... | ... |
@@ -698,16 +701,20 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s |
| 698 | 698 |
return imageID, manifestDigest, nil |
| 699 | 699 |
} |
| 700 | 700 |
|
| 701 |
-func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, string, error) {
|
|
| 701 |
+func receiveConfig(s ImageConfigStore, configChan <-chan []byte, errChan <-chan error) ([]byte, *image.RootFS, *specs.Platform, error) {
|
|
| 702 | 702 |
select {
|
| 703 | 703 |
case configJSON := <-configChan: |
| 704 |
- rootfs, os, err := s.RootFSAndOSFromConfig(configJSON) |
|
| 704 |
+ rootfs, err := s.RootFSFromConfig(configJSON) |
|
| 705 |
+ if err != nil {
|
|
| 706 |
+ return nil, nil, nil, err |
|
| 707 |
+ } |
|
| 708 |
+ platform, err := s.PlatformFromConfig(configJSON) |
|
| 705 | 709 |
if err != nil {
|
| 706 |
- return nil, nil, "", err |
|
| 710 |
+ return nil, nil, nil, err |
|
| 707 | 711 |
} |
| 708 |
- return configJSON, rootfs, os, nil |
|
| 712 |
+ return configJSON, rootfs, platform, nil |
|
| 709 | 713 |
case err := <-errChan: |
| 710 |
- return nil, nil, "", err |
|
| 714 |
+ return nil, nil, nil, err |
|
| 711 | 715 |
// Don't need a case for ctx.Done in the select because cancellation |
| 712 | 716 |
// will trigger an error in p.pullSchema2ImageConfig. |
| 713 | 717 |
} |
| ... | ... |
@@ -736,6 +743,10 @@ func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mf |
| 736 | 736 |
} |
| 737 | 737 |
manifestDigest := manifestMatches[0].Digest |
| 738 | 738 |
|
| 739 |
+ if err := checkImageCompatibility(manifestMatches[0].Platform.OS, manifestMatches[0].Platform.OSVersion); err != nil {
|
|
| 740 |
+ return "", "", err |
|
| 741 |
+ } |
|
| 742 |
+ |
|
| 739 | 743 |
manSvc, err := p.repo.Manifests(ctx) |
| 740 | 744 |
if err != nil {
|
| 741 | 745 |
return "", "", err |
| ... | ... |
@@ -27,3 +27,8 @@ func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []m |
| 27 | 27 |
} |
| 28 | 28 |
return matches |
| 29 | 29 |
} |
| 30 |
+ |
|
| 31 |
+// checkImageCompatibility is a Windows-specific function. No-op on Linux |
|
| 32 |
+func checkImageCompatibility(imageOS, imageOSVersion string) error {
|
|
| 33 |
+ return nil |
|
| 34 |
+} |
| ... | ... |
@@ -1,11 +1,13 @@ |
| 1 | 1 |
package distribution // import "github.com/docker/docker/distribution" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "errors" |
|
| 4 | 5 |
"fmt" |
| 5 | 6 |
"net/http" |
| 6 | 7 |
"os" |
| 7 | 8 |
"runtime" |
| 8 | 9 |
"sort" |
| 10 |
+ "strconv" |
|
| 9 | 11 |
"strings" |
| 10 | 12 |
|
| 11 | 13 |
"github.com/docker/distribution" |
| ... | ... |
@@ -63,7 +65,6 @@ func (ld *v2LayerDescriptor) open(ctx context.Context) (distribution.ReadSeekClo |
| 63 | 63 |
func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []manifestlist.ManifestDescriptor {
|
| 64 | 64 |
osVersion := "" |
| 65 | 65 |
if os == "windows" {
|
| 66 |
- // TODO: Add UBR (Update Build Release) component after build |
|
| 67 | 66 |
version := system.GetOSVersion() |
| 68 | 67 |
osVersion = fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build)
|
| 69 | 68 |
logrus.Debugf("will prefer entries with version %s", osVersion)
|
| ... | ... |
@@ -71,10 +72,11 @@ func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []m |
| 71 | 71 |
|
| 72 | 72 |
var matches []manifestlist.ManifestDescriptor |
| 73 | 73 |
for _, manifestDescriptor := range manifests {
|
| 74 |
- // TODO: Consider filtering out greater versions, including only greater UBR |
|
| 75 | 74 |
if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == os {
|
| 76 | 75 |
matches = append(matches, manifestDescriptor) |
| 77 |
- logrus.Debugf("found match for %s/%s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
|
|
| 76 |
+ logrus.Debugf("found match for %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
|
|
| 77 |
+ } else {
|
|
| 78 |
+ logrus.Debugf("ignoring %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
|
|
| 78 | 79 |
} |
| 79 | 80 |
} |
| 80 | 81 |
if os == "windows" {
|
| ... | ... |
@@ -107,3 +109,22 @@ func (mbv manifestsByVersion) Len() int {
|
| 107 | 107 |
func (mbv manifestsByVersion) Swap(i, j int) {
|
| 108 | 108 |
mbv.list[i], mbv.list[j] = mbv.list[j], mbv.list[i] |
| 109 | 109 |
} |
| 110 |
+ |
|
| 111 |
+// checkImageCompatibility blocks pulling incompatible images based on a later OS build |
|
| 112 |
+// Fixes https://github.com/moby/moby/issues/36184. |
|
| 113 |
+func checkImageCompatibility(imageOS, imageOSVersion string) error {
|
|
| 114 |
+ if imageOS == "windows" {
|
|
| 115 |
+ hostOSV := system.GetOSVersion() |
|
| 116 |
+ splitImageOSVersion := strings.Split(imageOSVersion, ".") // eg 10.0.16299.nnnn |
|
| 117 |
+ if len(splitImageOSVersion) >= 3 {
|
|
| 118 |
+ if imageOSBuild, err := strconv.Atoi(splitImageOSVersion[2]); err == nil {
|
|
| 119 |
+ if imageOSBuild > int(hostOSV.Build) {
|
|
| 120 |
+ errMsg := fmt.Sprintf("a Windows version %s.%s.%s-based image is incompatible with a %s host", splitImageOSVersion[0], splitImageOSVersion[1], splitImageOSVersion[2], hostOSV.ToString())
|
|
| 121 |
+ logrus.Debugf(errMsg) |
|
| 122 |
+ return errors.New(errMsg) |
|
| 123 |
+ } |
|
| 124 |
+ } |
|
| 125 |
+ } |
|
| 126 |
+ } |
|
| 127 |
+ return nil |
|
| 128 |
+} |
| ... | ... |
@@ -118,12 +118,17 @@ func (p *v2Pusher) pushV2Tag(ctx context.Context, ref reference.NamedTagged, id |
| 118 | 118 |
return fmt.Errorf("could not find image from tag %s: %v", reference.FamiliarString(ref), err)
|
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 |
- rootfs, os, err := p.config.ImageStore.RootFSAndOSFromConfig(imgConfig) |
|
| 121 |
+ rootfs, err := p.config.ImageStore.RootFSFromConfig(imgConfig) |
|
| 122 | 122 |
if err != nil {
|
| 123 | 123 |
return fmt.Errorf("unable to get rootfs for image %s: %s", reference.FamiliarString(ref), err)
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 |
- l, err := p.config.LayerStores[os].Get(rootfs.ChainID()) |
|
| 126 |
+ platform, err := p.config.ImageStore.PlatformFromConfig(imgConfig) |
|
| 127 |
+ if err != nil {
|
|
| 128 |
+ return fmt.Errorf("unable to get platform for image %s: %s", reference.FamiliarString(ref), err)
|
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ l, err := p.config.LayerStores[platform.OS].Get(rootfs.ChainID()) |
|
| 127 | 132 |
if err != nil {
|
| 128 | 133 |
return fmt.Errorf("failed to get top layer from image: %v", err)
|
| 129 | 134 |
} |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package system // import "github.com/docker/docker/pkg/system" |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"unsafe" |
| 5 | 6 |
|
| 6 | 7 |
"github.com/sirupsen/logrus" |
| ... | ... |
@@ -53,6 +54,10 @@ func GetOSVersion() OSVersion {
|
| 53 | 53 |
return osv |
| 54 | 54 |
} |
| 55 | 55 |
|
| 56 |
+func (osv OSVersion) ToString() string {
|
|
| 57 |
+ return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
|
|
| 58 |
+} |
|
| 59 |
+ |
|
| 56 | 60 |
// IsWindowsClient returns true if the SKU is client |
| 57 | 61 |
// @engine maintainers - this function should not be removed or modified as it |
| 58 | 62 |
// is used to enforce licensing restrictions on Windows. |
| ... | ... |
@@ -33,6 +33,7 @@ import ( |
| 33 | 33 |
"github.com/docker/docker/plugin/v2" |
| 34 | 34 |
refstore "github.com/docker/docker/reference" |
| 35 | 35 |
digest "github.com/opencontainers/go-digest" |
| 36 |
+ specs "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 36 | 37 |
"github.com/pkg/errors" |
| 37 | 38 |
"github.com/sirupsen/logrus" |
| 38 | 39 |
"golang.org/x/net/context" |
| ... | ... |
@@ -146,10 +147,15 @@ func (s *tempConfigStore) Get(d digest.Digest) ([]byte, error) {
|
| 146 | 146 |
return s.config, nil |
| 147 | 147 |
} |
| 148 | 148 |
|
| 149 |
-func (s *tempConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
|
| 149 |
+func (s *tempConfigStore) RootFSFromConfig(c []byte) (*image.RootFS, error) {
|
|
| 150 | 150 |
return configToRootFS(c) |
| 151 | 151 |
} |
| 152 | 152 |
|
| 153 |
+func (s *tempConfigStore) PlatformFromConfig(c []byte) (*specs.Platform, error) {
|
|
| 154 |
+ // TODO: LCOW/Plugins. This will need revisiting. For now use the runtime OS |
|
| 155 |
+ return &specs.Platform{OS: runtime.GOOS}, nil
|
|
| 156 |
+} |
|
| 157 |
+ |
|
| 153 | 158 |
func computePrivileges(c types.PluginConfig) types.PluginPrivileges {
|
| 154 | 159 |
var privileges types.PluginPrivileges |
| 155 | 160 |
if c.Network.Type != "null" && c.Network.Type != "bridge" && c.Network.Type != "" {
|
| ... | ... |
@@ -534,10 +540,15 @@ func (s *pluginConfigStore) Get(d digest.Digest) ([]byte, error) {
|
| 534 | 534 |
return ioutil.ReadAll(rwc) |
| 535 | 535 |
} |
| 536 | 536 |
|
| 537 |
-func (s *pluginConfigStore) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
|
| 537 |
+func (s *pluginConfigStore) RootFSFromConfig(c []byte) (*image.RootFS, error) {
|
|
| 538 | 538 |
return configToRootFS(c) |
| 539 | 539 |
} |
| 540 | 540 |
|
| 541 |
+func (s *pluginConfigStore) PlatformFromConfig(c []byte) (*specs.Platform, error) {
|
|
| 542 |
+ // TODO: LCOW/Plugins. This will need revisiting. For now use the runtime OS |
|
| 543 |
+ return &specs.Platform{OS: runtime.GOOS}, nil
|
|
| 544 |
+} |
|
| 545 |
+ |
|
| 541 | 546 |
type pluginLayerProvider struct {
|
| 542 | 547 |
pm *Manager |
| 543 | 548 |
plugin *v2.Plugin |
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"io/ioutil" |
| 7 | 7 |
"os" |
| 8 | 8 |
"path/filepath" |
| 9 |
+ "runtime" |
|
| 9 | 10 |
|
| 10 | 11 |
"github.com/docker/docker/distribution/xfer" |
| 11 | 12 |
"github.com/docker/docker/image" |
| ... | ... |
@@ -14,6 +15,7 @@ import ( |
| 14 | 14 |
"github.com/docker/docker/pkg/chrootarchive" |
| 15 | 15 |
"github.com/docker/docker/pkg/progress" |
| 16 | 16 |
"github.com/opencontainers/go-digest" |
| 17 |
+ specs "github.com/opencontainers/image-spec/specs-go/v1" |
|
| 17 | 18 |
"github.com/pkg/errors" |
| 18 | 19 |
"github.com/sirupsen/logrus" |
| 19 | 20 |
"golang.org/x/net/context" |
| ... | ... |
@@ -178,6 +180,10 @@ func (dm *downloadManager) Put(dt []byte) (digest.Digest, error) {
|
| 178 | 178 |
func (dm *downloadManager) Get(d digest.Digest) ([]byte, error) {
|
| 179 | 179 |
return nil, fmt.Errorf("digest not found")
|
| 180 | 180 |
} |
| 181 |
-func (dm *downloadManager) RootFSAndOSFromConfig(c []byte) (*image.RootFS, string, error) {
|
|
| 181 |
+func (dm *downloadManager) RootFSFromConfig(c []byte) (*image.RootFS, error) {
|
|
| 182 | 182 |
return configToRootFS(c) |
| 183 | 183 |
} |
| 184 |
+func (dm *downloadManager) PlatformFromConfig(c []byte) (*specs.Platform, error) {
|
|
| 185 |
+ // TODO: LCOW/Plugins. This will need revisiting. For now use the runtime OS |
|
| 186 |
+ return &specs.Platform{OS: runtime.GOOS}, nil
|
|
| 187 |
+} |
| ... | ... |
@@ -8,7 +8,6 @@ import ( |
| 8 | 8 |
"path/filepath" |
| 9 | 9 |
"reflect" |
| 10 | 10 |
"regexp" |
| 11 |
- "runtime" |
|
| 12 | 11 |
"sort" |
| 13 | 12 |
"strings" |
| 14 | 13 |
"sync" |
| ... | ... |
@@ -375,19 +374,17 @@ func isEqualPrivilege(a, b types.PluginPrivilege) bool {
|
| 375 | 375 |
return reflect.DeepEqual(a.Value, b.Value) |
| 376 | 376 |
} |
| 377 | 377 |
|
| 378 |
-func configToRootFS(c []byte) (*image.RootFS, string, error) {
|
|
| 379 |
- // TODO @jhowardmsft LCOW - Will need to revisit this. |
|
| 380 |
- os := runtime.GOOS |
|
| 378 |
+func configToRootFS(c []byte) (*image.RootFS, error) {
|
|
| 381 | 379 |
var pluginConfig types.PluginConfig |
| 382 | 380 |
if err := json.Unmarshal(c, &pluginConfig); err != nil {
|
| 383 |
- return nil, "", err |
|
| 381 |
+ return nil, err |
|
| 384 | 382 |
} |
| 385 | 383 |
// validation for empty rootfs is in distribution code |
| 386 | 384 |
if pluginConfig.Rootfs == nil {
|
| 387 |
- return nil, os, nil |
|
| 385 |
+ return nil, nil |
|
| 388 | 386 |
} |
| 389 | 387 |
|
| 390 |
- return rootFSFromPlugin(pluginConfig.Rootfs), os, nil |
|
| 388 |
+ return rootFSFromPlugin(pluginConfig.Rootfs), nil |
|
| 391 | 389 |
} |
| 392 | 390 |
|
| 393 | 391 |
func rootFSFromPlugin(pluginfs *types.PluginConfigRootfs) *image.RootFS {
|