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

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package clusterdefinition
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/spf13/cobra"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/cli-runtime/pkg/genericiooptions"
    28  	"k8s.io/client-go/dynamic"
    29  	clientset "k8s.io/client-go/kubernetes"
    30  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    31  	"k8s.io/kubectl/pkg/util/templates"
    32  
    33  	"github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    34  	"github.com/1aal/kubeblocks/pkg/cli/printer"
    35  	"github.com/1aal/kubeblocks/pkg/cli/types"
    36  	"github.com/1aal/kubeblocks/pkg/cli/util"
    37  	"github.com/1aal/kubeblocks/pkg/constant"
    38  	dptypes "github.com/1aal/kubeblocks/pkg/dataprotection/types"
    39  	"github.com/1aal/kubeblocks/pkg/dataprotection/utils/boolptr"
    40  )
    41  
    42  var (
    43  	describeExample = templates.Examples(`
    44  		# describe a specified cluster definition
    45  		kbcli clusterdefinition describe myclusterdef`)
    46  )
    47  
    48  type describeOptions struct {
    49  	factory   cmdutil.Factory
    50  	client    clientset.Interface
    51  	dynamic   dynamic.Interface
    52  	namespace string
    53  
    54  	names []string
    55  	genericiooptions.IOStreams
    56  }
    57  
    58  func NewDescribeCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
    59  	o := &describeOptions{
    60  		factory:   f,
    61  		IOStreams: streams,
    62  	}
    63  	cmd := &cobra.Command{
    64  		Use:               "describe",
    65  		Short:             "Describe ClusterDefinition.",
    66  		Example:           describeExample,
    67  		Aliases:           []string{"desc"},
    68  		ValidArgsFunction: util.ResourceNameCompletionFunc(f, types.ClusterDefGVR()),
    69  		Run: func(cmd *cobra.Command, args []string) {
    70  			cmdutil.CheckErr(o.complete(args))
    71  			cmdutil.CheckErr(o.run())
    72  		},
    73  	}
    74  	return cmd
    75  }
    76  
    77  func (o *describeOptions) complete(args []string) error {
    78  	var err error
    79  
    80  	if len(args) == 0 {
    81  		return fmt.Errorf("cluster definition name should be specified")
    82  	}
    83  	o.names = args
    84  
    85  	if o.client, err = o.factory.KubernetesClientSet(); err != nil {
    86  		return err
    87  	}
    88  
    89  	if o.dynamic, err = o.factory.DynamicClient(); err != nil {
    90  		return err
    91  	}
    92  
    93  	if o.namespace, _, err = o.factory.ToRawKubeConfigLoader().Namespace(); err != nil {
    94  		return err
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (o *describeOptions) run() error {
   101  	for _, name := range o.names {
   102  		if err := o.describeClusterDef(name); err != nil {
   103  			return err
   104  		}
   105  	}
   106  	return nil
   107  }
   108  
   109  func (o *describeOptions) describeClusterDef(name string) error {
   110  	// get cluster definition
   111  	clusterDefObject, err := o.dynamic.Resource(types.ClusterDefGVR()).Get(context.TODO(), name, metav1.GetOptions{})
   112  	if err != nil {
   113  		return err
   114  	}
   115  	clusterDef := v1alpha1.ClusterDefinition{}
   116  	if err := runtime.DefaultUnstructuredConverter.FromUnstructured(clusterDefObject.Object, &clusterDef); err != nil {
   117  		return err
   118  	}
   119  
   120  	// get backup policy templates of the cluster definition
   121  	opts := metav1.ListOptions{
   122  		LabelSelector: fmt.Sprintf("%s=%s", constant.ClusterDefLabelKey, name),
   123  	}
   124  	backupTemplatesListObj, err := o.dynamic.Resource(types.BackupPolicyTemplateGVR()).List(context.TODO(), opts)
   125  	if err != nil {
   126  		return err
   127  	}
   128  	var backupPolicyTemplates []*v1alpha1.BackupPolicyTemplate
   129  	for _, item := range backupTemplatesListObj.Items {
   130  		backupTemplate := v1alpha1.BackupPolicyTemplate{}
   131  		if err := runtime.DefaultUnstructuredConverter.FromUnstructured(item.Object, &backupTemplate); err != nil {
   132  			return err
   133  		}
   134  		backupPolicyTemplates = append(backupPolicyTemplates, &backupTemplate)
   135  	}
   136  
   137  	showClusterDef(&clusterDef, o.Out)
   138  
   139  	showBackupConfig(backupPolicyTemplates, o.Out)
   140  
   141  	return nil
   142  }
   143  
   144  func showClusterDef(cd *v1alpha1.ClusterDefinition, out io.Writer) {
   145  	if cd == nil {
   146  		return
   147  	}
   148  	fmt.Fprintf(out, "Name: %s\t Type: %s\n\n", cd.Name, cd.Spec.Type)
   149  }
   150  
   151  func showBackupConfig(backupPolicyTemplates []*v1alpha1.BackupPolicyTemplate, out io.Writer) {
   152  	if len(backupPolicyTemplates) == 0 {
   153  		return
   154  	}
   155  	fmt.Fprintf(out, "Backup Config:\n")
   156  	tbl := printer.NewTablePrinter(out)
   157  	defaultBackupPolicyTemplate := &v1alpha1.BackupPolicyTemplate{}
   158  	// if there is only one backup policy template, it will be the default backup policy template
   159  	if len(backupPolicyTemplates) == 1 {
   160  		defaultBackupPolicyTemplate = backupPolicyTemplates[0]
   161  	}
   162  	for _, item := range backupPolicyTemplates {
   163  		if item.Annotations[dptypes.DefaultBackupPolicyTemplateAnnotationKey] == "true" {
   164  			defaultBackupPolicyTemplate = item
   165  			break
   166  		}
   167  	}
   168  	tbl.SetHeader("BACKUP-METHOD", "ACTION-SET", "SNAPSHOT-VOLUME")
   169  	for _, policy := range defaultBackupPolicyTemplate.Spec.BackupPolicies {
   170  		for _, method := range policy.BackupMethods {
   171  			snapshotVolume := "false"
   172  			if boolptr.IsSetToTrue(method.SnapshotVolumes) {
   173  				snapshotVolume = "true"
   174  			}
   175  			tbl.AddRow(method.Name, method.ActionSetName, snapshotVolume)
   176  		}
   177  	}
   178  	tbl.Print()
   179  }