github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/admin-config-history.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  	"strings"
    22  	"text/tabwriter"
    23  	"text/template"
    24  
    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/pkg/v2/console"
    30  )
    31  
    32  var historyListFlags = []cli.Flag{
    33  	cli.IntFlag{
    34  		Name:  "count, n",
    35  		Usage: "list only last 'n' entries",
    36  		Value: 10,
    37  	},
    38  	cli.BoolFlag{
    39  		Name:  "clear, c",
    40  		Usage: "clear all history",
    41  	},
    42  }
    43  
    44  var adminConfigHistoryCmd = cli.Command{
    45  	Name:         "history",
    46  	Usage:        "show all historic configuration changes",
    47  	Before:       setGlobalsFromContext,
    48  	Action:       mainAdminConfigHistory,
    49  	OnUsageError: onUsageError,
    50  	Flags:        append(append([]cli.Flag{}, globalFlags...), historyListFlags...),
    51  	CustomHelpTemplate: `NAME:
    52    {{.HelpName}} - {{.Usage}}
    53  
    54  USAGE:
    55    {{.HelpName}} TARGET
    56  
    57  FLAGS:
    58    {{range .VisibleFlags}}{{.}}
    59    {{end}}
    60  EXAMPLES:
    61    1. List all history entries sorted by time.
    62       {{.Prompt}} {{.HelpName}} play/
    63  `,
    64  }
    65  
    66  // History template used by all sub-systems
    67  const History = `{{range .}}{{colorYellowBold "RestoreId:"}} {{colorYellowBold .RestoreID}}
    68  Date: {{.CreateTime}}
    69  
    70  {{.Targets}}
    71  
    72  {{end}}`
    73  
    74  // HistoryTemplate - captures history list template
    75  var HistoryTemplate = template.Must(template.New("history-list").Funcs(funcMap).Parse(History))
    76  
    77  type historyEntry struct {
    78  	RestoreID  string `json:"restoreId"`
    79  	CreateTime string `json:"createTime"`
    80  	Targets    string `json:"targets"`
    81  }
    82  
    83  // configHistoryMessage container to hold locks information.
    84  type configHistoryMessage struct {
    85  	Status  string         `json:"status"`
    86  	Entries []historyEntry `json:"entries"`
    87  }
    88  
    89  // String colorized service status message.
    90  func (u configHistoryMessage) String() string {
    91  	var s strings.Builder
    92  	w := tabwriter.NewWriter(&s, 1, 8, 2, ' ', 0)
    93  	e := HistoryTemplate.Execute(w, u.Entries)
    94  	fatalIf(probe.NewError(e), "Unable to initialize template writer")
    95  
    96  	w.Flush()
    97  	return s.String()
    98  }
    99  
   100  // JSON jsonified service status Message message.
   101  func (u configHistoryMessage) JSON() string {
   102  	u.Status = "success"
   103  	statusJSONBytes, e := json.MarshalIndent(u, "", " ")
   104  	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
   105  
   106  	return string(statusJSONBytes)
   107  }
   108  
   109  // checkAdminConfigHistorySyntax - validate all the passed arguments
   110  func checkAdminConfigHistorySyntax(ctx *cli.Context) {
   111  	if !ctx.Args().Present() || len(ctx.Args()) > 1 {
   112  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
   113  	}
   114  }
   115  
   116  func mainAdminConfigHistory(ctx *cli.Context) error {
   117  	checkAdminConfigHistorySyntax(ctx)
   118  
   119  	console.SetColor("ConfigHistoryMessageRestoreID", color.New(color.Bold))
   120  	console.SetColor("ConfigHistoryMessageTime", color.New(color.FgGreen))
   121  
   122  	// Get the alias parameter from cli
   123  	args := ctx.Args()
   124  	aliasedURL := args.Get(0)
   125  
   126  	// Create a new MinIO Admin Client
   127  	client, err := newAdminClient(aliasedURL)
   128  	fatalIf(err, "Unable to initialize admin connection.")
   129  
   130  	if ctx.IsSet("clear") {
   131  		fatalIf(probe.NewError(client.ClearConfigHistoryKV(globalContext, "all")), "Unable to clear server configuration.")
   132  
   133  		// Print
   134  		printMsg(configHistoryMessage{})
   135  		return nil
   136  	}
   137  
   138  	chEntries, e := client.ListConfigHistoryKV(globalContext, ctx.Int("count"))
   139  	fatalIf(probe.NewError(e), "Unable to list server history configuration.")
   140  
   141  	hentries := make([]historyEntry, len(chEntries))
   142  	for i, chEntry := range chEntries {
   143  		hentries[i] = historyEntry{
   144  			RestoreID:  chEntry.RestoreID,
   145  			CreateTime: chEntry.CreateTimeFormatted(),
   146  		}
   147  		hentries[i].Targets = chEntry.Data
   148  	}
   149  
   150  	// Print
   151  	printMsg(configHistoryMessage{
   152  		Entries: hentries,
   153  	})
   154  
   155  	return nil
   156  }