Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [S&R] Support data streams (#68078) #70595

Merged
merged 1 commit into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import './mocks';
import { setup as homeSetup } from './home.helpers';
import { setup as repositoryAddSetup } from './repository_add.helpers';
import { setup as repositoryEditSetup } from './repository_edit.helpers';
import { setup as policyAddSetup } from './policy_add.helpers';
import { setup as policyEditSetup } from './policy_edit.helpers';
import { setup as restoreSnapshotSetup } from './restore_snapshot.helpers';

export { nextTick, getRandomString, findTestSubject, TestBed } from '../../../../../test_utils';

Expand All @@ -20,4 +21,5 @@ export const pageHelpers = {
repositoryEdit: { setup: repositoryEditSetup },
policyAdd: { setup: policyAddSetup },
policyEdit: { setup: policyEditSetup },
restoreSnapshot: { setup: restoreSnapshotSetup },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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 React from 'react';

/*
* Mocking AutoSizer of the react-virtualized because it does not render children in JS DOM.
* This seems related to not being able to properly discover height and width.
*/
jest.mock('react-virtualized', () => {
const original = jest.requireActual('react-virtualized');

return {
...original,
AutoSizer: ({ children }: { children: any }) => (
<div>{children({ height: 500, width: 500 })}</div>
),
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export type PolicyFormTestSubjects =
| 'allIndicesToggle'
| 'backButton'
| 'deselectIndicesLink'
| 'allDataStreamsToggle'
| 'deselectDataStreamLink'
| 'expireAfterValueInput'
| 'expireAfterUnitSelect'
| 'ignoreUnavailableIndicesToggle'
Expand All @@ -53,4 +55,5 @@ export type PolicyFormTestSubjects =
| 'selectIndicesLink'
| 'showAdvancedCronLink'
| 'snapshotNameInput'
| 'dataStreamBadge'
| 'submitButton';
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 @kbn/eslint/no-restricted-paths */
import { registerTestBed, TestBed, TestBedConfig } from '../../../../../test_utils';
import { RestoreSnapshot } from '../../../public/application/sections/restore_snapshot';
import { WithAppDependencies } from './setup_environment';

const testBedConfig: TestBedConfig = {
memoryRouter: {
initialEntries: ['/add_policy'],
componentRoutePath: '/add_policy',
},
doMountAsync: true,
};

const initTestBed = registerTestBed<RestoreSnapshotFormTestSubject>(
WithAppDependencies(RestoreSnapshot),
testBedConfig
);

const setupActions = (testBed: TestBed<RestoreSnapshotFormTestSubject>) => {
const { find } = testBed;
return {
findDataStreamCallout() {
return find('dataStreamWarningCallOut');
},
};
};

type Actions = ReturnType<typeof setupActions>;

export type RestoreSnapshotTestBed = TestBed<RestoreSnapshotFormTestSubject> & {
actions: Actions;
};

export const setup = async (): Promise<RestoreSnapshotTestBed> => {
const testBed = await initTestBed();

return {
...testBed,
actions: setupActions(testBed),
};
};

export type RestoreSnapshotFormTestSubject =
| 'snapshotRestoreStepLogistics'
| 'dataStreamWarningCallOut';
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ export const setupEnvironment = () => {
};
};

/**
* Suppress error messages about Worker not being available in JS DOM.
*/
(window as any).Worker = function Worker() {
this.postMessage = () => {};
this.terminate = () => {};
};

export const WithAppDependencies = (Comp: any) => (props: any) => (
<AppContextProvider value={appDependencies as any}>
<Comp {...props} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

// import helpers first, this also sets up the mocks
import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers';

import { act } from 'react-dom/test-utils';

import * as fixtures from '../../test/fixtures';

import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers';
import { PolicyFormTestBed } from './helpers/policy_form.helpers';
import { DEFAULT_POLICY_SCHEDULE } from '../../public/application/constants';

Expand Down Expand Up @@ -37,7 +40,10 @@ describe('<PolicyAdd />', () => {
describe('on component mount', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setLoadRepositoriesResponse({ repositories: [repository] });
httpRequestsMockHelpers.setLoadIndicesResponse({ indices: ['my_index'] });
httpRequestsMockHelpers.setLoadIndicesResponse({
indices: ['my_index'],
dataStreams: ['my_data_stream', 'my_other_data_stream'],
});

testBed = await setup();
await nextTick();
Expand Down Expand Up @@ -96,7 +102,7 @@ describe('<PolicyAdd />', () => {
actions.clickNextButton();
});

test('should require at least one index', async () => {
test('should require at least one index if no data streams are provided', async () => {
const { find, form, component } = testBed;

await act(async () => {
Expand All @@ -109,7 +115,22 @@ describe('<PolicyAdd />', () => {
// Deselect all indices from list
find('deselectIndicesLink').simulate('click');

expect(form.getErrorsMessages()).toEqual(['You must select at least one index.']);
expect(form.getErrorsMessages()).toEqual([
'You must select at least one data stream or index.',
]);
});

test('should correctly indicate data streams with a badge', async () => {
const { find, component, form } = testBed;

await act(async () => {
// Toggle "All indices" switch
form.toggleEuiSwitch('allIndicesToggle', false);
await nextTick();
});
component.update();

expect(find('dataStreamBadge').length).toBe(2);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ describe('<PolicyEdit />', () => {
describe('on component mount', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setGetPolicyResponse({ policy: POLICY_EDIT });
httpRequestsMockHelpers.setLoadIndicesResponse({ indices: ['my_index'] });
httpRequestsMockHelpers.setLoadIndicesResponse({
indices: ['my_index'],
dataStreams: ['my_data_stream'],
});
httpRequestsMockHelpers.setLoadRepositoriesResponse({
repositories: [{ name: POLICY_EDIT.repository }],
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { nextTick, pageHelpers, setupEnvironment } from './helpers';
import { RestoreSnapshotTestBed } from './helpers/restore_snapshot.helpers';
import * as fixtures from '../../test/fixtures';

const {
restoreSnapshot: { setup },
} = pageHelpers;

describe('<RestoreSnapshot />', () => {
const { server, httpRequestsMockHelpers } = setupEnvironment();
let testBed: RestoreSnapshotTestBed;

afterAll(() => {
server.restore();
});
describe('with data streams', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot());
testBed = await setup();
await nextTick();
testBed.component.update();
});

it('shows the data streams warning when the snapshot has data streams', () => {
const { exists } = testBed;
expect(exists('dataStreamWarningCallOut')).toBe(true);
});
});

describe('without data streams', () => {
beforeEach(async () => {
httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot({ totalDataStreams: 0 }));
testBed = await setup();
await nextTick();
testBed.component.update();
});

it('hides the data streams warning when the snapshot has data streams', () => {
const { exists } = testBed;
expect(exists('dataStreamWarningCallOut')).toBe(false);
});
});
});
2 changes: 2 additions & 0 deletions x-pack/plugins/snapshot_restore/common/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export {
serializeSnapshotRetention,
} from './snapshot_serialization';
export { deserializePolicy, serializePolicy } from './policy_serialization';
export { csvToArray } from './utils';
export { isDataStreamBackingIndex } from './is_data_stream_backing_index';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

/**
* @remark
* WARNING!
*
* This is a very hacky way of determining whether an index is a backing index.
*
* We only do this so that we can show users during a snapshot restore workflow
* that an index is part of a data stream. At the moment there is no way for us
* to get this information from the snapshot itself, even though it contains the
* metadata for the data stream that information is fully opaque to us until after
* we have done the snapshot restore.
*
* Issue for tracking this discussion here: https://github.com/elastic/elasticsearch/issues/58890
*/
export const isDataStreamBackingIndex = (indexName: string) => {
return indexName.startsWith('.ds');
};
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ describe('deserializeSnapshotDetails', () => {
version: 'version',
// Indices are sorted.
indices: ['index1', 'index2', 'index3'],
dataStreams: [],
includeGlobalState: false,
// Failures are grouped and sorted by index, and the failures themselves are sorted by shard.
indexFailures: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {

import { deserializeTime, serializeTime } from './time_serialization';

import { csvToArray } from './utils';

export function deserializeSnapshotDetails(
repository: string,
snapshotDetailsEs: SnapshotDetailsEs,
Expand All @@ -33,6 +35,7 @@ export function deserializeSnapshotDetails(
version_id: versionId,
version,
indices = [],
data_streams: dataStreams = [],
include_global_state: includeGlobalState,
state,
start_time: startTime,
Expand Down Expand Up @@ -77,6 +80,7 @@ export function deserializeSnapshotDetails(
versionId,
version,
indices: [...indices].sort(),
dataStreams: [...dataStreams].sort(),
includeGlobalState,
state,
startTime,
Expand Down Expand Up @@ -127,8 +131,10 @@ export function deserializeSnapshotConfig(snapshotConfigEs: SnapshotConfigEs): S
export function serializeSnapshotConfig(snapshotConfig: SnapshotConfig): SnapshotConfigEs {
const { indices, ignoreUnavailable, includeGlobalState, partial, metadata } = snapshotConfig;

const indicesArray = csvToArray(indices);

const snapshotConfigEs: SnapshotConfigEs = {
indices,
indices: indicesArray,
ignore_unavailable: ignoreUnavailable,
include_global_state: includeGlobalState,
partial,
Expand Down
13 changes: 13 additions & 0 deletions x-pack/plugins/snapshot_restore/common/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export const csvToArray = (indices?: string | string[]): string[] => {
return indices && Array.isArray(indices)
? indices
: typeof indices === 'string'
? indices.split(',')
: [];
};
1 change: 1 addition & 0 deletions x-pack/plugins/snapshot_restore/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './repository';
export * from './snapshot';
export * from './restore';
export * from './policy';
export * from './indices';
10 changes: 10 additions & 0 deletions x-pack/plugins/snapshot_restore/common/types/indices.ts
Original file line number Diff line number Diff line change
@@ -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.
*/

export interface PolicyIndicesResponse {
indices: string[];
dataStreams: string[];
}
2 changes: 2 additions & 0 deletions x-pack/plugins/snapshot_restore/common/types/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface SnapshotDetails {
versionId: number;
version: string;
indices: string[];
dataStreams: string[];
includeGlobalState: boolean;
state: string;
/** e.g. '2019-04-05T21:56:40.438Z' */
Expand All @@ -52,6 +53,7 @@ export interface SnapshotDetailsEs {
version_id: number;
version: string;
indices: string[];
data_streams?: string[];
include_global_state: boolean;
state: string;
/** e.g. '2019-04-05T21:56:40.438Z' */
Expand Down
Loading