-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Expand file tree
/
Copy pathmount_utils.go
More file actions
135 lines (121 loc) · 4.06 KB
/
mount_utils.go
File metadata and controls
135 lines (121 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package opts
import (
"errors"
"fmt"
"strings"
"github.com/moby/moby/api/types/mount"
)
// validateMountOptions performs client-side validation of mount options. Similar
// validation happens on the daemon side, but this validation allows us to
// produce user-friendly errors matching command-line options.
func validateMountOptions(m *mount.Mount) error {
if err := validateExclusiveOptions(m); err != nil {
return err
}
if m.BindOptions != nil {
if m.BindOptions.ReadOnlyNonRecursive && !m.ReadOnly {
return errors.New("option 'bind-recursive=writable' requires 'readonly' to be specified in conjunction")
}
if m.BindOptions.ReadOnlyForceRecursive {
if !m.ReadOnly {
return errors.New("option 'bind-recursive=readonly' requires 'readonly' to be specified in conjunction")
}
if m.BindOptions.Propagation != mount.PropagationRPrivate {
// FIXME(thaJeztah): this is missing daemon-side validation
//
// docker run --rm --mount type=bind,src=/var/run,target=/foo,bind-recursive=readonly,readonly alpine
// # no error
return errors.New("option 'bind-recursive=readonly' requires 'bind-propagation=rprivate' to be specified in conjunction")
}
}
}
return nil
}
// validateExclusiveOptions checks if the given mount config only contains
// options for the given mount-type.
//
// This is the client-side equivalent of [mounts.validateExclusiveOptions] in
// the daemon, but with error-messages matching client-side flags / options.
//
// [mounts.validateExclusiveOptions]: https://github.com/moby/moby/blob/v2.0.0-beta.6/daemon/volume/mounts/validate.go#L31-L50
func validateExclusiveOptions(m *mount.Mount) error {
if m.Type == "" {
return errors.New("type is required")
}
if m.Type != mount.TypeBind && m.BindOptions != nil {
return fmt.Errorf("cannot mix 'bind-*' options with mount type '%s'", m.Type)
}
if m.Type != mount.TypeVolume && m.VolumeOptions != nil {
return fmt.Errorf("cannot mix 'volume-*' options with mount type '%s'", m.Type)
}
if m.Type != mount.TypeImage && m.ImageOptions != nil {
return fmt.Errorf("cannot mix 'image-*' options with mount type '%s'", m.Type)
}
if m.Type != mount.TypeTmpfs && m.TmpfsOptions != nil {
return fmt.Errorf("cannot mix 'tmpfs-*' options with mount type '%s'", m.Type)
}
if m.Type != mount.TypeCluster && m.ClusterOptions != nil {
return fmt.Errorf("cannot mix 'cluster-*' options with mount type '%s'", m.Type)
}
return nil
}
// parseBoolValue returns the boolean value represented by the string. It returns
// true if no value is set.
//
// It is similar to [strconv.ParseBool], but only accepts 1, true, 0, false.
// Any other value returns an error.
func parseBoolValue(key string, val string, hasValue bool) (bool, error) {
if !hasValue {
return true, nil
}
switch val {
case "1", "true":
return true, nil
case "0", "false":
return false, nil
default:
return false, fmt.Errorf(`invalid value for '%s': invalid boolean value (%q): must be one of "true", "1", "false", or "0" (default "true")`, key, val)
}
}
func ensureVolumeOptions(m *mount.Mount) *mount.VolumeOptions {
if m.VolumeOptions == nil {
m.VolumeOptions = &mount.VolumeOptions{}
}
return m.VolumeOptions
}
func ensureVolumeDriver(m *mount.Mount) *mount.Driver {
ensureVolumeOptions(m)
if m.VolumeOptions.DriverConfig == nil {
m.VolumeOptions.DriverConfig = &mount.Driver{}
}
return m.VolumeOptions.DriverConfig
}
func ensureImageOptions(m *mount.Mount) *mount.ImageOptions {
if m.ImageOptions == nil {
m.ImageOptions = &mount.ImageOptions{}
}
return m.ImageOptions
}
func ensureBindOptions(m *mount.Mount) *mount.BindOptions {
if m.BindOptions == nil {
m.BindOptions = &mount.BindOptions{}
}
return m.BindOptions
}
func ensureTmpfsOptions(m *mount.Mount) *mount.TmpfsOptions {
if m.TmpfsOptions == nil {
m.TmpfsOptions = &mount.TmpfsOptions{}
}
return m.TmpfsOptions
}
func setValueOnMap(target map[string]string, keyValue string) map[string]string {
k, v, _ := strings.Cut(keyValue, "=")
if k == "" {
return target
}
if target == nil {
target = map[string]string{}
}
target[k] = v
return target
}