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 }