Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan
- [#193](https://github.com/kobsio/kobs/pull/193): [elasticsearch] Adjust selected time range via logs chart and allow filtering via fields.
- [#201](https://github.com/kobsio/kobs/pull/201): [sonarqube] Add SonarQube plugin to view projects and their measures within kobs.
- [#202](https://github.com/kobsio/kobs/pull/202): [core] Add tooltip to refresh button to show selected time interval.
- [#204](https://github.com/kobsio/kobs/pull/204): [grafana] Add Grafana plugin, to show dashboards from a Grafana instance and to embed Grafana panels into kobs dashboards.

### Fixed

Expand Down
2 changes: 2 additions & 0 deletions app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import applicationsPlugin from '@kobsio/plugin-applications';
import dashboardsPlugin from '@kobsio/plugin-dashboards';
import elasticsearchPlugin from '@kobsio/plugin-elasticsearch';
import fluxPlugin from '@kobsio/plugin-flux';
import grafanaPlugin from '@kobsio/plugin-grafana';
import istioPlugin from '@kobsio/plugin-istio';
import jaegerPlugin from '@kobsio/plugin-jaeger';
import kialiPlugin from '@kobsio/plugin-kiali';
Expand All @@ -32,6 +33,7 @@ ReactDOM.render(
...dashboardsPlugin,
...elasticsearchPlugin,
...fluxPlugin,
...grafanaPlugin,
...istioPlugin,
...jaegerPlugin,
...kialiPlugin,
Expand Down
4 changes: 4 additions & 0 deletions cmd/kobs/plugins/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/kobsio/kobs/plugins/dashboards"
"github.com/kobsio/kobs/plugins/elasticsearch"
"github.com/kobsio/kobs/plugins/flux"
"github.com/kobsio/kobs/plugins/grafana"
"github.com/kobsio/kobs/plugins/istio"
"github.com/kobsio/kobs/plugins/jaeger"
"github.com/kobsio/kobs/plugins/kiali"
Expand All @@ -37,6 +38,7 @@ type Config struct {
Dashboards dashboards.Config `json:"dashboards"`
Elasticsearch elasticsearch.Config `json:"elasticsearch"`
Flux flux.Config `json:"flux"`
Grafana grafana.Config `json:"grafana"`
Istio istio.Config `json:"istio"`
Jaeger jaeger.Config `json:"jaeger"`
Kiali kiali.Config `json:"kiali"`
Expand Down Expand Up @@ -84,6 +86,7 @@ func Register(clusters *clusters.Clusters, config Config) chi.Router {
jaegerRouter := jaeger.Register(clusters, router.plugins, config.Jaeger)
kialiRouter := kiali.Register(clusters, router.plugins, config.Kiali)
istioRouter := istio.Register(clusters, router.plugins, config.Istio, prometheusInstances, clickhouseInstances)
grafanaRouter := grafana.Register(clusters, router.plugins, config.Grafana)
fluxRouter := flux.Register(clusters, router.plugins, config.Flux)
opsgenieRouter := opsgenie.Register(clusters, router.plugins, config.Opsgenie)
sonarqubeRouter := sonarqube.Register(clusters, router.plugins, config.Sonarqube)
Expand All @@ -103,6 +106,7 @@ func Register(clusters *clusters.Clusters, config Config) chi.Router {
router.Mount(jaeger.Route, jaegerRouter)
router.Mount(kiali.Route, kialiRouter)
router.Mount(istio.Route, istioRouter)
router.Mount(grafana.Route, grafanaRouter)
router.Mount(flux.Route, fluxRouter)
router.Mount(opsgenie.Route, opsgenieRouter)
router.Mount(sonarqube.Route, sonarqubeRouter)
Expand Down
25 changes: 25 additions & 0 deletions docs/configuration/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Plugins can be used to extend the functions of kobs. They can be configured usin
| applications | [Applications](#applications) | Configure the caching behaviour for the applications plugin. | No |
| clickhouse | [[]ClickHouse](#clickhouse) | Configure multiple ClickHouse instances, which can be used within kobs. | No |
| elasticsearch | [[]Elasticsearch](#elasticsearch) | Configure multiple Elasticsearch instances, which can be used within kobs. | No |
| grafana | [[]Grafana](#grafana) | Configure multiple Grafana instances, which can be used within kobs. | No |
| istio | [[]Istio](#istio) | Configure multiple Istio instances, which can be used within kobs. | No |
| jaeger | [[]Jaeger](#jaeger) | Configure multiple Jaeger instances, which can be used within kobs. | No |
| kiali | [[]Kiali](#kiali) | Configure multiple Kiali instances, which can be used within kobs. | No |
Expand Down Expand Up @@ -83,6 +84,30 @@ plugins:
| password | string | Password to access an Elasticsearch instance via basic authentication. | No |
| token | string | Token to access an Elasticsearch instance via token based authentication. | No |

## Grafana

The following config can be used to grant kobs access to a Grafana instance running on `grafana.kobs.io`.

```yaml
plugins:
grafana:
- name: Grafana
description: Query, visualize, alert on, and understand your data no matter where it’s stored. With Grafana you can create, explore and share all of your data through beautiful, flexible dashboards.
internalAddress: http://grafana.monitoring.svc.cluster.local:3000
publicAddress: https://grafana.kobs.io
```

| Field | Type | Description | Required |
| ----- | ---- | ----------- | -------- |
| name | string | Name of the Grafana instance. | Yes |
| displayName | string | Name of the Grafana as it is shown in the UI. | Yes |
| descriptions | string | Description of the Grafana instance. | No |
| internalAddress | string | The cluster internal address of the Grafana instance. | Yes |
| publicAddress | string | The public address of the Grafana instance. | Yes |
| username | string | Username to access an Grafana instance via basic authentication. | No |
| password | string | Password to access an Grafana instance via basic authentication. | No |
| token | string | Token to access an Grafana instance via token based authentication. | No |

## Istio

The following configuration can be used to access a Istio instances using a Prometheus plugin named `prometheus` and an Clickhouse plugin named `clickhouse`.
Expand Down
Binary file added docs/plugins/assets/grafana.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
165 changes: 165 additions & 0 deletions docs/plugins/grafana.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Grafana

The Grafana plugin can be used to search through all your Grafana dashboards and to show a list of dashboards or embed a Grafana panel within a kobs dashboard.

![Grafana](assets/grafana.png)

## Options

The following options can be used for a panel with the Elasticsearch plugin:

| Field | Type | Description | Required |
| ----- | ---- | ----------- | -------- |
| type | string | The panel type. This could be `dashboards` or `panel`. | No |
| dashboards | []string | A list of dashboard ids to show, when the type is `dashboards`. | Yes |
| panel | [Panel](#panel) | The panel which should be displayed, when the type is `panel`. | Yes |

### Panel

| Field | Type | Description | Required |
| ----- | ---- | ----------- | -------- |
| dashboardID | string | The id of the dashboard. | Yes |
| panelID | string | The id of the panel. | Yes |
| variables | map<string, string> | A map of variables, with the name of the variable as key and the value of the variable as value. | No |

## Example

The following dashboards shows some panels from a Grafana plugin and a list of dashboards from this instance. The dashboard also uses some variables, which are then passed to the panels from Grafana.

```yaml
---
apiVersion: kobs.io/v1beta1
kind: Dashboard
metadata:
name: istio-overview
namespace: kobs
spec:
title: Istio Overview
variables:
- name: var_namespace
label: Namespace
plugin:
name: core
options:
type: static
items:
- bookinfo
- name: var_workload
label: Workload
plugin:
name: core
options:
type: static
items:
- productpage
- details
- ratings
- reviews
rows:
- size: 1
panels:
- title: Global Request Volume
colSpan: 3
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: G8wLrJIZk
panelID: "20"
- title: Global Success Rate
colSpan: 3
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: G8wLrJIZk
panelID: "21"
- title: 4xx
colSpan: 3
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: G8wLrJIZk
panelID: "22"
- title: 5xx
colSpan: 3
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: G8wLrJIZk
panelID: "23"

- size: 1
panels:
- title: Incoming Request Volume
colSpan: 4
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: UbsSZTDik
panelID: "12"
variables:
var-datasource: default
var-namespace: "{% .var_namespace %}"
var-workload: "{% .var_workload %}"
var-qrep: destination
var-srcns: All
var-srcwl: All
var-dstsvc: All
- title: Incoming Success Rate
colSpan: 4
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: UbsSZTDik
panelID: "14"
variables:
var-datasource: default
var-namespace: "{% .var_namespace %}"
var-workload: "{% .var_workload %}"
var-qrep: destination
var-srcns: All
var-srcwl: All
var-dstsvc: All
- title: Request Duration
colSpan: 4
plugin:
name: grafana
options:
type: panel
panel:
dashboardID: UbsSZTDik
panelID: "87"
variables:
var-datasource: default
var-namespace: "{% .var_namespace %}"
var-workload: "{% .var_workload %}"
var-qrep: destination
var-srcns: All
var-srcwl: All
var-dstsvc: All

- size: 3
panels:
- title: Dashboards
plugin:
name: grafana
options:
type: dashboards
dashboards:
- 3--MLVZZk
- G8wLrJIZk
- vu8e0VWZk
- LJ_uJAvmk
- UbsSZTDik
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ nav:
- Dashboards: plugins/dashboards.md
- Elasticsearch: plugins/elasticsearch.md
- Flux: plugins/flux.md
- Grafana: plugins/grafana.md
- Istio: plugins/istio.md
- Jaeger: plugins/jaeger.md
- Kiali: plugins/kiali.md
Expand Down
118 changes: 118 additions & 0 deletions plugins/grafana/grafana.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package grafana

import (
"net/http"

"github.com/kobsio/kobs/pkg/api/clusters"
"github.com/kobsio/kobs/pkg/api/middleware/errresponse"
"github.com/kobsio/kobs/pkg/api/plugins/plugin"
"github.com/kobsio/kobs/plugins/grafana/pkg/instance"

"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/sirupsen/logrus"
)

// Route is the route under which the plugin should be registered in our router for the rest api.
const (
Route = "/grafana"
)

var (
log = logrus.WithFields(logrus.Fields{"package": "grafana"})
)

// Config is the structure of the configuration for the grafana plugin.
type Config []instance.Config

// Router implements the router for the resources plugin, which can be registered in the router for our rest api.
type Router struct {
*chi.Mux
clusters *clusters.Clusters
instances []*instance.Instance
}

func (router *Router) getInstance(name string) *instance.Instance {
for _, i := range router.instances {
if i.Name == name {
return i
}
}

return nil
}

func (router *Router) getDashboards(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
query := r.URL.Query().Get("query")
uids := r.URL.Query()["uid"]

log.WithFields(logrus.Fields{"name": name, "query": query, "uids": uids}).Tracef("getDashboards")

i := router.getInstance(name)
if i == nil {
errresponse.Render(w, r, nil, http.StatusBadRequest, "Could not find instance name")
return
}

if uids != nil {
var dashboards []instance.Dashboard
for _, uid := range uids {
dashboard, err := i.GetDashboard(r.Context(), uid)
if err != nil {
errresponse.Render(w, r, err, http.StatusInternalServerError, "Could not get dashboard")
return
}

dashboards = append(dashboards, *dashboard)
}

render.JSON(w, r, dashboards)
return
}

dashboards, err := i.GetDashboards(r.Context(), query)
if err != nil {
errresponse.Render(w, r, err, http.StatusInternalServerError, "Could not get dashboards")
return
}

render.JSON(w, r, dashboards)
}

// Register returns a new router which can be used in the router for the kobs rest api.
func Register(clusters *clusters.Clusters, plugins *plugin.Plugins, config Config) chi.Router {
var instances []*instance.Instance

for _, cfg := range config {
instance, err := instance.New(cfg)
if err != nil {
log.WithError(err).WithFields(logrus.Fields{"name": cfg.Name}).Fatalf("Could not create Grafana instance")
}

instances = append(instances, instance)

var options map[string]interface{}
options = make(map[string]interface{})
options["internalAddress"] = cfg.InternalAddress
options["publicAddress"] = cfg.PublicAddress

plugins.Append(plugin.Plugin{
Name: cfg.Name,
DisplayName: cfg.DisplayName,
Description: cfg.Description,
Type: "grafana",
Options: options,
})
}

router := Router{
chi.NewRouter(),
clusters,
instances,
}

router.Get("/dashboards/{name}", router.getDashboards)

return router
}
Loading