From ed0c8aee546db3e1bb00ac7c62f19161cd61f168 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Thu, 2 Nov 2023 10:52:25 +0100 Subject: [PATCH] add support for inline config Signed-off-by: Nicolas De Loof --- schema/compose-spec.json | 2 + types/types.go | 1 + validation/validation.go | 31 +++++++++++ validation/validation_test.go | 96 +++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 validation/validation_test.go diff --git a/schema/compose-spec.json b/schema/compose-spec.json index d4bff384..463d6822 100644 --- a/schema/compose-spec.json +++ b/schema/compose-spec.json @@ -764,6 +764,8 @@ "type": "object", "properties": { "name": {"type": "string"}, + "content": {"type": "string"}, + "environment": {"type": "string"}, "file": {"type": "string"}, "external": { "type": ["boolean", "object"], diff --git a/types/types.go b/types/types.go index 48c89024..83ca7b09 100644 --- a/types/types.go +++ b/types/types.go @@ -699,6 +699,7 @@ type FileObjectConfig struct { Name string `yaml:"name,omitempty" json:"name,omitempty"` File string `yaml:"file,omitempty" json:"file,omitempty"` Environment string `yaml:"environment,omitempty" json:"environment,omitempty"` + Content string `yaml:"content,omitempty" json:"content,omitempty"` External External `yaml:"external,omitempty" json:"external,omitempty"` Labels Labels `yaml:"labels,omitempty" json:"labels,omitempty"` Driver string `yaml:"driver,omitempty" json:"driver,omitempty"` diff --git a/validation/validation.go b/validation/validation.go index 3dc49334..25b37d9e 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -17,6 +17,9 @@ package validation import ( + "fmt" + "strings" + "github.com/compose-spec/compose-go/v2/tree" ) @@ -24,6 +27,8 @@ type checkerFunc func(value any, p tree.Path) error var checks = map[tree.Path]checkerFunc{ "volumes.*": checkVolume, + "configs.*": checkFileObject("file", "environment", "content"), + "secrets.*": checkFileObject("file", "environment"), } func Validate(dict map[string]any) error { @@ -54,3 +59,29 @@ func check(value any, p tree.Path) error { } return nil } + +func checkFileObject(keys ...string) checkerFunc { + return func(value any, p tree.Path) error { + + v := value.(map[string]any) + count := 0 + for _, s := range keys { + if _, ok := v[s]; ok { + count++ + } + } + if count > 1 { + return fmt.Errorf("%s: %s attributes are mutually exclusive", p, strings.Join(keys, "|")) + } + if count == 0 { + if _, ok := v["driver"]; ok { + // User specified a custom driver, which might have it's own way to set content + return nil + } + if _, ok := v["external"]; !ok { + return fmt.Errorf("%s: one of %s must be set", p, strings.Join(keys, "|")) + } + } + return nil + } +} diff --git a/validation/validation_test.go b/validation/validation_test.go new file mode 100644 index 00000000..6d7e4b2f --- /dev/null +++ b/validation/validation_test.go @@ -0,0 +1,96 @@ +/* + Copyright 2020 The Compose Specification Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package validation + +import ( + "testing" + + "github.com/compose-spec/compose-go/v2/tree" + "gopkg.in/yaml.v3" + "gotest.tools/v3/assert" +) + +func TestValidateSecret(t *testing.T) { + checker := checks["configs.*"] + tests := []struct { + name string + input string + err string + }{ + { + name: "file config", + input: ` +name: test +file: ./httpd.conf +`, + err: "", + }, + { + name: "environment config", + input: ` +name: test +environment: CONFIG +`, + err: "", + }, + { + name: "inlined config", + input: ` +name: test +content: foo=bar +`, + err: "", + }, + { + name: "conflict config", + input: ` +name: test +environment: CONFIG +content: foo=bar +`, + err: "configs.test: file|environment|content attributes are mutually exclusive", + }, + { + name: "missing config", + input: ` +name: test +`, + err: "configs.test: one of file|environment|content must be set", + }, + { + name: "external config", + input: ` +name: test +external: true +`, + err: "", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var input map[string]any + err := yaml.Unmarshal([]byte(tt.input), &input) + assert.NilError(t, err) + err = checker(input, tree.NewPath("configs.test")) + if tt.err == "" { + assert.NilError(t, err) + } else { + assert.Equal(t, tt.err, err.Error()) + } + }) + } +}