1
0
mirror of https://github.com/minio/minio.git synced 2025-04-10 06:30:07 -04:00

distributed-XL: Support to run one minio process per export even on the same machine. ()

fixes 
This commit is contained in:
Krishna Srinivas 2016-10-19 01:19:24 +05:30 committed by Harshavardhana
parent 41f9ab1c69
commit 32c3a558e9
29 changed files with 688 additions and 416 deletions

@ -35,7 +35,11 @@ func prepareBenchmarkBackend(instanceType string) (ObjectLayer, []string, error)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
obj, _, err := initObjectLayer(disks, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
return nil, nil, err
}
obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

@ -197,7 +197,7 @@ func testListenBucketNotificationHandler(obj ObjectLayer, instanceType string, t
} }
globalMinioAddr = fmt.Sprintf(":%d", globalMinioPort) globalMinioAddr = fmt.Sprintf(":%d", globalMinioPort)
// initialize the peer client(s) // initialize the peer client(s)
initGlobalS3Peers([]string{}) initGlobalS3Peers([]storageEndPoint{})
invalidBucket := "Invalid\\Bucket" invalidBucket := "Invalid\\Bucket"
noNotificationBucket := "nonotificationbucket" noNotificationBucket := "nonotificationbucket"

@ -256,7 +256,7 @@ func checkDuplicateQueueConfigs(configs []queueConfig) APIErrorCode {
} }
// Check if there are any duplicate counts. // Check if there are any duplicate counts.
if err := checkDuplicates(queueConfigARNS); err != nil { if err := checkDuplicateStrings(queueConfigARNS); err != nil {
errorIf(err, "Invalid queue configs found.") errorIf(err, "Invalid queue configs found.")
return ErrOverlappingConfigs return ErrOverlappingConfigs
} }

@ -73,7 +73,7 @@ func TestControlHealMain(t *testing.T) {
} }
// Remove the object - to simulate the case where the disk was down when the object was created. // Remove the object - to simulate the case where the disk was down when the object was created.
err = os.RemoveAll(path.Join(testServer.Disks[0], bucket, object)) err = os.RemoveAll(path.Join(testServer.Disks[0].path, bucket, object))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -20,10 +20,8 @@ import (
"fmt" "fmt"
"net/rpc" "net/rpc"
"path" "path"
"strings"
router "github.com/gorilla/mux" router "github.com/gorilla/mux"
"github.com/minio/minio-go/pkg/set"
) )
// Routes paths for "minio control" commands. // Routes paths for "minio control" commands.
@ -36,32 +34,26 @@ func initRemoteControlClients(srvCmdConfig serverCmdConfig) []*AuthRPCClient {
if !srvCmdConfig.isDistXL { if !srvCmdConfig.isDistXL {
return nil return nil
} }
var newExports []string
// Initialize auth rpc clients. // Initialize auth rpc clients.
exports := srvCmdConfig.disks
remoteHosts := set.NewStringSet()
var remoteControlClnts []*AuthRPCClient var remoteControlClnts []*AuthRPCClient
for _, export := range exports { localMap := make(map[storageEndPoint]int)
for _, ep := range srvCmdConfig.endPoints {
// Set path to "" so that it is not used for filtering the
// unique entries.
ep.path = ""
// Validates if remote disk is local. // Validates if remote disk is local.
if isLocalStorage(export) { if isLocalStorage(ep) {
continue continue
} }
newExports = append(newExports, export) if localMap[ep] == 1 {
} continue
for _, export := range newExports {
var host string
if idx := strings.LastIndex(export, ":"); idx != -1 {
host = export[:idx]
} }
remoteHosts.Add(fmt.Sprintf("%s:%d", host, globalMinioPort)) localMap[ep]++
}
for host := range remoteHosts {
remoteControlClnts = append(remoteControlClnts, newAuthClient(&authConfig{ remoteControlClnts = append(remoteControlClnts, newAuthClient(&authConfig{
accessKey: serverConfig.GetCredential().AccessKeyID, accessKey: serverConfig.GetCredential().AccessKeyID,
secretKey: serverConfig.GetCredential().SecretAccessKey, secretKey: serverConfig.GetCredential().SecretAccessKey,
secureConn: isSSL(), secureConn: isSSL(),
address: host, address: fmt.Sprintf("%s:%d", ep.host, ep.port),
path: path.Join(reservedBucket, controlPath), path: path.Join(reservedBucket, controlPath),
loginMethod: "Control.LoginHandler", loginMethod: "Control.LoginHandler",
})) }))

@ -41,11 +41,11 @@ func TestInitRemoteControlClients(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"10.1.10.1:/mnt/disk1", {"10.1.10.1", 9000, "/mnt/disk1"},
"10.1.10.1:/mnt/disk2", {"10.1.10.1", 9000, "/mnt/disk2"},
"10.1.10.2:/mnt/disk3", {"10.1.10.2", 9000, "/mnt/disk1"},
"10.1.10.2:/mnt/disk4", {"10.1.10.2", 9000, "/mnt/disk2"},
}, },
}, },
totalClients: 2, totalClients: 2,
@ -54,11 +54,11 @@ func TestInitRemoteControlClients(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"10.1.10.1:/mnt/disk1", {"10.1.10.1", 9000, "/mnt/disk1"},
"10.1.10.2:/mnt/disk2", {"10.1.10.2", 9000, "/mnt/disk2"},
"10.1.10.3:/mnt/disk3", {"10.1.10.3", 9000, "/mnt/disk3"},
"10.1.10.4:/mnt/disk4", {"10.1.10.4", 9000, "/mnt/disk4"},
}, },
}, },
totalClients: 4, totalClients: 4,

@ -222,7 +222,11 @@ func TestErasureReadUtils(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
objLayer, _, err := initObjectLayer(disks, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal(err)
}
objLayer, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
removeRoots(disks) removeRoots(disks)
t.Fatal(err) t.Fatal(err)

@ -35,12 +35,16 @@ func TestInitEventNotifierFaultyDisks(t *testing.T) {
// remove the root folder after the test ends. // remove the root folder after the test ends.
defer removeAll(rootPath) defer removeAll(rootPath)
disk, err := getRandomDisks(1) disks, err := getRandomDisks(1)
if err != nil { if err != nil {
t.Fatal("Unable to create directories for FS backend. ", err) t.Fatal("Unable to create directories for FS backend. ", err)
} }
defer removeAll(disk[0]) defer removeAll(disks[0])
obj, _, err := initObjectLayer(disk, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal(err)
}
obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unable to initialize FS backend.", err) t.Fatal("Unable to initialize FS backend.", err)
} }
@ -85,12 +89,16 @@ func TestInitEventNotifierWithAMQP(t *testing.T) {
// remove the root folder after the test ends. // remove the root folder after the test ends.
defer removeAll(rootPath) defer removeAll(rootPath)
disk, err := getRandomDisks(1) disks, err := getRandomDisks(1)
defer removeAll(disk[0]) defer removeAll(disks[0])
if err != nil { if err != nil {
t.Fatal("Unable to create directories for FS backend. ", err) t.Fatal("Unable to create directories for FS backend. ", err)
} }
fs, _, err := initObjectLayer(disk, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal(err)
}
fs, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unable to initialize FS backend.", err) t.Fatal("Unable to initialize FS backend.", err)
} }
@ -112,12 +120,16 @@ func TestInitEventNotifierWithElasticSearch(t *testing.T) {
// remove the root folder after the test ends. // remove the root folder after the test ends.
defer removeAll(rootPath) defer removeAll(rootPath)
disk, err := getRandomDisks(1) disks, err := getRandomDisks(1)
defer removeAll(disk[0]) defer removeAll(disks[0])
if err != nil { if err != nil {
t.Fatal("Unable to create directories for FS backend. ", err) t.Fatal("Unable to create directories for FS backend. ", err)
} }
fs, _, err := initObjectLayer(disk, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal(err)
}
fs, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unable to initialize FS backend.", err) t.Fatal("Unable to initialize FS backend.", err)
} }
@ -139,12 +151,16 @@ func TestInitEventNotifierWithRedis(t *testing.T) {
// remove the root folder after the test ends. // remove the root folder after the test ends.
defer removeAll(rootPath) defer removeAll(rootPath)
disk, err := getRandomDisks(1) disks, err := getRandomDisks(1)
defer removeAll(disk[0]) defer removeAll(disks[0])
if err != nil { if err != nil {
t.Fatal("Unable to create directories for FS backend. ", err) t.Fatal("Unable to create directories for FS backend. ", err)
} }
fs, _, err := initObjectLayer(disk, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal(err)
}
fs, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unable to initialize FS backend.", err) t.Fatal("Unable to initialize FS backend.", err)
} }
@ -184,7 +200,7 @@ func (s *TestPeerRPCServerData) TearDown() {
s.testServer.Stop() s.testServer.Stop()
_ = removeAll(s.testServer.Root) _ = removeAll(s.testServer.Root)
for _, d := range s.testServer.Disks { for _, d := range s.testServer.Disks {
_ = removeAll(d) _ = removeAll(d.path)
} }
} }

@ -275,8 +275,12 @@ func TestFormatXLHealFreshDisks(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Create an instance of xl backend. // Create an instance of xl backend.
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -307,8 +311,12 @@ func TestFormatXLHealFreshDisksErrorExpected(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Create an instance of xl backend. // Create an instance of xl backend.
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -592,8 +600,12 @@ func TestInitFormatXLErrors(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
defer removeRoots(fsDirs) defer removeRoots(fsDirs)
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Create an instance of xl backend. // Create an instance of xl backend.
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -694,8 +706,12 @@ func TestLoadFormatXLErrs(t *testing.T) {
} }
defer removeRoots(fsDirs) defer removeRoots(fsDirs)
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Create an instance of xl backend. // Create an instance of xl backend.
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -721,7 +737,11 @@ func TestLoadFormatXLErrs(t *testing.T) {
} }
defer removeRoots(fsDirs) defer removeRoots(fsDirs)
obj, _, err = initObjectLayer(fsDirs, nil) endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -745,7 +765,11 @@ func TestLoadFormatXLErrs(t *testing.T) {
} }
defer removeRoots(fsDirs) defer removeRoots(fsDirs)
obj, _, err = initObjectLayer(fsDirs, nil) endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -767,7 +791,11 @@ func TestLoadFormatXLErrs(t *testing.T) {
} }
defer removeRoots(fsDirs) defer removeRoots(fsDirs)
obj, _, err = initObjectLayer(fsDirs, nil) endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -790,8 +818,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Everything is fine, should return nil // Everything is fine, should return nil
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -807,8 +840,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Disks 0..15 are nil // Disks 0..15 are nil
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -826,8 +864,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// One disk returns Faulty Disk // One disk returns Faulty Disk
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -847,8 +890,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// One disk is not found, heal corrupted disks should return nil // One disk is not found, heal corrupted disks should return nil
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -864,8 +912,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Remove format.json of all disks // Remove format.json of all disks
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -885,8 +938,13 @@ func TestHealFormatXLCorruptedDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Corrupted format json in one disk // Corrupted format json in one disk
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -910,8 +968,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Everything is fine, should return nil // Everything is fine, should return nil
obj, _, err := initObjectLayer(fsDirs, nil) obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -926,8 +989,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Disks 0..15 are nil // Disks 0..15 are nil
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -945,8 +1013,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// One disk returns Faulty Disk // One disk returns Faulty Disk
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -966,8 +1039,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// One disk is not found, heal corrupted disks should return nil // One disk is not found, heal corrupted disks should return nil
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -983,8 +1061,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Remove format.json of all disks // Remove format.json of all disks
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1004,8 +1087,13 @@ func TestHealFormatXLFreshDisksErrs(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
endpoints, err = parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal(err)
}
// Remove format.json of all disks // Remove format.json of all disks
obj, _, err = initObjectLayer(fsDirs, nil) obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

@ -68,7 +68,11 @@ func TestHasExtendedHeader(t *testing.T) {
} }
func initFSObjects(disk string, t *testing.T) (obj ObjectLayer) { func initFSObjects(disk string, t *testing.T) (obj ObjectLayer) {
obj, _, err := initObjectLayer([]string{disk}, nil) endpoints, err := parseStorageEndPoints([]string{disk}, 0)
if err != nil {
t.Fatal(err)
}
obj, _, err = initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unexpected err: ", err) t.Fatal("Unexpected err: ", err)
} }

@ -40,12 +40,22 @@ func TestNewFS(t *testing.T) {
disks = append(disks, xlDisk) disks = append(disks, xlDisk)
} }
fsStorageDisks, err := initStorageDisks([]string{disk}, nil) endpoints, err := parseStorageEndPoints([]string{disk}, 0)
if err != nil { if err != nil {
t.Fatal("Uexpected error: ", err) t.Fatal("Uexpected error: ", err)
} }
xlStorageDisks, err := initStorageDisks(disks, nil) fsStorageDisks, err := initStorageDisks(endpoints, nil)
if err != nil {
t.Fatal("Uexpected error: ", err)
}
endpoints, err = parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal("Uexpected error: ", err)
}
xlStorageDisks, err := initStorageDisks(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Uexpected error: ", err) t.Fatal("Uexpected error: ", err)
} }

@ -57,6 +57,8 @@ var (
globalMinioAddr = "" globalMinioAddr = ""
// Minio default port, can be changed through command line. // Minio default port, can be changed through command line.
globalMinioPort = 9000 globalMinioPort = 9000
// Holds the host that was passed using --address
globalMinioHost = ""
// Peer communication struct // Peer communication struct
globalS3Peers = s3Peers{} globalS3Peers = s3Peers{}

@ -21,12 +21,10 @@ import (
"math/rand" "math/rand"
"net/rpc" "net/rpc"
"path" "path"
"strings"
"sync" "sync"
"time" "time"
router "github.com/gorilla/mux" router "github.com/gorilla/mux"
"github.com/minio/minio-go/pkg/set"
) )
const lockRPCPath = "/minio/lock" const lockRPCPath = "/minio/lock"
@ -84,31 +82,19 @@ func registerDistNSLockRouter(mux *router.Router, serverConfig serverCmdConfig)
// Create one lock server for every local storage rpc server. // Create one lock server for every local storage rpc server.
func newLockServers(serverConfig serverCmdConfig) (lockServers []*lockServer) { func newLockServers(serverConfig serverCmdConfig) (lockServers []*lockServer) {
// Initialize posix storage API. for _, ep := range serverConfig.endPoints {
exports := serverConfig.disks if ep.presentIn(serverConfig.ignoredEndPoints) {
ignoredExports := serverConfig.ignoredDisks // Skip initializing ignored end point.
continue
}
// Save ignored disks in a map
// Initialize ignored disks in a new set.
ignoredSet := set.NewStringSet()
if len(ignoredExports) > 0 {
ignoredSet = set.CreateStringSet(ignoredExports...)
}
for _, export := range exports {
if ignoredSet.Contains(export) {
// Ignore initializing ignored export.
continue
}
// Not local storage move to the next node. // Not local storage move to the next node.
if !isLocalStorage(export) { if !isLocalStorage(ep) {
continue continue
} }
if idx := strings.LastIndex(export, ":"); idx != -1 {
export = export[idx+1:]
}
// Create handler for lock RPCs // Create handler for lock RPCs
locker := &lockServer{ locker := &lockServer{
rpcPath: export, rpcPath: ep.path,
mutex: sync.Mutex{}, mutex: sync.Mutex{},
lockMap: make(map[string][]lockRequesterInfo), lockMap: make(map[string][]lockRequesterInfo),
} }

@ -452,11 +452,11 @@ func TestLockServers(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"localhost:/mnt/disk1", {"localhost", 9000, "/mnt/disk1"},
"1.1.1.2:/mnt/disk2", {"1.1.1.2", 9000, "/mnt/disk2"},
"1.1.2.1:/mnt/disk3", {"1.1.2.1", 9000, "/mnt/disk3"},
"1.1.2.2:/mnt/disk4", {"1.1.2.2", 9000, "/mnt/disk4"},
}, },
}, },
totalLockServers: 1, totalLockServers: 1,
@ -465,14 +465,14 @@ func TestLockServers(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"localhost:/mnt/disk1", {"localhost", 9000, "/mnt/disk1"},
"localhost:/mnt/disk2", {"localhost", 9000, "/mnt/disk2"},
"1.1.2.1:/mnt/disk3", {"1.1.2.1", 9000, "/mnt/disk3"},
"1.1.2.2:/mnt/disk4", {"1.1.2.2", 9000, "/mnt/disk4"},
}, },
ignoredDisks: []string{ ignoredEndPoints: []storageEndPoint{
"localhost:/mnt/disk2", {"localhost", 9000, "/mnt/disk2"},
}, },
}, },
totalLockServers: 1, totalLockServers: 1,

@ -21,7 +21,6 @@ import (
pathutil "path" pathutil "path"
"runtime" "runtime"
"strconv" "strconv"
"strings"
"sync" "sync"
"github.com/minio/dsync" "github.com/minio/dsync"
@ -32,27 +31,27 @@ var nsMutex *nsLockMap
// Initialize distributed locking only in case of distributed setup. // Initialize distributed locking only in case of distributed setup.
// Returns if the setup is distributed or not on success. // Returns if the setup is distributed or not on success.
func initDsyncNodes(disks []string, port int) error { func initDsyncNodes(eps []storageEndPoint) error {
serverPort := strconv.Itoa(port)
cred := serverConfig.GetCredential() cred := serverConfig.GetCredential()
// Initialize rpc lock client information only if this instance is a distributed setup. // Initialize rpc lock client information only if this instance is a distributed setup.
var clnts []dsync.RPC var clnts []dsync.RPC
myNode := -1 myNode := -1
for _, disk := range disks { for _, ep := range eps {
if idx := strings.LastIndex(disk, ":"); idx != -1 { if ep.host == "" || ep.port == 0 || ep.path == "" {
clnts = append(clnts, newAuthClient(&authConfig{ return errInvalidArgument
accessKey: cred.AccessKeyID, }
secretKey: cred.SecretAccessKey, clnts = append(clnts, newAuthClient(&authConfig{
// Construct a new dsync server addr. accessKey: cred.AccessKeyID,
secureConn: isSSL(), secretKey: cred.SecretAccessKey,
address: disk[:idx] + ":" + serverPort, // Construct a new dsync server addr.
// Construct a new rpc path for the disk. secureConn: isSSL(),
path: pathutil.Join(lockRPCPath, disk[idx+1:]), address: ep.host + ":" + strconv.Itoa(ep.port),
loginMethod: "Dsync.LoginHandler", // Construct a new rpc path for the endpoint.
})) path: pathutil.Join(lockRPCPath, ep.path),
if isLocalStorage(disk) && myNode == -1 { loginMethod: "Dsync.LoginHandler",
myNode = len(clnts) - 1 }))
} if isLocalStorage(ep) && myNode == -1 {
myNode = len(clnts) - 1
} }
} }
return dsync.SetNodesWithClients(clnts, myNode) return dsync.SetNodesWithClients(clnts, myNode)

@ -565,7 +565,12 @@ func testListObjects(obj ObjectLayer, instanceType string, t TestErrHandler) {
} }
func initFSObjectsB(disk string, t *testing.B) (obj ObjectLayer) { func initFSObjectsB(disk string, t *testing.B) (obj ObjectLayer) {
storageDisks, err := initStorageDisks([]string{disk}, nil) endPoints, err := parseStorageEndPoints([]string{disk}, 0)
if err != nil {
t.Fatal("Unexpected err: ", err)
}
storageDisks, err := initStorageDisks(endPoints, nil)
if err != nil { if err != nil {
t.Fatal("Unexpected err: ", err) t.Fatal("Unexpected err: ", err)
} }

@ -64,7 +64,11 @@ func houseKeeping(storageDisks []StorageAPI) error {
// Initialize all disks in parallel. // Initialize all disks in parallel.
for index, disk := range storageDisks { for index, disk := range storageDisks {
if disk == nil || !isLocalStorage(disk.String()) { if disk == nil {
continue
}
if _, ok := disk.(*networkStorage); ok {
// Skip remote disks.
continue continue
} }
wg.Add(1) wg.Add(1)
@ -100,59 +104,57 @@ func houseKeeping(storageDisks []StorageAPI) error {
} }
// Check if a network path is local to this node. // Check if a network path is local to this node.
func isLocalStorage(networkPath string) bool { func isLocalStorage(ep storageEndPoint) bool {
if idx := strings.LastIndex(networkPath, ":"); idx != -1 { if ep.host == "" {
// e.g 10.0.0.1:/mnt/networkPath return true
netAddr, _, err := splitNetPath(networkPath) }
if err != nil { if globalMinioHost != "" {
errorIf(err, "Splitting into ip and path failed") // if --address host:port was specified for distXL we short circuit only the endPoint
return false // that matches host:port
} if globalMinioHost == ep.host && globalMinioPort == ep.port {
// netAddr will only be set if this is not a local path.
if netAddr == "" {
return true 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(netAddr)
if err != nil {
errorIf(err, "Failed to lookup host")
return false
}
for _, addr := range addrs {
if ip := net.ParseIP(addr); ip.IsLoopback() {
return true
}
}
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 {
return true
}
}
}
return false return false
} }
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(ep.host)
if err != nil {
errorIf(err, "Failed to lookup host")
return false
}
for _, addr := range addrs {
if ip := net.ParseIP(addr); ip.IsLoopback() {
return true
}
}
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 {
return true
}
}
}
return false
} }
// Depending on the disk type network or local, initialize storage API. // Depending on the disk type network or local, initialize storage API.
func newStorageAPI(disk string) (storage StorageAPI, err error) { func newStorageAPI(ep storageEndPoint) (storage StorageAPI, err error) {
if isLocalStorage(disk) { if isLocalStorage(ep) {
return newPosix(disk) return newPosix(ep.path)
} }
return newRPCClient(disk) return newRPCClient(ep)
} }
// Initializes meta volume on all input storage disks. // Initializes meta volume on all input storage disks.

@ -20,7 +20,6 @@ import (
"time" "time"
"github.com/minio/mc/pkg/console" "github.com/minio/mc/pkg/console"
"github.com/minio/minio-go/pkg/set"
) )
// Channel where minioctl heal handler would notify if it were successful. This // Channel where minioctl heal handler would notify if it were successful. This
@ -250,34 +249,35 @@ func retryFormattingDisks(firstDisk bool, firstEndpoint string, storageDisks []S
} }
// Initialize storage disks based on input arguments. // Initialize storage disks based on input arguments.
func initStorageDisks(disks, ignoredDisks []string) ([]StorageAPI, error) { func initStorageDisks(endPoints, ignoredEndPoints []storageEndPoint) ([]StorageAPI, error) {
// Single disk means we will use FS backend. // Single disk means we will use FS backend.
if len(disks) == 1 { if len(endPoints) == 1 {
storage, err := newStorageAPI(disks[0]) storage, err := newStorageAPI(endPoints[0])
if err != nil && err != errDiskNotFound { if err != nil && err != errDiskNotFound {
return nil, err return nil, err
} }
return []StorageAPI{storage}, nil return []StorageAPI{storage}, nil
} // Otherwise proceed with XL setup.
if err := checkSufficientDisks(disks); err != nil {
return nil, err
}
disksSet := set.NewStringSet()
if len(ignoredDisks) > 0 {
disksSet = set.CreateStringSet(ignoredDisks...)
} }
// Otherwise proceed with XL setup.
// Bootstrap disks. // Bootstrap disks.
storageDisks := make([]StorageAPI, len(disks)) storageDisks := make([]StorageAPI, len(endPoints))
for index, disk := range disks { for index, ep := range endPoints {
// Check if disk is ignored. // Check if disk is ignored.
if disksSet.Contains(disk) { ignored := false
for _, iep := range ignoredEndPoints {
if ep == iep {
ignored = true
break
}
}
if ignored {
// Set this situation as disk not found. // Set this situation as disk not found.
storageDisks[index] = nil storageDisks[index] = nil
continue continue
} }
// Intentionally ignore disk not found errors. XL is designed // Intentionally ignore disk not found errors. XL is designed
// to handle these errors internally. // to handle these errors internally.
storage, err := newStorageAPI(disk) storage, err := newStorageAPI(ep)
if err != nil && err != errDiskNotFound { if err != nil && err != errDiskNotFound {
return nil, err return nil, err
} }

@ -23,8 +23,6 @@ import (
"path" "path"
"sync" "sync"
"time" "time"
"github.com/minio/minio-go/pkg/set"
) )
type s3Peers struct { type s3Peers struct {
@ -38,9 +36,9 @@ type s3Peers struct {
peers []string peers []string
} }
func initGlobalS3Peers(disks []string) { func initGlobalS3Peers(eps []storageEndPoint) {
// Get list of de-duplicated peers. // Get list of de-duplicated peers.
peers := getAllPeers(disks) peers := getAllPeers(eps)
// Initialize global state. // Initialize global state.
globalS3Peers = s3Peers{ globalS3Peers = s3Peers{
@ -112,23 +110,10 @@ func (s3p *s3Peers) Close() error {
// returns the network addresses of all Minio servers in the cluster // returns the network addresses of all Minio servers in the cluster
// in `host:port` format. // in `host:port` format.
func getAllPeers(disks []string) []string { func getAllPeers(eps []storageEndPoint) []string {
res := []string{} res := []string{}
// use set to de-duplicate for _, ep := range eps {
sset := set.NewStringSet() res = append(res, fmt.Sprintf("%s:%d", ep.host, ep.port))
for _, disk := range disks {
netAddr, _, err := splitNetPath(disk)
if err != nil || netAddr == "" {
errorIf(err, "Unexpected error - most likely a bug.")
continue
}
if !sset.Contains(netAddr) {
res = append(
res,
fmt.Sprintf("%s:%d", netAddr, globalMinioPort),
)
sset.Add(netAddr)
}
} }
return res return res
} }

@ -17,14 +17,18 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
"os" "os"
"runtime"
"strconv" "strconv"
"strings" "strings"
"time" "time"
"regexp"
"github.com/minio/cli" "github.com/minio/cli"
) )
@ -96,11 +100,118 @@ EXAMPLES:
} }
type serverCmdConfig struct { type serverCmdConfig struct {
serverAddr string serverAddr string
disks []string endPoints []storageEndPoint
ignoredDisks []string ignoredEndPoints []storageEndPoint
isDistXL bool // True only if its distributed XL. isDistXL bool // True only if its distributed XL.
storageDisks []StorageAPI storageDisks []StorageAPI
}
// End point is specified in the command line as host:port:path or host:path or path
// host:port:path or host:path - for distributed XL. Default port is 9000.
// just path - for single node XL or FS.
type storageEndPoint struct {
host string // Will be empty for single node XL and FS
port int // Will be valid for distributed XL
path string // Will be valid for all configs
}
// Returns string form.
func (ep storageEndPoint) String() string {
var str []string
if ep.host != "" {
str = append(str, ep.host)
}
if ep.port != 0 {
str = append(str, strconv.Itoa(ep.port))
}
if ep.path != "" {
str = append(str, ep.path)
}
return strings.Join(str, ":")
}
// Returns if ep is present in the eps list.
func (ep storageEndPoint) presentIn(eps []storageEndPoint) bool {
for _, entry := range eps {
if entry == ep {
return true
}
}
return false
}
// Parse end-point (of the form host:port:path or host:path or path)
func parseStorageEndPoint(ep string, defaultPort int) (storageEndPoint, error) {
if runtime.GOOS == "windows" {
// Try to match path, ex. C:\export
matched, err := regexp.MatchString(`^[a-zA-Z]:\\[^:]+$`, ep)
if err != nil {
return storageEndPoint{}, err
}
if matched {
return storageEndPoint{path: ep}, nil
}
// Try to match host:path ex. 127.0.0.1:C:\export
re, err := regexp.Compile(`^([^:]+):([a-zA-Z]:\\[^:]+)$`)
if err != nil {
return storageEndPoint{}, err
}
result := re.FindStringSubmatch(ep)
if len(result) != 0 {
return storageEndPoint{host: result[1], port: defaultPort, path: result[2]}, nil
}
// Try to match host:port:path ex. 127.0.0.1:443:C:\export
re, err = regexp.Compile(`^([^:]+):([0-9]+):([a-zA-Z]:\\[^:]+)$`)
if err != nil {
return storageEndPoint{}, err
}
result = re.FindStringSubmatch(ep)
if len(result) != 0 {
portInt, err := strconv.Atoi(result[2])
if err != nil {
return storageEndPoint{}, err
}
return storageEndPoint{host: result[1], port: portInt, path: result[3]}, nil
}
return storageEndPoint{}, errors.New("Unable to parse endpoint " + ep)
}
// For *nix OSes
parts := strings.Split(ep, ":")
var parsedep storageEndPoint
switch len(parts) {
case 1:
parsedep = storageEndPoint{path: parts[0]}
case 2:
parsedep = storageEndPoint{host: parts[0], port: defaultPort, path: parts[1]}
case 3:
port, err := strconv.Atoi(parts[1])
if err != nil {
return storageEndPoint{}, err
}
parsedep = storageEndPoint{host: parts[0], port: port, path: parts[2]}
default:
return storageEndPoint{}, errors.New("Unable to parse " + ep)
}
return parsedep, nil
}
// Parse an array of end-points (passed on the command line)
func parseStorageEndPoints(eps []string, defaultPort int) (endpoints []storageEndPoint, err error) {
for _, ep := range eps {
if ep == "" {
continue
}
var endpoint storageEndPoint
endpoint, err = parseStorageEndPoint(ep, defaultPort)
if err != nil {
return nil, err
}
endpoints = append(endpoints, endpoint)
}
return endpoints, nil
} }
// getListenIPs - gets all the ips to listen on. // getListenIPs - gets all the ips to listen on.
@ -194,13 +305,13 @@ func initServerConfig(c *cli.Context) {
} }
// Validate if input disks are sufficient for initializing XL. // Validate if input disks are sufficient for initializing XL.
func checkSufficientDisks(disks []string) error { func checkSufficientDisks(eps []storageEndPoint) error {
// Verify total number of disks. // Verify total number of disks.
totalDisks := len(disks) total := len(eps)
if totalDisks > maxErasureBlocks { if total > maxErasureBlocks {
return errXLMaxDisks return errXLMaxDisks
} }
if totalDisks < minErasureBlocks { if total < minErasureBlocks {
return errXLMinDisks return errXLMinDisks
} }
@ -211,7 +322,7 @@ func checkSufficientDisks(disks []string) error {
// Verify if we have even number of disks. // Verify if we have even number of disks.
// only combination of 4, 6, 8, 10, 12, 14, 16 are supported. // only combination of 4, 6, 8, 10, 12, 14, 16 are supported.
if !isEven(totalDisks) { if !isEven(total) {
return errXLNumDisks return errXLNumDisks
} }
@ -219,36 +330,19 @@ func checkSufficientDisks(disks []string) error {
return nil return nil
} }
// Validates if disks are of supported format, invalid arguments are rejected.
func checkNamingDisks(disks []string) error {
for _, disk := range disks {
_, _, err := splitNetPath(disk)
if err != nil {
return err
}
}
return nil
}
// Validate input disks. // Validate input disks.
func validateDisks(disks []string, ignoredDisks []string) []StorageAPI { func validateDisks(endPoints []storageEndPoint, ignoredEndPoints []storageEndPoint) []StorageAPI {
isXL := len(disks) > 1 isXL := len(endPoints) > 1
if isXL { if isXL {
// Validate if input disks have duplicates in them. // Validate if input disks have duplicates in them.
err := checkDuplicates(disks) err := checkDuplicateEndPoints(endPoints)
fatalIf(err, "Invalid disk arguments for server.") fatalIf(err, "Invalid disk arguments for server.")
// Validate if input disks are sufficient for erasure coded setup. // Validate if input disks are sufficient for erasure coded setup.
err = checkSufficientDisks(disks) err = checkSufficientDisks(endPoints)
fatalIf(err, "Invalid disk arguments for server.")
// Validate if input disks are properly named in accordance with either
// - /mnt/disk1
// - ip:/mnt/disk1
err = checkNamingDisks(disks)
fatalIf(err, "Invalid disk arguments for server.") fatalIf(err, "Invalid disk arguments for server.")
} }
storageDisks, err := initStorageDisks(disks, ignoredDisks) storageDisks, err := initStorageDisks(endPoints, ignoredEndPoints)
fatalIf(err, "Unable to initialize storage disks.") fatalIf(err, "Unable to initialize storage disks.")
return storageDisks return storageDisks
} }
@ -273,10 +367,10 @@ func getPort(address string) int {
} }
// Returns if slice of disks is a distributed setup. // Returns if slice of disks is a distributed setup.
func isDistributedSetup(disks []string) (isDist bool) { func isDistributedSetup(eps []storageEndPoint) (isDist bool) {
// Port to connect to for the lock servers in a distributed setup. // Port to connect to for the lock servers in a distributed setup.
for _, disk := range disks { for _, ep := range eps {
if !isLocalStorage(disk) { if !isLocalStorage(ep) {
// One or more disks supplied as arguments are not // One or more disks supplied as arguments are not
// attached to the local node. // attached to the local node.
isDist = true isDist = true
@ -295,17 +389,25 @@ func serverMain(c *cli.Context) {
serverAddr := c.String("address") serverAddr := c.String("address")
// Check if requested port is available. // Check if requested port is available.
port := getPort(serverAddr) host, portStr, err := net.SplitHostPort(serverAddr)
fatalIf(checkPortAvailability(port), "Port unavailable %d", port) fatalIf(err, "Unable to parse %s.", serverAddr)
// Saves port in a globally accessible value. portInt, err := strconv.Atoi(portStr)
globalMinioPort = port fatalIf(err, "Invalid port number.")
fatalIf(checkPortAvailability(portInt), "Port unavailable %d", portInt)
// Saves host and port in a globally accessible value.
globalMinioPort = portInt
globalMinioHost = host
// Disks to be ignored in server init, to skip format healing. // Disks to be ignored in server init, to skip format healing.
ignoredDisks := strings.Split(c.String("ignore-disks"), ",") ignoredDisks, err := parseStorageEndPoints(strings.Split(c.String("ignore-disks"), ","), portInt)
fatalIf(err, "Unable to parse storage endpoints %s", strings.Split(c.String("ignore-disks"), ","))
// Disks to be used in server init. // Disks to be used in server init.
disks := c.Args() disks, err := parseStorageEndPoints(c.Args(), portInt)
fatalIf(err, "Unable to parse storage endpoints %s", c.Args())
// Initialize server config. // Initialize server config.
initServerConfig(c) initServerConfig(c)
@ -324,11 +426,11 @@ func serverMain(c *cli.Context) {
// Configure server. // Configure server.
srvConfig := serverCmdConfig{ srvConfig := serverCmdConfig{
serverAddr: serverAddr, serverAddr: serverAddr,
disks: disks, endPoints: disks,
ignoredDisks: ignoredDisks, ignoredEndPoints: ignoredDisks,
storageDisks: storageDisks, storageDisks: storageDisks,
isDistXL: isDistributedSetup(disks), isDistXL: isDistributedSetup(disks),
} }
// Configure server. // Configure server.
@ -337,7 +439,7 @@ func serverMain(c *cli.Context) {
// Set nodes for dsync for distributed setup. // Set nodes for dsync for distributed setup.
if srvConfig.isDistXL { if srvConfig.isDistXL {
fatalIf(initDsyncNodes(disks, port), "Unable to initialize distributed locking") fatalIf(initDsyncNodes(disks), "Unable to initialize distributed locking")
} }
// Initialize name space lock. // Initialize name space lock.

@ -18,7 +18,6 @@ package cmd
import ( import (
"flag" "flag"
"net"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -64,23 +63,47 @@ func TestFinalizeEndpoints(t *testing.T) {
// Tests all the expected input disks for function checkSufficientDisks. // Tests all the expected input disks for function checkSufficientDisks.
func TestCheckSufficientDisks(t *testing.T) { func TestCheckSufficientDisks(t *testing.T) {
xlDisks := []string{ var xlDisks []string
"/mnt/backend1", if runtime.GOOS == "windows" {
"/mnt/backend2", xlDisks = []string{
"/mnt/backend3", "C:\\mnt\\backend1",
"/mnt/backend4", "C:\\mnt\\backend2",
"/mnt/backend5", "C:\\mnt\\backend3",
"/mnt/backend6", "C:\\mnt\\backend4",
"/mnt/backend7", "C:\\mnt\\backend5",
"/mnt/backend8", "C:\\mnt\\backend6",
"/mnt/backend9", "C:\\mnt\\backend7",
"/mnt/backend10", "C:\\mnt\\backend8",
"/mnt/backend11", "C:\\mnt\\backend9",
"/mnt/backend12", "C:\\mnt\\backend10",
"/mnt/backend13", "C:\\mnt\\backend11",
"/mnt/backend14", "C:\\mnt\\backend12",
"/mnt/backend15", "C:\\mnt\\backend13",
"/mnt/backend16", "C:\\mnt\\backend14",
"C:\\mnt\\backend15",
"C:\\mnt\\backend16",
"C:\\mnt\\backend17",
}
} else {
xlDisks = []string{
"/mnt/backend1",
"/mnt/backend2",
"/mnt/backend3",
"/mnt/backend4",
"/mnt/backend5",
"/mnt/backend6",
"/mnt/backend7",
"/mnt/backend8",
"/mnt/backend9",
"/mnt/backend10",
"/mnt/backend11",
"/mnt/backend12",
"/mnt/backend13",
"/mnt/backend14",
"/mnt/backend15",
"/mnt/backend16",
"/mnt/backend17",
}
} }
// List of test cases fo sufficient disk verification. // List of test cases fo sufficient disk verification.
testCases := []struct { testCases := []struct {
@ -104,7 +127,7 @@ func TestCheckSufficientDisks(t *testing.T) {
}, },
// Larger than maximum number of disks > 16. // Larger than maximum number of disks > 16.
{ {
append(xlDisks[0:16], "/mnt/unsupported"), xlDisks,
errXLMaxDisks, errXLMaxDisks,
}, },
// Lesser than minimum number of disks < 6. // Lesser than minimum number of disks < 6.
@ -121,47 +144,16 @@ func TestCheckSufficientDisks(t *testing.T) {
// Validates different variations of input disks. // Validates different variations of input disks.
for i, testCase := range testCases { for i, testCase := range testCases {
if checkSufficientDisks(testCase.disks) != testCase.expectedErr { endpoints, err := parseStorageEndPoints(testCase.disks, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
if checkSufficientDisks(endpoints) != testCase.expectedErr {
t.Errorf("Test %d expected to pass for disks %s", i+1, testCase.disks) t.Errorf("Test %d expected to pass for disks %s", i+1, testCase.disks)
} }
} }
} }
func TestCheckNamingDisks(t *testing.T) {
var testCases []struct {
disks []string
err error
}
if runtime.GOOS == "windows" {
testCases = []struct {
disks []string
err error
}{
{[]string{`:C:\\a\\b\\c`}, &net.AddrError{Err: "Missing address in network path", Addr: `:C:\\a\\b\\c`}},
{[]string{`localhost:C:\\mnt\\disk1`, `localhost:C:\\mnt\\disk2`}, nil},
}
} else {
testCases = []struct {
disks []string
err error
}{
{[]string{"localhost:/mnt/disk1", ":/a/b/c"}, &net.AddrError{Err: "Missing address in network path", Addr: ":/a/b/c"}},
{[]string{"localhost:/mnt/disk1", "localhost:/mnt/disk2"}, nil},
}
}
for i, test := range testCases {
err := checkNamingDisks(test.disks)
if test.err != nil {
if err == nil || err.Error() != test.err.Error() {
t.Errorf("Test %d failed with %v but expected error %v", i+1, err, test.err)
}
} else if err != test.err {
t.Errorf("Test %d failed with %v but expected error %v", i+1, err, test.err)
}
}
}
func TestCheckServerSyntax(t *testing.T) { func TestCheckServerSyntax(t *testing.T) {
app := cli.NewApp() app := cli.NewApp()
app.Commands = []cli.Command{serverCmd} app.Commands = []cli.Command{serverCmd}
@ -186,7 +178,11 @@ func TestCheckServerSyntax(t *testing.T) {
t.Errorf("Test %d failed to parse arguments %s", i+1, disks) t.Errorf("Test %d failed to parse arguments %s", i+1, disks)
} }
defer removeRoots(disks) defer removeRoots(disks)
_ = validateDisks(disks, nil) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
_ = validateDisks(endpoints, nil)
} }
} }
@ -268,7 +264,11 @@ func TestIsDistributedSetup(t *testing.T) {
} }
for i, test := range testCases { for i, test := range testCases {
res := isDistributedSetup(test.disks) endpoints, err := parseStorageEndPoints(test.disks, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
res := isDistributedSetup(endpoints)
if res != test.result { if res != test.result {
t.Errorf("Test %d: expected result %t but received %t", i+1, test.result, res) t.Errorf("Test %d: expected result %t but received %t", i+1, test.result, res)
} }

@ -17,12 +17,11 @@
package cmd package cmd
import ( import (
"fmt"
"io" "io"
"net" "net"
"net/rpc" "net/rpc"
"path" "path"
"strconv"
"strings"
"github.com/minio/minio/pkg/disk" "github.com/minio/minio/pkg/disk"
) )
@ -94,21 +93,16 @@ func toStorageErr(err error) error {
} }
// Initialize new rpc client. // Initialize new rpc client.
func newRPCClient(networkPath string) (StorageAPI, error) { func newRPCClient(ep storageEndPoint) (StorageAPI, error) {
// Input validation. // Input validation.
if networkPath == "" || strings.LastIndex(networkPath, ":") == -1 { if ep.host == "" || ep.port == 0 || ep.path == "" {
return nil, errInvalidArgument return nil, errInvalidArgument
} }
// Split network path into its components.
netAddr, netPath, err := splitNetPath(networkPath)
if err != nil {
return nil, err
}
// Dial minio rpc storage http path. // Dial minio rpc storage http path.
rpcPath := path.Join(storageRPCPath, netPath) rpcPath := path.Join(storageRPCPath, ep.path)
rpcAddr := netAddr + ":" + strconv.Itoa(globalMinioPort) rpcAddr := fmt.Sprintf("%s:%d", ep.host, ep.port)
// Initialize rpc client with network address and rpc path. // Initialize rpc client with network address and rpc path.
cred := serverConfig.GetCredential() cred := serverConfig.GetCredential()
rpcClient := newAuthClient(&authConfig{ rpcClient := newAuthClient(&authConfig{
@ -122,8 +116,8 @@ func newRPCClient(networkPath string) (StorageAPI, error) {
// Initialize network storage. // Initialize network storage.
ndisk := &networkStorage{ ndisk := &networkStorage{
netAddr: netAddr, netAddr: ep.host,
netPath: netPath, netPath: ep.path,
rpcClient: rpcClient, rpcClient: rpcClient,
} }

@ -24,8 +24,6 @@ import (
"net" "net"
"net/rpc" "net/rpc"
"runtime" "runtime"
"strconv"
"strings"
"testing" "testing"
) )
@ -144,14 +142,14 @@ type TestRPCStorageSuite struct {
// Starting the Test server with temporary FS backend. // Starting the Test server with temporary FS backend.
func (s *TestRPCStorageSuite) SetUpSuite(c *testing.T) { func (s *TestRPCStorageSuite) SetUpSuite(c *testing.T) {
s.testServer = StartTestStorageRPCServer(c, s.serverType, 1) s.testServer = StartTestStorageRPCServer(c, s.serverType, 1)
splitAddrs := strings.Split(s.testServer.Server.Listener.Addr().String(), ":") listenAddress := s.testServer.Server.Listener.Addr().String()
var err error
globalMinioPort, err = strconv.Atoi(splitAddrs[1])
if err != nil {
c.Fatalf("Unable to convert %s to its integer representation, %s", splitAddrs[1], err)
}
for _, disk := range s.testServer.Disks { for _, disk := range s.testServer.Disks {
storageDisk, err := newRPCClient(splitAddrs[0] + ":" + disk) remoteEndPoint, err := parseStorageEndPoint(listenAddress+":"+disk.path, 0)
if err != nil {
c.Fatalf("Unexpected error %s", err)
}
storageDisk, err := newRPCClient(remoteEndPoint)
if err != nil { if err != nil {
c.Fatal("Unable to initialize RPC client", err) c.Fatal("Unable to initialize RPC client", err)
} }

@ -21,11 +21,9 @@ import (
"io" "io"
"net/rpc" "net/rpc"
"path" "path"
"strings"
"time" "time"
router "github.com/gorilla/mux" router "github.com/gorilla/mux"
"github.com/minio/minio-go/pkg/set"
"github.com/minio/minio/pkg/disk" "github.com/minio/minio/pkg/disk"
) )
@ -220,36 +218,20 @@ func (s *storageServer) TryInitHandler(args *GenericArgs, reply *GenericReply) e
// Initialize new storage rpc. // Initialize new storage rpc.
func newRPCServer(serverConfig serverCmdConfig) (servers []*storageServer, err error) { func newRPCServer(serverConfig serverCmdConfig) (servers []*storageServer, err error) {
// Initialize posix storage API. for _, ep := range serverConfig.endPoints {
exports := serverConfig.disks if ep.presentIn(serverConfig.ignoredEndPoints) {
ignoredExports := serverConfig.ignoredDisks // Do not init ignored end point.
// Initialize ignored disks in a new set.
ignoredSet := set.NewStringSet()
if len(ignoredExports) > 0 {
ignoredSet = set.CreateStringSet(ignoredExports...)
}
for _, export := range exports {
if ignoredSet.Contains(export) {
// Ignore initializing ignored export.
continue continue
} }
// e.g server:/mnt/disk1 // e.g server:/mnt/disk1
if isLocalStorage(export) { if isLocalStorage(ep) {
if idx := strings.LastIndex(export, ":"); idx != -1 { storage, err := newPosix(ep.path)
export = export[idx+1:]
}
var storage StorageAPI
storage, err = newPosix(export)
if err != nil && err != errDiskNotFound { if err != nil && err != errDiskNotFound {
return nil, err return nil, err
} }
if idx := strings.LastIndex(export, ":"); idx != -1 {
export = export[idx+1:]
}
servers = append(servers, &storageServer{ servers = append(servers, &storageServer{
storage: storage, storage: storage,
path: export, path: ep.path,
}) })
} }
} }

@ -61,7 +61,11 @@ func prepareFS() (ObjectLayer, string, error) {
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
obj, _, err := initObjectLayer(fsDirs, nil) endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
return nil, "", err
}
obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
removeRoots(fsDirs) removeRoots(fsDirs)
return nil, "", err return nil, "", err
@ -75,7 +79,11 @@ func prepareXL() (ObjectLayer, []string, error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
obj, _, err := initObjectLayer(fsDirs, nil) endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
return nil, nil, err
}
obj, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
removeRoots(fsDirs) removeRoots(fsDirs)
return nil, nil, err return nil, nil, err
@ -145,7 +153,7 @@ func isSameType(obj1, obj2 interface{}) bool {
// defer s.Stop() // defer s.Stop()
type TestServer struct { type TestServer struct {
Root string Root string
Disks []string Disks []storageEndPoint
AccessKey string AccessKey string
SecretKey string SecretKey string
Server *httptest.Server Server *httptest.Server
@ -174,17 +182,20 @@ func StartTestServer(t TestErrHandler, instanceType string) TestServer {
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
testServer.Root = root testServer.Root = root
testServer.Disks = disks testServer.Disks, err = parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
testServer.AccessKey = credentials.AccessKeyID testServer.AccessKey = credentials.AccessKeyID
testServer.SecretKey = credentials.SecretAccessKey testServer.SecretKey = credentials.SecretAccessKey
objLayer, storageDisks, err := initObjectLayer(disks, nil) objLayer, storageDisks, err := initObjectLayer(testServer.Disks, nil)
if err != nil { if err != nil {
t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
} }
srvCmdCfg := serverCmdConfig{ srvCmdCfg := serverCmdConfig{
disks: disks, endPoints: testServer.Disks,
storageDisks: storageDisks, storageDisks: storageDisks,
} }
httpHandler, err := configureServerHandler( httpHandler, err := configureServerHandler(
@ -214,7 +225,11 @@ func StartTestServer(t TestErrHandler, instanceType string) TestServer {
t.Fatal("Early setup error:", err) t.Fatal("Early setup error:", err)
} }
globalMinioAddr = getLocalAddress(srvCmdCfg) globalMinioAddr = getLocalAddress(srvCmdCfg)
initGlobalS3Peers(disks) endpoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatal("Early setup error:", err)
}
initGlobalS3Peers(endpoints)
return testServer return testServer
} }
@ -236,6 +251,10 @@ func StartTestStorageRPCServer(t TestErrHandler, instanceType string, diskN int)
if err != nil { if err != nil {
t.Fatal("Failed to create disks for the backend") t.Fatal("Failed to create disks for the backend")
} }
endPoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatalf("%s", err)
}
root, err := newTestConfig("us-east-1") root, err := newTestConfig("us-east-1")
if err != nil { if err != nil {
@ -248,13 +267,13 @@ func StartTestStorageRPCServer(t TestErrHandler, instanceType string, diskN int)
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
testRPCServer.Root = root testRPCServer.Root = root
testRPCServer.Disks = disks testRPCServer.Disks = endPoints
testRPCServer.AccessKey = credentials.AccessKeyID testRPCServer.AccessKey = credentials.AccessKeyID
testRPCServer.SecretKey = credentials.SecretAccessKey testRPCServer.SecretKey = credentials.SecretAccessKey
// Run TestServer. // Run TestServer.
testRPCServer.Server = httptest.NewServer(initTestStorageRPCEndPoint(serverCmdConfig{ testRPCServer.Server = httptest.NewServer(initTestStorageRPCEndPoint(serverCmdConfig{
disks: disks, endPoints: endPoints,
})) }))
return testRPCServer return testRPCServer
} }
@ -267,6 +286,10 @@ func StartTestPeersRPCServer(t TestErrHandler, instanceType string) TestServer {
if err != nil { if err != nil {
t.Fatal("Failed to create disks for the backend") t.Fatal("Failed to create disks for the backend")
} }
endPoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatalf("%s", err)
}
root, err := newTestConfig("us-east-1") root, err := newTestConfig("us-east-1")
if err != nil { if err != nil {
@ -279,12 +302,12 @@ func StartTestPeersRPCServer(t TestErrHandler, instanceType string) TestServer {
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
testRPCServer.Root = root testRPCServer.Root = root
testRPCServer.Disks = disks testRPCServer.Disks = endPoints
testRPCServer.AccessKey = credentials.AccessKeyID testRPCServer.AccessKey = credentials.AccessKeyID
testRPCServer.SecretKey = credentials.SecretAccessKey testRPCServer.SecretKey = credentials.SecretAccessKey
// create temporary backend for the test server. // create temporary backend for the test server.
objLayer, storageDisks, err := initObjectLayer(disks, nil) objLayer, storageDisks, err := initObjectLayer(endPoints, nil)
if err != nil { if err != nil {
t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
} }
@ -295,7 +318,7 @@ func StartTestPeersRPCServer(t TestErrHandler, instanceType string) TestServer {
globalObjLayerMutex.Unlock() globalObjLayerMutex.Unlock()
srvCfg := serverCmdConfig{ srvCfg := serverCmdConfig{
disks: disks, endPoints: endPoints,
storageDisks: storageDisks, storageDisks: storageDisks,
} }
@ -335,6 +358,10 @@ func StartTestControlRPCServer(t TestErrHandler, instanceType string) TestServer
if err != nil { if err != nil {
t.Fatal("Failed to create disks for the backend") t.Fatal("Failed to create disks for the backend")
} }
endPoints, err := parseStorageEndPoints(disks, 0)
if err != nil {
t.Fatalf("%s", err)
}
root, err := newTestConfig("us-east-1") root, err := newTestConfig("us-east-1")
if err != nil { if err != nil {
@ -347,12 +374,12 @@ func StartTestControlRPCServer(t TestErrHandler, instanceType string) TestServer
credentials := serverConfig.GetCredential() credentials := serverConfig.GetCredential()
testRPCServer.Root = root testRPCServer.Root = root
testRPCServer.Disks = disks testRPCServer.Disks = endPoints
testRPCServer.AccessKey = credentials.AccessKeyID testRPCServer.AccessKey = credentials.AccessKeyID
testRPCServer.SecretKey = credentials.SecretAccessKey testRPCServer.SecretKey = credentials.SecretAccessKey
// create temporary backend for the test server. // create temporary backend for the test server.
objLayer, storageDisks, err := initObjectLayer(disks, nil) objLayer, storageDisks, err := initObjectLayer(endPoints, nil)
if err != nil { if err != nil {
t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) t.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err)
} }
@ -401,7 +428,7 @@ func newTestConfig(bucketLocation string) (rootPath string, err error) {
func (testServer TestServer) Stop() { func (testServer TestServer) Stop() {
removeAll(testServer.Root) removeAll(testServer.Root)
for _, disk := range testServer.Disks { for _, disk := range testServer.Disks {
removeAll(disk) removeAll(disk.path)
} }
testServer.Server.Close() testServer.Server.Close()
} }
@ -1454,8 +1481,8 @@ func getRandomDisks(N int) ([]string, error) {
} }
// initObjectLayer - Instantiates object layer and returns it. // initObjectLayer - Instantiates object layer and returns it.
func initObjectLayer(disks []string, ignoredDisks []string) (ObjectLayer, []StorageAPI, error) { func initObjectLayer(endPoints []storageEndPoint, ignoredEndPoints []storageEndPoint) (ObjectLayer, []StorageAPI, error) {
storageDisks, err := initStorageDisks(disks, ignoredDisks) storageDisks, err := initStorageDisks(endPoints, ignoredEndPoints)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -1531,7 +1558,12 @@ func prepareXLStorageDisks(t *testing.T) ([]StorageAPI, []string) {
if err != nil { if err != nil {
t.Fatal("Unexpected error: ", err) t.Fatal("Unexpected error: ", err)
} }
_, storageDisks, err := initObjectLayer(fsDirs, nil) endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatal("Unexpected error: ", err)
}
_, storageDisks, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
removeRoots(fsDirs) removeRoots(fsDirs)
t.Fatal("Unable to initialize storage disks", err) t.Fatal("Unable to initialize storage disks", err)
@ -1815,7 +1847,11 @@ func ExecObjectLayerStaleFilesTest(t *testing.T, objTest objTestStaleFilesType)
if err != nil { if err != nil {
t.Fatalf("Initialization of disks for XL setup: %s", err) t.Fatalf("Initialization of disks for XL setup: %s", err)
} }
objLayer, _, err := initObjectLayer(erasureDisks, nil) endpoints, err := parseStorageEndPoints(erasureDisks, 0)
if err != nil {
t.Fatalf("Initialization of disks for XL setup: %s", err)
}
objLayer, _, err := initObjectLayer(endpoints, nil)
if err != nil { if err != nil {
t.Fatalf("Initialization of object layer failed for XL setup: %s", err) t.Fatalf("Initialization of object layer failed for XL setup: %s", err)
} }

@ -163,11 +163,15 @@ func testTreeWalkMarker(t *testing.T, listDir listDirFunc, isLeaf isLeafFunc) {
func TestTreeWalk(t *testing.T) { func TestTreeWalk(t *testing.T) {
fsDir, err := ioutil.TempDir("", "minio-") fsDir, err := ioutil.TempDir("", "minio-")
if err != nil { if err != nil {
t.Errorf("Unable to create tmp directory: %s", err) t.Fatalf("Unable to create tmp directory: %s", err)
} }
disk, err := newStorageAPI(fsDir) endpoint, err := parseStorageEndPoint(fsDir, 0)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Fatalf("Unexpected error %s", err)
}
disk, err := newStorageAPI(endpoint)
if err != nil {
t.Fatalf("Unable to create StorageAPI: %s", err)
} }
var files = []string{ var files = []string{
@ -200,11 +204,15 @@ func TestTreeWalk(t *testing.T) {
func TestTreeWalkTimeout(t *testing.T) { func TestTreeWalkTimeout(t *testing.T) {
fsDir, err := ioutil.TempDir("", "minio-") fsDir, err := ioutil.TempDir("", "minio-")
if err != nil { if err != nil {
t.Errorf("Unable to create tmp directory: %s", err) t.Fatalf("Unable to create tmp directory: %s", err)
} }
disk, err := newStorageAPI(fsDir) endpoint, err := parseStorageEndPoint(fsDir, 0)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Fatalf("Unexpected error %s", err)
}
disk, err := newStorageAPI(endpoint)
if err != nil {
t.Fatalf("Unable to create StorageAPI: %s", err)
} }
var myfiles []string var myfiles []string
// Create maxObjectsList+1 number of entries. // Create maxObjectsList+1 number of entries.
@ -278,12 +286,23 @@ func TestListDir(t *testing.T) {
t.Errorf("Unable to create tmp directory: %s", err) t.Errorf("Unable to create tmp directory: %s", err)
} }
endpoint1, err := parseStorageEndPoint(fsDir1, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
// Create two StorageAPIs disk1 and disk2. // Create two StorageAPIs disk1 and disk2.
disk1, err := newStorageAPI(fsDir1) disk1, err := newStorageAPI(endpoint1)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Errorf("Unable to create StorageAPI: %s", err)
} }
disk2, err := newStorageAPI(fsDir2)
endpoint2, err := parseStorageEndPoint(fsDir2, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
disk2, err := newStorageAPI(endpoint2)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Errorf("Unable to create StorageAPI: %s", err)
} }
@ -348,13 +367,18 @@ func TestRecursiveTreeWalk(t *testing.T) {
// Create a backend directories fsDir1. // Create a backend directories fsDir1.
fsDir1, err := ioutil.TempDir("", "minio-") fsDir1, err := ioutil.TempDir("", "minio-")
if err != nil { if err != nil {
t.Errorf("Unable to create tmp directory: %s", err) t.Fatalf("Unable to create tmp directory: %s", err)
}
endpoint1, err := parseStorageEndPoint(fsDir1, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
} }
// Create two StorageAPIs disk1. // Create two StorageAPIs disk1.
disk1, err := newStorageAPI(fsDir1) disk1, err := newStorageAPI(endpoint1)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Fatalf("Unable to create StorageAPI: %s", err)
} }
// Simple isLeaf check, returns true if there is no trailing "/" // Simple isLeaf check, returns true if there is no trailing "/"
@ -458,8 +482,13 @@ func TestSortedness(t *testing.T) {
t.Errorf("Unable to create tmp directory: %s", err) t.Errorf("Unable to create tmp directory: %s", err)
} }
endpoint1, err := parseStorageEndPoint(fsDir1, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
// Create two StorageAPIs disk1. // Create two StorageAPIs disk1.
disk1, err := newStorageAPI(fsDir1) disk1, err := newStorageAPI(endpoint1)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Errorf("Unable to create StorageAPI: %s", err)
} }
@ -533,8 +562,13 @@ func TestTreeWalkIsEnd(t *testing.T) {
t.Errorf("Unable to create tmp directory: %s", err) t.Errorf("Unable to create tmp directory: %s", err)
} }
endpoint1, err := parseStorageEndPoint(fsDir1, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
// Create two StorageAPIs disk1. // Create two StorageAPIs disk1.
disk1, err := newStorageAPI(fsDir1) disk1, err := newStorageAPI(endpoint1)
if err != nil { if err != nil {
t.Errorf("Unable to create StorageAPI: %s", err) t.Errorf("Unable to create StorageAPI: %s", err)
} }

@ -46,7 +46,7 @@ func cloneHeader(h http.Header) http.Header {
} }
// checkDuplicates - function to validate if there are duplicates in a slice of strings. // checkDuplicates - function to validate if there are duplicates in a slice of strings.
func checkDuplicates(list []string) error { func checkDuplicateStrings(list []string) error {
// Empty lists are not allowed. // Empty lists are not allowed.
if len(list) == 0 { if len(list) == 0 {
return errInvalidArgument return errInvalidArgument
@ -72,6 +72,15 @@ func checkDuplicates(list []string) error {
return nil return nil
} }
// checkDuplicates - function to validate if there are duplicates in a slice of endPoints.
func checkDuplicateEndPoints(list []storageEndPoint) error {
var strs []string
for _, ep := range list {
strs = append(strs, ep.String())
}
return checkDuplicateStrings(strs)
}
// splits network path into its components Address and Path. // splits network path into its components Address and Path.
func splitNetPath(networkPath string) (netAddr, netPath string, err error) { func splitNetPath(networkPath string) (netAddr, netPath string, err error) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
@ -99,14 +108,10 @@ func getLocalAddress(srvCmdConfig serverCmdConfig) string {
if !srvCmdConfig.isDistXL { if !srvCmdConfig.isDistXL {
return srvCmdConfig.serverAddr return srvCmdConfig.serverAddr
} }
for _, export := range srvCmdConfig.disks { for _, ep := range srvCmdConfig.endPoints {
// Validates if remote disk is local. // Validates if remote disk is local.
if isLocalStorage(export) { if isLocalStorage(ep) {
var host string return fmt.Sprintf("%s:%d", ep.host, ep.port)
if idx := strings.LastIndex(export, ":"); idx != -1 {
host = export[:idx]
}
return fmt.Sprintf("%s:%d", host, globalMinioPort)
} }
} }
return "" return ""

@ -89,7 +89,7 @@ func TestCheckDuplicates(t *testing.T) {
// Validate if function runs as expected. // Validate if function runs as expected.
for i, test := range tests { for i, test := range tests {
err := checkDuplicates(test.list) err := checkDuplicateStrings(test.list)
if test.shouldPass && err != test.err { if test.shouldPass && err != test.err {
t.Errorf("Test: %d, Expected %s got %s", i+1, test.err, err) t.Errorf("Test: %d, Expected %s got %s", i+1, test.err, err)
} }
@ -233,11 +233,11 @@ func TestLocalAddress(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"localhost:/mnt/disk1", {"localhost", 9000, "/mnt/disk1"},
"1.1.1.2:/mnt/disk2", {"1.1.1.2", 9000, "/mnt/disk2"},
"1.1.2.1:/mnt/disk3", {"1.1.2.1", 9000, "/mnt/disk3"},
"1.1.2.2:/mnt/disk4", {"1.1.2.2", 9000, "/mnt/disk4"},
}, },
}, },
localAddr: fmt.Sprintf("localhost:%d", globalMinioPort), localAddr: fmt.Sprintf("localhost:%d", globalMinioPort),
@ -247,11 +247,11 @@ func TestLocalAddress(t *testing.T) {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
serverAddr: fmt.Sprintf(":%d", globalMinioPort), serverAddr: fmt.Sprintf(":%d", globalMinioPort),
isDistXL: false, isDistXL: false,
disks: []string{ endPoints: []storageEndPoint{
"/mnt/disk1", {path: "/mnt/disk1"},
"/mnt/disk2", {path: "/mnt/disk2"},
"/mnt/disk3", {path: "/mnt/disk3"},
"/mnt/disk4", {path: "/mnt/disk4"},
}, },
}, },
localAddr: fmt.Sprintf(":%d", globalMinioPort), localAddr: fmt.Sprintf(":%d", globalMinioPort),
@ -260,11 +260,11 @@ func TestLocalAddress(t *testing.T) {
{ {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
isDistXL: true, isDistXL: true,
disks: []string{ endPoints: []storageEndPoint{
"1.1.1.1:/mnt/disk1", {"1.1.1.1", 9000, "/mnt/disk1"},
"1.1.1.2:/mnt/disk2", {"1.1.1.2", 9000, "/mnt/disk2"},
"1.1.2.1:/mnt/disk3", {"1.1.2.1", 9000, "/mnt/disk3"},
"1.1.2.2:/mnt/disk4", {"1.1.2.2", 9000, "/mnt/disk4"},
}, },
}, },
localAddr: "", localAddr: "",
@ -276,11 +276,11 @@ func TestLocalAddress(t *testing.T) {
srvCmdConfig: serverCmdConfig{ srvCmdConfig: serverCmdConfig{
serverAddr: "play.minio.io:9000", serverAddr: "play.minio.io:9000",
isDistXL: false, isDistXL: false,
disks: []string{ endPoints: []storageEndPoint{
"/mnt/disk1", {path: "/mnt/disk1"},
"/mnt/disk2", {path: "/mnt/disk2"},
"/mnt/disk3", {path: "/mnt/disk3"},
"/mnt/disk4", {path: "/mnt/disk4"},
}, },
}, },
localAddr: "play.minio.io:9000", localAddr: "play.minio.io:9000",

@ -51,7 +51,17 @@ func TestStorageInfo(t *testing.T) {
t.Fatalf("Diskinfo total values should be greater 0") t.Fatalf("Diskinfo total values should be greater 0")
} }
storageDisks, err := initStorageDisks(fsDirs, fsDirs[:4]) endpoints, err := parseStorageEndPoints(fsDirs, 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
ignoredEndpoints, err := parseStorageEndPoints(fsDirs[:4], 0)
if err != nil {
t.Fatalf("Unexpected error %s", err)
}
storageDisks, err := initStorageDisks(endpoints, ignoredEndpoints)
if err != nil { if err != nil {
t.Fatal("Unexpected error: ", err) t.Fatal("Unexpected error: ", err)
} }
@ -141,7 +151,12 @@ func TestNewXL(t *testing.T) {
t.Fatalf("Unable to initialize erasure, %s", err) t.Fatalf("Unable to initialize erasure, %s", err)
} }
storageDisks, err := initStorageDisks(erasureDisks, nil) endpoints, err := parseStorageEndPoints(erasureDisks, 0)
if err != nil {
t.Fatalf("Unable to initialize erasure, %s", err)
}
storageDisks, err := initStorageDisks(endpoints, nil)
if err != nil { if err != nil {
t.Fatal("Unexpected error: ", err) t.Fatal("Unexpected error: ", err)
} }
@ -161,7 +176,16 @@ func TestNewXL(t *testing.T) {
t.Fatalf("Unable to initialize erasure, %s", err) t.Fatalf("Unable to initialize erasure, %s", err)
} }
storageDisks, err = initStorageDisks(erasureDisks, erasureDisks[:2]) endpoints, err = parseStorageEndPoints(erasureDisks, 0)
if err != nil {
t.Fatalf("Unable to initialize erasure, %s", err)
}
ignoredEndpoints, err := parseStorageEndPoints(erasureDisks[:2], 0)
if err != nil {
t.Fatalf("Unable to initialize erasure, %s", err)
}
storageDisks, err = initStorageDisks(endpoints, ignoredEndpoints)
if err != nil { if err != nil {
t.Fatal("Unexpected error: ", err) t.Fatal("Unexpected error: ", err)
} }