概要

ここではバックエンドデータソースプラグインの開発手順を記載する。

目次

開発環境の構築

https://grafana.com/tutorials/build-a-data-source-backend-plugin/ を参考に開発環境を構築する。

ビルドには以下が必要との事 (2021/10 現在)

以下、最初から構築する手順を記載する。

事前に必要なものをインストール。

apt update
apt install -y wget curl git curl nodejs npm

Go のインストール

curl -L -o go1.16.9.linux-amd64.tar.gz https://golang.org/dl/go1.16.9.linux-amd64.tar.gz
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.16.9.linux-amd64.tar.gz
echo "PATH=\$PATH:/usr/local/go/bin" >> ~/.bashrc

nodejsの新しいバージョンのインストール ( nパッケージを使って新しいバージョンをインストール )

npm install -g n
n install 16.11.0
node --version

Mageのインストール

echo "GOPATH=$HOME/go" >>~/.bashrc
source ~/.bashrc
mkdir -p $HOME/go/bin
git clone https://github.com/magefile/mage
cd mage
go run bootstrap.go
echo "PATH=\$PATH:$HOME/go/bin" >>~/.bashrc
source ~/.bashrc

grafana-plugin-sdk for go のインストール

go get -u github.com/grafana/grafana-plugin-sdk-go

最初にインストールした古いバージョンの nodejs npm を削除しておく

apy remove nodehsnpm install -g n
n install 16.11.0
node --version

新しいバージョンの Yarn をインストールする

apt remove -y cmdtest
apt remove -y yarn
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
apt-get update && apt-get install -y yarn

@grafana/toolkit のインストール

npm install -g @grafana/toolkit

プラグインの雛形の作成

npx @grafana/toolkit plugin:create my-backend-datasource-test
Need to install the following packages:
Ok to proceed? (y) y

? Select plugin type Backend Datasource Plugin
✔ Fetching plugin template...
? Plugin name my-backend-datasource-test
? Organization (used as part of plugin ID) sample
? Description 
? Keywords (separated by comma) 
? Author myname
? Your URL (i.e. organisation url) 
    
    Your plugin details
    ---
    Name:  my-backend-datasource-test
    ID:  sample-my-backend-datasource-test
    Description:  
    Keywords:  []
    Author:  myname
    Organisation:  sample
    Website:  
    
? Is that ok? Yes
✔ Saving package.json and plugin.json files
✔ Cleaning
    
    Congrats! You have just created Grafana Backend Datasource Plugin.
    
    Learn more about Grafana Plugins at https://grafana.com/docs/grafana/latest/plugins/developing/development/

ビルド確認

cd my-backend-datasource-test
mage -v

データソースプラグインのト作成

バックエンドのデータソースプラグインは設定画面とバックエンド処理の2つで成り立っており、フロント部分は TypeScrypt 、バックエンド部分は Go で作成する必要がある。
その為、ビルドは別々に行う事になるが、ビルド結果は両方とも dist 配下に出力される為、プラグインのデプロイは dist フォルダを grafana のプラグインディレクトリに配置するだけでOK。

フロント部分の作成

フロントエンドは、データソース自体の設定画面と各パネルで使用するクエリ編集画面用の2つある。

設定画面( ConfigEditor.tsx ) の作成

中身は react コンポーネントだが、各入力フィールドは Grafana の UIコンポーネントを利用して作成する。
通常の必要なフィールドは FormField、よりセキュアな情報を扱うフィールドは SecretFormField コンポーネントを利用して作成する。

以下、雛形生成された ConfigEditor.tsx より抜粋。

      :
    return (
      <div className="gf-form-group">
        <div className="gf-form">
          <FormField
            label="Path"
            labelWidth={6}
            inputWidth={20}
            onChange={this.onPathChange}
            value={jsonData.path || ''}
            placeholder="json field returned to frontend"
          />
        </div>

        <div className="gf-form-inline">
          <div className="gf-form">
            <SecretFormField
              isConfigured={(secureJsonFields && secureJsonFields.apiKey) as boolean}
              value={secureJsonData.apiKey || ''}
              label="API Key"
              placeholder="secure json field (backend only)"
              labelWidth={6}
              inputWidth={20}
              onReset={this.onResetAPIKey}
              onChange={this.onAPIKeyChange}
            />
          </div>
        </div>
      </div>
    );
  } 
} 

値変更時の処理は、項目毎に onChange メソッドを実装する必要がある。
※セキュア項目は onReset 時のメソッドも必要。

以下、雛形生成された ConfigEditor.tsx より抜粋。

  :
export class ConfigEditor extends PureComponent<Props, State> {
  onPathChange = (event: ChangeEvent<HTMLInputElement>) => {
    const { onOptionsChange, options } = this.props;
    const jsonData = {
      ...options.jsonData,
      path: event.target.value,
    };
    onOptionsChange({ ...options, jsonData });
  };

  // Secure field (only sent to the backend)
  onAPIKeyChange = (event: ChangeEvent<HTMLInputElement>) => {
    const { onOptionsChange, options } = this.props;
    onOptionsChange({
      ...options,
      secureJsonData: {
        apiKey: event.target.value,
      },
    });
  };

  onResetAPIKey = () => {
    const { onOptionsChange, options } = this.props;
    onOptionsChange({
      ...options,
      secureJsonFields: {
        ...options.secureJsonFields,
        apiKey: false,
      },
      secureJsonData: {
        ...options.secureJsonData,
        apiKey: '',
      },
    });
  };
  :

項目を追加する場合は、 types.ts に追加する。
デフォルトの状態だと、通常の設定項目は MyDataSourceOptions、セキュア項目は MySecureJsonData に定義されている為、ここに追加する。

types.ts

import { DataQuery, DataSourceJsonData } from '@grafana/data';
  
export interface MyQuery extends DataQuery {
  // ここはクエリ画面の項目定義
  queryText?: string;
  constant: number;
  withStreaming: boolean;
}

export const defaultQuery: Partial<MyQuery> = {
  // ここはクエリ画面の項目のデフォルト値
  constant: 6.5,
  withStreaming: false,
};

/**
 * These are options configured for each DataSource instance.
 */
export interface MyDataSourceOptions extends DataSourceJsonData {
  // ここに通常の設定項目
  path?: string;
}

/**
 * Value that is used in the backend, but never sent over HTTP to the frontend
 */
export interface MySecureJsonData {
  // ここにセキュアな設定項目
  apiKey?: string;
}

クエリ画面 ( QueryEditor.tsx ) の作成

クエリ画面側も設定画面と同じく react コンポーネントとして作成する。
※項目自体を追加する場合は、設定画面と同じく types.ts の編集も必要。

以下、雛形生成された QueryEditor.tsx をそのまま記載。

import { LegacyForms } from '@grafana/ui';
import { QueryEditorProps } from '@grafana/data';
import { DataSource } from './datasource';
import { defaultQuery, MyDataSourceOptions, MyQuery } from './types';

const { FormField, Switch } = LegacyForms;

type Props = QueryEditorProps<DataSource, MyQuery, MyDataSourceOptions>;

export class QueryEditor extends PureComponent<Props> {
  onQueryTextChange = (event: ChangeEvent<HTMLInputElement>) => {
    const { onChange, query } = this.props;
    onChange({ ...query, queryText: event.target.value });
  };

  onConstantChange = (event: ChangeEvent<HTMLInputElement>) => {
    const { onChange, query, onRunQuery } = this.props;
    onChange({ ...query, constant: parseFloat(event.target.value) });
    // executes the query
    onRunQuery();
  };

  onWithStreamingChange = (event: SyntheticEvent<HTMLInputElement>) => {
    const { onChange, query, onRunQuery } = this.props;
    onChange({ ...query, withStreaming: event.currentTarget.checked });
    // executes the query
    onRunQuery();
  };

  render() {
    const query = defaults(this.props.query, defaultQuery);
    const { queryText, constant, withStreaming } = query;

    return (
      <div className="gf-form">
        <FormField
          width={4}
          value={constant}
          onChange={this.onConstantChange}
          label="Constant"
          type="number"
          step="0.1"
        />
        <FormField
          labelWidth={8}
          value={queryText || ''}
          onChange={this.onQueryTextChange}
          label="Query Text"
          tooltip="Not used yet"
        />
        <Switch checked={withStreaming || false} label="Enable streaming (v8+)" onChange={this.onWithStreamingChange} />
      </div>
    );
  }
}

ビルド等は yarn を使用して行う事ができる。( package.json を参照 )

依存モジュールのインストール

yaren install

ビルド

yaren build

バックエンド処理の作成

バックエンド部分は Go で作成する。

TODO:

トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS