[AWS]Amazon Elasticsearch Serviceのバージョンをアップデート(移行)してみる

### 用意するもの
***
1. AWS ElasticSearch Service ドメイン:バージョン5.x

### 公式ドキュメントを見る
***
[別のElasticsearchバージョンへの以降](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-version-migration.html)
1. 公式ドキュメントを読むと下記注意事項がある(上記公式ドキュメントから引用)

    重要
    バージョン 6.0 で作成されたインデックスでは、複数のマッピングタイプがサポートされなくなりました。バージョン 5.x で作成されたインデックスでは引き続き、6.0 クラスターに復元する際に複数のマッピングタイプがサポートされます。
    Amazon Kinesis Firehose や Amazon CloudWatch Logs などのサービスを使用して Amazon ES にデータをストリーミングする場合は、移行前にこれらのサービスが Elasticsearch 6.0 をサポートしていることを確認します。
    AWS Lambda を使用する場合は、コードによって作成されるマッピングタイプがインデックスごとに 1 種類のみであることを確認します。

:construction:バージョン5.x => バージョン6.x にバージョンをアップデート(移行)する場合、複数のマッピングタイプがサポート外となっているため注意する

### 実際にバージョンをアップデートしてみる
***
ここで注意なのは、既に存在しているドメインのバージョンアップは出来ないということ
別ドメインを立てて、元ドメインの手動スナップショットから復元します
もちろん移行後は、元ドメインを削除しないと、ドメイン利用料金が発生しますね

と、いうことなので見出しを変えます

### 実際にバージョンを移行してみる
***
やること

1. 元ドメインのスナップショットを手動で取得
1. 移行先のドメインを作成
1. 移行先のドメインの`.kiban`をバージョン5.x用からバージョン6.x用に書き換える
1. 元ドメインのスナップショットを移行先のドメインに復元(.kibana以外)
1. 元ドメインが不要であれば削除(料金はかかりますが、すぐに消さないことをお勧めします)

```
Amazon Elasticsearch Serviceは自動スナップショットを毎日とっています
自動スナップショットは構成済みのAmazon S3 バケットに14日間保存されます(非課金対象
自動スナップショットはスナップショットの元となったドメイン内からしか読みこむことが出来ません
そのため、移行するときは `手動スナップショット` が必須となります
```

### 1. 元ドメインのスナップショットを手動で取得
[Amazon Elasticsearch Service インデックススナップショットの使用](https://docs.aws.amazon.com/ja_jp/elasticsearch-service/latest/developerguide/es-managedomains-snapshots.html#es-managedomains-snapshot-prerequisites)

#### 前提条件(上記公式ドキュメントから引用)

##### S3
Amazon Elasticsearch Serviceドメインの手動スナップショットを保存するため用意

```javascript:S3.ARN
arn:aws:s3:::es-index-backups
```

##### IAMロール
`"Service": "es.amazonaws.com"` のようにAmazon Elasticsearch Serviceを指定

```javascript:IAMロール
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

```javascript:IAMロール
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "iam:PassRole",
        "Resource": "arn:aws:iam::123456789012:role/TheServiceRole"
    }
}
```

##### IAMポリシー

```javascript:IAMポリシー
 {
    "Version":"2012-10-17",
    "Statement":[
        {
            "Action":[
                "s3:ListBucket"
            ],
            "Effect":"Allow",
            "Resource":[
                "arn:aws:s3:::es-index-backups"
            ]
        },
        {
            "Action":[
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Effect":"Allow",
            "Resource":[
                "arn:aws:s3:::es-index-backups/*"
            ]
        }
    ]
} 
```

#### 手動スナップショットレポジトリの登録
下記、Pythonファイルを作成して、手動スナップショットレポジトリを登録

```Python:register-repo.py

import boto3
import requests
from requests_aws4auth import AWS4Auth

host = '' # include https:// and trailing /
region = '' # e.g. us-west-1
service = 'es'
credentials = boto3.Session().get_credentials()
awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)

# REGISTER REPOSITORY

path = '_snapshot/my-snapshot-repo' # the Elasticsearch API endpoint
url = host + path

payload = {
  "type": "s3",
  "settings": {
    "bucket": "s3-bucket-name",
    "region": "",
    "role_arn": "arn:aws:iam::123456789012:role/TheServiceRole"
  }
}

headers = {"Content-Type": "application/json"}

r = requests.put(url, auth=awsauth, json=payload, headers=headers)

print(r.status_code)
print(r.text)

# # TAKE SNAPSHOT
# 
# path = '_snapshot/my-snapshot-repo/my-snapshot'
# url = host + path
# 
# r = requests.put(url, auth=awsauth)
# 
# print(r.text)
# 
# # DELETE INDEX
# 
# path = 'my-index'
# url = host + path
# 
# r = requests.delete(url, auth=awsauth)
# 
# print(r.text)
# 
# # RESTORE SNAPSHOT (ALL INDICES)
# 
# path = '_snapshot/my-snapshot-repo/my-snapshot/_restore'
# url = host + path
# 
# r = requests.post(url, auth=awsauth)
# 
# print(r.text)
# 
# # RESTORE SNAPSHOT (ONE INDEX)
# 
# path = '_snapshot/my-snapshot-repo/my-snapshot/_restore'
# url = host + path
# 
# payload = {"indices": "my-index"}
# 
# headers = {"Content-Type": "application/json"}
# 
# r = requests.post(url, auth=awsauth, json=payload, headers=headers)
# 
# print(r.text)
```

#### Amazon Elasticsearch Serviceに登録したS3のスナップショットディレクトリを確認
`$ curl -XGET '{elasticsearch-domain-endpoint}/{repository}/_all?pretty'`

```
例:
elasticsearch-domain-endpoint: https://search-xxx.es.amazonaws.com
repository: /_snapshot/backups

$ curl -XGET 'https://search-xxx.es.amazonaws.com/_snapshot/backups/_all?pretty' 
```

```
実行結果: スナップショットが一件も登録されていない
{
  "snapshots" : [ ]
}
```

#### 手動スナップショット作成
```
$ curl -XPUT '{elasticsearch-domain-endpoint}/{repository}/{snapshot-name}'
```

その後、ちゃんとできてるか確認

```
$ curl -XGET '{elasticsearch-domain-endpoint}/{repository}/_all?pretty'
```

### 2. 移行先のドメインを作成
### 3. 移行先のドメインの`.kiban`をバージョン5.x用からバージョン6.x用に書き換える
### 4. 元ドメインのスナップショットを移行先のドメインに復元(.kibana以外)
もちろんですが、移行先のドメインを指定すること

下記ですべてのindexを復元

```
$ curl -XPOST '{elasticsearch-domain-endpoint}/{repository}/{snapshot-name}/_restore'
```

下記で任意のindexを復元

```
$ curl -XPOST '{elasticsearch-domain-endpoint}/{repository}/{snapshot-name}/_restore' -d '{"indices": "my-index"}' -H 'Content-Type: application/json'
```

### 感想
***
だいぶ手間だね