Skip to content

Commit

Permalink
Manage secrets|configs.mode as an octal string||number
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <[email protected]>
  • Loading branch information
ndeloof committed Feb 13, 2025
1 parent 84b7d5a commit 67bdec0
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 54 deletions.
42 changes: 21 additions & 21 deletions loader/full-struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func services(workingDir, homeDir string) types.Services {
Target: "my_secret",
UID: "103",
GID: "103",
Mode: uint32Ptr(0o440),
Mode: ptr(types.FileMode(0o440)),
},
},
Tags: []string{"foo:v1.0.0", "docker.io/username/foo:my-other-tag", "full_example_project_name:1.0.0"},
Expand All @@ -91,7 +91,7 @@ func services(workingDir, homeDir string) types.Services {
Target: "/my_config",
UID: "103",
GID: "103",
Mode: uint32Ptr(0o440),
Mode: ptr(types.FileMode(0o440)),
},
},
ContainerName: "my-web-container",
Expand All @@ -101,18 +101,18 @@ func services(workingDir, homeDir string) types.Services {
},
Deploy: &types.DeployConfig{
Mode: "replicated",
Replicas: intPtr(6),
Replicas: ptr(6),
Labels: map[string]string{"FOO": "BAR"},
RollbackConfig: &types.UpdateConfig{
Parallelism: uint64Ptr(3),
Parallelism: ptr(uint64(3)),
Delay: types.Duration(10 * time.Second),
FailureAction: "continue",
Monitor: types.Duration(60 * time.Second),
MaxFailureRatio: 0.3,
Order: "start-first",
},
UpdateConfig: &types.UpdateConfig{
Parallelism: uint64Ptr(3),
Parallelism: ptr(uint64(3)),
Delay: types.Duration(10 * time.Second),
FailureAction: "continue",
Monitor: types.Duration(60 * time.Second),
Expand Down Expand Up @@ -145,9 +145,9 @@ func services(workingDir, homeDir string) types.Services {
},
RestartPolicy: &types.RestartPolicy{
Condition: types.RestartPolicyOnFailure,
Delay: durationPtr(5 * time.Second),
MaxAttempts: uint64Ptr(3),
Window: durationPtr(2 * time.Minute),
Delay: ptr(types.Duration(5 * time.Second)),
MaxAttempts: ptr(uint64(3)),
Window: ptr(types.Duration(2 * time.Minute)),
},
Placement: types.Placement{
Constraints: []string{"node=foo"},
Expand Down Expand Up @@ -206,11 +206,11 @@ func services(workingDir, homeDir string) types.Services {
},
HealthCheck: &types.HealthCheckConfig{
Test: types.HealthCheckTest([]string{"CMD-SHELL", "echo \"hello world\""}),
Interval: durationPtr(10 * time.Second),
Timeout: durationPtr(1 * time.Second),
Retries: uint64Ptr(5),
StartPeriod: durationPtr(15 * time.Second),
StartInterval: durationPtr(5 * time.Second),
Interval: ptr(types.Duration(10 * time.Second)),
Timeout: ptr(types.Duration(1 * time.Second)),
Retries: ptr(uint64(5)),
StartPeriod: ptr(types.Duration(15 * time.Second)),
StartInterval: ptr(types.Duration(5 * time.Second)),
},
Hostname: "foo",
Image: "redis",
Expand Down Expand Up @@ -417,7 +417,7 @@ func services(workingDir, homeDir string) types.Services {
Target: "my_secret",
UID: "103",
GID: "103",
Mode: uint32Ptr(0o440),
Mode: ptr(types.FileMode(0o440)),
},
},
SecurityOpt: []string{
Expand All @@ -427,7 +427,7 @@ func services(workingDir, homeDir string) types.Services {
StdinOpen: true,
StopSignal: "SIGUSR1",
StorageOpt: map[string]string{"size": "20G"},
StopGracePeriod: durationPtr(20 * time.Second),
StopGracePeriod: ptr(types.Duration(20 * time.Second)),
Sysctls: map[string]string{
"net.core.somaxconn": "1024",
"net.ipv4.tcp_syncookies": "0",
Expand Down Expand Up @@ -648,7 +648,7 @@ services:
target: my_secret
uid: "103"
gid: "103"
mode: 288
mode: "0440"
tags:
- foo:v1.0.0
- docker.io/username/foo:my-other-tag
Expand All @@ -674,7 +674,7 @@ services:
target: /my_config
uid: "103"
gid: "103"
mode: 288
mode: "0440"
container_name: my-web-container
depends_on:
db:
Expand Down Expand Up @@ -918,7 +918,7 @@ services:
target: my_secret
uid: "103"
gid: "103"
mode: 288
mode: "0440"
security_opt:
- label=level:s0:c100,c200
- label=type:svirt_apache_t
Expand Down Expand Up @@ -1219,7 +1219,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
"target": "my_secret",
"uid": "103",
"gid": "103",
"mode": 288
"mode": "0440"
}
],
"tags": [
Expand Down Expand Up @@ -1256,7 +1256,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
"target": "/my_config",
"uid": "103",
"gid": "103",
"mode": 288
"mode": "0440"
}
],
"container_name": "my-web-container",
Expand Down Expand Up @@ -1598,7 +1598,7 @@ func fullExampleJSON(workingDir, homeDir string) string {
"target": "my_secret",
"uid": "103",
"gid": "103",
"mode": 288
"mode": "0440"
}
],
"security_opt": [
Expand Down
2 changes: 0 additions & 2 deletions loader/interpolate.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
)

var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
servicePath("configs", tree.PathMatchList, "mode"): toInt,
servicePath("cpu_count"): toInt64,
servicePath("cpu_percent"): toFloat,
servicePath("cpu_period"): toInt64,
Expand All @@ -53,7 +52,6 @@ var interpolateTypeCastMapping = map[tree.Path]interp.Cast{
servicePath("privileged"): toBoolean,
servicePath("read_only"): toBoolean,
servicePath("scale"): toInt,
servicePath("secrets", tree.PathMatchList, "mode"): toInt,
servicePath("stdin_open"): toBoolean,
servicePath("tty"): toBoolean,
servicePath("ulimits", tree.PathMatchAll): toInt,
Expand Down
65 changes: 41 additions & 24 deletions loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -745,10 +745,10 @@ services:
web:
configs:
- source: appconfig
mode: $theint
mode: "$theint"
secrets:
- source: super
mode: $theint
mode: "$theint"
healthcheck:
retries: ${theint}
disable: $thebool
Expand Down Expand Up @@ -835,32 +835,32 @@ networks:
Configs: []types.ServiceConfigObjConfig{
{
Source: "appconfig",
Mode: uint32Ptr(555),
Mode: ptr(types.FileMode(0o555)),
},
},
Secrets: []types.ServiceSecretConfig{
{
Source: "super",
Target: "/run/secrets/super",
Mode: uint32Ptr(555),
Mode: ptr(types.FileMode(0o555)),
},
},
HealthCheck: &types.HealthCheckConfig{
Retries: uint64Ptr(555),
Retries: ptr(uint64(555)),
Disable: true,
},
Deploy: &types.DeployConfig{
Replicas: intPtr(555),
Replicas: ptr(555),
UpdateConfig: &types.UpdateConfig{
Parallelism: uint64Ptr(555),
Parallelism: ptr(uint64(555)),
MaxFailureRatio: 3.14,
},
RollbackConfig: &types.UpdateConfig{
Parallelism: uint64Ptr(555),
Parallelism: ptr(uint64(555)),
MaxFailureRatio: 3.14,
},
RestartPolicy: &types.RestartPolicy{
MaxAttempts: uint64Ptr(555),
MaxAttempts: ptr(uint64(555)),
},
Placement: types.Placement{
MaxReplicas: 555,
Expand Down Expand Up @@ -1167,21 +1167,8 @@ services:
assert.Equal(t, *foo.Scale, 2)
}

func durationPtr(value time.Duration) *types.Duration {
result := types.Duration(value)
return &result
}

func intPtr(value int) *int {
return &value
}

func uint64Ptr(value uint64) *uint64 {
return &value
}

func uint32Ptr(value uint32) *uint32 {
return &value
func ptr[T any](t T) *T {
return &t
}

func TestFullExample(t *testing.T) {
Expand Down Expand Up @@ -3750,3 +3737,33 @@ services:
assert.Equal(t, len(p.Services["test"].Gpus), 1)
assert.Equal(t, p.Services["test"].Gpus[0].Count, types.DeviceCount(-1))
}

func TestFileModeNumber(t *testing.T) {
p, err := loadYAML(`
name: load-file-mode
services:
test:
secrets:
- source: server-certificate
target: server.cert
mode: 0o440
`)
assert.NilError(t, err)
assert.Equal(t, len(p.Services["test"].Secrets), 1)
assert.Equal(t, *p.Services["test"].Secrets[0].Mode, types.FileMode(0o440))
}

func TestFileModeString(t *testing.T) {
p, err := loadYAML(`
name: load-file-mode
services:
test:
secrets:
- source: server-certificate
target: server.cert
mode: "0440"
`)
assert.NilError(t, err)
assert.Equal(t, len(p.Services["test"].Secrets), 1)
assert.Equal(t, *p.Services["test"].Secrets[0].Mode, types.FileMode(0o440))
}
5 changes: 3 additions & 2 deletions types/derived.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 40 additions & 5 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"sort"
"strconv"
"strings"

"github.com/docker/go-connections/nat"
Expand Down Expand Up @@ -604,17 +605,51 @@ type ServiceVolumeTmpfs struct {
Extensions Extensions `yaml:"#extensions,inline,omitempty" json:"-"`
}

type FileMode int64

// FileReferenceConfig for a reference to a swarm file object
type FileReferenceConfig struct {
Source string `yaml:"source,omitempty" json:"source,omitempty"`
Target string `yaml:"target,omitempty" json:"target,omitempty"`
UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
Mode *uint32 `yaml:"mode,omitempty" json:"mode,omitempty"`
Source string `yaml:"source,omitempty" json:"source,omitempty"`
Target string `yaml:"target,omitempty" json:"target,omitempty"`
UID string `yaml:"uid,omitempty" json:"uid,omitempty"`
GID string `yaml:"gid,omitempty" json:"gid,omitempty"`
Mode *FileMode `yaml:"mode,omitempty" json:"mode,omitempty"`

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

func (f *FileMode) DecodeMapstructure(value interface{}) error {
switch v := value.(type) {
case *FileMode:
return nil
case string:
i, err := strconv.ParseInt(v, 8, 64)
if err != nil {
return err
}
*f = FileMode(i)
case int:
*f = FileMode(v)
default:
return fmt.Errorf("unexpected value type %T for mode", value)
}
return nil
}

// MarshalYAML makes FileMode implement yaml.Marshaller
func (f *FileMode) MarshalYAML() (interface{}, error) {
return f.String(), nil
}

// MarshalJSON makes FileMode implement json.Marshaller
func (f *FileMode) MarshalJSON() ([]byte, error) {
return []byte("\"" + f.String() + "\""), nil
}

func (f *FileMode) String() string {
return fmt.Sprintf("0%o", int64(*f))
}

// ServiceConfigObjConfig is the config obj configuration for a service
type ServiceConfigObjConfig FileReferenceConfig

Expand Down

0 comments on commit 67bdec0

Please sign in to comment.