diff --git a/pkg/cmds/monitor.go b/pkg/cmds/monitor.go index 5010201d2..7b92995ee 100644 --- a/pkg/cmds/monitor.go +++ b/pkg/cmds/monitor.go @@ -70,6 +70,7 @@ func NewCmdMonitor(f cmdutil.Factory) *cobra.Command { var alertLong = templates.LongDesc(` Get the prometheus alerts for a specific database in just one command `) + var alertExample = templates.Examples(` kubectl dba monitor get-alerts mongodb -n demo sample-mongodb --prom-svc-name=prometheus-kube-prometheus-prometheus --prom-svc-namespace=monitoring @@ -107,8 +108,9 @@ var dashboardLong = templates.LongDesc(` `) var dashboardExample = templates.Examples(` - # Check availability of mongodb-summary-dashboard grafana dashboard of mongodb - kubectl dba monitor dashboard mongodb mongodb-summary-dashboard + # Check availability of mongodb-summary-dashboard grafana dashboard of postgres + kubectl-dba monitor dashboard [DATABASE] [DASHBOARD_NAME] + kubectl-dba dashboard postgres postgres_databases_dashboard --branch=metric --prom-svc-name=prometheus-kube-prometheus-prometheus --prom-svc-namespace=monitoring --prom-svc-port=9090 Valid dashboards include: * elasticsearch @@ -142,21 +144,32 @@ func DashboardCMD(f cmdutil.Factory) *cobra.Command { } // check-connection -// TODO var connectionLong = templates.LongDesc(` - - `) + Check connection status for different targets of prometheus server for specific DB. +`) -// TODO var connectionExample = templates.Examples(` -# kubectl dba monitor check-connection mongodb -n demo sample_mg -> all connection check and report + Check connection status for different targets of prometheus server of a mongodb. + kubectl-dba monitor check-connection [DATABASE] [DATABASENAME] -n [NAMESPACE] + kubectl dba monitor check-connection mongodb -n demo sample_mg + + Valid resource types include: + * elasticsearch + * mongodb + * mariadb + * mysql + * postgres + * redis + * kafka + * perconaxtradb + * proxysql `) func ConnectionCMD(f cmdutil.Factory) *cobra.Command { var prom connection.PromSvc cmd := &cobra.Command{ Use: "check-connection", - Short: i18n.T("Check connection status of prometheus target with server"), + Short: i18n.T("Check connection status of prometheus targets with server"), Long: connectionLong, Example: connectionExample, Run: func(cmd *cobra.Command, args []string) { diff --git a/pkg/connection/db.go b/pkg/connection/db.go index ff5405349..1f011eb7a 100644 --- a/pkg/connection/db.go +++ b/pkg/connection/db.go @@ -1,11 +1,33 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the AppsCode Community License 1.0.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://github.com/appscode/licenses/raw/1.0.0/AppsCode-Community-1.0.0.md + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package connection import ( - "k8s.io/klog/v2" - cmdutil "k8s.io/kubectl/pkg/cmd/util" - "kubedb.dev/cli/pkg/lib" + "context" + "fmt" "log" "strconv" + "time" + + "kubedb.dev/cli/pkg/lib" + + "github.com/prometheus/common/model" + "k8s.io/klog/v2" + cmdutil "k8s.io/kubectl/pkg/cmd/util" ) // kubectl dba monitor check-connection mongodb -n demo sample_mg -> all connection check and report @@ -16,8 +38,9 @@ type PromSvc struct { Port int } type metrics struct { - metric string - label string + metric string + label string + labelValue string } func Run(f cmdutil.Factory, args []string, prom PromSvc) { @@ -32,14 +55,6 @@ func Run(f cmdutil.Factory, args []string, prom PromSvc) { klog.Error(err, "failed to get current namespace") } - identicalMetrics := []metrics{ - {metric: cAdvisorMetric}, - {metric: kubeletMetric}, - {metric: ksmMetric}, - {metric: nodeExporterMetric}, - } - identicalMetrics = append(identicalMetrics, getDBMetrics(database, databaseName, namespace)...) - config, err := f.ToRESTConfig() if err != nil { log.Fatal(err) @@ -53,4 +68,52 @@ func Run(f cmdutil.Factory, args []string, prom PromSvc) { promClient := getPromClient(strconv.Itoa(tunnel.Local)) + queries := getIdenticalMetrics(database, databaseName) + var notFound []string + + for target, query := range queries { + metricName := query.metric + endTime := time.Now() + + result, _, err := promClient.Query(context.TODO(), metricName, endTime) + if err != nil { + log.Fatal("Error querying Prometheus:", err, " metric: ", metricName) + } + + matrix := result.(model.Vector) + + if len(matrix) > 0 { + if query.label != "" { + // DB and panopticon related metrics.So we need to check label also + // Check if the label exists for any result in the matrix + exist := false + for _, sample := range matrix { + if sample.Metric != nil { + if labelVal, ok := sample.Metric[model.LabelName(query.label)]; ok { + if string(labelVal) == query.labelValue { + if namespaceVal, ok := sample.Metric[model.LabelName("namespace")]; ok { + if string(namespaceVal) == namespace { + exist = true + } + } + } + } + } + } + if !exist { + notFound = append(notFound, target) + } + } + } else { + notFound = append(notFound, target) + } + } + + if len(notFound) == 0 { + fmt.Printf("All monitoring connection established successfully for %s : %s/%s\n", database, namespace, databaseName) + } else { + for _, target := range notFound { + fmt.Printf("%s monitoring connection not found for %s : %s/%s\n", target, database, namespace, databaseName) + } + } } diff --git a/pkg/connection/helper.go b/pkg/connection/helper.go index 314f0d4b0..9ad390105 100644 --- a/pkg/connection/helper.go +++ b/pkg/connection/helper.go @@ -1,10 +1,27 @@ +/* +Copyright AppsCode Inc. and Contributors + +Licensed under the AppsCode Community License 1.0.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://github.com/appscode/licenses/raw/1.0.0/AppsCode-Community-1.0.0.md + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package connection import ( "fmt" + "log" + "github.com/prometheus/client_golang/api" v1 "github.com/prometheus/client_golang/api/prometheus/v1" - "log" ) const ( @@ -14,41 +31,88 @@ const ( nodeExporterMetric = "node_cpu_seconds_total" ) -func getIdenticalMetrics(database, databaseName, namespace string) []metrics { - identicalMetrics := []metrics{ - {metric: cAdvisorMetric}, - {metric: kubeletMetric}, - {metric: ksmMetric}, - {metric: nodeExporterMetric}, - } - identicalMetrics = append(identicalMetrics, getDBMetrics(database, databaseName, namespace)...) - return identicalMetrics +func getIdenticalMetrics(database, databaseName string) map[string]*metrics { + queries := make(map[string]*metrics) + queries["cAdvisor"] = &metrics{metric: cAdvisorMetric} + queries["kubelet"] = &metrics{metric: kubeletMetric} + queries["kube-state-metric"] = &metrics{metric: ksmMetric} + queries["node-exporter"] = &metrics{metric: nodeExporterMetric} + + queries = getDBMetrics(database, databaseName, queries) + + return queries } -func getDBMetrics(database, name, namespace string) []metrics { - var dbMetric []metrics - label := fmt.Sprintf("%s-stats", name) - metric := fmt.Sprintf("kubedb_com_%s", database) + +func getDBMetrics(database, name string, queries map[string]*metrics) map[string]*metrics { + label := "service" + labelValue := fmt.Sprintf("%s-stats", name) switch database { case "mongodb": - dbMetric = append(dbMetric, metrics{ - metric: "", - label: "", - }) + queries[database] = &metrics{ + metric: "mongodb_up", + label: label, + labelValue: labelValue, + } case "postgres": + queries[database] = &metrics{ + metric: "pg_up", + label: label, + labelValue: labelValue, + } case "mysql": + queries[database] = &metrics{ + metric: "mysql_up", + label: label, + labelValue: labelValue, + } case "redis": + queries[database] = &metrics{ + metric: "redis_up", + label: label, + labelValue: labelValue, + } case "mariadb": + queries[database] = &metrics{ + metric: "mysql_up", + label: label, + labelValue: labelValue, + } case "proxysql": + /// TODO : NOT WORKING + queries[database] = &metrics{ + metric: "mysql_up", + label: label, + labelValue: labelValue, + } case "elasticsearch": + queries[database] = &metrics{ + metric: "elasticsearch_clusterinfo_up", + label: label, + labelValue: labelValue, + } case "perconaxtradb": + queries[database] = &metrics{ + metric: "mysql_up", + label: label, + labelValue: labelValue, + } case "kafka": + queries[database] = &metrics{ + metric: "kafka_controller_kafkacontroller_activebrokercount", + label: label, + labelValue: labelValue, + } default: - log.Fatal("database invalid") + log.Fatal("database invalid!") } - panopticon := getPanopticonMetric() -} -func getPanopticonMetric() { + // Panopticon + queries["panopticon"] = &metrics{ + metric: fmt.Sprintf("kubedb_com_%s_info", database), + label: database, + labelValue: name, + } + return queries } func getPromClient(localPort string) v1.API {