diff --git a/pkg/configfilearg/parser.go b/pkg/configfilearg/parser.go index fade98d5ba..4abd563e69 100644 --- a/pkg/configfilearg/parser.go +++ b/pkg/configfilearg/parser.go @@ -6,8 +6,10 @@ import ( "net/http" "net/url" "os" + "path/filepath" "strings" + "github.com/rancher/k3s/pkg/agent/util" "github.com/rancher/wrangler/pkg/data/convert" "gopkg.in/yaml.v2" ) @@ -19,7 +21,7 @@ type Parser struct { DefaultConfig string } -// Parser will parse an os.Args style slice looking for Parser.FlagNames after Parse.After. +// Parse will parse an os.Args style slice looking for Parser.FlagNames after Parse.After. // It will read the parameter value of Parse.FlagNames and read the file, appending all flags directly after // the Parser.After value. This means a the non-config file flags will override, or if a slice append to, the config // file values. @@ -110,31 +112,69 @@ func (p *Parser) findStart(args []string) ([]string, []string, bool) { return args, nil, false } +func dotDFiles(basefile string) (result []string, _ error) { + files, err := ioutil.ReadDir(basefile + ".d") + if os.IsNotExist(err) { + return nil, nil + } else if err != nil { + return nil, err + } + for _, file := range files { + if file.IsDir() || !util.HasSuffixI(file.Name(), ".yaml", ".yml") { + continue + } + result = append(result, filepath.Join(basefile+".d", file.Name())) + } + return +} + func readConfigFile(file string) (result []string, _ error) { - bytes, err := readConfigFileData(file) + files, err := dotDFiles(file) if err != nil { return nil, err } - data := yaml.MapSlice{} - if err := yaml.Unmarshal(bytes, &data); err != nil { + _, err = os.Stat(file) + if os.IsNotExist(err) && len(files) > 0 { + } else if err != nil { return nil, err + } else { + files = append([]string{file}, files...) } - for _, i := range data { - k, v := convert.ToString(i.Key), i.Value - prefix := "--" - if len(k) == 1 { - prefix = "-" + keySeen := map[string]bool{} + for i := len(files) - 1; i >= 0; i-- { + file := files[i] + bytes, err := readConfigFileData(file) + if err != nil { + return nil, err + } + + data := yaml.MapSlice{} + if err := yaml.Unmarshal(bytes, &data); err != nil { + return nil, err } - if slice, ok := v.([]interface{}); ok { - for _, v := range slice { - result = append(result, prefix+k+"="+convert.ToString(v)) + for _, i := range data { + k, v := convert.ToString(i.Key), i.Value + if keySeen[k] { + continue + } + keySeen[k] = true + + prefix := "--" + if len(k) == 1 { + prefix = "-" + } + + if slice, ok := v.([]interface{}); ok { + for _, v := range slice { + result = append(result, prefix+k+"="+convert.ToString(v)) + } + } else { + str := convert.ToString(v) + result = append(result, prefix+k+"="+str) } - } else { - str := convert.ToString(v) - result = append(result, prefix+k+"="+str) } } diff --git a/pkg/configfilearg/parser_test.go b/pkg/configfilearg/parser_test.go index 675a53f68a..8c3197e620 100644 --- a/pkg/configfilearg/parser_test.go +++ b/pkg/configfilearg/parser_test.go @@ -150,8 +150,9 @@ func TestConfigFile(t *testing.T) { func TestParse(t *testing.T) { testDataOutput := []string{ - "--foo-bar=baz", + "--foo-bar=bar-foo", "--a-slice=1", + "--a-slice=1.5", "--a-slice=2", "--a-slice=", "--a-slice=three", @@ -205,7 +206,7 @@ func TestParse(t *testing.T) { input: []string{"server", "-c=missing"}, output: []string{"server", "-c=missing"}, what: "fail when missing config", - err: "open missing: no such file or directory", + err: "stat missing: no such file or directory", }, { parser: Parser{ @@ -217,6 +218,16 @@ func TestParse(t *testing.T) { output: append(append([]string{"before", "server"}, testDataOutput...), "before", "-c", "./testdata/data.yaml", "after"), what: "read config file", }, + { + parser: Parser{ + After: []string{"server", "agent"}, + FlagNames: []string{"-c", "--config"}, + DefaultConfig: "missing", + }, + input: []string{"before", "server", "before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"}, + output: []string{"before", "server", "--foo-bar=bar-foo", "before", "-c", "./testdata/data.yaml.d/02-data.yaml", "after"}, + what: "read single config file", + }, } for _, testCase := range testCases { diff --git a/pkg/configfilearg/testdata/data.yaml.d/01-data.yml b/pkg/configfilearg/testdata/data.yaml.d/01-data.yml new file mode 100644 index 0000000000..d594177c69 --- /dev/null +++ b/pkg/configfilearg/testdata/data.yaml.d/01-data.yml @@ -0,0 +1,7 @@ +foo-bar: get-overriden +a-slice: +- 1 +- "1.5" +- "2" +- "" +- three \ No newline at end of file diff --git a/pkg/configfilearg/testdata/data.yaml.d/02-data-ignore-this.txt b/pkg/configfilearg/testdata/data.yaml.d/02-data-ignore-this.txt new file mode 100644 index 0000000000..f8048ad055 --- /dev/null +++ b/pkg/configfilearg/testdata/data.yaml.d/02-data-ignore-this.txt @@ -0,0 +1 @@ +foo-bar: ignored diff --git a/pkg/configfilearg/testdata/data.yaml.d/02-data.yaml b/pkg/configfilearg/testdata/data.yaml.d/02-data.yaml new file mode 100644 index 0000000000..65f5901a53 --- /dev/null +++ b/pkg/configfilearg/testdata/data.yaml.d/02-data.yaml @@ -0,0 +1 @@ +foo-bar: bar-foo \ No newline at end of file