diff --git a/cli/command/stack/kubernetes/stackclient.go b/cli/command/stack/kubernetes/stackclient.go index 763650f15b..4a9852850d 100644 --- a/cli/command/stack/kubernetes/stackclient.go +++ b/cli/command/stack/kubernetes/stackclient.go @@ -4,10 +4,14 @@ import ( "fmt" "io" + "github.com/docker/cli/cli/compose/loader" + "github.com/docker/cli/cli/compose/schema" composetypes "github.com/docker/cli/cli/compose/types" composev1beta1 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta1" composev1beta2 "github.com/docker/cli/kubernetes/client/clientset/typed/compose/v1beta2" + v1beta1types "github.com/docker/cli/kubernetes/compose/v1beta1" "github.com/docker/cli/kubernetes/labels" + "github.com/pkg/errors" yaml "gopkg.in/yaml.v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" corev1 "k8s.io/client-go/kubernetes/typed/core/v1" @@ -105,6 +109,7 @@ func verify(services corev1.ServiceInterface, stackName string, service string) } func (s *stackV1Beta1) FromCompose(stderr io.Writer, name string, cfg *composetypes.Config) (stack, error) { + cfg.Version = v1beta1types.MaxComposeVersion st, err := fromCompose(stderr, name, cfg) if err != nil { return stack{}, err @@ -113,6 +118,15 @@ func (s *stackV1Beta1) FromCompose(stderr io.Writer, name string, cfg *composety if err != nil { return stack{}, err } + // reload the result to check that it produced a valid 3.5 compose file + resparsedConfig, err := loader.ParseYAML(res) + if err != nil { + return stack{}, err + } + if err = schema.Validate(resparsedConfig, v1beta1types.MaxComposeVersion); err != nil { + return stack{}, errors.Wrapf(err, "the compose yaml file is invalid with v%s", v1beta1types.MaxComposeVersion) + } + st.composeFile = string(res) return st, nil } diff --git a/cli/command/stack/kubernetes/stackclient_test.go b/cli/command/stack/kubernetes/stackclient_test.go index 86af976936..b82e6b13ef 100644 --- a/cli/command/stack/kubernetes/stackclient_test.go +++ b/cli/command/stack/kubernetes/stackclient_test.go @@ -26,7 +26,7 @@ func TestFromCompose(t *testing.T) { }) assert.NilError(t, err) assert.Equal(t, "foo", s.name) - assert.Equal(t, string(`version: "3.1" + assert.Equal(t, string(`version: "3.5" services: bar: image: bar @@ -38,3 +38,27 @@ secrets: {} configs: {} `), s.composeFile) } + +func TestFromComposeUnsupportedVersion(t *testing.T) { + stackClient := &stackV1Beta1{} + _, err := stackClient.FromCompose(ioutil.Discard, "foo", &composetypes.Config{ + Version: "3.6", + Filename: "banana", + Services: []composetypes.ServiceConfig{ + { + Name: "foo", + Image: "foo", + Volumes: []composetypes.ServiceVolumeConfig{ + { + Type: "tmpfs", + Target: "/app", + Tmpfs: &composetypes.ServiceVolumeTmpfs{ + Size: 10000, + }, + }, + }, + }, + }, + }) + assert.ErrorContains(t, err, "the compose yaml file is invalid with v3.5: services.foo.volumes.0 Additional property tmpfs is not allowed") +} diff --git a/kubernetes/compose/v1beta1/parsing.go b/kubernetes/compose/v1beta1/parsing.go new file mode 100644 index 0000000000..634a8428a7 --- /dev/null +++ b/kubernetes/compose/v1beta1/parsing.go @@ -0,0 +1,4 @@ +package v1beta1 + +// MaxComposeVersion is the most recent version of compose file Schema supported in v1beta1 +const MaxComposeVersion = "3.5"