github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/accounts/base.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package accounts
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  
    26  	"github.com/spf13/cobra"
    27  	corev1 "k8s.io/api/core/v1"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/cli-runtime/pkg/genericiooptions"
    30  	"k8s.io/klog/v2"
    31  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    32  
    33  	clusterutil "github.com/1aal/kubeblocks/pkg/cli/cluster"
    34  	"github.com/1aal/kubeblocks/pkg/cli/exec"
    35  	"github.com/1aal/kubeblocks/pkg/cli/printer"
    36  	lorryutil "github.com/1aal/kubeblocks/pkg/lorry/util"
    37  )
    38  
    39  type AccountBaseOptions struct {
    40  	ClusterName   string
    41  	CharType      string
    42  	ComponentName string
    43  	PodName       string
    44  	Pod           *corev1.Pod
    45  	Verbose       bool
    46  	AccountOp     lorryutil.OperationKind
    47  	RequestMeta   map[string]interface{}
    48  	*exec.ExecOptions
    49  }
    50  
    51  var (
    52  	errClusterNameNum        = fmt.Errorf("please specify ONE cluster-name at a time")
    53  	errMissingUserName       = fmt.Errorf("please specify username")
    54  	errMissingRoleName       = fmt.Errorf("please specify at least ONE role name")
    55  	errInvalidRoleName       = fmt.Errorf("invalid role name, should be one of [SUPERUSER, READWRITE, READONLY] ")
    56  	errCompNameOrInstName    = fmt.Errorf("please specify either --component or --instance, they are exclusive")
    57  	errClusterNameorInstName = fmt.Errorf("specify either cluster name or --instance")
    58  )
    59  
    60  func NewAccountBaseOptions(f cmdutil.Factory, streams genericiooptions.IOStreams) *AccountBaseOptions {
    61  	return &AccountBaseOptions{
    62  		ExecOptions: exec.NewExecOptions(f, streams),
    63  	}
    64  }
    65  
    66  func (o *AccountBaseOptions) AddFlags(cmd *cobra.Command) {
    67  	cmd.Flags().StringVar(&o.ComponentName, "component", "", "Specify the name of component to be connected. If not specified, pick the first one.")
    68  	cmd.Flags().StringVarP(&o.PodName, "instance", "i", "", "Specify the name of instance to be connected.")
    69  }
    70  
    71  func (o *AccountBaseOptions) Validate(args []string) error {
    72  	if len(args) > 1 {
    73  		return errClusterNameNum
    74  	}
    75  
    76  	if len(o.PodName) > 0 {
    77  		if len(o.ComponentName) > 0 {
    78  			return errCompNameOrInstName
    79  		}
    80  		if len(args) > 0 {
    81  			return errClusterNameorInstName
    82  		}
    83  	} else if len(args) == 0 {
    84  		return errClusterNameorInstName
    85  	}
    86  	if len(args) == 1 {
    87  		o.ClusterName = args[0]
    88  	}
    89  	return nil
    90  }
    91  
    92  func (o *AccountBaseOptions) Complete(f cmdutil.Factory) error {
    93  	var err error
    94  	err = o.ExecOptions.Complete()
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	ctx, cancelFn := context.WithCancel(context.Background())
   100  	defer cancelFn()
   101  
   102  	if len(o.PodName) > 0 {
   103  		// get pod by name
   104  		o.Pod, err = o.ExecOptions.Client.CoreV1().Pods(o.Namespace).Get(ctx, o.PodName, metav1.GetOptions{})
   105  		if err != nil {
   106  			return err
   107  		}
   108  		o.ClusterName = clusterutil.GetPodClusterName(o.Pod)
   109  		o.ComponentName = clusterutil.GetPodComponentName(o.Pod)
   110  	}
   111  
   112  	compInfo, err := clusterutil.FillCompInfoByName(ctx, o.ExecOptions.Dynamic, o.Namespace, o.ClusterName, o.ComponentName)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	// fill component name
   117  	if len(o.ComponentName) == 0 {
   118  		o.ComponentName = compInfo.Component.Name
   119  	}
   120  	// fill character type
   121  	o.CharType = compInfo.ComponentDef.CharacterType
   122  
   123  	if len(o.PodName) == 0 {
   124  		if o.PodName, err = compInfo.InferPodName(); err != nil {
   125  			return err
   126  		}
   127  		// get pod by name
   128  		o.Pod, err = o.ExecOptions.Client.CoreV1().Pods(o.Namespace).Get(ctx, o.PodName, metav1.GetOptions{})
   129  		if err != nil {
   130  			return err
   131  		}
   132  	}
   133  
   134  	o.ExecOptions.Pod = o.Pod
   135  	o.ExecOptions.Namespace = o.Namespace
   136  	o.ExecOptions.Quiet = true
   137  	o.ExecOptions.TTY = true
   138  	o.ExecOptions.Stdin = true
   139  
   140  	o.Verbose = klog.V(1).Enabled()
   141  
   142  	return nil
   143  }
   144  
   145  func (o *AccountBaseOptions) newTblPrinterWithStyle(title string, header []interface{}) *printer.TablePrinter {
   146  	tblPrinter := printer.NewTablePrinter(o.Out)
   147  	tblPrinter.SetStyle(printer.TerminalStyle)
   148  	// tblPrinter.Tbl.SetTitle(title)
   149  	tblPrinter.SetHeader(header...)
   150  	return tblPrinter
   151  }
   152  
   153  func (o *AccountBaseOptions) printGeneralInfo(event, message string) {
   154  	tblPrinter := o.newTblPrinterWithStyle("QUERY RESULT", []interface{}{"RESULT", "MESSAGE"})
   155  	tblPrinter.AddRow(event, message)
   156  	tblPrinter.Print()
   157  }
   158  
   159  func (o *AccountBaseOptions) printUserInfo(users []map[string]any) {
   160  	// render user info with username and password expired boolean
   161  	tblPrinter := o.newTblPrinterWithStyle("USER INFO", []interface{}{"USERNAME", "EXPIRED"})
   162  	for _, user := range users {
   163  		tblPrinter.AddRow(user["userName"], user["expired"])
   164  	}
   165  
   166  	tblPrinter.Print()
   167  }
   168  
   169  func (o *AccountBaseOptions) printRoleInfo(users []map[string]any) {
   170  	tblPrinter := o.newTblPrinterWithStyle("USER INFO", []interface{}{"USERNAME", "ROLE"})
   171  	for _, user := range users {
   172  		tblPrinter.AddRow(user["userName"], user["roleName"])
   173  	}
   174  	tblPrinter.Print()
   175  }