func registerBefore(ctx *cli.Context) error { setMcConfigDir(ctx.GlobalString("config")) globalQuietFlag = ctx.GlobalBool("quiet") globalForceFlag = ctx.GlobalBool("force") globalAliasFlag = ctx.GlobalBool("alias") globalDebugFlag = ctx.GlobalBool("debug") globalJSONFlag = ctx.GlobalBool("json") themeName := ctx.GlobalString("theme") if globalDebugFlag { console.NoDebugPrint = false } switch { case console.IsValidTheme(themeName) != true: console.Errorf("Invalid theme, please choose from the following list: %s.\n", console.GetThemeNames()) return errInvalidTheme{Theme: themeName} default: err := console.SetTheme(themeName) if err != nil { console.Errorf("Failed to set theme ‘%s’.", themeName) return err } } // Migrate any old version of config / state files to newer format. migrate() checkConfig() return nil }
func mainVersion(ctx *cli.Context) { if ctx.Args().First() == "help" { cli.ShowCommandHelpAndExit(ctx, "version", 1) // last argument is exit code } setVersionPalette(ctx.GlobalString("colors")) if globalJSONFlag { tB, e := json.Marshal( struct { Version struct { Value string `json:"value"` Format string `json:"format"` } `json:"version"` }{ Version: struct { Value string `json:"value"` Format string `json:"format"` }{ Value: mcVersion, Format: "RFC2616", }, }, ) fatalIf(probe.NewError(e), "Unable to construct version string.") console.Println(string(tB)) return } msg := console.Colorize("Version", fmt.Sprintf("Version: %s\n", mcVersion)) msg += console.Colorize("Version", fmt.Sprintf("Release-Tag: %s", mcReleaseTag)) console.Println(msg) }
func mainMirror(ctx *cli.Context) { checkMirrorSyntax(ctx) setMirrorPalette(ctx.GlobalString("colors")) var e error session := newSessionV2() session.Header.CommandType = "mirror" session.Header.RootPath, e = os.Getwd() if e != nil { session.Delete() fatalIf(probe.NewError(e), "Unable to get current working folder.") } // extract URLs. var err *probe.Error session.Header.CommandArgs, err = args2URLs(ctx.Args()) if err != nil { session.Delete() fatalIf(err.Trace(ctx.Args()...), fmt.Sprintf("One or more unknown argument types found in ‘%s’.", ctx.Args())) } doMirrorSession(session) session.Delete() }
func registerBefore(ctx *cli.Context) error { setMcConfigDir(ctx.GlobalString("config-folder")) globalQuietFlag = ctx.GlobalBool("quiet") globalMimicFlag = ctx.GlobalBool("mimic") globalDebugFlag = ctx.GlobalBool("debug") globalJSONFlag = ctx.GlobalBool("json") if globalDebugFlag { console.NoDebugPrint = false } // Disable color themes. if ctx.GlobalBool("no-color") == true { console.SetColorOff() } // Verify golang runtime verifyMCRuntime() // Migrate any old version of config / state files to newer format. migrate() // Checkconfig if it can be read checkConfig() return nil }
// mainCopy is bound to sub-command func mainCopy(ctx *cli.Context) { checkCopySyntax(ctx) setCopyPalette(ctx.GlobalString("colors")) session := newSessionV2() var e error session.Header.CommandType = "cp" session.Header.RootPath, e = os.Getwd() if e != nil { session.Delete() fatalIf(probe.NewError(e), "Unable to get current working folder.") } // extract URLs. var err *probe.Error session.Header.CommandArgs, err = args2URLs(ctx.Args()) if err != nil { session.Delete() fatalIf(err.Trace(), "One or more unknown URL types passed.") } doCopySession(session) session.Delete() }
func runAnalyticsCmd(c *cli.Context) { conf, err := loadConfigV1() if err != nil { log.Fatal(err.Trace()) } s := connectToMongo(c) defer s.Close() var result LogMessage iter := db.Find(bson.M{"http.request.method": "GET"}).Iter() for iter.Next(&result) { if time.Since(result.StartTime) < time.Duration(24*time.Hour) { filters := strings.Split(c.GlobalString("filter"), ",") var skip bool for _, filter := range filters { if strings.Contains(result.HTTP.Request.RemoteAddr, filter) { skip = true break } } if skip { continue } if result.StatusMessage == "" || result.StatusMessage == "OK" { if strings.HasSuffix(result.HTTP.Request.RequestURI, "minio") || strings.HasSuffix(result.HTTP.Request.RequestURI, "minio.exe") || strings.HasSuffix(result.HTTP.Request.RequestURI, "mc") || strings.HasSuffix(result.HTTP.Request.RequestURI, "mc.exe") { if err := updateGoogleAnalytics(conf, result); err != nil { log.Fatal(err.Trace()) } } } } } }
func connectToMongo(c *cli.Context) *mgo.Session { session, err := mgo.Dial(c.GlobalString("server")) if err != nil { panic(err) } // Optional. Switch the session to a monotonic behavior. session.SetMode(mgo.Monotonic, true) // make this configurable db = session.DB("test").C("downloads") return session }
func runFindCmd(c *cli.Context) { if len(c.Args()) > 1 || c.Args().First() == "help" { cli.ShowCommandHelpAndExit(c, "find", 1) // last argument is exit code } s := connectToMongo(c) defer s.Close() var result LogMessage switch { case strings.ToUpper(c.Args().First()) == "GET": iter := db.Find(bson.M{"http.request.method": "GET"}).Iter() for iter.Next(&result) { filters := strings.Split(c.GlobalString("filter"), ",") var skip bool for _, filter := range filters { if strings.Contains(result.HTTP.Request.RemoteAddr, filter) { skip = true break } } if skip { continue } if strings.HasSuffix(result.HTTP.Request.RequestURI, "minio") || strings.HasSuffix(result.HTTP.Request.RequestURI, "minio.exe") || strings.HasSuffix(result.HTTP.Request.RequestURI, "mc") || strings.HasSuffix(result.HTTP.Request.RequestURI, "mc.exe") { fmt.Print(result.HTTP.Request.Method) fmt.Print(" ") fmt.Print(result.HTTP.Request.RemoteAddr) fmt.Print(" ") fmt.Print(result.HTTP.Request.RequestURI) fmt.Println(" ") } } case strings.ToUpper(c.Args().First()) == "HEAD": iter := db.Find(bson.M{"http.request.method": "HEAD"}).Iter() for iter.Next(&result) { filters := strings.Split(c.GlobalString("filter"), ",") for _, filter := range filters { if strings.Contains(result.HTTP.Request.RemoteAddr, filter) { continue } } if !strings.HasPrefix(result.HTTP.Request.RequestURI, "/updates/2015") { continue } fmt.Print(result.HTTP.Request.Method) fmt.Print(" ") fmt.Print(result.HTTP.Request.RemoteAddr) fmt.Print(" ") fmt.Print(result.HTTP.Request.RequestURI) fmt.Println(" ") } } }
// mainUpdate - func mainUpdate(ctx *cli.Context) { checkUpdateSyntax(ctx) setUpdatePalette(ctx.GlobalString("colors")) arg := strings.TrimSpace(ctx.Args().First()) switch arg { case "release": getReleaseUpdate() case "experimental": getExperimentalUpdate() } }
func mainSession(ctx *cli.Context) { checkSessionSyntax(ctx) setSessionPalette(ctx.GlobalString("colors")) if !isSessionDirExists() { fatalIf(createSessionDir().Trace(), "Unable to create session folder.") } switch strings.TrimSpace(ctx.Args().First()) { // list resumable sessions case "list": fatalIf(listSessions().Trace(), "Unable to list sessions.") case "resume": sid := strings.TrimSpace(ctx.Args().Tail().First()) if !isSession(sid) { fatalIf(errDummy().Trace(), "Session ‘"+sid+"’ not found.") } s, err := loadSessionV2(sid) fatalIf(err.Trace(sid), "Unable to load session.") // extra check for testing purposes if s == nil { return } savedCwd, e := os.Getwd() fatalIf(probe.NewError(e), "Unable to verify your current working folder.") if s.Header.RootPath != "" { // chdir to RootPath e = os.Chdir(s.Header.RootPath) fatalIf(probe.NewError(e), "Unable to change our folder to root path while resuming session.") } sessionExecute(s) err = s.Close() fatalIf(err.Trace(), "Unable to close session file properly.") err = s.Delete() fatalIf(err.Trace(), "Unable to clear session files properly.") // chdir back to saved path e = os.Chdir(savedCwd) fatalIf(probe.NewError(e), "Unable to change our folder to saved path ‘"+savedCwd+"’.") // purge a requested pending session, if "all" purge everything case "clear": clearSession(strings.TrimSpace(ctx.Args().Tail().First())) } }
func mainRm(ctx *cli.Context) { checkRmSyntax(ctx) var incomplete bool var force bool setRmPalette(ctx.GlobalString("colors")) args := ctx.Args() if len(args) != 1 { if len(args) == 2 && args.Get(0) == "force" && args.Get(1) == "incomplete" || len(args) == 2 && args.Get(0) == "incomplete" && args.Get(1) == "force" { args = args[:] } else { if args.Last() == "force" { force = true args = args[:len(args)-1] } if args.Last() == "incomplete" { incomplete = true args = args[:len(args)-1] } } } URLs, err := args2URLs(args) fatalIf(err.Trace(ctx.Args()...), "Unable to parse arguments.") rmPrint := rmPrinterFuncGenerate() // execute for incomplete if incomplete { for _, url := range URLs { if isURLRecursive(url) && force { rmAllIncompleteUploads(stripRecursiveURL(url), rmPrint) } else { rmIncompleteUpload(url, rmPrint) } } return } for _, url := range URLs { if isURLRecursive(url) && force { rmAll(stripRecursiveURL(url), rmPrint) } else { rmSingle(url, rmPrint) } } if !globalJSONFlag && !globalQuietFlag { console.Eraseline() } }
// Parse command arguments and set global variables accordingly func setGlobalsFromContext(c *cli.Context) { // Set config dir switch { case c.IsSet("config-dir"): globalConfigDir = c.String("config-dir") case c.GlobalIsSet("config-dir"): globalConfigDir = c.GlobalString("config-dir") } if globalConfigDir == "" { console.Fatalf("Unable to get config file. Config directory is empty.") } // Set global quiet flag. globalQuiet = c.Bool("quiet") || c.GlobalBool("quiet") }
// mainMakeBucket is the handler for mc mb command func mainMakeBucket(ctx *cli.Context) { checkMakeBucketSyntax(ctx) setMakeBucketPalette(ctx.GlobalString("colors")) config := mustGetMcConfig() for _, arg := range ctx.Args() { targetURL := getAliasURL(arg, config.Aliases) fatalIf(doMakeBucket(targetURL).Trace(targetURL), "Unable to make bucket ‘"+targetURL+"’.") Prints("%s\n", MakeBucketMessage{ Status: "success", Bucket: targetURL, }) } }
func mainConfigAlias(ctx *cli.Context) { checkConfigAliasSyntax(ctx) setConfigAliasPalette(ctx.GlobalString("colors")) arg := ctx.Args().First() tailArgs := ctx.Args().Tail() switch strings.TrimSpace(arg) { case "add": addAlias(tailArgs.Get(0), tailArgs.Get(1)) case "remove": removeAlias(tailArgs.Get(0)) case "list": listAliases() } }
func registerBefore(ctx *cli.Context) error { setMcConfigDir(ctx.GlobalString("config-folder")) // Verify golang runtime. verifyMCRuntime() // Migrate any old version of config / state files to newer format. migrate() // Set global flags. setGlobalsFromContext(ctx) // Checkconfig if it can be read. checkConfig() return nil }
func mainConfigHost(ctx *cli.Context) { checkConfigHostSyntax(ctx) setConfigHostPalette(ctx.GlobalString("colors")) arg := ctx.Args().First() tailArgs := ctx.Args().Tail() switch strings.TrimSpace(arg) { case "add": addHost(tailArgs.Get(0), tailArgs.Get(1), tailArgs.Get(2), tailArgs.Get(3)) case "remove": removeHost(tailArgs.Get(0)) case "list": listHosts() } }
// mainDiff - is a handler for mc diff command func mainDiff(ctx *cli.Context) { checkDiffSyntax(ctx) setDiffPalette(ctx.GlobalString("colors")) config := mustGetMcConfig() firstArg := ctx.Args().First() secondArg := ctx.Args().Last() firstURL := getAliasURL(firstArg, config.Aliases) secondURL := getAliasURL(secondArg, config.Aliases) newFirstURL := stripRecursiveURL(firstURL) for diff := range doDiff(newFirstURL, secondURL, isURLRecursive(firstURL)) { fatalIf(diff.Error.Trace(newFirstURL, secondURL), "Failed to diff ‘"+firstURL+"’ and ‘"+secondURL+"’.") Prints("%s\n", diff) } }
func registerBefore(ctx *cli.Context) error { setMcConfigDir(ctx.GlobalString("config-folder")) globalQuietFlag = ctx.GlobalBool("quiet") globalMimicFlag = ctx.GlobalBool("mimic") globalDebugFlag = ctx.GlobalBool("debug") globalJSONFlag = ctx.GlobalBool("json") if globalDebugFlag { console.NoDebugPrint = false } if ctx.GlobalBool("nocolor") { console.SetNoColor() } verifyMCRuntime() // Migrate any old version of config / state files to newer format. migrate() checkConfig() return nil }
func registerBefore(ctx *cli.Context) error { // Check if mc was compiled using a supported version of Golang. checkGoVersion() // Set the config folder. setMcConfigDir(ctx.GlobalString("config-folder")) // Migrate any old version of config / state files to newer format. migrate() // Initialize default config files. initMC() // Set global flags. setGlobalsFromContext(ctx) // Check if config can be read. checkConfig() return nil }
func mainShareDownload(ctx *cli.Context) { shareDataDirSetup() checkShareDownloadSyntax(ctx) setSharePalette(ctx.GlobalString("colors")) args := ctx.Args() config := mustGetMcConfig() url := args.Get(0) // default expiration is 7days expires := time.Duration(604800) * time.Second if len(args) == 2 { var err error expires, err = time.ParseDuration(args.Get(1)) fatalIf(probe.NewError(err), "Unable to parse time argument.") } targetURL := getAliasURL(url, config.Aliases) // if recursive strip off the "..." err := doShareDownloadURL(stripRecursiveURL(targetURL), isURLRecursive(targetURL), expires) fatalIf(err.Trace(targetURL), "Unable to generate URL for download.") return }
// mainList - is a handler for mc ls command func mainList(ctx *cli.Context) { setListPalette(ctx.GlobalString("colors")) checkListSyntax(ctx) args := ctx.Args() // Operating system tool behavior if globalMimicFlag && !ctx.Args().Present() { args = []string{"."} } var targetURLs []string var err *probe.Error if args.First() == "incomplete" { targetURLs, err = args2URLs(args.Tail()) fatalIf(err.Trace(args...), "One or more unknown URL types passed.") for _, targetURL := range targetURLs { // if recursive strip off the "..." var clnt client.Client clnt, err = url2Client(stripRecursiveURL(targetURL)) fatalIf(err.Trace(targetURL), "Unable to initialize target ‘"+targetURL+"’.") err = doListIncomplete(clnt, isURLRecursive(targetURL), len(targetURLs) > 1) fatalIf(err.Trace(clnt.URL().String()), "Unable to list target ‘"+clnt.URL().String()+"’.") } } else { targetURLs, err = args2URLs(args) fatalIf(err.Trace(args...), "One or more unknown URL types passed.") for _, targetURL := range targetURLs { // if recursive strip off the "..." var clnt client.Client clnt, err = url2Client(stripRecursiveURL(targetURL)) fatalIf(err.Trace(targetURL), "Unable to initialize target ‘"+targetURL+"’.") err = doList(clnt, isURLRecursive(targetURL), len(targetURLs) > 1) fatalIf(err.Trace(clnt.URL().String()), "Unable to list target ‘"+clnt.URL().String()+"’.") } } }
func registerBefore(ctx *cli.Context) error { setMcConfigDir(ctx.GlobalString("config-folder")) globalQuietFlag = ctx.GlobalBool("quiet") globalMimicFlag = ctx.GlobalBool("mimic") globalDebugFlag = ctx.GlobalBool("debug") globalJSONFlag = ctx.GlobalBool("json") if globalDebugFlag { console.NoDebugPrint = false } setMainPalette(ctx.GlobalString("colors")) // check if mc is being run as root checkUser() // verify golang runtime verifyMCRuntime() // Migrate any old version of config / state files to newer format. migrate() // checkConfig if it can be read checkConfig() return nil }
func getServerConfig(c *cli.Context) minioConfig { certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") { Fatalln("Both certificate and key are required to enable https.") } tls := (certFile != "" && keyFile != "") return minioConfig{ Address: c.GlobalString("address"), RPCAddress: c.GlobalString("address-server-rpc"), TLS: tls, CertFile: certFile, KeyFile: keyFile, RateLimit: c.GlobalInt("ratelimit"), } }
func mainShareUpload(ctx *cli.Context) { var expires time.Duration var err error shareDataDirSetup() checkShareUploadSyntax(ctx) setSharePalette(ctx.GlobalString("colors")) args := ctx.Args() config := mustGetMcConfig() if strings.TrimSpace(args.Get(1)) == "" { expires = time.Duration(604800) * time.Second } else { expires, err = time.ParseDuration(strings.TrimSpace(args.Get(1))) if err != nil { fatalIf(probe.NewError(err), "Unable to parse time argument.") } } contentType := strings.TrimSpace(args.Get(2)) targetURL := getAliasURL(strings.TrimSpace(args.Get(0)), config.Aliases) e := doShareUploadURL(stripRecursiveURL(targetURL), isURLRecursive(targetURL), expires, contentType) fatalIf(e.Trace(targetURL), "Unable to generate URL for upload.") }
func mainAccess(ctx *cli.Context) { checkAccessSyntax(ctx) setAccessPalette(ctx.GlobalString("colors")) config := mustGetMcConfig() switch ctx.Args().Get(0) { case "set": perms := accessPerms(ctx.Args().Tail().Get(0)) for _, arg := range ctx.Args().Tail().Tail() { targetURL := getAliasURL(arg, config.Aliases) fatalIf(doSetAccess(targetURL, perms).Trace(targetURL, string(perms)), "Unable to set access permission ‘"+string(perms)+"’ for ‘"+targetURL+"’.") Prints("%s\n", AccessMessage{ Operation: "set", Status: "success", Bucket: targetURL, Perms: perms, }) } case "get": for _, arg := range ctx.Args().Tail() { targetURL := getAliasURL(arg, config.Aliases) perms, err := doGetAccess(targetURL) fatalIf(err.Trace(targetURL), "Unable to get access permission for ‘"+targetURL+"’.") Prints("%s\n", AccessMessage{ Operation: "get", Status: "success", Bucket: targetURL, Perms: perms, }) } } }
func getControllerConfig(c *cli.Context) minioConfig { certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") { Fatalln("Both certificate and key are required to enable https.") } tls := (certFile != "" && keyFile != "") return minioConfig{ ControllerAddress: c.GlobalString("address-controller"), TLS: tls, CertFile: certFile, KeyFile: keyFile, RateLimit: c.GlobalInt("ratelimit"), Anonymous: c.GlobalBool("anonymous"), } }
func getServerConfig(c *cli.Context) fsConfig { certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") { Fatalln("Both certificate and key are required to enable https.") } tls := (certFile != "" && keyFile != "") return fsConfig{ Address: c.GlobalString("address"), Path: strings.TrimSpace(c.Args().First()), Anonymous: c.GlobalBool("anonymous"), TLS: tls, CertFile: certFile, KeyFile: keyFile, RateLimit: c.GlobalInt("ratelimit"), } }
func serverMain(c *cli.Context) { checkServerSyntax(c) perr := initServer() fatalIf(perr.Trace(), "Failed to read config for minio.", nil) certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") { fatalIf(probe.NewError(errInvalidArgument), "Both certificate and key are required to enable https.", nil) } var minFreeDisk int64 minFreeDiskSet := false // Default minFreeDisk = 10 var expiration time.Duration expirationSet := false args := c.Args() for len(args) >= 2 { switch args.First() { case "min-free-disk": if minFreeDiskSet { fatalIf(probe.NewError(errInvalidArgument), "Minimum free disk should be set only once.", nil) } args = args.Tail() var err *probe.Error minFreeDisk, err = parsePercentToInt(args.First(), 64) fatalIf(err.Trace(args.First()), "Invalid minium free disk size "+args.First()+" passed.", nil) args = args.Tail() minFreeDiskSet = true case "expiry": if expirationSet { fatalIf(probe.NewError(errInvalidArgument), "Expiration should be set only once.", nil) } args = args.Tail() var err error expiration, err = time.ParseDuration(args.First()) fatalIf(probe.NewError(err), "Invalid expiration time "+args.First()+" passed.", nil) args = args.Tail() expirationSet = true default: cli.ShowCommandHelpAndExit(c, "server", 1) // last argument is exit code } } path := strings.TrimSpace(c.Args().Last()) // Last argument is always path if _, err := os.Stat(path); err != nil { fatalIf(probe.NewError(err), "Unable to validate the path", nil) } tls := (certFile != "" && keyFile != "") apiServerConfig := cloudServerConfig{ Address: c.GlobalString("address"), AccessLog: c.GlobalBool("enable-accesslog"), Anonymous: c.GlobalBool("anonymous"), Path: path, MinFreeDisk: minFreeDisk, Expiry: expiration, TLS: tls, CertFile: certFile, KeyFile: keyFile, RateLimit: c.GlobalInt("ratelimit"), } perr = startServer(apiServerConfig) errorIf(perr.Trace(), "Failed to start the minio server.", nil) }
func mainShareList(ctx *cli.Context) { shareDataDirSetup() setSharePalette(ctx.GlobalString("colors")) err := doShareList() fatalIf(err.Trace(), "Unable to list shared URLs.") }
func serverMain(c *cli.Context) { checkServerSyntax(c) conf, err := initServer() fatalIf(err.Trace(), "Failed to read config for minio.", nil) certFile := c.GlobalString("cert") keyFile := c.GlobalString("key") if (certFile != "" && keyFile == "") || (certFile == "" && keyFile != "") { fatalIf(probe.NewError(errInvalidArgument), "Both certificate and key are required to enable https.", nil) } minFreeDisk, err := parsePercentToInt(c.String("min-free-disk"), 64) fatalIf(err.Trace(c.String("min-free-disk")), "Invalid minium free disk size "+c.String("min-free-disk")+" passed.", nil) path := strings.TrimSpace(c.Args().Last()) // Last argument is always path if _, err := os.Stat(path); err != nil { fatalIf(probe.NewError(err), "Unable to validate the path", nil) } tls := (certFile != "" && keyFile != "") serverConfig := cloudServerConfig{ Address: c.GlobalString("address"), AccessLog: c.GlobalBool("enable-accesslog"), AccessKeyID: conf.Credentials.AccessKeyID, SecretAccessKey: conf.Credentials.SecretAccessKey, Path: path, MinFreeDisk: minFreeDisk, TLS: tls, CertFile: certFile, KeyFile: keyFile, } // configure API server. apiServer, err := configureAPIServer(serverConfig) errorIf(err.Trace(), "Failed to configure API server.", nil) Println("\nMinio Object Storage:") printServerMsg(apiServer) // configure Web server. webServer, err := configureWebServer(serverConfig) errorIf(err.Trace(), "Failed to configure Web server.", nil) Println("\nMinio Browser:") printServerMsg(webServer) Println("\nTo configure Minio Client:") if runtime.GOOS == "windows" { Println(" Download \"mc\" from https://dl.minio.io/client/mc/release/" + runtime.GOOS + "-" + runtime.GOARCH + "/mc.exe") Println(" $ mc.exe config host add myminio http://localhost:9000 " + conf.Credentials.AccessKeyID + " " + conf.Credentials.SecretAccessKey) } else { Println(" $ wget https://dl.minio.io/client/mc/release/" + runtime.GOOS + "-" + runtime.GOARCH + "/mc") Println(" $ chmod 755 mc") Println(" $ ./mc config host add myminio http://localhost:9000 " + conf.Credentials.AccessKeyID + " " + conf.Credentials.SecretAccessKey) } // Start server. err = minhttp.ListenAndServe(apiServer, webServer) errorIf(err.Trace(), "Failed to start the minio server.", nil) }