github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/admin-replicate-update.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  	"net/url"
    22  	"strings"
    23  
    24  	"github.com/fatih/color"
    25  	"github.com/minio/cli"
    26  	json "github.com/minio/colorjson"
    27  	"github.com/minio/madmin-go/v3"
    28  	"github.com/minio/mc/pkg/probe"
    29  	"github.com/minio/pkg/v2/console"
    30  )
    31  
    32  var adminReplicateUpdateFlags = []cli.Flag{
    33  	cli.StringFlag{
    34  		Name:  "deployment-id",
    35  		Usage: "deployment id of the site, should be a unique value",
    36  	},
    37  	cli.StringFlag{
    38  		Name:  "endpoint",
    39  		Usage: "endpoint for the site",
    40  	},
    41  	cli.StringFlag{
    42  		Name:  "mode",
    43  		Usage: "change mode of replication for this target, valid values are ['sync', 'async'].",
    44  		Value: "",
    45  	},
    46  	cli.StringFlag{
    47  		Name:   "sync",
    48  		Usage:  "enable synchronous replication for this target, valid values are ['enable', 'disable'].",
    49  		Value:  "disable",
    50  		Hidden: true, // deprecated Jul 2023
    51  	},
    52  	cli.StringFlag{
    53  		Name:  "bucket-bandwidth",
    54  		Usage: "Set default bandwidth limit for bucket in bits per second (K,B,G,T for metric and Ki,Bi,Gi,Ti for IEC units)",
    55  	},
    56  	cli.BoolFlag{
    57  		Name:  "disable-ilm-expiry-replication",
    58  		Usage: "disable ILM expiry rules replication",
    59  	},
    60  	cli.BoolFlag{
    61  		Name:  "enable-ilm-expiry-replication",
    62  		Usage: "enable ILM expiry rules replication",
    63  	},
    64  }
    65  
    66  var adminReplicateUpdateCmd = cli.Command{
    67  	Name:          "update",
    68  	Aliases:       []string{"edit"},
    69  	HiddenAliases: true,
    70  	Usage:         "modify endpoint of site participating in site replication",
    71  	Action:        mainAdminReplicateUpdate,
    72  	OnUsageError:  onUsageError,
    73  	Before:        setGlobalsFromContext,
    74  	Flags:         append(globalFlags, adminReplicateUpdateFlags...),
    75  	CustomHelpTemplate: `NAME:
    76    {{.HelpName}} - {{.Usage}}
    77  
    78  USAGE:
    79    {{.HelpName}} ALIAS --deployment-id [DEPLOYMENT-ID] --endpoint [NEW-ENDPOINT]
    80  
    81  FLAGS:
    82    {{range .VisibleFlags}}{{.}}
    83    {{end}}
    84  
    85  EXAMPLES:
    86    1. Edit a site endpoint participating in cluster-level replication:
    87       {{.Prompt}} {{.HelpName}} myminio --deployment-id c1758167-4426-454f-9aae-5c3dfdf6df64 --endpoint https://minio2:9000
    88  
    89    2. Set default bucket bandwidth limit for replication from myminio to the peer cluster with deployment-id c1758167-4426-454f-9aae-5c3dfdf6df64
    90       {{.Prompt}} {{.HelpName}} myminio --deployment-id c1758167-4426-454f-9aae-5c3dfdf6df64 --bucket-bandwidth "2G"
    91  
    92    3. Disable replication of ILM expiry in cluster-level replication:
    93       {{.Prompt}} {{.HelpName}} myminio --disable-ilm-expiry-replication
    94  
    95    4. Enable replication of ILM expiry in cluster-level replication:
    96       {{.Prompt}} {{.HelpName}} myminio --enable-ilm-expiry-replication
    97  `,
    98  }
    99  
   100  type updateSuccessMessage madmin.ReplicateEditStatus
   101  
   102  func (m updateSuccessMessage) JSON() string {
   103  	bs, e := json.MarshalIndent(madmin.ReplicateEditStatus(m), "", " ")
   104  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
   105  	return string(bs)
   106  }
   107  
   108  func (m updateSuccessMessage) String() string {
   109  	v := madmin.ReplicateEditStatus(m)
   110  	messages := []string{v.Status}
   111  
   112  	if v.ErrDetail != "" {
   113  		messages = append(messages, v.ErrDetail)
   114  	}
   115  	return console.Colorize("UserMessage", strings.Join(messages, "\n"))
   116  }
   117  
   118  func checkAdminReplicateUpdateSyntax(ctx *cli.Context) {
   119  	// Check argument count
   120  	argsNr := len(ctx.Args())
   121  	if argsNr < 1 {
   122  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
   123  	}
   124  	if argsNr != 1 {
   125  		fatalIf(errInvalidArgument().Trace(ctx.Args().Tail()...),
   126  			"Invalid arguments specified for edit command.")
   127  	}
   128  }
   129  
   130  func mainAdminReplicateUpdate(ctx *cli.Context) error {
   131  	checkAdminReplicateUpdateSyntax(ctx)
   132  	console.SetColor("UserMessage", color.New(color.FgGreen))
   133  
   134  	// Get the alias parameter from cli
   135  	args := ctx.Args()
   136  	aliasedURL := args.Get(0)
   137  
   138  	// Create a new MinIO Admin Client
   139  	client, err := newAdminClient(aliasedURL)
   140  	fatalIf(err, "Unable to initialize admin connection.")
   141  
   142  	if !ctx.IsSet("deployment-id") && !ctx.IsSet("disable-ilm-expiry-replication") && !ctx.IsSet("enable-ilm-expiry-replication") {
   143  		fatalIf(errInvalidArgument(), "--deployment-id is a required flag")
   144  	}
   145  	if !ctx.IsSet("endpoint") && !ctx.IsSet("mode") && !ctx.IsSet("sync") && !ctx.IsSet("bucket-bandwidth") && !ctx.IsSet("disable-ilm-expiry-replication") && !ctx.IsSet("enable-ilm-expiry-replication") {
   146  		fatalIf(errInvalidArgument(), "--endpoint, --mode, --bucket-bandwidth, --disable-ilm-expiry-replication or --enable-ilm-expiry-replication is a required flag")
   147  	}
   148  	if ctx.IsSet("mode") && ctx.IsSet("sync") {
   149  		fatalIf(errInvalidArgument(), "either --sync or --mode flag should be specified")
   150  	}
   151  	if ctx.IsSet("disable-ilm-expiry-replication") && ctx.IsSet("enable-ilm-expiry-replication") {
   152  		fatalIf(errInvalidArgument(), "either --disable-ilm-expiry-replication or --enable-ilm-expiry-replication flag should be specified")
   153  	}
   154  	if (ctx.IsSet("disable-ilm-expiry-replication") || ctx.IsSet("enable-ilm-expiry-replication")) && ctx.IsSet("deployment-id") {
   155  		fatalIf(errInvalidArgument(), "--deployment-id should not be set with --disable-ilm-expiry-replication or --enable-ilm-expiry-replication")
   156  	}
   157  
   158  	var syncState string
   159  	if ctx.IsSet("sync") { // for backward compatibility - deprecated Jul 2023
   160  		syncState = strings.ToLower(ctx.String("sync"))
   161  		switch syncState {
   162  		case "enable", "disable":
   163  		default:
   164  			fatalIf(errInvalidArgument().Trace(args...), "--sync can be either [enable|disable]")
   165  		}
   166  	}
   167  
   168  	if ctx.IsSet("mode") {
   169  		mode := strings.ToLower(ctx.String("mode"))
   170  		switch mode {
   171  		case "sync":
   172  			syncState = "enable"
   173  		case "async":
   174  			syncState = "disable"
   175  		default:
   176  			fatalIf(errInvalidArgument().Trace(args...), "--mode can be either [sync|async]")
   177  		}
   178  	}
   179  
   180  	var bwDefaults madmin.BucketBandwidth
   181  	if ctx.IsSet("bucket-bandwidth") {
   182  		bandwidthStr := ctx.String("bucket-bandwidth")
   183  		bandwidth, e := getBandwidthInBytes(bandwidthStr)
   184  		fatalIf(probe.NewError(e).Trace(bandwidthStr), "invalid bandwidth value")
   185  
   186  		bwDefaults.Limit = bandwidth
   187  		bwDefaults.IsSet = true
   188  	}
   189  	var ep string
   190  	if ctx.IsSet("endpoint") {
   191  		parsedURL := ctx.String("endpoint")
   192  		u, e := url.Parse(parsedURL)
   193  		if e != nil {
   194  			fatalIf(errInvalidArgument().Trace(parsedURL), "Unsupported URL format %v", e)
   195  		}
   196  		ep = u.String()
   197  	}
   198  	var opts madmin.SREditOptions
   199  	opts.DisableILMExpiryReplication = ctx.Bool("disable-ilm-expiry-replication")
   200  	opts.EnableILMExpiryReplication = ctx.Bool("enable-ilm-expiry-replication")
   201  	res, e := client.SiteReplicationEdit(globalContext, madmin.PeerInfo{
   202  		DeploymentID:     ctx.String("deployment-id"),
   203  		Endpoint:         ep,
   204  		SyncState:        madmin.SyncStatus(syncState),
   205  		DefaultBandwidth: bwDefaults,
   206  	}, opts)
   207  	fatalIf(probe.NewError(e).Trace(args...), "Unable to edit cluster replication site endpoint")
   208  
   209  	printMsg(updateSuccessMessage(res))
   210  
   211  	return nil
   212  }