Skip to content

Commit

Permalink
Merge pull request #47191 from vvoland/volume-cifs-resolve-optout-25
Browse files Browse the repository at this point in the history
[25.0 backport] volume/local: Make host resolution backwards compatible
  • Loading branch information
vvoland authored Jan 23, 2024
2 parents e2ab471 + 3de920a commit 6eef840
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 16 deletions.
82 changes: 82 additions & 0 deletions volume/local/local_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package local // import "github.com/docker/docker/volume/local"

import (
"net"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -246,3 +247,84 @@ func TestVolCreateValidation(t *testing.T) {
})
}
}

func TestVolMountOpts(t *testing.T) {
tests := []struct {
name string
opts optsConfig
expectedErr string
expectedDevice, expectedOpts string
}{
{
name: "cifs url with space",
opts: optsConfig{
MountType: "cifs",
MountDevice: "//1.2.3.4/Program Files",
},
expectedDevice: "//1.2.3.4/Program Files",
expectedOpts: "",
},
{
name: "cifs resolve addr",
opts: optsConfig{
MountType: "cifs",
MountDevice: "//example.com/Program Files",
MountOpts: "addr=example.com",
},
expectedDevice: "//example.com/Program Files",
expectedOpts: "addr=1.2.3.4",
},
{
name: "cifs resolve device",
opts: optsConfig{
MountType: "cifs",
MountDevice: "//example.com/Program Files",
},
expectedDevice: "//1.2.3.4/Program Files",
},
{
name: "nfs dont resolve device",
opts: optsConfig{
MountType: "nfs",
MountDevice: "//example.com/Program Files",
},
expectedDevice: "//example.com/Program Files",
},
{
name: "nfs resolve addr",
opts: optsConfig{
MountType: "nfs",
MountDevice: "//example.com/Program Files",
MountOpts: "addr=example.com",
},
expectedDevice: "//example.com/Program Files",
expectedOpts: "addr=1.2.3.4",
},
}

ip1234 := net.ParseIP("1.2.3.4")
resolveIP := func(network, addr string) (*net.IPAddr, error) {
switch addr {
case "example.com":
return &net.IPAddr{IP: ip1234}, nil
}

return nil, &net.DNSError{Err: "no such host", Name: addr, IsNotFound: true}
}

for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
dev, opts, err := getMountOptions(&tc.opts, resolveIP)

if tc.expectedErr != "" {
assert.Check(t, is.ErrorContains(err, tc.expectedErr))
} else {
assert.Check(t, err)
}

assert.Check(t, is.Equal(dev, tc.expectedDevice))
assert.Check(t, is.Equal(opts, tc.expectedOpts))
})
}
}
51 changes: 35 additions & 16 deletions volume/local/local_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,37 +118,56 @@ func (v *localVolume) needsMount() bool {
return false
}

func (v *localVolume) mount() error {
if v.opts.MountDevice == "" {
return fmt.Errorf("missing device in volume options")
func getMountOptions(opts *optsConfig, resolveIP func(string, string) (*net.IPAddr, error)) (mountDevice string, mountOpts string, _ error) {
if opts.MountDevice == "" {
return "", "", fmt.Errorf("missing device in volume options")
}

mountOpts := v.opts.MountOpts
mountDevice := v.opts.MountDevice
mountOpts = opts.MountOpts
mountDevice = opts.MountDevice

switch v.opts.MountType {
case "nfs":
if addrValue := getAddress(v.opts.MountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil {
ipAddr, err := net.ResolveIPAddr("ip", addrValue)
switch opts.MountType {
case "nfs", "cifs":
if addrValue := getAddress(opts.MountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil {
ipAddr, err := resolveIP("ip", addrValue)
if err != nil {
return errors.Wrapf(err, "error resolving passed in network volume address")
return "", "", errors.Wrap(err, "error resolving passed in network volume address")
}
mountOpts = strings.Replace(mountOpts, "addr="+addrValue, "addr="+ipAddr.String(), 1)
break
}

if opts.MountType != "cifs" {
break
}
case "cifs":
deviceURL, err := url.Parse(v.opts.MountDevice)

deviceURL, err := url.Parse(mountDevice)
if err != nil {
return errors.Wrapf(err, "error parsing mount device url")
return "", "", errors.Wrap(err, "error parsing mount device url")
}
if deviceURL.Host != "" && net.ParseIP(deviceURL.Host) == nil {
ipAddr, err := net.ResolveIPAddr("ip", deviceURL.Host)
ipAddr, err := resolveIP("ip", deviceURL.Host)
if err != nil {
return errors.Wrapf(err, "error resolving passed in network volume address")
return "", "", errors.Wrap(err, "error resolving passed in network volume address")
}
deviceURL.Host = ipAddr.String()
mountDevice = deviceURL.String()
dev, err := url.QueryUnescape(deviceURL.String())
if err != nil {
return "", "", fmt.Errorf("failed to unescape device URL: %q", deviceURL)
}
mountDevice = dev
}
}

return mountDevice, mountOpts, nil
}

func (v *localVolume) mount() error {
mountDevice, mountOpts, err := getMountOptions(v.opts, net.ResolveIPAddr)
if err != nil {
return err
}

if err := mount.Mount(mountDevice, v.path, v.opts.MountType, mountOpts); err != nil {
if password := getPassword(v.opts.MountOpts); password != "" {
err = errors.New(strings.Replace(err.Error(), "password="+password, "password=********", 1))
Expand Down

0 comments on commit 6eef840

Please sign in to comment.