2016-06-03 01:09:14 +00:00
package command
2014-03-31 03:57:25 +00:00
import (
2020-09-28 06:00:43 +00:00
"fmt"
2022-03-07 10:00:14 +00:00
"net"
2014-03-31 03:57:25 +00:00
"net/http"
2021-02-01 06:16:52 +00:00
"os"
2022-04-18 07:08:31 +00:00
"runtime"
2022-06-27 04:09:16 +00:00
"sort"
"strings"
2014-03-31 03:57:25 +00:00
"time"
2014-10-26 18:34:55 +00:00
2020-01-29 17:09:55 +00:00
"google.golang.org/grpc/reflection"
2019-06-05 08:30:24 +00:00
2022-07-29 07:17:28 +00:00
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/security"
weed_server "github.com/seaweedfs/seaweedfs/weed/server"
stats_collect "github.com/seaweedfs/seaweedfs/weed/stats"
"github.com/seaweedfs/seaweedfs/weed/util"
2014-03-31 03:57:25 +00:00
)
var (
2021-02-01 06:16:52 +00:00
f FilerOptions
filerStartS3 * bool
filerS3Options S3Options
filerStartWebDav * bool
filerWebDavOptions WebDavOption
2021-03-29 07:01:44 +00:00
filerStartIam * bool
filerIamOptions IamOptions
2014-03-31 03:57:25 +00:00
)
type FilerOptions struct {
2022-03-26 20:33:17 +00:00
masters map [ string ] pb . ServerAddress
2021-09-13 05:47:52 +00:00
mastersString * string
2016-05-25 15:22:31 +00:00
ip * string
2020-04-21 21:21:06 +00:00
bindIp * string
2014-03-31 03:57:25 +00:00
port * int
2021-09-12 09:28:37 +00:00
portGrpc * int
2017-05-28 03:14:22 +00:00
publicPort * int
2022-05-02 04:59:16 +00:00
filerGroup * string
2014-03-31 03:57:25 +00:00
collection * string
defaultReplicaPlacement * string
2015-04-14 06:38:46 +00:00
disableDirListing * bool
2016-08-31 03:32:30 +00:00
maxMB * int
2018-07-07 09:18:47 +00:00
dirListingLimit * int
2018-07-09 09:22:48 +00:00
dataCenter * string
2020-10-21 00:41:39 +00:00
rack * string
2018-08-13 08:20:49 +00:00
enableNotification * bool
2019-03-21 23:00:46 +00:00
disableHttp * bool
2020-03-06 08:49:47 +00:00
cipher * bool
2020-09-24 12:45:39 +00:00
metricsHttpPort * int
2021-01-11 07:14:46 +00:00
saveToFilerLimit * int
2018-12-06 07:24:25 +00:00
defaultLevelDbDirectory * string
2021-03-30 09:10:50 +00:00
concurrentUploadLimitMB * int
2021-07-31 09:00:01 +00:00
debug * bool
2021-07-31 16:18:41 +00:00
debugPort * int
2022-03-07 10:00:14 +00:00
localSocket * string
2022-06-14 16:30:49 +00:00
showUIDirectoryDelete * bool
2022-08-05 08:16:42 +00:00
downloadMaxMBps * int
2023-02-25 17:48:59 +00:00
diskType * string
2014-03-31 03:57:25 +00:00
}
func init ( ) {
cmdFiler . Run = runFiler // break init cycle
2021-09-13 05:47:52 +00:00
f . mastersString = cmdFiler . Flag . String ( "master" , "localhost:9333" , "comma-separated master servers" )
2022-05-02 04:59:16 +00:00
f . filerGroup = cmdFiler . Flag . String ( "filerGroup" , "" , "share metadata with other filers in the same filerGroup" )
2021-02-18 20:15:09 +00:00
f . collection = cmdFiler . Flag . String ( "collection" , "" , "all data will be stored in this default collection" )
2020-04-18 22:17:27 +00:00
f . ip = cmdFiler . Flag . String ( "ip" , util . DetectedHostAddress ( ) , "filer server http listen ip address" )
2022-03-11 22:02:39 +00:00
f . bindIp = cmdFiler . Flag . String ( "ip.bind" , "" , "ip address to bind to. If empty, default to same as -ip option." )
2014-03-31 03:57:25 +00:00
f . port = cmdFiler . Flag . Int ( "port" , 8888 , "filer server http listen port" )
2021-09-20 21:05:59 +00:00
f . portGrpc = cmdFiler . Flag . Int ( "port.grpc" , 0 , "filer server grpc listen port" )
2019-04-12 03:42:55 +00:00
f . publicPort = cmdFiler . Flag . Int ( "port.readonly" , 0 , "readonly port opened to public" )
2020-09-30 16:32:00 +00:00
f . defaultReplicaPlacement = cmdFiler . Flag . String ( "defaultReplicaPlacement" , "" , "default replication type. If not specified, use master setting." )
2015-04-14 06:38:46 +00:00
f . disableDirListing = cmdFiler . Flag . Bool ( "disableDirListing" , false , "turn off directory listing" )
2021-04-01 09:21:59 +00:00
f . maxMB = cmdFiler . Flag . Int ( "maxMB" , 4 , "split files larger than the limit" )
2018-11-25 21:43:26 +00:00
f . dirListingLimit = cmdFiler . Flag . Int ( "dirListLimit" , 100000 , "limit sub dir listing size" )
2020-11-12 05:07:52 +00:00
f . dataCenter = cmdFiler . Flag . String ( "dataCenter" , "" , "prefer to read and write to volumes in this data center" )
2020-10-21 00:41:39 +00:00
f . rack = cmdFiler . Flag . String ( "rack" , "" , "prefer to write to volumes in this rack" )
2019-03-21 23:00:46 +00:00
f . disableHttp = cmdFiler . Flag . Bool ( "disableHttp" , false , "disable http request, only gRpc operations are allowed" )
2020-03-10 05:31:14 +00:00
f . cipher = cmdFiler . Flag . Bool ( "encryptVolumeData" , false , "encrypt data on volume servers" )
2020-09-24 12:45:39 +00:00
f . metricsHttpPort = cmdFiler . Flag . Int ( "metricsPort" , 0 , "Prometheus metrics listen port" )
2021-01-11 07:14:46 +00:00
f . saveToFilerLimit = cmdFiler . Flag . Int ( "saveToFilerLimit" , 0 , "files smaller than this limit will be saved in filer store" )
2020-12-23 01:33:37 +00:00
f . defaultLevelDbDirectory = cmdFiler . Flag . String ( "defaultStoreDir" , "." , "if filer.toml is empty, use an embedded filer store in the directory" )
2021-03-30 09:10:50 +00:00
f . concurrentUploadLimitMB = cmdFiler . Flag . Int ( "concurrentUploadLimitMB" , 128 , "limit total concurrent upload size" )
2021-07-31 16:18:41 +00:00
f . debug = cmdFiler . Flag . Bool ( "debug" , false , "serves runtime profiling data, e.g., http://localhost:<debug.port>/debug/pprof/goroutine?debug=2" )
f . debugPort = cmdFiler . Flag . Int ( "debug.port" , 6060 , "http port for debugging" )
2022-03-07 10:00:14 +00:00
f . localSocket = cmdFiler . Flag . String ( "localSocket" , "" , "default to /tmp/seaweedfs-filer-<port>.sock" )
2022-06-15 03:37:37 +00:00
f . showUIDirectoryDelete = cmdFiler . Flag . Bool ( "ui.deleteDir" , true , "enable filer UI show delete directory button" )
2022-08-05 08:16:42 +00:00
f . downloadMaxMBps = cmdFiler . Flag . Int ( "downloadMaxMBps" , 0 , "download max speed for each download request, in MB per second" )
2023-02-25 17:48:59 +00:00
f . diskType = cmdFiler . Flag . String ( "disk" , "" , "[hdd|ssd|<tag>] hard drive or solid state drive or any tag" )
2020-09-28 06:00:43 +00:00
// start s3 on filer
filerStartS3 = cmdFiler . Flag . Bool ( "s3" , false , "whether to start S3 gateway" )
filerS3Options . port = cmdFiler . Flag . Int ( "s3.port" , 8333 , "s3 server http listen port" )
2023-06-14 06:58:49 +00:00
filerS3Options . portHttps = cmdFiler . Flag . Int ( "s3.port.https" , 0 , "s3 server https listen port" )
2022-05-15 07:43:37 +00:00
filerS3Options . portGrpc = cmdFiler . Flag . Int ( "s3.port.grpc" , 0 , "s3 server grpc listen port" )
2020-10-22 06:23:00 +00:00
filerS3Options . domainName = cmdFiler . Flag . String ( "s3.domainName" , "" , "suffix of the host name in comma separated list, {bucket}.{domainName}" )
2022-08-05 00:35:00 +00:00
filerS3Options . dataCenter = cmdFiler . Flag . String ( "s3.dataCenter" , "" , "prefer to read and write to volumes in this data center" )
2020-09-28 06:00:43 +00:00
filerS3Options . tlsPrivateKey = cmdFiler . Flag . String ( "s3.key.file" , "" , "path to the TLS private key file" )
filerS3Options . tlsCertificate = cmdFiler . Flag . String ( "s3.cert.file" , "" , "path to the TLS certificate file" )
filerS3Options . config = cmdFiler . Flag . String ( "s3.config" , "" , "path to the config file" )
2021-12-07 13:20:52 +00:00
filerS3Options . auditLogConfig = cmdFiler . Flag . String ( "s3.auditLogConfig" , "" , "path to the audit log config file" )
2021-09-27 05:34:14 +00:00
filerS3Options . allowEmptyFolder = cmdFiler . Flag . Bool ( "s3.allowEmptyFolder" , true , "allow empty folders" )
2022-03-30 17:46:13 +00:00
filerS3Options . allowDeleteBucketNotEmpty = cmdFiler . Flag . Bool ( "s3.allowDeleteBucketNotEmpty" , true , "allow recursive deleting all entries along with bucket" )
2023-06-26 23:22:45 +00:00
filerS3Options . localSocket = cmdFiler . Flag . String ( "s3.localSocket" , "" , "default to /tmp/seaweedfs-s3-<port>.sock" )
2021-02-01 06:16:52 +00:00
// start webdav on filer
filerStartWebDav = cmdFiler . Flag . Bool ( "webdav" , false , "whether to start webdav gateway" )
filerWebDavOptions . port = cmdFiler . Flag . Int ( "webdav.port" , 7333 , "webdav server http listen port" )
filerWebDavOptions . collection = cmdFiler . Flag . String ( "webdav.collection" , "" , "collection to create the files" )
2021-02-18 20:15:09 +00:00
filerWebDavOptions . replication = cmdFiler . Flag . String ( "webdav.replication" , "" , "replication to create the files" )
2021-02-22 10:03:12 +00:00
filerWebDavOptions . disk = cmdFiler . Flag . String ( "webdav.disk" , "" , "[hdd|ssd|<tag>] hard drive or solid state drive or any tag" )
2021-02-01 06:16:52 +00:00
filerWebDavOptions . tlsPrivateKey = cmdFiler . Flag . String ( "webdav.key.file" , "" , "path to the TLS private key file" )
filerWebDavOptions . tlsCertificate = cmdFiler . Flag . String ( "webdav.cert.file" , "" , "path to the TLS certificate file" )
filerWebDavOptions . cacheDir = cmdFiler . Flag . String ( "webdav.cacheDir" , os . TempDir ( ) , "local cache directory for file chunks" )
2022-02-15 04:42:33 +00:00
filerWebDavOptions . cacheSizeMB = cmdFiler . Flag . Int64 ( "webdav.cacheCapacityMB" , 0 , "local cache capacity in MB" )
2023-01-09 02:03:22 +00:00
filerWebDavOptions . filerRootPath = cmdFiler . Flag . String ( "webdav.filer.path" , "/" , "use this remote path from filer server" )
2021-03-29 07:01:44 +00:00
// start iam on filer
filerStartIam = cmdFiler . Flag . Bool ( "iam" , false , "whether to start IAM service" )
2022-03-23 09:30:46 +00:00
filerIamOptions . ip = cmdFiler . Flag . String ( "iam.ip" , * f . ip , "iam server http listen ip address" )
2021-03-29 07:01:44 +00:00
filerIamOptions . port = cmdFiler . Flag . Int ( "iam.port" , 8111 , "iam server http listen port" )
2014-03-31 03:57:25 +00:00
}
2022-06-27 04:09:16 +00:00
func filerLongDesc ( ) string {
desc := ` start a file server which accepts REST operation for any files .
2015-01-06 07:03:27 +00:00
2014-03-31 03:57:25 +00:00
//create or overwrite the file, the directories /path/to will be automatically created
POST / path / to / file
//get the file content
GET / path / to / file
//create or overwrite the file, the filename in the multipart request will be used
POST / path / to /
//return a json format subdirectory and files listing
GET / path / to /
2015-01-06 07:03:27 +00:00
2020-12-08 00:46:48 +00:00
The configuration file "filer.toml" is read from "." , "$HOME/.seaweedfs/" , "/usr/local/etc/seaweedfs/" , or "/etc/seaweedfs/" , in that order .
2021-04-07 20:47:23 +00:00
If the "filer.toml" is not found , an embedded filer store will be created under "-defaultStoreDir" .
2015-01-06 07:03:27 +00:00
2019-02-10 05:07:12 +00:00
The example filer . toml configuration file can be generated by "weed scaffold -config=filer"
2014-03-31 03:57:25 +00:00
2022-06-27 04:09:16 +00:00
Supported Filer Stores :
`
storeNames := make ( [ ] string , len ( filer . Stores ) )
for i , store := range filer . Stores {
storeNames [ i ] = "\t" + store . GetName ( )
}
sort . Strings ( storeNames )
storeList := strings . Join ( storeNames , "\n" )
return desc + storeList
}
var cmdFiler = & Command {
UsageLine : "filer -port=8888 -master=<ip:port>[,<ip:port>]*" ,
Short : "start a file server that points to a master server, or a list of master servers" ,
Long : filerLongDesc ( ) ,
2014-03-31 03:57:25 +00:00
}
func runFiler ( cmd * Command , args [ ] string ) bool {
2021-07-31 09:00:01 +00:00
if * f . debug {
2021-07-31 16:18:41 +00:00
go http . ListenAndServe ( fmt . Sprintf ( ":%d" , * f . debugPort ) , nil )
2021-07-31 09:00:01 +00:00
}
2014-12-14 08:20:21 +00:00
2019-06-05 08:30:24 +00:00
util . LoadConfiguration ( "security" , false )
2019-02-18 20:11:52 +00:00
2022-11-24 18:22:59 +00:00
go stats_collect . StartMetricsServer ( * f . bindIp , * f . metricsHttpPort )
2020-09-24 17:21:23 +00:00
2021-09-07 23:43:54 +00:00
filerAddress := util . JoinHostPort ( * f . ip , * f . port )
2021-03-29 07:01:44 +00:00
startDelay := time . Duration ( 2 )
2020-09-28 06:00:43 +00:00
if * filerStartS3 {
filerS3Options . filer = & filerAddress
2021-12-17 19:34:37 +00:00
filerS3Options . bindIp = f . bindIp
2022-03-07 10:00:14 +00:00
filerS3Options . localFilerSocket = f . localSocket
2022-08-05 00:35:00 +00:00
if * f . dataCenter != "" && * filerS3Options . dataCenter == "" {
filerS3Options . dataCenter = f . dataCenter
}
2022-08-30 07:02:09 +00:00
go func ( delay time . Duration ) {
time . Sleep ( delay * time . Second )
2020-09-28 06:00:43 +00:00
filerS3Options . startS3Server ( )
2022-08-30 07:02:09 +00:00
} ( startDelay )
2021-03-29 07:01:44 +00:00
startDelay ++
2020-09-28 06:00:43 +00:00
}
2021-02-01 06:16:52 +00:00
if * filerStartWebDav {
filerWebDavOptions . filer = & filerAddress
2023-02-25 17:48:59 +00:00
if * filerWebDavOptions . disk == "" {
filerWebDavOptions . disk = f . diskType
}
2022-08-30 07:02:09 +00:00
go func ( delay time . Duration ) {
time . Sleep ( delay * time . Second )
2021-02-01 06:16:52 +00:00
filerWebDavOptions . startWebDav ( )
2022-08-30 07:02:09 +00:00
} ( startDelay )
2021-03-29 07:01:44 +00:00
startDelay ++
}
if * filerStartIam {
filerIamOptions . filer = & filerAddress
2021-09-13 05:47:52 +00:00
filerIamOptions . masters = f . mastersString
2022-08-30 07:02:09 +00:00
go func ( delay time . Duration ) {
time . Sleep ( delay * time . Second )
2021-03-29 07:01:44 +00:00
filerIamOptions . startIamServer ( )
2022-08-30 07:02:09 +00:00
} ( startDelay )
2021-02-01 06:16:52 +00:00
}
2022-03-26 20:33:17 +00:00
f . masters = pb . ServerAddresses ( * f . mastersString ) . ToAddressMap ( )
2021-09-13 05:47:52 +00:00
2018-10-11 06:19:54 +00:00
f . startFiler ( )
2017-05-28 03:14:22 +00:00
return true
}
2018-10-11 06:19:54 +00:00
func ( fo * FilerOptions ) startFiler ( ) {
2017-05-28 03:14:22 +00:00
2017-05-28 01:11:18 +00:00
defaultMux := http . NewServeMux ( )
2017-05-28 03:14:22 +00:00
publicVolumeMux := defaultMux
if * fo . publicPort != 0 {
publicVolumeMux = http . NewServeMux ( )
}
2021-09-20 21:05:59 +00:00
if * fo . portGrpc == 0 {
* fo . portGrpc = 10000 + * fo . port
}
2022-03-11 22:02:39 +00:00
if * fo . bindIp == "" {
* fo . bindIp = * fo . ip
}
2017-05-28 03:14:22 +00:00
2020-12-23 01:33:37 +00:00
defaultLevelDbDirectory := util . ResolvePath ( * fo . defaultLevelDbDirectory + "/filerldb2" )
2018-12-06 07:24:25 +00:00
2021-09-13 05:47:52 +00:00
filerAddress := pb . NewServerAddress ( * fo . ip , * fo . port , * fo . portGrpc )
2018-07-07 09:18:47 +00:00
fs , nfs_err := weed_server . NewFilerServer ( defaultMux , publicVolumeMux , & weed_server . FilerOption {
2021-09-13 05:47:52 +00:00
Masters : fo . masters ,
2022-05-02 04:59:16 +00:00
FilerGroup : * fo . filerGroup ,
2021-03-30 09:10:50 +00:00
Collection : * fo . collection ,
DefaultReplication : * fo . defaultReplicaPlacement ,
DisableDirListing : * fo . disableDirListing ,
MaxMB : * fo . maxMB ,
DirListingLimit : * fo . dirListingLimit ,
DataCenter : * fo . dataCenter ,
Rack : * fo . rack ,
DefaultLevelDbDir : defaultLevelDbDirectory ,
DisableHttp : * fo . disableHttp ,
2021-09-13 05:47:52 +00:00
Host : filerAddress ,
2021-03-30 09:10:50 +00:00
Cipher : * fo . cipher ,
2021-04-01 09:20:00 +00:00
SaveToFilerLimit : int64 ( * fo . saveToFilerLimit ) ,
2021-03-30 09:10:50 +00:00
ConcurrentUploadLimit : int64 ( * fo . concurrentUploadLimitMB ) * 1024 * 1024 ,
2022-06-14 16:30:49 +00:00
ShowUIDirectoryDelete : * fo . showUIDirectoryDelete ,
2022-08-05 08:16:42 +00:00
DownloadMaxBytesPs : int64 ( * fo . downloadMaxMBps ) * 1024 * 1024 ,
2023-02-25 17:48:59 +00:00
DiskType : * fo . diskType ,
2018-07-07 09:18:47 +00:00
} )
2014-03-31 03:57:25 +00:00
if nfs_err != nil {
2015-01-14 01:04:41 +00:00
glog . Fatalf ( "Filer startup error: %v" , nfs_err )
2014-03-31 03:57:25 +00:00
}
2017-05-28 03:14:22 +00:00
if * fo . publicPort != 0 {
2021-09-08 02:29:42 +00:00
publicListeningAddress := util . JoinHostPort ( * fo . bindIp , * fo . publicPort )
2020-06-02 07:10:35 +00:00
glog . V ( 0 ) . Infoln ( "Start Seaweed filer server" , util . Version ( ) , "public at" , publicListeningAddress )
2022-09-14 18:59:55 +00:00
publicListener , localPublicListener , e := util . NewIpAndLocalListeners ( * fo . bindIp , * fo . publicPort , 0 )
2017-05-28 03:14:22 +00:00
if e != nil {
glog . Fatalf ( "Filer server public listener error on port %d:%v" , * fo . publicPort , e )
}
go func ( ) {
if e := http . Serve ( publicListener , publicVolumeMux ) ; e != nil {
glog . Fatalf ( "Volume server fail to serve public: %v" , e )
}
} ( )
2022-09-14 18:59:55 +00:00
if localPublicListener != nil {
2022-03-16 05:28:18 +00:00
go func ( ) {
2022-09-14 18:59:55 +00:00
if e := http . Serve ( localPublicListener , publicVolumeMux ) ; e != nil {
2022-03-16 05:28:18 +00:00
glog . Errorf ( "Volume server fail to serve public: %v" , e )
}
} ( )
}
2017-05-28 03:14:22 +00:00
}
2020-06-02 07:10:35 +00:00
glog . V ( 0 ) . Infof ( "Start Seaweed Filer %s at %s:%d" , util . Version ( ) , * fo . ip , * fo . port )
2022-03-16 05:28:18 +00:00
filerListener , filerLocalListener , e := util . NewIpAndLocalListeners (
* fo . bindIp , * fo . port ,
2014-03-31 03:57:25 +00:00
time . Duration ( 10 ) * time . Second ,
)
if e != nil {
2015-01-14 01:04:41 +00:00
glog . Fatalf ( "Filer listener error: %v" , e )
2014-03-31 03:57:25 +00:00
}
2018-05-08 08:59:43 +00:00
2018-06-06 06:37:41 +00:00
// starting grpc server
2021-09-12 09:28:37 +00:00
grpcPort := * fo . portGrpc
2022-03-16 05:28:18 +00:00
grpcL , grpcLocalL , err := util . NewIpAndLocalListeners ( * fo . bindIp , grpcPort , 0 )
2018-06-06 06:37:41 +00:00
if err != nil {
glog . Fatalf ( "failed to listen on grpc port %d: %v" , grpcPort , err )
}
2020-03-04 08:39:47 +00:00
grpcS := pb . NewGrpcServer ( security . LoadServerTLS ( util . GetViper ( ) , "grpc.filer" ) )
2018-05-10 06:18:02 +00:00
filer_pb . RegisterSeaweedFilerServer ( grpcS , fs )
2018-05-08 08:59:43 +00:00
reflection . Register ( grpcS )
2022-03-16 05:28:18 +00:00
if grpcLocalL != nil {
go grpcS . Serve ( grpcLocalL )
}
2018-05-08 08:59:43 +00:00
go grpcS . Serve ( grpcL )
2018-06-06 06:37:41 +00:00
httpS := & http . Server { Handler : defaultMux }
2022-04-18 07:08:31 +00:00
if runtime . GOOS != "windows" {
2022-09-01 17:33:23 +00:00
localSocket := * fo . localSocket
if localSocket == "" {
2022-09-14 16:14:44 +00:00
localSocket = fmt . Sprintf ( "/tmp/seaweedfs-filer-%d.sock" , * fo . port )
2022-06-08 07:32:09 +00:00
}
2022-09-01 17:33:23 +00:00
if err := os . Remove ( localSocket ) ; err != nil && ! os . IsNotExist ( err ) {
glog . Fatalf ( "Failed to remove %s, error: %s" , localSocket , err . Error ( ) )
2022-04-18 07:08:31 +00:00
}
go func ( ) {
// start on local unix socket
2022-09-01 17:33:23 +00:00
filerSocketListener , err := net . Listen ( "unix" , localSocket )
2022-04-18 07:08:31 +00:00
if err != nil {
2022-09-01 17:33:23 +00:00
glog . Fatalf ( "Failed to listen on %s: %v" , localSocket , err )
2022-04-18 07:08:31 +00:00
}
httpS . Serve ( filerSocketListener )
} ( )
}
2022-03-16 05:28:18 +00:00
if filerLocalListener != nil {
go func ( ) {
if err := httpS . Serve ( filerLocalListener ) ; err != nil {
glog . Errorf ( "Filer Fail to serve: %v" , e )
}
} ( )
}
2018-06-06 06:37:41 +00:00
if err := httpS . Serve ( filerListener ) ; err != nil {
2015-01-14 01:04:41 +00:00
glog . Fatalf ( "Filer Fail to serve: %v" , e )
2014-03-31 03:57:25 +00:00
}
}