| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * 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/http" | 
					
						
							|  |  |  | 	"net/rpc" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | type networkStorage struct { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 	netScheme  string | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	netAddr    string | 
					
						
							|  |  |  | 	netPath    string | 
					
						
							|  |  |  | 	rpcClient  *rpc.Client | 
					
						
							|  |  |  | 	httpClient *http.Client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2016-04-24 15:36:00 +08:00
										 |  |  | 	storageRPCPath = reservedBucket + "/storage" | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | // Converts rpc.ServerError to underlying error. This function is
 | 
					
						
							|  |  |  | // written so that the storageAPI errors are consistent across network
 | 
					
						
							|  |  |  | // disks as well.
 | 
					
						
							|  |  |  | func toStorageErr(err error) error { | 
					
						
							|  |  |  | 	switch err.Error() { | 
					
						
							| 
									
										
										
										
											2016-04-19 17:42:10 +08:00
										 |  |  | 	case errDiskFull.Error(): | 
					
						
							|  |  |  | 		return errDiskFull | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 	case errVolumeNotFound.Error(): | 
					
						
							|  |  |  | 		return errVolumeNotFound | 
					
						
							|  |  |  | 	case errVolumeExists.Error(): | 
					
						
							|  |  |  | 		return errVolumeExists | 
					
						
							|  |  |  | 	case errFileNotFound.Error(): | 
					
						
							|  |  |  | 		return errFileNotFound | 
					
						
							|  |  |  | 	case errIsNotRegular.Error(): | 
					
						
							|  |  |  | 		return errIsNotRegular | 
					
						
							|  |  |  | 	case errVolumeNotEmpty.Error(): | 
					
						
							|  |  |  | 		return errVolumeNotEmpty | 
					
						
							|  |  |  | 	case errFileAccessDenied.Error(): | 
					
						
							|  |  |  | 		return errFileAccessDenied | 
					
						
							|  |  |  | 	case errVolumeAccessDenied.Error(): | 
					
						
							|  |  |  | 		return errVolumeAccessDenied | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:24:10 +08:00
										 |  |  | // Initialize new rpc client.
 | 
					
						
							|  |  |  | func newRPCClient(networkPath string) (StorageAPI, error) { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	// Input validation.
 | 
					
						
							| 
									
										
										
											
												routers: Fix a crash while initializing network fs. (#1382)
Crash happens when 'minio server filename' a file name is
provided instead of a directory on command line argument.
```
panic: runtime error: slice bounds out of range
goroutine 1 [running]:
panic(0x5eb460, 0xc82000e0b0)
	/usr/local/opt/go/libexec/src/runtime/panic.go:464 +0x3e6
main.splitNetPath(0x7fff5fbff9bd, 0x7, 0x0, 0x0, 0x0, 0x0)
	/Users/harsha/mygo/src/github.com/minio/minio/network-fs.go:49 +0xb7
main.newNetworkFS(0x7fff5fbff9bd, 0x7, 0x0, 0x0, 0x0, 0x0)
	/Users/harsha/mygo/src/github.com/minio/minio/network-fs.go:90 +0x20a
main.configureServerHandler(0xc82024e1c8, 0x5, 0xc8200640e0, 0x1, 0x1, 0x0, 0x0)
	/Users/harsha/mygo/src/github.com/minio/minio/routers.go:43 +0x6ce
main.configureServer(0xc82024e1c8, 0x5, 0xc8200640e0, 0x1, 0x1, 0x5)
	/Users/harsha/mygo/src/github.com/minio/minio/server-main.go:86 +0x67
```
											
										 
											2016-04-26 09:10:40 +08:00
										 |  |  | 	if networkPath == "" || strings.LastIndex(networkPath, ":") == -1 { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 		return nil, errInvalidArgument | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO validate netAddr and netPath.
 | 
					
						
							|  |  |  | 	netAddr, netPath := splitNetPath(networkPath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Dial minio rpc storage http path.
 | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 	rpcClient, err := rpc.DialHTTPPath("tcp", netAddr, storageRPCPath) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize http client.
 | 
					
						
							|  |  |  | 	httpClient := &http.Client{ | 
					
						
							|  |  |  | 		// Setting a sensible time out of 6minutes to wait for
 | 
					
						
							|  |  |  | 		// response headers. Request is pro-actively cancelled
 | 
					
						
							|  |  |  | 		// after 6minutes if no response was received from server.
 | 
					
						
							|  |  |  | 		Timeout:   6 * time.Minute, | 
					
						
							|  |  |  | 		Transport: http.DefaultTransport, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize network storage.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | 	ndisk := &networkStorage{ | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		netScheme:  "http", // TODO: fix for ssl rpc support.
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 		netAddr:    netAddr, | 
					
						
							|  |  |  | 		netPath:    netPath, | 
					
						
							|  |  |  | 		rpcClient:  rpcClient, | 
					
						
							|  |  |  | 		httpClient: httpClient, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Returns successfully here.
 | 
					
						
							|  |  |  | 	return ndisk, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MakeVol - make a volume.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) MakeVol(volume string) error { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	reply := GenericReply{} | 
					
						
							|  |  |  | 	if err := n.rpcClient.Call("Storage.MakeVolHandler", volume, &reply); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		return toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ListVols - List all volumes.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) ListVols() (vols []VolInfo, err error) { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	ListVols := ListVolsReply{} | 
					
						
							|  |  |  | 	err = n.rpcClient.Call("Storage.ListVolsHandler", "", &ListVols) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ListVols.Vols, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StatVol - get current Stat volume info.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) StatVol(volume string) (volInfo VolInfo, err error) { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	if err = n.rpcClient.Call("Storage.StatVolHandler", volume, &volInfo); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		return VolInfo{}, toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return volInfo, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteVol - Delete a volume.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) DeleteVol(volume string) error { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	reply := GenericReply{} | 
					
						
							|  |  |  | 	if err := n.rpcClient.Call("Storage.DeleteVolHandler", volume, &reply); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		return toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // File operations.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // CreateFile - create file.
 | 
					
						
							| 
									
										
										
										
											2016-06-20 06:31:13 +08:00
										 |  |  | func (n networkStorage) AppendFile(volume, path string, buffer []byte) (err error) { | 
					
						
							|  |  |  | 	reply := GenericReply{} | 
					
						
							| 
									
										
										
										
											2016-05-29 06:13:15 +08:00
										 |  |  | 	if err = n.rpcClient.Call("Storage.AppendFileHandler", AppendFileArgs{ | 
					
						
							|  |  |  | 		Vol:    volume, | 
					
						
							|  |  |  | 		Path:   path, | 
					
						
							|  |  |  | 		Buffer: buffer, | 
					
						
							| 
									
										
										
										
											2016-06-20 06:31:13 +08:00
										 |  |  | 	}, &reply); err != nil { | 
					
						
							|  |  |  | 		return toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-05-29 06:13:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-06-20 06:31:13 +08:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // StatFile - get latest Stat information for a file at path.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) StatFile(volume, path string) (fileInfo FileInfo, err error) { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	if err = n.rpcClient.Call("Storage.StatFileHandler", StatFileArgs{ | 
					
						
							|  |  |  | 		Vol:  volume, | 
					
						
							|  |  |  | 		Path: path, | 
					
						
							|  |  |  | 	}, &fileInfo); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		return FileInfo{}, toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return fileInfo, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-27 13:05:48 +08:00
										 |  |  | // ReadAll - reads entire contents of the file at path until EOF, returns the
 | 
					
						
							| 
									
										
										
										
											2016-06-26 05:51:06 +08:00
										 |  |  | // contents in a byte slice. Returns buf == nil if err != nil.
 | 
					
						
							|  |  |  | // This API is meant to be used on files which have small memory footprint, do
 | 
					
						
							|  |  |  | // not use this on large files as it would cause server to crash.
 | 
					
						
							|  |  |  | func (n networkStorage) ReadAll(volume, path string) (buf []byte, err error) { | 
					
						
							|  |  |  | 	if err = n.rpcClient.Call("Storage.ReadAllHandler", ReadAllArgs{ | 
					
						
							|  |  |  | 		Vol:  volume, | 
					
						
							|  |  |  | 		Path: path, | 
					
						
							|  |  |  | 	}, &buf); err != nil { | 
					
						
							|  |  |  | 		return nil, toStorageErr(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return buf, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | // ReadFile - reads a file.
 | 
					
						
							| 
									
										
										
										
											2016-05-29 06:13:15 +08:00
										 |  |  | func (n networkStorage) ReadFile(volume string, path string, offset int64, buffer []byte) (m int64, err error) { | 
					
						
							|  |  |  | 	if err = n.rpcClient.Call("Storage.ReadFileHandler", ReadFileArgs{ | 
					
						
							|  |  |  | 		Vol:    volume, | 
					
						
							|  |  |  | 		Path:   path, | 
					
						
							|  |  |  | 		Offset: offset, | 
					
						
							|  |  |  | 		Buffer: buffer, | 
					
						
							|  |  |  | 	}, &m); err != nil { | 
					
						
							|  |  |  | 		return 0, toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-05-29 06:13:15 +08:00
										 |  |  | 	return m, nil | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | // ListDir - list all entries at prefix.
 | 
					
						
							|  |  |  | func (n networkStorage) ListDir(volume, path string) (entries []string, err error) { | 
					
						
							|  |  |  | 	if err = n.rpcClient.Call("Storage.ListDirHandler", ListDirArgs{ | 
					
						
							|  |  |  | 		Vol:  volume, | 
					
						
							|  |  |  | 		Path: path, | 
					
						
							|  |  |  | 	}, &entries); err != nil { | 
					
						
							|  |  |  | 		return nil, toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 	// Return successfully unmarshalled results.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | 	return entries, nil | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // DeleteFile - Delete a file at path.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) DeleteFile(volume, path string) (err error) { | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	reply := GenericReply{} | 
					
						
							|  |  |  | 	if err = n.rpcClient.Call("Storage.DeleteFileHandler", DeleteFileArgs{ | 
					
						
							|  |  |  | 		Vol:  volume, | 
					
						
							|  |  |  | 		Path: path, | 
					
						
							|  |  |  | 	}, &reply); err != nil { | 
					
						
							| 
									
										
										
										
											2016-04-17 03:48:41 +08:00
										 |  |  | 		return toStorageErr(err) | 
					
						
							| 
									
										
										
										
											2016-04-13 03:45:15 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-04-30 03:17:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // RenameFile - Rename file.
 | 
					
						
							| 
									
										
										
										
											2016-05-06 03:51:56 +08:00
										 |  |  | func (n networkStorage) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err error) { | 
					
						
							| 
									
										
										
										
											2016-05-02 18:12:18 +08:00
										 |  |  | 	reply := GenericReply{} | 
					
						
							|  |  |  | 	if err = n.rpcClient.Call("Storage.RenameFileHandler", RenameFileArgs{ | 
					
						
							|  |  |  | 		SrcVol:  srcVolume, | 
					
						
							|  |  |  | 		SrcPath: srcPath, | 
					
						
							|  |  |  | 		DstVol:  dstVolume, | 
					
						
							|  |  |  | 		DstPath: dstPath, | 
					
						
							|  |  |  | 	}, &reply); err != nil { | 
					
						
							|  |  |  | 		return toStorageErr(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-04-30 03:17:48 +08:00
										 |  |  | } |