mirror of
https://github.com/minio/mc.git
synced 2026-01-04 02:44:40 +03:00
update ping command with new terminal UI (#4163)
This commit is contained in:
committed by
GitHub
parent
6cee296d04
commit
63d0e213c3
@@ -35,6 +35,7 @@ version manage bucket versioning
|
||||
replicate configure server side bucket replication
|
||||
admin manage MinIO servers
|
||||
update update mc to latest release
|
||||
ping perform liveness check
|
||||
```
|
||||
|
||||
## Docker Container
|
||||
|
||||
439
cmd/ping.go
439
cmd/ping.go
@@ -19,39 +19,41 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"errors"
|
||||
"math"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/fatih/color"
|
||||
"github.com/minio/cli"
|
||||
json "github.com/minio/colorjson"
|
||||
"github.com/minio/madmin-go"
|
||||
"github.com/minio/mc/pkg/probe"
|
||||
"github.com/minio/pkg/console"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
const (
|
||||
pingInterval = time.Second // keep it similar to unix ping interval
|
||||
)
|
||||
|
||||
var pingFlags = []cli.Flag{
|
||||
cli.IntFlag{
|
||||
Name: "count, c",
|
||||
Usage: "perform liveliness check for count number of times",
|
||||
Value: 4,
|
||||
},
|
||||
cli.DurationFlag{
|
||||
cli.IntFlag{
|
||||
Name: "error-count, e",
|
||||
Usage: "exit after N consecutive ping errors",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "interval, i",
|
||||
Usage: "Wait interval between each request",
|
||||
Value: pingInterval,
|
||||
Usage: "wait interval between each request in seconds",
|
||||
Value: 1,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "distributed, a",
|
||||
Usage: "ping all the servers in the cluster, use it when you have direct access to nodes/pods",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -81,10 +83,15 @@ EXAMPLES:
|
||||
{{.Prompt}} {{.HelpName}} --count 5 myminio
|
||||
|
||||
3. Return Latency and liveness with wait interval set to 30 seconds.
|
||||
{{.Prompt}} {{.HelpName}} --interval 30s myminio
|
||||
{{.Prompt}} {{.HelpName}} --interval 30 myminio
|
||||
|
||||
4. Stop pinging when error count > 20.
|
||||
{{.Prompt}} {{.HelpName}} --error-count 20 myminio
|
||||
`,
|
||||
}
|
||||
|
||||
var stop bool
|
||||
|
||||
// Validate command line arguments.
|
||||
func checkPingSyntax(cliCtx *cli.Context) {
|
||||
if !cliCtx.Args().Present() {
|
||||
@@ -92,17 +99,6 @@ func checkPingSyntax(cliCtx *cli.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// PingResult is result for each ping
|
||||
type PingResult struct {
|
||||
madmin.AliveResult
|
||||
}
|
||||
|
||||
// PingResults is result for each ping for all hosts
|
||||
type PingResults struct {
|
||||
Results map[string][]PingResult
|
||||
Final bool
|
||||
}
|
||||
|
||||
// JSON jsonified ping result message.
|
||||
func (pr PingResult) JSON() string {
|
||||
statusJSONBytes, e := json.MarshalIndent(pr, "", " ")
|
||||
@@ -111,141 +107,72 @@ func (pr PingResult) JSON() string {
|
||||
return string(statusJSONBytes)
|
||||
}
|
||||
|
||||
// String colorized ping result message.
|
||||
func (pr PingResult) String() (msg string) {
|
||||
if pr.Error == nil {
|
||||
coloredDot := console.Colorize("Info", dot)
|
||||
// Print server title
|
||||
msg += fmt.Sprintf("%s %s:", coloredDot, console.Colorize("PrintB", pr.Endpoint.String()))
|
||||
msg += fmt.Sprintf(" time=%s\n", pr.ResponseTime)
|
||||
return
|
||||
}
|
||||
coloredDot := console.Colorize("InfoFail", dot)
|
||||
msg += fmt.Sprintf("%s %s:", coloredDot, console.Colorize("PrintB", pr.Endpoint.String()))
|
||||
msg += fmt.Sprintf(" time=%s, error=%s\n", pr.ResponseTime, console.Colorize("InfoFail", pr.Error.Error()))
|
||||
|
||||
return msg
|
||||
var colorMap = template.FuncMap{
|
||||
"colorWhite": color.New(color.FgWhite).SprintfFunc(),
|
||||
"colorRed": color.New(color.FgRed).SprintfFunc(),
|
||||
}
|
||||
|
||||
type pingUI struct {
|
||||
spinner spinner.Model
|
||||
quitting bool
|
||||
results PingResults
|
||||
}
|
||||
// PingDist is the template for ping result in distributed mode
|
||||
const PingDist = `{{$x := .Counter}}{{range .EndPointsStats}}{{if eq "0" .CountErr}}{{colorWhite $x}}{{colorWhite ": "}}{{colorWhite .Endpoint.Scheme}}{{colorWhite "://"}}{{colorWhite .Endpoint.Host}}{{if ne "" .Endpoint.Port}}{{colorWhite ":"}}{{colorWhite .Endpoint.Port}}{{end}}{{"\t"}}{{ colorWhite "min="}}{{colorWhite .Min}}{{"\t"}}{{colorWhite "max="}}{{colorWhite .Max}}{{"\t"}}{{colorWhite "average="}}{{colorWhite .Average}}{{"\t"}}{{colorWhite "errors="}}{{colorWhite .CountErr}}{{"\t"}}{{colorWhite "roundtrip="}}{{colorWhite .Roundtrip}}{{else}}{{colorRed $x}}{{colorRed ": "}}{{colorRed .Endpoint.Scheme}}{{colorRed "://"}}{{colorRed .Endpoint.Host}}{{if ne "" .Endpoint.Port}}{{colorRed ":"}}{{colorRed .Endpoint.Port}}{{end}}{{"\t"}}{{ colorRed "min="}}{{colorRed .Min}}{{"\t"}}{{colorRed "max="}}{{colorRed .Max}}{{"\t"}}{{colorRed "average="}}{{colorRed .Average}}{{"\t"}}{{colorRed "errors="}}{{colorRed .CountErr}}{{"\t"}}{{colorRed "roundtrip="}}{{colorRed .Roundtrip}}{{end}}
|
||||
{{end}}`
|
||||
|
||||
func initPingUI() *pingUI {
|
||||
s := spinner.New()
|
||||
s.Spinner = spinner.Points
|
||||
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
|
||||
return &pingUI{
|
||||
spinner: s,
|
||||
}
|
||||
}
|
||||
// Ping is the template for ping result
|
||||
const Ping = `{{$x := .Counter}}{{range .EndPointsStats}}{{if eq "0" .CountErr}}{{colorWhite $x}}{{colorWhite ": "}}{{colorWhite .Endpoint.Scheme}}{{colorWhite "://"}}{{colorWhite .Endpoint.Host}}{{if ne "" .Endpoint.Port}}{{colorWhite ":"}}{{colorWhite .Endpoint.Port}}{{end}}{{"\t"}}{{ colorWhite "min="}}{{colorWhite .Min}}{{"\t"}}{{colorWhite "max="}}{{colorWhite .Max}}{{"\t"}}{{colorWhite "average="}}{{colorWhite .Average}}{{"\t"}}{{colorWhite "errors="}}{{colorWhite .CountErr}}{{"\t"}}{{colorWhite "roundtrip="}}{{colorWhite .Roundtrip}}{{else}}{{colorRed $x}}{{colorRed ": "}}{{colorRed .Endpoint.Scheme}}{{colorRed "://"}}{{colorRed .Endpoint.Host}}{{if ne "" .Endpoint.Port}}{{colorRed ":"}}{{colorRed .Endpoint.Port}}{{end}}{{"\t"}}{{ colorRed "min="}}{{colorRed .Min}}{{"\t"}}{{colorRed "max="}}{{colorRed .Max}}{{"\t"}}{{colorRed "average="}}{{colorRed .Average}}{{"\t"}}{{colorRed "errors="}}{{colorRed .CountErr}}{{"\t"}}{{colorRed "roundtrip="}}{{colorRed .Roundtrip}}{{end}}{{end}}`
|
||||
|
||||
func (m *pingUI) Init() tea.Cmd {
|
||||
return m.spinner.Tick
|
||||
}
|
||||
// PingTemplateDist - captures ping template
|
||||
var PingTemplateDist = template.Must(template.New("ping-list").Funcs(colorMap).Parse(PingDist))
|
||||
|
||||
func (m *pingUI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch msg.String() {
|
||||
case "ctrl+c":
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
default:
|
||||
return m, nil
|
||||
}
|
||||
case PingResults:
|
||||
m.results = msg
|
||||
if msg.Final {
|
||||
m.quitting = true
|
||||
return m, tea.Quit
|
||||
}
|
||||
return m, nil
|
||||
case spinner.TickMsg:
|
||||
var cmd tea.Cmd
|
||||
m.spinner, cmd = m.spinner.Update(msg)
|
||||
return m, cmd
|
||||
default:
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
// PingTemplate - captures ping template
|
||||
var PingTemplate = template.Must(template.New("ping-list").Funcs(colorMap).Parse(Ping))
|
||||
|
||||
func (m *pingUI) View() string {
|
||||
// String colorized service status message.
|
||||
func (pr PingResult) String() string {
|
||||
var s strings.Builder
|
||||
|
||||
// Set table header
|
||||
table := tablewriter.NewWriter(&s)
|
||||
table.SetAutoWrapText(false)
|
||||
table.SetAutoFormatHeaders(true)
|
||||
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetAlignment(tablewriter.ALIGN_LEFT)
|
||||
table.SetCenterSeparator("")
|
||||
table.SetColumnSeparator("")
|
||||
table.SetRowSeparator("")
|
||||
table.SetHeaderLine(false)
|
||||
table.SetBorder(false)
|
||||
table.SetTablePadding("\t") // pad with tabs
|
||||
table.SetNoWhiteSpace(true)
|
||||
|
||||
res := m.results
|
||||
|
||||
if len(res.Results) > 0 {
|
||||
s.WriteString("\n")
|
||||
}
|
||||
|
||||
trailerIfGreaterThan := func(in string, max int) string {
|
||||
if len(in) < max {
|
||||
return in
|
||||
}
|
||||
return in[:max] + "..."
|
||||
}
|
||||
|
||||
table.SetHeader([]string{"Node", "Avg-Latency", "Count", ""})
|
||||
data := make([][]string, 0, len(res.Results))
|
||||
|
||||
if len(res.Results) == 0 {
|
||||
data = append(data, []string{
|
||||
"...",
|
||||
whiteStyle.Render("-- ms"),
|
||||
whiteStyle.Render("--"),
|
||||
"",
|
||||
})
|
||||
w := tabwriter.NewWriter(&s, 1, 8, 3, ' ', 0)
|
||||
var e error
|
||||
if len(pr.EndPointsStats) > 1 {
|
||||
e = PingTemplateDist.Execute(w, pr)
|
||||
} else {
|
||||
for k, results := range res.Results {
|
||||
data = append(data, []string{
|
||||
trailerIfGreaterThan(k, 64),
|
||||
getAvgLatency(results...).String(),
|
||||
strconv.Itoa(len(results)),
|
||||
"",
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(data, func(i, j int) bool {
|
||||
return data[i][0] < data[j][0]
|
||||
})
|
||||
|
||||
table.AppendBulk(data)
|
||||
table.Render()
|
||||
}
|
||||
if !m.quitting {
|
||||
s.WriteString(fmt.Sprintf("\nPinging: %s", m.spinner.View()))
|
||||
} else {
|
||||
s.WriteString("\n")
|
||||
e = PingTemplate.Execute(w, pr)
|
||||
}
|
||||
fatalIf(probe.NewError(e), "Unable to initialize template writer")
|
||||
w.Flush()
|
||||
return s.String()
|
||||
}
|
||||
|
||||
func getAvgLatency(results ...PingResult) (avg time.Duration) {
|
||||
if len(results) == 0 {
|
||||
return avg
|
||||
}
|
||||
var totalDurationNS uint64
|
||||
for _, result := range results {
|
||||
totalDurationNS += uint64(result.ResponseTime.Nanoseconds())
|
||||
}
|
||||
return time.Duration(totalDurationNS / uint64(len(results)))
|
||||
// Endpoint - container to hold server info
|
||||
type Endpoint struct {
|
||||
Scheme string `json:"scheme"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
}
|
||||
|
||||
// EndPointStats - container to hold server ping stats
|
||||
type EndPointStats struct {
|
||||
Endpoint Endpoint `json:"endpoint"`
|
||||
Min string `json:"min"`
|
||||
Max string `json:"max"`
|
||||
Average string `json:"average"`
|
||||
CountErr string `json:"error-count,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Roundtrip string `json:"roundtrip"`
|
||||
}
|
||||
|
||||
// PingResult contains ping output
|
||||
type PingResult struct {
|
||||
Status string `json:"status"`
|
||||
Counter string `json:"counter"`
|
||||
EndPointsStats []EndPointStats `json:"servers"`
|
||||
}
|
||||
|
||||
type serverStats struct {
|
||||
min uint64
|
||||
max uint64
|
||||
sum uint64
|
||||
avg uint64
|
||||
errorCount int // used to keep a track of consecutive errors
|
||||
err string
|
||||
counter int // used to find the average, acts as denominator
|
||||
}
|
||||
|
||||
func fetchAdminInfo(admClnt *madmin.AdminClient) (madmin.InfoMessage, error) {
|
||||
@@ -264,12 +191,151 @@ func fetchAdminInfo(admClnt *madmin.AdminClient) (madmin.InfoMessage, error) {
|
||||
if e == nil {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
timer.Reset(time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ping(ctx context.Context, cliCtx *cli.Context, anonClient *madmin.AnonymousClient, admInfo madmin.InfoMessage, endPointMap map[string]serverStats, index int) {
|
||||
var endPointStats []EndPointStats
|
||||
var servers []madmin.ServerProperties
|
||||
if cliCtx.Bool("distributed") {
|
||||
servers = admInfo.Servers
|
||||
}
|
||||
|
||||
for result := range anonClient.Alive(ctx, madmin.AliveOpts{}, servers...) {
|
||||
host, port, _ := extractHostPort(result.Endpoint.String())
|
||||
endPoint := Endpoint{result.Endpoint.Scheme, host, port}
|
||||
stat := getPingInfo(cliCtx, result, endPointMap)
|
||||
endPointStat := EndPointStats{
|
||||
Endpoint: endPoint,
|
||||
Min: time.Duration(stat.min).Round(time.Microsecond).String(),
|
||||
Max: time.Duration(stat.max).Round(time.Microsecond).String(),
|
||||
Average: time.Duration(stat.avg).Round(time.Microsecond).String(),
|
||||
CountErr: strconv.Itoa(stat.errorCount),
|
||||
Error: stat.err,
|
||||
Roundtrip: result.ResponseTime.Round(time.Microsecond).String(),
|
||||
}
|
||||
endPointStats = append(endPointStats, endPointStat)
|
||||
endPointMap[result.Endpoint.Host] = stat
|
||||
|
||||
}
|
||||
printMsg(PingResult{
|
||||
Status: "success",
|
||||
Counter: strconv.Itoa(index),
|
||||
EndPointsStats: endPointStats,
|
||||
})
|
||||
|
||||
time.Sleep(time.Duration(cliCtx.Int("interval")) * time.Second)
|
||||
}
|
||||
|
||||
func getPingInfo(cliCtx *cli.Context, result madmin.AliveResult, serverMap map[string]serverStats) serverStats {
|
||||
var errorString string
|
||||
var sum, avg uint64
|
||||
min := uint64(math.MaxUint64)
|
||||
var max uint64
|
||||
var counter, errorCount int
|
||||
|
||||
if result.Error != nil {
|
||||
errorString = result.Error.Error()
|
||||
if stat, ok := serverMap[result.Endpoint.Host]; ok {
|
||||
min = stat.min
|
||||
max = stat.max
|
||||
sum = stat.sum
|
||||
counter = stat.counter
|
||||
avg = stat.avg
|
||||
errorCount = stat.errorCount + 1
|
||||
|
||||
} else {
|
||||
min = 0
|
||||
errorCount = 1
|
||||
}
|
||||
if cliCtx.IsSet("error-count") && errorCount >= cliCtx.Int("error-count") {
|
||||
stop = true
|
||||
}
|
||||
|
||||
} else {
|
||||
// reset consecutive error count
|
||||
errorCount = 0
|
||||
if stat, ok := serverMap[result.Endpoint.Host]; ok {
|
||||
var minVal uint64
|
||||
if stat.min == 0 {
|
||||
minVal = uint64(result.ResponseTime)
|
||||
} else {
|
||||
minVal = stat.min
|
||||
}
|
||||
min = uint64(math.Min(float64(minVal), float64(uint64(result.ResponseTime))))
|
||||
max = uint64(math.Max(float64(stat.max), float64(uint64(result.ResponseTime))))
|
||||
sum = stat.sum + uint64(result.ResponseTime.Nanoseconds())
|
||||
counter = stat.counter + 1
|
||||
|
||||
} else {
|
||||
min = uint64(math.Min(float64(min), float64(uint64(result.ResponseTime))))
|
||||
max = uint64(math.Max(float64(max), float64(uint64(result.ResponseTime))))
|
||||
sum = uint64(result.ResponseTime)
|
||||
counter = 1
|
||||
}
|
||||
avg = sum / uint64(counter)
|
||||
}
|
||||
return serverStats{min, max, sum, avg, errorCount, errorString, counter}
|
||||
}
|
||||
|
||||
// extractHostPort - extracts host/port from many address formats
|
||||
// such as, ":9000", "localhost:9000", "http://localhost:9000/"
|
||||
func extractHostPort(hostAddr string) (string, string, error) {
|
||||
var addr, scheme string
|
||||
|
||||
if hostAddr == "" {
|
||||
return "", "", errors.New("unable to process empty address")
|
||||
}
|
||||
|
||||
// Simplify the work of url.Parse() and always send a url with
|
||||
if !strings.HasPrefix(hostAddr, "http://") && !strings.HasPrefix(hostAddr, "https://") {
|
||||
hostAddr = "//" + hostAddr
|
||||
}
|
||||
|
||||
// Parse address to extract host and scheme field
|
||||
u, err := url.Parse(hostAddr)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
addr = u.Host
|
||||
scheme = u.Scheme
|
||||
|
||||
// Use the given parameter again if url.Parse()
|
||||
// didn't return any useful result.
|
||||
if addr == "" {
|
||||
addr = hostAddr
|
||||
scheme = "http"
|
||||
}
|
||||
|
||||
// At this point, addr can be one of the following form:
|
||||
// ":9000"
|
||||
// "localhost:9000"
|
||||
// "localhost" <- in this case, we check for scheme
|
||||
|
||||
host, port, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "missing port in address") {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
host = addr
|
||||
|
||||
switch scheme {
|
||||
case "https":
|
||||
port = "443"
|
||||
case "http":
|
||||
port = "80"
|
||||
default:
|
||||
return "", "", errors.New("unable to guess port from scheme")
|
||||
}
|
||||
}
|
||||
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
// mainPing is entry point for ping command.
|
||||
func mainPing(cliCtx *cli.Context) error {
|
||||
// check 'ping' cli arguments.
|
||||
@@ -282,61 +348,46 @@ func mainPing(cliCtx *cli.Context) error {
|
||||
defer cancel()
|
||||
|
||||
aliasedURL := cliCtx.Args().Get(0)
|
||||
|
||||
count := cliCtx.Int("count")
|
||||
if count < 1 {
|
||||
fatalIf(errInvalidArgument().Trace(cliCtx.Args()...), "ping count cannot be less than 1")
|
||||
}
|
||||
|
||||
interval := cliCtx.Duration("interval")
|
||||
|
||||
admClient, err := newAdminClient(aliasedURL)
|
||||
fatalIf(err.Trace(aliasedURL), "Unable to initialize admin client for `"+aliasedURL+"`.")
|
||||
|
||||
anonClient, err := newAnonymousClient(aliasedURL)
|
||||
fatalIf(err.Trace(aliasedURL), "Unable to initialize anonymous client for `"+aliasedURL+"`.")
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
ui := tea.NewProgram(initPingUI())
|
||||
if !globalJSON {
|
||||
go func() {
|
||||
if e := ui.Start(); e != nil {
|
||||
cancel()
|
||||
os.Exit(1)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
}
|
||||
|
||||
admInfo, e := fetchAdminInfo(admClient)
|
||||
fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to get server info")
|
||||
|
||||
pingResults := PingResults{
|
||||
Results: make(map[string][]PingResult),
|
||||
}
|
||||
for i := 0; i < count; i++ {
|
||||
for result := range anonClient.Alive(ctx, madmin.AliveOpts{}, admInfo.Servers...) {
|
||||
if globalJSON {
|
||||
printMsg(PingResult{result})
|
||||
} else {
|
||||
hostResults, ok := pingResults.Results[result.Endpoint.Host]
|
||||
if !ok {
|
||||
pingResults.Results[result.Endpoint.Host] = []PingResult{{result}}
|
||||
} else {
|
||||
hostResults = append(hostResults, PingResult{result})
|
||||
pingResults.Results[result.Endpoint.Host] = hostResults
|
||||
// map to contain server stats for all the servers
|
||||
serverMap := make(map[string]serverStats)
|
||||
|
||||
index := 1
|
||||
if cliCtx.IsSet("count") {
|
||||
count := cliCtx.Int("count")
|
||||
if count < 1 {
|
||||
fatalIf(errInvalidArgument().Trace(cliCtx.Args()...), "ping count cannot be less than 1")
|
||||
}
|
||||
for index <= count {
|
||||
// return if consecutive error count more then specified value
|
||||
if stop {
|
||||
return nil
|
||||
}
|
||||
ping(ctx, cliCtx, anonClient, admInfo, serverMap, index)
|
||||
index++
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
select {
|
||||
case <-globalContext.Done():
|
||||
return globalContext.Err()
|
||||
default:
|
||||
// return if consecutive error count more then specified value
|
||||
if stop {
|
||||
return nil
|
||||
}
|
||||
ui.Send(pingResults)
|
||||
ping(ctx, cliCtx, anonClient, admInfo, serverMap, index)
|
||||
index++
|
||||
}
|
||||
}
|
||||
time.Sleep(interval)
|
||||
}
|
||||
if !globalJSON {
|
||||
pingResults.Final = true
|
||||
ui.Send(pingResults)
|
||||
|
||||
<-done
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ replicate configure server side bucket replication
|
||||
admin manage MinIO servers
|
||||
update update mc to latest release
|
||||
support supportability tools like profile, register, callhome, inspect
|
||||
ping perform liveness check
|
||||
```
|
||||
|
||||
## 1. Download MinIO Client
|
||||
@@ -325,10 +326,11 @@ mc version RELEASE.2020-04-25T00-43-23Z
|
||||
| [**update** - manage software updates](#update) | [**watch** - watch for events](#watch) | [**retention** - set retention for object(s)](#retention) | [**sql** - run sql queries on objects](#sql) |
|
||||
| [**head** - display first 'n' lines of an object](#head) | [**stat** - stat contents of objects and folders](#stat) | [**legalhold** - set legal hold for object(s)](#legalhold) | [**mv** - move objects](#mv) |
|
||||
| [**du** - summarize disk usage recursively](#du) | [**tag** - manage tags for bucket and object(s)](#tag) | [**admin** - manage MinIO servers](#admin) | [**support** - generate profile data for debugging purposes](#support) |
|
||||
| [**ping** - perform liveness check](#ping) | | | |
|
||||
|
||||
|
||||
|
||||
### Command `ls`
|
||||
### Command `ls`
|
||||
`ls` command lists files, buckets and objects. Use `--incomplete` flag to list partially copied content.
|
||||
|
||||
```
|
||||
@@ -1964,4 +1966,33 @@ mc support logs show --last 5 --type application myminio node1
|
||||
Enable logs for cluster with alias 'play'
|
||||
```
|
||||
mc support logs enable play
|
||||
```
|
||||
```
|
||||
|
||||
|
||||
<a name="ping"></a>
|
||||
### Command `ping`
|
||||
`rb` command to perform liveness check
|
||||
|
||||
```
|
||||
USAGE:
|
||||
mc ping [FLAGS] TARGET
|
||||
|
||||
FLAGS:
|
||||
--count value, -c value perform liveliness check for count number of times (default: 0)
|
||||
--error-count value, -e value exit after N consecutive ping errors
|
||||
--interval value, -i value wait interval between each request in seconds (default: 1)
|
||||
--distributed, -a ping all the servers in the cluster, use it when you have direct access to nodes/pods
|
||||
--help, -h show help
|
||||
|
||||
|
||||
```
|
||||
|
||||
*Example: Perform liveness check on https://play.min.io.*
|
||||
|
||||
|
||||
```
|
||||
mc ping play
|
||||
1: https://play.min.io: min=919.538ms max=919.538ms average=919.538ms errors=0 roundtrip=919.538ms
|
||||
2: https://play.min.io: min=278.356ms max=919.538ms average=598.947ms errors=0 roundtrip=278.356ms
|
||||
3: https://play.min.io: min=278.356ms max=919.538ms average=504.759ms errors=0 roundtrip=316.384ms
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user