From 56003fded713e0cc1a5cb209ce16008ec66edbeb Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Tue, 20 Oct 2015 00:33:53 -0700 Subject: [PATCH] Add logger command - also migrate from old config to newer config --- api-signature.go | 24 ++--- auth-config.go | 127 ------------------------ config-logger-main.go | 78 +++++++++++++++ config-main.go | 53 ++++++++++ config-version-main.go | 64 ++++++++++++ flags.go | 6 ++ logger-file-hook.go | 54 ++++++++++ logger-syslog-hook.go | 8 +- main.go | 29 ++---- routers.go | 2 +- server-config.go | 218 +++++++++++++++++++++++++++++++++++++++++ server-main.go | 51 +++++++--- server_fs_test.go | 12 +-- 13 files changed, 538 insertions(+), 188 deletions(-) delete mode 100644 auth-config.go create mode 100644 config-logger-main.go create mode 100644 config-main.go create mode 100644 config-version-main.go create mode 100644 logger-file-hook.go create mode 100644 server-config.go diff --git a/api-signature.go b/api-signature.go index 66f171d05..b1c97bf94 100644 --- a/api-signature.go +++ b/api-signature.go @@ -105,17 +105,17 @@ func initSignatureV4(req *http.Request) (*fs.Signature, *probe.Error) { if err != nil { return nil, err.Trace() } - authConfig, err := loadAuthConfig() + config, err := loadConfigV2() if err != nil { return nil, err.Trace() } authFields := strings.Split(strings.TrimSpace(authHeaderValue), ",") signedHeaders := strings.Split(strings.Split(strings.TrimSpace(authFields[1]), "=")[1], ";") signature := strings.Split(strings.TrimSpace(authFields[2]), "=")[1] - if authConfig.AccessKeyID == accessKeyID { + if config.Credentials.AccessKeyID == accessKeyID { signature := &fs.Signature{ - AccessKeyID: authConfig.AccessKeyID, - SecretAccessKey: authConfig.SecretAccessKey, + AccessKeyID: config.Credentials.AccessKeyID, + SecretAccessKey: config.Credentials.SecretAccessKey, Signature: signature, SignedHeaders: signedHeaders, Request: req, @@ -210,14 +210,14 @@ func initPostPresignedPolicyV4(formValues map[string]string) (*fs.Signature, *pr if !isValidAccessKey(accessKeyID) { return nil, probe.NewError(errAccessKeyIDInvalid) } - authConfig, perr := loadAuthConfig() + config, perr := loadConfigV2() if perr != nil { return nil, perr.Trace() } - if authConfig.AccessKeyID == accessKeyID { + if config.Credentials.AccessKeyID == accessKeyID { signature := &fs.Signature{ - AccessKeyID: authConfig.AccessKeyID, - SecretAccessKey: authConfig.SecretAccessKey, + AccessKeyID: config.Credentials.AccessKeyID, + SecretAccessKey: config.Credentials.SecretAccessKey, Signature: formValues["X-Amz-Signature"], PresignedPolicy: formValues["Policy"], } @@ -236,16 +236,16 @@ func initPresignedSignatureV4(req *http.Request) (*fs.Signature, *probe.Error) { if !isValidAccessKey(accessKeyID) { return nil, probe.NewError(errAccessKeyIDInvalid) } - authConfig, err := loadAuthConfig() + config, err := loadConfigV2() if err != nil { return nil, err.Trace() } signedHeaders := strings.Split(strings.TrimSpace(req.URL.Query().Get("X-Amz-SignedHeaders")), ";") signature := strings.TrimSpace(req.URL.Query().Get("X-Amz-Signature")) - if authConfig.AccessKeyID == accessKeyID { + if config.Credentials.AccessKeyID == accessKeyID { signature := &fs.Signature{ - AccessKeyID: authConfig.AccessKeyID, - SecretAccessKey: authConfig.SecretAccessKey, + AccessKeyID: config.Credentials.AccessKeyID, + SecretAccessKey: config.Credentials.SecretAccessKey, Signature: signature, SignedHeaders: signedHeaders, Presigned: true, diff --git a/auth-config.go b/auth-config.go deleted file mode 100644 index 62d79aae6..000000000 --- a/auth-config.go +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Minio Cloud Storage, (C) 2015 Minio, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package main - -import ( - "os" - "os/user" - "path/filepath" - - "github.com/minio/minio-xl/pkg/probe" - "github.com/minio/minio-xl/pkg/quick" -) - -// AuthConfig auth keys -type AuthConfig struct { - Version string `json:"version"` - AccessKeyID string `json:"accessKeyId"` - SecretAccessKey string `json:"secretAccessKey"` -} - -// getAuthConfigPath get users config path -func getAuthConfigPath() (string, *probe.Error) { - if customConfigPath != "" { - return customConfigPath, nil - } - u, err := user.Current() - if err != nil { - return "", probe.NewError(err) - } - authConfigPath := filepath.Join(u.HomeDir, ".minio") - return authConfigPath, nil -} - -// createAuthConfigPath create users config path -func createAuthConfigPath() *probe.Error { - authConfigPath, err := getAuthConfigPath() - if err != nil { - return err.Trace() - } - if err := os.MkdirAll(authConfigPath, 0700); err != nil { - return probe.NewError(err) - } - return nil -} - -// isAuthConfigFileExists is auth config file exists? -func isAuthConfigFileExists() bool { - if _, err := os.Stat(mustGetAuthConfigFile()); err != nil { - if os.IsNotExist(err) { - return false - } - panic(err) - } - return true -} - -// mustGetAuthConfigFile always get users config file, if not panic -func mustGetAuthConfigFile() string { - authConfigFile, err := getAuthConfigFile() - if err != nil { - panic(err) - } - return authConfigFile -} - -// getAuthConfigFile get users config file -func getAuthConfigFile() (string, *probe.Error) { - authConfigPath, err := getAuthConfigPath() - if err != nil { - return "", err.Trace() - } - return filepath.Join(authConfigPath, "fsUsers.json"), nil -} - -// customConfigPath for custom config path only for testing purposes -var customConfigPath string - -// saveAuthConfig save auth config -func saveAuthConfig(a *AuthConfig) *probe.Error { - authConfigFile, err := getAuthConfigFile() - if err != nil { - return err.Trace() - } - qc, err := quick.New(a) - if err != nil { - return err.Trace() - } - if err := qc.Save(authConfigFile); err != nil { - return err.Trace() - } - return nil -} - -// loadAuthConfig load auth config -func loadAuthConfig() (*AuthConfig, *probe.Error) { - authConfigFile, err := getAuthConfigFile() - if err != nil { - return nil, err.Trace() - } - if _, err := os.Stat(authConfigFile); err != nil { - return nil, probe.NewError(err) - } - a := &AuthConfig{} - a.Version = "1" - qc, err := quick.New(a) - if err != nil { - return nil, err.Trace() - } - if err := qc.Load(authConfigFile); err != nil { - return nil, err.Trace() - } - return qc.Data().(*AuthConfig), nil -} diff --git a/config-logger-main.go b/config-logger-main.go new file mode 100644 index 000000000..0e46ef562 --- /dev/null +++ b/config-logger-main.go @@ -0,0 +1,78 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import "github.com/minio/cli" + +// Configure logger +var configLoggerCmd = cli.Command{ + Name: "logger", + Usage: "Configure logger.", + Action: mainConfigLogger, + CustomHelpTemplate: `NAME: + minio config {{.Name}} - {{.Usage}} + +USAGE: + minio config {{.Name}} + +`, +} + +func mainConfigLogger(ctx *cli.Context) { + if !ctx.Args().Present() || ctx.Args().First() == "help" { + cli.ShowCommandHelpAndExit(ctx, "logger", 1) // last argument is exit code + } + if ctx.Args().Get(0) == "mongo" { + enableLog2Mongo(ctx.Args().Tail()) + } + if ctx.Args().Get(0) == "syslog" { + enableLog2Syslog(ctx.Args().Tail()) + } + if ctx.Args().Get(0) == "file" { + enableLog2File(ctx.Args().Tail()) + } +} + +func enableLog2Mongo(args cli.Args) { + config, err := loadConfigV2() + fatalIf(err.Trace(), "Unable to load config", nil) + + config.MongoLogger.Addr = args.Get(0) + config.MongoLogger.DB = args.Get(1) + config.MongoLogger.Collection = args.Get(2) + + err = saveConfig(config) + fatalIf(err.Trace(), "Unable to save config.", nil) +} + +func enableLog2Syslog(args cli.Args) { + config, err := loadConfigV2() + fatalIf(err.Trace(), "Unable to load config.", nil) + + config.SyslogLogger.Addr = args.Get(0) + config.SyslogLogger.Network = args.Get(1) + err = saveConfig(config) + fatalIf(err.Trace(), "Unable to save config.", nil) +} + +func enableLog2File(args cli.Args) { + config, err := loadConfigV2() + fatalIf(err.Trace(), "Unable to load config.", nil) + config.FileLogger.Filename = args.Get(0) + err = saveConfig(config) + fatalIf(err.Trace(), "Unable to save config.", nil) +} diff --git a/config-main.go b/config-main.go new file mode 100644 index 000000000..75cb0c76b --- /dev/null +++ b/config-main.go @@ -0,0 +1,53 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import "github.com/minio/cli" + +// Configure minio server +// +// ---- +// NOTE: that the configure command only writes values to the config file. +// It does not use any configuration values from the environment variables. +// ---- +// +var configCmd = cli.Command{ + Name: "config", + Usage: "Collection of config management commands.", + Action: mainConfig, + Subcommands: []cli.Command{ + configLoggerCmd, + configVersionCmd, + }, + CustomHelpTemplate: `NAME: + {{.Name}} - {{.Usage}} + +USAGE: + {{.Name}} {{if .Flags}}[global flags] {{end}}command{{if .Flags}} [command flags]{{end}} [arguments...] + +COMMANDS: + {{range .Commands}}{{ .Name }}{{ "\t" }}{{.Usage}} + {{end}} +`, +} + +// mainConfig is the handle for "minio config" command. provides sub-commands which write configuration data in json format to config file. +func mainConfig(ctx *cli.Context) { + if !ctx.Args().Present() || ctx.Args().First() == "help" { + cli.ShowAppHelp(ctx) + } +} diff --git a/config-version-main.go b/config-version-main.go new file mode 100644 index 000000000..a135168f1 --- /dev/null +++ b/config-version-main.go @@ -0,0 +1,64 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "encoding/json" + + "github.com/minio/cli" + "github.com/minio/minio-xl/pkg/probe" +) + +// Print config version. +var configVersionCmd = cli.Command{ + Name: "version", + Usage: "Print config version.", + Action: mainConfigVersion, + CustomHelpTemplate: `NAME: + minio config {{.Name}} - {{.Usage}} + +USAGE: + minio config {{.Name}} + +`, +} + +func mainConfigVersion(ctx *cli.Context) { + if ctx.Args().First() == "help" { + cli.ShowCommandHelpAndExit(ctx, "version", 1) // last argument is exit code + } + + config, err := loadConfigV2() + fatalIf(err.Trace(), "Unable to load config", nil) + + // convert interface{} back to its original struct + newConf := config + type Version struct { + Value string `json:"value"` + } + if globalJSONFlag { + tB, e := json.Marshal( + struct { + Version Version `json:"version"` + }{Version: Version{newConf.Version}}, + ) + fatalIf(probe.NewError(e), "Unable to construct version string.", nil) + Println(string(tB)) + return + } + Println(newConf.Version) +} diff --git a/flags.go b/flags.go index 2709b9d5f..ed669d6b1 100644 --- a/flags.go +++ b/flags.go @@ -28,6 +28,12 @@ var ( Usage: "ADDRESS:PORT for cloud storage access.", } + loggerFlag = cli.StringFlag{ + Name: "logger", + Value: "none", + Usage: "Choose type of logging. Available options are [‘file’, ‘mongo’, ‘syslog’]", + } + accessLogFlag = cli.BoolFlag{ Name: "enable-accesslog", Hide: true, diff --git a/logger-file-hook.go b/logger-file-hook.go new file mode 100644 index 000000000..40db0d108 --- /dev/null +++ b/logger-file-hook.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "os" + + "github.com/Sirupsen/logrus" + "github.com/minio/minio-xl/pkg/probe" +) + +type localFile struct { + *os.File +} + +func log2File(filename string) *probe.Error { + fileHook, e := newFile(filename) + if e != nil { + return probe.NewError(e) + } + log.Hooks.Add(fileHook) // Add a local file hook. + log.Formatter = &logrus.JSONFormatter{} // JSON formatted log. + log.Level = logrus.InfoLevel // Minimum log level. + return nil +} + +func newFile(filename string) (*localFile, error) { + file, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) + if err != nil { + return nil, err + } + return &localFile{file}, nil +} + +func (l *localFile) Fire(entry *logrus.Entry) error { + line, err := entry.String() + if err != nil { + return fmt.Errorf("Unable to read entry, %v", err) + } + l.File.Write([]byte(line + "\n")) + l.File.Sync() + return nil +} + +// Levels - +func (l *localFile) Levels() []logrus.Level { + return []logrus.Level{ + logrus.PanicLevel, + logrus.FatalLevel, + logrus.ErrorLevel, + logrus.WarnLevel, + logrus.InfoLevel, + logrus.DebugLevel, + } +} diff --git a/logger-syslog-hook.go b/logger-syslog-hook.go index f27c706d3..bbcce20a8 100644 --- a/logger-syslog-hook.go +++ b/logger-syslog-hook.go @@ -33,8 +33,8 @@ type syslogHook struct { syslogRaddr string } -func log2Syslog(network, raddr string, priority syslog.Priority, tag string) *probe.Error { - syslogHook, e := newSyslog(network, raddr, priority, tag) +func log2Syslog(network, raddr string) *probe.Error { + syslogHook, e := newSyslog(network, raddr, syslog.LOG_ERR, "MINIO") if e != nil { return probe.NewError(e) } @@ -44,9 +44,7 @@ func log2Syslog(network, raddr string, priority syslog.Priority, tag string) *pr return nil } -// newSyslog - Creates a hook to be added to an instance of logger. This is called with -// `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` -// `if err == nil { log.Hooks.Add(hook) }` +// newSyslog - Creates a hook to be added to an instance of logger. func newSyslog(network, raddr string, priority syslog.Priority, tag string) (*syslogHook, error) { w, err := syslog.Dial(network, raddr, priority, tag) return &syslogHook{w, network, raddr}, err diff --git a/main.go b/main.go index 797edc0af..73b18b699 100644 --- a/main.go +++ b/main.go @@ -22,33 +22,11 @@ import ( "os/user" "runtime" "strconv" - "time" "github.com/dustin/go-humanize" "github.com/minio/cli" ) -// serverConfig - http server config -type serverConfig struct { - /// HTTP server options - Address string // Address:Port listening - AccessLog bool // Enable access log handler - Anonymous bool // No signature turn off - - /// FS options - Path string // Path to export for cloud storage - MinFreeDisk int64 // Minimum free disk space for filesystem - Expiry time.Duration // Set auto expiry for filesystem - - // TLS service - TLS bool // TLS on when certs are specified - CertFile string // Domain certificate - KeyFile string // Domain key - - /// Advanced HTTP server options - RateLimit int // Ratelimited server of incoming connections -} - func init() { // Check for the environment early on and gracefuly report. _, err := user.Current() @@ -64,6 +42,11 @@ func init() { checkGolangRuntimeVersion() } +func migrate() { + // Migrate config file + migrateConfig() +} + // Tries to get os/arch/platform specific information // Returns a map of current os/arch/platform/memstats func getSystemData() map[string]string { @@ -101,6 +84,7 @@ func findClosestCommands(command string) []string { func registerApp() *cli.App { // register all commands registerCommand(serverCmd) + registerCommand(configCmd) registerCommand(versionCmd) registerCommand(updateCmd) @@ -166,6 +150,7 @@ func main() { app := registerApp() app.Before = func(c *cli.Context) error { globalJSONFlag = c.GlobalBool("json") + migrate() return nil } app.ExtraInfo = func() map[string]string { diff --git a/routers.go b/routers.go index 96ccd0be0..667f5ea9d 100644 --- a/routers.go +++ b/routers.go @@ -54,7 +54,7 @@ func registerCloudStorageAPI(mux *router.Router, a CloudStorageAPI) { } // getNewCloudStorageAPI instantiate a new CloudStorageAPI -func getNewCloudStorageAPI(conf serverConfig) CloudStorageAPI { +func getNewCloudStorageAPI(conf cloudServerConfig) CloudStorageAPI { fs, err := fs.New() fatalIf(err.Trace(), "Instantiating filesystem failed.", nil) diff --git a/server-config.go b/server-config.go new file mode 100644 index 000000000..7918a8bde --- /dev/null +++ b/server-config.go @@ -0,0 +1,218 @@ +/* + * Minio Cloud Storage, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "errors" + "os" + "os/user" + "path/filepath" + + "github.com/minio/minio-xl/pkg/probe" + "github.com/minio/minio-xl/pkg/quick" +) + +// configV1 +type configV1 struct { + Version string `json:"version"` + AccessKeyID string `json:"accessKeyId"` + SecretAccessKey string `json:"secretAccessKey"` +} + +// configV2 +type configV2 struct { + Version string `json:"version"` + Credentials struct { + AccessKeyID string `json:"accessKeyId"` + SecretAccessKey string `json:"secretAccessKey"` + } `json:"credentials"` + MongoLogger struct { + Addr string `json:"addr"` + DB string `json:"db"` + Collection string `json:"collection"` + } `json:"mongoLogger"` + SyslogLogger struct { + Network string `json:"network"` + Addr string `json:"addr"` + } `json:"syslogLogger"` + FileLogger struct { + Filename string `json:"filename"` + } `json:"fileLogger"` +} + +// getConfigPath get users config path +func getConfigPath() (string, *probe.Error) { + if customConfigPath != "" { + return customConfigPath, nil + } + u, err := user.Current() + if err != nil { + return "", probe.NewError(err) + } + configPath := filepath.Join(u.HomeDir, ".minio") + return configPath, nil +} + +// createConfigPath create users config path +func createConfigPath() *probe.Error { + configPath, err := getConfigPath() + if err != nil { + return err.Trace() + } + if err := os.MkdirAll(configPath, 0700); err != nil { + return probe.NewError(err) + } + return nil +} + +// isAuthConfigFileExists is auth config file exists? +func isConfigFileExists() bool { + if _, err := os.Stat(mustGetConfigFile()); err != nil { + if os.IsNotExist(err) { + return false + } + panic(err) + } + return true +} + +// mustGetConfigFile always get users config file, if not panic +func mustGetConfigFile() string { + configFile, err := getConfigFile() + if err != nil { + panic(err) + } + return configFile +} + +// getConfigFile get users config file +func getConfigFile() (string, *probe.Error) { + configPath, err := getConfigPath() + if err != nil { + return "", err.Trace() + } + return filepath.Join(configPath, "config.json"), nil +} + +// configPath for custom config path only for testing purposes +var customConfigPath string + +// saveConfig save config +func saveConfig(a *configV2) *probe.Error { + configFile, err := getConfigFile() + if err != nil { + return err.Trace() + } + qc, err := quick.New(a) + if err != nil { + return err.Trace() + } + if err := qc.Save(configFile); err != nil { + return err.Trace() + } + return nil +} + +// loadConfigV2 load config +func loadConfigV2() (*configV2, *probe.Error) { + configFile, err := getConfigFile() + if err != nil { + return nil, err.Trace() + } + if _, err := os.Stat(configFile); err != nil { + return nil, probe.NewError(err) + } + a := &configV2{} + a.Version = "2" + qc, err := quick.New(a) + if err != nil { + return nil, err.Trace() + } + if err := qc.Load(configFile); err != nil { + return nil, err.Trace() + } + return qc.Data().(*configV2), nil +} + +// loadConfigV1 load config +func loadConfigV1() (*configV1, *probe.Error) { + configPath, err := getConfigPath() + if err != nil { + return nil, err.Trace() + } + configFile := filepath.Join(configPath, "fsUsers.json") + if _, err := os.Stat(configFile); err != nil { + return nil, probe.NewError(err) + } + a := &configV1{} + a.Version = "1" + qc, err := quick.New(a) + if err != nil { + return nil, err.Trace() + } + if err := qc.Load(configFile); err != nil { + return nil, err.Trace() + } + return qc.Data().(*configV1), nil +} + +func newConfigV2() *configV2 { + config := &configV2{} + config.Version = "2" + config.Credentials.AccessKeyID = "" + config.Credentials.SecretAccessKey = "" + config.MongoLogger.Addr = "" + config.MongoLogger.DB = "" + config.MongoLogger.Collection = "" + config.SyslogLogger.Network = "" + config.SyslogLogger.Addr = "" + config.FileLogger.Filename = "" + return config +} + +func migrateConfig() { + migrateV1ToV2() +} + +func migrateV1ToV2() { + cv1, err := loadConfigV1() + if err != nil { + if os.IsNotExist(err.ToGoError()) { + return + } + } + fatalIf(err.Trace(), "Unable to load config version ‘1’.", nil) + + if cv1.Version != "1" { + fatalIf(probe.NewError(errors.New("")), "Invalid version loaded ‘"+cv1.Version+"’.", nil) + } + + cv2 := newConfigV2() + cv2.Credentials.AccessKeyID = cv1.AccessKeyID + cv2.Credentials.SecretAccessKey = cv1.SecretAccessKey + err = saveConfig(cv2) + fatalIf(err.Trace(), "Unable to save config version ‘2’.", nil) + + Println("Migration from version ‘1’ to ‘2’ completed successfully.") + + /// Purge old fsUsers.json file + configPath, err := getConfigPath() + fatalIf(err.Trace(), "Unable to retrieve config path.", nil) + + configFile := filepath.Join(configPath, "fsUsers.json") + os.RemoveAll(configFile) +} diff --git a/server-main.go b/server-main.go index ca847cabe..1ff26d031 100644 --- a/server-main.go +++ b/server-main.go @@ -63,8 +63,29 @@ EXAMPLES: `, } +// cloudServerConfig - http server config +type cloudServerConfig struct { + /// HTTP server options + Address string // Address:Port listening + AccessLog bool // Enable access log handler + Anonymous bool // No signature turn off + + /// FS options + Path string // Path to export for cloud storage + MinFreeDisk int64 // Minimum free disk space for filesystem + Expiry time.Duration // Set auto expiry for filesystem + + // TLS service + TLS bool // TLS on when certs are specified + CertFile string // Domain certificate + KeyFile string // Domain key + + /// Advanced HTTP server options + RateLimit int // Ratelimited server of incoming connections +} + // configureAPIServer configure a new server instance -func configureAPIServer(conf serverConfig) (*http.Server, *probe.Error) { +func configureAPIServer(conf cloudServerConfig) (*http.Server, *probe.Error) { // Minio server config apiServer := &http.Server{ Addr: conf.Address, @@ -118,7 +139,7 @@ func configureAPIServer(conf serverConfig) (*http.Server, *probe.Error) { } // startServer starts an s3 compatible cloud storage server -func startServer(conf serverConfig) *probe.Error { +func startServer(conf cloudServerConfig) *probe.Error { apiServer, err := configureAPIServer(conf) if err != nil { return err.Trace() @@ -148,19 +169,19 @@ func parsePercentToInt(s string, bitSize int) (int64, *probe.Error) { return p, nil } -func getAuth() (*AuthConfig, *probe.Error) { - if err := createAuthConfigPath(); err != nil { +func getAuth() (*configV2, *probe.Error) { + if err := createConfigPath(); err != nil { return nil, err.Trace() } - config, err := loadAuthConfig() + config, err := loadConfigV2() if err != nil { if os.IsNotExist(err.ToGoError()) { // Initialize new config, since config file doesn't exist yet - config := &AuthConfig{} - config.Version = "1" - config.AccessKeyID = string(mustGenerateAccessKeyID()) - config.SecretAccessKey = string(mustGenerateSecretAccessKey()) - if err := saveAuthConfig(config); err != nil { + config := &configV2{} + config.Version = "2" + config.Credentials.AccessKeyID = string(mustGenerateAccessKeyID()) + config.Credentials.SecretAccessKey = string(mustGenerateSecretAccessKey()) + if err := saveConfig(config); err != nil { return nil, err.Trace() } return config, nil @@ -171,13 +192,13 @@ func getAuth() (*AuthConfig, *probe.Error) { } type accessKeys struct { - *AuthConfig + *configV2 } func (a accessKeys) String() string { magenta := color.New(color.FgMagenta, color.Bold).SprintFunc() white := color.New(color.FgWhite, color.Bold).SprintfFunc() - return fmt.Sprint(magenta("AccessKey: ") + white(a.AccessKeyID) + " " + magenta("SecretKey: ") + white(a.SecretAccessKey)) + return fmt.Sprint(magenta("AccessKey: ") + white(a.Credentials.AccessKeyID) + " " + magenta("SecretKey: ") + white(a.Credentials.SecretAccessKey)) } // JSON - json formatted output @@ -205,13 +226,13 @@ func fetchAuth() *probe.Error { Println("\nTo configure Minio Client.") if runtime.GOOS == "windows" { Println("\n\tDownload https://dl.minio.io:9000/updates/2015/Oct/" + runtime.GOOS + "-" + runtime.GOARCH + "/mc.exe") - Println("\t$ mc.exe config host add localhost:9000 " + conf.AccessKeyID + " " + conf.SecretAccessKey) + Println("\t$ mc.exe config host add localhost:9000 " + conf.Credentials.AccessKeyID + " " + conf.Credentials.SecretAccessKey) Println("\t$ mc.exe mb localhost/photobucket") Println("\t$ mc.exe cp C:\\Photos... localhost/photobucket") } else { Println("\n\t$ wget https://dl.minio.io:9000/updates/2015/Oct/" + runtime.GOOS + "-" + runtime.GOARCH + "/mc") Println("\t$ chmod 755 mc") - Println("\t$ ./mc config host add localhost:9000 " + conf.AccessKeyID + " " + conf.SecretAccessKey) + Println("\t$ ./mc config host add localhost:9000 " + conf.Credentials.AccessKeyID + " " + conf.Credentials.SecretAccessKey) Println("\t$ ./mc mb localhost/photobucket") Println("\t$ ./mc cp ~/Photos... localhost/photobucket") } @@ -287,7 +308,7 @@ func serverMain(c *cli.Context) { fatalIf(probe.NewError(err), "Unable to validate the path", nil) } tls := (certFile != "" && keyFile != "") - apiServerConfig := serverConfig{ + apiServerConfig := cloudServerConfig{ Address: c.GlobalString("address"), AccessLog: c.GlobalBool("enable-accesslog"), Anonymous: c.GlobalBool("anonymous"), diff --git a/server_fs_test.go b/server_fs_test.go index 2b9a1eb47..1e32e3c6b 100644 --- a/server_fs_test.go +++ b/server_fs_test.go @@ -70,24 +70,24 @@ func (s *MyAPIFSCacheSuite) SetUpSuite(c *C) { secretAccessKey, perr := generateSecretAccessKey() c.Assert(perr, IsNil) - authConf := &AuthConfig{} - authConf.AccessKeyID = string(accessKeyID) - authConf.SecretAccessKey = string(secretAccessKey) + conf := newConfigV2() + conf.Credentials.AccessKeyID = string(accessKeyID) + conf.Credentials.SecretAccessKey = string(secretAccessKey) s.accessKeyID = string(accessKeyID) s.secretAccessKey = string(secretAccessKey) // do this only once here customConfigPath = root - perr = saveAuthConfig(authConf) + perr = saveConfig(conf) c.Assert(perr, IsNil) - server := serverConfig{ + cloudServer := cloudServerConfig{ Path: fsroot, MinFreeDisk: 0, Anonymous: false, } - cloudStorageAPI := getNewCloudStorageAPI(server) + cloudStorageAPI := getNewCloudStorageAPI(cloudServer) httpHandler := getCloudStorageAPIHandler(cloudStorageAPI) testAPIFSCacheServer = httptest.NewServer(httpHandler) }