github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/printer/describe.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 printer
    21  
    22  import (
    23  	"encoding/json"
    24  	"fmt"
    25  	"io"
    26  	"reflect"
    27  
    28  	"gopkg.in/yaml.v2"
    29  	corev1 "k8s.io/api/core/v1"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    32  
    33  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    34  	"github.com/1aal/kubeblocks/pkg/cli/types"
    35  	"github.com/1aal/kubeblocks/pkg/cli/util"
    36  	cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core"
    37  )
    38  
    39  const NoneString = "<none>"
    40  
    41  func PrintAllWarningEvents(events *corev1.EventList, out io.Writer) {
    42  	objs := util.SortEventsByLastTimestamp(events, corev1.EventTypeWarning)
    43  	title := fmt.Sprintf("\n%s Events: ", corev1.EventTypeWarning)
    44  	if objs == nil || len(*objs) == 0 {
    45  		fmt.Fprintln(out, title+NoneString)
    46  		return
    47  	}
    48  	tbl := NewTablePrinter(out)
    49  	fmt.Fprintln(out, title)
    50  	tbl.SetHeader("TIME", "TYPE", "REASON", "OBJECT", "MESSAGE")
    51  	for _, o := range *objs {
    52  		e := o.(*corev1.Event)
    53  		tbl.AddRow(util.GetEventTimeStr(e), e.Type, e.Reason, util.GetEventObject(e), e.Message)
    54  	}
    55  	tbl.Print()
    56  
    57  }
    58  
    59  // PrintConditions prints the conditions of resource.
    60  func PrintConditions(conditions []metav1.Condition, out io.Writer) {
    61  	// if the conditions are empty, return.
    62  	if len(conditions) == 0 {
    63  		return
    64  	}
    65  	tbl := NewTablePrinter(out)
    66  	PrintTitle("Conditions")
    67  	tbl.SetHeader("LAST-TRANSITION-TIME", "TYPE", "REASON", "STATUS", "MESSAGE")
    68  	for _, con := range conditions {
    69  		tbl.AddRow(util.TimeFormat(&con.LastTransitionTime), con.Type, con.Reason, con.Status, con.Message)
    70  	}
    71  	tbl.Print()
    72  }
    73  
    74  // PrintComponentConfigMeta prints the conditions of resource.
    75  func PrintComponentConfigMeta(tplInfos []types.ConfigTemplateInfo, clusterName, componentName string, out io.Writer) {
    76  	if len(tplInfos) == 0 {
    77  		return
    78  	}
    79  	tbl := NewTablePrinter(out)
    80  	PrintTitle("ConfigSpecs Meta")
    81  	enableReconfiguring := func(tpl appsv1alpha1.ComponentConfigSpec, configFileKey string) string {
    82  		if len(tpl.ConfigConstraintRef) > 0 && cfgcore.IsSupportConfigFileReconfigure(tpl, configFileKey) {
    83  			return "true"
    84  		}
    85  		return "false"
    86  	}
    87  	tbl.SetHeader("CONFIG-SPEC-NAME", "FILE", "ENABLED", "TEMPLATE", "CONSTRAINT", "RENDERED", "COMPONENT", "CLUSTER")
    88  	for _, info := range tplInfos {
    89  		for configFileKey := range info.CMObj.Data {
    90  			tbl.AddRow(
    91  				BoldYellow(info.Name),
    92  				configFileKey,
    93  				BoldYellow(enableReconfiguring(info.TPL, configFileKey)),
    94  				info.TPL.TemplateRef,
    95  				info.TPL.ConfigConstraintRef,
    96  				info.CMObj.Name,
    97  				componentName,
    98  				clusterName)
    99  		}
   100  	}
   101  	tbl.Print()
   102  }
   103  
   104  // PrintHelmValues prints the helm values file of the release in specified format, supports JSON、YAML and Table
   105  func PrintHelmValues(configs map[string]interface{}, format Format, out io.Writer) {
   106  	inTable := func() {
   107  		p := NewTablePrinter(out)
   108  		p.SetHeader("KEY", "VALUE")
   109  		p.SortBy(1)
   110  		for key, value := range configs {
   111  			addRows(key, value, p, true) // to table
   112  		}
   113  		p.Print()
   114  	}
   115  	if format.IsHumanReadable() {
   116  		inTable()
   117  		return
   118  	}
   119  
   120  	var data []byte
   121  	if format == YAML {
   122  		data, _ = yaml.Marshal(configs)
   123  	} else {
   124  		data, _ = json.MarshalIndent(configs, "", "  ")
   125  		data = append(data, '\n')
   126  	}
   127  	fmt.Fprint(out, string(data))
   128  }
   129  
   130  // addRows parses the interface value and add it to the Table
   131  func addRows(key string, value interface{}, p *TablePrinter, ori bool) {
   132  	if value == nil {
   133  		p.AddRow(key, value)
   134  		return
   135  	}
   136  	if reflect.TypeOf(value).Kind() == reflect.Map && ori {
   137  		if len(value.(map[string]interface{})) == 0 {
   138  			data, _ := json.Marshal(value)
   139  			p.AddRow(key, string(data))
   140  		}
   141  		for k, v := range value.(map[string]interface{}) {
   142  			addRows(key+"."+k, v, p, false)
   143  		}
   144  	} else {
   145  		data, _ := json.Marshal(value)
   146  		p.AddRow(key, string(data))
   147  	}
   148  }
   149  
   150  func PrettyPrintObj(obj *unstructured.Unstructured) error {
   151  	objYAML, err := yaml.Marshal(obj.Object)
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	// Parse YAML back into a structured map for pretty printing
   157  	var parsedObj map[string]interface{}
   158  	if err := yaml.Unmarshal(objYAML, &parsedObj); err != nil {
   159  		return err
   160  	}
   161  
   162  	// Marshal again with indentation for pretty printing
   163  	prettyYAML, err := yaml.Marshal(parsedObj)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	fmt.Println(string(prettyYAML))
   169  	return nil
   170  }