mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Merge upstream/main into branch
This commit is contained in:
commit
45da099839
774 changed files with 11076 additions and 10500 deletions
|
@ -21,7 +21,7 @@ snapshots.js
|
|||
# plugin overrides
|
||||
/src/core/lib/kbn_internal_native_observable
|
||||
/src/plugins/data/common/es_query/kuery/ast/_generated_/**
|
||||
/src/plugins/vis_type_timelion/common/_generated_/**
|
||||
/src/plugins/vis_types/timelion/common/_generated_/**
|
||||
/x-pack/plugins/apm/e2e/tmp/*
|
||||
/x-pack/plugins/canvas/canvas_plugin
|
||||
/x-pack/plugins/canvas/shareable_runtime/build
|
||||
|
|
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
@ -27,9 +27,9 @@
|
|||
/src/plugins/kibana_legacy/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_default_editor/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/metric/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_type_table/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/table/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/tagcloud/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_type_timelion/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/timelion/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_type_timeseries/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/vega/ @elastic/kibana-vis-editors
|
||||
/src/plugins/vis_types/vislib/ @elastic/kibana-vis-editors
|
||||
|
|
|
@ -56,12 +56,12 @@
|
|||
"server": "src/legacy/server",
|
||||
"statusPage": "src/legacy/core_plugins/status_page",
|
||||
"telemetry": ["src/plugins/telemetry", "src/plugins/telemetry_management_section"],
|
||||
"timelion": ["src/plugins/vis_type_timelion"],
|
||||
"timelion": ["src/plugins/vis_types/timelion"],
|
||||
"uiActions": "src/plugins/ui_actions",
|
||||
"visDefaultEditor": "src/plugins/vis_default_editor",
|
||||
"visTypeMarkdown": "src/plugins/vis_type_markdown",
|
||||
"visTypeMetric": "src/plugins/vis_types/metric",
|
||||
"visTypeTable": "src/plugins/vis_type_table",
|
||||
"visTypeTable": "src/plugins/vis_types/table",
|
||||
"visTypeTagCloud": "src/plugins/vis_types/tagcloud",
|
||||
"visTypeTimeseries": "src/plugins/vis_type_timeseries",
|
||||
"visTypeVega": "src/plugins/vis_types/vega",
|
||||
|
|
|
@ -753,19 +753,19 @@
|
|||
"references": [
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/plugin.ts"
|
||||
"path": "src/plugins/vis_types/table/public/plugin.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/plugin.ts"
|
||||
"path": "src/plugins/vis_types/table/public/plugin.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/target/types/public/plugin.d.ts"
|
||||
"path": "src/plugins/vis_types/table/target/types/public/plugin.d.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/target/types/public/plugin.d.ts"
|
||||
"path": "src/plugins/vis_types/table/target/types/public/plugin.d.ts"
|
||||
}
|
||||
],
|
||||
"children": [
|
||||
|
|
|
@ -5004,11 +5004,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeVega",
|
||||
|
@ -16631,11 +16631,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visualize",
|
||||
|
@ -16671,11 +16671,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "dashboard",
|
||||
|
@ -18119,11 +18119,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/plugin_services.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/plugin_services.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/plugin_services.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/plugin_services.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "indexPatternManagement",
|
||||
|
@ -18135,11 +18135,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "discover",
|
||||
|
@ -19008,27 +19008,27 @@
|
|||
"references": [
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx"
|
||||
}
|
||||
],
|
||||
"initialIsOpen": false
|
||||
|
@ -21706,15 +21706,15 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeVega",
|
||||
|
@ -24261,7 +24261,7 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/plugin.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/plugin.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimeseries",
|
||||
|
@ -24479,7 +24479,7 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/plugin.ts"
|
||||
"path": "src/plugins/vis_types/table/public/plugin.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimeseries",
|
||||
|
@ -27306,11 +27306,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeVega",
|
||||
|
@ -32208,11 +32208,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visualize",
|
||||
|
@ -32248,11 +32248,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "dashboard",
|
||||
|
@ -38924,11 +38924,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visualize",
|
||||
|
@ -38964,11 +38964,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_fn.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_fn.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "dashboard",
|
||||
|
@ -39892,27 +39892,27 @@
|
|||
"references": [
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx"
|
||||
"path": "src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx"
|
||||
}
|
||||
],
|
||||
"initialIsOpen": false
|
||||
|
|
|
@ -5927,11 +5927,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTable",
|
||||
"path": "src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts"
|
||||
"path": "src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeVega",
|
||||
|
@ -13270,11 +13270,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/plugin_services.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/plugin_services.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/plugin_services.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/plugin_services.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "indexPatternManagement",
|
||||
|
@ -13286,11 +13286,11 @@
|
|||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "visTypeTimelion",
|
||||
"path": "src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
"path": "src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts"
|
||||
},
|
||||
{
|
||||
"plugin": "discover",
|
||||
|
|
|
@ -898,11 +898,11 @@ warning: This document is auto-generated and is meant to be viewed inside our ex
|
|||
|
||||
| Deprecated API | Reference location(s) | Remove By |
|
||||
| ---------------|-----------|-----------|
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.DataPublicPluginStart.fieldFormats" text="fieldFormats"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/plugin.ts#:~:text=fieldFormats) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-server.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibCorePluginApi" section="def-public.AsyncPlugin" text="AsyncPlugin"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/plugin.ts#:~:text=AsyncPlugin), [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/public/plugin.ts#:~:text=AsyncPlugin), [plugin.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/target/types/public/plugin.d.ts#:~:text=AsyncPlugin), [plugin.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_table/target/types/public/plugin.d.ts#:~:text=AsyncPlugin) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.DataPublicPluginStart.fieldFormats" text="fieldFormats"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/plugin.ts#:~:text=fieldFormats) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-server.IndexPattern" text="IndexPattern"/> | [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern), [table_vis_controller.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/legacy/table_vis_controller.test.ts#:~:text=IndexPattern) | - |
|
||||
| <DocLink id="kibCorePluginApi" section="def-public.AsyncPlugin" text="AsyncPlugin"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/plugin.ts#:~:text=AsyncPlugin), [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/public/plugin.ts#:~:text=AsyncPlugin), [plugin.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/target/types/public/plugin.d.ts#:~:text=AsyncPlugin), [plugin.d.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/table/target/types/public/plugin.d.ts#:~:text=AsyncPlugin) | - |
|
||||
|
||||
|
||||
|
||||
|
@ -910,15 +910,15 @@ warning: This document is auto-generated and is meant to be viewed inside our ex
|
|||
|
||||
| Deprecated API | Reference location(s) | Remove By |
|
||||
| ---------------|-----------|-----------|
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.IndexPatternsContract" text="IndexPatternsContract"/> | [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.DataPublicPluginStart.indexPatterns" text="indexPatterns"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/plugin.ts#:~:text=indexPatterns) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.RangeFilterParams" text="RangeFilterParams"/> | [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.esQuery" text="esQuery"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.RangeFilterParams" text="RangeFilterParams"/> | [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.IndexPatternsContract" text="IndexPatternsContract"/> | [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-server.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.IndexPatternsContract" text="IndexPatternsContract"/> | [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.DataPublicPluginStart.indexPatterns" text="indexPatterns"/> | [plugin.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/plugin.ts#:~:text=indexPatterns) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.RangeFilterParams" text="RangeFilterParams"/> | [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.esQuery" text="esQuery"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=esQuery) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-public.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.RangeFilterParams" text="RangeFilterParams"/> | [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_renderer.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_renderer.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams), [timelion_vis_component.tsx](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/legacy/timelion_vis_component.tsx#:~:text=RangeFilterParams) | 8.1 |
|
||||
| <DocLink id="kibDataPluginApi" section="def-common.IndexPatternsContract" text="IndexPatternsContract"/> | [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [plugin_services.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/plugin_services.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract), [timelion_expression_input_helpers.test.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/components/timelion_expression_input_helpers.test.ts#:~:text=IndexPatternsContract) | - |
|
||||
| <DocLink id="kibDataPluginApi" section="def-server.Filter" text="Filter"/> | [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_request_handler.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/helpers/timelion_request_handler.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter), [timelion_vis_fn.ts](https://github.com/elastic/kibana/tree/master/src/plugins/vis_types/timelion/public/timelion_vis_fn.ts#:~:text=Filter) | 8.1 |
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
"tags": [],
|
||||
"label": "TableVisParams",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false,
|
||||
"children": [
|
||||
{
|
||||
|
@ -40,7 +40,7 @@
|
|||
"signature": [
|
||||
"number | \"\""
|
||||
],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -50,7 +50,7 @@
|
|||
"tags": [],
|
||||
"label": "showPartialRows",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -60,7 +60,7 @@
|
|||
"tags": [],
|
||||
"label": "showMetricsAtAllLevels",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -70,7 +70,7 @@
|
|||
"tags": [],
|
||||
"label": "showToolbar",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -80,7 +80,7 @@
|
|||
"tags": [],
|
||||
"label": "showTotal",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -99,7 +99,7 @@
|
|||
"text": "AggTypes"
|
||||
}
|
||||
],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -109,7 +109,7 @@
|
|||
"tags": [],
|
||||
"label": "percentageCol",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -122,7 +122,7 @@
|
|||
"signature": [
|
||||
"boolean | undefined"
|
||||
],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
],
|
||||
|
@ -137,7 +137,7 @@
|
|||
"tags": [],
|
||||
"label": "AggTypes",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false,
|
||||
"initialIsOpen": false
|
||||
}
|
||||
|
@ -153,7 +153,7 @@
|
|||
"signature": [
|
||||
"\"table\""
|
||||
],
|
||||
"path": "src/plugins/vis_type_table/common/types.ts",
|
||||
"path": "src/plugins/vis_types/table/common/types.ts",
|
||||
"deprecated": false,
|
||||
"initialIsOpen": false
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
"tags": [],
|
||||
"label": "_LEGACY_",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"children": [
|
||||
{
|
||||
|
@ -24,7 +24,7 @@
|
|||
"tags": [],
|
||||
"label": "DEFAULT_TIME_FORMAT",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -37,7 +37,7 @@
|
|||
"signature": [
|
||||
"(from: number, to: number, size: number, interval: string, min: string) => string"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": [
|
||||
|
@ -48,7 +48,7 @@
|
|||
"tags": [],
|
||||
"label": "from",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/lib/calculate_interval.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/lib/calculate_interval.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -58,7 +58,7 @@
|
|||
"tags": [],
|
||||
"label": "to",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/lib/calculate_interval.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/lib/calculate_interval.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -68,7 +68,7 @@
|
|||
"tags": [],
|
||||
"label": "size",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/lib/calculate_interval.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/lib/calculate_interval.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -78,7 +78,7 @@
|
|||
"tags": [],
|
||||
"label": "interval",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/lib/calculate_interval.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/lib/calculate_interval.ts",
|
||||
"deprecated": false
|
||||
},
|
||||
{
|
||||
|
@ -88,7 +88,7 @@
|
|||
"tags": [],
|
||||
"label": "min",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/lib/calculate_interval.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/lib/calculate_interval.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
]
|
||||
|
@ -105,7 +105,7 @@
|
|||
"ParsedExpression",
|
||||
">"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": [
|
||||
|
@ -116,7 +116,7 @@
|
|||
"tags": [],
|
||||
"label": "input",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/common/parser_async.ts",
|
||||
"path": "src/plugins/vis_types/timelion/common/parser_async.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
]
|
||||
|
@ -137,7 +137,7 @@
|
|||
"LegacyAxis",
|
||||
"): string; }"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": []
|
||||
|
@ -160,7 +160,7 @@
|
|||
},
|
||||
") => string"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": [
|
||||
|
@ -180,7 +180,7 @@
|
|||
"text": "IUiSettingsClient"
|
||||
}
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/get_timezone.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/get_timezone.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
]
|
||||
|
@ -203,7 +203,7 @@
|
|||
},
|
||||
") => (esInterval: any) => any"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": [
|
||||
|
@ -223,7 +223,7 @@
|
|||
"text": "IUiSettingsClient"
|
||||
}
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/helpers/xaxis_formatter.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/helpers/xaxis_formatter.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
]
|
||||
|
@ -240,7 +240,7 @@
|
|||
"IAxis",
|
||||
") => number[]"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/index.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/index.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": []
|
||||
|
@ -256,7 +256,7 @@
|
|||
"tags": [],
|
||||
"label": "VisTypeTimelionPluginStart",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/public/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/plugin.ts",
|
||||
"deprecated": false,
|
||||
"children": [
|
||||
{
|
||||
|
@ -275,7 +275,7 @@
|
|||
"TimelionFunctionArgsSuggestion",
|
||||
"[]; }"
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/public/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/plugin.ts",
|
||||
"deprecated": false,
|
||||
"returnComment": [],
|
||||
"children": []
|
||||
|
@ -291,7 +291,7 @@
|
|||
"tags": [],
|
||||
"label": "VisTypeTimelionPluginSetup",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/public/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/plugin.ts",
|
||||
"deprecated": false,
|
||||
"children": [
|
||||
{
|
||||
|
@ -301,7 +301,7 @@
|
|||
"tags": [],
|
||||
"label": "isUiEnabled",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/public/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/public/plugin.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
],
|
||||
|
@ -322,7 +322,7 @@
|
|||
"description": [
|
||||
"\nDescribes public Timelion plugin contract returned at the `setup` stage."
|
||||
],
|
||||
"path": "src/plugins/vis_type_timelion/server/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/server/plugin.ts",
|
||||
"deprecated": false,
|
||||
"children": [
|
||||
{
|
||||
|
@ -332,7 +332,7 @@
|
|||
"tags": [],
|
||||
"label": "uiEnabled",
|
||||
"description": [],
|
||||
"path": "src/plugins/vis_type_timelion/server/plugin.ts",
|
||||
"path": "src/plugins/vis_types/timelion/server/plugin.ts",
|
||||
"deprecated": false
|
||||
}
|
||||
],
|
||||
|
|
|
@ -285,7 +285,7 @@ The plugin exposes the static DefaultEditorController class to consume.
|
|||
|WARNING: Missing README.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/src/plugins/vis_type_table/README.md[visTypeTable]
|
||||
|{kib-repo}blob/{branch}/src/plugins/vis_types/table/README.md[visTypeTable]
|
||||
|Contains the data table visualization, that allows presenting data in a simple table format.
|
||||
|
||||
|
||||
|
@ -293,7 +293,7 @@ The plugin exposes the static DefaultEditorController class to consume.
|
|||
|WARNING: Missing README.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/src/plugins/vis_type_timelion/README.md[visTypeTimelion]
|
||||
|{kib-repo}blob/{branch}/src/plugins/vis_types/timelion/README.md[visTypeTimelion]
|
||||
|Contains the timelion visualization and the timelion backend.
|
||||
|
||||
|
||||
|
@ -391,7 +391,7 @@ security and spaces filtering as well as performing audit logging.
|
|||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/enterprise_search/README.md[enterpriseSearch]
|
||||
|This plugin provides beta Kibana user interfaces for managing the Enterprise Search solution and its products, App Search and Workplace Search.
|
||||
|This plugin provides Kibana user interfaces for managing the Enterprise Search solution and its products, App Search and Workplace Search.
|
||||
|
||||
|
||||
|{kib-repo}blob/{branch}/x-pack/plugins/event_log/README.md[eventLog]
|
||||
|
|
|
@ -25,8 +25,6 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecationsContext): Promise<DeprecationsDetails[]> {
|
||||
const deprecations: DeprecationsDetails[] = [];
|
||||
|
||||
// Example of an api correctiveAction
|
||||
const count = await getFooCount(savedObjectsClient);
|
||||
if (count > 0) {
|
||||
deprecations.push({
|
||||
|
@ -42,12 +40,12 @@ async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecations
|
|||
level: 'warning',
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
i18n.translate('xpack.foo.deprecations.manualStepOneMessage', {
|
||||
defaultMessage: 'Navigate to the Kibana Dashboard and click "Create dashboard".',
|
||||
}),
|
||||
i18n.translate('xpack.foo.deprecations.manualStepTwoMessage', {
|
||||
defaultMessage: 'Select Foo from the "New Visualization" window.',
|
||||
}),
|
||||
i18n.translate('xpack.foo.deprecations.manualStepOneMessage', {
|
||||
defaultMessage: 'Navigate to the Kibana Dashboard and click "Create dashboard".',
|
||||
}),
|
||||
i18n.translate('xpack.foo.deprecations.manualStepTwoMessage', {
|
||||
defaultMessage: 'Select Foo from the "New Visualization" window.',
|
||||
}),
|
||||
],
|
||||
api: {
|
||||
path: '/internal/security/users/test_dashboard_user',
|
||||
|
@ -68,7 +66,6 @@ async function getDeprecations({ esClient, savedObjectsClient }: GetDeprecations
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
return deprecations;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md) > [(constructor)](./kibana-plugin-core-server.eventloopdelaysmonitor._constructor_.md)
|
||||
|
||||
## EventLoopDelaysMonitor.(constructor)
|
||||
|
||||
Creating a new instance from EventLoopDelaysMonitor will automatically start tracking event loop delays.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
constructor();
|
||||
```
|
|
@ -0,0 +1,19 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md) > [collect](./kibana-plugin-core-server.eventloopdelaysmonitor.collect.md)
|
||||
|
||||
## EventLoopDelaysMonitor.collect() method
|
||||
|
||||
Collect gathers event loop delays metrics from nodejs perf\_hooks.monitorEventLoopDelay the histogram calculations start from the last time `reset` was called or this EventLoopDelaysMonitor instance was created.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
collect(): IntervalHistogram;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`IntervalHistogram`
|
||||
|
||||
{<!-- -->IntervalHistogram<!-- -->}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md)
|
||||
|
||||
## EventLoopDelaysMonitor class
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare class EventLoopDelaysMonitor
|
||||
```
|
||||
|
||||
## Constructors
|
||||
|
||||
| Constructor | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [(constructor)()](./kibana-plugin-core-server.eventloopdelaysmonitor._constructor_.md) | | Creating a new instance from EventLoopDelaysMonitor will automatically start tracking event loop delays. |
|
||||
|
||||
## Methods
|
||||
|
||||
| Method | Modifiers | Description |
|
||||
| --- | --- | --- |
|
||||
| [collect()](./kibana-plugin-core-server.eventloopdelaysmonitor.collect.md) | | Collect gathers event loop delays metrics from nodejs perf\_hooks.monitorEventLoopDelay the histogram calculations start from the last time <code>reset</code> was called or this EventLoopDelaysMonitor instance was created. |
|
||||
| [reset()](./kibana-plugin-core-server.eventloopdelaysmonitor.reset.md) | | Resets the collected histogram data. |
|
||||
| [stop()](./kibana-plugin-core-server.eventloopdelaysmonitor.stop.md) | | Disables updating the interval timer for collecting new data points. |
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md) > [reset](./kibana-plugin-core-server.eventloopdelaysmonitor.reset.md)
|
||||
|
||||
## EventLoopDelaysMonitor.reset() method
|
||||
|
||||
Resets the collected histogram data.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
reset(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md) > [stop](./kibana-plugin-core-server.eventloopdelaysmonitor.stop.md)
|
||||
|
||||
## EventLoopDelaysMonitor.stop() method
|
||||
|
||||
Disables updating the interval timer for collecting new data points.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stop(): void;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
`void`
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [exceeds](./kibana-plugin-core-server.intervalhistogram.exceeds.md)
|
||||
|
||||
## IntervalHistogram.exceeds property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
exceeds: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [fromTimestamp](./kibana-plugin-core-server.intervalhistogram.fromtimestamp.md)
|
||||
|
||||
## IntervalHistogram.fromTimestamp property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
fromTimestamp: string;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [lastUpdatedAt](./kibana-plugin-core-server.intervalhistogram.lastupdatedat.md)
|
||||
|
||||
## IntervalHistogram.lastUpdatedAt property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lastUpdatedAt: string;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [max](./kibana-plugin-core-server.intervalhistogram.max.md)
|
||||
|
||||
## IntervalHistogram.max property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
max: number;
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md)
|
||||
|
||||
## IntervalHistogram interface
|
||||
|
||||
an IntervalHistogram object that samples and reports the event loop delay over time. The delays will be reported in nanoseconds.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface IntervalHistogram
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [exceeds](./kibana-plugin-core-server.intervalhistogram.exceeds.md) | <code>number</code> | |
|
||||
| [fromTimestamp](./kibana-plugin-core-server.intervalhistogram.fromtimestamp.md) | <code>string</code> | |
|
||||
| [lastUpdatedAt](./kibana-plugin-core-server.intervalhistogram.lastupdatedat.md) | <code>string</code> | |
|
||||
| [max](./kibana-plugin-core-server.intervalhistogram.max.md) | <code>number</code> | |
|
||||
| [mean](./kibana-plugin-core-server.intervalhistogram.mean.md) | <code>number</code> | |
|
||||
| [min](./kibana-plugin-core-server.intervalhistogram.min.md) | <code>number</code> | |
|
||||
| [percentiles](./kibana-plugin-core-server.intervalhistogram.percentiles.md) | <code>{</code><br/><code> 50: number;</code><br/><code> 75: number;</code><br/><code> 95: number;</code><br/><code> 99: number;</code><br/><code> }</code> | |
|
||||
| [stddev](./kibana-plugin-core-server.intervalhistogram.stddev.md) | <code>number</code> | |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [mean](./kibana-plugin-core-server.intervalhistogram.mean.md)
|
||||
|
||||
## IntervalHistogram.mean property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
mean: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [min](./kibana-plugin-core-server.intervalhistogram.min.md)
|
||||
|
||||
## IntervalHistogram.min property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
min: number;
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [percentiles](./kibana-plugin-core-server.intervalhistogram.percentiles.md)
|
||||
|
||||
## IntervalHistogram.percentiles property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
percentiles: {
|
||||
50: number;
|
||||
75: number;
|
||||
95: number;
|
||||
99: number;
|
||||
};
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) > [stddev](./kibana-plugin-core-server.intervalhistogram.stddev.md)
|
||||
|
||||
## IntervalHistogram.stddev property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
stddev: number;
|
||||
```
|
|
@ -19,6 +19,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [BasePath](./kibana-plugin-core-server.basepath.md) | Access or manipulate the Kibana base path |
|
||||
| [CspConfig](./kibana-plugin-core-server.cspconfig.md) | CSP configuration for use in Kibana. |
|
||||
| [ElasticsearchConfig](./kibana-plugin-core-server.elasticsearchconfig.md) | Wrapper of config schema. |
|
||||
| [EventLoopDelaysMonitor](./kibana-plugin-core-server.eventloopdelaysmonitor.md) | |
|
||||
| [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md) | Kibana specific abstraction for an incoming request. |
|
||||
| [RouteValidationError](./kibana-plugin-core-server.routevalidationerror.md) | Error to return when the validation is not successful. |
|
||||
| [SavedObjectsClient](./kibana-plugin-core-server.savedobjectsclient.md) | |
|
||||
|
@ -97,6 +98,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
|
|||
| [IExternalUrlPolicy](./kibana-plugin-core-server.iexternalurlpolicy.md) | A policy describing whether access to an external destination is allowed. |
|
||||
| [IKibanaResponse](./kibana-plugin-core-server.ikibanaresponse.md) | A response data object, expected to returned as a result of [RequestHandler](./kibana-plugin-core-server.requesthandler.md) execution |
|
||||
| [IKibanaSocket](./kibana-plugin-core-server.ikibanasocket.md) | A tiny abstraction for TCP socket. |
|
||||
| [IntervalHistogram](./kibana-plugin-core-server.intervalhistogram.md) | an IntervalHistogram object that samples and reports the event loop delay over time. The delays will be reported in nanoseconds. |
|
||||
| [IRenderOptions](./kibana-plugin-core-server.irenderoptions.md) | |
|
||||
| [IRouter](./kibana-plugin-core-server.irouter.md) | Registers route handlers for specified resource path and method. See [RouteConfig](./kibana-plugin-core-server.routeconfig.md) and [RequestHandler](./kibana-plugin-core-server.requesthandler.md) for more information about arguments to route registrations. |
|
||||
| [ISavedObjectsPointInTimeFinder](./kibana-plugin-core-server.isavedobjectspointintimefinder.md) | |
|
||||
|
|
|
@ -19,7 +19,8 @@ export interface OpsMetrics
|
|||
| [collected\_at](./kibana-plugin-core-server.opsmetrics.collected_at.md) | <code>Date</code> | Time metrics were recorded at. |
|
||||
| [concurrent\_connections](./kibana-plugin-core-server.opsmetrics.concurrent_connections.md) | <code>OpsServerMetrics['concurrent_connections']</code> | number of current concurrent connections to the server |
|
||||
| [os](./kibana-plugin-core-server.opsmetrics.os.md) | <code>OpsOsMetrics</code> | OS related metrics |
|
||||
| [process](./kibana-plugin-core-server.opsmetrics.process.md) | <code>OpsProcessMetrics</code> | Process related metrics |
|
||||
| [process](./kibana-plugin-core-server.opsmetrics.process.md) | <code>OpsProcessMetrics</code> | Process related metrics. Deprecated in favor of processes field. |
|
||||
| [processes](./kibana-plugin-core-server.opsmetrics.processes.md) | <code>OpsProcessMetrics[]</code> | Process related metrics. Reports an array of objects for each kibana pid. |
|
||||
| [requests](./kibana-plugin-core-server.opsmetrics.requests.md) | <code>OpsServerMetrics['requests']</code> | server requests stats |
|
||||
| [response\_times](./kibana-plugin-core-server.opsmetrics.response_times.md) | <code>OpsServerMetrics['response_times']</code> | server response time stats |
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
## OpsMetrics.process property
|
||||
|
||||
Process related metrics
|
||||
> Warning: This API is now obsolete.
|
||||
>
|
||||
>
|
||||
|
||||
Process related metrics. Deprecated in favor of processes field.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) > [processes](./kibana-plugin-core-server.opsmetrics.processes.md)
|
||||
|
||||
## OpsMetrics.processes property
|
||||
|
||||
Process related metrics. Reports an array of objects for each kibana pid.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
processes: OpsProcessMetrics[];
|
||||
```
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## OpsProcessMetrics.event\_loop\_delay property
|
||||
|
||||
node event loop delay
|
||||
mean event loop delay since last collection
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OpsProcessMetrics](./kibana-plugin-core-server.opsprocessmetrics.md) > [event\_loop\_delay\_histogram](./kibana-plugin-core-server.opsprocessmetrics.event_loop_delay_histogram.md)
|
||||
|
||||
## OpsProcessMetrics.event\_loop\_delay\_histogram property
|
||||
|
||||
node event loop delay histogram since last collection
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
event_loop_delay_histogram: IntervalHistogram;
|
||||
```
|
|
@ -16,7 +16,8 @@ export interface OpsProcessMetrics
|
|||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [event\_loop\_delay](./kibana-plugin-core-server.opsprocessmetrics.event_loop_delay.md) | <code>number</code> | node event loop delay |
|
||||
| [event\_loop\_delay\_histogram](./kibana-plugin-core-server.opsprocessmetrics.event_loop_delay_histogram.md) | <code>IntervalHistogram</code> | node event loop delay histogram since last collection |
|
||||
| [event\_loop\_delay](./kibana-plugin-core-server.opsprocessmetrics.event_loop_delay.md) | <code>number</code> | mean event loop delay since last collection |
|
||||
| [memory](./kibana-plugin-core-server.opsprocessmetrics.memory.md) | <code>{</code><br/><code> heap: {</code><br/><code> total_in_bytes: number;</code><br/><code> used_in_bytes: number;</code><br/><code> size_limit: number;</code><br/><code> };</code><br/><code> resident_set_size_in_bytes: number;</code><br/><code> }</code> | process memory usage |
|
||||
| [pid](./kibana-plugin-core-server.opsprocessmetrics.pid.md) | <code>number</code> | pid of the kibana process |
|
||||
| [uptime\_in\_millis](./kibana-plugin-core-server.opsprocessmetrics.uptime_in_millis.md) | <code>number</code> | uptime of the kibana process |
|
||||
|
|
|
@ -512,10 +512,6 @@ Enables the legacy charts library for timelion charts in Visualize.
|
|||
**This setting is deprecated and will not be supported as of 8.0.**
|
||||
Maps values to specific colors in charts using the *Compatibility* palette.
|
||||
|
||||
[[visualization-dimmingopacity]]`visualization:dimmingOpacity`::
|
||||
The opacity of the chart items that are dimmed when highlighting another element
|
||||
of the chart. Use numbers between 0 and 1. The lower the number, the more the highlighted element stands out.
|
||||
|
||||
[[visualization-heatmap-maxbuckets]]`visualization:heatmap:maxBuckets`::
|
||||
The maximum number of buckets a datasource can return. High numbers can have a negative impact on your browser rendering performance.
|
||||
|
||||
|
|
|
@ -375,7 +375,7 @@
|
|||
"safe-squel": "^5.12.5",
|
||||
"seedrandom": "^3.0.5",
|
||||
"semver": "^7.3.2",
|
||||
"set-value": "^3.0.2",
|
||||
"set-value": "^4.1.0",
|
||||
"source-map-support": "^0.5.19",
|
||||
"stats-lite": "^2.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
|
|
|
@ -92,5 +92,6 @@ module.exports = {
|
|||
],
|
||||
|
||||
'@kbn/eslint/no_async_promise_body': 'error',
|
||||
'@kbn/eslint/no_async_foreach': 'error',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
export interface ManagedConfigKey {
|
||||
key: string;
|
||||
value: Record<string, any>;
|
||||
value: string | Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,4 +37,9 @@ export const MANAGED_CONFIG_KEYS: ManagedConfigKey[] = [
|
|||
['**/packages/kbn-pm/dist/index.js']: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'typescript.tsdk',
|
||||
// we use a relative path here so that it works with remote vscode connections
|
||||
value: './node_modules/typescript/lib',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -22,6 +22,10 @@ const TEST_KEYS: ManagedConfigKey[] = [
|
|||
world: [1, 2, 3],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'stringKey',
|
||||
value: 'foo',
|
||||
},
|
||||
];
|
||||
|
||||
const run = (json?: string) => updateVscodeConfig(TEST_KEYS, '', json);
|
||||
|
@ -35,7 +39,9 @@ it('updates the passed JSON with the managed settings', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -50,7 +56,9 @@ it('initialized empty or undefined json values', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -63,14 +71,16 @@ it('initialized empty or undefined json values', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
});
|
||||
|
||||
it('replaces conflicting managed keys which do not have object values', () => {
|
||||
expect(run(`{ "key": false }`)).toMatchInlineSnapshot(`
|
||||
it('replaces conflicting managed keys which do not have matching value types', () => {
|
||||
expect(run(`{ "key": false, "stringKey": { "a": "B" } }`)).toMatchInlineSnapshot(`
|
||||
// @managed
|
||||
{
|
||||
"key": {
|
||||
|
@ -78,7 +88,9 @@ it('replaces conflicting managed keys which do not have object values', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -122,7 +134,9 @@ it('persists comments in the original file', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -148,7 +162,9 @@ it('overrides old values for managed keys', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -176,7 +192,9 @@ it('does not modify properties with leading `// self managed` comment', () => {
|
|||
// self managed
|
||||
"key": {
|
||||
"world": [5]
|
||||
}
|
||||
},
|
||||
// self managed
|
||||
"stringKey": "--"
|
||||
}
|
||||
`);
|
||||
|
||||
|
@ -186,7 +204,9 @@ it('does not modify properties with leading `// self managed` comment', () => {
|
|||
// self managed
|
||||
"key": {
|
||||
"world": [5]
|
||||
}
|
||||
},
|
||||
// self managed
|
||||
"stringKey": "--"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -210,7 +230,9 @@ it('does not modify child properties with leading `// self managed` comment', ()
|
|||
"world": [5],
|
||||
// @managed
|
||||
"hello": true
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -236,7 +258,9 @@ it('does not modify unknown child properties', () => {
|
|||
"world": [5],
|
||||
// @managed
|
||||
"hello": true
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -262,7 +286,9 @@ it('removes managed properties which are no longer managed', () => {
|
|||
"world": [5],
|
||||
// @managed
|
||||
"hello": true
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -286,7 +312,9 @@ it('wipes out child keys which conflict with newly managed child keys', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -308,7 +336,9 @@ it('correctly formats info text when specified', () => {
|
|||
"hello": true,
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
"stringKey": "foo"
|
||||
}
|
||||
|
||||
`);
|
||||
|
@ -321,7 +351,10 @@ it('allows "// self managed" comments conflicting with "// @managed" comments to
|
|||
// @managed
|
||||
// self managed
|
||||
"hello": ["world"]
|
||||
}
|
||||
},
|
||||
// @managed
|
||||
// self managed
|
||||
"stringKey": 12345
|
||||
}
|
||||
`);
|
||||
|
||||
|
@ -333,7 +366,9 @@ it('allows "// self managed" comments conflicting with "// @managed" comments to
|
|||
"hello": ["world"],
|
||||
// @managed
|
||||
"world": [1, 2, 3]
|
||||
}
|
||||
},
|
||||
// self managed
|
||||
"stringKey": 12345
|
||||
}
|
||||
|
||||
`);
|
||||
|
|
|
@ -25,11 +25,20 @@ const isManaged = (node?: t.Node) =>
|
|||
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === '@managed'
|
||||
);
|
||||
|
||||
const isSelfManaged = (node?: t.Node) =>
|
||||
!!node?.leadingComments?.some(
|
||||
const isSelfManaged = (node?: t.Node) => {
|
||||
const result = !!node?.leadingComments?.some(
|
||||
(c) => c.type === 'CommentLine' && c.value.trim().toLocaleLowerCase() === 'self managed'
|
||||
);
|
||||
|
||||
// if we find a node which is both managed and self managed remove the managed comment
|
||||
if (result && node && isManaged(node)) {
|
||||
node.leadingComments =
|
||||
node.leadingComments?.filter((c) => c.value.trim() !== '@managed') ?? null;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const remove = <T>(arr: T[], value: T) => {
|
||||
const index = arr.indexOf(value);
|
||||
if (index > -1) {
|
||||
|
@ -37,16 +46,16 @@ const remove = <T>(arr: T[], value: T) => {
|
|||
}
|
||||
};
|
||||
|
||||
const createManagedChildProp = (key: string, value: any) => {
|
||||
const createManagedProp = (key: string, value: any) => {
|
||||
const childProp = t.objectProperty(t.stringLiteral(key), parseExpression(JSON.stringify(value)));
|
||||
t.addComment(childProp, 'leading', ' @managed', true);
|
||||
return childProp;
|
||||
};
|
||||
|
||||
const createManagedProp = (key: string, value: Record<string, any>) => {
|
||||
const createObjectPropOfManagedValues = (key: string, value: Record<string, any>) => {
|
||||
return t.objectProperty(
|
||||
t.stringLiteral(key),
|
||||
t.objectExpression(Object.entries(value).map(([k, v]) => createManagedChildProp(k, v)))
|
||||
t.objectExpression(Object.entries(value).map(([k, v]) => createManagedProp(k, v)))
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -57,8 +66,16 @@ const createManagedProp = (key: string, value: Record<string, any>) => {
|
|||
* @param key the key name to add
|
||||
* @param value managed value which should be set at `key`
|
||||
*/
|
||||
const addManagedProp = (ast: t.ObjectExpression, key: string, value: Record<string, any>) => {
|
||||
ast.properties.push(createManagedProp(key, value));
|
||||
const addManagedProp = (
|
||||
ast: t.ObjectExpression,
|
||||
key: string,
|
||||
value: string | Record<string, any>
|
||||
) => {
|
||||
ast.properties.push(
|
||||
typeof value === 'string'
|
||||
? createManagedProp(key, value)
|
||||
: createObjectPropOfManagedValues(key, value)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -72,7 +89,7 @@ const addManagedProp = (ast: t.ObjectExpression, key: string, value: Record<stri
|
|||
const replaceManagedProp = (
|
||||
ast: t.ObjectExpression,
|
||||
existing: BasicObjectProp,
|
||||
value: Record<string, any>
|
||||
value: string | Record<string, any>
|
||||
) => {
|
||||
remove(ast.properties, existing);
|
||||
addManagedProp(ast, existing.key.value, value);
|
||||
|
@ -98,15 +115,11 @@ const mergeManagedProperties = (
|
|||
|
||||
if (!existing) {
|
||||
// add the new managed prop
|
||||
properties.push(createManagedChildProp(key, value));
|
||||
properties.push(createManagedProp(key, value));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isSelfManaged(existing)) {
|
||||
// strip "// @managed" comment if conflicting with "// self managed"
|
||||
existing.leadingComments = (existing.leadingComments ?? []).filter(
|
||||
(c) => c.value.trim() !== '@managed'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -119,7 +132,7 @@ const mergeManagedProperties = (
|
|||
// take over the unmanaged child prop by deleting the previous prop and replacing it
|
||||
// with a brand new one
|
||||
remove(properties, existing);
|
||||
properties.push(createManagedChildProp(key, value));
|
||||
properties.push(createManagedProp(key, value));
|
||||
}
|
||||
|
||||
// iterate through the props to find "// @managed" props which are no longer in
|
||||
|
@ -170,20 +183,29 @@ export function updateVscodeConfig(keys: ManagedConfigKey[], infoText: string, j
|
|||
continue;
|
||||
}
|
||||
|
||||
if (existingProp && existingProp.value.type === 'ObjectExpression') {
|
||||
// setting exists and is an object so merge properties of `value` with it
|
||||
mergeManagedProperties(existingProp.value.properties, value);
|
||||
if (typeof value === 'object') {
|
||||
if (existingProp && existingProp.value.type === 'ObjectExpression') {
|
||||
// setting exists and is an object so merge properties of `value` with it
|
||||
mergeManagedProperties(existingProp.value.properties, value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingProp) {
|
||||
// setting exists but its value is not an object expression so replace it
|
||||
replaceManagedProp(ast, existingProp, value);
|
||||
continue;
|
||||
}
|
||||
|
||||
// setting isn't in config file so create it
|
||||
addManagedProp(ast, key, value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingProp) {
|
||||
// setting exists but its value is not an object expression so replace it
|
||||
replaceManagedProp(ast, existingProp, value);
|
||||
continue;
|
||||
} else {
|
||||
addManagedProp(ast, key, value);
|
||||
}
|
||||
|
||||
// setting isn't in config file so create it
|
||||
addManagedProp(ast, key, value);
|
||||
}
|
||||
|
||||
ast.leadingComments = [
|
||||
|
|
|
@ -14,5 +14,6 @@ module.exports = {
|
|||
module_migration: require('./rules/module_migration'),
|
||||
no_export_all: require('./rules/no_export_all'),
|
||||
no_async_promise_body: require('./rules/no_async_promise_body'),
|
||||
no_async_foreach: require('./rules/no_async_foreach'),
|
||||
},
|
||||
};
|
||||
|
|
62
packages/kbn-eslint-plugin-eslint/rules/no_async_foreach.js
Normal file
62
packages/kbn-eslint-plugin-eslint/rules/no_async_foreach.js
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const tsEstree = require('@typescript-eslint/typescript-estree');
|
||||
const esTypes = tsEstree.AST_NODE_TYPES;
|
||||
|
||||
/** @typedef {import("eslint").Rule.RuleModule} Rule */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Node} Node */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.CallExpression} CallExpression */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.FunctionExpression} FunctionExpression */
|
||||
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.ArrowFunctionExpression} ArrowFunctionExpression */
|
||||
/** @typedef {import("eslint").Rule.RuleFixer} Fixer */
|
||||
|
||||
const ERROR_MSG =
|
||||
'Passing an async function to .forEach() prevents promise rejections from being handled. Use asyncForEach() or similar helper from "@kbn/std" instead.';
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {node is ArrowFunctionExpression | FunctionExpression}
|
||||
*/
|
||||
const isFunc = (node) =>
|
||||
node.type === esTypes.ArrowFunctionExpression || node.type === esTypes.FunctionExpression;
|
||||
|
||||
/**
|
||||
* @param {any} context
|
||||
* @param {CallExpression} node
|
||||
*/
|
||||
const isAsyncForEachCall = (node) => {
|
||||
return (
|
||||
node.callee.type === esTypes.MemberExpression &&
|
||||
node.callee.property.type === esTypes.Identifier &&
|
||||
node.callee.property.name === 'forEach' &&
|
||||
node.arguments.length >= 1 &&
|
||||
isFunc(node.arguments[0]) &&
|
||||
node.arguments[0].async
|
||||
);
|
||||
};
|
||||
|
||||
/** @type {Rule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
create: (context) => ({
|
||||
CallExpression(_) {
|
||||
const node = /** @type {CallExpression} */ (_);
|
||||
|
||||
if (isAsyncForEachCall(node)) {
|
||||
context.report({
|
||||
message: ERROR_MSG,
|
||||
loc: node.arguments[0].loc,
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const { RuleTester } = require('eslint');
|
||||
const rule = require('./no_async_foreach');
|
||||
const dedent = require('dedent');
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
parser: require.resolve('@typescript-eslint/parser'),
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2018,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
ruleTester.run('@kbn/eslint/no_async_foreach', rule, {
|
||||
valid: [
|
||||
{
|
||||
code: dedent`
|
||||
array.forEach((a) => {
|
||||
b(a)
|
||||
})
|
||||
`,
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
array.forEach(function (a) {
|
||||
b(a)
|
||||
})
|
||||
`,
|
||||
},
|
||||
],
|
||||
|
||||
invalid: [
|
||||
{
|
||||
code: dedent`
|
||||
array.forEach(async (a) => {
|
||||
await b(a)
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message:
|
||||
'Passing an async function to .forEach() prevents promise rejections from being handled. Use asyncForEach() or similar helper from "@kbn/std" instead.',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
code: dedent`
|
||||
array.forEach(async function (a) {
|
||||
await b(a)
|
||||
})
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
line: 1,
|
||||
message:
|
||||
'Passing an async function to .forEach() prevents promise rejections from being handled. Use asyncForEach() or similar helper from "@kbn/std" instead.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
|
@ -9,7 +9,10 @@ SOURCE_FILES = glob(
|
|||
[
|
||||
"src/**/*.ts",
|
||||
],
|
||||
exclude = ["**/*.test.*"],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
"**/test_helpers.ts",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
|
|
@ -18,3 +18,11 @@ export { unset } from './unset';
|
|||
export { getFlattenedObject } from './get_flattened_object';
|
||||
export { ensureNoUnsafeProperties } from './ensure_no_unsafe_properties';
|
||||
export * from './rxjs_7';
|
||||
export {
|
||||
map$,
|
||||
mapWithLimit$,
|
||||
asyncMap,
|
||||
asyncMapWithLimit,
|
||||
asyncForEach,
|
||||
asyncForEachWithLimit,
|
||||
} from './iteration';
|
||||
|
|
81
packages/kbn-std/src/iteration/for_each.test.ts
Normal file
81
packages/kbn-std/src/iteration/for_each.test.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
|
||||
import { asyncForEach, asyncForEachWithLimit } from './for_each';
|
||||
import { list, sleep } from './test_helpers';
|
||||
|
||||
jest.mock('./observable');
|
||||
const mockMapWithLimit$: jest.Mock = jest.requireMock('./observable').mapWithLimit$;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('asyncForEachWithLimit', () => {
|
||||
it('calls mapWithLimit$ and resolves with undefined when it completes', async () => {
|
||||
const iter = list(10);
|
||||
const limit = 5;
|
||||
const fn = jest.fn();
|
||||
|
||||
const result$ = new Rx.Subject();
|
||||
mockMapWithLimit$.mockImplementation(() => result$);
|
||||
const promise = asyncForEachWithLimit(iter, limit, fn);
|
||||
|
||||
let resolved = false;
|
||||
promise.then(() => (resolved = true));
|
||||
|
||||
expect(mockMapWithLimit$).toHaveBeenCalledTimes(1);
|
||||
expect(mockMapWithLimit$).toHaveBeenCalledWith(iter, limit, fn);
|
||||
|
||||
expect(resolved).toBe(false);
|
||||
result$.next(1);
|
||||
result$.next(2);
|
||||
result$.next(3);
|
||||
|
||||
await sleep(10);
|
||||
expect(resolved).toBe(false);
|
||||
|
||||
result$.complete();
|
||||
await expect(promise).resolves.toBe(undefined);
|
||||
});
|
||||
|
||||
it('resolves when iterator is empty', async () => {
|
||||
mockMapWithLimit$.mockImplementation((x) => Rx.from(x));
|
||||
await expect(asyncForEachWithLimit([], 100, async () => 'foo')).resolves.toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncForEach', () => {
|
||||
it('calls mapWithLimit$ without limit and resolves with undefined when it completes', async () => {
|
||||
const iter = list(10);
|
||||
const fn = jest.fn();
|
||||
|
||||
const result$ = new Rx.Subject();
|
||||
mockMapWithLimit$.mockImplementation(() => result$);
|
||||
const promise = asyncForEach(iter, fn);
|
||||
|
||||
let resolved = false;
|
||||
promise.then(() => (resolved = true));
|
||||
|
||||
expect(mockMapWithLimit$).toHaveBeenCalledTimes(1);
|
||||
expect(mockMapWithLimit$).toHaveBeenCalledWith(iter, Infinity, fn);
|
||||
|
||||
expect(resolved).toBe(false);
|
||||
result$.next(1);
|
||||
result$.next(2);
|
||||
result$.next(3);
|
||||
|
||||
await sleep(10);
|
||||
expect(resolved).toBe(false);
|
||||
|
||||
result$.complete();
|
||||
await expect(promise).resolves.toBe(undefined);
|
||||
});
|
||||
});
|
44
packages/kbn-std/src/iteration/for_each.ts
Normal file
44
packages/kbn-std/src/iteration/for_each.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { defaultIfEmpty } from 'rxjs/operators';
|
||||
|
||||
import { lastValueFrom } from '../rxjs_7';
|
||||
import { mapWithLimit$ } from './observable';
|
||||
import { IterableInput, AsyncMapFn } from './types';
|
||||
|
||||
/**
|
||||
* Creates a promise which resolves with `undefined` after calling `fn` for each
|
||||
* item in `iterable`. `fn` can return either a Promise or Observable. If `fn`
|
||||
* returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param fn Function to call for each item
|
||||
*/
|
||||
export async function asyncForEach<T>(iterable: IterableInput<T>, fn: AsyncMapFn<T, any>) {
|
||||
await lastValueFrom(mapWithLimit$(iterable, Infinity, fn).pipe(defaultIfEmpty()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise which resolves with `undefined` after calling `fn` for each
|
||||
* item in `iterable`. `fn` can return either a Promise or Observable. If `fn`
|
||||
* returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* The number of concurrent executions of `fn` is limited by `limit`.
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param limit Maximum number of operations to run in parallel
|
||||
* @param fn Function to call for each item
|
||||
*/
|
||||
export async function asyncForEachWithLimit<T>(
|
||||
iterable: IterableInput<T>,
|
||||
limit: number,
|
||||
fn: AsyncMapFn<T, any>
|
||||
) {
|
||||
await lastValueFrom(mapWithLimit$(iterable, limit, fn).pipe(defaultIfEmpty()));
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
// TODO: https://github.com/elastic/kibana/issues/110891
|
||||
/* eslint-disable @kbn/eslint/no_export_all */
|
||||
|
||||
export * from './types';
|
||||
export * from './observable';
|
||||
export * from './for_each';
|
||||
export * from './map';
|
82
packages/kbn-std/src/iteration/map.test.ts
Normal file
82
packages/kbn-std/src/iteration/map.test.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import { mapTo } from 'rxjs/operators';
|
||||
|
||||
import { asyncMap, asyncMapWithLimit } from './map';
|
||||
import { list } from './test_helpers';
|
||||
|
||||
jest.mock('./observable');
|
||||
const mapWithLimit$: jest.Mock = jest.requireMock('./observable').mapWithLimit$;
|
||||
mapWithLimit$.mockImplementation(jest.requireActual('./observable').mapWithLimit$);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('asyncMapWithLimit', () => {
|
||||
it('calls mapWithLimit$ and resolves with properly sorted results', async () => {
|
||||
const iter = list(10);
|
||||
const limit = 5;
|
||||
const fn = jest.fn((n) => (n % 2 ? Rx.timer(n) : Rx.timer(n * 4)).pipe(mapTo(n)));
|
||||
const result = await asyncMapWithLimit(iter, limit, fn);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
]
|
||||
`);
|
||||
|
||||
expect(mapWithLimit$).toHaveBeenCalledTimes(1);
|
||||
expect(mapWithLimit$).toHaveBeenCalledWith(iter, limit, expect.any(Function));
|
||||
});
|
||||
|
||||
it.each([
|
||||
[list(0), []] as const,
|
||||
[list(1), ['foo']] as const,
|
||||
[list(2), ['foo', 'foo']] as const,
|
||||
])('resolves when iterator is %p', async (input, output) => {
|
||||
await expect(asyncMapWithLimit(input, 100, async () => 'foo')).resolves.toEqual(output);
|
||||
});
|
||||
});
|
||||
|
||||
describe('asyncMap', () => {
|
||||
it('calls mapWithLimit$ without limit and resolves with undefined when it completes', async () => {
|
||||
const iter = list(10);
|
||||
const fn = jest.fn((n) => (n % 2 ? Rx.timer(n) : Rx.timer(n * 4)).pipe(mapTo(n)));
|
||||
const result = await asyncMap(iter, fn);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
]
|
||||
`);
|
||||
|
||||
expect(mapWithLimit$).toHaveBeenCalledTimes(1);
|
||||
expect(mapWithLimit$).toHaveBeenCalledWith(iter, Infinity, expect.any(Function));
|
||||
});
|
||||
});
|
63
packages/kbn-std/src/iteration/map.ts
Normal file
63
packages/kbn-std/src/iteration/map.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { from } from 'rxjs';
|
||||
import { toArray } from 'rxjs/operators';
|
||||
import { lastValueFrom } from '../rxjs_7';
|
||||
|
||||
import { IterableInput, AsyncMapFn, AsyncMapResult } from './types';
|
||||
import { mapWithLimit$ } from './observable';
|
||||
|
||||
const getAllResults = <T>(input: AsyncMapResult<T>) => lastValueFrom(from(input).pipe(toArray()));
|
||||
|
||||
/**
|
||||
* Creates a promise whose values is the array of results produced by calling `fn` for
|
||||
* each item in `iterable`. `fn` can return either a Promise or Observable. If `fn`
|
||||
* returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* The result array follows the order of the input iterable, even though the calls
|
||||
* to `fn` may not. (so avoid side effects)
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param fn Function to call for each item. Result is added/concatenated into the result array in place of the input value
|
||||
*/
|
||||
export async function asyncMap<T1, T2>(iterable: IterableInput<T1>, fn: AsyncMapFn<T1, T2>) {
|
||||
return await asyncMapWithLimit(iterable, Infinity, fn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise whose values is the array of results produced by calling `fn` for
|
||||
* each item in `iterable`. `fn` can return either a Promise or Observable. If `fn`
|
||||
* returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* The number of concurrent executions of `fn` is limited by `limit`.
|
||||
*
|
||||
* The result array follows the order of the input iterable, even though the calls
|
||||
* to `fn` may not. (so avoid side effects)
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param limit Maximum number of operations to run in parallel
|
||||
* @param fn Function to call for each item. Result is added/concatenated into the result array in place of the input value
|
||||
*/
|
||||
export async function asyncMapWithLimit<T1, T2>(
|
||||
iterable: IterableInput<T1>,
|
||||
limit: number,
|
||||
fn: AsyncMapFn<T1, T2>
|
||||
) {
|
||||
const results$ = mapWithLimit$(
|
||||
iterable,
|
||||
limit,
|
||||
async (item, i) => [i, await getAllResults(fn(item, i))] as const
|
||||
);
|
||||
|
||||
const results = await getAllResults(results$);
|
||||
|
||||
return results
|
||||
.sort(([a], [b]) => a - b)
|
||||
.reduce((acc: T2[], [, result]) => acc.concat(result), []);
|
||||
}
|
81
packages/kbn-std/src/iteration/observable.test.ts
Normal file
81
packages/kbn-std/src/iteration/observable.test.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import * as Rx from 'rxjs';
|
||||
import { toArray } from 'rxjs/operators';
|
||||
import { lastValueFrom } from '../rxjs_7';
|
||||
|
||||
import { map$, mapWithLimit$ } from './observable';
|
||||
import { list, sleep, generator } from './test_helpers';
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('mapWithLimit$', () => {
|
||||
it('calls the fn for each item and produced each item on the stream with limit 1', async () => {
|
||||
let maxConcurrency = 0;
|
||||
let active = 0;
|
||||
const limit = Math.random() > 0.5 ? 20 : 40;
|
||||
|
||||
const results = await lastValueFrom(
|
||||
mapWithLimit$(list(100), limit, async (n) => {
|
||||
active += 1;
|
||||
if (active > maxConcurrency) {
|
||||
maxConcurrency = active;
|
||||
}
|
||||
await sleep(5);
|
||||
active -= 1;
|
||||
return n;
|
||||
}).pipe(toArray())
|
||||
);
|
||||
|
||||
expect(maxConcurrency).toBe(limit);
|
||||
expect(results).toHaveLength(100);
|
||||
for (const [n, i] of results.entries()) {
|
||||
expect(n).toBe(i);
|
||||
}
|
||||
});
|
||||
|
||||
it.each([
|
||||
['empty array', [], []] as const,
|
||||
['empty generator', generator(0), []] as const,
|
||||
['generator', generator(5), [0, 1, 2, 3, 4]] as const,
|
||||
['set', new Set([5, 4, 3, 2, 1]), [5, 4, 3, 2, 1]] as const,
|
||||
['observable', Rx.of(1, 2, 3, 4, 5), [1, 2, 3, 4, 5]] as const,
|
||||
])('works with %p', async (_, iter, expected) => {
|
||||
const mock = jest.fn(async (n) => n);
|
||||
const results = await lastValueFrom(mapWithLimit$(iter, 1, mock).pipe(toArray()));
|
||||
expect(results).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('map$', () => {
|
||||
it('applies no limit to mapWithLimit$', async () => {
|
||||
let maxConcurrency = 0;
|
||||
let active = 0;
|
||||
|
||||
const results = await lastValueFrom(
|
||||
map$(list(100), async (n) => {
|
||||
active += 1;
|
||||
if (active > maxConcurrency) {
|
||||
maxConcurrency = active;
|
||||
}
|
||||
await sleep(5);
|
||||
active -= 1;
|
||||
return n;
|
||||
}).pipe(toArray())
|
||||
);
|
||||
|
||||
expect(maxConcurrency).toBe(100);
|
||||
expect(results).toHaveLength(100);
|
||||
for (const [n, i] of results.entries()) {
|
||||
expect(n).toBe(i);
|
||||
}
|
||||
});
|
||||
});
|
49
packages/kbn-std/src/iteration/observable.ts
Normal file
49
packages/kbn-std/src/iteration/observable.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { from } from 'rxjs';
|
||||
import { mergeMap } from 'rxjs/operators';
|
||||
|
||||
import { IterableInput, AsyncMapFn } from './types';
|
||||
|
||||
/**
|
||||
* Creates an observable whose values are the result of calling `fn` for each
|
||||
* item in `iterable`. `fn` can return either a Promise or an Observable. If
|
||||
* `fn` returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* Results are emitted as soon as they are available so their order is very
|
||||
* likely to not match their order in the input `array`.
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param fn Function to call for each item. Result is added/concatenated into the result array in place of the input value
|
||||
*/
|
||||
export function map$<T1, T2>(iterable: IterableInput<T1>, fn: AsyncMapFn<T1, T2>) {
|
||||
return from(iterable).pipe(mergeMap(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an observable whose values are the result of calling `fn` for each
|
||||
* item in `iterable`. `fn` can return either a Promise or an Observable. If
|
||||
* `fn` returns observables then they will properly abort if an error occurs.
|
||||
*
|
||||
* The number of concurrent executions of `fn` is limited by `limit`.
|
||||
*
|
||||
* Results are emitted as soon as they are available so their order is very
|
||||
* likely to not match their order in the input `array`.
|
||||
*
|
||||
* @param iterable Items to iterate
|
||||
* @param limit Maximum number of operations to run in parallel
|
||||
* @param fn Function to call for each item. Result is added/concatenated into the result array in place of the input value
|
||||
*/
|
||||
export function mapWithLimit$<T1, T2>(
|
||||
iterable: IterableInput<T1>,
|
||||
limit: number,
|
||||
fn: AsyncMapFn<T1, T2>
|
||||
) {
|
||||
return from(iterable).pipe(mergeMap(fn, limit));
|
||||
}
|
17
packages/kbn-std/src/iteration/test_helpers.ts
Normal file
17
packages/kbn-std/src/iteration/test_helpers.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export const list = (size: number) => Array.from({ length: size }, (_, i) => i);
|
||||
|
||||
export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
export const generator = function* (size: number) {
|
||||
for (const n of list(size)) {
|
||||
yield n;
|
||||
}
|
||||
};
|
13
packages/kbn-std/src/iteration/types.ts
Normal file
13
packages/kbn-std/src/iteration/types.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Subscribable } from 'rxjs';
|
||||
|
||||
export type IterableInput<T> = Iterable<T> | Subscribable<T>;
|
||||
export type AsyncMapResult<T> = Promise<T> | Subscribable<T>;
|
||||
export type AsyncMapFn<T1, T2> = (item: T1, i: number) => AsyncMapResult<T2>;
|
|
@ -85,8 +85,8 @@
|
|||
'xml-crypto', '@types/xml-crypto'
|
||||
],
|
||||
reviewers: ['team:kibana-security'],
|
||||
matchBaseBranches: ['master', '7.x'],
|
||||
labels: ['Team:Security'],
|
||||
matchBaseBranches: ['master'],
|
||||
labels: ['Team:Security', 'release_note:skip', 'auto-backport'],
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -13,14 +13,12 @@ const alwaysImportedTests = [
|
|||
require.resolve('../test/ui_capabilities/newsfeed_err/config.ts'),
|
||||
require.resolve('../test/new_visualize_flow/config.ts'),
|
||||
require.resolve('../test/security_functional/config.ts'),
|
||||
require.resolve('../test/functional/config.legacy.ts'),
|
||||
];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const onlyNotInCoverageTests = [
|
||||
require.resolve('../test/api_integration/config.js'),
|
||||
require.resolve('../test/interpreter_functional/config.ts'),
|
||||
require.resolve('../test/examples/config.js'),
|
||||
require.resolve('../test/functional_execution_context/config.ts'),
|
||||
];
|
||||
|
||||
require('../src/setup_node_env');
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { registerLegacyVis } from './register_legacy_vis';
|
||||
require('../src/cli_verification_code/dev');
|
39
src/cli_verification_code/cli_verification_code.js
Normal file
39
src/cli_verification_code/cli_verification_code.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { kibanaPackageJson, getDataPath } from '@kbn/utils';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import Command from '../cli/command';
|
||||
|
||||
const program = new Command('bin/kibana-verification-code');
|
||||
|
||||
program
|
||||
.version(kibanaPackageJson.version)
|
||||
.description('Tool to get Kibana verification code')
|
||||
.action(() => {
|
||||
const fpath = path.join(getDataPath(), 'verification_code');
|
||||
try {
|
||||
const code = fs.readFileSync(fpath).toString();
|
||||
console.log(
|
||||
`Your verification code is: ${chalk.black.bgCyanBright(
|
||||
` ${code.substr(0, 3)} ${code.substr(3)} `
|
||||
)}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.log(`Couldn't find verification code.
|
||||
|
||||
If Kibana hasn't been configured yet, restart Kibana to generate a new code.
|
||||
|
||||
Otherwise, you can safely ignore this message and start using Kibana.`);
|
||||
}
|
||||
});
|
||||
|
||||
program.parse(process.argv);
|
10
src/cli_verification_code/dev.js
Normal file
10
src/cli_verification_code/dev.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
require('../setup_node_env');
|
||||
require('./cli_verification_code');
|
10
src/cli_verification_code/dist.js
Normal file
10
src/cli_verification_code/dist.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
require('../setup_node_env/dist');
|
||||
require('./cli_verification_code');
|
|
@ -9,6 +9,7 @@
|
|||
import { StatusResponse } from '../../../../types/status';
|
||||
import { httpServiceMock } from '../../../http/http_service.mock';
|
||||
import { notificationServiceMock } from '../../../notifications/notifications_service.mock';
|
||||
import { mocked } from '../../../../server/metrics/event_loop_delays/event_loop_delays_monitor.mocks';
|
||||
import { loadStatus } from './load_status';
|
||||
|
||||
const mockedResponse: StatusResponse = {
|
||||
|
@ -61,6 +62,7 @@ const mockedResponse: StatusResponse = {
|
|||
},
|
||||
},
|
||||
process: {
|
||||
pid: 1,
|
||||
memory: {
|
||||
heap: {
|
||||
size_limit: 1000000,
|
||||
|
@ -70,9 +72,25 @@ const mockedResponse: StatusResponse = {
|
|||
resident_set_size_in_bytes: 1,
|
||||
},
|
||||
event_loop_delay: 1,
|
||||
pid: 1,
|
||||
event_loop_delay_histogram: mocked.createHistogram(),
|
||||
uptime_in_millis: 1,
|
||||
},
|
||||
processes: [
|
||||
{
|
||||
pid: 1,
|
||||
memory: {
|
||||
heap: {
|
||||
size_limit: 1000000,
|
||||
used_in_bytes: 100,
|
||||
total_in_bytes: 0,
|
||||
},
|
||||
resident_set_size_in_bytes: 1,
|
||||
},
|
||||
event_loop_delay: 1,
|
||||
event_loop_delay_histogram: mocked.createHistogram(),
|
||||
uptime_in_millis: 1,
|
||||
},
|
||||
],
|
||||
response_times: {
|
||||
avg_in_millis: 4000,
|
||||
max_in_millis: 8000,
|
||||
|
|
|
@ -39,7 +39,6 @@ import { SavedObjectsClientContract } from '../saved_objects/types';
|
|||
* const deprecations: DeprecationsDetails[] = [];
|
||||
* const count = await getFooCount(savedObjectsClient);
|
||||
* if (count > 0) {
|
||||
* // Example of a manual correctiveAction
|
||||
* deprecations.push({
|
||||
* title: i18n.translate('xpack.foo.deprecations.title', {
|
||||
* defaultMessage: `Foo's are deprecated`
|
||||
|
|
|
@ -378,7 +378,9 @@ export type {
|
|||
OpsProcessMetrics,
|
||||
MetricsServiceSetup,
|
||||
MetricsServiceStart,
|
||||
IntervalHistogram,
|
||||
} from './metrics';
|
||||
export { EventLoopDelaysMonitor } from './metrics';
|
||||
|
||||
export type { I18nServiceSetup } from './i18n';
|
||||
export type {
|
||||
|
|
|
@ -65,8 +65,10 @@ export class FileAppender implements DisposableAppender {
|
|||
return resolve();
|
||||
}
|
||||
|
||||
this.outputStream.end(() => {
|
||||
this.outputStream = undefined;
|
||||
const outputStream = this.outputStream;
|
||||
this.outputStream = undefined;
|
||||
|
||||
outputStream.end(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
import { MetricsCollector } from './types';
|
||||
|
||||
const createCollector = (collectReturnValue: any = {}): jest.Mocked<MetricsCollector<any>> => {
|
||||
const collector: jest.Mocked<MetricsCollector<any>> = {
|
||||
const createCollector = <T = any>(
|
||||
collectReturnValue: any = {}
|
||||
): jest.Mocked<MetricsCollector<T>> => {
|
||||
const collector: jest.Mocked<MetricsCollector<T>> = {
|
||||
collect: jest.fn().mockResolvedValue(collectReturnValue),
|
||||
reset: jest.fn(),
|
||||
};
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { MetricsCollector } from './types';
|
||||
import type { MetricsCollector } from './types';
|
||||
import { createMockOpsProcessMetrics } from './process.mocks';
|
||||
|
||||
const createMock = () => {
|
||||
const mocked: jest.Mocked<MetricsCollector<any>> = {
|
||||
|
@ -21,4 +22,5 @@ const createMock = () => {
|
|||
|
||||
export const collectorMock = {
|
||||
create: createMock,
|
||||
createOpsProcessMetrics: createMockOpsProcessMetrics,
|
||||
};
|
||||
|
|
24
src/core/server/metrics/collectors/process.mocks.ts
Normal file
24
src/core/server/metrics/collectors/process.mocks.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { mocked } from '../event_loop_delays/event_loop_delays_monitor.mocks';
|
||||
import type { OpsProcessMetrics } from './types';
|
||||
|
||||
export function createMockOpsProcessMetrics(): OpsProcessMetrics {
|
||||
const histogram = mocked.createHistogram();
|
||||
|
||||
return {
|
||||
memory: {
|
||||
heap: { total_in_bytes: 1, used_in_bytes: 1, size_limit: 1 },
|
||||
resident_set_size_in_bytes: 1,
|
||||
},
|
||||
event_loop_delay: 1,
|
||||
event_loop_delay_histogram: histogram,
|
||||
pid: 1,
|
||||
uptime_in_millis: 1,
|
||||
};
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
import v8, { HeapInfo } from 'v8';
|
||||
import { ProcessMetricsCollector } from './process';
|
||||
|
||||
/* eslint-disable dot-notation */
|
||||
describe('ProcessMetricsCollector', () => {
|
||||
let collector: ProcessMetricsCollector;
|
||||
|
||||
|
@ -20,28 +21,34 @@ describe('ProcessMetricsCollector', () => {
|
|||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('collects pid from the process', async () => {
|
||||
const metrics = await collector.collect();
|
||||
it('collects pid from the process', () => {
|
||||
const metrics = collector.collect();
|
||||
|
||||
expect(metrics.pid).toEqual(process.pid);
|
||||
expect(metrics).toHaveLength(1);
|
||||
expect(metrics[0].pid).toEqual(process.pid);
|
||||
});
|
||||
|
||||
it('collects event loop delay', async () => {
|
||||
const metrics = await collector.collect();
|
||||
|
||||
expect(metrics.event_loop_delay).toBeGreaterThan(0);
|
||||
it('collects event loop delay', () => {
|
||||
const mockEventLoopDelayMonitor = { collect: jest.fn().mockReturnValue({ mean: 13 }) };
|
||||
// @ts-expect-error-next-line readonly private method.
|
||||
collector['eventLoopDelayMonitor'] = mockEventLoopDelayMonitor;
|
||||
const metrics = collector.collect();
|
||||
expect(metrics).toHaveLength(1);
|
||||
expect(metrics[0].event_loop_delay).toBe(13);
|
||||
expect(mockEventLoopDelayMonitor.collect).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it('collects uptime info from the process', async () => {
|
||||
it('collects uptime info from the process', () => {
|
||||
const uptime = 58986;
|
||||
jest.spyOn(process, 'uptime').mockImplementation(() => uptime);
|
||||
|
||||
const metrics = await collector.collect();
|
||||
const metrics = collector.collect();
|
||||
|
||||
expect(metrics.uptime_in_millis).toEqual(uptime * 1000);
|
||||
expect(metrics).toHaveLength(1);
|
||||
expect(metrics[0].uptime_in_millis).toEqual(uptime * 1000);
|
||||
});
|
||||
|
||||
it('collects memory info from the process', async () => {
|
||||
it('collects memory info from the process', () => {
|
||||
const heapTotal = 58986;
|
||||
const heapUsed = 4688;
|
||||
const heapSizeLimit = 5788;
|
||||
|
@ -61,11 +68,12 @@ describe('ProcessMetricsCollector', () => {
|
|||
} as HeapInfo)
|
||||
);
|
||||
|
||||
const metrics = await collector.collect();
|
||||
const metrics = collector.collect();
|
||||
|
||||
expect(metrics.memory.heap.total_in_bytes).toEqual(heapTotal);
|
||||
expect(metrics.memory.heap.used_in_bytes).toEqual(heapUsed);
|
||||
expect(metrics.memory.heap.size_limit).toEqual(heapSizeLimit);
|
||||
expect(metrics.memory.resident_set_size_in_bytes).toEqual(rss);
|
||||
expect(metrics).toHaveLength(1);
|
||||
expect(metrics[0].memory.heap.total_in_bytes).toEqual(heapTotal);
|
||||
expect(metrics[0].memory.heap.used_in_bytes).toEqual(heapUsed);
|
||||
expect(metrics[0].memory.heap.size_limit).toEqual(heapSizeLimit);
|
||||
expect(metrics[0].memory.resident_set_size_in_bytes).toEqual(rss);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,14 +7,26 @@
|
|||
*/
|
||||
|
||||
import v8 from 'v8';
|
||||
import { Bench } from '@hapi/hoek';
|
||||
import { OpsProcessMetrics, MetricsCollector } from './types';
|
||||
import { EventLoopDelaysMonitor } from '../event_loop_delays';
|
||||
|
||||
export class ProcessMetricsCollector implements MetricsCollector<OpsProcessMetrics> {
|
||||
public async collect(): Promise<OpsProcessMetrics> {
|
||||
export class ProcessMetricsCollector implements MetricsCollector<OpsProcessMetrics[]> {
|
||||
static getMainThreadMetrics(processes: OpsProcessMetrics[]): undefined | OpsProcessMetrics {
|
||||
/**
|
||||
* Currently Kibana does not support multi-processes.
|
||||
* Once we have multiple processes we can add a `name` field
|
||||
* and filter on `name === 'server_worker'` to get the main thread.
|
||||
*/
|
||||
return processes[0];
|
||||
}
|
||||
|
||||
private readonly eventLoopDelayMonitor = new EventLoopDelaysMonitor();
|
||||
|
||||
private getCurrentPidMetrics(): OpsProcessMetrics {
|
||||
const eventLoopDelayHistogram = this.eventLoopDelayMonitor.collect();
|
||||
const heapStats = v8.getHeapStatistics();
|
||||
const memoryUsage = process.memoryUsage();
|
||||
const [eventLoopDelay] = await Promise.all([getEventLoopDelay()]);
|
||||
|
||||
return {
|
||||
memory: {
|
||||
heap: {
|
||||
|
@ -25,19 +37,17 @@ export class ProcessMetricsCollector implements MetricsCollector<OpsProcessMetri
|
|||
resident_set_size_in_bytes: memoryUsage.rss,
|
||||
},
|
||||
pid: process.pid,
|
||||
event_loop_delay: eventLoopDelay,
|
||||
event_loop_delay: eventLoopDelayHistogram.mean,
|
||||
event_loop_delay_histogram: eventLoopDelayHistogram,
|
||||
uptime_in_millis: process.uptime() * 1000,
|
||||
};
|
||||
}
|
||||
|
||||
public reset() {}
|
||||
}
|
||||
public collect(): OpsProcessMetrics[] {
|
||||
return [this.getCurrentPidMetrics()];
|
||||
}
|
||||
|
||||
const getEventLoopDelay = (): Promise<number> => {
|
||||
const bench = new Bench();
|
||||
return new Promise((resolve) => {
|
||||
setImmediate(() => {
|
||||
return resolve(bench.elapsed());
|
||||
});
|
||||
});
|
||||
};
|
||||
public reset() {
|
||||
this.eventLoopDelayMonitor.reset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { MaybePromise } from '@kbn/utility-types';
|
||||
import type { IntervalHistogram } from '../types';
|
||||
|
||||
/** Base interface for all metrics gatherers */
|
||||
export interface MetricsCollector<T> {
|
||||
/** collect the data currently gathered by the collector */
|
||||
collect(): Promise<T>;
|
||||
collect(): MaybePromise<T>;
|
||||
/** reset the internal state of the collector */
|
||||
reset(): void;
|
||||
}
|
||||
|
@ -19,6 +21,8 @@ export interface MetricsCollector<T> {
|
|||
* @public
|
||||
*/
|
||||
export interface OpsProcessMetrics {
|
||||
/** pid of the kibana process */
|
||||
pid: number;
|
||||
/** process memory usage */
|
||||
memory: {
|
||||
/** heap memory usage */
|
||||
|
@ -33,10 +37,10 @@ export interface OpsProcessMetrics {
|
|||
/** node rss */
|
||||
resident_set_size_in_bytes: number;
|
||||
};
|
||||
/** node event loop delay */
|
||||
/** mean event loop delay since last collection*/
|
||||
event_loop_delay: number;
|
||||
/** pid of the kibana process */
|
||||
pid: number;
|
||||
/** node event loop delay histogram since last collection */
|
||||
event_loop_delay_histogram: IntervalHistogram;
|
||||
/** uptime of the kibana process */
|
||||
uptime_in_millis: number;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { mocked } from '../event_loop_delays_monitor.mocks';
|
||||
|
||||
export const monitorEventLoopDelay = jest.fn().mockImplementation(() => {
|
||||
const mockedHistogram = mocked.createHistogram();
|
||||
|
||||
return {
|
||||
...mockedHistogram,
|
||||
enable: jest.fn(),
|
||||
percentile: jest.fn().mockImplementation((percentile: number) => {
|
||||
return (mockedHistogram.percentiles as Record<string, number | undefined>)[`${percentile}`];
|
||||
}),
|
||||
disable: jest.fn(),
|
||||
reset: jest.fn(),
|
||||
};
|
||||
});
|
|
@ -6,26 +6,11 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
import moment from 'moment';
|
||||
import type { IntervalHistogram } from './event_loop_delays';
|
||||
|
||||
export const mockMonitorEnable = jest.fn();
|
||||
export const mockMonitorPercentile = jest.fn();
|
||||
export const mockMonitorReset = jest.fn();
|
||||
export const mockMonitorDisable = jest.fn();
|
||||
export const monitorEventLoopDelay = jest.fn().mockReturnValue({
|
||||
enable: mockMonitorEnable,
|
||||
percentile: mockMonitorPercentile,
|
||||
disable: mockMonitorDisable,
|
||||
reset: mockMonitorReset,
|
||||
...createMockHistogram(),
|
||||
});
|
||||
|
||||
jest.doMock('perf_hooks', () => ({
|
||||
monitorEventLoopDelay,
|
||||
}));
|
||||
import type { EventLoopDelaysMonitor } from './event_loop_delays_monitor';
|
||||
import type { IntervalHistogram } from '../types';
|
||||
|
||||
function createMockHistogram(overwrites: Partial<IntervalHistogram> = {}): IntervalHistogram {
|
||||
const now = moment();
|
||||
const now = Date.now();
|
||||
|
||||
return {
|
||||
min: 9093120,
|
||||
|
@ -33,8 +18,8 @@ function createMockHistogram(overwrites: Partial<IntervalHistogram> = {}): Inter
|
|||
mean: 11993238.600747818,
|
||||
exceeds: 0,
|
||||
stddev: 1168191.9357543814,
|
||||
fromTimestamp: now.startOf('day').toISOString(),
|
||||
lastUpdatedAt: now.toISOString(),
|
||||
fromTimestamp: moment(now).toISOString(),
|
||||
lastUpdatedAt: moment(now).toISOString(),
|
||||
percentiles: {
|
||||
'50': 12607487,
|
||||
'75': 12615679,
|
||||
|
@ -45,6 +30,22 @@ function createMockHistogram(overwrites: Partial<IntervalHistogram> = {}): Inter
|
|||
};
|
||||
}
|
||||
|
||||
function createMockEventLoopDelaysMonitor() {
|
||||
const mockCollect = jest.fn();
|
||||
const MockEventLoopDelaysMonitor: jest.MockedClass<
|
||||
typeof EventLoopDelaysMonitor
|
||||
> = jest.fn().mockReturnValue({
|
||||
collect: mockCollect,
|
||||
reset: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
});
|
||||
|
||||
mockCollect.mockReturnValue(createMockHistogram());
|
||||
|
||||
return new MockEventLoopDelaysMonitor();
|
||||
}
|
||||
|
||||
export const mocked = {
|
||||
createHistogram: createMockHistogram,
|
||||
createEventLoopDelaysMonitor: createMockEventLoopDelaysMonitor,
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
/* eslint-disable dot-notation */
|
||||
jest.mock('perf_hooks');
|
||||
import { monitorEventLoopDelay } from 'perf_hooks';
|
||||
import { EventLoopDelaysMonitor } from './event_loop_delays_monitor';
|
||||
import { mocked } from './event_loop_delays_monitor.mocks';
|
||||
|
||||
describe('EventLoopDelaysMonitor', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers('modern');
|
||||
const mockNow = jest.getRealSystemTime();
|
||||
jest.setSystemTime(mockNow);
|
||||
});
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
afterAll(() => jest.useRealTimers());
|
||||
|
||||
test('#constructor enables monitoring', () => {
|
||||
const eventLoopDelaysMonitor = new EventLoopDelaysMonitor();
|
||||
expect(monitorEventLoopDelay).toBeCalledTimes(1);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].enable).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('#collect returns event loop delays histogram', () => {
|
||||
const eventLoopDelaysMonitor = new EventLoopDelaysMonitor();
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].disable).toBeCalledTimes(0);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].enable).toBeCalledTimes(1);
|
||||
const histogramData = eventLoopDelaysMonitor.collect();
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].disable).toBeCalledTimes(1);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].enable).toBeCalledTimes(2);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].percentile).toHaveBeenNthCalledWith(1, 50);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].percentile).toHaveBeenNthCalledWith(2, 75);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].percentile).toHaveBeenNthCalledWith(3, 95);
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].percentile).toHaveBeenNthCalledWith(4, 99);
|
||||
|
||||
// mocked perf_hook returns `mocked.createHistogram()`.
|
||||
// This ensures that the wiring of the `collect` function is correct.
|
||||
const mockedHistogram = mocked.createHistogram();
|
||||
expect(histogramData).toEqual(mockedHistogram);
|
||||
});
|
||||
|
||||
test('#reset resets histogram data', () => {
|
||||
const eventLoopDelaysMonitor = new EventLoopDelaysMonitor();
|
||||
eventLoopDelaysMonitor.reset();
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].reset).toBeCalledTimes(1);
|
||||
});
|
||||
test('#stop disables monitoring event loop delays', () => {
|
||||
const eventLoopDelaysMonitor = new EventLoopDelaysMonitor();
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].disable).toBeCalledTimes(0);
|
||||
eventLoopDelaysMonitor.stop();
|
||||
expect(eventLoopDelaysMonitor['loopMonitor'].disable).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -8,48 +8,41 @@
|
|||
|
||||
import type { EventLoopDelayMonitor } from 'perf_hooks';
|
||||
import { monitorEventLoopDelay } from 'perf_hooks';
|
||||
import { MONITOR_EVENT_LOOP_DELAYS_RESOLUTION } from './constants';
|
||||
import type { IntervalHistogram } from '../types';
|
||||
|
||||
export interface IntervalHistogram {
|
||||
fromTimestamp: string;
|
||||
lastUpdatedAt: string;
|
||||
min: number;
|
||||
max: number;
|
||||
mean: number;
|
||||
exceeds: number;
|
||||
stddev: number;
|
||||
percentiles: {
|
||||
50: number;
|
||||
75: number;
|
||||
95: number;
|
||||
99: number;
|
||||
};
|
||||
}
|
||||
|
||||
export class EventLoopDelaysCollector {
|
||||
export class EventLoopDelaysMonitor {
|
||||
private readonly loopMonitor: EventLoopDelayMonitor;
|
||||
private fromTimestamp: Date;
|
||||
|
||||
/**
|
||||
* Creating a new instance from EventLoopDelaysMonitor will
|
||||
* automatically start tracking event loop delays.
|
||||
*/
|
||||
constructor() {
|
||||
const monitor = monitorEventLoopDelay({
|
||||
resolution: MONITOR_EVENT_LOOP_DELAYS_RESOLUTION,
|
||||
});
|
||||
const monitor = monitorEventLoopDelay();
|
||||
monitor.enable();
|
||||
this.fromTimestamp = new Date();
|
||||
this.loopMonitor = monitor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect gathers event loop delays metrics from nodejs perf_hooks.monitorEventLoopDelay
|
||||
* the histogram calculations start from the last time `reset` was called or this
|
||||
* EventLoopDelaysMonitor instance was created.
|
||||
* @returns {IntervalHistogram}
|
||||
*/
|
||||
public collect(): IntervalHistogram {
|
||||
const lastUpdated = new Date();
|
||||
this.loopMonitor.disable();
|
||||
const { min, max, mean, exceeds, stddev } = this.loopMonitor;
|
||||
|
||||
return {
|
||||
const collectedData: IntervalHistogram = {
|
||||
min,
|
||||
max,
|
||||
mean,
|
||||
exceeds,
|
||||
stddev,
|
||||
fromTimestamp: this.fromTimestamp.toISOString(),
|
||||
lastUpdatedAt: new Date().toISOString(),
|
||||
lastUpdatedAt: lastUpdated.toISOString(),
|
||||
percentiles: {
|
||||
50: this.loopMonitor.percentile(50),
|
||||
75: this.loopMonitor.percentile(75),
|
||||
|
@ -57,13 +50,22 @@ export class EventLoopDelaysCollector {
|
|||
99: this.loopMonitor.percentile(99),
|
||||
},
|
||||
};
|
||||
|
||||
this.loopMonitor.enable();
|
||||
return collectedData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the collected histogram data.
|
||||
*/
|
||||
public reset() {
|
||||
this.loopMonitor.reset();
|
||||
this.fromTimestamp = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables updating the interval timer for collecting new data points.
|
||||
*/
|
||||
public stop() {
|
||||
this.loopMonitor.disable();
|
||||
}
|
9
src/core/server/metrics/event_loop_delays/index.ts
Normal file
9
src/core/server/metrics/event_loop_delays/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { EventLoopDelaysMonitor } from './event_loop_delays_monitor';
|
|
@ -12,8 +12,10 @@ export type {
|
|||
MetricsServiceSetup,
|
||||
MetricsServiceStart,
|
||||
OpsMetrics,
|
||||
IntervalHistogram,
|
||||
} from './types';
|
||||
export type { OpsProcessMetrics, OpsServerMetrics, OpsOsMetrics } from './collectors';
|
||||
export { MetricsService } from './metrics_service';
|
||||
export { opsConfig } from './ops_config';
|
||||
export type { OpsConfigType } from './ops_config';
|
||||
export { EventLoopDelaysMonitor } from './event_loop_delays';
|
||||
|
|
|
@ -8,19 +8,15 @@
|
|||
|
||||
import { OpsMetrics } from '..';
|
||||
import { getEcsOpsMetricsLog } from './get_ops_metrics_log';
|
||||
import { collectorMock } from '../collectors/mocks';
|
||||
|
||||
function createBaseOpsMetrics(): OpsMetrics {
|
||||
const mockProcess = collectorMock.createOpsProcessMetrics();
|
||||
|
||||
return {
|
||||
collected_at: new Date('2020-01-01 01:00:00'),
|
||||
process: {
|
||||
memory: {
|
||||
heap: { total_in_bytes: 1, used_in_bytes: 1, size_limit: 1 },
|
||||
resident_set_size_in_bytes: 1,
|
||||
},
|
||||
event_loop_delay: 1,
|
||||
pid: 1,
|
||||
uptime_in_millis: 1,
|
||||
},
|
||||
process: mockProcess,
|
||||
processes: [mockProcess],
|
||||
os: {
|
||||
platform: 'darwin' as const,
|
||||
platformRelease: 'test',
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import type { PublicMethodsOf } from '@kbn/utility-types';
|
||||
|
||||
import type { MetricsService } from './metrics_service';
|
||||
import { collectorMock } from './collectors/mocks';
|
||||
import { mocked as eventLoopDelaysMonitorMock } from './event_loop_delays/event_loop_delays_monitor.mocks';
|
||||
import {
|
||||
InternalMetricsServiceSetup,
|
||||
InternalMetricsServiceStart,
|
||||
|
@ -22,18 +23,14 @@ const createInternalSetupContractMock = () => {
|
|||
collectionInterval: 30000,
|
||||
getOpsMetrics$: jest.fn(),
|
||||
};
|
||||
|
||||
const processMock = collectorMock.createOpsProcessMetrics();
|
||||
|
||||
setupContract.getOpsMetrics$.mockReturnValue(
|
||||
new BehaviorSubject({
|
||||
collected_at: new Date('2020-01-01 01:00:00'),
|
||||
process: {
|
||||
memory: {
|
||||
heap: { total_in_bytes: 1, used_in_bytes: 1, size_limit: 1 },
|
||||
resident_set_size_in_bytes: 1,
|
||||
},
|
||||
event_loop_delay: 1,
|
||||
pid: 1,
|
||||
uptime_in_millis: 1,
|
||||
},
|
||||
process: processMock,
|
||||
processes: [processMock],
|
||||
os: {
|
||||
platform: 'darwin' as const,
|
||||
platformRelease: 'test',
|
||||
|
@ -81,4 +78,5 @@ export const metricsServiceMock = {
|
|||
createStartContract: createStartContractMock,
|
||||
createInternalSetupContract: createInternalSetupContractMock,
|
||||
createInternalStartContract: createInternalStartContractMock,
|
||||
createEventLoopDelaysMonitor: eventLoopDelaysMonitorMock.createEventLoopDelaysMonitor,
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('OpsMetricsCollector', () => {
|
|||
describe('#collect', () => {
|
||||
it('gathers metrics from the underlying collectors', async () => {
|
||||
mockOsCollector.collect.mockResolvedValue('osMetrics');
|
||||
mockProcessCollector.collect.mockResolvedValue('processMetrics');
|
||||
mockProcessCollector.collect.mockResolvedValue(['processMetrics']);
|
||||
mockServerCollector.collect.mockResolvedValue({
|
||||
requests: 'serverRequestsMetrics',
|
||||
response_times: 'serverTimingMetrics',
|
||||
|
@ -43,6 +43,7 @@ describe('OpsMetricsCollector', () => {
|
|||
expect(metrics).toEqual({
|
||||
collected_at: expect.any(Date),
|
||||
process: 'processMetrics',
|
||||
processes: ['processMetrics'],
|
||||
os: 'osMetrics',
|
||||
requests: 'serverRequestsMetrics',
|
||||
response_times: 'serverTimingMetrics',
|
||||
|
|
|
@ -28,14 +28,21 @@ export class OpsMetricsCollector implements MetricsCollector<OpsMetrics> {
|
|||
}
|
||||
|
||||
public async collect(): Promise<OpsMetrics> {
|
||||
const [process, os, server] = await Promise.all([
|
||||
const [processes, os, server] = await Promise.all([
|
||||
this.processCollector.collect(),
|
||||
this.osCollector.collect(),
|
||||
this.serverCollector.collect(),
|
||||
]);
|
||||
|
||||
return {
|
||||
collected_at: new Date(),
|
||||
process,
|
||||
/**
|
||||
* Kibana does not yet support multi-process nodes.
|
||||
* `processes` is just an Array(1) only returning the current process's data
|
||||
* which is why we can just use processes[0] for `process`
|
||||
*/
|
||||
process: processes[0],
|
||||
processes,
|
||||
os,
|
||||
...server,
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import { OpsProcessMetrics, OpsOsMetrics, OpsServerMetrics } from './collectors';
|
||||
import type { OpsProcessMetrics, OpsOsMetrics, OpsServerMetrics } from './collectors';
|
||||
|
||||
/**
|
||||
* APIs to retrieves metrics gathered and exposed by the core platform.
|
||||
|
@ -51,8 +51,13 @@ export type InternalMetricsServiceStart = MetricsServiceStart;
|
|||
export interface OpsMetrics {
|
||||
/** Time metrics were recorded at. */
|
||||
collected_at: Date;
|
||||
/** Process related metrics */
|
||||
/**
|
||||
* Process related metrics.
|
||||
* @deprecated use the processes field instead.
|
||||
*/
|
||||
process: OpsProcessMetrics;
|
||||
/** Process related metrics. Reports an array of objects for each kibana pid.*/
|
||||
processes: OpsProcessMetrics[];
|
||||
/** OS related metrics */
|
||||
os: OpsOsMetrics;
|
||||
/** server response time stats */
|
||||
|
@ -62,3 +67,37 @@ export interface OpsMetrics {
|
|||
/** number of current concurrent connections to the server */
|
||||
concurrent_connections: OpsServerMetrics['concurrent_connections'];
|
||||
}
|
||||
|
||||
/**
|
||||
* an IntervalHistogram object that samples and reports the event loop delay over time.
|
||||
* The delays will be reported in nanoseconds.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface IntervalHistogram {
|
||||
// The first timestamp the interval timer kicked in for collecting data points.
|
||||
fromTimestamp: string;
|
||||
// Last timestamp the interval timer kicked in for collecting data points.
|
||||
lastUpdatedAt: string;
|
||||
// The minimum recorded event loop delay.
|
||||
min: number;
|
||||
// The maximum recorded event loop delay.
|
||||
max: number;
|
||||
// The mean of the recorded event loop delays.
|
||||
mean: number;
|
||||
// The number of times the event loop delay exceeded the maximum 1 hour event loop delay threshold.
|
||||
exceeds: number;
|
||||
// The standard deviation of the recorded event loop delays.
|
||||
stddev: number;
|
||||
// An object detailing the accumulated percentile distribution.
|
||||
percentiles: {
|
||||
// 50th percentile of delays of the collected data points.
|
||||
50: number;
|
||||
// 75th percentile of delays of the collected data points.
|
||||
75: number;
|
||||
// 95th percentile of delays of the collected data points.
|
||||
95: number;
|
||||
// 99th percentile of delays of the collected data points.
|
||||
99: number;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import type { RegisterDeprecationsConfig } from '../../deprecations';
|
||||
import type { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import { getUnknownTypesDeprecations } from './unknown_object_types';
|
||||
|
||||
interface GetDeprecationProviderOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const getSavedObjectsDeprecationsProvider = (
|
||||
config: GetDeprecationProviderOptions
|
||||
): RegisterDeprecationsConfig => {
|
||||
return {
|
||||
getDeprecations: async (context) => {
|
||||
return [
|
||||
...(await getUnknownTypesDeprecations({
|
||||
...config,
|
||||
esClient: context.esClient,
|
||||
})),
|
||||
];
|
||||
},
|
||||
};
|
||||
};
|
10
src/core/server/saved_objects/deprecations/index.ts
Normal file
10
src/core/server/saved_objects/deprecations/index.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { getSavedObjectsDeprecationsProvider } from './deprecation_factory';
|
||||
export { deleteUnknownTypeObjects } from './unknown_object_types';
|
|
@ -6,9 +6,8 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext } from 'kibana/public';
|
||||
import { TableVisPlugin as Plugin } from './plugin';
|
||||
export const getIndexForTypeMock = jest.fn();
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new Plugin(initializerContext);
|
||||
}
|
||||
jest.doMock('../service/lib/get_index_for_type', () => ({
|
||||
getIndexForType: getIndexForTypeMock,
|
||||
}));
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { getIndexForTypeMock } from './unknown_object_types.test.mocks';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { deleteUnknownTypeObjects, getUnknownTypesDeprecations } from './unknown_object_types';
|
||||
import { typeRegistryMock } from '../saved_objects_type_registry.mock';
|
||||
import { elasticsearchClientMock } from '../../elasticsearch/client/mocks';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
|
||||
const createSearchResponse = (count: number): estypes.SearchResponse => {
|
||||
return {
|
||||
hits: {
|
||||
total: count,
|
||||
max_score: 0,
|
||||
hits: new Array(count).fill({}),
|
||||
},
|
||||
} as estypes.SearchResponse;
|
||||
};
|
||||
|
||||
describe('unknown saved object types deprecation', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
let esClient: ReturnType<typeof elasticsearchClientMock.createScopedClusterClient>;
|
||||
let kibanaConfig: KibanaConfigType;
|
||||
let savedObjectsConfig: SavedObjectConfig;
|
||||
|
||||
beforeEach(() => {
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
esClient = elasticsearchClientMock.createScopedClusterClient();
|
||||
|
||||
typeRegistry.getAllTypes.mockReturnValue([
|
||||
{ name: 'foo' },
|
||||
{ name: 'bar' },
|
||||
] as SavedObjectsType[]);
|
||||
getIndexForTypeMock.mockImplementation(({ type }: { type: string }) => `${type}-index`);
|
||||
|
||||
kibanaConfig = {
|
||||
index: '.kibana',
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
savedObjectsConfig = {
|
||||
migration: {
|
||||
enableV2: true,
|
||||
},
|
||||
} as SavedObjectConfig;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getIndexForTypeMock.mockReset();
|
||||
});
|
||||
|
||||
describe('getUnknownTypesDeprecations', () => {
|
||||
beforeEach(() => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(0))
|
||||
);
|
||||
});
|
||||
|
||||
it('calls `esClient.asInternalUser.search` with the correct parameters', async () => {
|
||||
await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(esClient.asInternalUser.search).toHaveBeenCalledTimes(1);
|
||||
expect(esClient.asInternalUser.search).toHaveBeenCalledWith({
|
||||
index: ['foo-index', 'bar-index'],
|
||||
body: {
|
||||
size: 10000,
|
||||
query: {
|
||||
bool: {
|
||||
must_not: [{ term: { type: 'foo' } }, { term: { type: 'bar' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns no deprecation if no unknown type docs are found', async () => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(0))
|
||||
);
|
||||
|
||||
const deprecations = await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(deprecations.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns a deprecation if any unknown type docs are found', async () => {
|
||||
esClient.asInternalUser.search.mockReturnValue(
|
||||
elasticsearchClientMock.createSuccessTransportRequestPromise(createSearchResponse(1))
|
||||
);
|
||||
|
||||
const deprecations = await getUnknownTypesDeprecations({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(deprecations.length).toEqual(1);
|
||||
expect(deprecations[0]).toEqual({
|
||||
title: expect.any(String),
|
||||
message: expect.any(String),
|
||||
level: 'critical',
|
||||
requireRestart: false,
|
||||
deprecationType: undefined,
|
||||
correctiveActions: {
|
||||
manualSteps: expect.any(Array),
|
||||
api: {
|
||||
path: '/internal/saved_objects/deprecations/_delete_unknown_types',
|
||||
method: 'POST',
|
||||
body: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteUnknownTypeObjects', () => {
|
||||
it('calls `esClient.asInternalUser.search` with the correct parameters', async () => {
|
||||
await deleteUnknownTypeObjects({
|
||||
savedObjectsConfig,
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
|
||||
expect(esClient.asInternalUser.deleteByQuery).toHaveBeenCalledTimes(1);
|
||||
expect(esClient.asInternalUser.deleteByQuery).toHaveBeenCalledWith({
|
||||
index: ['foo-index', 'bar-index'],
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
must_not: [{ term: { type: 'foo' } }, { term: { type: 'bar' } }],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { DeprecationsDetails } from '../../deprecations';
|
||||
import { IScopedClusterClient } from '../../elasticsearch';
|
||||
import { ISavedObjectTypeRegistry } from '../saved_objects_type_registry';
|
||||
import { SavedObjectsRawDocSource } from '../serialization';
|
||||
import type { KibanaConfigType } from '../../kibana_config';
|
||||
import type { SavedObjectConfig } from '../saved_objects_config';
|
||||
import { getIndexForType } from '../service/lib';
|
||||
|
||||
interface UnknownTypesDeprecationOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
esClient: IScopedClusterClient;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
const getKnownTypes = (typeRegistry: ISavedObjectTypeRegistry) =>
|
||||
typeRegistry.getAllTypes().map((type) => type.name);
|
||||
|
||||
const getTargetIndices = ({
|
||||
types,
|
||||
typeRegistry,
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
}: {
|
||||
types: string[];
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}) => {
|
||||
return [
|
||||
...new Set(
|
||||
types.map((type) =>
|
||||
getIndexForType({
|
||||
type,
|
||||
typeRegistry,
|
||||
migV2Enabled: savedObjectsConfig.migration.enableV2,
|
||||
kibanaVersion,
|
||||
defaultIndex: kibanaConfig.index,
|
||||
})
|
||||
)
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
const getUnknownTypesQuery = (knownTypes: string[]): estypes.QueryDslQueryContainer => {
|
||||
return {
|
||||
bool: {
|
||||
must_not: knownTypes.map((type) => ({
|
||||
term: { type },
|
||||
})),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const getUnknownSavedObjects = async ({
|
||||
typeRegistry,
|
||||
esClient,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
kibanaVersion,
|
||||
}: UnknownTypesDeprecationOptions) => {
|
||||
const knownTypes = getKnownTypes(typeRegistry);
|
||||
const targetIndices = getTargetIndices({
|
||||
types: knownTypes,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
savedObjectsConfig,
|
||||
});
|
||||
const query = getUnknownTypesQuery(knownTypes);
|
||||
|
||||
const { body } = await esClient.asInternalUser.search<SavedObjectsRawDocSource>({
|
||||
index: targetIndices,
|
||||
body: {
|
||||
size: 10000,
|
||||
query,
|
||||
},
|
||||
});
|
||||
const { hits: unknownDocs } = body.hits;
|
||||
|
||||
return unknownDocs.map((doc) => ({ id: doc._id, type: doc._source?.type ?? 'unknown' }));
|
||||
};
|
||||
|
||||
export const getUnknownTypesDeprecations = async (
|
||||
options: UnknownTypesDeprecationOptions
|
||||
): Promise<DeprecationsDetails[]> => {
|
||||
const deprecations: DeprecationsDetails[] = [];
|
||||
const unknownDocs = await getUnknownSavedObjects(options);
|
||||
if (unknownDocs.length) {
|
||||
deprecations.push({
|
||||
title: i18n.translate('core.savedObjects.deprecations.unknownTypes.title', {
|
||||
defaultMessage: 'Saved objects with unknown types are present in Kibana system indices',
|
||||
}),
|
||||
message: i18n.translate('core.savedObjects.deprecations.unknownTypes.message', {
|
||||
defaultMessage:
|
||||
'{objectCount, plural, one {# object} other {# objects}} with unknown types {objectCount, plural, one {was} other {were}} found in Kibana system indices. ' +
|
||||
'Upgrading with unknown savedObject types is no longer supported. ' +
|
||||
`To ensure that upgrades will succeed in the future, either re-enable plugins or delete these documents from the Kibana indices`,
|
||||
values: {
|
||||
objectCount: unknownDocs.length,
|
||||
},
|
||||
}),
|
||||
level: 'critical',
|
||||
requireRestart: false,
|
||||
deprecationType: undefined, // not config nor feature...
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
i18n.translate('core.savedObjects.deprecations.unknownTypes.manualSteps.1', {
|
||||
defaultMessage: 'Enable disabled plugins then restart Kibana.',
|
||||
}),
|
||||
i18n.translate('core.savedObjects.deprecations.unknownTypes.manualSteps.2', {
|
||||
defaultMessage:
|
||||
'If no plugins are disabled, or if enabling them does not fix the issue, delete the documents.',
|
||||
}),
|
||||
],
|
||||
api: {
|
||||
path: '/internal/saved_objects/deprecations/_delete_unknown_types',
|
||||
method: 'POST',
|
||||
body: {},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
return deprecations;
|
||||
};
|
||||
|
||||
interface DeleteUnknownTypesOptions {
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
esClient: IScopedClusterClient;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
savedObjectsConfig: SavedObjectConfig;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const deleteUnknownTypeObjects = async ({
|
||||
esClient,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
savedObjectsConfig,
|
||||
kibanaVersion,
|
||||
}: DeleteUnknownTypesOptions) => {
|
||||
const knownTypes = getKnownTypes(typeRegistry);
|
||||
const targetIndices = getTargetIndices({
|
||||
types: knownTypes,
|
||||
typeRegistry,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
savedObjectsConfig,
|
||||
});
|
||||
const query = getUnknownTypesQuery(knownTypes);
|
||||
|
||||
await esClient.asInternalUser.deleteByQuery({
|
||||
index: targetIndices,
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query,
|
||||
},
|
||||
});
|
||||
};
|
937
src/core/server/saved_objects/migrationsv2/__snapshots__/migrations_state_action_machine.test.ts.snap
generated
Normal file
937
src/core/server/saved_objects/migrationsv2/__snapshots__/migrations_state_action_machine.test.ts.snap
generated
Normal file
|
@ -0,0 +1,937 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`migrationsStateActionMachine logs state transitions, messages in state.logs and action responses when reaching DONE 1`] = `
|
||||
Object {
|
||||
"debug": Array [
|
||||
Array [
|
||||
"[.my-so-index] INIT RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] INIT -> LEGACY_REINDEX. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "LEGACY_REINDEX",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_REINDEX control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_REINDEX RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_REINDEX -> LEGACY_DELETE. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "LEGACY_DELETE",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_REINDEX control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> LEGACY_DELETE. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "LEGACY_DELETE",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_REINDEX control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> DONE. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "DONE",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_REINDEX control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from DONE control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
"error": Array [],
|
||||
"fatal": Array [],
|
||||
"info": Array [
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_REINDEX control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] INIT -> LEGACY_REINDEX. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_DELETE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_REINDEX -> LEGACY_DELETE. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_DELETE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> LEGACY_DELETE. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from DONE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> DONE. took: 0ms.",
|
||||
],
|
||||
],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`migrationsStateActionMachine logs state transitions, messages in state.logs and action responses when reaching FATAL 1`] = `
|
||||
Object {
|
||||
"debug": Array [
|
||||
Array [
|
||||
"[.my-so-index] INIT RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] INIT -> LEGACY_DELETE. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "LEGACY_DELETE",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [
|
||||
Object {
|
||||
"_id": "1234",
|
||||
},
|
||||
],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"reason": "the fatal reason",
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [
|
||||
Array [
|
||||
Object {
|
||||
"_id": "1234",
|
||||
},
|
||||
],
|
||||
],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> FATAL. took: 0ms.",
|
||||
Object {
|
||||
"kibana": Object {
|
||||
"migrations": Object {
|
||||
"duration": 0,
|
||||
"state": Object {
|
||||
"batchSize": 1000,
|
||||
"controlState": "FATAL",
|
||||
"currentAlias": ".my-so-index",
|
||||
"excludeFromUpgradeFilterHooks": Object {},
|
||||
"indexPrefix": ".my-so-index",
|
||||
"kibanaVersion": "7.11.0",
|
||||
"knownTypes": Array [],
|
||||
"legacyIndex": ".my-so-index",
|
||||
"logs": Array [
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from LEGACY_DELETE control state",
|
||||
},
|
||||
Object {
|
||||
"level": "info",
|
||||
"message": "Log from FATAL control state",
|
||||
},
|
||||
],
|
||||
"maxBatchSizeBytes": 100000000,
|
||||
"outdatedDocuments": Array [
|
||||
Object {
|
||||
"_id": "1234",
|
||||
},
|
||||
],
|
||||
"outdatedDocumentsQuery": Object {
|
||||
"bool": Object {
|
||||
"should": Array [],
|
||||
},
|
||||
},
|
||||
"preMigrationScript": Object {
|
||||
"_tag": "None",
|
||||
},
|
||||
"reason": "the fatal reason",
|
||||
"retryAttempts": 5,
|
||||
"retryCount": 0,
|
||||
"retryDelay": 0,
|
||||
"targetIndexMappings": Object {
|
||||
"properties": Object {},
|
||||
},
|
||||
"tempIndex": ".my-so-index_7.11.0_reindex_temp",
|
||||
"tempIndexMappings": Object {
|
||||
"dynamic": false,
|
||||
"properties": Object {
|
||||
"migrationVersion": Object {
|
||||
"dynamic": "true",
|
||||
"type": "object",
|
||||
},
|
||||
"type": Object {
|
||||
"type": "keyword",
|
||||
},
|
||||
},
|
||||
},
|
||||
"transformedDocBatches": Array [
|
||||
Array [
|
||||
Object {
|
||||
"_id": "1234",
|
||||
},
|
||||
],
|
||||
],
|
||||
"unusedTypesQuery": Object {
|
||||
"bool": Object {
|
||||
"must_not": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "apm-services-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "background-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "cases-sub-case",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "file-upload-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "fleet-agent-events",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "ml-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "osquery-usage-metric",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "server",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "timelion-sheet",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"type": "tsvb-validation-telemetry",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"bool": Object {
|
||||
"must": Array [
|
||||
Object {
|
||||
"match": Object {
|
||||
"type": "search-session",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"match": Object {
|
||||
"search-session.persisted": false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"versionAlias": ".my-so-index_7.11.0",
|
||||
"versionIndex": ".my-so-index_7.11.0_001",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
"error": Array [],
|
||||
"fatal": Array [],
|
||||
"info": Array [
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_DELETE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] INIT -> LEGACY_DELETE. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from FATAL control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> FATAL. took: 0ms.",
|
||||
],
|
||||
],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [],
|
||||
}
|
||||
`;
|
|
@ -44,6 +44,7 @@ function createRoot() {
|
|||
{
|
||||
name: 'root',
|
||||
appenders: ['file'],
|
||||
level: 'debug', // DEBUG logs are required to retrieve the PIT _id from the action response logs
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
*/
|
||||
|
||||
import Path from 'path';
|
||||
import Fs from 'fs';
|
||||
import Util from 'util';
|
||||
import glob from 'glob';
|
||||
import del from 'del';
|
||||
import { kibanaServerTestUser } from '@kbn/test';
|
||||
import { kibanaPackageJson as pkg } from '@kbn/utils';
|
||||
import * as kbnTestServer from '../../../../test_helpers/kbn_server';
|
||||
|
@ -18,15 +16,8 @@ import { Root } from '../../../root';
|
|||
|
||||
const LOG_FILE_PREFIX = 'migration_test_multiple_es_nodes';
|
||||
|
||||
const asyncUnlink = Util.promisify(Fs.unlink);
|
||||
|
||||
async function removeLogFile() {
|
||||
glob(Path.join(__dirname, `${LOG_FILE_PREFIX}_*.log`), (err, files) => {
|
||||
files.forEach(async (file) => {
|
||||
// ignore errors if it doesn't exist
|
||||
await asyncUnlink(file).catch(() => void 0);
|
||||
});
|
||||
});
|
||||
await del([Path.join(__dirname, `${LOG_FILE_PREFIX}_*.log`)], { force: true });
|
||||
}
|
||||
|
||||
function extractSortNumberFromId(id: string): number {
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
*/
|
||||
|
||||
import Path from 'path';
|
||||
import Fs from 'fs';
|
||||
import Util from 'util';
|
||||
import glob from 'glob';
|
||||
import del from 'del';
|
||||
import { esTestConfig, kibanaServerTestUser } from '@kbn/test';
|
||||
import { kibanaPackageJson as pkg } from '@kbn/utils';
|
||||
import * as kbnTestServer from '../../../../test_helpers/kbn_server';
|
||||
|
@ -19,15 +17,8 @@ import type { Root } from '../../../root';
|
|||
|
||||
const LOG_FILE_PREFIX = 'migration_test_multiple_kibana_nodes';
|
||||
|
||||
const asyncUnlink = Util.promisify(Fs.unlink);
|
||||
|
||||
async function removeLogFiles() {
|
||||
glob(Path.join(__dirname, `${LOG_FILE_PREFIX}_*.log`), (err, files) => {
|
||||
files.forEach(async (file) => {
|
||||
// ignore errors if it doesn't exist
|
||||
await asyncUnlink(file).catch(() => void 0);
|
||||
});
|
||||
});
|
||||
await del([Path.join(__dirname, `${LOG_FILE_PREFIX}_*.log`)], { force: true });
|
||||
}
|
||||
|
||||
function extractSortNumberFromId(id: string): number {
|
||||
|
|
|
@ -77,7 +77,7 @@ describe('migrationsStateActionMachine', () => {
|
|||
};
|
||||
};
|
||||
|
||||
it('logs state transitions, messages in state.logs and action responses', async () => {
|
||||
it('logs state transitions, messages in state.logs and action responses when reaching DONE', async () => {
|
||||
await migrationStateActionMachine({
|
||||
initialState,
|
||||
logger: mockLogger.get(),
|
||||
|
@ -88,71 +88,23 @@ describe('migrationsStateActionMachine', () => {
|
|||
const logs = loggingSystemMock.collect(mockLogger);
|
||||
const doneLog = logs.info.splice(8, 1)[0][0];
|
||||
expect(doneLog).toMatch(/\[.my-so-index\] Migration completed after \d+ms/);
|
||||
expect(logs).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"debug": Array [
|
||||
Array [
|
||||
"[.my-so-index] INIT RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_REINDEX RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE RESPONSE",
|
||||
Object {
|
||||
"_tag": "Right",
|
||||
"right": "response",
|
||||
},
|
||||
],
|
||||
],
|
||||
"error": Array [],
|
||||
"fatal": Array [],
|
||||
"info": Array [
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_REINDEX control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] INIT -> LEGACY_REINDEX. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_DELETE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_REINDEX -> LEGACY_DELETE. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from LEGACY_DELETE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> LEGACY_DELETE. took: 0ms.",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] Log from DONE control state",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] LEGACY_DELETE -> DONE. took: 0ms.",
|
||||
],
|
||||
],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [],
|
||||
}
|
||||
`);
|
||||
expect(logs).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('logs state transitions, messages in state.logs and action responses when reaching FATAL', async () => {
|
||||
await migrationStateActionMachine({
|
||||
initialState: {
|
||||
...initialState,
|
||||
reason: 'the fatal reason',
|
||||
outdatedDocuments: [{ _id: '1234', password: 'sensitive password' }],
|
||||
transformedDocBatches: [[{ _id: '1234', password: 'sensitive transformed password' }]],
|
||||
} as State,
|
||||
logger: mockLogger.get(),
|
||||
model: transitionModel(['LEGACY_DELETE', 'FATAL']),
|
||||
next,
|
||||
client: esClient,
|
||||
}).catch((err) => err);
|
||||
expect(loggingSystemMock.collect(mockLogger)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// see https://github.com/elastic/kibana/issues/98406
|
||||
|
@ -196,6 +148,7 @@ describe('migrationsStateActionMachine', () => {
|
|||
})
|
||||
).resolves.toEqual(expect.anything());
|
||||
});
|
||||
|
||||
it('resolves with migrated status if some sourceIndex in the DONE state', async () => {
|
||||
await expect(
|
||||
migrationStateActionMachine({
|
||||
|
@ -207,6 +160,7 @@ describe('migrationsStateActionMachine', () => {
|
|||
})
|
||||
).resolves.toEqual(expect.objectContaining({ status: 'migrated' }));
|
||||
});
|
||||
|
||||
it('resolves with patched status if none sourceIndex in the DONE state', async () => {
|
||||
await expect(
|
||||
migrationStateActionMachine({
|
||||
|
@ -218,6 +172,7 @@ describe('migrationsStateActionMachine', () => {
|
|||
})
|
||||
).resolves.toEqual(expect.objectContaining({ status: 'patched' }));
|
||||
});
|
||||
|
||||
it('rejects with error message when reaching the FATAL state', async () => {
|
||||
await expect(
|
||||
migrationStateActionMachine({
|
||||
|
@ -231,127 +186,8 @@ describe('migrationsStateActionMachine', () => {
|
|||
`[Error: Unable to complete saved object migrations for the [.my-so-index] index: the fatal reason]`
|
||||
);
|
||||
});
|
||||
it('logs all state transitions and action responses when reaching the FATAL state', async () => {
|
||||
await migrationStateActionMachine({
|
||||
initialState: {
|
||||
...initialState,
|
||||
reason: 'the fatal reason',
|
||||
outdatedDocuments: [{ _id: '1234', password: 'sensitive password' }],
|
||||
transformedDocBatches: [[{ _id: '1234', password: 'sensitive transformed password' }]],
|
||||
} as State,
|
||||
logger: mockLogger.get(),
|
||||
model: transitionModel(['LEGACY_DELETE', 'FATAL']),
|
||||
next,
|
||||
client: esClient,
|
||||
}).catch((err) => err);
|
||||
// Ignore the first 4 log entries that come from our model
|
||||
const executionLogLogs = loggingSystemMock.collect(mockLogger).info.slice(4);
|
||||
expect(executionLogLogs).toEqual([
|
||||
[
|
||||
'[.my-so-index] INIT RESPONSE',
|
||||
{
|
||||
_tag: 'Right',
|
||||
right: 'response',
|
||||
},
|
||||
],
|
||||
[
|
||||
'[.my-so-index] INIT -> LEGACY_DELETE',
|
||||
{
|
||||
kibana: {
|
||||
migrationState: {
|
||||
batchSize: 1000,
|
||||
maxBatchSizeBytes: 1e8,
|
||||
controlState: 'LEGACY_DELETE',
|
||||
currentAlias: '.my-so-index',
|
||||
excludeFromUpgradeFilterHooks: {},
|
||||
indexPrefix: '.my-so-index',
|
||||
kibanaVersion: '7.11.0',
|
||||
knownTypes: [],
|
||||
legacyIndex: '.my-so-index',
|
||||
logs: [
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from LEGACY_DELETE control state',
|
||||
},
|
||||
],
|
||||
outdatedDocuments: [{ _id: '1234' }],
|
||||
outdatedDocumentsQuery: expect.any(Object),
|
||||
preMigrationScript: {
|
||||
_tag: 'None',
|
||||
},
|
||||
reason: 'the fatal reason',
|
||||
retryAttempts: 5,
|
||||
retryCount: 0,
|
||||
retryDelay: 0,
|
||||
targetIndexMappings: {
|
||||
properties: {},
|
||||
},
|
||||
tempIndex: '.my-so-index_7.11.0_reindex_temp',
|
||||
tempIndexMappings: expect.any(Object),
|
||||
transformedDocBatches: [[{ _id: '1234' }]],
|
||||
unusedTypesQuery: expect.any(Object),
|
||||
versionAlias: '.my-so-index_7.11.0',
|
||||
versionIndex: '.my-so-index_7.11.0_001',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'[.my-so-index] LEGACY_DELETE RESPONSE',
|
||||
{
|
||||
_tag: 'Right',
|
||||
right: 'response',
|
||||
},
|
||||
],
|
||||
[
|
||||
'[.my-so-index] LEGACY_DELETE -> FATAL',
|
||||
{
|
||||
kibana: {
|
||||
migrationState: {
|
||||
batchSize: 1000,
|
||||
maxBatchSizeBytes: 1e8,
|
||||
controlState: 'FATAL',
|
||||
currentAlias: '.my-so-index',
|
||||
excludeFromUpgradeFilterHooks: {},
|
||||
indexPrefix: '.my-so-index',
|
||||
kibanaVersion: '7.11.0',
|
||||
knownTypes: [],
|
||||
legacyIndex: '.my-so-index',
|
||||
logs: [
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from LEGACY_DELETE control state',
|
||||
},
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from FATAL control state',
|
||||
},
|
||||
],
|
||||
outdatedDocuments: [{ _id: '1234' }],
|
||||
outdatedDocumentsQuery: expect.any(Object),
|
||||
preMigrationScript: {
|
||||
_tag: 'None',
|
||||
},
|
||||
reason: 'the fatal reason',
|
||||
retryAttempts: 5,
|
||||
retryCount: 0,
|
||||
retryDelay: 0,
|
||||
targetIndexMappings: {
|
||||
properties: {},
|
||||
},
|
||||
tempIndex: '.my-so-index_7.11.0_reindex_temp',
|
||||
tempIndexMappings: expect.any(Object),
|
||||
transformedDocBatches: [[{ _id: '1234' }]],
|
||||
unusedTypesQuery: expect.any(Object),
|
||||
versionAlias: '.my-so-index_7.11.0',
|
||||
versionIndex: '.my-so-index_7.11.0_001',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
it('rejects and logs the error when an action throws with an ResponseError', async () => {
|
||||
|
||||
it('rejects and logs the error when an action throws with a ResponseError', async () => {
|
||||
await expect(
|
||||
migrationStateActionMachine({
|
||||
initialState: { ...initialState, reason: 'the fatal reason' } as State,
|
||||
|
@ -384,9 +220,6 @@ describe('migrationsStateActionMachine', () => {
|
|||
Array [
|
||||
"[.my-so-index] Unexpected Elasticsearch ResponseError: statusCode: 200, method: POST, url: /mock error: [snapshot_in_progress_exception]: Cannot delete indices that are being snapshotted,",
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] migration failed, dumping execution log:",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
|
@ -417,9 +250,6 @@ describe('migrationsStateActionMachine', () => {
|
|||
Array [
|
||||
[Error: this action throws],
|
||||
],
|
||||
Array [
|
||||
"[.my-so-index] migration failed, dumping execution log:",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
|
@ -429,116 +259,6 @@ describe('migrationsStateActionMachine', () => {
|
|||
}
|
||||
`);
|
||||
});
|
||||
it('logs all state transitions and action responses when an action throws', async () => {
|
||||
try {
|
||||
await migrationStateActionMachine({
|
||||
initialState: { ...initialState, reason: 'the fatal reason' } as State,
|
||||
logger: mockLogger.get(),
|
||||
model: transitionModel(['LEGACY_REINDEX', 'LEGACY_DELETE', 'FATAL']),
|
||||
next: (state) => {
|
||||
if (state.controlState === 'LEGACY_DELETE') throw new Error('this action throws');
|
||||
return () => Promise.resolve('hello');
|
||||
},
|
||||
client: esClient,
|
||||
});
|
||||
} catch (e) {
|
||||
/** ignore */
|
||||
}
|
||||
// Ignore the first 4 log entries that come from our model
|
||||
const executionLogLogs = loggingSystemMock.collect(mockLogger).info.slice(4);
|
||||
expect(executionLogLogs).toEqual([
|
||||
['[.my-so-index] INIT RESPONSE', 'hello'],
|
||||
[
|
||||
'[.my-so-index] INIT -> LEGACY_REINDEX',
|
||||
{
|
||||
kibana: {
|
||||
migrationState: {
|
||||
batchSize: 1000,
|
||||
maxBatchSizeBytes: 1e8,
|
||||
controlState: 'LEGACY_REINDEX',
|
||||
currentAlias: '.my-so-index',
|
||||
excludeFromUpgradeFilterHooks: {},
|
||||
indexPrefix: '.my-so-index',
|
||||
kibanaVersion: '7.11.0',
|
||||
knownTypes: [],
|
||||
legacyIndex: '.my-so-index',
|
||||
logs: [
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from LEGACY_REINDEX control state',
|
||||
},
|
||||
],
|
||||
outdatedDocuments: [],
|
||||
outdatedDocumentsQuery: expect.any(Object),
|
||||
preMigrationScript: {
|
||||
_tag: 'None',
|
||||
},
|
||||
reason: 'the fatal reason',
|
||||
retryAttempts: 5,
|
||||
retryCount: 0,
|
||||
retryDelay: 0,
|
||||
targetIndexMappings: {
|
||||
properties: {},
|
||||
},
|
||||
tempIndex: '.my-so-index_7.11.0_reindex_temp',
|
||||
tempIndexMappings: expect.any(Object),
|
||||
transformedDocBatches: [],
|
||||
unusedTypesQuery: expect.any(Object),
|
||||
versionAlias: '.my-so-index_7.11.0',
|
||||
versionIndex: '.my-so-index_7.11.0_001',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
['[.my-so-index] LEGACY_REINDEX RESPONSE', 'hello'],
|
||||
[
|
||||
'[.my-so-index] LEGACY_REINDEX -> LEGACY_DELETE',
|
||||
{
|
||||
kibana: {
|
||||
migrationState: {
|
||||
batchSize: 1000,
|
||||
maxBatchSizeBytes: 1e8,
|
||||
controlState: 'LEGACY_DELETE',
|
||||
currentAlias: '.my-so-index',
|
||||
excludeFromUpgradeFilterHooks: {},
|
||||
indexPrefix: '.my-so-index',
|
||||
kibanaVersion: '7.11.0',
|
||||
knownTypes: [],
|
||||
legacyIndex: '.my-so-index',
|
||||
logs: [
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from LEGACY_REINDEX control state',
|
||||
},
|
||||
{
|
||||
level: 'info',
|
||||
message: 'Log from LEGACY_DELETE control state',
|
||||
},
|
||||
],
|
||||
outdatedDocuments: [],
|
||||
outdatedDocumentsQuery: expect.any(Object),
|
||||
preMigrationScript: {
|
||||
_tag: 'None',
|
||||
},
|
||||
reason: 'the fatal reason',
|
||||
retryAttempts: 5,
|
||||
retryCount: 0,
|
||||
retryDelay: 0,
|
||||
targetIndexMappings: {
|
||||
properties: {},
|
||||
},
|
||||
tempIndex: '.my-so-index_7.11.0_reindex_temp',
|
||||
tempIndexMappings: expect.any(Object),
|
||||
transformedDocBatches: [],
|
||||
unusedTypesQuery: expect.any(Object),
|
||||
versionAlias: '.my-so-index_7.11.0',
|
||||
versionIndex: '.my-so-index_7.11.0_001',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
describe('cleanup', () => {
|
||||
beforeEach(() => {
|
||||
cleanupMock.mockClear();
|
||||
|
|
|
@ -16,41 +16,24 @@ import { cleanup } from './migrations_state_machine_cleanup';
|
|||
import { ReindexSourceToTempIndex, ReindexSourceToTempIndexBulk, State } from './types';
|
||||
import { SavedObjectsRawDoc } from '../serialization';
|
||||
|
||||
interface StateLogMeta extends LogMeta {
|
||||
interface StateTransitionLogMeta extends LogMeta {
|
||||
kibana: {
|
||||
migrationState: State;
|
||||
migrations: {
|
||||
state: State;
|
||||
duration: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type ExecutionLog = Array<
|
||||
| {
|
||||
type: 'transition';
|
||||
prevControlState: State['controlState'];
|
||||
controlState: State['controlState'];
|
||||
state: State;
|
||||
}
|
||||
| {
|
||||
type: 'response';
|
||||
controlState: State['controlState'];
|
||||
res: unknown;
|
||||
}
|
||||
| {
|
||||
type: 'cleanup';
|
||||
state: State;
|
||||
message: string;
|
||||
}
|
||||
>;
|
||||
|
||||
const logStateTransition = (
|
||||
logger: Logger,
|
||||
logMessagePrefix: string,
|
||||
oldState: State,
|
||||
newState: State,
|
||||
prevState: State,
|
||||
currState: State,
|
||||
tookMs: number
|
||||
) => {
|
||||
if (newState.logs.length > oldState.logs.length) {
|
||||
newState.logs.slice(oldState.logs.length).forEach(({ message, level }) => {
|
||||
if (currState.logs.length > prevState.logs.length) {
|
||||
currState.logs.slice(prevState.logs.length).forEach(({ message, level }) => {
|
||||
switch (level) {
|
||||
case 'error':
|
||||
return logger.error(logMessagePrefix + message);
|
||||
|
@ -65,7 +48,18 @@ const logStateTransition = (
|
|||
}
|
||||
|
||||
logger.info(
|
||||
logMessagePrefix + `${oldState.controlState} -> ${newState.controlState}. took: ${tookMs}ms.`
|
||||
logMessagePrefix + `${prevState.controlState} -> ${currState.controlState}. took: ${tookMs}ms.`
|
||||
);
|
||||
logger.debug<StateTransitionLogMeta>(
|
||||
logMessagePrefix + `${prevState.controlState} -> ${currState.controlState}. took: ${tookMs}ms.`,
|
||||
{
|
||||
kibana: {
|
||||
migrations: {
|
||||
state: currState,
|
||||
duration: tookMs,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -77,24 +71,6 @@ const logActionResponse = (
|
|||
) => {
|
||||
logger.debug(logMessagePrefix + `${state.controlState} RESPONSE`, res as LogMeta);
|
||||
};
|
||||
const dumpExecutionLog = (logger: Logger, logMessagePrefix: string, executionLog: ExecutionLog) => {
|
||||
logger.error(logMessagePrefix + 'migration failed, dumping execution log:');
|
||||
executionLog.forEach((log) => {
|
||||
if (log.type === 'transition') {
|
||||
logger.info<StateLogMeta>(
|
||||
logMessagePrefix + `${log.prevControlState} -> ${log.controlState}`,
|
||||
{
|
||||
kibana: {
|
||||
migrationState: log.state,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
if (log.type === 'response') {
|
||||
logger.info(logMessagePrefix + `${log.controlState} RESPONSE`, log.res as LogMeta);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* A specialized migrations-specific state-action machine that:
|
||||
|
@ -118,7 +94,6 @@ export async function migrationStateActionMachine({
|
|||
model: Model<State>;
|
||||
client: ElasticsearchClient;
|
||||
}) {
|
||||
const executionLog: ExecutionLog = [];
|
||||
const startTime = Date.now();
|
||||
// Since saved object index names usually start with a `.` and can be
|
||||
// configured by users to include several `.`'s we can't use a logger tag to
|
||||
|
@ -132,11 +107,6 @@ export async function migrationStateActionMachine({
|
|||
(state) => next(state),
|
||||
(state, res) => {
|
||||
lastState = state;
|
||||
executionLog.push({
|
||||
type: 'response',
|
||||
res,
|
||||
controlState: state.controlState,
|
||||
});
|
||||
logActionResponse(logger, logMessagePrefix, state, res);
|
||||
const newState = model(state, res);
|
||||
// Redact the state to reduce the memory consumption and so that we
|
||||
|
@ -158,12 +128,7 @@ export async function migrationStateActionMachine({
|
|||
).map((batches) => batches.map((doc) => ({ _id: doc._id }))) as [SavedObjectsRawDoc[]],
|
||||
},
|
||||
};
|
||||
executionLog.push({
|
||||
type: 'transition',
|
||||
state: redactedNewState,
|
||||
controlState: newState.controlState,
|
||||
prevControlState: state.controlState,
|
||||
});
|
||||
|
||||
const now = Date.now();
|
||||
logStateTransition(
|
||||
logger,
|
||||
|
@ -195,8 +160,11 @@ export async function migrationStateActionMachine({
|
|||
};
|
||||
}
|
||||
} else if (finalState.controlState === 'FATAL') {
|
||||
await cleanup(client, executionLog, finalState);
|
||||
dumpExecutionLog(logger, logMessagePrefix, executionLog);
|
||||
try {
|
||||
await cleanup(client, finalState);
|
||||
} catch (e) {
|
||||
logger.warn('Failed to cleanup after migrations:', e.message);
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
`Unable to complete saved object migrations for the [${initialState.indexPrefix}] index: ` +
|
||||
|
@ -207,7 +175,11 @@ export async function migrationStateActionMachine({
|
|||
throw new Error('Invalid terminating control state');
|
||||
}
|
||||
} catch (e) {
|
||||
await cleanup(client, executionLog, lastState);
|
||||
try {
|
||||
await cleanup(client, lastState);
|
||||
} catch (err) {
|
||||
logger.warn('Failed to cleanup after migrations:', err.message);
|
||||
}
|
||||
if (e instanceof EsErrors.ResponseError) {
|
||||
// Log the failed request. This is very similar to the
|
||||
// elasticsearch-service's debug logs, but we log everything in single
|
||||
|
@ -219,15 +191,12 @@ export async function migrationStateActionMachine({
|
|||
req.statusCode
|
||||
}, method: ${req.method}, url: ${req.url} error: ${getErrorMessage(e)},`;
|
||||
logger.error(logMessagePrefix + failedRequestMessage);
|
||||
dumpExecutionLog(logger, logMessagePrefix, executionLog);
|
||||
throw new Error(
|
||||
`Unable to complete saved object migrations for the [${initialState.indexPrefix}] index. Please check the health of your Elasticsearch cluster and try again. ${failedRequestMessage}`
|
||||
);
|
||||
} else {
|
||||
logger.error(e);
|
||||
|
||||
dumpExecutionLog(logger, logMessagePrefix, executionLog);
|
||||
|
||||
const newError = new Error(
|
||||
`Unable to complete saved object migrations for the [${initialState.indexPrefix}] index. ${e}`
|
||||
);
|
||||
|
|
|
@ -9,23 +9,10 @@
|
|||
import type { ElasticsearchClient } from '../../elasticsearch';
|
||||
import * as Actions from './actions';
|
||||
import type { State } from './types';
|
||||
import type { ExecutionLog } from './migrations_state_action_machine';
|
||||
|
||||
export async function cleanup(
|
||||
client: ElasticsearchClient,
|
||||
executionLog: ExecutionLog,
|
||||
state?: State
|
||||
) {
|
||||
export async function cleanup(client: ElasticsearchClient, state?: State) {
|
||||
if (!state) return;
|
||||
if ('sourceIndexPitId' in state) {
|
||||
try {
|
||||
await Actions.closePit({ client, pitId: state.sourceIndexPitId })();
|
||||
} catch (e) {
|
||||
executionLog.push({
|
||||
type: 'cleanup',
|
||||
state,
|
||||
message: e.message,
|
||||
});
|
||||
}
|
||||
await Actions.closePit({ client, pitId: state.sourceIndexPitId })();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { IRouter } from '../../../http';
|
||||
import { catchAndReturnBoomErrors } from '../utils';
|
||||
import { deleteUnknownTypeObjects } from '../../deprecations';
|
||||
import { SavedObjectConfig } from '../../saved_objects_config';
|
||||
import { KibanaConfigType } from '../../../kibana_config';
|
||||
|
||||
interface RouteDependencies {
|
||||
config: SavedObjectConfig;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
kibanaVersion: string;
|
||||
}
|
||||
|
||||
export const registerDeleteUnknownTypesRoute = (
|
||||
router: IRouter,
|
||||
{ config, kibanaConfig, kibanaVersion }: RouteDependencies
|
||||
) => {
|
||||
router.post(
|
||||
{
|
||||
path: '/deprecations/_delete_unknown_types',
|
||||
validate: false,
|
||||
},
|
||||
catchAndReturnBoomErrors(async (context, req, res) => {
|
||||
await deleteUnknownTypeObjects({
|
||||
esClient: context.core.elasticsearch.client,
|
||||
typeRegistry: context.core.savedObjects.typeRegistry,
|
||||
savedObjectsConfig: config,
|
||||
kibanaConfig,
|
||||
kibanaVersion,
|
||||
});
|
||||
return res.ok({
|
||||
body: {
|
||||
success: true,
|
||||
},
|
||||
});
|
||||
})
|
||||
);
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { registerDeleteUnknownTypesRoute } from './delete_unknown_types';
|
|
@ -26,6 +26,8 @@ import { registerResolveImportErrorsRoute } from './resolve_import_errors';
|
|||
import { registerMigrateRoute } from './migrate';
|
||||
import { registerLegacyImportRoute } from './legacy_import_export/import';
|
||||
import { registerLegacyExportRoute } from './legacy_import_export/export';
|
||||
import { registerDeleteUnknownTypesRoute } from './deprecations';
|
||||
import { KibanaConfigType } from '../../kibana_config';
|
||||
|
||||
export function registerRoutes({
|
||||
http,
|
||||
|
@ -34,6 +36,7 @@ export function registerRoutes({
|
|||
config,
|
||||
migratorPromise,
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
}: {
|
||||
http: InternalHttpServiceSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
|
@ -41,6 +44,7 @@ export function registerRoutes({
|
|||
config: SavedObjectConfig;
|
||||
migratorPromise: Promise<IKibanaMigrator>;
|
||||
kibanaVersion: string;
|
||||
kibanaConfig: KibanaConfigType;
|
||||
}) {
|
||||
const router = http.createRouter('/api/saved_objects/');
|
||||
|
||||
|
@ -68,4 +72,5 @@ export function registerRoutes({
|
|||
const internalRouter = http.createRouter('/internal/saved_objects/');
|
||||
|
||||
registerMigrateRoute(internalRouter, migratorPromise);
|
||||
registerDeleteUnknownTypesRoute(internalRouter, { config, kibanaConfig, kibanaVersion });
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import supertest from 'supertest';
|
||||
import { UnwrapPromise } from '@kbn/utility-types';
|
||||
import { registerDeleteUnknownTypesRoute } from '../deprecations';
|
||||
import { elasticsearchServiceMock } from '../../../../../core/server/elasticsearch/elasticsearch_service.mock';
|
||||
import { typeRegistryMock } from '../../saved_objects_type_registry.mock';
|
||||
import { setupServer } from '../test_utils';
|
||||
import { KibanaConfigType } from '../../../kibana_config';
|
||||
import { SavedObjectConfig } from '../../saved_objects_config';
|
||||
import { SavedObjectsType } from 'kibana/server';
|
||||
|
||||
type SetupServerReturn = UnwrapPromise<ReturnType<typeof setupServer>>;
|
||||
|
||||
describe('POST /internal/saved_objects/deprecations/_delete_unknown_types', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
const kibanaConfig: KibanaConfigType = {
|
||||
enabled: true,
|
||||
index: '.kibana',
|
||||
};
|
||||
const config: SavedObjectConfig = {
|
||||
maxImportExportSize: 10000,
|
||||
maxImportPayloadBytes: 24000000,
|
||||
migration: {
|
||||
enableV2: true,
|
||||
} as SavedObjectConfig['migration'],
|
||||
};
|
||||
|
||||
let server: SetupServerReturn['server'];
|
||||
let httpSetup: SetupServerReturn['httpSetup'];
|
||||
let handlerContext: SetupServerReturn['handlerContext'];
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
let elasticsearchClient: ReturnType<typeof elasticsearchServiceMock.createScopedClusterClient>;
|
||||
|
||||
beforeEach(async () => {
|
||||
({ server, httpSetup, handlerContext } = await setupServer());
|
||||
elasticsearchClient = elasticsearchServiceMock.createScopedClusterClient();
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
|
||||
typeRegistry.getAllTypes.mockReturnValue([{ name: 'known-type' } as SavedObjectsType]);
|
||||
typeRegistry.getIndex.mockImplementation((type) => `${type}-index`);
|
||||
|
||||
handlerContext.savedObjects.typeRegistry = typeRegistry;
|
||||
handlerContext.elasticsearch.client.asCurrentUser = elasticsearchClient.asCurrentUser;
|
||||
handlerContext.elasticsearch.client.asInternalUser = elasticsearchClient.asInternalUser;
|
||||
|
||||
const router = httpSetup.createRouter('/internal/saved_objects/');
|
||||
registerDeleteUnknownTypesRoute(router, {
|
||||
kibanaVersion,
|
||||
kibanaConfig,
|
||||
config,
|
||||
});
|
||||
|
||||
await server.start();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await server.stop();
|
||||
});
|
||||
|
||||
it('formats successful response', async () => {
|
||||
const result = await supertest(httpSetup.server.listener)
|
||||
.post('/internal/saved_objects/deprecations/_delete_unknown_types')
|
||||
.expect(200);
|
||||
|
||||
expect(result.body).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('calls upon esClient.deleteByQuery', async () => {
|
||||
await supertest(httpSetup.server.listener)
|
||||
.post('/internal/saved_objects/deprecations/_delete_unknown_types')
|
||||
.expect(200);
|
||||
|
||||
expect(elasticsearchClient.asInternalUser.deleteByQuery).toHaveBeenCalledTimes(1);
|
||||
expect(elasticsearchClient.asInternalUser.deleteByQuery).toHaveBeenCalledWith({
|
||||
index: ['known-type-index_8.0.0'],
|
||||
wait_for_completion: false,
|
||||
body: {
|
||||
query: {
|
||||
bool: {
|
||||
must_not: expect.any(Array),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
|
@ -20,17 +20,26 @@ import { Env } from '../config';
|
|||
import { configServiceMock } from '../mocks';
|
||||
import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock';
|
||||
import { coreUsageDataServiceMock } from '../core_usage_data/core_usage_data_service.mock';
|
||||
import { deprecationsServiceMock } from '../deprecations/deprecations_service.mock';
|
||||
import { httpServiceMock } from '../http/http_service.mock';
|
||||
import { httpServerMock } from '../http/http_server.mocks';
|
||||
import { SavedObjectsClientFactoryProvider } from './service/lib';
|
||||
import { NodesVersionCompatibility } from '../elasticsearch/version_check/ensure_es_version';
|
||||
import { SavedObjectsRepository } from './service/lib/repository';
|
||||
import { registerCoreObjectTypes } from './object_types';
|
||||
import { getSavedObjectsDeprecationsProvider } from './deprecations';
|
||||
|
||||
jest.mock('./service/lib/repository');
|
||||
jest.mock('./object_types');
|
||||
jest.mock('./deprecations');
|
||||
|
||||
describe('SavedObjectsService', () => {
|
||||
let deprecationsSetup: ReturnType<typeof deprecationsServiceMock.createInternalSetupContract>;
|
||||
|
||||
beforeEach(() => {
|
||||
deprecationsSetup = deprecationsServiceMock.createInternalSetupContract();
|
||||
});
|
||||
|
||||
const createCoreContext = ({
|
||||
skipMigration = true,
|
||||
env,
|
||||
|
@ -53,6 +62,7 @@ describe('SavedObjectsService', () => {
|
|||
return {
|
||||
http: httpServiceMock.createInternalSetupContract(),
|
||||
elasticsearch: elasticsearchMock,
|
||||
deprecations: deprecationsSetup,
|
||||
coreUsageData: coreUsageDataServiceMock.createSetupContract(),
|
||||
};
|
||||
};
|
||||
|
@ -79,6 +89,24 @@ describe('SavedObjectsService', () => {
|
|||
expect(mockedRegisterCoreObjectTypes).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('register the deprecation provider', async () => {
|
||||
const coreContext = createCoreContext();
|
||||
const soService = new SavedObjectsService(coreContext);
|
||||
|
||||
const mockRegistry = deprecationsServiceMock.createSetupContract();
|
||||
deprecationsSetup.getRegistry.mockReturnValue(mockRegistry);
|
||||
|
||||
const deprecations = Symbol('deprecations');
|
||||
const mockedGetSavedObjectsDeprecationsProvider = getSavedObjectsDeprecationsProvider as jest.Mock;
|
||||
mockedGetSavedObjectsDeprecationsProvider.mockReturnValue(deprecations);
|
||||
await soService.setup(createSetupDeps());
|
||||
|
||||
expect(deprecationsSetup.getRegistry).toHaveBeenCalledTimes(1);
|
||||
expect(deprecationsSetup.getRegistry).toHaveBeenCalledWith('savedObjects');
|
||||
expect(mockRegistry.registerDeprecations).toHaveBeenCalledTimes(1);
|
||||
expect(mockRegistry.registerDeprecations).toHaveBeenCalledWith(deprecations);
|
||||
});
|
||||
|
||||
describe('#setClientFactoryProvider', () => {
|
||||
it('registers the factory to the clientProvider', async () => {
|
||||
const coreContext = createCoreContext();
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
InternalElasticsearchServiceSetup,
|
||||
InternalElasticsearchServiceStart,
|
||||
} from '../elasticsearch';
|
||||
import { InternalDeprecationsServiceSetup } from '../deprecations';
|
||||
import { KibanaConfigType } from '../kibana_config';
|
||||
import {
|
||||
SavedObjectsConfigType,
|
||||
|
@ -44,6 +45,7 @@ import { registerRoutes } from './routes';
|
|||
import { ServiceStatus } from '../status';
|
||||
import { calculateStatus$ } from './status';
|
||||
import { registerCoreObjectTypes } from './object_types';
|
||||
import { getSavedObjectsDeprecationsProvider } from './deprecations';
|
||||
|
||||
/**
|
||||
* Saved Objects is Kibana's data persistence mechanism allowing plugins to
|
||||
|
@ -251,6 +253,7 @@ export interface SavedObjectsSetupDeps {
|
|||
http: InternalHttpServiceSetup;
|
||||
elasticsearch: InternalElasticsearchServiceSetup;
|
||||
coreUsageData: InternalCoreUsageDataSetup;
|
||||
deprecations: InternalDeprecationsServiceSetup;
|
||||
}
|
||||
|
||||
interface WrappedClientFactoryWrapper {
|
||||
|
@ -286,7 +289,7 @@ export class SavedObjectsService
|
|||
this.logger.debug('Setting up SavedObjects service');
|
||||
|
||||
this.setupDeps = setupDeps;
|
||||
const { http, elasticsearch, coreUsageData } = setupDeps;
|
||||
const { http, elasticsearch, coreUsageData, deprecations } = setupDeps;
|
||||
|
||||
const savedObjectsConfig = await this.coreContext.configService
|
||||
.atPath<SavedObjectsConfigType>('savedObjects')
|
||||
|
@ -298,6 +301,20 @@ export class SavedObjectsService
|
|||
.toPromise();
|
||||
this.config = new SavedObjectConfig(savedObjectsConfig, savedObjectsMigrationConfig);
|
||||
|
||||
const kibanaConfig = await this.coreContext.configService
|
||||
.atPath<KibanaConfigType>('kibana')
|
||||
.pipe(first())
|
||||
.toPromise();
|
||||
|
||||
deprecations.getRegistry('savedObjects').registerDeprecations(
|
||||
getSavedObjectsDeprecationsProvider({
|
||||
kibanaConfig,
|
||||
savedObjectsConfig: this.config,
|
||||
kibanaVersion: this.coreContext.env.packageInfo.version,
|
||||
typeRegistry: this.typeRegistry,
|
||||
})
|
||||
);
|
||||
|
||||
coreUsageData.registerType(this.typeRegistry);
|
||||
|
||||
registerRoutes({
|
||||
|
@ -306,6 +323,7 @@ export class SavedObjectsService
|
|||
logger: this.logger,
|
||||
config: this.config,
|
||||
migratorPromise: this.migrator$.pipe(first()).toPromise(),
|
||||
kibanaConfig,
|
||||
kibanaVersion: this.coreContext.env.packageInfo.version,
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { getIndexForType } from './get_index_for_type';
|
||||
import { typeRegistryMock } from '../../saved_objects_type_registry.mock';
|
||||
|
||||
describe('getIndexForType', () => {
|
||||
const kibanaVersion = '8.0.0';
|
||||
const defaultIndex = '.kibana';
|
||||
let typeRegistry: ReturnType<typeof typeRegistryMock.create>;
|
||||
|
||||
beforeEach(() => {
|
||||
typeRegistry = typeRegistryMock.create();
|
||||
});
|
||||
|
||||
describe('when migV2 is enabled', () => {
|
||||
const migV2Enabled = true;
|
||||
|
||||
it('returns the correct index for a type specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => `.${type}-index`);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.foo-index_8.0.0');
|
||||
});
|
||||
|
||||
it('returns the correct index for a type not specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => undefined);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.kibana_8.0.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when migV2 is disabled', () => {
|
||||
const migV2Enabled = false;
|
||||
|
||||
it('returns the correct index for a type specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => `.${type}-index`);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.foo-index');
|
||||
});
|
||||
|
||||
it('returns the correct index for a type not specifying a custom index', () => {
|
||||
typeRegistry.getIndex.mockImplementation((type) => undefined);
|
||||
expect(
|
||||
getIndexForType({
|
||||
type: 'foo',
|
||||
typeRegistry,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
migV2Enabled,
|
||||
})
|
||||
).toEqual('.kibana');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ISavedObjectTypeRegistry } from '../../saved_objects_type_registry';
|
||||
|
||||
interface GetIndexForTypeOptions {
|
||||
type: string;
|
||||
typeRegistry: ISavedObjectTypeRegistry;
|
||||
migV2Enabled: boolean;
|
||||
kibanaVersion: string;
|
||||
defaultIndex: string;
|
||||
}
|
||||
|
||||
export const getIndexForType = ({
|
||||
type,
|
||||
typeRegistry,
|
||||
migV2Enabled,
|
||||
defaultIndex,
|
||||
kibanaVersion,
|
||||
}: GetIndexForTypeOptions): string => {
|
||||
// TODO migrationsV2: Remove once we remove migrations v1
|
||||
// This is a hacky, but it required the least amount of changes to
|
||||
// existing code to support a migrations v2 index. Long term we would
|
||||
// want to always use the type registry to resolve a type's index
|
||||
// (including the default index).
|
||||
if (migV2Enabled) {
|
||||
return `${typeRegistry.getIndex(type) || defaultIndex}_${kibanaVersion}`;
|
||||
} else {
|
||||
return typeRegistry.getIndex(type) || defaultIndex;
|
||||
}
|
||||
};
|
|
@ -41,3 +41,5 @@ export type {
|
|||
SavedObjectsUpdateObjectsSpacesResponse,
|
||||
SavedObjectsUpdateObjectsSpacesResponseObject,
|
||||
} from './update_objects_spaces';
|
||||
|
||||
export { getIndexForType } from './get_index_for_type';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue