github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/replicate-list.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  	"errors"
    23  	"fmt"
    24  	"strings"
    25  
    26  	"github.com/fatih/color"
    27  	"github.com/minio/cli"
    28  	json "github.com/minio/colorjson"
    29  	"github.com/minio/madmin-go/v3"
    30  	"github.com/minio/mc/pkg/probe"
    31  	"github.com/minio/minio-go/v7/pkg/replication"
    32  	"github.com/minio/pkg/v2/console"
    33  )
    34  
    35  var replicateListFlags = []cli.Flag{
    36  	cli.StringFlag{
    37  		Name:  "status",
    38  		Usage: "show rules by status. Valid options are [enabled,disabled]",
    39  	},
    40  }
    41  
    42  var replicateListCmd = cli.Command{
    43  	Name:         "list",
    44  	ShortName:    "ls",
    45  	Usage:        "list server side replication configuration rules",
    46  	Action:       mainReplicateList,
    47  	OnUsageError: onUsageError,
    48  	Before:       setGlobalsFromContext,
    49  	Flags:        append(globalFlags, replicateListFlags...),
    50  	CustomHelpTemplate: `NAME:
    51    {{.HelpName}} - {{.Usage}}
    52  
    53  USAGE:
    54    {{.HelpName}} TARGET
    55  
    56  FLAGS:
    57    {{range .VisibleFlags}}{{.}}
    58    {{end}}
    59  EXAMPLES:
    60    1. List server side replication configuration rules on bucket "mybucket" for alias "myminio".
    61       {{.Prompt}} {{.HelpName}} myminio/mybucket
    62  `,
    63  }
    64  
    65  // checkReplicateListSyntax - validate all the passed arguments
    66  func checkReplicateListSyntax(ctx *cli.Context) {
    67  	if len(ctx.Args()) != 1 {
    68  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
    69  	}
    70  }
    71  
    72  func printReplicateListHeader() {
    73  	if globalJSON {
    74  		return
    75  	}
    76  	console.Println(console.Colorize("Headers", "Rules:"))
    77  }
    78  
    79  type replicateListMessage struct {
    80  	Op      string           `json:"op"`
    81  	Status  string           `json:"status"`
    82  	URL     string           `json:"url"`
    83  	Rule    replication.Rule `json:"rule"`
    84  	targets []madmin.BucketTarget
    85  }
    86  
    87  func (l replicateListMessage) JSON() string {
    88  	l.Status = "success"
    89  	jsonMessageBytes, e := json.MarshalIndent(l, "", " ")
    90  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
    91  	return string(jsonMessageBytes)
    92  }
    93  
    94  func (l replicateListMessage) String() string {
    95  	r := l.Rule
    96  	destBucket := r.Destination.Bucket
    97  	if arn, err := madmin.ParseARN(r.Destination.Bucket); err == nil {
    98  		destBucket = arn.Bucket
    99  	}
   100  	endpoint := r.Destination.Bucket
   101  	for _, t := range l.targets {
   102  		if t.Arn == r.Destination.Bucket {
   103  			endpoint = t.Endpoint
   104  			break
   105  		}
   106  	}
   107  	var sb strings.Builder
   108  	sb.WriteString(console.Colorize("Key", "Remote Bucket: "))
   109  
   110  	sb.WriteString(console.Colorize("EpVal", fmt.Sprintf("%s/%s\n", endpoint, destBucket)))
   111  
   112  	sb.WriteString(fmt.Sprintf("  Rule ID: %s\n", console.Colorize("Val", r.ID)))
   113  	sb.WriteString(fmt.Sprintf("  Priority: %s\n", console.Colorize("Val", r.Priority)))
   114  	if r.Filter.And.Prefix != "" {
   115  		sb.WriteString(fmt.Sprintf("  Prefix: %s\n", console.Colorize("Val", r.Filter.And.Prefix)))
   116  	}
   117  	if r.Tags() != "" {
   118  		sb.WriteString(fmt.Sprintf("  Tags: %s\n", console.Colorize("Val", r.Tags())))
   119  	}
   120  	if r.Destination.StorageClass != "" && r.Destination.StorageClass != "STANDARD" {
   121  		sb.WriteString(fmt.Sprintf("  StorageClass: %s\n", console.Colorize("Val", r.Destination.StorageClass)))
   122  	}
   123  	return sb.String() + "\n"
   124  }
   125  
   126  func mainReplicateList(cliCtx *cli.Context) error {
   127  	ctx, cancelReplicateList := context.WithCancel(globalContext)
   128  	defer cancelReplicateList()
   129  
   130  	console.SetColor("Headers", color.New(color.Bold, color.FgHiGreen))
   131  	console.SetColor("Key", color.New(color.Bold, color.FgWhite))
   132  
   133  	console.SetColor("Val", color.New(color.Bold, color.FgCyan))
   134  	console.SetColor("EpVal", color.New(color.Bold, color.FgYellow))
   135  
   136  	checkReplicateListSyntax(cliCtx)
   137  
   138  	// Get the alias parameter from cli
   139  	args := cliCtx.Args()
   140  	aliasedURL := args.Get(0)
   141  	// Create a new Client
   142  	client, err := newClient(aliasedURL)
   143  	fatalIf(err, "Unable to initialize connection.")
   144  	rCfg, err := client.GetReplication(ctx)
   145  	fatalIf(err.Trace(args...), "Unable to get replication configuration")
   146  
   147  	if rCfg.Empty() {
   148  		fatalIf(probe.NewError(errors.New("replication configuration not set")).Trace(aliasedURL),
   149  			"Unable to list replication configuration")
   150  	}
   151  	printReplicateListHeader()
   152  	// Create a new MinIO Admin Client
   153  	admClient, cerr := newAdminClient(aliasedURL)
   154  	fatalIf(cerr, "Unable to initialize admin connection.")
   155  	_, sourceBucket := url2Alias(args[0])
   156  	targets, e := admClient.ListRemoteTargets(globalContext, sourceBucket, "")
   157  	fatalIf(probe.NewError(e).Trace(args...), "Unable to fetch remote target.")
   158  
   159  	statusFlag := cliCtx.String("status")
   160  	for _, rule := range rCfg.Rules {
   161  		if statusFlag == "" || strings.EqualFold(statusFlag, string(rule.Status)) {
   162  			printMsg(replicateListMessage{
   163  				Rule:    rule,
   164  				targets: targets,
   165  			})
   166  		}
   167  	}
   168  
   169  	return nil
   170  }