Kibana Plugin開発（Javascriptの自習）

#概要
 Javascript, Kibana,  Elasticsearchの自習用にKibana Plugin開発環境を構築するさいのメモです。
 Open Distro for Elasticsearch を使うので、Kibana, Elasticsearchは 6.7.1を使います。
 うそはないと思いますが、間違いはあるででしょうし、もっといい方法があると思いますが生温かい目で。。。参考にされる方は注意してください。

#開発環境の準備
- OSはCentOS7を利用
- Java : Elasticsearchを動かすのに必要です。open-jdk-11を使います。
- Git : Kibanaのコードを取得するのに使います。面倒なのでgit-allで全部いれます。
- Elasticsearch は6.7.1を使うのでダウンロードしておきます。
 - Elasticsearchのサイトのダウンロードページでpast releaseのところで探せます。
- nvm, yarn

開発用のアカウントは、pdevというものを作って利用しています。
以下は、pdevでの作業。

###gitの設定
開発マシンはESXi 仮想環境上のVLAN内にいるのでPROXYを設定してます。

```ShellSession
[pdev@kpdev ~]$ git config --global http.proxy http://172.16.1.1:8080
[pdev@kpdev ~]$ git config --global https.proxy http://172.16.1.1:8080
```


###KibanaをCLONE
まず開発に必要なKibanaの準備をします。
cloneしてブランチをV6.7.1にします。

```ShellSession
[pdev@kpdev ~]$ git clone https://github.com/elastic/kibana.git kibana
Cloning into 'kibana'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 524960 (delta 0), reused 1 (delta 0), pack-reused 524950
Receiving objects: 100% (524960/524960), 840.54 MiB | 8.43 MiB/s, done.
Resolving deltas: 100% (318801/318801), done.
Checking out files: 100% (18230/18230), done.
[pdev@kpdev ~]$ cd kibana/
[pdev@kpdev kibana]$ git checkout -b v6.7.1
Switched to a new branch 'v6.7.1'
[pdev@kpdev kibana]$ git branch
  master
* v6.7.1
 ```

###Node.jsのインストール

Kibanaの対象とするNode.jsをインストールします。

```ShellSession
[pdev@kpdev kibana]$ nvm install "$(cat .node-version)"
Downloading and installing node v10.15.2...
Downloading https://nodejs.org/dist/v10.15.2/node-v10.15.2-linux-x64.tar.xz...
######################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v10.15.2 (npm v6.4.1)
Creating default alias: default -> 10.15.2 (-> v10.15.2)
```

###必要なライブラリのダウンロード

3000以上のダウンロードが行われるようです。

```ShellSession
[pdev@kpdev kibana]$ yarn kbn bootstrap
yarn run v1.16.0
$ node scripts/kbn bootstrap
Running [bootstrap] command from [/home/pdev/kibana]:

Found [27] projects:

kibana
tqq packages
x   tqq elastic-datemath (@elastic/datemath)
　：

kibana: Registering Kibana pre-commit git hook...
kibana: success Kibana pre-commit git hook was installed successfully.

Bootstrapping completed!

Done in 510.53s.
```

###起動確認

Kibana、Elasticsearchともにフォアグランドで動作しますので、終了時は、CTRL+Cで終わらせます。

####Elasticsearch起動
まずは、開発対象となるElasticsearch6.7.1を起動してみます。

```ShellSession
[pdev@kpdev kibana]$ yarn es archive /opt/elasticsearch-6.7.1.tar.gz
yarn run v1.16.0
$ node scripts/es archive /opt/elasticsearch-6.7.1.tar.gz
 info Installing from an archive
   x info extracting /opt/elasticsearch-6.7.1.tar.gz
   x info extracted to /home/pdev/kibana/.es/elasticsearch-6.7.1
   x info setting bootstrap password to changeme
　:
   x info [o.e.l.LicenseService] [w1aIYaD] license [d664eee1-3a62-4f3b-8106-99b4481d6feb] mode [basic] - valid
```

Elasticsearchは、Kibanaの開発環境内で起動せず、別にインストールしたものを利用しても良いです。


####kibana起動
別のコンソールを開いて実行します。
Kibanaには別マシンからアクセスできるようにserver.hostにアドレスを設定しておきます。

Kibanaなの起動には結構時間（数分）がかかります。

```Shellsession
[pdev@kpdev ~]$ cd kibana/
[pdev@kpdev kibana]$ cd config/
[pdev@kpdev config]$ vi kibana.yml
  :
 server.host: "0.0.0.0"
  :
[pdev@kpdev config]$ cd ..
[pdev@kpdev kibana]$ yarn start
yarn run v1.16.0
$ sh ./bin/kibana --dev
  log   [13:01:02.711] [info][plugins-service] Plugin initialization disabled.
 watching for changes  (3053 files)
  log   [13:01:05.858] [info][server] basepath proxy server running at http://0.0.0.0:5601/zhm
  :
server    log   [13:04:51.710] [info][listening] Server running at http://0.0.0.0:5603/zhm
server    log   [13:04:52.455] [info][status][plugin:spaces@6.7.1] Status changed from yellow to green - Ready
```

ここまででればアクセスできます。
ブラウザでアクセスすると、コンパイルが走るのでまたちょっと待ちます。

```ShellSession
optmzr    log   [13:05:49.280] [info][optimize:dynamic_dll_plugin] Need to compile the client vendors dll
optmzr    log   [13:05:49.334] [info][optimize:dynamic_dll_plugin] Client vendors dll compilation started
optmzr    log   [13:06:17.453] [info][optimize:dynamic_dll_plugin] Client vendors dll compilation finished with success
optmzr    log   [13:06:40.745] [info][optimize:dynamic_dll_plugin] Client vendors dll compilation started
optmzr    log   [13:07:02.395] [info][optimize:dynamic_dll_plugin] Client vendors dll compilation finished with success
optmzr    log   [13:07:22.429] [info][optimize:dynamic_dll_plugin] Finished all dynamic dll plugin tasks
optmzr    log   [13:07:22.439] [info][optimize] Optimization success in 308.04 seconds
optmzr    log   [13:07:33.964] [info][optimize:dynamic_dll_plugin] No need to compile client vendors dll
optmzr    log   [13:07:33.966] [info][optimize:dynamic_dll_plugin] Finished all dynamic dll plugin tasks
optmzr    log   [13:07:33.967] [info][optimize] Optimization success in 9.28 seconds

```
確認がおわったらCTRL+CでKibanaを終了して、プラグイン開発環境を準備します。Elasticsearchはそのままにしておきます。


#プラグインテンプレートの作成

Kibanaに用意されているgenerate_pluginスクリプトを利用します。

実行すると質問があるので、説明と後はEnterキーで進めます。

プラグインは /_cat/indicesで取れる一覧を表示するものを作るので、catindicesとしています。

```Shellsession
[pdev@kpdev kibana]$ node scripts/generate_plugin catindices
? Provide a short description Index List
? What Kibana version are you targeting? 6.7.1
? Should an app component be generated? Yes
? Should translation files be generated? Yes
? Should a hack component be generated? Yes
? Should a server API be generated? Yes
? Should SCSS be used? Yes
Initialized empty Git repository in /home/pdev/kibana-extra/catindices/.git/
yarn run v1.16.0
$ node scripts/kbn bootstrap
Running [bootstrap] command from [/home/pdev/kibana]:

Found [28] projects:

kibana
tqq packages
x   tqq elastic-datemath (@elastic/datemath)
x   tqq eslint-config-kibana (@elastic/eslint-config-kibana)

 :
kibana: $ yarn build:types && node scripts/register_git_hook
kibana: $ tsc --p tsconfig.types.json
kibana: Registering Kibana pre-commit git hook...
kibana: success Kibana pre-commit git hook was installed successfully.

Bootstrapping completed!

Done in 129.67s.
success ?

  Your plugin has been created in ../kibana-extra/catindices. Move into that directory to run it:

    cd "../kibana-extra/catindices"
    yarn start
```

生成に成功すると、最後にディレクトリを移動して実行するようにメッセージが表示されます。
この通りディレクトリを移動して、Kibanaを起動します。

```Shellsession
[pdev@kpdev kibana]$ cd "../kibana-extra/catindices"
[pdev@kpdev catindices]$ yarn start
yarn run v1.16.0
warning package.json: No license field
$ plugin-helpers start
  :
```

Kibana起動後、ブラウザでアクセスすると、生成されたテンプレートのプラグインが左のメニューにCatindicesと表示されているはずです。

そのまま、プラグインの編集を行います。

###プラグイン開発ディレクトリ
生成されたディレクトリは主に以下のような構成になっています。

```plaintext
.
|-- README.md
|-- index.js //ここでexample.jsの初期化をしている
|-- node_modules
   :
|-- package.json
|-- public
|   |-- __tests__
|   |-- components
|   |   `-- main // ブラウザ側で動作する
|   |       |--  index.js
|   |       `--  main.js
|   `-- less
|-- server
|   |-- __tests__
|   `-- routes // Kibanaサーバ側で動作する
|       `-- example.js
|-- translations // 日本語化する場合にリソースをおく
`-- yarn.lock
```

とりあえずElasticsearchから情報を取得するものを作ってみます。
修正するのは、main.jsとexample.jsです。
main.jsはブラウザ側、example.jsはKiabanaサーバで動作します。

参照したURL
- Elasticsearch へのアクセス
 - https://www.elastic.co/guide/en/kibana/6.7/development-elasticsearch.html
- テーブル表示
 - https://elastic.github.io/eui/#/
 - https://elastic.github.io/eui/#/display/tables
- ElasticsearchからINDEXを取得するAPI
 - https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/6.x/index.html
 - https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/6.x/api-reference.html


まずはサーバ側の処理を修正。

Elasticsearchから取得する処理を追加。
Javascriptはまだ良くわからないので調べながらの修正です。
非同期で結果をうまく返す方法があると思うのですが。。。

```javascript:example.js
export default function (server) {

const {callWithRequest} = server.plugins.elasticsearch.getCluster('data');

  server.route({
    path: '/api/catindices/example',
    method: 'GET',
    async handler(req) {
      try {
        var lists ;
        await callWithRequest(req, 'cat.indices', { // Elasticsearch呼び出し 
            format : 'json'
          }
        ).then(function(resp){
           lists= resp;
        });
        return { idata: lists };

      } catch (error) {
        console.log('ERROR:[cat.indices]  ' + error);
        return { idata: "Error in Server:"+error };
      }
    }
  });

}
```

次にサーバからの結果をテーブルで表示できるように
main.js に処理を追加します。

テーブルはEuiFrameworkのEuiBasicTableを利用します。

```javascript:main.js
import React from 'react';
import {
  EuiBasicTable, // TABLE表示用
  EuiPage,
  EuiPageHeader,
  EuiTitle,
  EuiPageBody,
  EuiPageContent,
  EuiPageContentHeader,
  EuiPageContentBody,
  EuiText
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

const columns=[ // テーブルヘッダ
 { field:'health', name:'health', },
 { field:'status', name:'status', },
 { field:'index', name:'index', },
 { field:'uuid', name:'uuid', },
 { field:'pri', name:'pri' },
 { field:'rep', name:'rep' },
 { field:'docs.count', name:'docs.count' },
 { field:'docs.deleted', name:'docs.deleted' },
 { field:'store.size', name:'store.size' },
 { field:'pri.store.size', name:'pri.store.size' },
];

export class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = {idata:[]};
  }
  componentDidMount() {
    const { httpClient } = this.props;
    httpClient.get('../api/catindices/example').then((resp) => {
      this.setState({ idata: resp.data.idata }); // 取得するデータ名変更
    });
  }
  render() {
    const { title } = this.props;
    return (
      <EuiPage>
        <EuiPageBody>
          <EuiPageHeader>
            <EuiTitle size="l">
              <h1>
                <FormattedMessage
                  id="catindices.helloWorldText"
                  defaultMessage="{title} Hello World!"
                  values={{ title }}
                />
              </h1>
            </EuiTitle>
          </EuiPageHeader>
          <EuiPageContent>
            <EuiPageContentHeader>
              <EuiTitle>
                <h2>
                  <FormattedMessage
                    id="catindices.congratulationsTitle"
                    defaultMessage="Congratulations"
                  />
                </h2>
              </EuiTitle>
            </EuiPageContentHeader>
            <EuiPageContentBody>
              <EuiText>
                <h3>
                  <FormattedMessage
                    id="catindices.congratulationsText"
                    defaultMessage="You have successfully created your first Kibana Plugin!"
                  />
                </h3>
              </EuiText>
              <!-- 時間表示のテキストを削除して、テーブル追加 -->
              <EuiBasicTable
                items={this.state.idata} 
                columns={columns}
              />
            </EuiPageContentBody>
          </EuiPageContent>
        </EuiPageBody>
      </EuiPage>
    );
  }
}

```


これでElasticsearch内のINDEXの一覧が表示されます。
開発環境ですので、ファイルを修正するとKibanaが自動的に修正を反映していきますので、ブラウザでアクセスします。
エラーが出た場合は、ファイルを修正してブラウザでアクセスを繰り返すことになります。


これがプラグイン開発の一通りの流れです。