Read-only Grafana data source plugin for AggregatorService (Chotki/Aggregator gRPC).
- Only read RPC methods (strict allowlist):
GetOwner,GetFullOwner,GetOwnerHits,GetOwnerMetadataGetKey,GetKeyHits,ListKeysGetOwnersWithBalance,GetAllOwnerIdsGetNodeCoreKey,ListNodeCoreKeys
- Query model:
method + params(no SQL/DSL in MVP) - Query editor modes:
- Builder (form fields by method)
- Raw JSON
- Output format:
tablestat
Use this section for fastest production-like installation from GitHub Releases:
- Releases: drpcorg/grafana-chotki-datasource/releases
- Recommended asset for Linux Grafana hosts:
grafana-chotki-datasource-<version>-linux.zip - Plugin ID:
grafana-chotki-datasource
# set VER to the release you want to install
export VER=1.0.1
curl -fL -o /tmp/grafana-chotki-datasource-linux.zip \
"https://github.com/drpcorg/grafana-chotki-datasource/releases/download/v${VER}/grafana-chotki-datasource-${VER}-linux.zip"
curl -fL -o /tmp/grafana-chotki-datasource-linux.zip.sha256 \
"https://github.com/drpcorg/grafana-chotki-datasource/releases/download/v${VER}/grafana-chotki-datasource-${VER}-linux.zip.sha256"cd /tmp
sha256sum -c grafana-chotki-datasource-linux.zip.sha256Expected: OK.
sudo mkdir -p /var/lib/grafana/plugins
sudo rm -rf /var/lib/grafana/plugins/grafana-chotki-datasource
sudo unzip -qo /tmp/grafana-chotki-datasource-linux.zip -d /var/lib/grafana/plugins
sudo chown -R grafana:grafana /var/lib/grafana/plugins/grafana-chotki-datasourceIf plugin is unsigned (for example, release was built without signing token), allow it explicitly:
[plugins]
allow_loading_unsigned_plugins = grafana-chotki-datasourceOr environment variable:
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=grafana-chotki-datasourceThen restart Grafana:
sudo systemctl restart grafana-serverMinimal provisioning example:
apiVersion: 1
datasources:
- name: grafana chotki datasource
type: grafana-chotki-datasource
access: proxy
jsonData:
grpcAddress: chotki:9393
insecure: true
timeoutMs: 4000
defaultLimit: 200
hardLimit: 1000
decodeIds: true
decodeEnums: true
decodeTimestamps: true- Grafana -> Data sources ->
grafana chotki datasource->Save & test. - Expect:
connected to AggregatorService. - Explore -> run
GetAllOwnerIds(table mode), expect status200.
{
"mode": "rpc",
"method": "ListKeys",
"params": {
"ownerId": "7e03c6f9-ede5-4225-9454-5bb34db55ce1",
"limit": 100
},
"options": {
"format": "table",
"decodeIds": true,
"decodeEnums": true,
"decodeTimestamps": true,
"limit": 200
}
}jsonData:
grpcAddress(host:port)insecure(default:true)timeoutMs(default:4000)defaultLimit(default:200)hardLimit(default:1000)decodeIds,decodeEnums,decodeTimestamps(default:true)
secureJsonData:
authTokentlsCACerttlsClientCerttlsClientKey
bytesIDs (ownerId,keyId) -> UUID string (or base64 ifdecodeIds=false)- Timestamps ->
time.Time+ RFC3339 string + unix seconds - Enum/int labels:
tier->free/paidmev_mode->unset/enabled/disabled
PublicKey.bytes-> base64ClientSpec-> parse JSON if valid, else keep raw- Arrays -> dual representation (
*_json+*_csv)
Sensitive fields are not masked in MVP.
npm installnpm run devmage -vnpm run serverSee:
provisioning/datasources/datasources.yml
- Enable unsigned plugins in Grafana:
allow_loading_unsigned_plugins=grafana-chotki-datasource
- Deploy artifact and restart Grafana.
- Sign plugin:
npm run sign- Publish versioned artifact to internal storage/registry.
- Canary rollout: one Grafana instance -> full pool.
- Rollback: previous artifact version + Grafana restart.
- Push a version tag (
v*, for examplev1.0.1). - Workflow
.github/workflows/release.ymlbuilds the plugin and publishes release assets:grafana-chotki-datasource-<version>.zip(all platforms)grafana-chotki-datasource-<version>-linux.zip(recommended for Linux Grafana hosts)*.sha256checksums
- If repository secret
GRAFANA_ACCESS_POLICY_TOKENis configured, the release workflow signs the plugin before packaging.
go test ./pkg/plugin/... -count=1npm run typecheck
npm run test:cinpm run server
npm run e2eThis flow validates the datasource against a real chotki gRPC server from the dproxy project.
cd ../dproxy
docker compose up -d chotki
docker compose ps chotkiOptional gRPC check:
grpcurl -plaintext localhost:9393 listExpected service: aggregator_api.AggregatorService.
cd /path/to/grafana-datasource-chotki/grafana-chotki-datasource
cp .env.integration.example .env.integrationDefault values:
DPROXY_NETWORK_NAME=dproxy_keymanagerCHOTKI_GRPC_ADDR=chotki:9393
npm run build
mage -vIf mage is not installed:
go install github.com/magefile/mage@latestdocker compose -f docker-compose.yaml -f docker-compose.integration.yaml --env-file .env.integration up -d
docker compose psVerify Grafana container is attached to the external dproxy network:
docker network inspect ${DPROXY_NETWORK_NAME:-dproxy_keymanager} | rg grafana-chotki-datasourceOpen http://localhost:3000:
- Data sources ->
chotki datasource->Save & test. - Explore -> run
GetAllOwnerIdsintableandstat. - If owner IDs exist:
GetOwner,GetFullOwner,GetOwnerHits,GetOwnerMetadata.
- Keys flow:
ListKeys-> takekey_id->GetKey,GetKeyHits.
- NodeCore flow:
ListNodeCoreKeys-> if found ->GetNodeCoreKey.
- Run
GetOwnersWithBalance.
ownerId=not-a-uuid-> expect validation errorparameter "ownerId" must be UUID or base64 bytes.- Timeout (deterministic):
docker pause dproxy-chotki-1, run query, thendocker unpause dproxy-chotki-1-> expectcontext deadline exceeded(status=504in Query Inspector/API). limit=999999inListKeys/ListNodeCoreKeys-> returned rows do not exceed datasourcehardLimit.- Stop chotki (
docker compose stop chotkiin dproxy) and rerun query -> expect transport error mapped toBadGateway(status=502in API response).
| Check | Expected |
|---|---|
| Save & test | connected to AggregatorService |
| GetAllOwnerIds | Works in table and stat |
| Owner pipeline | Owner methods work for valid ownerId |
| Key pipeline | ListKeys -> GetKey -> GetKeyHits works |
| NodeCore pipeline | ListNodeCoreKeys -> GetNodeCoreKey works if data exists |
| Converter output | UUID/time/enum/array fields are readable |
| Error mapping | invalid arg / timeout / unavailable mapped correctly |
If GetAllOwnerIds returns empty result, infrastructure is considered healthy and owner/key/nodecore scenarios are not applicable until data appears.
plugin.jsonchanges require Grafana restart.- Plugin ID is fixed:
grafana-chotki-datasource.