mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
minio: Server upon start displays a message if update is available.
This code also handles to turn itself off when network is not available and if request fails. Also prints only when the update is available.
This commit is contained in:
parent
24ae5467c8
commit
3538c9f598
23
commands.go
23
commands.go
@ -18,13 +18,30 @@ package main
|
||||
|
||||
import "github.com/minio/cli"
|
||||
|
||||
// Collection of minio commands currently supported are
|
||||
// Collection of minio commands currently supported are.
|
||||
var commands = []cli.Command{}
|
||||
|
||||
// Collection of minio commands currently supported in a trie tree
|
||||
// Collection of minio commands currently supported in a trie tree.
|
||||
var commandsTree = newTrie()
|
||||
|
||||
// registerCommand registers a cli command
|
||||
// Collection of minio flags currently supported.
|
||||
var globalFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Suppress chatty console output.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "debug",
|
||||
Usage: "Enable debugging output.",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "config-dir, C",
|
||||
Value: mustGetConfigPath(),
|
||||
Usage: "Path to configuration folder.",
|
||||
},
|
||||
}
|
||||
|
||||
// registerCommand registers a cli command.
|
||||
func registerCommand(command cli.Command) {
|
||||
commands = append(commands, command)
|
||||
commandsTree.Insert(command.Name)
|
||||
|
18
flags.go
18
flags.go
@ -15,21 +15,3 @@
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/minio/cli"
|
||||
|
||||
// Collection of minio flags currently supported
|
||||
var flags = []cli.Flag{}
|
||||
|
||||
var (
|
||||
configFolderFlag = cli.StringFlag{
|
||||
Name: "config-folder, C",
|
||||
Value: mustGetConfigPath(),
|
||||
Usage: "Path to configuration folder.",
|
||||
}
|
||||
)
|
||||
|
||||
// registerFlag registers a cli flag
|
||||
func registerFlag(flag cli.Flag) {
|
||||
flags = append(flags, flag)
|
||||
}
|
||||
|
31
globals.go
31
globals.go
@ -16,7 +16,11 @@
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/fatih/color"
|
||||
import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mc/pkg/console"
|
||||
)
|
||||
|
||||
// Global constants for Minio.
|
||||
const (
|
||||
@ -33,9 +37,34 @@ const (
|
||||
globalMinioConfigFile = "config.json"
|
||||
)
|
||||
|
||||
var (
|
||||
globalQuiet = false // Quiet flag set via command line
|
||||
globalDebug = false // Debug flag set via command line
|
||||
// Add new global flags here.
|
||||
)
|
||||
|
||||
// global colors.
|
||||
var (
|
||||
colorMagenta = color.New(color.FgMagenta, color.Bold).SprintfFunc()
|
||||
colorWhite = color.New(color.FgWhite, color.Bold).SprintfFunc()
|
||||
colorGreen = color.New(color.FgGreen, color.Bold).SprintfFunc()
|
||||
)
|
||||
|
||||
// Set global states. NOTE: It is deliberately kept monolithic to
|
||||
// ensure we dont miss out any flags.
|
||||
func setGlobals(quiet, debug bool) {
|
||||
globalQuiet = quiet
|
||||
globalDebug = debug
|
||||
// Enable debug messages if requested.
|
||||
if globalDebug == true {
|
||||
console.DebugPrint = true
|
||||
}
|
||||
}
|
||||
|
||||
// Set global states. NOTE: It is deliberately kept monolithic to
|
||||
// ensure we dont miss out any flags.
|
||||
func setGlobalsFromContext(ctx *cli.Context) {
|
||||
quiet := ctx.Bool("quiet") || ctx.GlobalBool("quiet")
|
||||
debug := ctx.Bool("debug") || ctx.GlobalBool("debug")
|
||||
setGlobals(quiet, debug)
|
||||
}
|
||||
|
45
main.go
45
main.go
@ -27,6 +27,17 @@ import (
|
||||
"github.com/minio/cli"
|
||||
"github.com/minio/mc/pkg/console"
|
||||
"github.com/minio/minio/pkg/probe"
|
||||
"github.com/olekukonko/ts"
|
||||
)
|
||||
|
||||
var (
|
||||
// global flags for minio.
|
||||
minioFlags = []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
Name: "help, h",
|
||||
Usage: "Show help.",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Help template for minio.
|
||||
@ -136,16 +147,13 @@ func registerApp() *cli.App {
|
||||
registerCommand(versionCmd)
|
||||
registerCommand(updateCmd)
|
||||
|
||||
// Register all flags.
|
||||
registerFlag(configFolderFlag)
|
||||
|
||||
// Set up app.
|
||||
app := cli.NewApp()
|
||||
app.Name = "Minio"
|
||||
app.Author = "Minio.io"
|
||||
app.Usage = "Distributed Object Storage Server for Micro Services."
|
||||
app.Description = `Micro services environment provisions one Minio server per application instance. Scalability is achieved through large number of smaller personalized instances. This version of the Minio binary is built using Filesystem storage backend for magnetic and solid state disks.`
|
||||
app.Flags = flags
|
||||
app.Flags = append(minioFlags, globalFlags...)
|
||||
app.Commands = commands
|
||||
app.CustomAppHelpTemplate = minioHelpTemplate
|
||||
app.CommandNotFound = func(ctx *cli.Context, command string) {
|
||||
@ -168,7 +176,7 @@ func checkMainSyntax(c *cli.Context) {
|
||||
console.Fatalf("Unable to obtain user's home directory. \nError: %s\n", err)
|
||||
}
|
||||
if configPath == "" {
|
||||
console.Fatalln("Config folder cannot be empty, please specify --config-folder <foldername>.")
|
||||
console.Fatalln("Config folder cannot be empty, please specify --config-dir <foldername>.")
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,8 +187,11 @@ func main() {
|
||||
|
||||
app := registerApp()
|
||||
app.Before = func(c *cli.Context) error {
|
||||
// Set global flags.
|
||||
setGlobalsFromContext(c)
|
||||
|
||||
// Sets new config folder.
|
||||
setGlobalConfigPath(c.GlobalString("config-folder"))
|
||||
setGlobalConfigPath(c.GlobalString("config-dir"))
|
||||
|
||||
// Valid input arguments to main.
|
||||
checkMainSyntax(c)
|
||||
@ -191,11 +202,29 @@ func main() {
|
||||
// Enable all loggers by now.
|
||||
enableLoggers()
|
||||
|
||||
// Do not print update messages, if quiet flag is set.
|
||||
if !globalQuiet {
|
||||
// Do not print any errors in release update function.
|
||||
noError := true
|
||||
updateMsg := getReleaseUpdate(minioUpdateStableURL, noError)
|
||||
if updateMsg.Update {
|
||||
console.Println(updateMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// Return here.
|
||||
return nil
|
||||
}
|
||||
app.ExtraInfo = func() map[string]string {
|
||||
return getSystemData()
|
||||
if _, e := ts.GetSize(); e != nil {
|
||||
globalQuiet = true
|
||||
}
|
||||
// Enable if debug is enabled.
|
||||
if globalDebug {
|
||||
return getSystemData()
|
||||
}
|
||||
return make(map[string]string)
|
||||
}
|
||||
|
||||
// Run the app - exit on error.
|
||||
app.RunAndExitOnError()
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ func initServer(c *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// check init arguments.
|
||||
// Check init arguments.
|
||||
func checkInitSyntax(c *cli.Context) {
|
||||
if !c.Args().Present() || c.Args().First() == "help" {
|
||||
cli.ShowCommandHelpAndExit(c, "init", 1)
|
||||
@ -214,8 +214,7 @@ func checkInitSyntax(c *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// extract port number from address.
|
||||
// address should be of the form host:port
|
||||
// Extract port number from address address should be of the form host:port.
|
||||
func getPort(address string) int {
|
||||
_, portStr, e := net.SplitHostPort(address)
|
||||
fatalIf(probe.NewError(e), "Unable to split host port.", nil)
|
||||
@ -307,6 +306,7 @@ func serverMain(c *cli.Context) {
|
||||
cli.ShowCommandHelpAndExit(c, "server", 1)
|
||||
}
|
||||
|
||||
// get backend.
|
||||
backend := serverConfig.GetBackend()
|
||||
if backend.Type == "fs" {
|
||||
// Initialize file system.
|
||||
@ -348,6 +348,7 @@ func serverMain(c *cli.Context) {
|
||||
// Start server.
|
||||
err = minhttp.ListenAndServe(apiServer)
|
||||
errorIf(err.Trace(), "Failed to start the minio server.", nil)
|
||||
return
|
||||
}
|
||||
console.Println(colorGreen("No known backends configured, please use ‘minio init --help’ to initialize a backend."))
|
||||
}
|
||||
|
38
notifier.go
38
notifier.go
@ -18,7 +18,6 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@ -29,25 +28,22 @@ import (
|
||||
|
||||
// colorizeUpdateMessage - inspired from Yeoman project npm package https://github.com/yeoman/update-notifier
|
||||
func colorizeUpdateMessage(updateString string) (string, *probe.Error) {
|
||||
// initialize coloring
|
||||
// Initialize coloring.
|
||||
cyan := color.New(color.FgCyan, color.Bold).SprintFunc()
|
||||
yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
|
||||
|
||||
// calculate length without color coding, due to ANSI color characters padded to actual
|
||||
// string the final length is wrong than the original string length
|
||||
line1Str := fmt.Sprintf(" Update available: ")
|
||||
line2Str := fmt.Sprintf(" Run \"%s\" to update. ", updateString)
|
||||
// Calculate length without color coding, due to ANSI color
|
||||
// characters padded to actual string the final length is wrong
|
||||
// than the original string length.
|
||||
line1Str := fmt.Sprintf(" New update: %s ", updateString)
|
||||
line1Length := len(line1Str)
|
||||
line2Length := len(line2Str)
|
||||
|
||||
// populate lines with color coding
|
||||
line1InColor := line1Str
|
||||
line2InColor := fmt.Sprintf(" Run \"%s\" to update. ", cyan(updateString))
|
||||
// Populate lines with color coding.
|
||||
line1InColor := fmt.Sprintf(" New update: %s ", cyan(updateString))
|
||||
|
||||
// calculate the rectangular box size
|
||||
maxContentWidth := int(math.Max(float64(line1Length), float64(line2Length)))
|
||||
// Calculate the rectangular box size.
|
||||
maxContentWidth := line1Length
|
||||
line1Rest := maxContentWidth - line1Length
|
||||
line2Rest := maxContentWidth - line2Length
|
||||
|
||||
terminal, err := ts.GetSize()
|
||||
if err != nil {
|
||||
@ -56,31 +52,29 @@ func colorizeUpdateMessage(updateString string) (string, *probe.Error) {
|
||||
|
||||
var message string
|
||||
switch {
|
||||
case len(line2Str) > terminal.Col():
|
||||
message = "\n" + line1InColor + "\n" + line2InColor + "\n"
|
||||
case len(line1Str) > terminal.Col():
|
||||
message = "\n" + line1InColor + "\n"
|
||||
default:
|
||||
// on windows terminal turn off unicode characters
|
||||
// On windows terminal turn off unicode characters.
|
||||
var top, bottom, sideBar string
|
||||
if runtime.GOOS == "windows" {
|
||||
top = yellow("*" + strings.Repeat("*", maxContentWidth) + "*")
|
||||
bottom = yellow("*" + strings.Repeat("*", maxContentWidth) + "*")
|
||||
sideBar = yellow("|")
|
||||
} else {
|
||||
// color the rectangular box, use unicode characters here
|
||||
// Color the rectangular box, use unicode characters here.
|
||||
top = yellow("┏" + strings.Repeat("━", maxContentWidth) + "┓")
|
||||
bottom = yellow("┗" + strings.Repeat("━", maxContentWidth) + "┛")
|
||||
sideBar = yellow("┃")
|
||||
}
|
||||
// fill spaces to the rest of the area
|
||||
// Fill spaces to the rest of the area.
|
||||
spacePaddingLine1 := strings.Repeat(" ", line1Rest)
|
||||
spacePaddingLine2 := strings.Repeat(" ", line2Rest)
|
||||
|
||||
// construct the final message
|
||||
// Construct the final message.
|
||||
message = "\n" + top + "\n" +
|
||||
sideBar + line1InColor + spacePaddingLine1 + sideBar + "\n" +
|
||||
sideBar + line2InColor + spacePaddingLine2 + sideBar + "\n" +
|
||||
bottom + "\n"
|
||||
}
|
||||
// return the final message
|
||||
// Return the final message.
|
||||
return message, nil
|
||||
}
|
||||
|
121
update-main.go
121
update-main.go
@ -89,13 +89,7 @@ func (u updateMessage) String() string {
|
||||
updateMessage := color.New(color.FgGreen, color.Bold).SprintfFunc()
|
||||
return updateMessage("You are already running the most recent version of ‘minio’.")
|
||||
}
|
||||
var msg string
|
||||
if runtime.GOOS == "windows" {
|
||||
msg = "Download " + u.Download
|
||||
} else {
|
||||
msg = "Download " + u.Download
|
||||
}
|
||||
msg, err := colorizeUpdateMessage(msg)
|
||||
msg, err := colorizeUpdateMessage(u.Download)
|
||||
fatalIf(err.Trace(msg), "Unable to colorize experimental update notification string ‘"+msg+"’.", nil)
|
||||
return msg
|
||||
}
|
||||
@ -141,59 +135,108 @@ func parseReleaseData(data string) (time.Time, *probe.Error) {
|
||||
}
|
||||
|
||||
// verify updates for releases.
|
||||
func getReleaseUpdate(updateURL string) {
|
||||
func getReleaseUpdate(updateURL string, noError bool) updateMessage {
|
||||
// Construct a new update url.
|
||||
newUpdateURLPrefix := updateURL + "/" + runtime.GOOS + "-" + runtime.GOARCH
|
||||
newUpdateURL := newUpdateURLPrefix + "/minio.shasum"
|
||||
data, e := http.Get(newUpdateURL)
|
||||
fatalIf(probe.NewError(e), "Unable to read from update URL ‘"+newUpdateURL+"’.", nil)
|
||||
|
||||
if minioVersion == "DEVELOPMENT.GOGET" {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Update mechanism is not supported for ‘go get’ based binary builds. Please download official releases from https://minio.io/#minio", nil)
|
||||
}
|
||||
|
||||
current, e := time.Parse(time.RFC3339, minioVersion)
|
||||
fatalIf(probe.NewError(e), "Unable to parse version string as time.", nil)
|
||||
|
||||
if current.IsZero() {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Updates not supported for custom builds. Version field is empty. Please download official releases from https://minio.io/#minio", nil)
|
||||
}
|
||||
|
||||
body, e := ioutil.ReadAll(data.Body)
|
||||
fatalIf(probe.NewError(e), "Fetching updates failed. Please try again.", nil)
|
||||
|
||||
latest, err := parseReleaseData(string(body))
|
||||
fatalIf(err.Trace(updateURL), "Please report this issue at https://github.com/minio/minio/issues.", nil)
|
||||
|
||||
if latest.IsZero() {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Unable to validate any update available at this time. Please open an issue at https://github.com/minio/minio/issues", nil)
|
||||
}
|
||||
|
||||
// Get the downloadURL.
|
||||
var downloadURL string
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||
switch runtime.GOOS {
|
||||
case "windows", "darwin":
|
||||
// For windows and darwin.
|
||||
downloadURL = newUpdateURLPrefix + "/minio.zip"
|
||||
} else {
|
||||
default:
|
||||
// For all other operating systems.
|
||||
downloadURL = newUpdateURLPrefix + "/minio.gz"
|
||||
}
|
||||
|
||||
// Initialize update message.
|
||||
updateMsg := updateMessage{
|
||||
Download: downloadURL,
|
||||
Version: minioVersion,
|
||||
}
|
||||
|
||||
// Instantiate a new client with 1 sec timeout.
|
||||
client := &http.Client{
|
||||
Timeout: 500 * time.Millisecond,
|
||||
}
|
||||
|
||||
// Fetch new update.
|
||||
data, e := client.Get(newUpdateURL)
|
||||
if e != nil && noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf(probe.NewError(e), "Unable to read from update URL ‘"+newUpdateURL+"’.", nil)
|
||||
|
||||
// Error out if 'update' command is issued for development based builds.
|
||||
if minioVersion == "DEVELOPMENT.GOGET" && !noError {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Update mechanism is not supported for ‘go get’ based binary builds. Please download official releases from https://minio.io/#minio", nil)
|
||||
}
|
||||
|
||||
// Parse current minio version into RFC3339.
|
||||
current, e := time.Parse(time.RFC3339, minioVersion)
|
||||
if e != nil && noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf(probe.NewError(e), "Unable to parse version string as time.", nil)
|
||||
|
||||
// Verify if current minio version is zero.
|
||||
if current.IsZero() && !noError {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Updates not supported for custom builds. Version field is empty. Please download official releases from https://minio.io/#minio", nil)
|
||||
}
|
||||
|
||||
// Verify if we have a valid http response i.e http.StatusOK.
|
||||
if data != nil {
|
||||
if data.StatusCode != http.StatusOK {
|
||||
// Return quickly if noError is set.
|
||||
if noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf(probe.NewError(errors.New("")), "Update server responsed with "+data.Status, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// Read the response body.
|
||||
updateBody, e := ioutil.ReadAll(data.Body)
|
||||
if e != nil && noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf(probe.NewError(e), "Fetching updates failed. Please try again.", nil)
|
||||
|
||||
// Parse the date if its valid.
|
||||
latest, err := parseReleaseData(string(updateBody))
|
||||
if err != nil && noError {
|
||||
return updateMsg
|
||||
}
|
||||
fatalIf(err.Trace(updateURL), "Please report this issue at https://github.com/minio/minio/issues.", nil)
|
||||
|
||||
// Verify if the date is not zero.
|
||||
if latest.IsZero() && !noError {
|
||||
fatalIf(probe.NewError(errors.New("")),
|
||||
"Unable to validate any update available at this time. Please open an issue at https://github.com/minio/minio/issues", nil)
|
||||
}
|
||||
|
||||
// Is the update latest?.
|
||||
if latest.After(current) {
|
||||
updateMsg.Update = true
|
||||
}
|
||||
console.Println(updateMsg)
|
||||
|
||||
// Return update message.
|
||||
return updateMsg
|
||||
}
|
||||
|
||||
// main entry point for update command.
|
||||
func mainUpdate(ctx *cli.Context) {
|
||||
// Print all errors as they occur.
|
||||
noError := false
|
||||
|
||||
// Check for update.
|
||||
if ctx.Bool("experimental") {
|
||||
getReleaseUpdate(minioUpdateExperimentalURL)
|
||||
console.Println(getReleaseUpdate(minioUpdateExperimentalURL, noError))
|
||||
} else {
|
||||
getReleaseUpdate(minioUpdateStableURL)
|
||||
console.Println(getReleaseUpdate(minioUpdateStableURL, noError))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user