Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 28 additions & 10 deletions format/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,29 @@ func ParseVolume(spec string) (types.ServiceVolumeConfig, error) {
return volume, nil
}

if strings.Count(spec, "/dev") == 2 {
parts := strings.Split(spec, ":/dev")
source := parts[0]
target := "/dev" + parts[1]

if err := populateFieldFromBuffer(':', []rune(source), &volume); err != nil {
populateType(&volume)
return volume, fmt.Errorf("invalid spec: %s: %w", spec, err)
}

if err := populateFieldFromBuffer(endOfSpec, []rune(target), &volume); err != nil {
populateType(&volume)
return volume, fmt.Errorf("invalid spec: %s: %w", spec, err)
}

targetParts := strings.Split(target, ":")
if len(targetParts) > 1 {
parseOptions(targetParts[len(targetParts)-1], &volume)
}
populateType(&volume)
return volume, nil
}

var buffer []rune
for _, char := range spec + string(endOfSpec) {
switch {
Expand Down Expand Up @@ -83,6 +106,11 @@ func populateFieldFromBuffer(char rune, buffer []rune, volume *types.ServiceVolu
case char == ':':
return errors.New("too many colons")
}
parseOptions(strBuffer, volume)
return nil
}

func parseOptions(strBuffer string, volume *types.ServiceVolumeConfig) {
for _, option := range strings.Split(strBuffer, ",") {
switch option {
case "ro":
Expand All @@ -98,16 +126,6 @@ func populateFieldFromBuffer(char rune, buffer []rune, volume *types.ServiceVolu
// ignore unknown options
}
}
return nil
}

var Propagations = []string{
types.PropagationRPrivate,
types.PropagationPrivate,
types.PropagationRShared,
types.PropagationShared,
types.PropagationRSlave,
types.PropagationSlave,
}

type setBindOptionFunc func(bind *types.ServiceVolumeBind, option string)
Expand Down
15 changes: 15 additions & 0 deletions format/volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ func TestParseVolumeRelativeBindMountWindows(t *testing.T) {
}
}

func TestParseVolumeWithDeviceWithMultipleColons(t *testing.T) {
volume, err := ParseVolume("/dev/usb-0:1.3:1.0-port0:/dev/usb-0:1.3:1.0-port0")
expected := types.ServiceVolumeConfig{
Type: "bind",
Source: "/dev/usb-0:1.3:1.0-port0",
Target: "/dev/usb-0:1.3:1.0-port0",
Bind: &types.ServiceVolumeBind{
CreateHostPath: true,
Propagation: "",
},
}
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(expected, volume))
}

func TestParseVolumeWithBindOptions(t *testing.T) {
volume, err := ParseVolume("/source:/target:slave")
expected := types.ServiceVolumeConfig{
Expand Down
20 changes: 19 additions & 1 deletion override/uncity.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func init() {
unique["services.*.build.labels"] = keyValueIndexer
unique["services.*.cap_add"] = keyValueIndexer
unique["services.*.cap_drop"] = keyValueIndexer
unique["services.*.devices"] = volumeIndexer
unique["services.*.devices"] = devicesIndexer
unique["services.*.configs"] = mountIndexer("")
unique["services.*.deploy.labels"] = keyValueIndexer
unique["services.*.dns"] = keyValueIndexer
Expand Down Expand Up @@ -139,6 +139,24 @@ func volumeIndexer(y any, p tree.Path) (string, error) {
return "", nil
}

func devicesIndexer(y any, p tree.Path) (string, error) {
switch value := y.(type) {
case map[string]any:
target, ok := value["target"].(string)
if !ok {
return "", fmt.Errorf("service devices %s is missing a mount target", p)
}
return target, nil
case string:
volume, err := format.ParseVolume(value)
if err != nil {
return "", err
}
return volume.Target, nil
}
return "", nil
}

func exposeIndexer(a any, path tree.Path) (string, error) {
switch v := a.(type) {
case string:
Expand Down