8000 Add support for using Configs as CredentialSpecs in services · docker/cli@6bab2be · GitHub
[go: up one dir, main page]

Skip to content

Commit 6bab2be

Browse files
committed
Add support for using Configs as CredentialSpecs in services
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 05fd2a8 commit 6bab2be

File tree

9 files changed

+196
-70
lines changed

9 files changed

+196
-70
lines changed

cli/command/service/opts.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,12 +331,14 @@ func (c *credentialSpecOpt) Set(value string) error {
331331
c.source = value
332332
c.value = &swarm.CredentialSpec{}
333333
switch {
334+
case strings.HasPrefix(value, "config://"):
335+
c.value.Config = strings.TrimPrefix(value, "config://")
334336
case strings.HasPrefix(value, "file://"):
335337
c.value.File = strings.TrimPrefix(value, "file://")
336338
case strings.HasPrefix(value, "registry://"):
337339
c.value.Registry = strings.TrimPrefix(value, "registry://")
338340
default:
339-
return errors.New("Invalid credential spec - value must be prefixed file:// or registry:// followed by a value")
341+
return errors.New(`invalid credential spec: value must be prefixed with "config://", "file://", or "registry://"`)
340342
}
341343

342344
return nil

cli/command/service/opts_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,61 @@ import (
1414
is "gotest.tools/assert/cmp"
1515
)
1616

17+
func TestCredentialSpecOpt(t *testing.T) {
18+
tests := []struct {
19+
name string
20+
in string
21+
value swarm.CredentialSpec
22+
expectedErr string
23+
}{
24+
{
25+
name: "empty",
26+
in: "",
27+
value: swarm.CredentialSpec{},
28+
expectedErr: `invalid credential spec: value must be prefixed with "config://", "file://", or "registry://"`,
29+
},
30+
{
31+
name: "no-prefix",
32+
in: "noprefix",
33+
value: swarm.CredentialSpec{},
34+
expectedErr: `invalid credential spec: value must be prefixed with "config://", "file://", or "registry://"`,
35+
},
36+
{
37+
name: "config",
38+
in: "config://0bt9dmxjvjiqermk6xrop3ekq",
39+
value: swarm.CredentialSpec{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
40+
},
41+
{
42+
name: "file",
43+
in: "file://somefile.json",
44+
value: swarm.CredentialSpec{File: "somefile.json"},
45+
},
46+
{
47+
name: "registry",
48+
in: "registry://testing",
49+
value: swarm.CredentialSpec{Registry: "testing"},
50+
},
51+
}
52+
53+
for _, tc := range tests {
54+
tc := tc
55+
t.Run(tc.name, func(t *testing.T) {
56+
var cs credentialSpecOpt
57+
58+
err := cs.Set(tc.in)
59+
60+
if tc.expectedErr != "" {
61+
assert.Error(t, err, tc.expectedErr)
62+
} else {
63+
assert.NilError(t, err)
64+
}
65+
66+
assert.Equal(t, cs.String(), tc.in)
67+
assert.DeepEqual(t, cs.Value(), &tc.value)
68+
})
69+
}
70+
}
71+
1772
func TestMemBytesString(t *testing.T) {
1873
var mem opts.MemBytes = 1048576
1974
assert.Check(t, is.Equal("1MiB", mem.String()))

cli/compose/convert/service.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,11 +599,26 @@ func convertDNSConfig(DNS []string, DNSSearch []string) (*swarm.DNSConfig, error
599599
}
600600

601601
func convertCredentialSpec(spec composetypes.CredentialSpecConfig) (*swarm.CredentialSpec, error) {
602-
if spec.File == "" && spec.Registry == "" {
603-
return nil, nil
602+
var o []string
603+
604+
// Config was added in API v1.40
605+
if spec.Config != "" {
606+
o = append(o, `"Config"`)
607+
}
608+
if spec.File != "" {
609+
o = append(o, `"File"`)
604610
}
605-
if spec.File != "" && spec.Registry != "" {
606-
return nil, errors.New("Invalid credential spec - must provide one of `File` or `Registry`")
611+
if spec.Registry != "" {
612+
o = append(o, `"Registry"`)
613+
}
614+
l := len(o)
615+
switch {
616+
case l == 0:
617+
return nil, nil
618+
case l == 2:
619+
return nil, errors.Errorf("invalid credential spec: cannot specify both %s and %s", o[0], o[1])
620+
case l > 2:
621+
return nil, errors.Errorf("invalid credential spec: cannot specify both %s, and %s", strings.Join(o[:l-1], ", "), o[l-1])
607622
}
608623
swarmCredSpec := swarm.CredentialSpec(spec)
609624
return &swarmCredSpec, nil

cli/compose/convert/service_test.go

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -314,30 +314,65 @@ func TestConvertDNSConfigSearch(t *testing.T) {
314314
}
315315

316316
func TestConvertCredentialSpec(t *testing.T) {
317-
swarmSpec, err := convertCredentialSpec(composetypes.CredentialSpecConfig{})
318-
assert.NilError(t, err)
319-
assert.Check(t, is.Nil(swarmSpec))
320-
321-
swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
322-
File: "/foo",
323-
})
324-
assert.NilError(t, err)
325-
assert.Check(t, is.Equal(swarmSpec.File, "/foo"))
326-
assert.Check(t, is.Equal(swarmSpec.Registry, ""))
317+
tests := []struct {
318+
name string
319+
in composetypes.CredentialSpecConfig
320+
out *swarm.CredentialSpec
321+
expectedErr string
322+
}{
323+
{
324+
name: "empty",
325+
},
326+
{
327+
name: "config-and-file",
328+
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json"},
329+
expectedErr: `invalid credential spec: cannot specify both "Config" and "File"`,
330+
},
331+
{
332+
name: "config-and-registry",
333+
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", Registry: "testing"},
334+
expectedErr: `invalid credential spec: cannot specify both "Config" and "Registry"`,
335+
},
336+
{
337+
name: "file-and-registry",
338+
in: composetypes.CredentialSpecConfig{File: "somefile.json", Registry: "testing"},
339+
expectedErr: `invalid credential spec: cannot specify both "File" and "Registry"`,
340+
},
341+
{
342+
name: "config-and-file-and-registry",
343+
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq", File: "somefile.json", Registry: "testing"},
344+
expectedErr: `invalid credential spec: cannot specify both "Config", "File", and "Registry"`,
345+
},
346+
{
347+
name: "config",
348+
in: composetypes.CredentialSpecConfig{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
349+
out: &swarm.CredentialSpec{Config: "0bt9dmxjvjiqermk6xrop3ekq"},
350+
},
351+
{
352+
name: "file",
353+
in: composetypes.CredentialSpecConfig{File: "somefile.json"},
354+
out: &swarm.CredentialSpec{File: "somefile.json"},
355+
},
356+
{
357+
name: "registry",
358+
in: composetypes.CredentialSpecConfig{Registry: "testing"},
359+
out: &swarm.CredentialSpec{Registry: "testing"},
360+
},
361+
}
327362

328-
swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
329-
Registry: "foo",
330-
})
331-
assert.NilError(t, err)
332-
assert.Check(t, is.Equal(swarmSpec.File, ""))
333-
assert.Check(t, is.Equal(swarmSpec.Registry, "foo"))
363+
for _, tc := range tests {
364+
tc := tc
365+
t.Run(tc.name, func(t *testing.T) {
366+
swarmSpec, err := convertCredentialSpec(tc.in)
334367

335-
swarmSpec, err = convertCredentialSpec(composetypes.CredentialSpecConfig{
336-
File: "/asdf",
337-
Registry: "foo",
338-
})
339-
assert.Check(t, is.ErrorContains(err, ""))
340-
assert.Check(t, is.Nil(swarmSpec))
368+
if tc.expectedErr != "" {
369+
assert.Error(t, err, tc.expectedErr)
370+
} else {
371+
assert.NilError(t, err)
372+
}
373+
assert.DeepEqual(t, swarmSpec, tc.out)
374+
})
375+
}
341376
}
342377

343378
func TestConvertUpdateConfigOrder(t *testing.T) {

cli/compose/loader/loader_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,20 @@ configs:
295295
assert.Assert(t, is.Len(actual.Configs, 1))
296296
}
297297

298+
func TestLoadV38(t *testing.T) {
299+
actual, err := loadYAML(`
300+
version: "3.8"
301+
services:
302+
foo:
303+
image: busybox
304+
credential_spec:
305+
config: "0bt9dmxjvjiqermk6xrop3ekq"
306+
`)
307+
assert.NilError(t, err)
308+
assert.Assert(t, is.Len(actual.Services, 1))
309+
assert.Check(t, is.Equal(actual.Services[0].CredentialSpec.Config, "0bt9dmxjvjiqermk6xrop3ekq"))
310+
}
311+
298312
func TestParseAndLoad(t *testing.T) {
299313
actual, err := loadYAML(sampleYAML)
300314
assert.NilError(t, err)

cli/compose/schema/bindata.go

Lines changed: 37 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/compose/schema/data/config_schema_v3.8.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,15 @@
122122
}
123123
},
124124
"container_name": {"type": "string"},
125-
"credential_spec": {"type": "object", "properties": {
126-
"file": {"type": "string"},
127-
"registry": {"type": "string"}
128-
}},
125+
"credential_spec": {
126+
"type": "object",
127+
"properties": {
128+
"config": {"type": "string"},
129+
"file": {"type": "string"},
130+
"registry": {"type": "string"}
131+
},
132+
"additionalProperties": false
133+
},
129134
"depends_on": {"$ref": "#/definitions/list_of_strings"},
130135
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
131136
"dns": {"$ref": "#/definitions/string_or_list"},

cli/compose/schema/schema_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func TestValidateCredentialSpecs(t *testing.T) {
103103
{version: "3.5", expectedErr: "config"},
104104
{version: "3.6", expectedErr: "config"},
105105
{version: "3.7", expectedErr: "config"},
106+
{version: "3.8"},
106107
}
107108

108109
for _, tc := range tests {

cli/compose/types/types.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,7 @@ func (e External) MarshalJSON() ([]byte, error) {
495495

496496
// CredentialSpecConfig for credential spec on Windows
497497
type CredentialSpecConfig struct {
498-
// @TODO Config is not yet in use
499-
Config string `yaml:"-" json:"-"` // Config was added in API v1.40
498+
Config string `yaml:",omitempty" json:"config,omitempty"` // Config was added in API v1.40
500499
File string `yaml:",omitempty" json:"file,omitempty"`
501500
Registry string `yaml:",omitempty" json:"registry,omitempty"`
502501
}

0 commit comments

Comments
 (0)
0