[elasticsearch] Add migration for Kibana 6.x index

Elasticsearch 6.x dropped support for mapping types[1], which by default
the Kibana index used. This means that when deploying ELK 6.x, the
Kibana index must be migrated to the new schema to preserve dashboards
and visualizations. There is a process defined[2], which involves
creating a new index with the specified schema, then reindexing the old
index's data into the new index, then doing a rename/delete.

This adds support for that workflow via Ansible. It takes place after
the ES container is restarted after an upgrade, so there will be a
(short) period of time where the Kibana index is not migrated. During
this time, Kibana still loads, but presents the user with a status
screen informing that the index needs migration.

[1]:
https://www.elastic.co/guide/en/elasticsearch/reference/6.x/removal-of-types.html
[2]: https://www.elastic.co/guide/en/kibana/6.x/migrating-6.0-index.html

Implements: blueprint elasticsearch-kibana-version-upgrade
Depends-On: https://review.opendev.org/709624
Change-Id: I4550629e2113f3da7f1cecfeab0d5fe0d899dae8
This commit is contained in:
Jason Anderson 2020-02-24 15:36:46 -06:00
parent 4d46c428d0
commit 8c489009c2
No known key found for this signature in database
GPG Key ID: 9207452BF63947DD
3 changed files with 377 additions and 0 deletions

View File

@ -0,0 +1,264 @@
{
"settings" : {
"number_of_shards" : 1,
"index.mapper.dynamic": false
},
"mappings" : {
"doc": {
"properties": {
"type": {
"type": "keyword"
},
"updated_at": {
"type": "date"
},
"config": {
"properties": {
"buildNum": {
"type": "keyword"
}
}
},
"index-pattern": {
"properties": {
"fieldFormatMap": {
"type": "text"
},
"fields": {
"type": "text"
},
"intervalName": {
"type": "keyword"
},
"notExpandable": {
"type": "boolean"
},
"sourceFilters": {
"type": "text"
},
"timeFieldName": {
"type": "keyword"
},
"title": {
"type": "text"
}
}
},
"visualization": {
"properties": {
"description": {
"type": "text"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"savedSearchId": {
"type": "keyword"
},
"title": {
"type": "text"
},
"uiStateJSON": {
"type": "text"
},
"version": {
"type": "integer"
},
"visState": {
"type": "text"
}
}
},
"search": {
"properties": {
"columns": {
"type": "keyword"
},
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"sort": {
"type": "keyword"
},
"title": {
"type": "text"
},
"version": {
"type": "integer"
}
}
},
"dashboard": {
"properties": {
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"optionsJSON": {
"type": "text"
},
"panelsJSON": {
"type": "text"
},
"refreshInterval": {
"properties": {
"display": {
"type": "keyword"
},
"pause": {
"type": "boolean"
},
"section": {
"type": "integer"
},
"value": {
"type": "integer"
}
}
},
"timeFrom": {
"type": "keyword"
},
"timeRestore": {
"type": "boolean"
},
"timeTo": {
"type": "keyword"
},
"title": {
"type": "text"
},
"uiStateJSON": {
"type": "text"
},
"version": {
"type": "integer"
}
}
},
"url": {
"properties": {
"accessCount": {
"type": "long"
},
"accessDate": {
"type": "date"
},
"createDate": {
"type": "date"
},
"url": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 2048
}
}
}
}
},
"server": {
"properties": {
"uuid": {
"type": "keyword"
}
}
},
"timelion-sheet": {
"properties": {
"description": {
"type": "text"
},
"hits": {
"type": "integer"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"timelion_chart_height": {
"type": "integer"
},
"timelion_columns": {
"type": "integer"
},
"timelion_interval": {
"type": "keyword"
},
"timelion_other_interval": {
"type": "keyword"
},
"timelion_rows": {
"type": "integer"
},
"timelion_sheet": {
"type": "text"
},
"title": {
"type": "text"
},
"version": {
"type": "integer"
}
}
},
"graph-workspace": {
"properties": {
"description": {
"type": "text"
},
"kibanaSavedObjectMeta": {
"properties": {
"searchSourceJSON": {
"type": "text"
}
}
},
"numLinks": {
"type": "integer"
},
"numVertices": {
"type": "integer"
},
"title": {
"type": "text"
},
"version": {
"type": "integer"
},
"wsState": {
"type": "text"
}
}
}
}
}
}
}

View File

@ -0,0 +1,111 @@
---
- name: Set fact for Elasticsearch URL
set_fact:
elasticsearch_url: "{{ internal_protocol }}://{{ kolla_internal_vip_address | put_address_in_context('url') }}:{{ elasticsearch_port }}"
- name: Wait for Elasticsearch
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}"
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
retries: 10
delay: 5
register: result
until: ('status' in result) and result.status == 200
- name: Check state of migration
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}/.kibana/_mappings/doc"
status_code: [200, 404]
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
register: kibana_6_index
# The official procedure for migrating the Kibana index:
# https://www.elastic.co/guide/en/kibana/6.x/migrating-6.0-index.html
- name: Migrate Kibana index to 6.x
block:
- name: Set .kibana index to read-only
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}/.kibana/_settings"
method: PUT
status_code: 200
return_content: yes
body: |
{
"index.blocks.write": true
}
body_format: json
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
- name: Create .kibana-6 index
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}/.kibana-6"
method: PUT
status_code: 200
return_content: yes
body: "{{ lookup('file', 'kibana-6-index.json') }}"
body_format: json
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
- name: Reindex .kibana into .kibana-6
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}/_reindex"
method: POST
status_code: 200
return_content: yes
body: |
{
"source": {
"index": ".kibana"
},
"dest": {
"index": ".kibana-6"
},
"script": {
"inline": "ctx._source = [ ctx._type : ctx._source ]; ctx._source.type = ctx._type; ctx._id = ctx._type + \":\" + ctx._id; ctx._type = \"doc\"; ",
"lang": "painless"
}
}
body_format: json
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
- name: Alias .kibana-6 to .kibana and remove legacy .kibana index
become: true
kolla_toolbox:
module_name: uri
module_args:
url: "{{ elasticsearch_url }}/_aliases"
method: POST
status_code: 200
return_content: yes
body: |
{
"actions" : [
{ "add": { "index": ".kibana-6", "alias": ".kibana" } },
{ "remove_index": { "index": ".kibana" } }
]
}
body_format: json
delegate_to: "{{ groups['elasticsearch'][0] }}"
run_once: true
when: ('status' in kibana_6_index) and kibana_6_index.status != 200

View File

@ -1,5 +1,7 @@
---
- include_tasks: config.yml
- include_tasks: migrate-kibana-index.yml
- name: Flush handlers
meta: flush_handlers