splitNetPath: Add support for windows paths including volumeNames e.g ip:C:\network\path

This commit is contained in:
awwalker 2016-08-15 14:33:48 -07:00 committed by Harshavardhana
parent 0bce3d6d63
commit 7c7eb1475d
6 changed files with 155 additions and 16 deletions

View File

@ -56,18 +56,21 @@ func fsHouseKeeping(storageDisk StorageAPI) error {
// Check if a network path is local to this node.
func isLocalStorage(networkPath string) bool {
if idx := strings.LastIndex(networkPath, ":"); idx != -1 {
// e.g 10.0.0.1:9000:/mnt/networkPath
netAddr, _ := splitNetPath(networkPath)
var netHost string
var err error
netHost, _, err = net.SplitHostPort(netAddr)
// e.g 10.0.0.1:/mnt/networkPath
netAddr, _, err := splitNetPath(networkPath)
if err != nil {
netHost = netAddr
errorIf(err, "Splitting into ip and path failed")
return false
}
// netAddr will only be set if this is not a local path.
if netAddr == "" {
return true
}
// Resolve host to address to check if the IP is loopback.
// If address resolution fails, assume it's a non-local host.
addrs, err := net.LookupHost(netHost)
addrs, err := net.LookupHost(netAddr)
if err != nil {
errorIf(err, "Failed to lookup host")
return false
}
for _, addr := range addrs {
@ -77,12 +80,14 @@ func isLocalStorage(networkPath string) bool {
}
iaddrs, err := net.InterfaceAddrs()
if err != nil {
errorIf(err, "Unable to list interface addresses")
return false
}
for _, addr := range addrs {
for _, iaddr := range iaddrs {
ip, _, err := net.ParseCIDR(iaddr.String())
if err != nil {
errorIf(err, "Unable to parse CIDR")
return false
}
if ip.String() == addr {

View File

@ -36,14 +36,6 @@ const (
storageRPCPath = reservedBucket + "/storage"
)
// splits network path into its components Address and Path.
func splitNetPath(networkPath string) (netAddr, netPath string) {
index := strings.LastIndex(networkPath, ":")
netAddr = networkPath[:index]
netPath = networkPath[index+1:]
return netAddr, netPath
}
// Converts rpc.ServerError to underlying error. This function is
// written so that the storageAPI errors are consistent across network
// disks as well.
@ -111,7 +103,10 @@ func newRPCClient(networkPath string) (StorageAPI, error) {
}
// TODO validate netAddr and netPath.
netAddr, netPath := splitNetPath(networkPath)
netAddr, netPath, err := splitNetPath(networkPath)
if err != nil {
return nil, err
}
// Dial minio rpc storage http path.
rpcPath := path.Join(storageRPCPath, netPath)

View File

@ -21,9 +21,12 @@ import (
"encoding/xml"
"errors"
"io"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
@ -43,6 +46,28 @@ func cloneHeader(h http.Header) http.Header {
return h2
}
// splits network path into its components Address and Path.
func splitNetPath(networkPath string) (netAddr, netPath string, err error) {
if runtime.GOOS == "windows" {
if volumeName := filepath.VolumeName(networkPath); volumeName != "" {
return "", networkPath, nil
}
}
networkParts := strings.SplitN(networkPath, ":", 2)
switch len(networkParts) {
case 1:
return "", networkPath, nil
case 2:
if networkParts[1] == "" {
return "", "", &net.AddrError{Err: "missing path in network path", Addr: networkPath}
} else if networkParts[0] == "" {
return "", "", &net.AddrError{Err: "missing address in network path", Addr: networkPath}
}
return networkParts[0], networkParts[1], nil
}
return networkParts[0], networkParts[1], nil
}
// xmlDecoder provide decoded value in xml.
func xmlDecoder(body io.Reader, v interface{}, size int64) error {
var lbody io.Reader

View File

@ -43,6 +43,10 @@ func newClient(node, rpcPath string) *RPCClient {
func (rpcClient *RPCClient) Close() error {
rpcClient.Lock()
defer rpcClient.Unlock()
// If rpc client has not connected yet there is nothing to close.
if rpcClient.rpc == nil {
return nil
}
// Reset rpcClient.rpc to allow for subsequent calls to use a new
// (socket) connection.
clnt := rpcClient.rpc

55
utils_nix_test.go Normal file
View File

@ -0,0 +1,55 @@
// +build !windows
/*
* Minio Cloud Storage, (C) 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"net"
"testing"
)
// Test for splitNetPath
func TestSplitNetPath(t *testing.T) {
testCases := []struct {
networkPath string
netAddr string
netPath string
err error
}{
{"10.1.10.1:", "", "", &net.AddrError{Err: "missing path in network path", Addr: "10.1.10.1:"}},
{"10.1.10.1", "", "10.1.10.1", nil},
{"10.1.10.1://", "10.1.10.1", "//", nil},
{"10.1.10.1:/disk/1", "10.1.10.1", "/disk/1", nil},
{"10.1.10.1:\\path\\test", "10.1.10.1", "\\path\\test", nil},
}
for i, test := range testCases {
receivedAddr, receivedPath, receivedErr := splitNetPath(test.networkPath)
if receivedAddr != test.netAddr {
t.Errorf("Test case %d: Expected: %s, Received: %s", i+1, test.netAddr, receivedAddr)
}
if receivedPath != test.netPath {
t.Errorf("Test case %d: Expected: %s, Received: %s", i+1, test.netPath, receivedPath)
}
if test.err != nil {
if receivedErr == nil || receivedErr.Error() != test.err.Error() {
t.Errorf("Test case %d: Expected: %v, Received: %v", i+1, test.err, receivedErr)
}
}
}
}

55
utils_windows_test.go Normal file
View File

@ -0,0 +1,55 @@
// +build windows
/*
* Minio Cloud Storage, (C) 2015 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"net"
"testing"
)
// Test for splitNetPath
func TestSplitNetPath(t *testing.T) {
testCases := []struct {
networkPath string
netAddr string
netPath string
err error
}{
{"10.1.10.1:C:\\path\\test", "10.1.10.1", "C:\\path\\test", nil},
{"10.1.10.1:C:", "10.1.10.1", "C:", nil},
{":C:", "", "", &net.AddrError{Err: "missing address in network path", Addr: ":C:"}},
{"C:\\path\\test", "", "C:\\path\\test", nil},
{"10.1.10.1::C:\\path\\test", "10.1.10.1", ":C:\\path\\test", nil},
}
for i, test := range testCases {
receivedAddr, receivedPath, receivedErr := splitNetPath(test.networkPath)
if receivedAddr != test.netAddr {
t.Errorf("Test case %d: Expected: %s, Received: %s", i+1, test.netAddr, receivedAddr)
}
if receivedPath != test.netPath {
t.Errorf("Test case %d: Expected: %s, Received: %s", i+1, test.netPath, receivedPath)
}
if test.err != nil {
if receivedErr == nil || receivedErr.Error() != test.err.Error() {
t.Errorf("Test case %d: Expected: %v, Received: %v", i+1, test.err, receivedErr)
}
}
}
}