github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/replicate-reset-status.go (about)

     1  // Copyright (c) 2015-2022 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  
    24  	humanize "github.com/dustin/go-humanize"
    25  	"github.com/fatih/color"
    26  	"github.com/minio/cli"
    27  	json "github.com/minio/colorjson"
    28  	"github.com/minio/mc/pkg/probe"
    29  	"github.com/minio/minio-go/v7/pkg/replication"
    30  	"github.com/minio/pkg/v2/console"
    31  )
    32  
    33  var replicateResyncStatusFlags = []cli.Flag{
    34  	cli.StringFlag{
    35  		Name:  "remote-bucket",
    36  		Usage: "remote bucket ARN",
    37  	},
    38  }
    39  
    40  var replicateResyncStatusCmd = cli.Command{
    41  	Name:         "status",
    42  	Usage:        "status of replication recovery",
    43  	Action:       mainreplicateResyncStatus,
    44  	OnUsageError: onUsageError,
    45  	Before:       setGlobalsFromContext,
    46  	Flags:        append(globalFlags, replicateResyncStatusFlags...),
    47  	CustomHelpTemplate: `NAME:
    48     {{.HelpName}} - {{.Usage}}
    49  
    50  USAGE:
    51     {{.HelpName}} TARGET
    52  
    53  FLAGS:
    54     {{range .VisibleFlags}}{{.}}
    55     {{end}}
    56  EXAMPLES:
    57    1. Status of replication resync in bucket "mybucket" under alias "myminio" for all targets.
    58     {{.Prompt}} {{.HelpName}} myminio/mybucket
    59  
    60    2. Status of replication resync in bucket "mybucket" under specific remote bucket target.
    61     {{.Prompt}} {{.HelpName}} myminio/mybucket --remote-bucket "arn:minio:replication::xxx:mybucket"
    62  `,
    63  }
    64  
    65  // checkreplicateResyncStatusSyntax - validate all the passed arguments
    66  func checkreplicateResyncStatusSyntax(ctx *cli.Context) {
    67  	if len(ctx.Args()) != 1 {
    68  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
    69  	}
    70  }
    71  
    72  type replicateResyncStatusMessage struct {
    73  	Op                string                        `json:"op"`
    74  	URL               string                        `json:"url"`
    75  	ResyncTargetsInfo replication.ResyncTargetsInfo `json:"resyncInfo"`
    76  	Status            string                        `json:"status"`
    77  	TargetArn         string                        `json:"targetArn"`
    78  }
    79  
    80  func (r replicateResyncStatusMessage) JSON() string {
    81  	r.Status = "success"
    82  	jsonMessageBytes, e := json.MarshalIndent(r, "", " ")
    83  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
    84  	return string(jsonMessageBytes)
    85  }
    86  
    87  func (r replicateResyncStatusMessage) String() string {
    88  	if len(r.ResyncTargetsInfo.Targets) == 0 {
    89  		return console.Colorize("replicateResyncStatusWarn", "No replication resync status available.")
    90  	}
    91  	coloredDot := console.Colorize("Headers", dot)
    92  	var rows string
    93  	rows += console.Colorize("TDetail", "Resync status summary:")
    94  
    95  	for _, st := range r.ResyncTargetsInfo.Targets {
    96  		rows += "\n"
    97  		rows += console.Colorize("replicateResyncStatusMsg", newPrettyTable(" | ",
    98  			Field{"ARN", 120},
    99  		).buildRow(fmt.Sprintf("%s %s", coloredDot, st.Arn)))
   100  		rows += "\n"
   101  		rows += console.Colorize("TDetail", "   Status: ")
   102  		rows += console.Colorize(st.ResyncStatus, st.ResyncStatus)
   103  		rows += "\n"
   104  
   105  		maxLen := 15
   106  		theme := []string{"Replicated", "Failed"}
   107  		rows += console.Colorize("THeaders", newPrettyTable(" | ",
   108  			Field{"Status", 21},
   109  			Field{"Size", maxLen},
   110  			Field{"Count", maxLen},
   111  		).buildRow("   Replication Status", "Size (Bytes)", "Count"))
   112  		rows += "\n"
   113  		rows += console.Colorize(theme[0], newPrettyTable(" | ",
   114  			Field{"Status", 21},
   115  			Field{"Size", maxLen},
   116  			Field{"Count", maxLen},
   117  		).buildRow("   Replicated", humanize.IBytes(uint64(st.ReplicatedSize)), humanize.Comma(int64(st.ReplicatedCount))))
   118  		rows += "\n"
   119  		rows += console.Colorize(theme[0], newPrettyTable(" | ",
   120  			Field{"Status", 21},
   121  			Field{"Size", maxLen},
   122  			Field{"Count", maxLen},
   123  		).buildRow("   Failed", humanize.IBytes(uint64(st.FailedSize)), humanize.Comma(int64(st.FailedCount))))
   124  		rows += "\n"
   125  	}
   126  	return rows
   127  }
   128  
   129  func mainreplicateResyncStatus(cliCtx *cli.Context) error {
   130  	ctx, cancelreplicateResyncStatus := context.WithCancel(globalContext)
   131  	defer cancelreplicateResyncStatus()
   132  
   133  	console.SetColor("replicateResyncStatusWarn", color.New(color.FgHiYellow))
   134  	console.SetColor("replicateResyncStatusMsg", color.New(color.FgGreen))
   135  	console.SetColor("Headers", color.New(color.FgGreen, color.Bold))
   136  	console.SetColor("THeaders", color.New(color.Bold, color.FgCyan))
   137  
   138  	console.SetColor("TDetail", color.New(color.FgWhite, color.Bold))
   139  	console.SetColor("Ongoing", color.New(color.Bold, color.FgYellow))
   140  	console.SetColor("Failed", color.New(color.Bold, color.FgRed))
   141  	console.SetColor("Completed", color.New(color.Bold, color.FgGreen))
   142  
   143  	checkreplicateResyncStatusSyntax(cliCtx)
   144  
   145  	// Get the alias parameter from cli
   146  	args := cliCtx.Args()
   147  	aliasedURL := args.Get(0)
   148  	// Create a new Client
   149  	client, err := newClient(aliasedURL)
   150  	fatalIf(err, "Unable to initialize connection.")
   151  
   152  	rinfo, err := client.ReplicationResyncStatus(ctx, cliCtx.String("remote-bucket"))
   153  	fatalIf(err.Trace(args...), "Unable to get replication resync status")
   154  	printMsg(replicateResyncStatusMessage{
   155  		Op:                cliCtx.Command.Name,
   156  		URL:               aliasedURL,
   157  		ResyncTargetsInfo: rinfo,
   158  		TargetArn:         cliCtx.String("remote-bucket"),
   159  	})
   160  	return nil
   161  }