* Storage server runs own instrumentation server if its the sole target. Starts adding some sample metrics for now. * adds metric for failed optimistic locks * refactors metrics registration to own method on service for testability. Adds tests. * Register sql storage server metrics from within the service * fixes test * troubleshooting drone test failures. Maybe timing when starting instrumentation server? * Waits until instrumentation server has started. Updates tests. * defer wont get called unless theres an error. removing. * wait for instrumentation server to be running * linter - close res body * use port 3000 for metrics and removes test metric inc() call * fixes test - updates port * refactors module server to provide an instrumentation server module when there is no ALL or CORE target provided and running as single target * make instrumentation server a dependency of all modules that do not run their own http server * adds module server test * adds tests for instrumentation service and removes old tests that aren't needed * ignore error in test * uses helper to start and run service * when running wait on ctx done or http server err * wait for http server * removes println * updates module server test to be integration test * require no error in goroutine * skips integration test when GRAFANA_TEST_DB not defined * move http server start into start, verify returned content * make test error when run fails * try waiting longer and see if drone tests pass * update integration test mysql creds to match drone * go back to only waiting half second * debug log drone mysql connection string * use same db connection config as drone * try using same hostname as drone * cant use localhost as mysql hostname in drone tests. Need to parse it from the cfg db connection string --------- Co-authored-by: Dan Cech <dcech@grafana.com>
Unified Storage
The unified storage projects aims to provide a simple and extensible backend to unify the way we store different objects within the Grafana app platform.
It provides generic storage for k8s objects, and can store data either within dedicated tables in the main Grafana database, or in separate storage.
By default it runs in-process within Grafana, but it can also be run as a standalone GRPC service (storage-server).
Storage Overview
There are 2 main tables, the entity table stores a "current" view of the objects, and the entity_history table stores a record of each revision of a given object.
Running Unified Storage
Baseline configuration
The minimum config settings required are:
; dev mode is required
app_mode = development
; need to specify target here for override to work later
target = all
[server]
; https is required for kubectl
protocol = https
[feature_toggles]
; enable unified storage
unifiedStorage = true
; enable k8s apiserver
grafanaAPIServer = true
; store playlists in k8s
kubernetesPlaylists = true
; store json id token in context
idForwarding = true
[grafana-apiserver]
; use unified storage for k8s apiserver
storage_type = unified
With this configuration, you can run everything in-process. Run the Grafana backend with:
bra run
or
make run
The default kubeconfig sends requests directly to the apiserver, to authenticate as a grafana user, create grafana.kubeconfig:
apiVersion: v1
clusters:
- cluster:
insecure-skip-tls-verify: true
server: https://127.0.0.1:3000
name: default-cluster
contexts:
- context:
cluster: default-cluster
namespace: default
user: default
name: default-context
current-context: default-context
kind: Config
preferences: {}
users:
- name: default
user:
username: <username>
password: <password>
Where <username> and <password> are credentials for basic auth against Grafana. For example, with the default credentials:
username: admin
password: admin
In this mode, you can interact with the k8s api. Make sure you are in the directory where you created grafana.kubeconfig. Then run:
kubectl --kubeconfig=./grafana.kubeconfig get playlist
If this is your first time running the command, a successful response would be:
No resources found in default namespace.
To create a playlist, create a file playlist-generate.yaml:
apiVersion: playlist.grafana.app/v0alpha1
kind: Playlist
metadata:
generateName: x # anything is ok here... except yes or true -- they become boolean!
labels:
foo: bar
spec:
title: Playlist with auto generated UID
interval: 5m
items:
- type: dashboard_by_tag
value: panel-tests
- type: dashboard_by_uid
value: vmie2cmWz # dashboard from devenv
then run:
kubectl --kubeconfig=./grafana.kubeconfig create -f playlist-generate.yaml
For example, a successful response would be:
playlist.playlist.grafana.app/u394j4d3-s63j-2d74-g8hf-958773jtybf2 created
When running
kubectl --kubeconfig=./grafana.kubeconfig get playlist
you should now see something like:
NAME TITLE INTERVAL CREATED AT
u394j4d3-s63j-2d74-g8hf-958773jtybf2 Playlist with auto generated UID 5m 2023-12-14T13:53:35Z
Use a separate database
By default Unified Storage uses the Grafana database. To run against a separate database, update custom.ini by adding the following section to it:
[entity_api]
db_type = mysql
db_host = localhost:3306
db_name = grafana
db_user = <username>
db_pass = <password>
MySQL and Postgres are both supported. The <username> and <password> values can be found in the following devenv docker compose files: MySQL and Postgres.
Then, run
make devenv sources=<source>
where source is either mysql or postgres.
Finally, run the Grafana backend with
bra run
or
make run
Run as a GRPC service
Start GRPC storage-server
This currently only works with a separate database configuration (see previous section).
Start the storage-server with:
GF_DEFAULT_TARGET=storage-server ./bin/grafana server target
The GRPC service will listen on port 10000
Use GRPC server
To run grafana against the storage-server, override the storage_type setting:
GF_GRAFANA_APISERVER_STORAGE_TYPE=unified-grpc ./bin/grafana server
You can then list the previously-created playlists with:
kubectl --kubeconfig=./grafana.kubeconfig get playlist
Changing protobuf interface
- install protoc
- install the protocol compiler plugin for Go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
- make changes in
.protofile - to compile all protobuf files in the repository run
make protobufat its top level