Skip to content

Commit 6ec1edc

Browse files
ndeloofglours
authored andcommitted
Manage secrets|configs.mode as an octal string||number
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent e345079 commit 6ec1edc

File tree

5 files changed

+104
-54
lines changed

5 files changed

+104
-54
lines changed

loader/full-struct_test.go

+21-21
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func services(workingDir, homeDir string) types.Services {
7272
Target: "my_secret",
7373
UID: "103",
7474
GID: "103",
75-
Mode: uint32Ptr(0o440),
75+
Mode: ptr(types.FileMode(0o440)),
7676
},
7777
},
7878
Tags: []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag", "full_example_project_name:1.0.0"},
@@ -91,7 +91,7 @@ func services(workingDir, homeDir string) types.Services {
9191
Target: "/my_config",
9292
UID: "103",
9393
GID: "103",
94-
Mode: uint32Ptr(0o440),
94+
Mode: ptr(types.FileMode(0o440)),
9595
},
9696
},
9797
ContainerName: "my-web-container",
@@ -101,18 +101,18 @@ func services(workingDir, homeDir string) types.Services {
101101
},
102102
Deploy: &types.DeployConfig{
103103
Mode: "replicated",
104-
Replicas: intPtr(6),
104+
Replicas: ptr(6),
105105
Labels: map[string]string{"FOO": "BAR"},
106106
RollbackConfig: &types.UpdateConfig{
107-
Parallelism: uint64Ptr(3),
107+
Parallelism: ptr(uint64(3)),
108108
Delay: types.Duration(10 * time.Second),
109109
FailureAction: "continue",
110110
Monitor: types.Duration(60 * time.Second),
111111
MaxFailureRatio: 0.3,
112112
Order: "start-first",
113113
},
114114
UpdateConfig: &types.UpdateConfig{
115-
Parallelism: uint64Ptr(3),
115+
Parallelism: ptr(uint64(3)),
116116
Delay: types.Duration(10 * time.Second),
117117
FailureAction: "continue",
118118
Monitor: types.Duration(60 * time.Second),
@@ -145,9 +145,9 @@ func services(workingDir, homeDir string) types.Services {
145145
},
146146
RestartPolicy: &types.RestartPolicy{
147147
Condition: types.RestartPolicyOnFailure,
148-
Delay: durationPtr(5 * time.Second),
149-
MaxAttempts: uint64Ptr(3),
150-
Window: durationPtr(2 * time.Minute),
148+
Delay: ptr(types.Duration(5 * time.Second)),
149+
MaxAttempts: ptr(uint64(3)),
150+
Window: ptr(types.Duration(2 * time.Minute)),
151151
},
152152
Placement: types.Placement{
153153
Constraints: []string{"node=foo"},
@@ -207,11 +207,11 @@ func services(workingDir, homeDir string) types.Services {
207207
},
208208
HealthCheck: &types.HealthCheckConfig{
209209
Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}),
210-
Interval: durationPtr(10 * time.Second),
211-
Timeout: durationPtr(1 * time.Second),
212-
Retries: uint64Ptr(5),
213-
StartPeriod: durationPtr(15 * time.Second),
214-
StartInterval: durationPtr(5 * time.Second),
210+
Interval: ptr(types.Duration(10 * time.Second)),
211+
Timeout: ptr(types.Duration(1 * time.Second)),
212+
Retries: ptr(uint64(5)),
213+
StartPeriod: ptr(types.Duration(15 * time.Second)),
214+
StartInterval: ptr(types.Duration(5 * time.Second)),
215215
},
216216
Hostname: "foo",
217217
Image: "redis",
@@ -418,7 +418,7 @@ func services(workingDir, homeDir string) types.Services {
418418
Target: "my_secret",
419419
UID: "103",
420420
GID: "103",
421-
Mode: uint32Ptr(0o440),
421+
Mode: ptr(types.FileMode(0o440)),
422422
},
423423
},
424424
SecurityOpt: []string{
@@ -428,7 +428,7 @@ func services(workingDir, homeDir string) types.Services {
428428
StdinOpen: true,
429429
StopSignal: "SIGUSR1",
430430
StorageOpt: map[string]string{"size": "20G"},
431-
StopGracePeriod: durationPtr(20 * time.Second),
431+
StopGracePeriod: ptr(types.Duration(20 * time.Second)),
432432
Sysctls: map[string]string{
433433
"net.core.somaxconn": "1024",
434434
"net.ipv4.tcp_syncookies": "0",
@@ -649,7 +649,7 @@ services:
649649
target: my_secret
650650
uid: "103"
651651
gid: "103"
652-
mode: 288
652+
mode: "0440"
653653
tags:
654654
- foo:v1.0.0
655655
- docker.io/username/foo:my-other-tag
@@ -675,7 +675,7 @@ services:
675675
target: /my_config
676676
uid: "103"
677677
gid: "103"
678-
mode: 288
678+
mode: "0440"
679679
container_name: my-web-container
680680
depends_on:
681681
db:
@@ -919,7 +919,7 @@ services:
919919
target: my_secret
920920
uid: "103"
921921
gid: "103"
922-
mode: 288
922+
mode: "0440"
923923
security_opt:
924924
- label=level:s0:c100,c200
925925
- label=type:svirt_apache_t
@@ -1220,7 +1220,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
12201220
"target": "my_secret",
12211221
"uid": "103",
12221222
"gid": "103",
1223-
"mode": 288
1223+
"mode": "0440"
12241224
}
12251225
],
12261226
"tags": [
@@ -1257,7 +1257,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
12571257
"target": "/my_config",
12581258
"uid": "103",
12591259
"gid": "103",
1260-
"mode": 288
1260+
"mode": "0440"
12611261
}
12621262
],
12631263
"container_name": "my-web-container",
@@ -1599,7 +1599,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
15991599
"target": "my_secret",
16001600
"uid": "103",
16011601
"gid": "103",
1602-
"mode": 288
1602+
"mode": "0440"
16031603
}
16041604
],
16051605
"security_opt": [

loader/interpolate.go

-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
)
2828

2929
var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
30-
servicePath("configs", tree.PathMatchList, "mode"): toInt,
3130
servicePath("cpu_count"): toInt64,
3231
servicePath("cpu_percent"): toFloat,
3332
servicePath("cpu_period"): toInt64,
@@ -53,7 +52,6 @@ var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
5352
servicePath("privileged"): toBoolean,
5453
servicePath("read_only"): toBoolean,
5554
servicePath("scale"): toInt,
56-
servicePath("secrets", tree.PathMatchList, "mode"): toInt,
5755
servicePath("stdin_open"): toBoolean,
5856
servicePath("tty"): toBoolean,
5957
servicePath("ulimits", tree.PathMatchAll): toInt,

loader/loader_test.go

+41-24
Original file line numberDiff line numberDiff line change
@@ -699,10 +699,10 @@ services:
699699
web:
700700
configs:
701701
- source: appconfig
702-
mode: $theint
702+
mode: "$theint"
703703
secrets:
704704
- source: super
705-
mode: $theint
705+
mode: "$theint"
706706
healthcheck:
707707
retries: ${theint}
708708
disable: $thebool
@@ -789,32 +789,32 @@ networks:
789789
Configs: []types.ServiceConfigObjConfig{
790790
{
791791
Source: "appconfig",
792-
Mode: uint32Ptr(555),
792+
Mode: ptr(types.FileMode(0o555)),
793793
},
794794
},
795795
Secrets: []types.ServiceSecretConfig{
796796
{
797797
Source: "super",
798798
Target: "/run/secrets/super",
799-
Mode: uint32Ptr(555),
799+
Mode: ptr(types.FileMode(0o555)),
800800
},
801801
},
802802
HealthCheck: &types.HealthCheckConfig{
803-
Retries: uint64Ptr(555),
803+
Retries: ptr(uint64(555)),
804804
Disable: true,
805805
},
806806
Deploy: &types.DeployConfig{
807-
Replicas: intPtr(555),
807+
Replicas: ptr(555),
808808
UpdateConfig: &types.UpdateConfig{
809-
Parallelism: uint64Ptr(555),
809+
Parallelism: ptr(uint64(555)),
810810
MaxFailureRatio: 3.14,
811811
},
812812
RollbackConfig: &types.UpdateConfig{
813-
Parallelism: uint64Ptr(555),
813+
Parallelism: ptr(uint64(555)),
814814
MaxFailureRatio: 3.14,
815815
},
816816
RestartPolicy: &types.RestartPolicy{
817-
MaxAttempts: uint64Ptr(555),
817+
MaxAttempts: ptr(uint64(555)),
818818
},
819819
Placement: types.Placement{
820820
MaxReplicas: 555,
@@ -1122,21 +1122,8 @@ services:
11221122
assert.Equal(t, *foo.Scale, 2)
11231123
}
11241124

1125-
func durationPtr(value time.Duration) *types.Duration {
1126-
result := types.Duration(value)
1127-
return &result
1128-
}
1129-
1130-
func intPtr(value int) *int {
1131-
return &value
1132-
}
1133-
1134-
func uint64Ptr(value uint64) *uint64 {
1135-
return &value
1136-
}
1137-
1138-
func uint32Ptr(value uint32) *uint32 {
1139-
return &value
1125+
func ptr[T any](t T) *T {
1126+
return &t
11401127
}
11411128

11421129
func TestFullExample(t *testing.T) {
@@ -3744,3 +3731,33 @@ services:
37443731
`)
37453732
assert.Check(t, strings.Contains(err.Error(), "'services[test].environment': environment variable DEBUG is declared with a trailing space"))
37463733
}
3734+
3735+
func TestFileModeNumber(t *testing.T) {
3736+
p, err := loadYAML(`
3737+
name: load-file-mode
3738+
services:
3739+
test:
3740+
secrets:
3741+
- source: server-certificate
3742+
target: server.cert
3743+
mode: 0o440
3744+
`)
3745+
assert.NilError(t, err)
3746+
assert.Equal(t, len(p.Services["test"].Secrets), 1)
3747+
assert.Equal(t, *p.Services["test"].Secrets[0].Mode, types.FileMode(0o440))
3748+
}
3749+
3750+
func TestFileModeString(t *testing.T) {
3751+
p, err := loadYAML(`
3752+
name: load-file-mode
3753+
services:
3754+
test:
3755+
secrets:
3756+
- source: server-certificate
3757+
target: server.cert
3758+
mode: "0440"
3759+
`)
3760+
assert.NilError(t, err)
3761+
assert.Equal(t, len(p.Services["test"].Secrets), 1)
3762+
assert.Equal(t, *p.Services["test"].Secrets[0].Mode, types.FileMode(0o440))
3763+
}

types/derived.gen.go

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

types/types.go

+40-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"fmt"
2222
"sort"
23+
"strconv"
2324
"strings"
2425
"time"
2526

@@ -626,17 +627,51 @@ type ServiceVolumeTmpfs struct {
626627
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
627628
}
628629

630+
type FileMode int64
631+
629632
// FileReferenceConfig for a reference to a swarm file object
630633
type FileReferenceConfig struct {
631-
Source string `yaml:"source,omitempty" json:"source,omitempty"`
632-
Target string `yaml:"target,omitempty" json:"target,omitempty"`
633-
UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
634-
GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
635-
Mode *uint32 `yaml:"mode,omitempty" json:"mode,omitempty"`
634+
Source string `yaml:"source,omitempty" json:"source,omitempty"`
635+
Target string `yaml:"target,omitempty" json:"target,omitempty"`
636+
UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
637+
GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
638+
Mode *FileMode `yaml:"mode,omitempty" json:"mode,omitempty"`
636639

637640
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
638641
}
639642

643+
func (f *FileMode) DecodeMapstructure(value interface{}) error {
644+
switch v := value.(type) {
645+
case *FileMode:
646+
return nil
647+
case string:
648+
i, err := strconv.ParseInt(v, 8, 64)
649+
if err != nil {
650+
return err
651+
}
652+
*f = FileMode(i)
653+
case int:
654+
*f = FileMode(v)
655+
default:
656+
return fmt.Errorf("unexpected value type %T for mode", value)
657+
}
658+
return nil
659+
}
660+
661+
// MarshalYAML makes FileMode implement yaml.Marshaller
662+
func (f *FileMode) MarshalYAML() (interface{}, error) {
663+
return f.String(), nil
664+
}
665+
666+
// MarshalJSON makes FileMode implement json.Marshaller
667+
func (f *FileMode) MarshalJSON() ([]byte, error) {
668+
return []byte("\"" + f.String() + "\""), nil
669+
}
670+
671+
func (f *FileMode) String() string {
672+
return fmt.Sprintf("0%o", int64(*f))
673+
}
674+
640675
// ServiceConfigObjConfig is the config obj configuration for a service
641676
type ServiceConfigObjConfig FileReferenceConfig
642677

0 commit comments

Comments
 (0)