diff --git a/cli/command/swarm/opts.go b/cli/command/swarm/opts.go index 1aa90e757bac..338d998b2fdc 100644 --- a/cli/command/swarm/opts.go +++ b/cli/command/swarm/opts.go @@ -5,6 +5,7 @@ import ( "encoding/pem" "errors" "fmt" + "io" "os" "strings" "time" @@ -99,7 +100,9 @@ func (m *ExternalCAOption) Set(value string) error { return err } - m.values = append(m.values, parsed) + if parsed != nil { + m.values = append(m.values, parsed) + } return nil } @@ -112,8 +115,10 @@ func (*ExternalCAOption) Type() string { func (m *ExternalCAOption) String() string { externalCAs := make([]string, 0, len(m.values)) for _, externalCA := range m.values { - repr := fmt.Sprintf("%s: %s", externalCA.Protocol, externalCA.URL) - externalCAs = append(externalCAs, repr) + if externalCA != nil { + repr := fmt.Sprintf("%s: %s", externalCA.Protocol, externalCA.URL) + externalCAs = append(externalCAs, repr) + } } return strings.Join(externalCAs, ", ") } @@ -161,6 +166,9 @@ func (p *PEMFile) Contents() string { func parseExternalCA(caSpec string) (*swarm.ExternalCA, error) { csvReader := csv.NewReader(strings.NewReader(caSpec)) fields, err := csvReader.Read() + if err == io.EOF { + return nil, nil + } if err != nil { return nil, err } diff --git a/cli/command/swarm/opts_test.go b/cli/command/swarm/opts_test.go index 407cfa0f9a3d..72b8819cae9b 100644 --- a/cli/command/swarm/opts_test.go +++ b/cli/command/swarm/opts_test.go @@ -3,6 +3,7 @@ package swarm import ( "testing" + "github.com/moby/moby/api/types/swarm" "gotest.tools/v3/assert" is "gotest.tools/v3/assert/cmp" ) @@ -42,10 +43,6 @@ func TestExternalCAOptionErrors(t *testing.T) { externalCA string expectedError string }{ - { - externalCA: "", - expectedError: "EOF", - }, { externalCA: "anything", expectedError: "invalid field 'anything' must be a key=value pair", @@ -71,34 +68,112 @@ func TestExternalCAOptionErrors(t *testing.T) { func TestExternalCAOption(t *testing.T) { testCases := []struct { - externalCA string - expected string + externalCAs []string + expected []*swarm.ExternalCA + expectedString string }{ { - externalCA: "protocol=cfssl,url=anything", - expected: "cfssl: anything", + externalCAs: []string{""}, + expected: nil, + expectedString: "", + }, + { + externalCAs: []string{"protocol=cfssl,url=anything"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "anything", + Options: make(map[string]string), + }, + }, + expectedString: "cfssl: anything", + }, + { + externalCAs: []string{"protocol=CFSSL,url=anything"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "anything", + Options: make(map[string]string), + }, + }, + expectedString: "cfssl: anything", + }, + { + externalCAs: []string{"protocol=Cfssl,url=https://example.com"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example.com", + Options: make(map[string]string), + }, + }, + expectedString: "cfssl: https://example.com", }, { - externalCA: "protocol=CFSSL,url=anything", - expected: "cfssl: anything", + externalCAs: []string{"protocol=Cfssl,url=https://example.com,foo=bar"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example.com", + Options: map[string]string{ + "foo": "bar", + }, + }, + }, + expectedString: "cfssl: https://example.com", }, { - externalCA: "protocol=Cfssl,url=https://example.com", - expected: "cfssl: https://example.com", + externalCAs: []string{"protocol=Cfssl,url=https://example.com,foo=bar,foo=baz"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example.com", + Options: map[string]string{ + "foo": "baz", + }, + }, + }, + expectedString: "cfssl: https://example.com", }, { - externalCA: "protocol=Cfssl,url=https://example.com,foo=bar", - expected: "cfssl: https://example.com", + externalCAs: []string{"", "protocol=Cfssl,url=https://example.com"}, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example.com", + Options: make(map[string]string), + }, + }, + expectedString: "cfssl: https://example.com", }, { - externalCA: "protocol=Cfssl,url=https://example.com,foo=bar,foo=baz", - expected: "cfssl: https://example.com", + externalCAs: []string{ + "protocol=Cfssl,url=https://example.com", + "protocol=Cfssl,url=https://example2.com", + }, + expected: []*swarm.ExternalCA{ + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example.com", + Options: make(map[string]string), + }, + { + Protocol: swarm.ExternalCAProtocolCFSSL, + URL: "https://example2.com", + Options: make(map[string]string), + }, + }, + expectedString: "cfssl: https://example.com, cfssl: https://example2.com", }, } for _, tc := range testCases { opt := &ExternalCAOption{} - assert.NilError(t, opt.Set(tc.externalCA)) - assert.Check(t, is.Equal(tc.expected, opt.String())) + for _, extCA := range tc.externalCAs { + assert.NilError(t, opt.Set(extCA)) + } + assert.Check(t, is.DeepEqual(tc.expected, opt.Value())) + assert.Check(t, is.Equal(tc.expectedString, opt.String())) } }