diff --git a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx index dfbe19ba21a94..953e6244b077f 100644 --- a/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx +++ b/x-pack/plugins/index_lifecycle_management/__jest__/components/edit_policy.test.tsx @@ -21,8 +21,10 @@ import { fatalErrorsServiceMock, } from '../../../../../src/core/public/mocks'; import { usageCollectionPluginMock } from '../../../../../src/plugins/usage_collection/public/mocks'; +import { CloudSetup } from '../../../cloud/public'; import { EditPolicy } from '../../public/application/sections/edit_policy/edit_policy'; +import { KibanaContextProvider } from '../../public/shared_imports'; import { init as initHttp } from '../../public/application/services/http'; import { init as initUiMetric } from '../../public/application/services/ui_metric'; import { init as initNotification } from '../../public/application/services/notification'; @@ -148,7 +150,14 @@ const save = (rendered: ReactWrapper) => { describe('edit policy', () => { beforeEach(() => { component = ( - + + + ); ({ http } = editPolicyHelpers.setup()); @@ -447,6 +456,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data: ['node1'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -495,6 +505,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: {}, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -507,6 +518,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data_hot: ['test'], data_cold: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -519,6 +531,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -568,6 +581,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data: ['node1'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -626,6 +640,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: {}, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -638,6 +653,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data_hot: ['test'], data_warm: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -650,6 +666,7 @@ describe('edit policy', () => { http.setupNodeListResponse({ nodesByAttributes: {}, nodesByRoles: { data: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, }); const rendered = mountWithIntl(component); noRollover(rendered); @@ -679,4 +696,104 @@ describe('edit policy', () => { expectedErrorMessages(rendered, [positiveNumberRequiredMessage]); }); }); + describe('not on cloud', () => { + beforeEach(() => { + server.respondImmediately = true; + }); + test('should show all allocation options, even if using legacy config', async () => { + http.setupNodeListResponse({ + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] }, + isUsingDeprecatedDataRoleConfig: true, + }); + const rendered = mountWithIntl(component); + noRollover(rendered); + setPolicyName(rendered, 'mypolicy'); + await activatePhase(rendered, 'warm'); + expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); + + // Assert that only the custom and off options exist + findTestSubject(rendered, 'dataTierSelect').simulate('click'); + expect(findTestSubject(rendered, 'defaultDataAllocationOption').exists()).toBeTruthy(); + expect(findTestSubject(rendered, 'customDataAllocationOption').exists()).toBeTruthy(); + expect(findTestSubject(rendered, 'noneDataAllocationOption').exists()).toBeTruthy(); + }); + }); + describe('on cloud', () => { + beforeEach(() => { + component = ( + + + + ); + ({ http } = editPolicyHelpers.setup()); + ({ server, httpRequestsMockHelpers } = http); + server.respondImmediately = true; + + httpRequestsMockHelpers.setPoliciesResponse(policies); + }); + + describe('with legacy data role config', () => { + test('should hide data tier option on cloud using legacy node role configuration', async () => { + http.setupNodeListResponse({ + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] }, + isUsingDeprecatedDataRoleConfig: true, + }); + const rendered = mountWithIntl(component); + noRollover(rendered); + setPolicyName(rendered, 'mypolicy'); + await activatePhase(rendered, 'warm'); + expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); + + // Assert that only the custom and off options exist + findTestSubject(rendered, 'dataTierSelect').simulate('click'); + expect(findTestSubject(rendered, 'defaultDataAllocationOption').exists()).toBeFalsy(); + expect(findTestSubject(rendered, 'customDataAllocationOption').exists()).toBeTruthy(); + expect(findTestSubject(rendered, 'noneDataAllocationOption').exists()).toBeTruthy(); + }); + }); + + describe('with node role config', () => { + test('should show off, custom and data role options on cloud with data roles', async () => { + http.setupNodeListResponse({ + nodesByAttributes: { test: ['123'] }, + nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + const rendered = mountWithIntl(component); + noRollover(rendered); + setPolicyName(rendered, 'mypolicy'); + await activatePhase(rendered, 'warm'); + expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); + + findTestSubject(rendered, 'dataTierSelect').simulate('click'); + expect(findTestSubject(rendered, 'defaultDataAllocationOption').exists()).toBeTruthy(); + expect(findTestSubject(rendered, 'customDataAllocationOption').exists()).toBeTruthy(); + expect(findTestSubject(rendered, 'noneDataAllocationOption').exists()).toBeTruthy(); + }); + + test('should show cloud notice when cold tier nodes do not exist', async () => { + http.setupNodeListResponse({ + nodesByAttributes: {}, + nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] }, + isUsingDeprecatedDataRoleConfig: false, + }); + const rendered = mountWithIntl(component); + noRollover(rendered); + setPolicyName(rendered, 'mypolicy'); + await activatePhase(rendered, 'cold'); + expect(rendered.find('.euiLoadingSpinner').exists()).toBeFalsy(); + expect(findTestSubject(rendered, 'cloudDataTierCallout').exists()).toBeTruthy(); + // Assert that other notices are not showing + expect(findTestSubject(rendered, 'defaultAllocationNotice').exists()).toBeFalsy(); + expect(findTestSubject(rendered, 'noNodeAttributesWarning').exists()).toBeFalsy(); + }); + }); + }); }); diff --git a/x-pack/plugins/index_lifecycle_management/common/types/api.ts b/x-pack/plugins/index_lifecycle_management/common/types/api.ts index fcdbdf2c9cc90..ccdd7fcb11778 100644 --- a/x-pack/plugins/index_lifecycle_management/common/types/api.ts +++ b/x-pack/plugins/index_lifecycle_management/common/types/api.ts @@ -9,4 +9,12 @@ import { NodeDataRoleWithCatchAll } from '.'; export interface ListNodesRouteResponse { nodesByAttributes: { [attributePair: string]: string[] }; nodesByRoles: { [role in NodeDataRoleWithCatchAll]?: string[] }; + + /** + * A flag to indicate whether a node is using `settings.node.data` which is the now deprecated way cloud configured + * nodes to have data (and other) roles. + * + * If this is true, it means the cluster is using legacy cloud configuration for data allocation, not node roles. + */ + isUsingDeprecatedDataRoleConfig: boolean; } diff --git a/x-pack/plugins/index_lifecycle_management/kibana.json b/x-pack/plugins/index_lifecycle_management/kibana.json index 479d651fc6698..1b0a73c6a0133 100644 --- a/x-pack/plugins/index_lifecycle_management/kibana.json +++ b/x-pack/plugins/index_lifecycle_management/kibana.json @@ -9,6 +9,7 @@ "features" ], "optionalPlugins": [ + "cloud", "usageCollection", "indexManagement", "home" diff --git a/x-pack/plugins/index_lifecycle_management/public/application/index.tsx b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx index d7812f186a03f..7a7fd20e96c63 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/index.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/index.tsx @@ -8,6 +8,9 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nStart, ScopedHistory, ApplicationStart } from 'kibana/public'; import { UnmountCallback } from 'src/core/public'; +import { CloudSetup } from '../../../cloud/public'; + +import { KibanaContextProvider } from '../shared_imports'; import { App } from './app'; @@ -16,11 +19,14 @@ export const renderApp = ( I18nContext: I18nStart['Context'], history: ScopedHistory, navigateToApp: ApplicationStart['navigateToApp'], - getUrlForApp: ApplicationStart['getUrlForApp'] + getUrlForApp: ApplicationStart['getUrlForApp'], + cloud?: CloudSetup ): UnmountCallback => { render( - + + + , element ); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/cloud_data_tier_callout.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/cloud_data_tier_callout.tsx new file mode 100644 index 0000000000000..2dff55ac10de1 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/cloud_data_tier_callout.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React, { FunctionComponent } from 'react'; +import { EuiCallOut } from '@elastic/eui'; + +const i18nTexts = { + title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.title', { + defaultMessage: 'Create a cold tier', + }), + body: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.body', { + defaultMessage: 'Edit your Elastic Cloud deployment to set up a cold tier.', + }), +}; + +export const CloudDataTierCallout: FunctionComponent = () => { + return ( + + {i18nTexts.body} + + ); +}; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/data_tier_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/data_tier_allocation.tsx index 4ec488f95c94d..f58f36fc45a0c 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/data_tier_allocation.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/data_tier_allocation.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FunctionComponent } from 'react'; +import React, { FunctionComponent, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiText, EuiFormRow, EuiSpacer, EuiSuperSelect, EuiSuperSelectOption } from '@elastic/eui'; @@ -90,7 +90,25 @@ const i18nTexts = { }; export const DataTierAllocation: FunctionComponent = (props) => { - const { phaseData, setPhaseData, phase, hasNodeAttributes } = props; + const { phaseData, setPhaseData, phase, hasNodeAttributes, disableDataTierOption } = props; + + useEffect(() => { + if (disableDataTierOption && phaseData.dataTierAllocationType === 'default') { + /** + * @TODO + * This is a slight hack because we only know we should disable the "default" option further + * down the component tree (i.e., after the policy has been deserialized). + * + * We reset the value to "custom" if we deserialized to "default". + * + * It would be better if we had all the information we needed before deserializing and + * were able to handle this at the deserialization step instead of patching further down + * the component tree - this should be a future refactor. + */ + setPhaseData('dataTierAllocationType', 'custom'); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return (
@@ -102,21 +120,40 @@ export const DataTierAllocation: FunctionComponent = (props) => { onChange={(value) => setPhaseData('dataTierAllocationType', value)} options={ [ + disableDataTierOption + ? undefined + : { + 'data-test-subj': 'defaultDataAllocationOption', + value: 'default', + inputDisplay: i18nTexts.allocationOptions[phase].default.input, + dropdownDisplay: ( + <> + {i18nTexts.allocationOptions[phase].default.input} + +

+ {i18nTexts.allocationOptions[phase].default.helpText} +

+
+ + ), + }, { - value: 'default', - inputDisplay: i18nTexts.allocationOptions[phase].default.input, + 'data-test-subj': 'customDataAllocationOption', + value: 'custom', + inputDisplay: i18nTexts.allocationOptions[phase].custom.inputDisplay, dropdownDisplay: ( <> - {i18nTexts.allocationOptions[phase].default.input} + {i18nTexts.allocationOptions[phase].custom.inputDisplay}

- {i18nTexts.allocationOptions[phase].default.helpText} + {i18nTexts.allocationOptions[phase].custom.helpText}

), }, { + 'data-test-subj': 'noneDataAllocationOption', value: 'none', inputDisplay: i18nTexts.allocationOptions[phase].none.inputDisplay, dropdownDisplay: ( @@ -130,22 +167,7 @@ export const DataTierAllocation: FunctionComponent = (props) => { ), }, - { - 'data-test-subj': 'customDataAllocationOption', - value: 'custom', - inputDisplay: i18nTexts.allocationOptions[phase].custom.inputDisplay, - dropdownDisplay: ( - <> - {i18nTexts.allocationOptions[phase].custom.inputDisplay} - -

- {i18nTexts.allocationOptions[phase].custom.helpText} -

-
- - ), - }, - ] as SelectOptions[] + ].filter(Boolean) as SelectOptions[] } /> diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/default_allocation_notice.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/default_allocation_notice.tsx index 8faa9bb2972c2..42f9e8494a0b3 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/default_allocation_notice.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/default_allocation_notice.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import React, { FunctionComponent } from 'react'; -import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut } from '@elastic/eui'; import { PhaseWithAllocation, NodeDataRole } from '../../../../../../common/types'; @@ -102,10 +102,5 @@ export const DefaultAllocationNotice: FunctionComponent = ({ phase, targe ); - return ( - <> - - {content} - - ); + return content; }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/index.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/index.ts index dcbdf960fd380..937e3dd28da97 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/index.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/index.ts @@ -10,3 +10,4 @@ export { NodeAttrsDetails } from './node_attrs_details'; export { DataTierAllocation } from './data_tier_allocation'; export { DefaultAllocationNotice } from './default_allocation_notice'; export { NoNodeAttributesWarning } from './no_node_attributes_warning'; +export { CloudDataTierCallout } from './cloud_data_tier_callout'; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/no_node_attributes_warning.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/no_node_attributes_warning.tsx index ceccc51f95c1f..69185277f64ce 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/no_node_attributes_warning.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/no_node_attributes_warning.tsx @@ -5,7 +5,7 @@ */ import React, { FunctionComponent } from 'react'; -import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PhaseWithAllocation } from '../../../../../../common/types'; @@ -38,16 +38,13 @@ export const NoNodeAttributesWarning: FunctionComponent<{ phase: PhaseWithAlloca phase, }) => { return ( - <> - - - {i18nTexts[phase].body} - - + + {i18nTexts[phase].body} + ); }; diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/types.ts b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/types.ts index d4cb31a3be9e7..d3dd536d97df0 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/types.ts +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/data_tier_allocation/types.ts @@ -19,4 +19,10 @@ export interface SharedProps { isShowingErrors: boolean; nodes: ListNodesRouteResponse['nodesByAttributes']; hasNodeAttributes: boolean; + /** + * When on Cloud we want to disable the data tier allocation option when we detect that we are not + * using node roles in our Node config yet. See {@link ListNodesRouteResponse} for information about how this is + * detected. + */ + disableDataTierOption: boolean; } diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/phases/shared/data_tier_allocation_field.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/phases/shared/data_tier_allocation_field.tsx index 623d443a1db01..b3772a6e3ebd4 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/phases/shared/data_tier_allocation_field.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/phases/shared/data_tier_allocation_field.tsx @@ -6,8 +6,9 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiDescribedFormGroup, EuiFormRow } from '@elastic/eui'; +import { EuiDescribedFormGroup, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import { useKibana } from '../../../../../shared_imports'; import { PhaseWithAllocationAction, PhaseWithAllocation } from '../../../../../../common/types'; import { PhaseValidationErrors } from '../../../../services/policies/policy_validation'; import { getAvailableNodeRoleForPhase } from '../../../../lib/data_tiers'; @@ -18,6 +19,7 @@ import { DefaultAllocationNotice, NoNodeAttributesWarning, NodesDataProvider, + CloudDataTierCallout, } from '../../components/data_tier_allocation'; const i18nTexts = { @@ -46,35 +48,61 @@ export const DataTierAllocationField: FunctionComponent = ({ isShowingErrors, errors, }) => { + const { + services: { cloud }, + } = useKibana(); + return ( - {(nodesData) => { - const hasNodeAttrs = Boolean(Object.keys(nodesData.nodesByAttributes ?? {}).length); - - const renderDefaultAllocationNotice = () => { - if (phaseData.dataTierAllocationType !== 'default') { - return null; - } + {({ nodesByRoles, nodesByAttributes, isUsingDeprecatedDataRoleConfig }) => { + const hasNodeAttrs = Boolean(Object.keys(nodesByAttributes ?? {}).length); - const allocationNodeRole = getAvailableNodeRoleForPhase(phase, nodesData.nodesByRoles); - if ( - allocationNodeRole !== 'none' && - isNodeRoleFirstPreference(phase, allocationNodeRole) - ) { - return null; - } + const renderNotice = () => { + switch (phaseData.dataTierAllocationType) { + case 'default': + const isCloudEnabled = cloud?.isCloudEnabled ?? false; + const isUsingNodeRoles = !isUsingDeprecatedDataRoleConfig; + if ( + isCloudEnabled && + isUsingNodeRoles && + phase === 'cold' && + !nodesByRoles.data_cold?.length + ) { + // Tell cloud users they can deploy cold tier nodes. + return ( + <> + + + + ); + } - return ; - }; - - const renderNodeAttributesWarning = () => { - if (phaseData.dataTierAllocationType !== 'custom') { - return null; - } - if (hasNodeAttrs) { - return null; + const allocationNodeRole = getAvailableNodeRoleForPhase(phase, nodesByRoles); + if ( + allocationNodeRole === 'none' || + !isNodeRoleFirstPreference(phase, allocationNodeRole) + ) { + return ( + <> + + + + ); + } + break; + case 'custom': + if (!hasNodeAttrs) { + return ( + <> + + + + ); + } + break; + default: + return null; } - return ; }; return ( @@ -92,12 +120,14 @@ export const DataTierAllocationField: FunctionComponent = ({ setPhaseData={setPhaseData} phaseData={phaseData} isShowingErrors={isShowingErrors} - nodes={nodesData.nodesByAttributes} + nodes={nodesByAttributes} + disableDataTierOption={ + !!(isUsingDeprecatedDataRoleConfig && cloud?.isCloudEnabled) + } /> - {/* Data tier related warnings */} - {renderDefaultAllocationNotice()} - {renderNodeAttributesWarning()} + {/* Data tier related warnings and call-to-action notices */} + {renderNotice()} diff --git a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx index 645a78bfc99b8..24ce036c0e058 100644 --- a/x-pack/plugins/index_lifecycle_management/public/plugin.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/plugin.tsx @@ -31,7 +31,7 @@ export class IndexLifecycleManagementPlugin { getStartServices, } = coreSetup; - const { usageCollection, management, indexManagement, home } = plugins; + const { usageCollection, management, indexManagement, home, cloud } = plugins; // Initialize services even if the app isn't mounted, because they're used by index management extensions. initHttp(http); @@ -65,7 +65,8 @@ export class IndexLifecycleManagementPlugin { I18nContext, history, navigateToApp, - getUrlForApp + getUrlForApp, + cloud ); return () => { diff --git a/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts new file mode 100644 index 0000000000000..d479b821ceefc --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/public/shared_imports.ts @@ -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; + * you may not use this file except in compliance with the Elastic License. + */ +import { AppServicesContext } from './types'; +import { useKibana as _useKibana } from '../../../../src/plugins/kibana_react/public'; + +export { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; +export const useKibana = () => _useKibana(); diff --git a/x-pack/plugins/index_lifecycle_management/public/types.ts b/x-pack/plugins/index_lifecycle_management/public/types.ts index 65db00f1e68c1..c9b9b063cd45f 100644 --- a/x-pack/plugins/index_lifecycle_management/public/types.ts +++ b/x-pack/plugins/index_lifecycle_management/public/types.ts @@ -8,10 +8,12 @@ import { HomePublicPluginSetup } from '../../../../src/plugins/home/public'; import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/public'; import { ManagementSetup } from '../../../../src/plugins/management/public'; import { IndexManagementPluginSetup } from '../../index_management/public'; +import { CloudSetup } from '../../cloud/public'; export interface PluginsDependencies { usageCollection?: UsageCollectionSetup; management: ManagementSetup; + cloud?: CloudSetup; indexManagement?: IndexManagementPluginSetup; home?: HomePublicPluginSetup; } @@ -21,3 +23,7 @@ export interface ClientConfigType { enabled: boolean; }; } + +export interface AppServicesContext { + cloud?: CloudSetup; +} diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/fixtures.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/fixtures.ts new file mode 100644 index 0000000000000..e547c3f662432 --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/fixtures.ts @@ -0,0 +1,2295 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable @typescript-eslint/naming-convention */ + +/** + * The fixtures below are from the "_nodes/settings" endpoint on a 7.9.2 Cloud-created cluster. + */ + +export const cloudNodeSettingsWithLegacy = { + _nodes: { + successful: 5, + failed: 0, + total: 5, + }, + cluster_name: '6ee9547c30214d278d2a63c4de98dea5', + nodes: { + t49k7mdeRIiELuOt_MOZ1g: { + transport_address: '10.47.32.43:19833', + name: 'instance-0000000002', + roles: ['data', 'ingest', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000002.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highstorage.1', + logical_availability_zone: 'zone-0', + data: 'warm', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000002', + master: 'false', + data: 'true', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18120', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18120', + }, + network: { + publish_host: '10.47.32.43', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19833', + }, + profiles: { + client: { + port: '20296', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.43', + host: '10.47.32.43', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000002.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highstorage.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-0', + data: 'warm', + }, + build_type: 'docker', + }, + 'SgaCpsXAQu-oTsP4iLGZWw': { + transport_address: '10.47.32.33:19227', + name: 'tiebreaker-0000000004', + roles: ['master', 'remote_cluster_client', 'voting_only'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'tiebreaker-0000000004.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-b', + region: 'unknown-region', + transform: { + node: 'false', + }, + instance_configuration: 'gcp.master.1', + logical_availability_zone: 'tiebreaker', + data: 'hot', + }, + ml: 'false', + ingest: 'false', + name: 'tiebreaker-0000000004', + master: 'true', + voting_only: 'true', + data: 'false', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18013', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18013', + }, + network: { + publish_host: '10.47.32.33', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19227', + }, + profiles: { + client: { + port: '20281', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.33', + host: '10.47.32.33', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'tiebreaker-0000000004.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-b', + 'transform.node': 'false', + region: 'unknown-region', + instance_configuration: 'gcp.master.1', + 'xpack.installed': 'true', + logical_availability_zone: 'tiebreaker', + data: 'hot', + }, + build_type: 'docker', + }, + 'ZVndRfrfSl-kmEyZgJu0JQ': { + transport_address: '10.47.47.205:19570', + name: 'instance-0000000001', + roles: ['data', 'ingest', 'master', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000001.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highio.1', + logical_availability_zone: 'zone-1', + data: 'hot', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000001', + master: 'true', + data: 'true', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18760', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18760', + }, + network: { + publish_host: '10.47.47.205', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19570', + }, + profiles: { + client: { + port: '20803', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.47.205', + host: '10.47.47.205', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000001.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highio.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-1', + data: 'hot', + }, + build_type: 'docker', + }, + Tx8Xig60SIuitXhY0srD6Q: { + transport_address: '10.47.32.41:19901', + name: 'instance-0000000003', + roles: ['data', 'ingest', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000003.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highstorage.1', + logical_availability_zone: 'zone-1', + data: 'warm', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000003', + master: 'false', + data: 'true', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18977', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18977', + }, + network: { + publish_host: '10.47.32.41', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19901', + }, + profiles: { + client: { + port: '20466', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.41', + host: '10.47.32.41', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000003.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highstorage.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-1', + data: 'warm', + }, + build_type: 'docker', + }, + Qtpmy7aBSIaOZisv9Q92TA: { + transport_address: '10.47.47.203:19498', + name: 'instance-0000000000', + roles: ['data', 'ingest', 'master', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000000.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highio.1', + logical_availability_zone: 'zone-0', + data: 'hot', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000000', + master: 'true', + data: 'true', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18221', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18221', + }, + network: { + publish_host: '10.47.47.203', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19498', + }, + profiles: { + client: { + port: '20535', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.47.203', + host: '10.47.47.203', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000000.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highio.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-0', + data: 'hot', + }, + build_type: 'docker', + }, + }, +}; + +export const cloudNodeSettingsWithoutLegacy = { + _nodes: { + successful: 5, + failed: 0, + total: 5, + }, + cluster_name: '6ee9547c30214d278d2a63c4de98dea5', + nodes: { + t49k7mdeRIiELuOt_MOZ1g: { + transport_address: '10.47.32.43:19833', + name: 'instance-0000000002', + roles: ['data', 'ingest', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000002.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highstorage.1', + logical_availability_zone: 'zone-0', + data: 'warm', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000002', + master: 'false', + data: undefined, + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18120', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18120', + }, + network: { + publish_host: '10.47.32.43', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19833', + }, + profiles: { + client: { + port: '20296', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.43', + host: '10.47.32.43', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000002.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highstorage.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-0', + data: 'warm', + }, + build_type: 'docker', + }, + 'SgaCpsXAQu-oTsP4iLGZWw': { + transport_address: '10.47.32.33:19227', + name: 'tiebreaker-0000000004', + roles: ['master', 'remote_cluster_client', 'voting_only'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'tiebreaker-0000000004.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-b', + region: 'unknown-region', + transform: { + node: 'false', + }, + instance_configuration: 'gcp.master.1', + logical_availability_zone: 'tiebreaker', + data: 'hot', + }, + ml: 'false', + ingest: 'false', + name: 'tiebreaker-0000000004', + master: 'true', + voting_only: 'true', + data: 'false', + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18013', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18013', + }, + network: { + publish_host: '10.47.32.33', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19227', + }, + profiles: { + client: { + port: '20281', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.33', + host: '10.47.32.33', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'tiebreaker-0000000004.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-b', + 'transform.node': 'false', + region: 'unknown-region', + instance_configuration: 'gcp.master.1', + 'xpack.installed': 'true', + logical_availability_zone: 'tiebreaker', + data: 'hot', + }, + build_type: 'docker', + }, + 'ZVndRfrfSl-kmEyZgJu0JQ': { + transport_address: '10.47.47.205:19570', + name: 'instance-0000000001', + roles: ['data', 'ingest', 'master', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000001.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highio.1', + logical_availability_zone: 'zone-1', + data: 'hot', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000001', + master: 'true', + data: undefined, + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18760', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18760', + }, + network: { + publish_host: '10.47.47.205', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19570', + }, + profiles: { + client: { + port: '20803', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.47.205', + host: '10.47.47.205', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000001.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highio.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-1', + data: 'hot', + }, + build_type: 'docker', + }, + Tx8Xig60SIuitXhY0srD6Q: { + transport_address: '10.47.32.41:19901', + name: 'instance-0000000003', + roles: ['data', 'ingest', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000003.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highstorage.1', + logical_availability_zone: 'zone-1', + data: 'warm', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000003', + master: 'false', + data: undefined, + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18977', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18977', + }, + network: { + publish_host: '10.47.32.41', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19901', + }, + profiles: { + client: { + port: '20466', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.32.41', + host: '10.47.32.41', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000003.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-a', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highstorage.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-1', + data: 'warm', + }, + build_type: 'docker', + }, + Qtpmy7aBSIaOZisv9Q92TA: { + transport_address: '10.47.47.203:19498', + name: 'instance-0000000000', + roles: ['data', 'ingest', 'master', 'remote_cluster_client', 'transform'], + settings: { + node: { + attr: { + xpack: { + installed: 'true', + }, + server_name: 'instance-0000000000.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + region: 'unknown-region', + transform: { + node: 'true', + }, + instance_configuration: 'gcp.data.highio.1', + logical_availability_zone: 'zone-0', + data: 'hot', + }, + ml: 'false', + ingest: 'true', + name: 'instance-0000000000', + master: 'true', + data: undefined, + pidfile: '/app/es.pid', + max_local_storage_nodes: '1', + }, + reindex: { + remote: { + whitelist: ['*.io:*', '*.com:*'], + }, + }, + http: { + compression: 'true', + type: 'security4', + max_warning_header_count: '64', + publish_port: '18221', + 'type.default': 'netty4', + max_warning_header_size: '7168b', + port: '18221', + }, + network: { + publish_host: '10.47.47.203', + bind_host: '_site:ipv4_', + }, + xpack: { + monitoring: { + collection: { + enabled: 'false', + }, + history: { + duration: '3d', + }, + }, + license: { + self_generated: { + type: 'trial', + }, + }, + ml: { + enabled: 'true', + }, + ccr: { + enabled: 'false', + }, + notification: { + email: { + account: { + work: { + email_defaults: { + from: 'Watcher Alert ', + }, + smtp: { + host: 'dockerhost', + port: '10025', + }, + }, + }, + }, + }, + security: { + authc: { + token: { + enabled: 'true', + }, + reserved_realm: { + enabled: 'false', + }, + realms: { + native: { + native: { + order: '1', + }, + }, + file: { + found: { + order: '0', + }, + }, + saml: { + 'cloud-saml-kibana-916c269173df465f9826f4471799de42': { + attributes: { + name: 'http://saml.elastic-cloud.com/attributes/name', + groups: 'http://saml.elastic-cloud.com/attributes/roles', + principal: 'http://saml.elastic-cloud.com/attributes/principal', + }, + sp: { + acs: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/api/security/saml/callback', + entity_id: 'ec:2628060457:916c269173df465f9826f4471799de42', + logout: + 'https://916c269173df465f9826f4471799de42.europe-west4.gcp.elastic-cloud.com:9243/logout', + }, + order: '3', + idp: { + entity_id: 'urn:idp-cloud-elastic-co', + metadata: { + path: + '/app/config/cloud-saml-metadata-916c269173df465f9826f4471799de42.xml', + }, + }, + }, + }, + }, + anonymous: { + username: 'anonymous', + authz_exception: 'false', + roles: 'anonymous', + }, + }, + enabled: 'true', + http: { + ssl: { + enabled: 'true', + }, + }, + transport: { + ssl: { + enabled: 'true', + }, + }, + }, + }, + script: { + allowed_types: 'stored,inline', + }, + cluster: { + routing: { + allocation: { + disk: { + threshold_enabled: 'true', + watermark: { + enable_for_single_data_node: 'true', + }, + }, + awareness: { + attributes: 'region,logical_availability_zone', + }, + }, + }, + name: '6ee9547c30214d278d2a63c4de98dea5', + initial_master_nodes: 'instance-0000000000,instance-0000000001,tiebreaker-0000000004', + election: { + strategy: 'supports_voting_only', + }, + indices: { + close: { + enable: 'true', + }, + }, + metadata: { + managed_policies: ['cloud-snapshot-policy'], + managed_repository: 'found-snapshots', + managed_index_templates: '.cloud-', + }, + }, + client: { + type: 'node', + }, + action: { + auto_create_index: 'true', + destructive_requires_name: 'false', + }, + path: { + home: '/usr/share/elasticsearch', + data: ['/app/data'], + logs: '/app/logs', + }, + transport: { + 'type.default': 'netty4', + type: 'security4', + tcp: { + port: '19498', + }, + profiles: { + client: { + port: '20535', + }, + }, + features: { + 'x-pack': 'true', + }, + }, + discovery: { + seed_hosts: [], + seed_providers: 'file', + }, + }, + ip: '10.47.47.203', + host: '10.47.47.203', + version: '7.9.2', + build_flavor: 'default', + build_hash: 'd34da0ea4a966c4e49417f2da2f244e3e97b4e6e', + attributes: { + server_name: 'instance-0000000000.6ee9547c30214d278d2a63c4de98dea5', + availability_zone: 'europe-west4-c', + 'transform.node': 'true', + region: 'unknown-region', + instance_configuration: 'gcp.data.highio.1', + 'xpack.installed': 'true', + logical_availability_zone: 'zone-0', + data: 'hot', + }, + build_type: 'docker', + }, + }, +}; diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/register_list_route.test.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/register_list_route.test.ts new file mode 100644 index 0000000000000..5adb7763074fe --- /dev/null +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/__jest__/register_list_route.test.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { convertSettingsIntoLists } from '../register_list_route'; +import { cloudNodeSettingsWithLegacy, cloudNodeSettingsWithoutLegacy } from './fixtures'; + +describe('convertSettingsIntoLists', () => { + it('detects node role config', () => { + const result = convertSettingsIntoLists(cloudNodeSettingsWithoutLegacy, []); + expect(result.isUsingDeprecatedDataRoleConfig).toBe(false); + }); + + it('converts cloud settings into the expected response and detects deprecated config', () => { + const result = convertSettingsIntoLists(cloudNodeSettingsWithLegacy, []); + + expect(result.isUsingDeprecatedDataRoleConfig).toBe(true); + expect(result.nodesByRoles).toEqual({ + data: [ + 't49k7mdeRIiELuOt_MOZ1g', + 'ZVndRfrfSl-kmEyZgJu0JQ', + 'Tx8Xig60SIuitXhY0srD6Q', + 'Qtpmy7aBSIaOZisv9Q92TA', + ], + }); + expect(result.nodesByAttributes).toMatchInlineSnapshot(` + Object { + "availability_zone:europe-west4-a": Array [ + "ZVndRfrfSl-kmEyZgJu0JQ", + "Tx8Xig60SIuitXhY0srD6Q", + ], + "availability_zone:europe-west4-b": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + ], + "availability_zone:europe-west4-c": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "data:hot": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + "ZVndRfrfSl-kmEyZgJu0JQ", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "data:warm": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "Tx8Xig60SIuitXhY0srD6Q", + ], + "instance_configuration:gcp.data.highio.1": Array [ + "ZVndRfrfSl-kmEyZgJu0JQ", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "instance_configuration:gcp.data.highstorage.1": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "Tx8Xig60SIuitXhY0srD6Q", + ], + "instance_configuration:gcp.master.1": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + ], + "logical_availability_zone:tiebreaker": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + ], + "logical_availability_zone:zone-0": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "logical_availability_zone:zone-1": Array [ + "ZVndRfrfSl-kmEyZgJu0JQ", + "Tx8Xig60SIuitXhY0srD6Q", + ], + "region:unknown-region": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "SgaCpsXAQu-oTsP4iLGZWw", + "ZVndRfrfSl-kmEyZgJu0JQ", + "Tx8Xig60SIuitXhY0srD6Q", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "server_name:instance-0000000000.6ee9547c30214d278d2a63c4de98dea5": Array [ + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "server_name:instance-0000000001.6ee9547c30214d278d2a63c4de98dea5": Array [ + "ZVndRfrfSl-kmEyZgJu0JQ", + ], + "server_name:instance-0000000002.6ee9547c30214d278d2a63c4de98dea5": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + ], + "server_name:instance-0000000003.6ee9547c30214d278d2a63c4de98dea5": Array [ + "Tx8Xig60SIuitXhY0srD6Q", + ], + "server_name:tiebreaker-0000000004.6ee9547c30214d278d2a63c4de98dea5": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + ], + "transform.node:false": Array [ + "SgaCpsXAQu-oTsP4iLGZWw", + ], + "transform.node:true": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "ZVndRfrfSl-kmEyZgJu0JQ", + "Tx8Xig60SIuitXhY0srD6Q", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + "xpack.installed:true": Array [ + "t49k7mdeRIiELuOt_MOZ1g", + "SgaCpsXAQu-oTsP4iLGZWw", + "ZVndRfrfSl-kmEyZgJu0JQ", + "Tx8Xig60SIuitXhY0srD6Q", + "Qtpmy7aBSIaOZisv9Q92TA", + ], + } + `); + }); +}); diff --git a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts index 99df70e7df82d..4a176545743d0 100644 --- a/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts +++ b/x-pack/plugins/index_lifecycle_management/server/routes/api/nodes/register_list_route.ts @@ -11,22 +11,27 @@ import { ListNodesRouteResponse, NodeDataRole } from '../../../../common/types'; import { RouteDependencies } from '../../../types'; import { addBasePath } from '../../../services'; -interface Stats { +interface Settings { nodes: { [nodeId: string]: { attributes: Record; roles: string[]; + settings: { + node: { + data?: string; + }; + }; }; }; } -function convertStatsIntoList( - stats: Stats, +export function convertSettingsIntoLists( + settings: Settings, disallowedNodeAttributes: string[] ): ListNodesRouteResponse { - return Object.entries(stats.nodes).reduce( - (accum, [nodeId, nodeStats]) => { - const attributes = nodeStats.attributes || {}; + return Object.entries(settings.nodes).reduce( + (accum, [nodeId, nodeSettings]) => { + const attributes = nodeSettings.attributes || {}; for (const [key, value] of Object.entries(attributes)) { const isNodeAttributeAllowed = !disallowedNodeAttributes.includes(key); if (isNodeAttributeAllowed) { @@ -36,23 +41,37 @@ function convertStatsIntoList( } } - const dataRoles = nodeStats.roles.filter((r) => r.startsWith('data')) as NodeDataRole[]; + const dataRoles = nodeSettings.roles.filter((r) => r.startsWith('data')) as NodeDataRole[]; for (const role of dataRoles) { accum.nodesByRoles[role as NodeDataRole] = accum.nodesByRoles[role] ?? []; accum.nodesByRoles[role as NodeDataRole]!.push(nodeId); } + + // If we detect a single node using legacy "data:true" setting we know we are not using data roles for + // data allocation. + if (nodeSettings.settings?.node?.data === 'true') { + accum.isUsingDeprecatedDataRoleConfig = true; + } + return accum; }, - { nodesByAttributes: {}, nodesByRoles: {} } as ListNodesRouteResponse + { + nodesByAttributes: {}, + nodesByRoles: {}, + // Start with assumption that we are not using deprecated config + isUsingDeprecatedDataRoleConfig: false, + } as ListNodesRouteResponse ); } -async function fetchNodeStats(callAsCurrentUser: LegacyAPICaller): Promise { - const params = { - format: 'json', - }; - - return await callAsCurrentUser('nodes.stats', params); +async function fetchNodeSettings(callAsCurrentUser: LegacyAPICaller): Promise { + return await callAsCurrentUser('transport.request', { + method: 'GET', + path: '/_nodes/settings', + query: { + format: 'json', + }, + }); } export function registerListRoute({ router, config, license, lib }: RouteDependencies) { @@ -74,10 +93,13 @@ export function registerListRoute({ router, config, license, lib }: RouteDepende { path: addBasePath('/nodes/list'), validate: false }, license.guardApiRoute(async (context, request, response) => { try { - const stats = await fetchNodeStats( + const settings = await fetchNodeSettings( context.core.elasticsearch.legacy.client.callAsCurrentUser ); - const body: ListNodesRouteResponse = convertStatsIntoList(stats, disallowedNodeAttributes); + const body: ListNodesRouteResponse = convertSettingsIntoLists( + settings, + disallowedNodeAttributes + ); return response.ok({ body }); } catch (e) { if (lib.isEsError(e)) { diff --git a/x-pack/test/api_integration/apis/management/index_lifecycle_management/nodes.js b/x-pack/test/api_integration/apis/management/index_lifecycle_management/nodes.js index bb35f6fd96429..25522aeaaa79b 100644 --- a/x-pack/test/api_integration/apis/management/index_lifecycle_management/nodes.js +++ b/x-pack/test/api_integration/apis/management/index_lifecycle_management/nodes.js @@ -29,6 +29,7 @@ export default function ({ getService }) { const nodesIds = Object.keys(nodeStats.nodes); const { body } = await loadNodes().expect(200); + expect(body.isUsingDeprecatedDataRoleConfig).to.eql(false); expect(body.nodesByAttributes[NODE_CUSTOM_ATTRIBUTE]).to.eql(nodesIds); }); });