From c93d7c53b77c8e0f27403a7846f5d12b95f17408 Mon Sep 17 00:00:00 2001 From: YanzhaoLi Date: Thu, 30 Aug 2018 16:35:56 +0800 Subject: [PATCH] Fix NFS VolumeStore FQDN not working When docker using a nfs VolumeStore as a volume, the mount action will fail if the nfs-server url is a FQDN. A dotted ip url works well. When the linux syscall mount(source, target, flag, mountOptions) using for nfs mount, its mountOptions should contain 'addr=serverip' and the serverip must be an ip(ps. the url in source is useless). Thus the fix resolve the FQDN and give its mountOptions the 'addr=ip'. The mountOptions is generated as 'addr=host' at CreateMountSpec when creating the endpointVM. The fix choose to do the resolve just before the mounting action. Resolve: #8043 --- lib/tether/ops_linux.go | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/tether/ops_linux.go b/lib/tether/ops_linux.go index 267a7010ce..1b6a4033ef 100644 --- a/lib/tether/ops_linux.go +++ b/lib/tether/ops_linux.go @@ -960,14 +960,33 @@ func (t *BaseOperations) MountTarget(ctx context.Context, source url.URL, target } rawSource.WriteString(source.Path) - // NOTE: by default we are supporting "NOATIME" and it can be configurable later. this must be specfied as a flag. - // Additionally, we must parse out the "ro" option and supply it as a flag as well for this flavor of the mount call. - if err := Sys.Syscall.Mount(rawSource.String(), target, nfsFileSystemType, syscall.MS_NOATIME, mountOptions); err != nil { + if ip := net.ParseIP(source.Hostname()); ip != nil { + // NOTE: by default we are supporting "NOATIME" and it can be configurable later. this must be specfied as a flag. + // Additionally, we must parse out the "ro" option and supply it as a flag as well for this flavor of the mount call. + if err := Sys.Syscall.Mount(rawSource.String(), target, nfsFileSystemType, syscall.MS_NOATIME, mountOptions); err != nil { + log.Errorf("mounting %s on %s failed: %s", source.String(), target, err) + return err + } + return nil + } + + log.Debugf("Looking up host %s", source.Hostname()) + ips, err := net.LookupIP(source.Hostname()) + if err != nil { log.Errorf("mounting %s on %s failed: %s", source.String(), target, err) return err } - - return nil + for _, ip := range ips { + //NOTE: the mountOptions of syscall mount only accept addr=ip; addr=FQDN doesn't work + //We resolve the ip address nearest the mounting action. + //An alternative place is nfs.CreateMountSpec function in /lib/portlayer/storage/nfs/vm.go + mountOptionsFQDN2IP := strings.Replace(mountOptions, source.Hostname(), ip.String(), -1) + if err = Sys.Syscall.Mount(rawSource.String(), target, nfsFileSystemType, syscall.MS_NOATIME, mountOptionsFQDN2IP); err == nil { + return nil + } + } + log.Errorf("mounting %s on %s failed: %s", source.String(), target, err) + return err } // CopyExistingContent copies the underlying files shadowed by a mount on a directory