Simplify the marshaling of compose types.Config

- Add `Version` to `types.Config`
- Add a new `Services` types (that is just `[]ServiceConfig`) and add
  `MarshalYAML` method on it.
- Clean other top-level custom marshaling as `Services` is the only one
  required.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
This commit is contained in:
Vincent Demeester 2018-02-21 18:31:52 +01:00
parent 939938b976
commit cf86a4d922
No known key found for this signature in database
GPG Key ID: 083CC6FD6EB699A3
11 changed files with 60 additions and 70 deletions

View File

@ -22,11 +22,11 @@ func RunDeploy(dockerCli *KubeCli, opts options.Deploy) error {
}
// Parse the compose file
cfg, version, err := loader.LoadComposefile(dockerCli, opts)
cfg, err := loader.LoadComposefile(dockerCli, opts)
if err != nil {
return err
}
stack, err := LoadStack(opts.Namespace, version, *cfg)
stack, err := LoadStack(opts.Namespace, *cfg)
if err != nil {
return err
}

View File

@ -7,32 +7,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type versionedConfig struct {
composetypes.Config
version string
}
func (c versionedConfig) MarshalYAML() (interface{}, error) {
services := map[string]composetypes.ServiceConfig{}
for _, service := range c.Services {
services[service.Name] = service
}
return map[string]interface{}{
"services": services,
"networks": c.Networks,
"volumes": c.Volumes,
"secrets": c.Secrets,
"configs": c.Configs,
"version": c.version,
}, nil
}
// LoadStack loads a stack from a Compose config, with a given name.
func LoadStack(name, version string, cfg composetypes.Config) (*apiv1beta1.Stack, error) {
res, err := yaml.Marshal(versionedConfig{
version: version,
Config: cfg,
})
func LoadStack(name string, cfg composetypes.Config) (*apiv1beta1.Stack, error) {
res, err := yaml.Marshal(cfg)
if err != nil {
return nil, err
}

View File

@ -10,7 +10,8 @@ import (
)
func TestLoadStack(t *testing.T) {
s, err := LoadStack("foo", "3.1", composetypes.Config{
s, err := LoadStack("foo", composetypes.Config{
Version: "3.1",
Filename: "banana",
Services: []composetypes.ServiceConfig{
{
@ -29,16 +30,16 @@ func TestLoadStack(t *testing.T) {
Name: "foo",
},
Spec: apiv1beta1.StackSpec{
ComposeFile: string(`configs: {}
networks: {}
secrets: {}
ComposeFile: string(`version: "3.1"
services:
bar:
image: bar
foo:
image: foo
version: "3.1"
networks: {}
volumes: {}
secrets: {}
configs: {}
`),
},
}, s)

View File

@ -18,21 +18,21 @@ import (
)
// LoadComposefile parse the composefile specified in the cli and returns its Config and version.
func LoadComposefile(dockerCli command.Cli, opts options.Deploy) (*composetypes.Config, string, error) {
func LoadComposefile(dockerCli command.Cli, opts options.Deploy) (*composetypes.Config, error) {
configDetails, err := getConfigDetails(opts.Composefiles, dockerCli.In())
if err != nil {
return nil, "", err
return nil, err
}
dicts := getDictsFrom(configDetails.ConfigFiles)
config, err := loader.Load(configDetails)
if err != nil {
if fpe, ok := err.(*loader.ForbiddenPropertiesError); ok {
return nil, "", errors.Errorf("Compose file contains unsupported options:\n\n%s\n",
return nil, errors.Errorf("Compose file contains unsupported options:\n\n%s\n",
propertyWarnings(fpe.Properties))
}
return nil, "", err
return nil, err
}
unsupportedProperties := loader.GetUnsupportedProperties(dicts...)
@ -46,7 +46,7 @@ func LoadComposefile(dockerCli command.Cli, opts options.Deploy) (*composetypes.
fmt.Fprintf(dockerCli.Err(), "Ignoring deprecated options:\n\n%s\n\n",
propertyWarnings(deprecatedProperties))
}
return config, configDetails.Version, nil
return config, nil
}
func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]interface{} {

View File

@ -18,7 +18,7 @@ import (
)
func deployCompose(ctx context.Context, dockerCli command.Cli, opts options.Deploy) error {
config, _, err := loader.LoadComposefile(dockerCli, opts)
config, err := loader.LoadComposefile(dockerCli, opts)
if err != nil {
return err
}

View File

@ -8,6 +8,7 @@ import (
func fullExampleConfig(workingDir, homeDir string) *types.Config {
return &types.Config{
Version: "3.6",
Services: services(workingDir, homeDir),
Networks: networks(),
Volumes: volumes(),

View File

@ -98,7 +98,9 @@ func validateForbidden(configDict map[string]interface{}) error {
func loadSections(config map[string]interface{}, configDetails types.ConfigDetails) (*types.Config, error) {
var err error
cfg := types.Config{}
cfg := types.Config{
Version: schema.Version(config),
}
var loaders = []struct {
key string

View File

@ -119,6 +119,7 @@ func strPtr(val string) *string {
}
var sampleConfig = types.Config{
Version: "3.0",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -174,6 +175,7 @@ func TestParseYAML(t *testing.T) {
func TestLoad(t *testing.T) {
actual, err := Load(buildConfigDetails(sampleDict, nil))
require.NoError(t, err)
assert.Equal(t, sampleConfig.Version, actual.Version)
assert.Equal(t, serviceSort(sampleConfig.Services), serviceSort(actual.Services))
assert.Equal(t, sampleConfig.Networks, actual.Networks)
assert.Equal(t, sampleConfig.Volumes, actual.Volumes)
@ -573,6 +575,7 @@ networks:
require.NoError(t, err)
expected := &types.Config{
Filename: "filename.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "web",

View File

@ -207,6 +207,7 @@ func TestLoadLogging(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -325,6 +326,7 @@ func TestLoadMultipleServicePorts(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -450,6 +452,7 @@ func TestLoadMultipleSecretsConfig(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -575,6 +578,7 @@ func TestLoadMultipleConfigobjsConfig(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -690,6 +694,7 @@ func TestLoadMultipleUlimits(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -808,6 +813,7 @@ func TestLoadMultipleNetworks(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "foo",
@ -895,6 +901,7 @@ func TestLoadMultipleConfigs(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &types.Config{
Filename: "base.yml",
Version: "3.4",
Services: []types.ServiceConfig{
{
Name: "bar",

View File

@ -9,26 +9,7 @@ import (
func TestMarshallConfig(t *testing.T) {
cfg := fullExampleConfig("/foo", "/bar")
expected := `configs: {}
networks:
external-network:
name: external-network
external: true
other-external-network:
name: my-cool-network
external: true
other-network:
driver: overlay
driver_opts:
baz: "1"
foo: bar
ipam:
driver: overlay
config:
- subnet: 172.16.238.0/24
- subnet: 2001:3984:3989::/64
some-network: {}
secrets: {}
expected := `version: "3.6"
services:
foo:
build:
@ -292,6 +273,24 @@ services:
tmpfs:
size: 10000
working_dir: /code
networks:
external-network:
name: external-network
external: true
other-external-network:
name: my-cool-network
external: true
other-network:
driver: overlay
driver_opts:
baz: "1"
foo: bar
ipam:
driver: overlay
config:
- subnet: 172.16.238.0/24
- subnet: 2001:3984:3989::/64
some-network: {}
volumes:
another-volume:
name: user_specified_name
@ -314,6 +313,8 @@ volumes:
baz: "1"
foo: bar
some-volume: {}
secrets: {}
configs: {}
`
actual, err := yaml.Marshal(cfg)

View File

@ -71,26 +71,24 @@ func (cd ConfigDetails) LookupEnv(key string) (string, bool) {
// Config is a full compose file configuration
type Config struct {
Filename string `yaml:"-"`
Services []ServiceConfig
Version string
Services Services
Networks map[string]NetworkConfig
Volumes map[string]VolumeConfig
Secrets map[string]SecretConfig
Configs map[string]ConfigObjConfig
}
// MarshalYAML makes Config implement yaml.Marshaller
func (c *Config) MarshalYAML() (interface{}, error) {
// Services is a list of ServiceConfig
type Services []ServiceConfig
// MarshalYAML makes Services implement yaml.Marshaller
func (s Services) MarshalYAML() (interface{}, error) {
services := map[string]ServiceConfig{}
for _, service := range c.Services {
for _, service := range s {
services[service.Name] = service
}
return map[string]interface{}{
"services": services,
"networks": c.Networks,
"volumes": c.Volumes,
"secrets": c.Secrets,
"configs": c.Configs,
}, nil
return services, nil
}
// ServiceConfig is the configuration of one service