Amazon ESでISMポリシーを設定する

## やりたいこと
Amazon Elasticsearch Service（以下Amazon ES）でISMを設定してUltraWarmを動かしたい。
Amazon ES側の公式ドキュメントの説明が少ないので、OpenDistroのドキュメントや先達の記録を参考にしつつ、手探りで進めてみる。

> （2021/9/7追記）
> 最近のエンジンアップデートで、テンプレート経由でのISMポリシーアタッチはdeplicatedとなったようです。
> 現在は、ISMポリシー内に適用対象のインデックスパターンを直接記載する形に変更されています。
> 参考：https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ism.html


### 参考：
[Index State Management](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/ism.html)
[Amazon ES用のUltraWarm](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/ultrawarm.html)
[Index State Management(OpenDistro)](https://opendistro.github.io/for-elasticsearch-docs/docs/ism/)
[ISM API(OpenDistro)](https://opendistro.github.io/for-elasticsearch-docs/docs/ism/api/)

## やってみる

### 前提条件

- UltraWarm付き、バージョン7.9のAmazon ESドメインが作成済み。
- 手元の端末からアクセスできるよう、アクセスポリシーを構成済み。
- bashで実行。

### ISMポリシー作成
- ポリシードキュメントを準備。
    - `ism-policy`というポリシーを作ってみる。
    - [公式](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/ism.html)のサンプルポリシーをベースに、「インデックス作成後5分経過したらUltraWarmへ移動、15分経過したら削除」の内容とする。
    - JSONファイルを作成して、引数渡しでISMポリシーを作成する。

**※2021/3/4追記**

- timeoutを短くし過ぎると、ステートの移行が失敗することがある模様。
- 以下の例では元々timeout=5m、delay=5mとしていたが、warmステートへの移行は成功したもののdeleteステートへの移行（削除）が`Action timed out`となってしまった。
- timeout=2h、delay=1hとしたところ無事成功。混乱を避けるため、後追いとなるが下記JSONも修正した。

```json:ism-policy.json
{
  "policy": {
    "description": "Demonstrate a hot-warm-delete workflow.",
    "default_state": "hot",
    "schema_version": 1,
    "states": [{
        "name": "hot",
        "actions": [],
        "transitions": [{
          "state_name": "warm",
          "conditions": {
            "min_index_age": "5m"
          }
        }]
      },
      {
        "name": "warm",
        "actions": [{
          "warm_migration": {},
          "timeout": "2h",
          "retry": {
            "count": 5,
            "delay": "1h"
          }
        }],
        "transitions": [{
          "state_name": "delete",
          "conditions": {
            "min_index_age": "15m"
          }
        }]
      },
      {
        "name": "delete",
        "actions": [{
            "delete": {}
        }],
        "transitions": []
      }
    ]
  }
}
```

- ISMポリシーをPUT。
    - 結果はポリシードキュメントがそのまま返されるだけなので省略。

```bash:ISMポリシー作成
$ curl -X PUT https://<文字列>.ap-northeast-1.es.amazonaws.com/_opendistro/_ism/policies/ism-policy?pretty -H 'Content-Type: application/json' -d @ism-policy.json
```

- ISMポリシーを確認。
    - 同じく長いので、存在確認できたらOK。

```bash:ISMポリシー確認
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_opendistro/_ism/policies/ism-policy?pretty | head -8 
```

```bash:結果
{
  "_id" : "ism-policy",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "policy" : {
    "policy_id" : "ism-policy",
    "description" : "Demonstrate a hot-warm-delete workflow.",
```

### インデックステンプレート作成

- ポリシードキュメントを準備。
    - 作成したポリシーを新規インデックスに自動アタッチするよう、インデックステンプレート（`ism-settings`）を作成する。

```json:ism-settings.json
{
	"template": "log-*",
	"settings": {
		"index": {
			"number_of_shards": 1,
			"opendistro.index_state_management.policy_id": "ism-policy"
		}
	}
}
```

- インデックステンプレートをPUT。
    - 結果は省略。

```bash:インデックステンプレート作成
$ curl -X PUT https://<文字列>.ap-northeast-1.es.amazonaws.com/_template/ism-settings?pretty -H 'Content-Type: application/json' -d @ism-settings.json
```

- インデックステンプレートを確認。

```bash:インデックステンプレート
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_template/ism-settings?pretty
```

```bash:結果
{
  "ism-settings" : {
    "order" : 0,
    "index_patterns" : [
      "log-*"
    ],
    "settings" : {
      "index" : {
        "number_of_shards" : "1",
        "opendistro" : {
          "index_state_management" : {
            "policy_id" : "ism-policy"
          }
        }
      }
    },
    "mappings" : { },
    "aliases" : { }
  }
}
```

ISMポリシーが設定に含まれていることが分かる。
これで、`log-`で始まるインデックスには自動的にISMポリシーがアタッチされるようになる（はず）。

### テストの準備
- テストインデックスを作る。
    - インデックステンプレートに合致するよう`log-20210217`というインデックスを作り、同時にデータを投入する。
    - ちなみにsample.jsonの中身はこんな感じ（[公式](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-gsg-upload-data.html)のサンプルから拝借）。

```json:sample.json
{
	"director": "Burton, Tim",
	"genre": ["Comedy","Sci-Fi"],
	"year": 1996,
	"actor": ["Jack Nicholson","Pierce Brosnan","Sarah Jessica Parker"],
	"title": "Mars Attacks!"
}
```

```bash:テストインデックス作成＆データ投入
$ curl -X PUT https://<文字列>.ap-northeast-1.es.amazonaws.com/log-20210217/_doc/1?pretty -H 'Content-Type: application/json' -d @sample.json
```

- インデックス設定を確認する。

```bash:インデックス設定の確認
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/log-20210217?pretty
```

```bash:結果
$ {
  "log-20210217" : {
    "aliases" : { },
    "mappings" : { },
    "settings" : {
      "index" : {
        "opendistro" : {
          "index_state_management" : {
            "policy_id" : "ism-policy"
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "log-20210217",
        "creation_date" : "1613518166590",
        "number_of_replicas" : "1",
        "uuid" : "PTgQT-EwQlSyzfqo_S7iCg",
        "version" : {
          "created" : "7090199"
        }
      }
    }
  }
}
```

無事ISMポリシーがアタッチされている。
ついでにインデックス一覧の方でも確認しておく。

```bash:インデックス一覧
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_cat/indices?v | egrep 'log-|uuid'
```
```bash:結果
health status index                          uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   log-20210217                   BTmZU_MBS-yMss2uFrvbHQ   1   0          1            0      6.2kb          6.2kb
```

### テスト

- ISMの挙動を確認する（①ホット→UltraWarm）。

```bash:UltraWarmの移行状態の確認
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_ultrawarm/migration/_status?v
```
```bash:結果
index migration_type state
```

空。

```bash:UltraWarmの移行状態の確認（インデックス単位）
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_ultrawarm/migration/log-20210217/_status?pretty
```
```bash:結果
{
  "error" : {
    "root_cause" : [
      {
        "type" : "illegal_argument_exception",
        "reason" : "Index [log-20210217] has no active migrations"
      }
    ],
    "type" : "illegal_argument_exception",
    "reason" : "Index [log-20210217] has no active migrations"
  },
  "status" : 400
}
```

エラー。

もしかしてもう終わったのか？
[公式](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/ultrawarm.html#ultrawarm-migrating)によるとUltraWarmに移行したインデックスには`"box_type" : "warm"`の項目が現れているはずなので、確認してみる。

```bash:UltraWarm移行確認
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/log-20210217 | jq '.[].settings.index.routing.allocation'
```
```bash:結果
null
```

...ということで、まだのようだ。
作成後5分待てばOKかと思ったが、どうやらポリシーの評価は小一時間ごとに起動するISMジョブによって行われるようで、ポリシーアタッチからしばらく待たないとダメっぽい。

>ポリシーをインデックスにアタッチすると、ISM は 30～48 分ごとに実行されるジョブを作成し、ポリシーアクションを実行して条件を確認してから、インデックスを別の状態に移行します。このジョブを実行する基本時間は 30 分ごとです。さらに、0～60% のランダムなジッターが追加され、すべてのインデックスから同時にアクティビティが急増しないようにします。 

今回はテストなので分単位にしているが、もともと日単位で移行したり削除したりするための仕組みなので、運用上はそれで問題はなさそうではある。
ということで、しばらく放置して別の作業に向かうことにする。

### テスト（再訪）

ポリシーアタッチから約2時間。
再度確認してみる。

```bash:UltraWarm移行確認
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/log-20210217 | jq '.[].settings.index.routing.allocation'
```
```bash:結果
        "routing" : {
          "allocation" : {
            "require" : {
              "box_type" : "warm"
            }
          }
```

今度は出てきた。無事UltraWarmノードに移行されている模様。
ちなみにマネジメントコンソールのAmazon ESダッシュボードにも"UltraWarmストレージの使用状況"という列があり、そこの容量が増えていることでも確認できる。

- ISMの挙動を確認する（②UltraWarm→削除）。

さらに10分待てばインデックスが削除、されて欲しいところだが、これもISMジョブが巡回するのを待つ時間の方が方が長そうなので、今回は省略。

### 掃除

- インデックステンプレートを削除（結果は省略）。

```bash:インデックステンプレート削除
$ curl -X DELETE https://<文字列>.ap-northeast-1.es.amazonaws.com/_template/ism-settings?pretty
```

- ISMポリシーを削除。

```bash:ISMポリシー削除
$ curl -X DELETE https://<文字列>.ap-northeast-1.es.amazonaws.com/_opendistro/_ism/policies/ism-policy?pretty
```
```bash:結果
{
  "_index" : ".opendistro-ism-config",
  "_type" : "_doc",
  "_id" : "ism-policy",
  "_version" : 2,
  "result" : "deleted",
  "forced_refresh" : true,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}
```

### 余談

- UltraWarmへの移行確認には以下のコマンドも使える。特に`explain`が有益。

```bash:ISM実行状況の確認
$ curl -X GET https://<エンドポイント>.ap-northeast-1.es.amazonaws.com/_opendistro/_ism/explain/<インデックス名>
```

```bash:UltraWarmに移行されたインデックスの表示
$ curl -X GET https://<エンドポイント>.ap-northeast-1.es.amazonaws.com/_cat/indices/_warm?v
```

- ISMを待たず、直接APIでUltraWarmに送り込んでしまいたい場合はこちら（`_warm`を`_hot`に変えると、ホットノードに戻すこともできる）。

```bash:強制移行
$ curl -X POST https://<文字列>.ap-northeast-1.es.amazonaws.com/_ultrawarm/migration/log-20210217/_warm
```
- 以下のコマンドで、ホットノード上にある、あるいはUltraWarmに移動したインデックスの内容を取得できる。取れる内容はインデックスを指定してGETした場合と同じ。

```bash:それぞれのノードにあるインデックスの取得
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_hot?pretty
$ curl -X GET https://<文字列>.ap-northeast-1.es.amazonaws.com/_warm?pretty
```