mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Add "Include aliases" toggle to the Restore Snapshot Wizard (#95882)
* Add support for includeAliases to restore API endpoint, with unit tests. * Remove unused deserializeRestoreSettings function. * Add 'Include aliases' option to the UI, with default value of true. * Add client integration test.
This commit is contained in:
parent
f7caf44876
commit
b531d28364
10 changed files with 111 additions and 80 deletions
|
@ -108,6 +108,14 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
]);
|
||||
};
|
||||
|
||||
const setRestoreSnapshotResponse = (response?: HttpResponse) => {
|
||||
server.respondWith('POST', `${API_BASE_PATH}restore/:repository/:snapshot`, [
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify(response),
|
||||
]);
|
||||
};
|
||||
|
||||
return {
|
||||
setLoadRepositoriesResponse,
|
||||
setLoadRepositoryTypesResponse,
|
||||
|
@ -119,6 +127,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
|
|||
setAddPolicyResponse,
|
||||
setGetPolicyResponse,
|
||||
setCleanupRepositoryResponse,
|
||||
setRestoreSnapshotResponse,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ const initTestBed = registerTestBed<RestoreSnapshotFormTestSubject>(
|
|||
|
||||
const setupActions = (testBed: TestBed<RestoreSnapshotFormTestSubject>) => {
|
||||
const { find, component, form } = testBed;
|
||||
|
||||
return {
|
||||
findDataStreamCallout() {
|
||||
return find('dataStreamWarningCallOut');
|
||||
|
@ -37,6 +38,28 @@ const setupActions = (testBed: TestBed<RestoreSnapshotFormTestSubject>) => {
|
|||
|
||||
component.update();
|
||||
},
|
||||
|
||||
toggleIncludeAliases() {
|
||||
act(() => {
|
||||
form.toggleEuiSwitch('includeAliasesSwitch');
|
||||
});
|
||||
|
||||
component.update();
|
||||
},
|
||||
|
||||
goToStep(step: number) {
|
||||
while (--step > 0) {
|
||||
find('nextButton').simulate('click');
|
||||
}
|
||||
component.update();
|
||||
},
|
||||
|
||||
async clickRestore() {
|
||||
await act(async () => {
|
||||
find('restoreButton').simulate('click');
|
||||
});
|
||||
component.update();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -58,5 +81,8 @@ export const setup = async (): Promise<RestoreSnapshotTestBed> => {
|
|||
export type RestoreSnapshotFormTestSubject =
|
||||
| 'snapshotRestoreStepLogistics'
|
||||
| 'includeGlobalStateSwitch'
|
||||
| 'includeAliasesSwitch'
|
||||
| 'nextButton'
|
||||
| 'restoreButton'
|
||||
| 'systemIndicesInfoCallOut'
|
||||
| 'dataStreamWarningCallOut';
|
||||
|
|
|
@ -33,7 +33,7 @@ describe('<RestoreSnapshot />', () => {
|
|||
testBed.component.update();
|
||||
});
|
||||
|
||||
it('shows the data streams warning when the snapshot has data streams', () => {
|
||||
test('shows the data streams warning when the snapshot has data streams', () => {
|
||||
const { exists } = testBed;
|
||||
expect(exists('dataStreamWarningCallOut')).toBe(true);
|
||||
});
|
||||
|
@ -49,7 +49,7 @@ describe('<RestoreSnapshot />', () => {
|
|||
testBed.component.update();
|
||||
});
|
||||
|
||||
it('hides the data streams warning when the snapshot has data streams', () => {
|
||||
test('hides the data streams warning when the snapshot has data streams', () => {
|
||||
const { exists } = testBed;
|
||||
expect(exists('dataStreamWarningCallOut')).toBe(false);
|
||||
});
|
||||
|
@ -65,7 +65,7 @@ describe('<RestoreSnapshot />', () => {
|
|||
testBed.component.update();
|
||||
});
|
||||
|
||||
it('shows an info callout when include_global_state is enabled', () => {
|
||||
test('shows an info callout when include_global_state is enabled', () => {
|
||||
const { exists, actions } = testBed;
|
||||
|
||||
expect(exists('systemIndicesInfoCallOut')).toBe(false);
|
||||
|
@ -75,4 +75,30 @@ describe('<RestoreSnapshot />', () => {
|
|||
expect(exists('systemIndicesInfoCallOut')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
// NOTE: This suite can be expanded to simulate the user setting non-default values for all of
|
||||
// the form controls and asserting that the correct payload is sent to the API.
|
||||
describe('include aliases', () => {
|
||||
beforeEach(async () => {
|
||||
httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot());
|
||||
httpRequestsMockHelpers.setRestoreSnapshotResponse({});
|
||||
|
||||
await act(async () => {
|
||||
testBed = await setup();
|
||||
});
|
||||
|
||||
testBed.component.update();
|
||||
});
|
||||
|
||||
test('is sent to the API', async () => {
|
||||
const { actions } = testBed;
|
||||
actions.toggleIncludeAliases();
|
||||
actions.goToStep(3);
|
||||
await actions.clickRestore();
|
||||
|
||||
const expectedPayload = { includeAliases: false };
|
||||
const latestRequest = server.requests[server.requests.length - 1];
|
||||
expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expectedPayload);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,10 +6,7 @@
|
|||
*/
|
||||
|
||||
export { flatten } from './flatten';
|
||||
export {
|
||||
deserializeRestoreSettings,
|
||||
serializeRestoreSettings,
|
||||
} from './restore_settings_serialization';
|
||||
export { serializeRestoreSettings } from './restore_settings_serialization';
|
||||
export {
|
||||
deserializeSnapshotDetails,
|
||||
deserializeSnapshotConfig,
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import {
|
||||
deserializeRestoreSettings,
|
||||
serializeRestoreSettings,
|
||||
} from './restore_settings_serialization';
|
||||
import { serializeRestoreSettings } from './restore_settings_serialization';
|
||||
|
||||
describe('restore_settings_serialization()', () => {
|
||||
it('should serialize blank restore settings', () => {
|
||||
|
@ -56,6 +53,7 @@ describe('restore_settings_serialization()', () => {
|
|||
indexSettings: '{"modified_setting":123}',
|
||||
ignoreIndexSettings: ['setting1'],
|
||||
ignoreUnavailable: true,
|
||||
includeAliases: true,
|
||||
})
|
||||
).toEqual({
|
||||
indices: ['foo', 'bar'],
|
||||
|
@ -66,6 +64,7 @@ describe('restore_settings_serialization()', () => {
|
|||
index_settings: { modified_setting: 123 },
|
||||
ignore_index_settings: ['setting1'],
|
||||
ignore_unavailable: true,
|
||||
include_aliases: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -76,47 +75,4 @@ describe('restore_settings_serialization()', () => {
|
|||
})
|
||||
).toEqual({});
|
||||
});
|
||||
|
||||
it('should deserialize blank restore settings', () => {
|
||||
expect(deserializeRestoreSettings({})).toEqual({});
|
||||
});
|
||||
|
||||
it('should deserialize partial restore settings', () => {
|
||||
expect(deserializeRestoreSettings({})).toEqual({});
|
||||
expect(
|
||||
deserializeRestoreSettings({
|
||||
indices: ['foo', 'bar'],
|
||||
ignore_index_settings: ['setting1'],
|
||||
partial: true,
|
||||
})
|
||||
).toEqual({
|
||||
indices: ['foo', 'bar'],
|
||||
ignoreIndexSettings: ['setting1'],
|
||||
partial: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('should deserialize full restore settings', () => {
|
||||
expect(
|
||||
deserializeRestoreSettings({
|
||||
indices: ['foo', 'bar'],
|
||||
rename_pattern: 'capture_pattern',
|
||||
rename_replacement: 'replacement_pattern',
|
||||
include_global_state: true,
|
||||
partial: true,
|
||||
index_settings: { modified_setting: 123 },
|
||||
ignore_index_settings: ['setting1'],
|
||||
ignore_unavailable: true,
|
||||
})
|
||||
).toEqual({
|
||||
indices: ['foo', 'bar'],
|
||||
renamePattern: 'capture_pattern',
|
||||
renameReplacement: 'replacement_pattern',
|
||||
includeGlobalState: true,
|
||||
partial: true,
|
||||
indexSettings: '{"modified_setting":123}',
|
||||
ignoreIndexSettings: ['setting1'],
|
||||
ignoreUnavailable: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,6 +26,7 @@ export function serializeRestoreSettings(restoreSettings: RestoreSettings): Rest
|
|||
indexSettings,
|
||||
ignoreIndexSettings,
|
||||
ignoreUnavailable,
|
||||
includeAliases,
|
||||
} = restoreSettings;
|
||||
|
||||
let parsedIndexSettings: RestoreSettingsEs['index_settings'] | undefined;
|
||||
|
@ -47,32 +48,7 @@ export function serializeRestoreSettings(restoreSettings: RestoreSettings): Rest
|
|||
index_settings: parsedIndexSettings,
|
||||
ignore_index_settings: ignoreIndexSettings,
|
||||
ignore_unavailable: ignoreUnavailable,
|
||||
};
|
||||
|
||||
return removeUndefinedSettings(settings);
|
||||
}
|
||||
|
||||
export function deserializeRestoreSettings(restoreSettingsEs: RestoreSettingsEs): RestoreSettings {
|
||||
const {
|
||||
indices,
|
||||
rename_pattern: renamePattern,
|
||||
rename_replacement: renameReplacement,
|
||||
include_global_state: includeGlobalState,
|
||||
partial,
|
||||
index_settings: indexSettings,
|
||||
ignore_index_settings: ignoreIndexSettings,
|
||||
ignore_unavailable: ignoreUnavailable,
|
||||
} = restoreSettingsEs;
|
||||
|
||||
const settings: RestoreSettings = {
|
||||
indices,
|
||||
renamePattern,
|
||||
renameReplacement,
|
||||
includeGlobalState,
|
||||
partial,
|
||||
indexSettings: indexSettings ? JSON.stringify(indexSettings) : undefined,
|
||||
ignoreIndexSettings,
|
||||
ignoreUnavailable,
|
||||
include_aliases: includeAliases,
|
||||
};
|
||||
|
||||
return removeUndefinedSettings(settings);
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface RestoreSettings {
|
|||
indexSettings?: string;
|
||||
ignoreIndexSettings?: string[];
|
||||
ignoreUnavailable?: boolean;
|
||||
includeAliases?: boolean;
|
||||
}
|
||||
|
||||
export interface RestoreSettingsEs {
|
||||
|
@ -25,6 +26,7 @@ export interface RestoreSettingsEs {
|
|||
index_settings?: { [key: string]: any };
|
||||
ignore_index_settings?: string[];
|
||||
ignore_unavailable?: boolean;
|
||||
include_aliases?: boolean;
|
||||
}
|
||||
|
||||
export interface SnapshotRestore {
|
||||
|
|
|
@ -140,6 +140,7 @@ export const RestoreSnapshotForm: React.FunctionComponent<Props> = ({
|
|||
iconType="arrowRight"
|
||||
onClick={() => onNext()}
|
||||
disabled={!validation.isValid}
|
||||
data-test-subj="nextButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.restoreForm.nextButtonLabel"
|
||||
|
@ -156,6 +157,7 @@ export const RestoreSnapshotForm: React.FunctionComponent<Props> = ({
|
|||
iconType="check"
|
||||
onClick={() => executeRestore()}
|
||||
isLoading={isSaving}
|
||||
data-test-subj="restoreButton"
|
||||
>
|
||||
{isSaving ? (
|
||||
<FormattedMessage
|
||||
|
|
|
@ -81,6 +81,7 @@ export const RestoreSnapshotStepLogistics: React.FunctionComponent<StepProps> =
|
|||
renameReplacement,
|
||||
partial,
|
||||
includeGlobalState,
|
||||
includeAliases,
|
||||
} = restoreSettings;
|
||||
|
||||
// States for choosing all indices, or a subset, including caching previously chosen subset list
|
||||
|
@ -625,6 +626,41 @@ export const RestoreSnapshotStepLogistics: React.FunctionComponent<StepProps> =
|
|||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
|
||||
{/* Include aliases */}
|
||||
<EuiDescribedFormGroup
|
||||
title={
|
||||
<EuiTitle size="s">
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.restoreForm.stepLogistics.includeAliasesTitle"
|
||||
defaultMessage="Restore aliases"
|
||||
/>
|
||||
</h3>
|
||||
</EuiTitle>
|
||||
}
|
||||
description={
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.restoreForm.stepLogistics.includeAliasesDescription"
|
||||
defaultMessage="Restores index aliases along with their associated indices."
|
||||
/>
|
||||
}
|
||||
fullWidth
|
||||
>
|
||||
<EuiFormRow hasEmptyLabelSpace={true} fullWidth>
|
||||
<EuiSwitch
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="xpack.snapshotRestore.restoreForm.stepLogistics.includeAliasesLabel"
|
||||
defaultMessage="Restore aliases"
|
||||
/>
|
||||
}
|
||||
checked={includeAliases === undefined ? true : includeAliases}
|
||||
onChange={(e) => updateRestoreSettings({ includeAliases: e.target.checked })}
|
||||
data-test-subj="includeAliasesSwitch"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiDescribedFormGroup>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -176,4 +176,5 @@ export const restoreSettingsSchema = schema.object({
|
|||
indexSettings: schema.maybe(schema.string()),
|
||||
ignoreIndexSettings: schema.maybe(schema.arrayOf(schema.string())),
|
||||
ignoreUnavailable: schema.maybe(schema.boolean()),
|
||||
includeAliases: schema.maybe(schema.boolean()),
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue