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 }