mirror of https://github.com/docker/cli.git
Only warn on volume.external.name for version 3.4
Also remove use of volume.external.name Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
parent
e2ada663d2
commit
aea9544db5
|
@ -68,16 +68,15 @@ func convertVolumeToMount(
|
||||||
result.VolumeOptions.NoCopy = volume.Volume.NoCopy
|
result.VolumeOptions.NoCopy = volume.Volume.NoCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
// External named volumes
|
|
||||||
if stackVolume.External.External {
|
|
||||||
result.Source = stackVolume.External.Name
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if stackVolume.Name != "" {
|
if stackVolume.Name != "" {
|
||||||
result.Source = stackVolume.Name
|
result.Source = stackVolume.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External named volumes
|
||||||
|
if stackVolume.External.External {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
result.VolumeOptions.Labels = AddStackLabel(namespace, stackVolume.Labels)
|
result.VolumeOptions.Labels = AddStackLabel(namespace, stackVolume.Labels)
|
||||||
if stackVolume.Driver != "" || stackVolume.DriverOpts != nil {
|
if stackVolume.Driver != "" || stackVolume.DriverOpts != nil {
|
||||||
result.VolumeOptions.DriverConfig = &mount.Driver{
|
result.VolumeOptions.DriverConfig = &mount.Driver{
|
||||||
|
|
|
@ -148,20 +148,16 @@ func TestConvertVolumeToMountNamedVolumeWithNameCustomizd(t *testing.T) {
|
||||||
func TestConvertVolumeToMountNamedVolumeExternal(t *testing.T) {
|
func TestConvertVolumeToMountNamedVolumeExternal(t *testing.T) {
|
||||||
stackVolumes := volumes{
|
stackVolumes := volumes{
|
||||||
"outside": composetypes.VolumeConfig{
|
"outside": composetypes.VolumeConfig{
|
||||||
External: composetypes.External{
|
Name: "special",
|
||||||
External: true,
|
External: composetypes.External{External: true},
|
||||||
Name: "special",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
namespace := NewNamespace("foo")
|
namespace := NewNamespace("foo")
|
||||||
expected := mount.Mount{
|
expected := mount.Mount{
|
||||||
Type: mount.TypeVolume,
|
Type: mount.TypeVolume,
|
||||||
Source: "special",
|
Source: "special",
|
||||||
Target: "/foo",
|
Target: "/foo",
|
||||||
VolumeOptions: &mount.VolumeOptions{
|
VolumeOptions: &mount.VolumeOptions{NoCopy: false},
|
||||||
NoCopy: false,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
config := composetypes.ServiceVolumeConfig{
|
config := composetypes.ServiceVolumeConfig{
|
||||||
Type: "volume",
|
Type: "volume",
|
||||||
|
@ -176,10 +172,8 @@ func TestConvertVolumeToMountNamedVolumeExternal(t *testing.T) {
|
||||||
func TestConvertVolumeToMountNamedVolumeExternalNoCopy(t *testing.T) {
|
func TestConvertVolumeToMountNamedVolumeExternalNoCopy(t *testing.T) {
|
||||||
stackVolumes := volumes{
|
stackVolumes := volumes{
|
||||||
"outside": composetypes.VolumeConfig{
|
"outside": composetypes.VolumeConfig{
|
||||||
External: composetypes.External{
|
Name: "special",
|
||||||
External: true,
|
External: composetypes.External{External: true},
|
||||||
Name: "special",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
namespace := NewNamespace("foo")
|
namespace := NewNamespace("foo")
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/docker/cli/cli/compose/template"
|
"github.com/docker/cli/cli/compose/template"
|
||||||
"github.com/docker/cli/cli/compose/types"
|
"github.com/docker/cli/cli/compose/types"
|
||||||
"github.com/docker/cli/opts"
|
"github.com/docker/cli/opts"
|
||||||
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
shellwords "github.com/mattn/go-shellwords"
|
shellwords "github.com/mattn/go-shellwords"
|
||||||
|
@ -49,6 +50,7 @@ func Load(configDetails types.ConfigDetails) (*types.Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
configDict := getConfigDict(configDetails)
|
configDict := getConfigDict(configDetails)
|
||||||
|
configDetails.Version = schema.Version(configDict)
|
||||||
|
|
||||||
if err := validateForbidden(configDict); err != nil {
|
if err := validateForbidden(configDict); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -60,7 +62,7 @@ func Load(configDetails types.ConfigDetails) (*types.Config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := schema.Validate(configDict, schema.Version(configDict)); err != nil {
|
if err := schema.Validate(configDict, configDetails.Version); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return loadSections(configDict, configDetails)
|
return loadSections(configDict, configDetails)
|
||||||
|
@ -103,7 +105,7 @@ func loadSections(config map[string]interface{}, configDetails types.ConfigDetai
|
||||||
{
|
{
|
||||||
key: "volumes",
|
key: "volumes",
|
||||||
fnc: func(config map[string]interface{}) error {
|
fnc: func(config map[string]interface{}) error {
|
||||||
cfg.Volumes, err = LoadVolumes(config)
|
cfg.Volumes, err = LoadVolumes(config, configDetails.Version)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -446,34 +448,36 @@ func externalVolumeError(volume, key string) error {
|
||||||
|
|
||||||
// LoadVolumes produces a VolumeConfig map from a compose file Dict
|
// LoadVolumes produces a VolumeConfig map from a compose file Dict
|
||||||
// the source Dict is not validated if directly used. Use Load() to enable validation
|
// the source Dict is not validated if directly used. Use Load() to enable validation
|
||||||
func LoadVolumes(source map[string]interface{}) (map[string]types.VolumeConfig, error) {
|
func LoadVolumes(source map[string]interface{}, version string) (map[string]types.VolumeConfig, error) {
|
||||||
volumes := make(map[string]types.VolumeConfig)
|
volumes := make(map[string]types.VolumeConfig)
|
||||||
err := transform(source, &volumes)
|
if err := transform(source, &volumes); err != nil {
|
||||||
if err != nil {
|
|
||||||
return volumes, err
|
return volumes, err
|
||||||
}
|
}
|
||||||
for name, volume := range volumes {
|
|
||||||
if volume.External.External {
|
|
||||||
if volume.Driver != "" {
|
|
||||||
return nil, externalVolumeError(name, "driver")
|
|
||||||
}
|
|
||||||
if len(volume.DriverOpts) > 0 {
|
|
||||||
return nil, externalVolumeError(name, "driver_opts")
|
|
||||||
}
|
|
||||||
if len(volume.Labels) > 0 {
|
|
||||||
return nil, externalVolumeError(name, "labels")
|
|
||||||
}
|
|
||||||
if volume.External.Name == "" {
|
|
||||||
volume.External.Name = name
|
|
||||||
volumes[name] = volume
|
|
||||||
} else {
|
|
||||||
logrus.Warnf("volume %s: volume.external.name is deprecated in favor of volume.name", name)
|
|
||||||
|
|
||||||
if volume.Name != "" {
|
for name, volume := range volumes {
|
||||||
return nil, errors.Errorf("volume %s: volume.external.name and volume.name conflict; only use volume.name", name)
|
if !volume.External.External {
|
||||||
}
|
continue
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
switch {
|
||||||
|
case volume.Driver != "":
|
||||||
|
return nil, externalVolumeError(name, "driver")
|
||||||
|
case len(volume.DriverOpts) > 0:
|
||||||
|
return nil, externalVolumeError(name, "driver_opts")
|
||||||
|
case len(volume.Labels) > 0:
|
||||||
|
return nil, externalVolumeError(name, "labels")
|
||||||
|
case volume.External.Name != "":
|
||||||
|
if volume.Name != "" {
|
||||||
|
return nil, errors.Errorf("volume %s: volume.external.name and volume.name conflict; only use volume.name", name)
|
||||||
|
}
|
||||||
|
if versions.GreaterThanOrEqualTo(version, "3.4") {
|
||||||
|
logrus.Warnf("volume %s: volume.external.name is deprecated in favor of volume.name", name)
|
||||||
|
}
|
||||||
|
volume.Name = volume.External.Name
|
||||||
|
volume.External.Name = ""
|
||||||
|
case volume.Name == "":
|
||||||
|
volume.Name = name
|
||||||
|
}
|
||||||
|
volumes[name] = volume
|
||||||
}
|
}
|
||||||
return volumes, nil
|
return volumes, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package loader
|
package loader
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -9,6 +10,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/compose/types"
|
"github.com/docker/cli/cli/compose/types"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -630,7 +632,7 @@ networks:
|
||||||
"super": {External: types.External{External: true, Name: "super"}},
|
"super": {External: types.External{External: true, Name: "super"}},
|
||||||
},
|
},
|
||||||
Volumes: map[string]types.VolumeConfig{
|
Volumes: map[string]types.VolumeConfig{
|
||||||
"data": {External: types.External{External: true, Name: "data"}},
|
"data": {External: types.External{External: true}, Name: "data"},
|
||||||
},
|
},
|
||||||
Networks: map[string]types.NetworkConfig{
|
Networks: map[string]types.NetworkConfig{
|
||||||
"front": {
|
"front": {
|
||||||
|
@ -1190,23 +1192,16 @@ func TestFullExample(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"external-volume": {
|
"external-volume": {
|
||||||
External: types.External{
|
Name: "external-volume",
|
||||||
Name: "external-volume",
|
External: types.External{External: true},
|
||||||
External: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"other-external-volume": {
|
"other-external-volume": {
|
||||||
External: types.External{
|
Name: "my-cool-volume",
|
||||||
Name: "my-cool-volume",
|
External: types.External{External: true},
|
||||||
External: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"external-volume3": {
|
"external-volume3": {
|
||||||
Name: "this-is-volume3",
|
Name: "this-is-volume3",
|
||||||
External: types.External{
|
External: types.External{External: true},
|
||||||
Name: "external-volume3",
|
|
||||||
External: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1406,3 +1401,58 @@ services:
|
||||||
require.Len(t, config.Services, 1)
|
require.Len(t, config.Services, 1)
|
||||||
assert.Equal(t, expected, config.Services[0].ExtraHosts)
|
assert.Equal(t, expected, config.Services[0].ExtraHosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadVolumesWarnOnDeprecatedExternalNameVersion34(t *testing.T) {
|
||||||
|
buf, cleanup := patchLogrus()
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
source := map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"external": map[string]interface{}{
|
||||||
|
"name": "oops",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
volumes, err := LoadVolumes(source, "3.4")
|
||||||
|
require.NoError(t, err)
|
||||||
|
expected := map[string]types.VolumeConfig{
|
||||||
|
"foo": {
|
||||||
|
Name: "oops",
|
||||||
|
External: types.External{External: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expected, volumes)
|
||||||
|
assert.Contains(t, buf.String(), "volume.external.name is deprecated")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func patchLogrus() (*bytes.Buffer, func()) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
out := logrus.StandardLogger().Out
|
||||||
|
logrus.SetOutput(buf)
|
||||||
|
return buf, func() { logrus.SetOutput(out) }
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadVolumesWarnOnDeprecatedExternalNameVersion33(t *testing.T) {
|
||||||
|
buf, cleanup := patchLogrus()
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
source := map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"external": map[string]interface{}{
|
||||||
|
"name": "oops",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
volumes, err := LoadVolumes(source, "3.3")
|
||||||
|
require.NoError(t, err)
|
||||||
|
expected := map[string]types.VolumeConfig{
|
||||||
|
"foo": {
|
||||||
|
Name: "oops",
|
||||||
|
External: types.External{External: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expected, volumes)
|
||||||
|
assert.Equal(t, "", buf.String())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ type ConfigFile struct {
|
||||||
|
|
||||||
// ConfigDetails are the details about a group of ConfigFiles
|
// ConfigDetails are the details about a group of ConfigFiles
|
||||||
type ConfigDetails struct {
|
type ConfigDetails struct {
|
||||||
|
Version string
|
||||||
WorkingDir string
|
WorkingDir string
|
||||||
ConfigFiles []ConfigFile
|
ConfigFiles []ConfigFile
|
||||||
Environment map[string]string
|
Environment map[string]string
|
||||||
|
|
Loading…
Reference in New Issue