Skip to content

Commit

Permalink
[ILM ] Fix logic for showing/hiding recommended allocation on Cloud (#…
Browse files Browse the repository at this point in the history
…90592)

* updated logic for hiding recommended allocation options on cloud and moved tests over from legacy test folder

* added version check and tests for version check to enable pre v8 behaviour

* implement feedback to make tests more legible, fix test names and minor refactors

* added additional callout for data tier state, also added some new copy specific to the migration of a deployment on cloud

* remove unused stackVersion context value

* address windows max path length constraint

* - Fix botched conflict resolution!
- Addressed PR feedback, updated data allocation field for readability; added comments and refactored default allocation notice and warning
- Added one more test case for on cloud; when to show the call to migrate to node roles

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
jloleysens and kibanamachine committed Feb 25, 2021
1 parent f0838e6 commit 83593bd
Show file tree
Hide file tree
Showing 10 changed files with 320 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ export const setup = async (arg?: {

const enable = (phase: Phases) => createFormToggleAction(`enablePhaseSwitch-${phase}`);

const showDataAllocationOptions = (phase: Phases) => () => {
act(() => {
find(`${phase}-dataTierAllocationControls.dataTierSelect`).simulate('click');
});
component.update();
};

const createMinAgeActions = (phase: Phases) => {
return {
hasMinAgeInput: () => exists(`${phase}-selectedMinimumAge`),
Expand Down Expand Up @@ -379,6 +386,7 @@ export const setup = async (arg?: {
},
warm: {
enable: enable('warm'),
showDataAllocationOptions: showDataAllocationOptions('warm'),
...createMinAgeActions('warm'),
setReplicas: setReplicas('warm'),
hasErrorIndicator: () => exists('phaseErrorIndicator-warm'),
Expand All @@ -390,6 +398,7 @@ export const setup = async (arg?: {
},
cold: {
enable: enable('cold'),
showDataAllocationOptions: showDataAllocationOptions('cold'),
...createMinAgeActions('cold'),
setReplicas: setReplicas('cold'),
setFreeze,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -693,43 +693,52 @@ describe('<EditPolicy />', () => {
expect(find('cold-dataTierAllocationControls.dataTierSelect').text()).toContain('Off');
});
});
});

describe('searchable snapshot', () => {
describe('on cloud', () => {
describe('new policy', () => {
describe('using legacy data role config', () => {
beforeEach(async () => {
// simulate creating a new policy
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]);
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
httpRequestsMockHelpers.setListNodes({
isUsingDeprecatedDataRoleConfig: false,
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data: ['123'] },
// On cloud, even if there are data_* roles set, the default, recommended allocation option should not
// be available.
nodesByRoles: { data_hot: ['123'] },
isUsingDeprecatedDataRoleConfig: true,
});
httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });

await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
testBed = await setup({
appServicesContext: {
cloud: {
isCloudEnabled: true,
},
license: licensingMock.createLicense({ license: { type: 'basic' } }),
},
});
});

const { component } = testBed;
component.update();
});
test('defaults searchable snapshot to true on cloud', async () => {
const { find, actions } = testBed;
await actions.cold.enable(true);
expect(
find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked']
).toBe(true);
test('removes default, recommended option', async () => {
const { actions, find } = testBed;
await actions.warm.enable(true);
actions.warm.showDataAllocationOptions();

expect(find('defaultDataAllocationOption').exists()).toBeFalsy();
expect(find('customDataAllocationOption').exists()).toBeTruthy();
expect(find('noneDataAllocationOption').exists()).toBeTruthy();
// Show the call-to-action for users to migrate their cluster to use node roles
expect(find('cloudDataTierCallout').exists()).toBeTruthy();
});
});
describe('existing policy', () => {
describe('using node roles', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
httpRequestsMockHelpers.setListNodes({
isUsingDeprecatedDataRoleConfig: false,
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data: ['123'] },
nodesByRoles: { data_hot: ['123'] },
isUsingDeprecatedDataRoleConfig: false,
});
httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });

Expand All @@ -740,19 +749,34 @@ describe('<EditPolicy />', () => {
const { component } = testBed;
component.update();
});
test('correctly sets snapshot repository default to "found-snapshots"', async () => {
const { actions } = testBed;

test('should show recommended, custom and "off" options on cloud with data roles', async () => {
const { actions, find } = testBed;

await actions.warm.enable(true);
actions.warm.showDataAllocationOptions();
expect(find('defaultDataAllocationOption').exists()).toBeTruthy();
expect(find('customDataAllocationOption').exists()).toBeTruthy();
expect(find('noneDataAllocationOption').exists()).toBeTruthy();
// We should not be showing the call-to-action for users to activate the cold tier on cloud
expect(find('cloudMissingColdTierCallout').exists()).toBeFalsy();
// Do not show the call-to-action for users to migrate their cluster to use node roles
expect(find('cloudDataTierCallout').exists()).toBeFalsy();
});

test('should show cloud notice when cold tier nodes do not exist', async () => {
const { actions, find } = testBed;
await actions.cold.enable(true);
await actions.cold.toggleSearchableSnapshot(true);
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
const request = JSON.parse(JSON.parse(latestRequest.requestBody).body);
expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual(
'found-snapshots'
);
expect(find('cloudMissingColdTierCallout').exists()).toBeTruthy();
// Assert that other notices are not showing
expect(find('defaultAllocationNotice').exists()).toBeFalsy();
expect(find('noNodeAttributesWarning').exists()).toBeFalsy();
});
});
});
});

describe('searchable snapshot', () => {
describe('on non-enterprise license', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
Expand Down Expand Up @@ -789,6 +813,64 @@ describe('<EditPolicy />', () => {
expect(actions.cold.searchableSnapshotDisabledDueToLicense()).toBeTruthy();
});
});

describe('on cloud', () => {
describe('new policy', () => {
beforeEach(async () => {
// simulate creating a new policy
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('')]);
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data: ['123'] },
isUsingDeprecatedDataRoleConfig: false,
});
httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });

await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
});

const { component } = testBed;
component.update();
});
test('defaults searchable snapshot to true on cloud', async () => {
const { find, actions } = testBed;
await actions.cold.enable(true);
expect(
find('searchableSnapshotField-cold.searchableSnapshotToggle').props()['aria-checked']
).toBe(true);
});
});
describe('existing policy', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadPolicies([getDefaultHotPhasePolicy('my_policy')]);
httpRequestsMockHelpers.setListNodes({
isUsingDeprecatedDataRoleConfig: false,
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data_hot: ['123'] },
});
httpRequestsMockHelpers.setListSnapshotRepos({ repositories: ['found-snapshots'] });

await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
});

const { component } = testBed;
component.update();
});
test('correctly sets snapshot repository default to "found-snapshots"', async () => {
const { actions } = testBed;
await actions.cold.enable(true);
await actions.cold.toggleSearchableSnapshot(true);
await actions.savePolicy();
const latestRequest = server.requests[server.requests.length - 1];
const request = JSON.parse(JSON.parse(latestRequest.requestBody).body);
expect(request.phases.cold.actions.searchable_snapshot.snapshot_repository).toEqual(
'found-snapshots'
);
});
});
});
});
describe('with rollover', () => {
beforeEach(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe('<EditPolicy /> node allocation', () => {
expect(actions.warm.hasDefaultAllocationWarning()).toBeTruthy();
});

test('shows default allocation notice when hot tier exists, but not warm tier', async () => {
test('when configuring warm phase shows default allocation notice when hot tier exists, but not warm tier', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: {},
nodesByRoles: { data_hot: ['test'], data_cold: ['test'] },
Expand Down Expand Up @@ -309,7 +309,7 @@ describe('<EditPolicy /> node allocation', () => {

describe('on cloud', () => {
describe('with deprecated data role config', () => {
test('should hide data tier option on cloud using legacy node role configuration', async () => {
test('should hide data tier option on cloud', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
// On cloud, if using legacy config there will not be any "data_*" roles set.
Expand All @@ -331,10 +331,29 @@ describe('<EditPolicy /> node allocation', () => {
expect(exists('customDataAllocationOption')).toBeTruthy();
expect(exists('noneDataAllocationOption')).toBeTruthy();
});

test('should ask users to migrate to node roles when on cloud using legacy data role', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
// On cloud, if using legacy config there will not be any "data_*" roles set.
nodesByRoles: { data: ['test'] },
isUsingDeprecatedDataRoleConfig: true,
});
await act(async () => {
testBed = await setup({ appServicesContext: { cloud: { isCloudEnabled: true } } });
});
const { actions, component, exists } = testBed;

component.update();
await actions.warm.enable(true);
expect(component.find('.euiLoadingSpinner').exists()).toBeFalsy();

expect(exists('cloudDataTierCallout')).toBeTruthy();
});
});

describe('with node role config', () => {
test('shows off, custom and data role options on cloud with data roles', async () => {
test('shows data role, custom and "off" options on cloud with data roles', async () => {
httpRequestsMockHelpers.setListNodes({
nodesByAttributes: { test: ['123'] },
nodesByRoles: { data: ['test'], data_hot: ['test'], data_warm: ['test'] },
Expand Down Expand Up @@ -372,7 +391,7 @@ describe('<EditPolicy /> node allocation', () => {
await actions.cold.enable(true);
expect(component.find('.euiLoadingSpinner').exists()).toBeFalsy();

expect(exists('cloudDataTierCallout')).toBeTruthy();
expect(exists('cloudMissingColdTierCallout')).toBeTruthy();
// Assert that other notices are not showing
expect(actions.cold.hasDefaultAllocationNotice()).toBeFalsy();
expect(actions.cold.hasNoNodeAttrsWarning()).toBeFalsy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,38 @@

import { i18n } from '@kbn/i18n';
import React, { FunctionComponent } from 'react';
import { EuiCallOut } from '@elastic/eui';
import { EuiCallOut, EuiLink } from '@elastic/eui';

const i18nTexts = {
title: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.title', {
defaultMessage: 'Create a cold tier',
defaultMessage: 'Migrate to data tiers',
}),
body: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.body', {
defaultMessage: 'Edit your Elastic Cloud deployment to set up a cold tier.',
defaultMessage: 'Migrate your Elastic Cloud deployment to use data tiers.',
}),
linkText: i18n.translate(
'xpack.indexLifecycleMgmt.editPolicy.cloudDataTierCallout.linkToCloudDeploymentDescription',
{ defaultMessage: 'View cloud deployment' }
),
};

export const CloudDataTierCallout: FunctionComponent = () => {
interface Props {
linkToCloudDeployment?: string;
}

/**
* A call-to-action for users to migrate to data tiers if their cluster is still running
* the deprecated node.data:true config.
*/
export const CloudDataTierCallout: FunctionComponent<Props> = ({ linkToCloudDeployment }) => {
return (
<EuiCallOut title={i18nTexts.title} data-test-subj="cloudDataTierCallout">
{i18nTexts.body}
{i18nTexts.body}{' '}
{Boolean(linkToCloudDeployment) && (
<EuiLink href={linkToCloudDeployment} external>
{i18nTexts.linkText}
</EuiLink>
)}
</EuiCallOut>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import { EuiCallOut } from '@elastic/eui';

import { PhaseWithAllocation, DataTierRole } from '../../../../../../../../../common/types';

import { AllocationNodeRole } from '../../../../../../../lib';

const i18nTextsNodeRoleToDataTier: Record<DataTierRole, string> = {
data_hot: i18n.translate('xpack.indexLifecycleMgmt.editPolicy.dataTierHotLabel', {
defaultMessage: 'hot',
Expand Down Expand Up @@ -84,24 +82,13 @@ const i18nTexts = {

interface Props {
phase: PhaseWithAllocation;
targetNodeRole: AllocationNodeRole;
targetNodeRole: DataTierRole;
}

export const DefaultAllocationNotice: FunctionComponent<Props> = ({ phase, targetNodeRole }) => {
const content =
targetNodeRole === 'none' ? (
<EuiCallOut
data-test-subj="defaultAllocationWarning"
title={i18nTexts.warning[phase].title}
color="warning"
>
{i18nTexts.warning[phase].body}
</EuiCallOut>
) : (
<EuiCallOut data-test-subj="defaultAllocationNotice" title={i18nTexts.notice[phase].title}>
{i18nTexts.notice[phase].body(targetNodeRole)}
</EuiCallOut>
);

return content;
return (
<EuiCallOut data-test-subj="defaultAllocationNotice" title={i18nTexts.notice[phase].title}>
{i18nTexts.notice[phase].body(targetNodeRole)}
</EuiCallOut>
);
};
Loading

0 comments on commit 83593bd

Please sign in to comment.