github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/cmd/alert/list_receivers.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 alert
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  
    26  	"github.com/mitchellh/mapstructure"
    27  	"github.com/spf13/cobra"
    28  	"k8s.io/cli-runtime/pkg/genericiooptions"
    29  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    30  	"k8s.io/kubectl/pkg/util/templates"
    31  
    32  	"github.com/1aal/kubeblocks/pkg/cli/printer"
    33  	"github.com/1aal/kubeblocks/pkg/cli/util"
    34  )
    35  
    36  var (
    37  	listReceiversExample = templates.Examples(`
    38  		# list all alert receivers
    39  		kbcli alert list-receivers`)
    40  )
    41  
    42  type listReceiversOptions struct {
    43  	baseOptions
    44  }
    45  
    46  func newListReceiversCmd(f cmdutil.Factory, streams genericiooptions.IOStreams) *cobra.Command {
    47  	o := &listReceiversOptions{baseOptions: baseOptions{IOStreams: streams}}
    48  	cmd := &cobra.Command{
    49  		Use:     "list-receivers",
    50  		Short:   "List all alert receivers.",
    51  		Example: listReceiversExample,
    52  		Run: func(cmd *cobra.Command, args []string) {
    53  			util.CheckErr(o.complete(f))
    54  			util.CheckErr(o.run())
    55  		},
    56  	}
    57  	return cmd
    58  }
    59  
    60  func (o *listReceiversOptions) run() error {
    61  	data, err := getConfigData(o.alertConfigMap, alertConfigFileName)
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	webhookData, err := getConfigData(o.webhookConfigMap, webhookAdaptorFileName)
    67  	if err != nil {
    68  		return err
    69  	}
    70  
    71  	receivers := getReceiversFromData(data)
    72  	if len(receivers) == 0 {
    73  		fmt.Fprintf(o.Out, "No receivers found in alertmanager config %s\n", alertConfigmapName)
    74  		return nil
    75  	}
    76  	webhookReceivers := getReceiversFromData(webhookData)
    77  	if len(receivers) == 0 {
    78  		fmt.Fprintf(o.Out, "No receivers found in webhook adaptor config %s\n", webhookAdaptorConfigmapName)
    79  		return nil
    80  	}
    81  
    82  	// build receiver webhook map, key is receiver name, value is webhook config that with
    83  	// the real webhook url
    84  	receiverWebhookMap := make(map[string][]webhookConfig)
    85  	for _, r := range receivers {
    86  		var cfgs []webhookConfig
    87  		name := r.(map[string]interface{})["name"].(string)
    88  		for _, w := range webhookReceivers {
    89  			obj := w.(map[string]interface{})
    90  			if obj["name"] == name {
    91  				cfg := webhookConfig{}
    92  				params := obj["params"].(map[string]interface{})
    93  				cfg.URL = params["url"].(string)
    94  				cfgs = append(cfgs, cfg)
    95  			}
    96  		}
    97  		receiverWebhookMap[name] = cfgs
    98  	}
    99  
   100  	// build receiver route map, key is receiver name, value is route
   101  	receiverRouteMap := make(map[string]*route)
   102  	routes := getRoutesFromData(data)
   103  	for _, r := range routes {
   104  		res := &route{}
   105  		if err = mapstructure.Decode(r, &res); err != nil {
   106  			return err
   107  		}
   108  		receiverRouteMap[res.Receiver] = res
   109  	}
   110  
   111  	tbl := printer.NewTablePrinter(o.Out)
   112  	tbl.SetHeader("NAME", "WEBHOOK", "EMAIL", "SLACK", "CLUSTER", "SEVERITY")
   113  	for _, rec := range receivers {
   114  		recMap := rec.(map[string]interface{})
   115  		name := recMap["name"].(string)
   116  		routeInfo := getRouteInfo(receiverRouteMap[name])
   117  		webhookCfgs := receiverWebhookMap[name]
   118  		tbl.AddRow(name, joinWebhookConfigs(webhookCfgs),
   119  			joinConfigs(recMap, "email_configs"),
   120  			joinConfigs(recMap, "slack_configs"),
   121  			strings.Join(routeInfo[routeMatcherClusterKey], ","),
   122  			strings.Join(routeInfo[routeMatcherSeverityKey], ","))
   123  	}
   124  	tbl.Print()
   125  	return nil
   126  }
   127  
   128  // getRouteInfo gets route clusters and severity
   129  func getRouteInfo(route *route) map[string][]string {
   130  	routeInfoMap := map[string][]string{
   131  		routeMatcherClusterKey:  {},
   132  		routeMatcherSeverityKey: {},
   133  	}
   134  	if route == nil {
   135  		return routeInfoMap
   136  	}
   137  
   138  	fetchInfo := func(m, t string) {
   139  		if !strings.Contains(m, t) {
   140  			return
   141  		}
   142  		matcher := strings.Split(m, routeMatcherOperator)
   143  		if len(matcher) != 2 {
   144  			return
   145  		}
   146  		info := removeDuplicateStr(strings.Split(matcher[1], "|"))
   147  		routeInfoMap[t] = append(routeInfoMap[t], info...)
   148  	}
   149  
   150  	for _, m := range route.Matchers {
   151  		fetchInfo(m, routeMatcherClusterKey)
   152  		fetchInfo(m, routeMatcherSeverityKey)
   153  	}
   154  	return routeInfoMap
   155  }
   156  
   157  func joinWebhookConfigs(cfgs []webhookConfig) string {
   158  	var result []string
   159  	for _, c := range cfgs {
   160  		result = append(result, c.string())
   161  	}
   162  	return strings.Join(result, "\n")
   163  }
   164  
   165  func joinConfigs(rec map[string]interface{}, key string) string {
   166  	var result []string
   167  	if rec == nil {
   168  		return ""
   169  	}
   170  
   171  	cfg, ok := rec[key]
   172  	if !ok {
   173  		return ""
   174  	}
   175  
   176  	switch key {
   177  	case "slack_configs":
   178  		for _, c := range cfg.([]interface{}) {
   179  			var slack slackConfig
   180  			_ = mapstructure.Decode(c, &slack)
   181  			result = append(result, slack.string())
   182  		}
   183  	case "email_configs":
   184  		for _, c := range cfg.([]interface{}) {
   185  			var email emailConfig
   186  			_ = mapstructure.Decode(c, &email)
   187  			result = append(result, email.string())
   188  		}
   189  	}
   190  	return strings.Join(result, "\n")
   191  }