From ede3cb19c548397bfbc6790736a31362472a861a Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 24 Aug 2022 18:28:41 +0000 Subject: [PATCH 001/160] Change alignment of Snapshot Management panels in pages/Main/Main.tsx Signed-off-by: Chris Hesterman --- public/pages/Main/Main.tsx | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/public/pages/Main/Main.tsx b/public/pages/Main/Main.tsx index caa574bab..2db1e7abc 100644 --- a/public/pages/Main/Main.tsx +++ b/public/pages/Main/Main.tsx @@ -171,23 +171,29 @@ export default class Main extends Component { ( - +
+ +
)} /> ( - +
+ +
)} /> ( - +
+ +
)} /> { ( -
+
)} From a5fa7fbc85a127f225c2e435715227802671fdc5 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 24 Aug 2022 21:30:40 +0000 Subject: [PATCH 002/160] Unify vertical button alignment across panels, ContentPanel.tsx Signed-off-by: Chris Hesterman --- public/components/ContentPanel/ContentPanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/components/ContentPanel/ContentPanel.tsx b/public/components/ContentPanel/ContentPanel.tsx index 59fe0e600..5beae96e2 100644 --- a/public/components/ContentPanel/ContentPanel.tsx +++ b/public/components/ContentPanel/ContentPanel.tsx @@ -40,7 +40,7 @@ const ContentPanel: React.SFC = ({ children, }) => ( - + {typeof title === "string" ? ( From 61455936d6ea2b40517aa1ebb1631e3ab3ea63c9 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 24 Aug 2022 22:37:50 +0000 Subject: [PATCH 003/160] Update jest snapshots, add ROUTE_STYLE variable Signed-off-by: Chris Hesterman --- .../__snapshots__/ContentPanel.test.tsx.snap | 2 +- .../ChangeManagedIndices.test.tsx.snap | 2 +- .../__snapshots__/NewPolicy.test.tsx.snap | 2 +- .../__snapshots__/ChangePolicy.test.tsx.snap | 4 +-- .../ConfigurePolicy.test.tsx.snap | 2 +- .../__snapshots__/DefinePolicy.test.tsx.snap | 2 +- .../__snapshots__/CreatePolicy.test.tsx.snap | 8 ++--- .../CreateRollupForm.test.tsx.snap | 4 +-- .../CreateTransformForm.test.tsx.snap | 4 +-- .../__snapshots__/EditRollup.test.tsx.snap | 4 +-- .../__snapshots__/Indices.test.tsx.snap | 2 +- public/pages/Main/Main.tsx | 32 ++++++++++--------- .../ManagedIndices.test.tsx.snap | 2 +- .../__snapshots__/Policies.test.tsx.snap | 2 +- .../PolicySettings.test.tsx.snap | 2 +- .../containers/Snapshots/Snapshots.tsx | 1 + .../__snapshots__/EditTransform.test.tsx.snap | 6 ++-- .../__snapshots__/ISMTemplates.test.tsx.snap | 2 +- .../__snapshots__/PolicyInfo.test.tsx.snap | 2 +- .../States/__snapshots__/States.test.tsx.snap | 2 +- .../ErrorNotification.test.tsx.snap | 2 +- 21 files changed, 46 insertions(+), 43 deletions(-) diff --git a/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap b/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap index 2b892c14e..4ae35fa25 100644 --- a/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap +++ b/public/components/ContentPanel/__snapshots__/ContentPanel.test.tsx.snap @@ -6,7 +6,7 @@ exports[` spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the create component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the create component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the edit component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the edit component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding: 20px 20px;" >
spec renders the component 1`] = ` style="padding: 20px 20px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
{ const { landingPage } = this.props; + const ROUTE_STYLE = { padding: "25px 25px" }; + return ( {(core: CoreStart | null) => @@ -171,7 +173,7 @@ export default class Main extends Component { ( -
+
{ ( -
+
)} @@ -191,7 +193,7 @@ export default class Main extends Component { ( -
+
)} @@ -273,7 +275,7 @@ export default class Main extends Component { ( -
+
)} @@ -281,7 +283,7 @@ export default class Main extends Component { ( -
+
)} @@ -289,7 +291,7 @@ export default class Main extends Component { ( -
+
)} @@ -297,7 +299,7 @@ export default class Main extends Component { ( -
+
)} @@ -305,7 +307,7 @@ export default class Main extends Component { ( -
+
)} @@ -313,7 +315,7 @@ export default class Main extends Component { ( -
+
)} @@ -321,7 +323,7 @@ export default class Main extends Component { ( -
+
)} @@ -329,7 +331,7 @@ export default class Main extends Component { ( -
+
)} @@ -337,7 +339,7 @@ export default class Main extends Component { ( -
+
)} @@ -345,7 +347,7 @@ export default class Main extends Component { ( -
+
{ ( -
+
)} @@ -366,7 +368,7 @@ export default class Main extends Component { ( -
+
)} diff --git a/public/pages/ManagedIndices/containers/ManagedIndices/__snapshots__/ManagedIndices.test.tsx.snap b/public/pages/ManagedIndices/containers/ManagedIndices/__snapshots__/ManagedIndices.test.tsx.snap index ef9d37583..2bc6ce8f9 100644 --- a/public/pages/ManagedIndices/containers/ManagedIndices/__snapshots__/ManagedIndices.test.tsx.snap +++ b/public/pages/ManagedIndices/containers/ManagedIndices/__snapshots__/ManagedIndices.test.tsx.snap @@ -45,7 +45,7 @@ exports[` spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
Take snapshot , + Restore, ]; const subTitleText = ( diff --git a/public/pages/Transforms/containers/Transforms/__snapshots__/EditTransform.test.tsx.snap b/public/pages/Transforms/containers/Transforms/__snapshots__/EditTransform.test.tsx.snap index 5768aaffb..088b2fd32 100644 --- a/public/pages/Transforms/containers/Transforms/__snapshots__/EditTransform.test.tsx.snap +++ b/public/pages/Transforms/containers/Transforms/__snapshots__/EditTransform.test.tsx.snap @@ -17,7 +17,7 @@ exports[` spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
spec renders the component 1`] = ` style="padding-left: 0px; padding-right: 0px;" >
Date: Wed, 24 Aug 2022 23:17:45 +0000 Subject: [PATCH 004/160] Add placeholder restore button to Snapshots panel Signed-off-by: Chris Hesterman --- public/pages/Snapshots/containers/Snapshots/Snapshots.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index eccc32b7f..b41e09ba1 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -269,7 +269,9 @@ export default class Snapshots extends Component Take snapshot , - Restore, + + Restore + , ]; const subTitleText = ( From 8001349b23097cbed299ec2d0d88f9d60a13d27b Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 26 Aug 2022 22:40:10 +0000 Subject: [PATCH 005/160] Comment out line 20 rollups_spec.js in cypress/integration/ Signed-off-by: Chris Hesterman --- cypress/integration/rollups_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress/integration/rollups_spec.js b/cypress/integration/rollups_spec.js index 70aa508e2..d4fbb1aa3 100644 --- a/cypress/integration/rollups_spec.js +++ b/cypress/integration/rollups_spec.js @@ -17,7 +17,7 @@ describe("Rollups", () => { cy.visit(`${Cypress.env("opensearch_dashboards")}/app/home#/tutorial_directory/sampleData`); // Click on "Sample data" tab - cy.contains("Sample data").click({ force: true }); + // cy.contains("Sample data").click({ force: true }); // Load sample eCommerce data cy.get(`button[data-test-subj="addSampleDataSetecommerce"]`).click({ force: true }); From f27c4e471df1c5e53dedd5fe1682bb637ac3317f Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 26 Aug 2022 23:11:02 +0000 Subject: [PATCH 006/160] Remove unused code and comment cypress/integration/rollups_spec.js Signed-off-by: Chris Hesterman --- cypress/integration/rollups_spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/cypress/integration/rollups_spec.js b/cypress/integration/rollups_spec.js index d4fbb1aa3..896a06271 100644 --- a/cypress/integration/rollups_spec.js +++ b/cypress/integration/rollups_spec.js @@ -16,8 +16,6 @@ describe("Rollups", () => { // Go to sample data page cy.visit(`${Cypress.env("opensearch_dashboards")}/app/home#/tutorial_directory/sampleData`); - // Click on "Sample data" tab - // cy.contains("Sample data").click({ force: true }); // Load sample eCommerce data cy.get(`button[data-test-subj="addSampleDataSetecommerce"]`).click({ force: true }); From 391159fe84d1da9fd42d89ac58806d47a99e0760 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 10:42:54 -0700 Subject: [PATCH 007/160] Starting adaptation/use of existing code for Restore functionality Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 220 ++++++++++++++++++ .../components/RestoreSnapshotFlyout/index.ts | 8 + 2 files changed, 228 insertions(+) create mode 100644 public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx create mode 100644 public/pages/Snapshots/components/RestoreSnapshotFlyout/index.ts diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx new file mode 100644 index 000000000..ac55a625f --- /dev/null +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -0,0 +1,220 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiAccordion, + EuiComboBoxOptionOption, + EuiFieldText, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiFormRow, + EuiSpacer, + EuiTitle, +} from "@elastic/eui"; +import _ from "lodash"; + +import React, { Component } from "react"; +import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; +import { CoreServicesContext } from "../../../../components/core_services"; +import { IndexService, SnapshotManagementService } from "../../../../services"; +import { getErrorMessage, wildcardOption } from "../../../../utils/helpers"; +import { IndexItem, Snapshot } from "../../../../../models/interfaces"; +import { CatRepository } from "../../../../../server/models/interfaces"; +import CustomLabel from "../../../../components/CustomLabel"; +import { getEmptySnapshot } from "../CreateSnapshotFlyout/constants"; +import SnapshotAdvancedSettings from "../../../CreateSnapshotPolicy/components/SnapshotAdvancedSettings"; +import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; +import { ChangeEvent } from "react"; +import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; + +interface RestoreSnapshotProps { + snapshotManagementService: SnapshotManagementService; + indexService: IndexService; + onCloseFlyout: () => void; + restoreSnapshot: (snapshotId: string, repository: string) => void; +} + +interface RestoreSnapshotState { + indexOptions: EuiComboBoxOptionOption[]; + selectedIndexOptions: EuiComboBoxOptionOption[]; + + repositories: CatRepository[]; + selectedRepoValue: string; + + snapshot: Snapshot; + snapshotId: string; + + repoError: string; + snapshotIdError: string; +} + +export default class RestoreSnapshotFlyout extends Component { + static contextType = CoreServicesContext; + constructor(props: RestoreSnapshotProps) { + super(props); + + this.state = { + indexOptions: [], + selectedIndexOptions: [], + repositories: [], + selectedRepoValue: "", + snapshot: getEmptySnapshot(), + snapshotId: "", + repoError: "", + snapshotIdError: "", + }; + } + + async componentDidMount() { + await this.getIndexOptions(""); + await this.getRepos(); + } + + onClickAction = () => { + const { restoreSnapshot } = this.props; + const { snapshotId, selectedRepoValue } = this.state; + let repoError = ""; + if (!snapshotId.trim()) { + this.setState({ snapshotIdError: "Required" }); + return; + } + if (!selectedRepoValue) { + repoError = ERROR_PROMPT.REPO; + this.setState({ repoError }); + return; + } + restoreSnapshot(snapshotId, selectedRepoValue); + }; + + onIndicesSelectionChange = (selectedOptions: EuiComboBoxOptionOption[]) => { + const selectedIndexOptions = selectedOptions.map((o) => o.label); + let newJSON = this.state.snapshot; + newJSON.indices = selectedIndexOptions.toString(); + this.setState({ snapshot: newJSON, selectedIndexOptions: selectedOptions }); + }; + + getIndexOptions = async (searchValue: string) => { + const { indexService } = this.props; + this.setState({ indexOptions: [] }); + try { + const optionsResponse = await indexService.getDataStreamsAndIndicesNames(searchValue); + if (optionsResponse.ok) { + // Adding wildcard to search value + const options = searchValue.trim() ? [{ label: wildcardOption(searchValue) }, { label: searchValue }] : []; + // const dataStreams = optionsResponse.response.dataStreams.map((label) => ({ label })); + const indices = optionsResponse.response.indices.map((label) => ({ label })); + // this.setState({ indexOptions: options.concat(dataStreams, indices)}); + this.setState({ indexOptions: options.concat(indices) }); + } else { + if (optionsResponse.error.startsWith("[index_not_found_exception]")) { + this.context.notifications.toasts.addDanger("No index available"); + } else { + this.context.notifications.toasts.addDanger(optionsResponse.error); + } + } + } catch (err) { + this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem fetching index options.")); + } + }; + + onCreateOption = (searchValue: string, options: Array>) => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); + if (!normalizedSearchValue) { + return; + } + const newOption = { + label: searchValue, + }; + // Create the option if it doesn't exist. + if (options.findIndex((option) => option.label.trim().toLowerCase() === normalizedSearchValue) === -1) { + this.setState({ indexOptions: [...this.state.indexOptions, newOption] }); + } + + const selectedIndexOptions = [...this.state.selectedIndexOptions, newOption]; + this.setState({ selectedIndexOptions: selectedIndexOptions }); + }; + + getRepos = async () => { + try { + const { snapshotManagementService } = this.props; + const response = await snapshotManagementService.catRepositories(); + if (response.ok) { + const selectedRepoValue = response.response.length > 0 ? response.response[0].id : ""; + this.setState({ repositories: response.response, selectedRepoValue }); + } else { + this.context.notifications.toasts.addDanger(response.error); + } + } catch (err) { + this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem loading the snapshots.")); + } + }; + + onRepoSelectionChange = (e: React.ChangeEvent) => { + const selectedRepo = e.target.value; + let repoError = ""; + if (!selectedRepo) { + repoError = ERROR_PROMPT.REPO; + } + this.setState({ selectedRepoValue: selectedRepo, repoError }); + }; + + // onIncludeGlobalStateToggle = (e: ChangeEvent) => { + // this.setState({ snapshot: _.set(this.state.snapshot, "include_global_state", e.target.checked) }); + // }; + + // onIgnoreUnavailableToggle = (e: ChangeEvent) => { + // this.setState({ snapshot: _.set(this.state.snapshot, "ignore_unavailable", e.target.checked) }); + // }; + + // onPartialToggle = (e: ChangeEvent) => { + // const { checked } = e.target; + // let newJSON = this.state.snapshot; + // newJSON.partial = checked; + // this.setState({ snapshot: newJSON }); + // }; + + render() { + const { onCloseFlyout } = this.props; + const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, snapshotId, repoError, snapshotIdError } = this.state; + + const repoOptions = repositories.map((r) => ({ value: r.id, text: r.id })); + + return ( + + + +

Restore snapshot

+
+
+ + + + + + + + + + + + + + +
+ ); + } +} diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/index.ts b/public/pages/Snapshots/components/RestoreSnapshotFlyout/index.ts new file mode 100644 index 000000000..b5a24d1da --- /dev/null +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import RestoreSnapshotFlyout from "./RestoreSnapshotFlyout"; + +export default RestoreSnapshotFlyout; From 983ed48035a72fbcde1689ef7ce83a0bf1bd9aee Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 10:53:11 -0700 Subject: [PATCH 008/160] Adapt Snapshots.tsx to include RestoreSnapshotFlyout Signed-off-by: Chris Hesterman --- .../containers/Snapshots/Snapshots.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index b41e09ba1..ec8929b89 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -15,6 +15,7 @@ import { CatSnapshotWithRepoAndPolicy as SnapshotsWithRepoAndPolicy } from "../. import { ContentPanel } from "../../../../components/ContentPanel"; import SnapshotFlyout from "../../components/SnapshotFlyout/SnapshotFlyout"; import CreateSnapshotFlyout from "../../components/CreateSnapshotFlyout/CreateSnapshotFlyout"; +import RestoreSnapshotFlyout from "../../components/RestoreSnapshotFlyout/RestoreSnapshotFlyout"; import { Snapshot } from "../../../../../models/interfaces"; import { BREADCRUMBS, RESTORE_SNAPSHOT_DOCUMENTATION_URL, ROUTES } from "../../../../utils/constants"; import { renderTimestampMillis } from "../../../SnapshotPolicies/helpers"; @@ -38,6 +39,7 @@ interface SnapshotsState { flyoutSnapshotRepo: string; showCreateFlyout: boolean; + showRestoreFlyout: boolean; message?: React.ReactNode; @@ -60,6 +62,7 @@ export default class Snapshots extends Component flyoutSnapshotId: "", flyoutSnapshotRepo: "", showCreateFlyout: false, + showRestoreFlyout: false, message: null, isDeleteModalVisible: false, }; @@ -215,6 +218,30 @@ export default class Snapshots extends Component } }; + restoreSnapshot = async (snapshotId: string, repository: string) => { + try { + const { snapshotManagementService } = this.props; + const response = await snapshotManagementService.restoreSnapshot(snapshotId, repository); + if (response.ok) { + this.context.notifications.toasts.addSuccess(`Restored snapshot ${snapshotId} to repository ${repository}.`); + } else { + this.context.notifications.toasts.addDanger(response.error); + } + } catch (err) { + this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem restoring the snapshot.")); + } + }; + + onClickRestore = async () => { + const { selectedItems } = this.state; + await this.restoreSnapshot(selectedItems[0].id, selectedItems[0].repository); + this.setState({ showRestoreFlyout: true }); + }; + + onCloseRestoreFlyout = () => { + this.setState({ showRestoreFlyout: false }); + }; + render() { const { snapshots, @@ -225,6 +252,7 @@ export default class Snapshots extends Component flyoutSnapshotId, flyoutSnapshotRepo, showCreateFlyout, + showRestoreFlyout, isDeleteModalVisible, } = this.state; @@ -326,6 +354,15 @@ export default class Snapshots extends Component /> )} + {showRestoreFlyout && ( + + )} + {isDeleteModalVisible && ( Date: Mon, 29 Aug 2022 11:01:04 -0700 Subject: [PATCH 009/160] Add restoreSnapshot method to SMservice,RestoreSnapshotResponse int Signed-off-by: Chris Hesterman --- public/services/SnapshotManagementService.ts | 7 +++++++ server/models/interfaces.ts | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 7035bed04..e985381d0 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -13,6 +13,7 @@ import { CreateRepositoryBody, AcknowledgedResponse, CreateSnapshotResponse, + RestoreSnapshotResponse, } from "../../server/models/interfaces"; import { ServerResponse } from "../../server/models/types"; import { DocumentSMPolicy, DocumentSMPolicyWithMetadata, SMPolicy, Snapshot } from "../../models/interfaces"; @@ -50,6 +51,12 @@ export default class SnapshotManagementService { return response; }; + restoreSnapshot = async (snapshotId: string, repository: string): Promise> => { + let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; + const response = (await this.httpClient.put(url, { query: { repository } })) as ServerResponse; + return response; + }; + createPolicy = async (policyId: string, policy: SMPolicy): Promise> => { let url = `..${NODE_API.SMPolicies}/${policyId}`; const response = (await this.httpClient.post(url, { body: JSON.stringify(policy) })) as ServerResponse; diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index f93626352..9592cc7a5 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -386,6 +386,10 @@ export interface CreateSnapshotResponse { snapshot: GetSnapshot; } +export interface RestoreSnapshotResponse { + snapshot: GetSnapshot; +} + export interface GetSnapshot { snapshot: string; uuid: string; From b3141bd7758db4b7d12c8fe82c4bdd791375eac9 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 11:08:07 -0700 Subject: [PATCH 010/160] Implement RestoreSnapshotFlyout open/close Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 13 +------------ .../Snapshots/containers/Snapshots/Snapshots.tsx | 4 ++-- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index ac55a625f..b57614ff3 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -3,18 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - EuiAccordion, - EuiComboBoxOptionOption, - EuiFieldText, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiFormRow, - EuiSpacer, - EuiTitle, -} from "@elastic/eui"; +import { EuiComboBoxOptionOption, EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, EuiSpacer, EuiTitle } from "@elastic/eui"; import _ from "lodash"; import React, { Component } from "react"; diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index ec8929b89..e57c35afd 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -297,7 +297,7 @@ export default class Snapshots extends Component Take snapshot , - + Restore , ]; @@ -358,7 +358,7 @@ export default class Snapshots extends Component )} From 7bfdb86956e46958d584a5cd7bc08a2245ceb49c Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 11:18:06 -0700 Subject: [PATCH 011/160] Make Snapshot name appear on RestoreSnapshotFlyout Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 8 +++++--- public/pages/Snapshots/containers/Snapshots/Snapshots.tsx | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index b57614ff3..d82d3e2ed 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -25,6 +25,7 @@ interface RestoreSnapshotProps { indexService: IndexService; onCloseFlyout: () => void; restoreSnapshot: (snapshotId: string, repository: string) => void; + snapshotId: string; } interface RestoreSnapshotState { @@ -167,8 +168,8 @@ export default class RestoreSnapshotFlyout extends Component ({ value: r.id, text: r.id })); @@ -176,12 +177,13 @@ export default class RestoreSnapshotFlyout extends Component -

Restore snapshot

+

Restore snapshot

+

{snapshotId}

diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index e57c35afd..98318683c 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -360,6 +360,7 @@ export default class Snapshots extends Component indexService={this.props.indexService} onCloseFlyout={this.onCloseRestoreFlyout} restoreSnapshot={this.restoreSnapshot} + snapshotId={snapshots[0].id} /> )} From 845cca2129f296cf4f9681c8d3a1c5dcb5c12197 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 11:29:54 -0700 Subject: [PATCH 012/160] Add/adapt restoreSnapshot to server/SnapshotManagementService Signed-off-by: Chris Hesterman --- server/services/SnapshotManagementService.ts | 32 ++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 84d405fca..014ad2762 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -23,6 +23,7 @@ import { GetRepositoryResponse, AcknowledgedResponse, CreateSnapshotResponse, + RestoreSnapshotResponse, } from "../models/interfaces"; import { FailedServerResponse, ServerResponse } from "../models/types"; @@ -187,6 +188,37 @@ export default class SnapshotManagementService { } }; + restoreSnapshot = async ( + context: RequestHandlerContext, + request: OpenSearchDashboardsRequest, + response: OpenSearchDashboardsResponseFactory + ): Promise>> => { + try { + const { id } = request.params as { + id: string; + }; + const { repository } = request.query as { + repository: string; + }; + const params = { + repository: repository, + snapshot: id, + }; + const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); + const resp: RestoreSnapshotResponse = await callWithRequest("snapshot.restore", params); + + return response.custom({ + statusCode: 200, + body: { + ok: true, + response: resp, + }, + }); + } catch (err) { + return this.errorResponse(response, err, "restoreSnapshot"); + } + }; + createPolicy = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, From 703d93b31c90c69ac8dd42f64406d945bf0fb06f Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 11:38:26 -0700 Subject: [PATCH 013/160] Add route for restoreSnapshot in server/routes.ts Signed-off-by: Chris Hesterman --- server/routes/snapshotManagement.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index 13cf02a4b..ba64335bb 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -65,6 +65,21 @@ export default function (services: NodeServices, router: IRouter) { snapshotManagementService.createSnapshot ); + router.post( + { + path: `${NODE_API._SNAPSHOTS}/{id}`, + validate: { + params: schema.object({ + id: schema.string(), + }), + query: schema.object({ + repository: schema.string(), + }), + }, + }, + snapshotManagementService.restoreSnapshot + ); + router.post( { path: `${NODE_API.SMPolicies}/{id}`, From 78095b705c1b63c0255eb2f436e944512c617dd3 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 15:00:21 -0700 Subject: [PATCH 014/160] Rudimentary restore from snapshot functionality reached, buggy Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 73 +++++++------------ .../SnapshotFlyout/SnapshotFlyout.tsx | 1 + .../containers/Snapshots/Snapshots.tsx | 2 - public/services/SnapshotManagementService.ts | 2 +- 4 files changed, 30 insertions(+), 48 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index d82d3e2ed..7e7d484ee 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -5,19 +5,16 @@ import { EuiComboBoxOptionOption, EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, EuiSpacer, EuiTitle } from "@elastic/eui"; import _ from "lodash"; - import React, { Component } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; import { CoreServicesContext } from "../../../../components/core_services"; import { IndexService, SnapshotManagementService } from "../../../../services"; -import { getErrorMessage, wildcardOption } from "../../../../utils/helpers"; -import { IndexItem, Snapshot } from "../../../../../models/interfaces"; -import { CatRepository } from "../../../../../server/models/interfaces"; +import { getErrorMessage } from "../../../../utils/helpers"; +import { IndexItem } from "../../../../../models/interfaces"; +import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; -import { getEmptySnapshot } from "../CreateSnapshotFlyout/constants"; import SnapshotAdvancedSettings from "../../../CreateSnapshotPolicy/components/SnapshotAdvancedSettings"; import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; -import { ChangeEvent } from "react"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; interface RestoreSnapshotProps { @@ -35,7 +32,7 @@ interface RestoreSnapshotState { repositories: CatRepository[]; selectedRepoValue: string; - snapshot: Snapshot; + snapshot: GetSnapshot | null; snapshotId: string; repoError: string; @@ -52,7 +49,7 @@ export default class RestoreSnapshotFlyout extends Component { - const { restoreSnapshot } = this.props; - const { snapshotId, selectedRepoValue } = this.state; + const { restoreSnapshot, snapshotId } = this.props; + const { selectedRepoValue } = this.state; let repoError = ""; + console.log("clicked"); if (!snapshotId.trim()) { this.setState({ snapshotIdError: "Required" }); + return; } if (!selectedRepoValue) { repoError = ERROR_PROMPT.REPO; this.setState({ repoError }); + return; } restoreSnapshot(snapshotId, selectedRepoValue); @@ -83,34 +83,32 @@ export default class RestoreSnapshotFlyout extends Component[]) => { const selectedIndexOptions = selectedOptions.map((o) => o.label); let newJSON = this.state.snapshot; - newJSON.indices = selectedIndexOptions.toString(); + // newJSON.indices = selectedIndexOptions.toString(); this.setState({ snapshot: newJSON, selectedIndexOptions: selectedOptions }); }; - getIndexOptions = async (searchValue: string) => { - const { indexService } = this.props; - this.setState({ indexOptions: [] }); + getSnapshot = async (snapshotId: string, repository: string) => { + console.log("flyout", [repository, snapshotId]); + console.log("repositories", [...this.state.repositories]); + const { snapshotManagementService } = this.props; try { - const optionsResponse = await indexService.getDataStreamsAndIndicesNames(searchValue); - if (optionsResponse.ok) { - // Adding wildcard to search value - const options = searchValue.trim() ? [{ label: wildcardOption(searchValue) }, { label: searchValue }] : []; - // const dataStreams = optionsResponse.response.dataStreams.map((label) => ({ label })); - const indices = optionsResponse.response.indices.map((label) => ({ label })); - // this.setState({ indexOptions: options.concat(dataStreams, indices)}); - this.setState({ indexOptions: options.concat(indices) }); - } else { - if (optionsResponse.error.startsWith("[index_not_found_exception]")) { - this.context.notifications.toasts.addDanger("No index available"); - } else { - this.context.notifications.toasts.addDanger(optionsResponse.error); - } + const response = await snapshotManagementService.getSnapshot(snapshotId, repository); + console.log("my response", response); + if (response.ok) { + const newOptions = response.response.indices.map((index) => { + return { label: index }; + }); + this.setState({ snapshot: response.response, indexOptions: [...newOptions] }); } } catch (err) { - this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem fetching index options.")); + this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem loading the snapshot.")); } }; + getIndexOptions = () => { + this.getSnapshot(this.props.snapshotId, this.state.selectedRepoValue); + }; + onCreateOption = (searchValue: string, options: Array>) => { const normalizedSearchValue = searchValue.trim().toLowerCase(); if (!normalizedSearchValue) { @@ -152,21 +150,6 @@ export default class RestoreSnapshotFlyout extends Component) => { - // this.setState({ snapshot: _.set(this.state.snapshot, "include_global_state", e.target.checked) }); - // }; - - // onIgnoreUnavailableToggle = (e: ChangeEvent) => { - // this.setState({ snapshot: _.set(this.state.snapshot, "ignore_unavailable", e.target.checked) }); - // }; - - // onPartialToggle = (e: ChangeEvent) => { - // const { checked } = e.target; - // let newJSON = this.state.snapshot; - // newJSON.partial = checked; - // this.setState({ snapshot: newJSON }); - // }; - render() { const { onCloseFlyout, snapshotId } = this.props; const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, repoError } = this.state; diff --git a/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx b/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx index 8901f9ef6..7864dafbc 100644 --- a/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx @@ -55,6 +55,7 @@ export default class SnapshotFlyout extends Component { + console.log("flyout"); const { snapshotManagementService } = this.props; try { const response = await snapshotManagementService.getSnapshot(snapshotId, repository); diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 98318683c..4bbec9c5b 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -233,8 +233,6 @@ export default class Snapshots extends Component }; onClickRestore = async () => { - const { selectedItems } = this.state; - await this.restoreSnapshot(selectedItems[0].id, selectedItems[0].repository); this.setState({ showRestoreFlyout: true }); }; diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index e985381d0..564358e66 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -53,7 +53,7 @@ export default class SnapshotManagementService { restoreSnapshot = async (snapshotId: string, repository: string): Promise> => { let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; - const response = (await this.httpClient.put(url, { query: { repository } })) as ServerResponse; + const response = (await this.httpClient.post(url, { query: { repository } })) as ServerResponse; return response; }; From e16528b2a82e8200455ab543e4722d06a001a724 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 29 Aug 2022 16:27:39 -0700 Subject: [PATCH 015/160] Fix index list-snapshot restore, restrict restore to single selection Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 1 + .../Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx | 1 - public/pages/Snapshots/containers/Snapshots/Snapshots.tsx | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 7e7d484ee..b70e772b2 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -78,6 +78,7 @@ export default class RestoreSnapshotFlyout extends Component[]) => { diff --git a/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx b/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx index 7864dafbc..8901f9ef6 100644 --- a/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/SnapshotFlyout/SnapshotFlyout.tsx @@ -55,7 +55,6 @@ export default class SnapshotFlyout extends Component { - console.log("flyout"); const { snapshotManagementService } = this.props; try { const response = await snapshotManagementService.getSnapshot(snapshotId, repository); diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 4bbec9c5b..f67007921 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -295,7 +295,7 @@ export default class Snapshots extends Component Take snapshot , - + Restore , ]; @@ -358,7 +358,7 @@ export default class Snapshots extends Component indexService={this.props.indexService} onCloseFlyout={this.onCloseRestoreFlyout} restoreSnapshot={this.restoreSnapshot} - snapshotId={snapshots[0].id} + snapshotId={selectedItems[0].id} /> )} From 75e1dfeb03176838c250d41117ba96bb6ca2bf05 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 6 Sep 2022 14:53:38 -0700 Subject: [PATCH 016/160] Remove console.logs, commented out code Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index b70e772b2..af5c4ecaf 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -65,7 +65,7 @@ export default class RestoreSnapshotFlyout extends Component[]) => { const selectedIndexOptions = selectedOptions.map((o) => o.label); let newJSON = this.state.snapshot; - // newJSON.indices = selectedIndexOptions.toString(); + this.setState({ snapshot: newJSON, selectedIndexOptions: selectedOptions }); }; From 02d651cc2abfe019d9b94def2cfdb1312e7145d7 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 30 Aug 2022 11:20:01 -0700 Subject: [PATCH 017/160] Create Advanced options accordion for Snapshot restore. Signed-off-by: Chris Hesterman Currently only visually functional. TODO - make it apply the options Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 93 +++++++++++--- .../SnapshotRestoreAdvancedOptions.tsx | 114 ++++++++++++++++++ .../SnapshotRestoreAdvancedOptions/index.ts | 8 ++ 3 files changed, 198 insertions(+), 17 deletions(-) create mode 100644 public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx create mode 100644 public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/index.ts diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index af5c4ecaf..268f3356b 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -3,9 +3,21 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiComboBoxOptionOption, EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, EuiSpacer, EuiTitle } from "@elastic/eui"; +import { + EuiComboBoxOptionOption, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiSpacer, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiRadioGroup, + EuiAccordion, +} from "@elastic/eui"; import _ from "lodash"; -import React, { Component } from "react"; +import React, { Component, ChangeEvent } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; import { CoreServicesContext } from "../../../../components/core_services"; import { IndexService, SnapshotManagementService } from "../../../../services"; @@ -13,7 +25,7 @@ import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; -import SnapshotAdvancedSettings from "../../../CreateSnapshotPolicy/components/SnapshotAdvancedSettings"; +import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; @@ -151,14 +163,38 @@ export default class RestoreSnapshotFlyout extends Component) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "restore_aliases", e.target.checked) }); + }; + + onRestoreClusterStateToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "restore_cluster_state", e.target.checked) }); + }; + + onIgnoreUnavailableToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "ignore_unavailable", e.target.checked) }); + }; + + onRestorePartialToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "restore_partial", e.target.checked) }); + }; + + onCustomizeIndexSettingsToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "customize_index_settings", e.target.checked) }); + }; + + onIgnoreIndexSettingsToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "ignore_index_settings", e.target.checked) }); + }; + render() { - const { onCloseFlyout, snapshotId } = this.props; - const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, repoError } = this.state; + const { onCloseFlyout } = this.props; + const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, restoreSpecific, repoError, snapshot } = this.state; const repoOptions = repositories.map((r) => ({ value: r.id, text: r.id })); return ( - +

Restore snapshot

@@ -171,17 +207,40 @@ export default class RestoreSnapshotFlyout extends Component - + {restoreSpecific && ( + + )} + + + + + + +
diff --git a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx new file mode 100644 index 000000000..9de6f79ca --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx @@ -0,0 +1,114 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiCheckbox, EuiSpacer, EuiText } from "@elastic/eui"; +import CustomLabel from "../../../../components/CustomLabel"; +import React, { ChangeEvent } from "react"; + +interface SnapshotAdvancedOptionsProps { + restoreAliases: boolean; + onRestoreAliasesToggle: (e: ChangeEvent) => void; + restoreClusterState: boolean; + onRestoreClusterStateToggle: (e: ChangeEvent) => void; + ignoreUnavailable: boolean; + onIgnoreUnavailableToggle: (e: ChangeEvent) => void; + restorePartial: boolean; + onRestorePartialToggle: (e: ChangeEvent) => void; + customizeIndexSettings: boolean; + onCustomizeIndexSettingsToggle: (e: ChangeEvent) => void; + ignoreIndexSettings: boolean; + onIgnoreIndexSettingsToggle: (e: ChangeEvent) => void; + width?: string; +} + +const SnapshotRestoreAdvancedOptions = ({ + restoreAliases, + onRestoreAliasesToggle, + ignoreUnavailable, + onIgnoreUnavailableToggle, + restoreClusterState, + onRestoreClusterStateToggle, + restorePartial, + onRestorePartialToggle, + customizeIndexSettings, + onCustomizeIndexSettingsToggle, + ignoreIndexSettings, + onIgnoreIndexSettingsToggle, + width, +}: SnapshotAdvancedOptionsProps) => ( +
+ } + checked={restoreAliases} + onChange={onRestoreAliasesToggle} + /> + + + + } + checked={restoreClusterState} + onChange={onRestoreClusterStateToggle} + /> + + + + + } + checked={ignoreUnavailable} + onChange={onIgnoreUnavailableToggle} + /> + + + + } + checked={restorePartial} + onChange={onRestorePartialToggle} + /> + + + +
Custom index settings
+ +

+ By default, index settings are restored from indices in snapshots. You can choose to +
+ customize index settings on restore. +

+
+ + + + } + checked={customizeIndexSettings} + onChange={onCustomizeIndexSettingsToggle} + /> + + + + + } + checked={ignoreIndexSettings} + onChange={onIgnoreIndexSettingsToggle} + /> +
+); + +export default SnapshotRestoreAdvancedOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/index.ts b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/index.ts new file mode 100644 index 000000000..940d333c3 --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import SnapshotRestoreAdvancedOptions from "./SnapshotRestoreAdvancedOptions"; + +export default SnapshotRestoreAdvancedOptions; From bf4a4a56e29a467c67b96d45bef4b8b8126f6c6d Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 30 Aug 2022 13:19:58 -0700 Subject: [PATCH 018/160] Add initial restore/rename options to ui. Only visual functionality Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 46 ++++++++- .../SnapshotRestoreInitialOptions.tsx | 96 +++++++++++++++++++ .../SnapshotRestoreInitialOptions/index.ts | 8 ++ 3 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx create mode 100644 public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 268f3356b..ca8866990 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -13,7 +13,6 @@ import { EuiTitle, EuiFlexGroup, EuiFlexItem, - EuiRadioGroup, EuiAccordion, } from "@elastic/eui"; import _ from "lodash"; @@ -26,6 +25,7 @@ import { IndexItem } from "../../../../../models/interfaces"; import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; +import SnapshotRestoreInitialOptions from "../SnapshotRestoreInitialOptions"; import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; @@ -63,6 +63,7 @@ export default class RestoreSnapshotFlyout extends Component { - console.log("flyout", [repository, snapshotId]); - console.log("repositories", [...this.state.repositories]); const { snapshotManagementService } = this.props; + try { const response = await snapshotManagementService.getSnapshot(snapshotId, repository); - console.log("my response", response); + if (response.ok) { const newOptions = response.response.indices.map((index) => { return { label: index }; @@ -163,6 +163,26 @@ export default class RestoreSnapshotFlyout extends Component) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "restore_all_indices", e.target.checked) }); + }; + + onRestoreSpecificIndicesToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "restore_specific_indices", e.target.checked) }); + }; + + onDoNotRenameToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "do_not_rename", e.target.checked) }); + }; + + onAddPrefixToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "add_prefix", e.target.checked) }); + }; + + onRenameIndicesToggle = (e: ChangeEvent) => { + this.setState({ snapshot: _.set(this.state.snapshot!, "rename_indices", e.target.checked) }); + }; + onRestoreAliasesToggle = (e: ChangeEvent) => { this.setState({ snapshot: _.set(this.state.snapshot!, "restore_aliases", e.target.checked) }); }; @@ -205,7 +225,23 @@ export default class RestoreSnapshotFlyout extends Component

{snapshotId}

- + + + {!restoreSpecific && ( + + )} {restoreSpecific && ( ) => void; + restoreSpecificIndices: boolean; + onRestoreSpecificIndicesToggle: (e: ChangeEvent) => void; + doNotRename: boolean; + onDoNotRenameToggle: (e: ChangeEvent) => void; + addPrefix: boolean; + onAddPrefixToggle: (e: ChangeEvent) => void; + renameIndices: boolean; + onRenameIndicesToggle: (e: ChangeEvent) => void; + width: string; +} + +const SnapshotRestoreInitialOptions = ({ + restoreAllIndices, + onRestoreAllIndicesToggle, + restoreSpecificIndices, + onRestoreSpecificIndicesToggle, + doNotRename, + onDoNotRenameToggle, + addPrefix, + onAddPrefixToggle, + renameIndices, + onRenameIndicesToggle, + width, +}: SnapshotInitialOptionsProps) => ( +
+
Specify restore option
+ + + + } + checked={true} + onChange={onRestoreAllIndicesToggle} + /> + + + + } + checked={restoreSpecificIndices} + onChange={onRestoreSpecificIndicesToggle} + /> + + + +
Rename restored indices
+ + + + } + checked={true} + onChange={onDoNotRenameToggle} + /> + + + + } + checked={addPrefix} + onChange={onAddPrefixToggle} + /> + + + + } + checked={renameIndices} + onChange={onRenameIndicesToggle} + /> +
+); + +export default SnapshotRestoreInitialOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts b/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts new file mode 100644 index 000000000..73e864820 --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import SnapshotRestoreInitialOptions from "./SnapshotRestoreInitialOptions"; + +export default SnapshotRestoreInitialOptions; From e8e46eac265ce5d0cb16b716b8f5f76575629952 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 31 Aug 2022 16:19:40 -0700 Subject: [PATCH 019/160] Resolve radio button events not firing Signed-off-by: Chris Hesterman Split radio buttons into SnapshotRestoreOption and SnapshotRenameOptions Signed-off-by: Chris Hesterman Move 'restore' button between 'delete' and 'take snapshot' Signed-off-by: Chris Hesterman Set default rename option to 'add prefix' Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 156 +++++++----------- .../SnapshotIndicesInput.tsx | 46 ++++++ .../components/SnapshotIndicesInput/index.ts | 8 + .../SnapshotRenameOptions.tsx | 64 +++++++ .../components/SnapshotRenameOptions/index.ts | 8 + .../SnapshotRestoreInitialOptions.tsx | 6 +- .../SnapshotRestoreOption.tsx | 50 ++++++ .../components/SnapshotRestoreOption/index.ts | 8 + .../containers/Snapshots/Snapshots.tsx | 6 +- .../components/FlyoutFooter/FlyoutFooter.tsx | 5 +- public/services/SnapshotManagementService.ts | 9 +- server/routes/snapshotManagement.ts | 1 + server/services/SnapshotManagementService.ts | 4 + 13 files changed, 265 insertions(+), 106 deletions(-) create mode 100644 public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx create mode 100644 public/pages/Snapshots/components/SnapshotIndicesInput/index.ts create mode 100644 public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.tsx create mode 100644 public/pages/Snapshots/components/SnapshotRenameOptions/index.ts create mode 100644 public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx create mode 100644 public/pages/Snapshots/components/SnapshotRestoreOption/index.ts diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index ca8866990..984e03460 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -25,21 +25,24 @@ import { IndexItem } from "../../../../../models/interfaces"; import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; -import SnapshotRestoreInitialOptions from "../SnapshotRestoreInitialOptions"; -import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; +import SnapshotRestoreOption from "../SnapshotRestoreOption"; +import SnapshotRenameOptions from "../SnapshotRenameOptions"; +// import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; +import SnapshotIndicesInput from "../SnapshotIndicesInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; interface RestoreSnapshotProps { snapshotManagementService: SnapshotManagementService; indexService: IndexService; onCloseFlyout: () => void; - restoreSnapshot: (snapshotId: string, repository: string) => void; + restoreSnapshot: (snapshotId: string, repository: string, indices: string) => void; snapshotId: string; } interface RestoreSnapshotState { indexOptions: EuiComboBoxOptionOption[]; selectedIndexOptions: EuiComboBoxOptionOption[]; + renameIndices: string; repositories: CatRepository[]; selectedRepoValue: string; @@ -55,10 +58,10 @@ export default class RestoreSnapshotFlyout extends Component { const { restoreSnapshot, snapshotId } = this.props; - const { selectedRepoValue } = this.state; + const { selectedRepoValue, snapshot } = this.state; + const indices = snapshot?.indices.join(","); let repoError = ""; if (!snapshotId.trim()) { @@ -90,14 +94,14 @@ export default class RestoreSnapshotFlyout extends Component[]) => { const selectedIndexOptions = selectedOptions.map((o) => o.label); let newJSON = this.state.snapshot; - + newJSON!.indices = [...selectedIndexOptions]; this.setState({ snapshot: newJSON, selectedIndexOptions: selectedOptions }); }; @@ -154,64 +158,26 @@ export default class RestoreSnapshotFlyout extends Component) => { - const selectedRepo = e.target.value; - let repoError = ""; - if (!selectedRepo) { - repoError = ERROR_PROMPT.REPO; + onToggle = (e: ChangeEvent) => { + if (e.target.id === "restore_specific_indices") { + this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); + return; + } + if (e.target.id === "restore_all_indices") { + this.setState({ restoreSpecific: false, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); + return; + } + if (e.target.name === "rename_option") { + this.setState({ renameIndices: e.target.id, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); + return; } - this.setState({ selectedRepoValue: selectedRepo, repoError }); - }; - - onRestoreAllIndicesToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "restore_all_indices", e.target.checked) }); - }; - - onRestoreSpecificIndicesToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "restore_specific_indices", e.target.checked) }); - }; - - onDoNotRenameToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "do_not_rename", e.target.checked) }); - }; - - onAddPrefixToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "add_prefix", e.target.checked) }); - }; - - onRenameIndicesToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "rename_indices", e.target.checked) }); - }; - - onRestoreAliasesToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "restore_aliases", e.target.checked) }); - }; - - onRestoreClusterStateToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "restore_cluster_state", e.target.checked) }); - }; - - onIgnoreUnavailableToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "ignore_unavailable", e.target.checked) }); - }; - - onRestorePartialToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "restore_partial", e.target.checked) }); - }; - - onCustomizeIndexSettingsToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "customize_index_settings", e.target.checked) }); - }; - onIgnoreIndexSettingsToggle = (e: ChangeEvent) => { - this.setState({ snapshot: _.set(this.state.snapshot!, "ignore_index_settings", e.target.checked) }); + this.setState({ snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); }; render() { const { onCloseFlyout } = this.props; - const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, restoreSpecific, repoError, snapshot } = this.state; - - const repoOptions = repositories.map((r) => ({ value: r.id, text: r.id })); + const { indexOptions, selectedIndexOptions, repositories, selectedRepoValue, restoreSpecific, snapshot, renameIndices } = this.state; return ( @@ -227,62 +193,62 @@ export default class RestoreSnapshotFlyout extends Component - {!restoreSpecific && ( - - )} + + + - {restoreSpecific && ( - - )} - + + {restoreSpecific && ( + + )} - + ); diff --git a/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx new file mode 100644 index 000000000..93914b963 --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx @@ -0,0 +1,46 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiComboBox, EuiComboBoxOptionOption, EuiSpacer } from "@elastic/eui"; +import React from "react"; +import { IndexItem } from "../../../../../models/interfaces"; +import CustomLabel from "../../../../components/CustomLabel"; + +interface SnapshotIndicesProps { + indexOptions: EuiComboBoxOptionOption[]; + selectedIndexOptions: EuiComboBoxOptionOption[]; + onIndicesSelectionChange: (selectedOptions: EuiComboBoxOptionOption[]) => void; + getIndexOptions: (searchValue: string) => void; + onCreateOption: (searchValue: string, options: Array>) => void; + selectedRepoValue: string; + isClearable: boolean; +} + +const SnapshotIndicesInput = ({ + indexOptions, + selectedIndexOptions, + onIndicesSelectionChange, + getIndexOptions, + onCreateOption, +}: SnapshotIndicesProps) => { + return ( + <> + + + + + + ); +}; + +export default SnapshotIndicesInput; diff --git a/public/pages/Snapshots/components/SnapshotIndicesInput/index.ts b/public/pages/Snapshots/components/SnapshotIndicesInput/index.ts new file mode 100644 index 000000000..2029cf583 --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotIndicesInput/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import SnapshotIndicesInput from "./SnapshotIndicesInput"; + +export default SnapshotIndicesInput; diff --git a/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.tsx b/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.tsx new file mode 100644 index 000000000..c634b1bcd --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.tsx @@ -0,0 +1,64 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiRadio, EuiSpacer } from "@elastic/eui"; +import CustomLabel from "../../../../components/CustomLabel"; +import React, { ChangeEvent } from "react"; + +interface SnapshotRenameOptionsProps { + doNotRename: boolean; + onDoNotRenameToggle: (e: ChangeEvent) => void; + addPrefix: boolean; + onAddPrefixToggle: (e: ChangeEvent) => void; + renameIndices: boolean; + onRenameIndicesToggle: (e: ChangeEvent) => void; + width: string; +} + +const SnapshotRenameOptions = ({ + doNotRename, + onDoNotRenameToggle, + addPrefix, + onAddPrefixToggle, + renameIndices, + onRenameIndicesToggle, + width, +}: SnapshotRenameOptionsProps) => ( +
+
Rename restored indices
+ + + + } + checked={doNotRename} + onChange={onDoNotRenameToggle} + /> + + + + } + checked={addPrefix} + onChange={onAddPrefixToggle} + /> + + + + } + checked={renameIndices} + onChange={onRenameIndicesToggle} + /> +
+); + +export default SnapshotRenameOptions; diff --git a/public/pages/Snapshots/components/SnapshotRenameOptions/index.ts b/public/pages/Snapshots/components/SnapshotRenameOptions/index.ts new file mode 100644 index 000000000..532fb263d --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRenameOptions/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import SnapshotRenameOptions from "./SnapshotRenameOptions"; + +export default SnapshotRenameOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx b/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx index 3c82a7137..edf41e228 100644 --- a/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx +++ b/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiRadio, EuiSpacer, EuiText } from "@elastic/eui"; +import { EuiRadio, EuiSpacer } from "@elastic/eui"; import CustomLabel from "../../../../components/CustomLabel"; import React, { ChangeEvent } from "react"; @@ -43,7 +43,7 @@ const SnapshotRestoreInitialOptions = ({ id="restore_all_indices" name="restore_option" label={} - checked={true} + checked={restoreAllIndices} onChange={onRestoreAllIndicesToggle} /> @@ -67,7 +67,7 @@ const SnapshotRestoreInitialOptions = ({ id="do_not_rename" name="rename_option" label={} - checked={true} + checked={doNotRename} onChange={onDoNotRenameToggle} /> diff --git a/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx b/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx new file mode 100644 index 000000000..6d5e3b88c --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiRadio, EuiSpacer } from "@elastic/eui"; +import CustomLabel from "../../../../components/CustomLabel"; +import React, { ChangeEvent } from "react"; + +interface SnapshotRestoreOptionProps { + restoreAllIndices: boolean; + onRestoreAllIndicesToggle: (e: ChangeEvent) => void; + restoreSpecificIndices: boolean; + onRestoreSpecificIndicesToggle: (e: ChangeEvent) => void; + width: string; +} + +const SnapshotRestoreOption = ({ + restoreAllIndices, + onRestoreAllIndicesToggle, + restoreSpecificIndices, + onRestoreSpecificIndicesToggle, + width, +}: SnapshotRestoreOptionProps) => ( +
+
Specify restore option
+ + + + } + checked={restoreAllIndices} + onChange={onRestoreAllIndicesToggle} + /> + + + + } + checked={restoreSpecificIndices} + onChange={onRestoreSpecificIndicesToggle} + /> +
+); + +export default SnapshotRestoreOption; diff --git a/public/pages/Snapshots/components/SnapshotRestoreOption/index.ts b/public/pages/Snapshots/components/SnapshotRestoreOption/index.ts new file mode 100644 index 000000000..50f5c8958 --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRestoreOption/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import SnapshotRestoreOption from "./SnapshotRestoreOption"; + +export default SnapshotRestoreOption; diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index f67007921..22c666736 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -292,12 +292,12 @@ export default class Snapshots extends Component Delete , - - Take snapshot - , Restore , + + Take snapshot + , ]; const subTitleText = ( diff --git a/public/pages/VisualCreatePolicy/components/FlyoutFooter/FlyoutFooter.tsx b/public/pages/VisualCreatePolicy/components/FlyoutFooter/FlyoutFooter.tsx index 3186668f9..6ccde3c67 100644 --- a/public/pages/VisualCreatePolicy/components/FlyoutFooter/FlyoutFooter.tsx +++ b/public/pages/VisualCreatePolicy/components/FlyoutFooter/FlyoutFooter.tsx @@ -13,9 +13,10 @@ interface FlyoutFooterProps { onClickCancel: () => void; onClickAction: () => void; save?: boolean; + restore?: boolean; } -const FlyoutFooter = ({ edit, action, disabledAction = false, onClickCancel, onClickAction, save }: FlyoutFooterProps) => ( +const FlyoutFooter = ({ edit, action, disabledAction = false, onClickCancel, onClickAction, save, restore }: FlyoutFooterProps) => ( @@ -24,7 +25,7 @@ const FlyoutFooter = ({ edit, action, disabledAction = false, onClickCancel, onC - {!save ? `${edit ? "Edit" : "Add"} ${action}` : save ? "Save" : "Create"} + {restore ? "Restore snapshot" : !save ? `${edit ? "Edit" : "Add"} ${action}` : save ? "Save" : "Create"} diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 564358e66..ae03bcf46 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -44,16 +44,19 @@ export default class SnapshotManagementService { }; createSnapshot = async (snapshotId: string, repository: string, snapshot: Snapshot): Promise> => { - let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; + let url = `..${NODE_API._SNAPSHOTS}/${repository}/${snapshotId}`; const response = (await this.httpClient.put(url, { query: { repository }, body: JSON.stringify(snapshot) })) as ServerResponse< CreateSnapshotResponse >; return response; }; - restoreSnapshot = async (snapshotId: string, repository: string): Promise> => { + restoreSnapshot = async (snapshotId: string, repository: string, indices: string): Promise> => { let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; - const response = (await this.httpClient.post(url, { query: { repository } })) as ServerResponse; + const response = (await this.httpClient.post(url, { + query: { repository }, + body: JSON.stringify({ indices: indices }), + })) as ServerResponse; return response; }; diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index ba64335bb..6a280b78d 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -75,6 +75,7 @@ export default function (services: NodeServices, router: IRouter) { query: schema.object({ repository: schema.string(), }), + body: schema.any(), }, }, snapshotManagementService.restoreSnapshot diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 014ad2762..36b519a37 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -200,9 +200,13 @@ export default class SnapshotManagementService { const { repository } = request.query as { repository: string; }; + const { indices } = request.body as { + indices: string; + }; const params = { repository: repository, snapshot: id, + indices: indices, }; const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); const resp: RestoreSnapshotResponse = await callWithRequest("snapshot.restore", params); From 5cd9afc835fcd9bd1d12b8682377c7eed28c6e2c Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 31 Aug 2022 17:37:09 -0700 Subject: [PATCH 020/160] Add AddPrefixInput, remove unused component RestoreSnapshotInitialOptions Signed-off-by: Chris Hesterman --- .../AddPrefixInput/AddPrefixInput.tsx | 36 +++++++ .../components/AddPrefixInput/index.ts | 8 ++ .../RestoreSnapshotFlyout.tsx | 44 ++++++--- .../SnapshotIndicesInput.tsx | 8 +- .../SnapshotRestoreInitialOptions.tsx | 96 ------------------- .../SnapshotRestoreInitialOptions/index.ts | 8 -- 6 files changed, 77 insertions(+), 123 deletions(-) create mode 100644 public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx create mode 100644 public/pages/Snapshots/components/AddPrefixInput/index.ts delete mode 100644 public/pages/Snapshots/components/SnapshotRestoreInitialOptions/SnapshotRestoreInitialOptions.tsx delete mode 100644 public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx new file mode 100644 index 000000000..ff92318a5 --- /dev/null +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx @@ -0,0 +1,36 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFormRow, EuiFieldText, EuiSpacer } from "@elastic/eui"; +import React, { useState, ChangeEvent } from "react"; +import CustomLabel from "../../../../components/CustomLabel"; + +interface AddPrefixesInputProps { + getPrefix: (prefix: string) => void; +} + +const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { + const [prefix, setPrefix] = useState(""); + + const handleChange = (e: ChangeEvent) => { + setPrefix(e.target.value); + getPrefix(e.target.value); + }; + + return ( + <> + + + + + + + + + + ); +}; + +export default AddPrefixesInput; diff --git a/public/pages/Snapshots/components/AddPrefixInput/index.ts b/public/pages/Snapshots/components/AddPrefixInput/index.ts new file mode 100644 index 000000000..2ae205f75 --- /dev/null +++ b/public/pages/Snapshots/components/AddPrefixInput/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import AddPrefixInput from "./AddPrefixInput"; + +export default AddPrefixInput; diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 984e03460..7b00397f7 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -27,6 +27,7 @@ import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; import SnapshotRenameOptions from "../SnapshotRenameOptions"; +import AddPrefixInput from "../AddPrefixInput"; // import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; import SnapshotIndicesInput from "../SnapshotIndicesInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; @@ -43,12 +44,15 @@ interface RestoreSnapshotState { indexOptions: EuiComboBoxOptionOption[]; selectedIndexOptions: EuiComboBoxOptionOption[]; renameIndices: string; + prefix: string; repositories: CatRepository[]; selectedRepoValue: string; snapshot: GetSnapshot | null; snapshotId: string; + restoreSpecific: boolean; + restoreAliases: boolean; repoError: string; snapshotIdError: string; @@ -62,11 +66,13 @@ export default class RestoreSnapshotFlyout extends Component { + this.setState({ prefix: prefix }); + }; + onToggle = (e: ChangeEvent) => { if (e.target.id === "restore_specific_indices") { this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); @@ -177,7 +187,7 @@ export default class RestoreSnapshotFlyout extends Component @@ -201,6 +211,22 @@ export default class RestoreSnapshotFlyout extends Component + + + {restoreSpecific && ( + + )} + + + + {renameIndices === "add_prefix" && } + @@ -231,20 +259,6 @@ export default class RestoreSnapshotFlyout extends Component - - - - {restoreSpecific && ( - - )} diff --git a/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx index 93914b963..8de4d962f 100644 --- a/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx +++ b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx @@ -8,7 +8,7 @@ import React from "react"; import { IndexItem } from "../../../../../models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; -interface SnapshotIndicesProps { +interface SnapshotIndicesInputProps { indexOptions: EuiComboBoxOptionOption[]; selectedIndexOptions: EuiComboBoxOptionOption[]; onIndicesSelectionChange: (selectedOptions: EuiComboBoxOptionOption[]) => void; @@ -24,12 +24,12 @@ const SnapshotIndicesInput = ({ onIndicesSelectionChange, getIndexOptions, onCreateOption, -}: SnapshotIndicesProps) => { +}: SnapshotIndicesInputProps) => { return ( <> - + ) => void; - restoreSpecificIndices: boolean; - onRestoreSpecificIndicesToggle: (e: ChangeEvent) => void; - doNotRename: boolean; - onDoNotRenameToggle: (e: ChangeEvent) => void; - addPrefix: boolean; - onAddPrefixToggle: (e: ChangeEvent) => void; - renameIndices: boolean; - onRenameIndicesToggle: (e: ChangeEvent) => void; - width: string; -} - -const SnapshotRestoreInitialOptions = ({ - restoreAllIndices, - onRestoreAllIndicesToggle, - restoreSpecificIndices, - onRestoreSpecificIndicesToggle, - doNotRename, - onDoNotRenameToggle, - addPrefix, - onAddPrefixToggle, - renameIndices, - onRenameIndicesToggle, - width, -}: SnapshotInitialOptionsProps) => ( -
-
Specify restore option
- - - - } - checked={restoreAllIndices} - onChange={onRestoreAllIndicesToggle} - /> - - - - } - checked={restoreSpecificIndices} - onChange={onRestoreSpecificIndicesToggle} - /> - - - -
Rename restored indices
- - - - } - checked={doNotRename} - onChange={onDoNotRenameToggle} - /> - - - - } - checked={addPrefix} - onChange={onAddPrefixToggle} - /> - - - - } - checked={renameIndices} - onChange={onRenameIndicesToggle} - /> -
-); - -export default SnapshotRestoreInitialOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts b/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts deleted file mode 100644 index 73e864820..000000000 --- a/public/pages/Snapshots/components/SnapshotRestoreInitialOptions/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import SnapshotRestoreInitialOptions from "./SnapshotRestoreInitialOptions"; - -export default SnapshotRestoreInitialOptions; From a80656fb13c9ff846fa6f7de42eed4dcf0ad40e4 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 1 Sep 2022 13:01:23 -0700 Subject: [PATCH 021/160] Fix issues with restore specific indices Signed-off-by: Chris Hesterman Implement first 4 Advanced restore options functionality Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 27 +++++++++++++------ .../SnapshotRestoreAdvancedOptions.tsx | 4 +-- .../containers/Snapshots/Snapshots.tsx | 4 +-- public/services/SnapshotManagementService.ts | 9 ++++--- server/models/interfaces.ts | 5 ++++ server/services/SnapshotManagementService.ts | 5 +--- 6 files changed, 35 insertions(+), 19 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 7b00397f7..7419025e1 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -36,7 +36,7 @@ interface RestoreSnapshotProps { snapshotManagementService: SnapshotManagementService; indexService: IndexService; onCloseFlyout: () => void; - restoreSnapshot: (snapshotId: string, repository: string, indices: string) => void; + restoreSnapshot: (snapshotId: string, repository: string, options: object) => void; snapshotId: string; } @@ -53,6 +53,7 @@ interface RestoreSnapshotState { snapshotId: string; restoreSpecific: boolean; restoreAliases: boolean; + partial: boolean; repoError: string; snapshotIdError: string; @@ -73,6 +74,7 @@ export default class RestoreSnapshotFlyout extends Component { const { restoreSnapshot, snapshotId } = this.props; - const { selectedRepoValue, snapshot } = this.state; - const indices = snapshot?.indices.join(","); + const { selectedRepoValue, selectedIndexOptions, snapshot, partial, prefix } = this.state; + const selectedIndices = selectedIndexOptions.map((option) => option.label).join(","); + const options = { + indices: selectedIndices, + ignore_unavailable: snapshot?.ignore_unavailable || false, + include_global_state: snapshot?.include_global_state, + rename_pattern: snapshot?.rename_pattern || "", + rename_replacement: snapshot?.rename_replacement || "", + include_aliases: snapshot?.restore_aliases || false, + partial: snapshot?.partial || false, + }; let repoError = ""; if (!snapshotId.trim()) { @@ -100,8 +111,8 @@ export default class RestoreSnapshotFlyout extends Component[]) => { @@ -187,7 +198,7 @@ export default class RestoreSnapshotFlyout extends Component @@ -246,11 +257,11 @@ export default class RestoreSnapshotFlyout extends Component } checked={restoreClusterState} onChange={onRestoreClusterStateToggle} @@ -72,7 +72,7 @@ const SnapshotRestoreAdvancedOptions = ({ } checked={restorePartial} onChange={onRestorePartialToggle} diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 22c666736..aa15965d6 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -218,10 +218,10 @@ export default class Snapshots extends Component } }; - restoreSnapshot = async (snapshotId: string, repository: string) => { + restoreSnapshot = async (snapshotId: string, repository: string, options: object) => { try { const { snapshotManagementService } = this.props; - const response = await snapshotManagementService.restoreSnapshot(snapshotId, repository); + const response = await snapshotManagementService.restoreSnapshot(snapshotId, repository, options); if (response.ok) { this.context.notifications.toasts.addSuccess(`Restored snapshot ${snapshotId} to repository ${repository}.`); } else { diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index ae03bcf46..75b08bc14 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -44,18 +44,21 @@ export default class SnapshotManagementService { }; createSnapshot = async (snapshotId: string, repository: string, snapshot: Snapshot): Promise> => { - let url = `..${NODE_API._SNAPSHOTS}/${repository}/${snapshotId}`; + let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; const response = (await this.httpClient.put(url, { query: { repository }, body: JSON.stringify(snapshot) })) as ServerResponse< CreateSnapshotResponse >; return response; }; - restoreSnapshot = async (snapshotId: string, repository: string, indices: string): Promise> => { + restoreSnapshot = async (snapshotId: string, repository: string, options: object): Promise> => { let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; + + console.log("to be sent to server", [url, options]); + const response = (await this.httpClient.post(url, { query: { repository }, - body: JSON.stringify({ indices: indices }), + body: JSON.stringify(options), })) as ServerResponse; return response; }; diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 9592cc7a5..8b380c943 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -409,6 +409,11 @@ export interface GetSnapshot { successful: number; failed: number; }; + restore_aliases?: boolean; + ignore_unavailable?: boolean; + rename_pattern?: string; + rename_replacement?: string; + partial?: boolean; metadata?: { sm_policy?: string; }; diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 36b519a37..2be52b265 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -200,13 +200,10 @@ export default class SnapshotManagementService { const { repository } = request.query as { repository: string; }; - const { indices } = request.body as { - indices: string; - }; const params = { repository: repository, snapshot: id, - indices: indices, + body: JSON.stringify(request.body), }; const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); const resp: RestoreSnapshotResponse = await callWithRequest("snapshot.restore", params); From aa46d71f732ea3473bae113821f3eaea8478d02c Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 1 Sep 2022 16:45:28 -0700 Subject: [PATCH 022/160] Begin cypress testing for snapshots Signed-off-by: Chris Hesterman Passing tests for create repo and create snapshot Signed-off-by: Chris Hesterman --- cypress/integration/snapshots_spec.js | 95 +++++++++++++++++++ .../CreateRepositoryFlyout.tsx | 7 +- .../CreateSnapshotFlyout.tsx | 1 + 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 cypress/integration/snapshots_spec.js diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js new file mode 100644 index 000000000..d05716c63 --- /dev/null +++ b/cypress/integration/snapshots_spec.js @@ -0,0 +1,95 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { PLUGIN_NAME } from "../support/constants"; + +describe("Snapshots", () => { + before(() => { + // Load ecommerce data + cy.request({ + method: "POST", + url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`, + headers: { + "osd-xsrf": true, + }, + }).then((response) => { + expect(response.status).equal(200); + }); + + // Load flight data + cy.request({ + method: "POST", + url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/flights`, + headers: { + "osd-xsrf": true, + }, + }).then((response) => { + expect(response.status).equal(200); + }); + + // Load web log data + cy.request({ + method: "POST", + url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/logs`, + headers: { + "osd-xsrf": true, + }, + }).then((response) => { + expect(response.status).equal(200); + }); + }); + + beforeEach(() => { + // Set welcome screen tracking to false + localStorage.setItem("home:welcome:show", "false"); + + // Visit ISM Snapshots Dashboard + cy.visit(`${Cypress.env("opensearch_dashboards")}/app/${PLUGIN_NAME}#/snapshots`); + + // Common text to wait for to confirm page loaded, give up to 60 seconds for initial load + cy.contains("Restore", { timeout: 60000 }); + }); + + describe("Repository can be created", () => { + it("successfully creates a new repository", () => { + // Create repository to store snapshots + cy.visit(`${Cypress.env("opensearch_dashboards")}/app/${PLUGIN_NAME}#/repositories`); + + // Route to create repository page + cy.contains("Create repository").click({ force: true }); + + // Type in repository name + cy.get(`input[data-test-subj="repoNameInput"]`).focus().type("test_repo"); + + // Type in repository location + cy.get(`input[placeholder="e.g., /mnt/snapshots"]`).focus().type("~/Desktop"); + + // Click Add button + cy.get("button").contains("Add").click({ force: true }); + + // Confirm repository created + cy.contains("test_repo"); + }); + }); + + describe("Snapshot can be created", () => { + it("successfully creates a new snapshot", () => { + // Click Take snapshot button + cy.get("button").contains("Take snapshot").click({ force: true }); + + // Type in Snapshot name + cy.get(`input[data-test-subj="snapshotNameInput"]`).focus().type("test_snapshot"); + + // Select indexes to be included + cy.get(`button[data-test-subj="comboBoxToggleListButton"]`).first().click({ force: true }); + + // Confirm test_repo exists + cy.contains("test_repo"); + + // Click 'Add' button to create snapshot + cy.get("button").contains("Add").click({ force: true }); + }); + }); +}); diff --git a/public/pages/Repositories/components/CreateRepositoryFlyout/CreateRepositoryFlyout.tsx b/public/pages/Repositories/components/CreateRepositoryFlyout/CreateRepositoryFlyout.tsx index 686c0c015..5d23cd6ed 100644 --- a/public/pages/Repositories/components/CreateRepositoryFlyout/CreateRepositoryFlyout.tsx +++ b/public/pages/Repositories/components/CreateRepositoryFlyout/CreateRepositoryFlyout.tsx @@ -258,7 +258,12 @@ export default class CreateRepositoryFlyout extends Component - this.setState({ repoName: e.target.value })} /> + this.setState({ repoName: e.target.value })} + /> diff --git a/public/pages/Snapshots/components/CreateSnapshotFlyout/CreateSnapshotFlyout.tsx b/public/pages/Snapshots/components/CreateSnapshotFlyout/CreateSnapshotFlyout.tsx index 2ab6397d9..4657ad5f6 100644 --- a/public/pages/Snapshots/components/CreateSnapshotFlyout/CreateSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/CreateSnapshotFlyout/CreateSnapshotFlyout.tsx @@ -208,6 +208,7 @@ export default class CreateSnapshotFlyout extends Component { this.setState({ snapshotId: e.target.value }); }} + data-test-subj="snapshotNameInput" /> From 3cf371103fb1f4f5d389be46580c0f230874e93d Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 2 Sep 2022 12:36:47 -0700 Subject: [PATCH 023/160] Begin cypress testing Snapshots. Create repo and Create snapshot done Signed-off-by: Chris Hesterman --- cypress/integration/snapshots_spec.js | 21 ++++++++++++++-- .../SnapshotIndicesRepoInput.tsx | 1 + .../RestoreSnapshotFlyout.tsx | 24 ++++++++++++++++--- .../containers/Snapshots/Snapshots.tsx | 4 ++-- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js index d05716c63..c025e2a1e 100644 --- a/cypress/integration/snapshots_spec.js +++ b/cypress/integration/snapshots_spec.js @@ -7,6 +7,9 @@ import { PLUGIN_NAME } from "../support/constants"; describe("Snapshots", () => { before(() => { + // Delete any existing indices + cy.deleteAllIndices(); + // Load ecommerce data cy.request({ method: "POST", @@ -80,16 +83,30 @@ describe("Snapshots", () => { cy.get("button").contains("Take snapshot").click({ force: true }); // Type in Snapshot name - cy.get(`input[data-test-subj="snapshotNameInput"]`).focus().type("test_snapshot"); + cy.get(`input[data-test-subj="snapshotNameInput"]`).type("test_snapshot{enter}"); // Select indexes to be included - cy.get(`button[data-test-subj="comboBoxToggleListButton"]`).first().click({ force: true }); + cy.get(`[data-test-subj="indicesComboBoxInput"]`).type("open*{enter}"); // Confirm test_repo exists cy.contains("test_repo"); // Click 'Add' button to create snapshot cy.get("button").contains("Add").click({ force: true }); + + // check for success status and snapshot name + cy.contains("In_progress"); + cy.contains("test_snapshot"); }); }); + + // describe("Snapshots can be restored", () => { + // it("Successfully restores all indices", () => { + // // Delete existing indices + // cy.deleteAllIndices(); + + // // Select snapshot to restore + // cy.get("checkbox").contains("test") + // }) + // }) }); diff --git a/public/pages/CreateSnapshotPolicy/components/SnapshotIndicesRepoInput/SnapshotIndicesRepoInput.tsx b/public/pages/CreateSnapshotPolicy/components/SnapshotIndicesRepoInput/SnapshotIndicesRepoInput.tsx index 9c63bbec6..590889cdc 100644 --- a/public/pages/CreateSnapshotPolicy/components/SnapshotIndicesRepoInput/SnapshotIndicesRepoInput.tsx +++ b/public/pages/CreateSnapshotPolicy/components/SnapshotIndicesRepoInput/SnapshotIndicesRepoInput.tsx @@ -73,6 +73,7 @@ const SnapshotIndicesRepoInput = ({ onSearchChange={getIndexOptions} onCreateOption={onCreateOption} isClearable={true} + data-test-subj="indicesComboBoxInput" /> diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 7419025e1..723a6b92d 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -45,6 +45,7 @@ interface RestoreSnapshotState { selectedIndexOptions: EuiComboBoxOptionOption[]; renameIndices: string; prefix: string; + listIndices: boolean; repositories: CatRepository[]; selectedRepoValue: string; @@ -68,6 +69,7 @@ export default class RestoreSnapshotFlyout extends Component { + this.setState({ listIndices: true }); + }; + onIndicesSelectionChange = (selectedOptions: EuiComboBoxOptionOption[]) => { const selectedIndexOptions = selectedOptions.map((o) => o.label); let newJSON = this.state.snapshot; @@ -198,7 +204,7 @@ export default class RestoreSnapshotFlyout extends Component @@ -209,8 +215,20 @@ export default class RestoreSnapshotFlyout extends Component - -

{snapshotId}

+ + + +

{snapshot?.snapshot}

+
+ + +

{snapshot?.state}

+
+ + + {snapshot?.indices.length} + +
diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index aa15965d6..108693266 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -14,8 +14,8 @@ import { getErrorMessage } from "../../../../utils/helpers"; import { CatSnapshotWithRepoAndPolicy as SnapshotsWithRepoAndPolicy } from "../../../../../server/models/interfaces"; import { ContentPanel } from "../../../../components/ContentPanel"; import SnapshotFlyout from "../../components/SnapshotFlyout/SnapshotFlyout"; -import CreateSnapshotFlyout from "../../components/CreateSnapshotFlyout/CreateSnapshotFlyout"; -import RestoreSnapshotFlyout from "../../components/RestoreSnapshotFlyout/RestoreSnapshotFlyout"; +import CreateSnapshotFlyout from "../../components/CreateSnapshotFlyout"; +import RestoreSnapshotFlyout from "../../components/RestoreSnapshotFlyout"; import { Snapshot } from "../../../../../models/interfaces"; import { BREADCRUMBS, RESTORE_SNAPSHOT_DOCUMENTATION_URL, ROUTES } from "../../../../utils/constants"; import { renderTimestampMillis } from "../../../SnapshotPolicies/helpers"; From b9ad019b0aaf20fa72f256c54b5d09449d3d3254 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 2 Sep 2022 13:33:40 -0700 Subject: [PATCH 024/160] Implement add_prefix functionality for snapshot restore Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 723a6b92d..c6584c984 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -89,14 +89,15 @@ export default class RestoreSnapshotFlyout extends Component { const { restoreSnapshot, snapshotId } = this.props; - const { selectedRepoValue, selectedIndexOptions, snapshot, partial, prefix } = this.state; + const { selectedRepoValue, selectedIndexOptions, snapshot, renameIndices, prefix } = this.state; const selectedIndices = selectedIndexOptions.map((option) => option.label).join(","); + const renamePattern = renameIndices === "add_prefix" ? "(? Date: Fri, 2 Sep 2022 15:46:54 -0700 Subject: [PATCH 025/160] Implement rename indices option for restore snapshot Signed-off-by: Chris Hesterman --- .../AddPrefixInput/AddPrefixInput.tsx | 4 +- .../components/RenameInput/RenameInput.tsx | 53 +++++++++++++++++++ .../Snapshots/components/RenameInput/index.ts | 8 +++ .../RestoreSnapshotFlyout.tsx | 40 +++++++++++--- public/services/SnapshotManagementService.ts | 2 - server/services/SnapshotManagementService.ts | 2 +- 6 files changed, 98 insertions(+), 11 deletions(-) create mode 100644 public/pages/Snapshots/components/RenameInput/RenameInput.tsx create mode 100644 public/pages/Snapshots/components/RenameInput/index.ts diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx index ff92318a5..59abedf74 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx @@ -14,7 +14,7 @@ interface AddPrefixesInputProps { const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { const [prefix, setPrefix] = useState(""); - const handleChange = (e: ChangeEvent) => { + const onPrefixChange = (e: ChangeEvent) => { setPrefix(e.target.value); getPrefix(e.target.value); }; @@ -25,7 +25,7 @@ const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { - + diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx new file mode 100644 index 000000000..f35019fde --- /dev/null +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx @@ -0,0 +1,53 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFormRow, EuiFieldText, EuiSpacer } from "@elastic/eui"; +import React, { useState, ChangeEvent } from "react"; +import CustomLabel from "../../../../components/CustomLabel"; + +interface RenameInputProps { + getRenamePattern: (prefix: string) => void; + getRenameReplacement: (prefix: string) => void; +} + +const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProps) => { + const [renamePattern, setRenamePattern] = useState(""); + const [renameReplacement, setRenameReplacement] = useState(""); + + const onPatternChange = (e: ChangeEvent) => { + setRenamePattern(e.target.value); + getRenamePattern(e.target.value); + }; + + const onReplacementChange = (e: ChangeEvent) => { + setRenameReplacement(e.target.value); + getRenameReplacement(e.target.value); + }; + + const patternHelpText = + "Use regular expressiojn to define how index names will be renamed. By default, input (.+) to reuse the entire index name [Learn more]"; + const replacementHelpText = + "Define the format of renamed inices. Use $0 to include the entire matching index name, $1 to include the content of the first capture group, etc. [Learn more]"; + + return ( + <> + + + + + + + + + + + + + + + ); +}; + +export default RenameInput; diff --git a/public/pages/Snapshots/components/RenameInput/index.ts b/public/pages/Snapshots/components/RenameInput/index.ts new file mode 100644 index 000000000..5fe87f5f0 --- /dev/null +++ b/public/pages/Snapshots/components/RenameInput/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import RenameInput from "./RenameInput"; + +export default RenameInput; diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index c6584c984..a5078953a 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -28,6 +28,7 @@ import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; import SnapshotRenameOptions from "../SnapshotRenameOptions"; import AddPrefixInput from "../AddPrefixInput"; +import RenameInput from "../RenameInput"; // import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; import SnapshotIndicesInput from "../SnapshotIndicesInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; @@ -45,6 +46,8 @@ interface RestoreSnapshotState { selectedIndexOptions: EuiComboBoxOptionOption[]; renameIndices: string; prefix: string; + renamePattern: string; + renameReplacement: string; listIndices: boolean; repositories: CatRepository[]; @@ -69,6 +72,8 @@ export default class RestoreSnapshotFlyout extends Component { const { restoreSnapshot, snapshotId } = this.props; - const { selectedRepoValue, selectedIndexOptions, snapshot, renameIndices, prefix } = this.state; + const { + selectedRepoValue, + restoreSpecific, + selectedIndexOptions, + indexOptions, + snapshot, + renameIndices, + prefix, + renamePattern, + renameReplacement, + } = this.state; const selectedIndices = selectedIndexOptions.map((option) => option.label).join(","); - const renamePattern = renameIndices === "add_prefix" ? "(? option.label).join(","); + const pattern = renameIndices === "add_prefix" ? "(? { + this.setState({ renamePattern: renamePattern }); + }; + + getRenameReplacement = (renameReplacement: string) => { + this.setState({ renameReplacement: renameReplacement }); + }; + onToggle = (e: ChangeEvent) => { if (e.target.id === "restore_specific_indices") { this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); @@ -205,7 +230,7 @@ export default class RestoreSnapshotFlyout extends Component @@ -268,6 +293,9 @@ export default class RestoreSnapshotFlyout extends Component {renameIndices === "add_prefix" && } + {renameIndices === "rename_indices" && ( + + )} diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 75b08bc14..574fc78cb 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -54,8 +54,6 @@ export default class SnapshotManagementService { restoreSnapshot = async (snapshotId: string, repository: string, options: object): Promise> => { let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; - console.log("to be sent to server", [url, options]); - const response = (await this.httpClient.post(url, { query: { repository }, body: JSON.stringify(options), diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 2be52b265..379055b7a 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -312,7 +312,7 @@ export default class SnapshotManagementService { queryString: queryString.trim() ? `${queryString.trim()}` : "*", }; const res = await callWithRequest("ism.getSMPolicies", params); - + console.log("policy response", res); const policies: DocumentSMPolicy[] = res.policies.map( (p: { _id: string; _seq_no: number; _primary_term: number; sm_policy: SMPolicy }) => ({ seqNo: p._seq_no, From 5af4208147c540957c408397a890a003724858dc Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 5 Sep 2022 08:30:34 -0700 Subject: [PATCH 026/160] Remove console.logs, unusted variables in SnapshotFlyout, SMservice Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 4 +--- public/services/SnapshotManagementService.ts | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index a5078953a..591d66643 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -29,7 +29,6 @@ import SnapshotRestoreOption from "../SnapshotRestoreOption"; import SnapshotRenameOptions from "../SnapshotRenameOptions"; import AddPrefixInput from "../AddPrefixInput"; import RenameInput from "../RenameInput"; -// import SnapshotIndicesRepoInput from "../../../CreateSnapshotPolicy/components/SnapshotIndicesRepoInput"; import SnapshotIndicesInput from "../SnapshotIndicesInput"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; @@ -131,7 +130,6 @@ export default class RestoreSnapshotFlyout extends Component diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 574fc78cb..f98272a80 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -53,7 +53,6 @@ export default class SnapshotManagementService { restoreSnapshot = async (snapshotId: string, repository: string, options: object): Promise> => { let url = `..${NODE_API._SNAPSHOTS}/${snapshotId}`; - const response = (await this.httpClient.post(url, { query: { repository }, body: JSON.stringify(options), From 5cf239f61029cdab5d517e0d2b39b97c44d42d10 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 7 Sep 2022 09:39:19 -0700 Subject: [PATCH 027/160] Add full stop to help text/errors, add RESTORE_OPTIONS enum Signed-off-by: Chris Hesterman --- cypress/integration/snapshots_spec.js | 10 -- public/models/interfaces.ts | 14 ++ .../AddPrefixInput/AddPrefixInput.tsx | 2 +- .../components/RenameInput/RenameInput.tsx | 4 +- .../RestoreSnapshotFlyout.tsx | 52 +++--- .../SnapshotIndicesInput.tsx | 2 +- .../SnapshotRenameOptions.tsx | 66 ++++---- .../SnapshotRestoreAdvancedOptions.tsx | 159 ++++++++++-------- .../SnapshotRestoreOption.tsx | 57 ++++--- 9 files changed, 202 insertions(+), 164 deletions(-) diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js index c025e2a1e..b412fbd74 100644 --- a/cypress/integration/snapshots_spec.js +++ b/cypress/integration/snapshots_spec.js @@ -99,14 +99,4 @@ describe("Snapshots", () => { cy.contains("test_snapshot"); }); }); - - // describe("Snapshots can be restored", () => { - // it("Successfully restores all indices", () => { - // // Delete existing indices - // cy.deleteAllIndices(); - - // // Select snapshot to restore - // cy.get("checkbox").contains("test") - // }) - // }) }); diff --git a/public/models/interfaces.ts b/public/models/interfaces.ts index 5a645fecc..e1eb26f39 100644 --- a/public/models/interfaces.ts +++ b/public/models/interfaces.ts @@ -55,3 +55,17 @@ export interface LatestActivities { cause?: string; }; } + +export enum RESTORE_OPTIONS { + restore_specific_indices = "restore_specific_indices", + restore_all_indices = "restore_all_indices", + do_not_rename = "do_not_rename", + add_prefix = "add_prefix", + rename_indices = "rename_indices", + restore_aliases = "restore_aliases", + include_global_state = "include_global_state", + ignore_unavailable = "ignore_unavailable", + partial = "partial", + customize_index_settings = "customize_index_settings", + ignore_index_settings = "ignore_index_settings", +} diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx index 59abedf74..4f6dd08c3 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx @@ -23,7 +23,7 @@ const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { <> - + diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx index f35019fde..b549d1b92 100644 --- a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx @@ -27,9 +27,9 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp }; const patternHelpText = - "Use regular expressiojn to define how index names will be renamed. By default, input (.+) to reuse the entire index name [Learn more]"; + "Use regular expressiojn to define how index names will be renamed. By default, input (.+) to reuse the entire index name. [Learn more]"; const replacementHelpText = - "Define the format of renamed inices. Use $0 to include the entire matching index name, $1 to include the content of the first capture group, etc. [Learn more]"; + "Define the format of renamed indices. Use $0 to include the entire matching index name, $1 to include the content of the first capture group, etc. [Learn more]"; return ( <> diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 591d66643..9d7734362 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -20,6 +20,7 @@ import React, { Component, ChangeEvent } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; import { CoreServicesContext } from "../../../../components/core_services"; import { IndexService, SnapshotManagementService } from "../../../../services"; +import { RESTORE_OPTIONS } from "../../../../models/interfaces"; import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; @@ -55,7 +56,6 @@ interface RestoreSnapshotState { snapshot: GetSnapshot | null; snapshotId: string; restoreSpecific: boolean; - restoreAliases: boolean; partial: boolean; repoError: string; @@ -79,7 +79,6 @@ export default class RestoreSnapshotFlyout extends Component option.label).join(","); const allIndices = indexOptions.map((option) => option.label).join(","); - const pattern = renameIndices === "add_prefix" ? "(?) => { - if (e.target.id === "restore_specific_indices") { + const { restore_specific_indices, restore_all_indices } = RESTORE_OPTIONS; + + if (e.target.id === restore_specific_indices) { this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); return; } - if (e.target.id === "restore_all_indices") { + if (e.target.id === restore_all_indices) { this.setState({ restoreSpecific: false, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); return; } @@ -230,6 +232,18 @@ export default class RestoreSnapshotFlyout extends Component @@ -281,17 +295,17 @@ export default class RestoreSnapshotFlyout extends Component - {renameIndices === "add_prefix" && } - {renameIndices === "rename_indices" && ( + {renameIndices === add_prefix && } + {renameIndices === rename_indices && ( )} @@ -300,17 +314,17 @@ export default class RestoreSnapshotFlyout extends Component diff --git a/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx index 8de4d962f..06c2dd536 100644 --- a/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx +++ b/public/pages/Snapshots/components/SnapshotIndicesInput/SnapshotIndicesInput.tsx @@ -29,7 +29,7 @@ const SnapshotIndicesInput = ({ <> ) => void; @@ -25,40 +25,44 @@ const SnapshotRenameOptions = ({ renameIndices, onRenameIndicesToggle, width, -}: SnapshotRenameOptionsProps) => ( -
-
Rename restored indices
+}: SnapshotRenameOptionsProps) => { + const { do_not_rename, add_prefix, rename_indices } = RESTORE_OPTIONS; + + return ( +
+
Rename restored indices
- + - } - checked={doNotRename} - onChange={onDoNotRenameToggle} - /> + } + checked={doNotRename} + onChange={onDoNotRenameToggle} + /> - + - } - checked={addPrefix} - onChange={onAddPrefixToggle} - /> + } + checked={addPrefix} + onChange={onAddPrefixToggle} + /> - + - } - checked={renameIndices} - onChange={onRenameIndicesToggle} - /> -
-); + } + checked={renameIndices} + onChange={onRenameIndicesToggle} + /> +
+ ); +}; export default SnapshotRenameOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx index 5ae6f799b..a7a583b23 100644 --- a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx +++ b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import React, { ChangeEvent } from "react"; import { EuiCheckbox, EuiSpacer, EuiText } from "@elastic/eui"; import CustomLabel from "../../../../components/CustomLabel"; -import React, { ChangeEvent } from "react"; +import { RESTORE_OPTIONS } from "../../../../models/interfaces"; interface SnapshotAdvancedOptionsProps { restoreAliases: boolean; @@ -37,78 +38,88 @@ const SnapshotRestoreAdvancedOptions = ({ ignoreIndexSettings, onIgnoreIndexSettingsToggle, width, -}: SnapshotAdvancedOptionsProps) => ( -
- } - checked={restoreAliases} - onChange={onRestoreAliasesToggle} - /> - - - - } - checked={restoreClusterState} - onChange={onRestoreClusterStateToggle} - /> - - - - - } - checked={ignoreUnavailable} - onChange={onIgnoreUnavailableToggle} - /> - - - - } - checked={restorePartial} - onChange={onRestorePartialToggle} - /> - - - -
Custom index settings
- -

- By default, index settings are restored from indices in snapshots. You can choose to -
- customize index settings on restore. -

-
- - - - } - checked={customizeIndexSettings} - onChange={onCustomizeIndexSettingsToggle} - /> - - - - - } - checked={ignoreIndexSettings} - onChange={onIgnoreIndexSettingsToggle} - /> -
-); +}: SnapshotAdvancedOptionsProps) => { + const { + restore_aliases, + include_global_state, + ignore_unavailable, + partial, + customize_index_settings, + ignore_index_settings, + } = RESTORE_OPTIONS; + return ( +
+ } + checked={restoreAliases} + onChange={onRestoreAliasesToggle} + /> + + + + } + checked={restoreClusterState} + onChange={onRestoreClusterStateToggle} + /> + + + + + } + checked={ignoreUnavailable} + onChange={onIgnoreUnavailableToggle} + /> + + + + } + checked={restorePartial} + onChange={onRestorePartialToggle} + /> + + + +
Custom index settings
+ +

+ By default, index settings are restored from indices in snapshots. You can choose to +
+ customize index settings on restore. +

+
+ + + + } + checked={customizeIndexSettings} + onChange={onCustomizeIndexSettingsToggle} + /> + + + + + } + checked={ignoreIndexSettings} + onChange={onIgnoreIndexSettingsToggle} + /> +
+ ); +}; export default SnapshotRestoreAdvancedOptions; diff --git a/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx b/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx index 6d5e3b88c..49dd2fec4 100644 --- a/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx +++ b/public/pages/Snapshots/components/SnapshotRestoreOption/SnapshotRestoreOption.tsx @@ -3,9 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +import React, { ChangeEvent } from "react"; import { EuiRadio, EuiSpacer } from "@elastic/eui"; import CustomLabel from "../../../../components/CustomLabel"; -import React, { ChangeEvent } from "react"; +import { RESTORE_OPTIONS } from "../../../../models/interfaces"; interface SnapshotRestoreOptionProps { restoreAllIndices: boolean; @@ -21,30 +22,34 @@ const SnapshotRestoreOption = ({ restoreSpecificIndices, onRestoreSpecificIndicesToggle, width, -}: SnapshotRestoreOptionProps) => ( -
-
Specify restore option
- - - - } - checked={restoreAllIndices} - onChange={onRestoreAllIndicesToggle} - /> - - - - } - checked={restoreSpecificIndices} - onChange={onRestoreSpecificIndicesToggle} - /> -
-); +}: SnapshotRestoreOptionProps) => { + const { restore_all_indices, restore_specific_indices } = RESTORE_OPTIONS; + + return ( +
+
Specify restore option
+ + + + } + checked={restoreAllIndices} + onChange={onRestoreAllIndicesToggle} + /> + + + + } + checked={restoreSpecificIndices} + onChange={onRestoreSpecificIndicesToggle} + /> +
+ ); +}; export default SnapshotRestoreOption; From 934a27d542ba5780b1bd30067e9c241ac3b7015d Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 7 Sep 2022 11:03:54 -0700 Subject: [PATCH 028/160] Add placeholder examples to rename options, add line breaks to help text Signed-off-by: Chris Hesterman --- .../AddPrefixInput/AddPrefixInput.tsx | 2 +- .../components/RenameInput/RenameInput.tsx | 46 ++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx index 4f6dd08c3..a24bdd57b 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx @@ -25,7 +25,7 @@ const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { - + diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx index b549d1b92..768e9175b 100644 --- a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx @@ -3,10 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiFormRow, EuiFieldText, EuiSpacer } from "@elastic/eui"; +import { EuiFormRow, EuiFieldText, EuiSpacer, EuiText } from "@elastic/eui"; import React, { useState, ChangeEvent } from "react"; -import CustomLabel from "../../../../components/CustomLabel"; - interface RenameInputProps { getRenamePattern: (prefix: string) => void; getRenameReplacement: (prefix: string) => void; @@ -26,25 +24,51 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp getRenameReplacement(e.target.value); }; - const patternHelpText = - "Use regular expressiojn to define how index names will be renamed. By default, input (.+) to reuse the entire index name. [Learn more]"; - const replacementHelpText = - "Define the format of renamed indices. Use $0 to include the entire matching index name, $1 to include the content of the first capture group, etc. [Learn more]"; + const renamePatternUrl = + "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-rename-pattern"; + const renameReplacementUrl = + "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-rename-replacement"; return ( <> - + +

Rename Pattern

+
+ +

+ Use regular expression to define how index names will be renamed. +
+ By default, input (.+) to reuse the entire index name.{" "} + + [Learn more] + +

+
- + - + +

Rename Replacement

+
+ +

+ Define the format of renamed indices. Use $0 to include the +
+ entire matching index name, $1 to include the content of the first +
+ capture group, etc.{" "} + + [Learn more] + +

+
- + ); From 81f99d7286b80587035834a0a4ed23e57a5d71f6 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 7 Sep 2022 16:53:54 -0700 Subject: [PATCH 029/160] Progress on custom index settings, ignore index settings Signed-off-by: Chris Hesterman --- .../IndexSettingsInput/IndexSettingsInput.tsx | 55 +++++++++++++++++++ .../components/IndexSettingsInput/index.ts | 8 +++ .../RestoreSnapshotFlyout.tsx | 22 +++++++- .../SnapshotRestoreAdvancedOptions.tsx | 12 +++- server/models/interfaces.ts | 1 + 5 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx create mode 100644 public/pages/Snapshots/components/IndexSettingsInput/index.ts diff --git a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx new file mode 100644 index 000000000..e8d774c98 --- /dev/null +++ b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx @@ -0,0 +1,55 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiFormRow, EuiText, EuiTextArea, EuiSpacer } from "@elastic/eui"; +import React, { useState, ChangeEvent } from "react"; + +interface IndexSettingsInputProps { + getIndexSettings: (indexSettings: string) => void; + ignore: boolean; +} + +const IndexSettingsInput = ({ getIndexSettings, ignore }: IndexSettingsInputProps) => { + const [indexSettings, setIndexSettings] = useState(""); + + const onSettingsChange = (e: ChangeEvent) => { + setIndexSettings(e.target.value); + getIndexSettings(e.target.value); + }; + + const title = ignore ? "Specify index settings to ignore" : "Specify custom index settings"; + const indexSettingsUrl = ignore + ? "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-ignore-index-settings" + : "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-index-settings"; + const helperText = ignore + ? "Specify a comma-delimited list of settings to exclude from a snapshot." + : "Specify a comma-delimited list of settings to override in all restored indices."; + const placeholderText = ignore ? `Example: \n \"index.refresh_interval\"` : `Example: \n \"index.number_of_replicas: 0;\"`; + + return ( + <> + + + +

{title}

+
+ +

+ {helperText} + + [Learn more] + +

+
+ + + + + + + ); +}; + +export default IndexSettingsInput; diff --git a/public/pages/Snapshots/components/IndexSettingsInput/index.ts b/public/pages/Snapshots/components/IndexSettingsInput/index.ts new file mode 100644 index 000000000..267979ec0 --- /dev/null +++ b/public/pages/Snapshots/components/IndexSettingsInput/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import IndexSettingsInput from "./IndexSettingsInput"; + +export default IndexSettingsInput; diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 9d7734362..4198dbab9 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -49,6 +49,8 @@ interface RestoreSnapshotState { renamePattern: string; renameReplacement: string; listIndices: boolean; + customIndexSettings: object; + ignoreSettings: string; repositories: CatRepository[]; selectedRepoValue: string; @@ -74,6 +76,8 @@ export default class RestoreSnapshotFlyout extends Component { + const { snapshot } = this.state; + const ignore = snapshot?.ignore_index_settings ? snapshot.ignore_index_settings : false; + + !ignore && this.setState({ customIndexSettings: indexSettings }); + ignore && this.setState({ ignoreSettings: indexSettings }); + }; + onCreateOption = (searchValue: string, options: Array>) => { const normalizedSearchValue = searchValue.trim().toLowerCase(); if (!normalizedSearchValue) { @@ -210,7 +226,7 @@ export default class RestoreSnapshotFlyout extends Component) => { - const { restore_specific_indices, restore_all_indices } = RESTORE_OPTIONS; + const { restore_specific_indices, restore_all_indices, ignore_index_settings } = RESTORE_OPTIONS; if (e.target.id === restore_specific_indices) { this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); @@ -314,6 +330,8 @@ export default class RestoreSnapshotFlyout extends Component void; restoreAliases: boolean; onRestoreAliasesToggle: (e: ChangeEvent) => void; restoreClusterState: boolean; @@ -25,6 +28,8 @@ interface SnapshotAdvancedOptionsProps { } const SnapshotRestoreAdvancedOptions = ({ + ignore, + getIndexSettings, restoreAliases, onRestoreAliasesToggle, ignoreUnavailable, @@ -47,6 +52,7 @@ const SnapshotRestoreAdvancedOptions = ({ customize_index_settings, ignore_index_settings, } = RESTORE_OPTIONS; + return (
Custom index settings
- +

By default, index settings are restored from indices in snapshots. You can choose to
@@ -108,6 +114,8 @@ const SnapshotRestoreAdvancedOptions = ({ onChange={onCustomizeIndexSettingsToggle} /> + {customizeIndexSettings && } + + + {ignoreIndexSettings && }

); }; diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 8b380c943..0751cbc2c 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -411,6 +411,7 @@ export interface GetSnapshot { }; restore_aliases?: boolean; ignore_unavailable?: boolean; + ignore_index_settings?: boolean; rename_pattern?: string; rename_replacement?: string; partial?: boolean; From 3ebe37a13e3c7719b4876f7d3babb5174bccbf86 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 8 Sep 2022 09:56:10 -0700 Subject: [PATCH 030/160] Implement custom index settings functionality Signed-off-by: Chris Hesterman --- .../components/IndexSettingsInput/IndexSettingsInput.tsx | 4 +++- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx index e8d774c98..042a341d1 100644 --- a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx +++ b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx @@ -26,7 +26,9 @@ const IndexSettingsInput = ({ getIndexSettings, ignore }: IndexSettingsInputProp const helperText = ignore ? "Specify a comma-delimited list of settings to exclude from a snapshot." : "Specify a comma-delimited list of settings to override in all restored indices."; - const placeholderText = ignore ? `Example: \n \"index.refresh_interval\"` : `Example: \n \"index.number_of_replicas: 0;\"`; + const placeholderText = ignore + ? `Example: \n \"index.refresh_interval\"` + : `Example: \n {\"index.number_of_replicas\": 0,\n\"index.auto_expand_replicas\": true}`; return ( <> diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 4198dbab9..7380187d1 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -49,7 +49,7 @@ interface RestoreSnapshotState { renamePattern: string; renameReplacement: string; listIndices: boolean; - customIndexSettings: object; + customIndexSettings: string; ignoreSettings: string; repositories: CatRepository[]; @@ -116,7 +116,7 @@ export default class RestoreSnapshotFlyout extends Component Date: Thu, 8 Sep 2022 10:35:07 -0700 Subject: [PATCH 031/160] Successfully implement/debug custom index settings/ignore index settings. Signed-off-by: Chris Hesterman --- .../IndexSettingsInput/IndexSettingsInput.tsx | 4 ++-- .../RestoreSnapshotFlyout.tsx | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx index 042a341d1..245e93df1 100644 --- a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx +++ b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx @@ -27,8 +27,8 @@ const IndexSettingsInput = ({ getIndexSettings, ignore }: IndexSettingsInputProp ? "Specify a comma-delimited list of settings to exclude from a snapshot." : "Specify a comma-delimited list of settings to override in all restored indices."; const placeholderText = ignore - ? `Example: \n \"index.refresh_interval\"` - : `Example: \n {\"index.number_of_replicas\": 0,\n\"index.auto_expand_replicas\": true}`; + ? `Example: \nindex.refresh_interval,\nindex.max_script_fields ` + : `Example: \n {\n\"index.number_of_replicas\": 0,\n\"index.auto_expand_replicas\": true\n}`; return ( <> diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 7380187d1..570106d1e 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -50,7 +50,7 @@ interface RestoreSnapshotState { renameReplacement: string; listIndices: boolean; customIndexSettings: string; - ignoreSettings: string; + ignoreIndexSettings: string; repositories: CatRepository[]; selectedRepoValue: string; @@ -77,7 +77,7 @@ export default class RestoreSnapshotFlyout extends Component>) => { @@ -226,7 +226,7 @@ export default class RestoreSnapshotFlyout extends Component) => { - const { restore_specific_indices, restore_all_indices, ignore_index_settings } = RESTORE_OPTIONS; + const { restore_specific_indices, restore_all_indices } = RESTORE_OPTIONS; if (e.target.id === restore_specific_indices) { this.setState({ restoreSpecific: true, snapshot: _.set(this.state.snapshot!, e.target.id, e.target.checked) }); From b3a093604d23644371aca981e9e61856164aac5b Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 8 Sep 2022 16:02:59 -0700 Subject: [PATCH 032/160] Progress on IndexList component, using cat.index. Signed-off-by: Chris Hesterman --- .../components/IndexList/IndexList.tsx | 35 +++ .../Snapshots/components/IndexList/index.ts | 8 + .../RestoreSnapshotFlyout.tsx | 220 ++++++++++-------- public/services/SnapshotManagementService.ts | 8 + server/routes/snapshotManagement.ts | 12 + server/services/SnapshotManagementService.ts | 24 ++ 6 files changed, 216 insertions(+), 91 deletions(-) create mode 100644 public/pages/Snapshots/components/IndexList/IndexList.tsx create mode 100644 public/pages/Snapshots/components/IndexList/index.ts diff --git a/public/pages/Snapshots/components/IndexList/IndexList.tsx b/public/pages/Snapshots/components/IndexList/IndexList.tsx new file mode 100644 index 000000000..73fb584d2 --- /dev/null +++ b/public/pages/Snapshots/components/IndexList/IndexList.tsx @@ -0,0 +1,35 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiBasicTable, EuiSpacer } from "@elastic/eui"; +import React, { useState, ChangeEvent, useEffect } from "react"; +import { IndexService } from "../../../../services"; +import { CatIndex } from "../../../../../server/models/interfaces"; + +interface IndexListProps { + indices: CatIndex[]; +} + +const IndexList = ({ indices }: IndexListProps) => { + return ( + <> + + + {/* } + onChange={this.onTableChange} + pagination={pagination} + selection={selection} + sorting={sorting} + /> */} + + ); +}; + +export default IndexList; diff --git a/public/pages/Snapshots/components/IndexList/index.ts b/public/pages/Snapshots/components/IndexList/index.ts new file mode 100644 index 000000000..99d8ecf07 --- /dev/null +++ b/public/pages/Snapshots/components/IndexList/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import IndexList from "./IndexList"; + +export default IndexList; diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 9d7734362..23a09ff14 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -15,7 +15,7 @@ import { EuiFlexItem, EuiAccordion, } from "@elastic/eui"; -import _ from "lodash"; +import _, { result } from "lodash"; import React, { Component, ChangeEvent } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; import { CoreServicesContext } from "../../../../components/core_services"; @@ -23,7 +23,7 @@ import { IndexService, SnapshotManagementService } from "../../../../services"; import { RESTORE_OPTIONS } from "../../../../models/interfaces"; import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; -import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; +import { CatRepository, GetSnapshot, CatIndex } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; @@ -31,6 +31,7 @@ import SnapshotRenameOptions from "../SnapshotRenameOptions"; import AddPrefixInput from "../AddPrefixInput"; import RenameInput from "../RenameInput"; import SnapshotIndicesInput from "../SnapshotIndicesInput"; +import IndexList from "../IndexList"; import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; interface RestoreSnapshotProps { @@ -49,6 +50,7 @@ interface RestoreSnapshotState { renamePattern: string; renameReplacement: string; listIndices: boolean; + indicesList: CatIndex[]; repositories: CatRepository[]; selectedRepoValue: string; @@ -74,6 +76,7 @@ export default class RestoreSnapshotFlyout extends Component { + const { indexOptions } = this.state; + const indices = indexOptions.map((index) => index.label).join(","); + console.log("indices", indices); this.setState({ listIndices: true }); + this.getSnapshotIndices(indices); }; onIndicesSelectionChange = (selectedOptions: EuiComboBoxOptionOption[]) => { @@ -197,6 +204,23 @@ export default class RestoreSnapshotFlyout extends Component { + try { + const { snapshotManagementService } = this.props; + const response = await snapshotManagementService.catSnapshotIndices(indices); + + if (response.ok) { + console.log("indices response", response); + this.setState({ indicesList: response.response }); + } else { + this.context.notifications.toasts.addDanger(response.error); + } + } catch (err) { + console.log("this failed"); + this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem loading the indices for this snapshot.")); + } + }; + getPrefix = (prefix: string) => { this.setState({ prefix: prefix }); }; @@ -230,7 +254,16 @@ export default class RestoreSnapshotFlyout extends Component - - -

Restore snapshot

-
-
- - - - - -

{snapshot?.snapshot}

-
- - -

{snapshot?.state}

-
- - - {snapshot?.indices.length} - -
- - - - - - - - {restoreSpecific && ( - - )} - - - - - - {renameIndices === add_prefix && } - {renameIndices === rename_indices && ( - - )} - - - - - - - -
- - - - + {listIndices && } + {listIndices || ( + <> + + +

Restore snapshot

+
+
+ + + + + +

{snapshot?.snapshot}

+
+ + +

{snapshot?.state}

+
+ + + {snapshot?.indices.length} + +
+ + + + + + + + {restoreSpecific && ( + + )} + + + + + + {renameIndices === add_prefix && } + {renameIndices === rename_indices && ( + + )} + + + + + + + +
+ + + + + + )} ); } diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index f98272a80..4ce532455 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -10,6 +10,7 @@ import { GetSMPoliciesResponse, GetSnapshot, CatRepository, + CatIndex, CreateRepositoryBody, AcknowledgedResponse, CreateSnapshotResponse, @@ -115,6 +116,13 @@ export default class SnapshotManagementService { return response; }; + catSnapshotIndices = async (indices: string): Promise> => { + console.log("Indices client service", indices); + const url = `..${NODE_API._INDICES}/${indices}`; + const response = (await this.httpClient.get(url)) as ServerResponse; + return response; + }; + getRepository = async (repo: string): Promise> => { const url = `..${NODE_API._REPOSITORIES}/${repo}`; const response = (await this.httpClient.get(url)) as ServerResponse; diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index 6a280b78d..4888e1db9 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -184,6 +184,18 @@ export default function (services: NodeServices, router: IRouter) { snapshotManagementService.catRepositoriesWithSnapshotCount ); + router.get( + { + path: `${NODE_API._INDICES}/{indices}`, + validate: { + params: schema.object({ + indices: schema.string(), + }), + }, + }, + snapshotManagementService.catSnapshotIndices + ); + router.delete( { path: `${NODE_API._REPOSITORIES}/{id}`, diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 379055b7a..6d479de64 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -14,6 +14,7 @@ import { import { SMPolicy, DocumentSMPolicy, DocumentSMPolicyWithMetadata } from "../../models/interfaces"; import { CatRepository, + CatIndex, CatSnapshotWithRepoAndPolicy, GetSnapshotsResponse, GetSMPoliciesResponse, @@ -486,6 +487,29 @@ export default class SnapshotManagementService { } }; + catSnapshotIndices = async ( + context: RequestHandlerContext, + request: OpenSearchDashboardsRequest, + response: OpenSearchDashboardsResponseFactory + ): Promise>> => { + try { + const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); + const res: CatIndex[] = await callWithRequest("cat.indices", { + format: "json", + }); + console.log("server"); + return response.custom({ + statusCode: 200, + body: { + ok: true, + response: res, + }, + }); + } catch (err) { + return this.errorResponse(response, err, "catSnapshotIndices"); + } + }; + catRepositoriesWithSnapshotCount = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, From 88bef4b619b5d963110086e3616a5e08c35f588f Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 9 Sep 2022 09:25:59 -0700 Subject: [PATCH 033/160] IndexList with pagination fully functional, todo: styling Signed-off-by: Chris Hesterman --- .../components/IndexList/IndexList.tsx | 44 ++++++++++++------- .../RestoreSnapshotFlyout.tsx | 15 ++++--- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/public/pages/Snapshots/components/IndexList/IndexList.tsx b/public/pages/Snapshots/components/IndexList/IndexList.tsx index 73fb584d2..2916dfb4e 100644 --- a/public/pages/Snapshots/components/IndexList/IndexList.tsx +++ b/public/pages/Snapshots/components/IndexList/IndexList.tsx @@ -3,31 +3,41 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiBasicTable, EuiSpacer } from "@elastic/eui"; -import React, { useState, ChangeEvent, useEffect } from "react"; -import { IndexService } from "../../../../services"; +import { EuiInMemoryTable, EuiIcon, EuiSpacer, EuiFlyoutHeader, EuiTitle, Pagination } from "@elastic/eui"; +import React, { useState, ChangeEvent, useEffect, MouseEvent } from "react"; import { CatIndex } from "../../../../../server/models/interfaces"; interface IndexListProps { indices: CatIndex[]; + snapshot: string; + onClick: (e: React.MouseEvent) => void; } -const IndexList = ({ indices }: IndexListProps) => { +const IndexList = ({ indices, snapshot, onClick }: IndexListProps) => { + const columns = [ + { + field: "index", + name: "Index", + }, + { + field: "store.size", + name: "Total size", + }, + ]; + return ( <> - - - {/* } - onChange={this.onTableChange} - pagination={pagination} - selection={selection} - sorting={sorting} - /> */} + + +

+ Indices in snapshot{" "} + {snapshot} +

+
+
+
+ +
); }; diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 23a09ff14..b37b60dfb 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -56,7 +56,6 @@ interface RestoreSnapshotState { selectedRepoValue: string; snapshot: GetSnapshot | null; - snapshotId: string; restoreSpecific: boolean; partial: boolean; @@ -80,7 +79,6 @@ export default class RestoreSnapshotFlyout extends Component { + this.setState({ listIndices: false }); + }; + onIndicesSelectionChange = (selectedOptions: EuiComboBoxOptionOption[]) => { const selectedIndexOptions = selectedOptions.map((o) => o.label); let newJSON = this.state.snapshot; @@ -169,7 +171,9 @@ export default class RestoreSnapshotFlyout extends Component { - this.getSnapshot(this.props.snapshotId, this.state.selectedRepoValue); + const { snapshotId } = this.props; + const { selectedRepoValue } = this.state; + this.getSnapshot(snapshotId, selectedRepoValue); }; onCreateOption = (searchValue: string, options: Array>) => { @@ -253,7 +257,7 @@ export default class RestoreSnapshotFlyout extends Component - {listIndices && } + {console.log("snapshot flyout", snapshotId)} + {listIndices && } {listIndices || ( <> From 15f41a4b009b78729aa907dd55eb4fa56ce408f7 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 9 Sep 2022 09:40:59 -0700 Subject: [PATCH 034/160] Add RestoreActivitiesPanel component folder, files (starter) Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 44 +++++++++++++++++++ .../RestoreActivitiesPanel/index.ts | 8 ++++ 2 files changed, 52 insertions(+) create mode 100644 public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx create mode 100644 public/pages/Snapshots/components/RestoreActivitiesPanel/index.ts diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx new file mode 100644 index 000000000..04c7b10f8 --- /dev/null +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -0,0 +1,44 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + EuiComboBoxOptionOption, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiSpacer, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiAccordion, +} from "@elastic/eui"; +import _ from "lodash"; +import React, { Component, ChangeEvent } from "react"; +import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; +import { CoreServicesContext } from "../../../../components/core_services"; +import { IndexService, SnapshotManagementService } from "../../../../services"; +import { RESTORE_OPTIONS } from "../../../../models/interfaces"; +import { getErrorMessage } from "../../../../utils/helpers"; +import { IndexItem } from "../../../../../models/interfaces"; +import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; +import CustomLabel from "../../../../components/CustomLabel"; +import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; +import SnapshotRestoreOption from "../SnapshotRestoreOption"; +import SnapshotRenameOptions from "../SnapshotRenameOptions"; +import AddPrefixInput from "../AddPrefixInput"; +import RenameInput from "../RenameInput"; +import SnapshotIndicesInput from "../SnapshotIndicesInput"; +import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; + +interface RestoreActivitiesPanelProps { + snapshotManagementService: SnapshotManagementService; + indexService: IndexService; + snapshotId: string; +} + +export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { + return <>; +}; diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/index.ts b/public/pages/Snapshots/components/RestoreActivitiesPanel/index.ts new file mode 100644 index 000000000..b67ece4d9 --- /dev/null +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { RestoreActivitiesPanel } from "./RestoreActivitiesPanel"; + +export default RestoreActivitiesPanel; From 366e5a5c3bc5cad7de10c3780395423e70725a4b Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 9 Sep 2022 11:06:40 -0700 Subject: [PATCH 035/160] Complete IndexList with pagination, sorting. Signed-off-by: Chris Hesterman --- .../components/IndexList/IndexList.tsx | 24 ++++++++++++++----- .../RestoreSnapshotFlyout.tsx | 7 ++---- public/services/SnapshotManagementService.ts | 1 - server/services/SnapshotManagementService.ts | 2 +- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/public/pages/Snapshots/components/IndexList/IndexList.tsx b/public/pages/Snapshots/components/IndexList/IndexList.tsx index 2916dfb4e..951a3a721 100644 --- a/public/pages/Snapshots/components/IndexList/IndexList.tsx +++ b/public/pages/Snapshots/components/IndexList/IndexList.tsx @@ -3,8 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiInMemoryTable, EuiIcon, EuiSpacer, EuiFlyoutHeader, EuiTitle, Pagination } from "@elastic/eui"; -import React, { useState, ChangeEvent, useEffect, MouseEvent } from "react"; +import { EuiInMemoryTable, EuiIcon, EuiFlyoutHeader, EuiTitle } from "@elastic/eui"; +import React from "react"; import { CatIndex } from "../../../../../server/models/interfaces"; interface IndexListProps { @@ -14,29 +14,41 @@ interface IndexListProps { } const IndexList = ({ indices, snapshot, onClick }: IndexListProps) => { + indices = indices.filter((index) => index.index.substring(0, 7) !== ".kibana"); + const columns = [ { field: "index", name: "Index", + width: "70%", + sortable: true, }, { field: "store.size", name: "Total size", + sortable: true, }, ]; + const sorting = { + sort: { + field: "index", + direction: "asc", + }, + }; + return ( <>

- Indices in snapshot{" "} - {snapshot} + {" "} + Indices in snapshot {snapshot} ({indices.length})

-
- +
+
); diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index b37b60dfb..d42001e6d 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -15,7 +15,7 @@ import { EuiFlexItem, EuiAccordion, } from "@elastic/eui"; -import _, { result } from "lodash"; +import _ from "lodash"; import React, { Component, ChangeEvent } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; import { CoreServicesContext } from "../../../../components/core_services"; @@ -137,7 +137,7 @@ export default class RestoreSnapshotFlyout extends Component { const { indexOptions } = this.state; const indices = indexOptions.map((index) => index.label).join(","); - console.log("indices", indices); + this.setState({ listIndices: true }); this.getSnapshotIndices(indices); }; @@ -214,13 +214,11 @@ export default class RestoreSnapshotFlyout extends Component - {console.log("snapshot flyout", snapshotId)} {listIndices && } {listIndices || ( <> diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 4ce532455..427cdb8d0 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -117,7 +117,6 @@ export default class SnapshotManagementService { }; catSnapshotIndices = async (indices: string): Promise> => { - console.log("Indices client service", indices); const url = `..${NODE_API._INDICES}/${indices}`; const response = (await this.httpClient.get(url)) as ServerResponse; return response; diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 6d479de64..53f919508 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -497,7 +497,7 @@ export default class SnapshotManagementService { const res: CatIndex[] = await callWithRequest("cat.indices", { format: "json", }); - console.log("server"); + return response.custom({ statusCode: 200, body: { From 70d56c8ba863ab2a6b9f940ccfca20d9786c62a1 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 9 Sep 2022 12:22:21 -0700 Subject: [PATCH 036/160] Add maxWidth to RestoreSnapshotFlyout Signed-off-by: Chris Hesterman + {listIndices && } {listIndices || ( <> From 6a8a56ca0458537d12c6fa749769f99eba6506ad Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 9 Sep 2022 18:23:48 -0700 Subject: [PATCH 037/160] Implement tabs on Snapshots page: Snapshots, Restore activities... Signed-off-by: Chris Hesterman Implement skeleton Restore activities panel, panel switching in Snapshots Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 55 +++++++++--- .../containers/Snapshots/Snapshots.tsx | 85 ++++++++++++++----- 2 files changed, 107 insertions(+), 33 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 04c7b10f8..fe7fa8969 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -3,18 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - EuiComboBoxOptionOption, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiFlyoutHeader, - EuiSpacer, - EuiTitle, - EuiFlexGroup, - EuiFlexItem, - EuiAccordion, -} from "@elastic/eui"; +import { EuiInMemoryTable } from "@elastic/eui"; import _ from "lodash"; import React, { Component, ChangeEvent } from "react"; import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; @@ -25,6 +14,7 @@ import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; +import { ContentPanel } from "../../../../components/ContentPanel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; import SnapshotRenameOptions from "../SnapshotRenameOptions"; @@ -40,5 +30,44 @@ interface RestoreActivitiesPanelProps { } export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { - return <>; + let getRestoreStatus = () => { + console.log("getting status"); + }; + + const columns = [ + { + field: "id", + name: "Start time", + }, + { + field: "status", + name: "Completion time", + }, + { + field: "policy", + name: "Policy", + }, + { + field: "repository", + name: "Snapshot name", + }, + { + field: "start_epoch", + name: "Status", + }, + { + field: "end_epoch", + name: "Indices being restored", + }, + ]; + + getRestoreStatus = _.debounce(getRestoreStatus, 500, { leading: true }); + + return ( + <> + + + + + ); }; diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 108693266..6cb21a0d0 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { Component } from "react"; +import React, { Component, MouseEvent } from "react"; import _ from "lodash"; import { RouteComponentProps } from "react-router-dom"; -import { EuiButton, EuiInMemoryTable, EuiLink, EuiTableFieldDataColumnType, EuiText } from "@elastic/eui"; +import { EuiButton, EuiInMemoryTable, EuiLink, EuiTableFieldDataColumnType, EuiText, EuiPageHeader, EuiSpacer } from "@elastic/eui"; import { FieldValueSelectionFilterConfigType } from "@elastic/eui/src/components/search_bar/filters/field_value_selection_filter"; import { CoreServicesContext } from "../../../../components/core_services"; import { SnapshotManagementService, IndexService } from "../../../../services"; @@ -16,6 +16,7 @@ import { ContentPanel } from "../../../../components/ContentPanel"; import SnapshotFlyout from "../../components/SnapshotFlyout/SnapshotFlyout"; import CreateSnapshotFlyout from "../../components/CreateSnapshotFlyout"; import RestoreSnapshotFlyout from "../../components/RestoreSnapshotFlyout"; +import RestoreActivitiesPanel from "../../components/RestoreActivitiesPanel"; import { Snapshot } from "../../../../../models/interfaces"; import { BREADCRUMBS, RESTORE_SNAPSHOT_DOCUMENTATION_URL, ROUTES } from "../../../../utils/constants"; import { renderTimestampMillis } from "../../../SnapshotPolicies/helpers"; @@ -31,6 +32,7 @@ interface SnapshotsState { snapshots: SnapshotsWithRepoAndPolicy[]; existingPolicyNames: string[]; loadingSnapshots: boolean; + snapshotPanel: boolean; selectedItems: SnapshotsWithRepoAndPolicy[]; @@ -57,6 +59,7 @@ export default class Snapshots extends Component snapshots: [], existingPolicyNames: [], loadingSnapshots: false, + snapshotPanel: true, selectedItems: [], showFlyout: false, flyoutSnapshotId: "", @@ -240,12 +243,36 @@ export default class Snapshots extends Component this.setState({ showRestoreFlyout: false }); }; + onClickTab = (e: React.MouseEvent) => { + e.stopPropagation(); + const target = e.currentTarget; + + const snapshotPanel = target.textContent === "Snapshots" ? true : false; + const prev = target.previousElementSibling; + const next = target.nextElementSibling; + + target.ariaSelected = "true"; + target.classList.add("euiTab-isSelected"); + + if (prev) { + prev.classList.remove("euiTab-isSelected"); + prev.ariaSelected = "false"; + } + if (next) { + next.classList.remove("euiTab-isSelected"); + next.ariaSelected = "false"; + } + + this.setState({ snapshotPanel: snapshotPanel }); + }; + render() { const { snapshots, existingPolicyNames, selectedItems, loadingSnapshots, + snapshotPanel, showFlyout, flyoutSnapshotId, flyoutSnapshotRepo, @@ -314,24 +341,42 @@ export default class Snapshots extends Component return ( <> - - `${item.repository}:${item.id}`} - columns={this.columns} - pagination={true} - sorting={{ - sort: { - field: "end_epoch", - direction: "desc", - }, - }} - isSelectable={true} - selection={{ onSelectionChange: this.onSelectionChange }} - search={search} - loading={loadingSnapshots} - /> - + + {snapshotPanel || } + {snapshotPanel && ( + + `${item.repository}:${item.id}`} + columns={this.columns} + pagination={true} + sorting={{ + sort: { + field: "end_epoch", + direction: "desc", + }, + }} + isSelectable={true} + selection={{ onSelectionChange: this.onSelectionChange }} + search={search} + loading={loadingSnapshots} + /> + + )} {showFlyout && ( Date: Mon, 12 Sep 2022 10:13:49 -0700 Subject: [PATCH 038/160] Progress on catIndexRecovery, TODO - debug Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 18 +++++++++--------- .../containers/Snapshots/Snapshots.tsx | 14 ++++++++++---- public/services/SnapshotManagementService.ts | 7 +++++++ server/models/interfaces.ts | 5 +++++ server/routes/snapshotManagement.ts | 7 +++++++ utils/constants.ts | 1 + 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index fe7fa8969..d79822175 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -36,27 +36,27 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService const columns = [ { - field: "id", - name: "Start time", + field: "index", + name: "Index", }, { - field: "status", - name: "Completion time", + field: "start_epoch", + name: "Start time", }, { - field: "policy", - name: "Policy", + field: "end_epoch", + name: "Completion time", }, { - field: "repository", + field: "snapshot", name: "Snapshot name", }, { - field: "start_epoch", + field: "stage", name: "Status", }, { - field: "end_epoch", + field: "indices", name: "Indices being restored", }, ]; diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 6cb21a0d0..bfe6321f7 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -3,10 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import React, { Component, MouseEvent } from "react"; +import React, { Component } from "react"; import _ from "lodash"; import { RouteComponentProps } from "react-router-dom"; -import { EuiButton, EuiInMemoryTable, EuiLink, EuiTableFieldDataColumnType, EuiText, EuiPageHeader, EuiSpacer } from "@elastic/eui"; +import { EuiButton, EuiInMemoryTable, EuiLink, EuiTableFieldDataColumnType, EuiText, EuiPageHeader } from "@elastic/eui"; import { FieldValueSelectionFilterConfigType } from "@elastic/eui/src/components/search_bar/filters/field_value_selection_filter"; import { CoreServicesContext } from "../../../../components/core_services"; import { SnapshotManagementService, IndexService } from "../../../../services"; @@ -280,7 +280,7 @@ export default class Snapshots extends Component showRestoreFlyout, isDeleteModalVisible, } = this.state; - + const { indexService, snapshotManagementService } = this.props; const repos = [...new Set(snapshots.map((snapshot) => snapshot.repository))]; const status = [...new Set(snapshots.map((snapshot) => snapshot.status))]; const search = { @@ -356,7 +356,13 @@ export default class Snapshots extends Component paddingSize="l" onClick={this.onClickTab} /> - {snapshotPanel || } + {snapshotPanel || ( + + )} {snapshotPanel && ( > => { + const url = `..${NODE_API._RECOVERY}`; + const response = (await this.httpClient.get(url)) as ServerResponse; + return response; + }; + createPolicy = async (policyId: string, policy: SMPolicy): Promise> => { let url = `..${NODE_API.SMPolicies}/${policyId}`; const response = (await this.httpClient.post(url, { body: JSON.stringify(policy) })) as ServerResponse; diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 8b380c943..99c9f21cd 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -22,6 +22,7 @@ import { Rollup, Transform, } from "../../models/interfaces"; +import { integer } from "@opensearch-project/opensearch/api/types"; export interface NodeServices { indexService: IndexService; @@ -364,6 +365,10 @@ export interface GetSnapshotsResponse { totalSnapshots: number; } +export interface CatIndexRecovery { + response: object; +} + export interface CatSnapshotWithRepoAndPolicy { id: string; status: string; diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index 6a280b78d..a9c3c8d24 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -184,6 +184,13 @@ export default function (services: NodeServices, router: IRouter) { snapshotManagementService.catRepositoriesWithSnapshotCount ); + router.get( + { + path: NODE_API._RECOVERY, + }, + snapshotManagementService.catIndexRecovery + ); + router.delete( { path: `${NODE_API._REPOSITORIES}/{id}`, diff --git a/utils/constants.ts b/utils/constants.ts index d6d16c8f5..9b969e6d1 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -14,6 +14,7 @@ export const NODE_API = Object.freeze({ EDIT_ROLLOVER_ALIAS: `${BASE_API_PATH}/editRolloverAlias`, POLICIES: `${BASE_API_PATH}/policies`, ROLLUPS: `${BASE_API_PATH}/rollups`, + _RECOVERY: `${BASE_API_PATH}/_recovery`, TRANSFORMS: `${BASE_API_PATH}/transforms`, MANAGED_INDICES: `${BASE_API_PATH}/managedIndices`, CHANNELS: `${BASE_API_PATH}/_notifications/channels`, From a08c1b4d17fc3b1f5a7ea57ad17c55aa345eced2 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 12 Sep 2022 10:18:17 -0700 Subject: [PATCH 039/160] Fix syntax bug - server/services/SnapshotManagementService.ts Signed-off-by: Chris Hesterman --- server/services/SnapshotManagementService.ts | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 379055b7a..be309dbda 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -15,6 +15,7 @@ import { SMPolicy, DocumentSMPolicy, DocumentSMPolicyWithMetadata } from "../../ import { CatRepository, CatSnapshotWithRepoAndPolicy, + CatIndexRecovery, GetSnapshotsResponse, GetSMPoliciesResponse, DeletePolicyResponse, @@ -486,6 +487,28 @@ export default class SnapshotManagementService { } }; + catIndexRecovery = async ( + context: RequestHandlerContext, + request: OpenSearchDashboardsRequest, + response: OpenSearchDashboardsResponseFactory + ): Promise>> => { + try { + const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); + const res: CatIndexRecovery = await callWithRequest("cat.repositories", { + format: "json", + }); + return response.custom({ + statusCode: 200, + body: { + ok: true, + response: res, + }, + }); + } catch (err) { + return this.errorResponse(response, err, "catIndexRecovery"); + } + }; + catRepositoriesWithSnapshotCount = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, From 327d7da69c88d29c8a86f0022576e1b3046e1edf Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 12 Sep 2022 12:02:23 -0700 Subject: [PATCH 040/160] Resolved some errors, getting a response but not correct response. Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 27 ++++++------------- public/services/SnapshotManagementService.ts | 4 +-- server/routes/snapshotManagement.ts | 1 + 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index d79822175..1b15dc7bd 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -5,23 +5,9 @@ import { EuiInMemoryTable } from "@elastic/eui"; import _ from "lodash"; -import React, { Component, ChangeEvent } from "react"; -import FlyoutFooter from "../../../VisualCreatePolicy/components/FlyoutFooter"; -import { CoreServicesContext } from "../../../../components/core_services"; +import React, { useEffect } from "react"; import { IndexService, SnapshotManagementService } from "../../../../services"; -import { RESTORE_OPTIONS } from "../../../../models/interfaces"; -import { getErrorMessage } from "../../../../utils/helpers"; -import { IndexItem } from "../../../../../models/interfaces"; -import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; -import CustomLabel from "../../../../components/CustomLabel"; import { ContentPanel } from "../../../../components/ContentPanel"; -import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; -import SnapshotRestoreOption from "../SnapshotRestoreOption"; -import SnapshotRenameOptions from "../SnapshotRenameOptions"; -import AddPrefixInput from "../AddPrefixInput"; -import RenameInput from "../RenameInput"; -import SnapshotIndicesInput from "../SnapshotIndicesInput"; -import { ERROR_PROMPT } from "../../../CreateSnapshotPolicy/constants"; interface RestoreActivitiesPanelProps { snapshotManagementService: SnapshotManagementService; @@ -30,8 +16,13 @@ interface RestoreActivitiesPanelProps { } export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { - let getRestoreStatus = () => { - console.log("getting status"); + useEffect(() => { + getRestoreStatus(); + }, []); + + const getRestoreStatus = async () => { + const status = await snapshotManagementService.catIndexRecovery(); + console.log("status", status); }; const columns = [ @@ -61,8 +52,6 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService }, ]; - getRestoreStatus = _.debounce(getRestoreStatus, 500, { leading: true }); - return ( <> diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 0f639980a..92b23e6e1 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -61,9 +61,9 @@ export default class SnapshotManagementService { return response; }; - catSnapshotRecovery = async (): Promise> => { + catIndexRecovery = async (): Promise> => { const url = `..${NODE_API._RECOVERY}`; - const response = (await this.httpClient.get(url)) as ServerResponse; + const response = (await this.httpClient.get(url)) as ServerResponse; return response; }; diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index a9c3c8d24..66921635d 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -187,6 +187,7 @@ export default function (services: NodeServices, router: IRouter) { router.get( { path: NODE_API._RECOVERY, + validate: {}, }, snapshotManagementService.catIndexRecovery ); From fd77a64a29554331b1909b3b2bdf313d49ebd15a Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 12 Sep 2022 12:08:32 -0700 Subject: [PATCH 041/160] Add back line 20 in rollups_spec, required by changes in 2.3 release. Signed-off-by: Chris Hesterman --- cypress/integration/rollups_spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cypress/integration/rollups_spec.js b/cypress/integration/rollups_spec.js index 896a06271..866e49ab1 100644 --- a/cypress/integration/rollups_spec.js +++ b/cypress/integration/rollups_spec.js @@ -16,6 +16,9 @@ describe("Rollups", () => { // Go to sample data page cy.visit(`${Cypress.env("opensearch_dashboards")}/app/home#/tutorial_directory/sampleData`); + // Click on "Sample data" tab + cy.contains("Sample data").click({ force: true }); + // Load sample eCommerce data cy.get(`button[data-test-subj="addSampleDataSetecommerce"]`).click({ force: true }); From 9caf86b444978eb62006511594817e62486bf974 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 12 Sep 2022 13:29:42 -0700 Subject: [PATCH 042/160] Implement code to use Index Recovery api. successful. Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel/RestoreActivitiesPanel.tsx | 2 +- public/services/SnapshotManagementService.ts | 9 +++++---- server/models/interfaces.ts | 5 ++--- server/routes/snapshotManagement.ts | 2 +- server/services/SnapshotManagementService.ts | 10 +++++----- utils/constants.ts | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 1b15dc7bd..bc09b6cca 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -21,7 +21,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService }, []); const getRestoreStatus = async () => { - const status = await snapshotManagementService.catIndexRecovery(); + const status = await snapshotManagementService.getIndexRecovery(); console.log("status", status); }; diff --git a/public/services/SnapshotManagementService.ts b/public/services/SnapshotManagementService.ts index 92b23e6e1..4f2a5a8f0 100644 --- a/public/services/SnapshotManagementService.ts +++ b/public/services/SnapshotManagementService.ts @@ -14,7 +14,7 @@ import { AcknowledgedResponse, CreateSnapshotResponse, RestoreSnapshotResponse, - CatIndexRecovery, + GetIndexRecoveryResponse, } from "../../server/models/interfaces"; import { ServerResponse } from "../../server/models/types"; import { DocumentSMPolicy, DocumentSMPolicyWithMetadata, SMPolicy, Snapshot } from "../../models/interfaces"; @@ -61,9 +61,10 @@ export default class SnapshotManagementService { return response; }; - catIndexRecovery = async (): Promise> => { - const url = `..${NODE_API._RECOVERY}`; - const response = (await this.httpClient.get(url)) as ServerResponse; + getIndexRecovery = async (): Promise> => { + const url = NODE_API._RECOVERY; + console.log("URL", url); + const response = (await this.httpClient.get(url)) as ServerResponse; return response; }; diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 99c9f21cd..5d3aa49bd 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -22,7 +22,6 @@ import { Rollup, Transform, } from "../../models/interfaces"; -import { integer } from "@opensearch-project/opensearch/api/types"; export interface NodeServices { indexService: IndexService; @@ -365,8 +364,8 @@ export interface GetSnapshotsResponse { totalSnapshots: number; } -export interface CatIndexRecovery { - response: object; +export interface GetIndexRecoveryResponse { + response: any; } export interface CatSnapshotWithRepoAndPolicy { diff --git a/server/routes/snapshotManagement.ts b/server/routes/snapshotManagement.ts index 66921635d..f770d410c 100644 --- a/server/routes/snapshotManagement.ts +++ b/server/routes/snapshotManagement.ts @@ -189,7 +189,7 @@ export default function (services: NodeServices, router: IRouter) { path: NODE_API._RECOVERY, validate: {}, }, - snapshotManagementService.catIndexRecovery + snapshotManagementService.getIndexRecovery ); router.delete( diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index be309dbda..8f31860fa 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -15,7 +15,7 @@ import { SMPolicy, DocumentSMPolicy, DocumentSMPolicyWithMetadata } from "../../ import { CatRepository, CatSnapshotWithRepoAndPolicy, - CatIndexRecovery, + GetIndexRecoveryResponse, GetSnapshotsResponse, GetSMPoliciesResponse, DeletePolicyResponse, @@ -487,14 +487,14 @@ export default class SnapshotManagementService { } }; - catIndexRecovery = async ( + getIndexRecovery = async ( context: RequestHandlerContext, request: OpenSearchDashboardsRequest, response: OpenSearchDashboardsResponseFactory - ): Promise>> => { + ): Promise>> => { try { const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); - const res: CatIndexRecovery = await callWithRequest("cat.repositories", { + const res: GetIndexRecoveryResponse[] = await callWithRequest("indices.recovery", { format: "json", }); return response.custom({ @@ -505,7 +505,7 @@ export default class SnapshotManagementService { }, }); } catch (err) { - return this.errorResponse(response, err, "catIndexRecovery"); + return this.errorResponse(response, err, "getIndexRecovery"); } }; diff --git a/utils/constants.ts b/utils/constants.ts index 9b969e6d1..685b5f99d 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -13,8 +13,8 @@ export const NODE_API = Object.freeze({ APPLY_POLICY: `${BASE_API_PATH}/applyPolicy`, EDIT_ROLLOVER_ALIAS: `${BASE_API_PATH}/editRolloverAlias`, POLICIES: `${BASE_API_PATH}/policies`, - ROLLUPS: `${BASE_API_PATH}/rollups`, _RECOVERY: `${BASE_API_PATH}/_recovery`, + ROLLUPS: `${BASE_API_PATH}/rollups`, TRANSFORMS: `${BASE_API_PATH}/transforms`, MANAGED_INDICES: `${BASE_API_PATH}/managedIndices`, CHANNELS: `${BASE_API_PATH}/_notifications/channels`, From efc525c17f280f86753a8c7a184bdff3bdb95769 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 12 Sep 2022 17:20:19 -0700 Subject: [PATCH 043/160] Current progress extracting data and displaying in Restore activities Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 65 +++++++++++++++---- server/models/interfaces.ts | 30 ++++++++- server/services/SnapshotManagementService.ts | 4 +- 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index bc09b6cca..61c72368d 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -5,9 +5,13 @@ import { EuiInMemoryTable } from "@elastic/eui"; import _ from "lodash"; -import React, { useEffect } from "react"; +import React, { useEffect, useContext, useState } from "react"; import { IndexService, SnapshotManagementService } from "../../../../services"; +import { CoreServicesContext } from "../../../../components/core_services"; +import { getErrorMessage } from "../../../../utils/helpers"; +import { GetIndexRecoveryResponse } from "../../../../../server/models/interfaces"; import { ContentPanel } from "../../../../components/ContentPanel"; +import { info } from "console"; interface RestoreActivitiesPanelProps { snapshotManagementService: SnapshotManagementService; @@ -16,26 +20,65 @@ interface RestoreActivitiesPanelProps { } export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { + const [restoreStatus, setRestoreStatus] = useState([]); + const context = useContext(CoreServicesContext); + useEffect(() => { getRestoreStatus(); + // const newInterval = setInterval(() => { + // getRestoreStatus(); + // }, 5000); + // return () => clearInterval(newInterval); }, []); const getRestoreStatus = async () => { - const status = await snapshotManagementService.getIndexRecovery(); - console.log("status", status); + try { + const res = await snapshotManagementService.getIndexRecovery(); + + if (res.ok) { + const response: GetIndexRecoveryResponse = res.response; + console.log(response); + + let restoreInfo: object; + let minStartTime: number | null = null; + let maxStopTime: number | null = null; + // let item: string; + for (let item in response) { + const info = response[item].shards[0]; + const stats = { + index: info.source.index, + status: info.stage, + start_time: info.start_time_in_millis, + stop_time: info.stop_time_in_millis, + }; + minStartTime = minStartTime && minStartTime < stats.start_time ? minStartTime : stats.start_time; + maxStopTime = maxStopTime && maxStopTime > stats.stop_time ? maxStopTime : stats.stop_time; + } + setRestoreStatus([{ start_time: minStartTime, stop_time: maxStopTime, snapshot: snapshotId, status: "OK", indices: 3 }]); + } else { + context?.notifications.toasts.addDanger(res.error); + } + } catch (err) { + context?.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem loading the recovery.")); + } }; + // const status = response.map((item: GetIndexRecoveryResponse) => { + // return ({ + // index: item.shards[0].source.index, + // status: item.shards[0].stage, + // start_time: item.shards[0].start_time_in_millis, + // completion_time: item.shards[0].stop_time_in_millis, + // }) + // }) + const columns = [ { - field: "index", - name: "Index", - }, - { - field: "start_epoch", + field: "start_time", name: "Start time", }, { - field: "end_epoch", + field: "stop_time", name: "Completion time", }, { @@ -43,7 +86,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService name: "Snapshot name", }, { - field: "stage", + field: "status", name: "Status", }, { @@ -55,7 +98,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService return ( <> - + ); diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 5d3aa49bd..dbe5699d0 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -22,6 +22,7 @@ import { Rollup, Transform, } from "../../models/interfaces"; +import { getIndexToDataStreamMapping } from "../services/DataStreamService"; export interface NodeServices { indexService: IndexService; @@ -365,7 +366,34 @@ export interface GetSnapshotsResponse { } export interface GetIndexRecoveryResponse { - response: any; + response: { + shards: [ + { + source: { + index: string; + repository: string; + snapshot: string; + }; + stage: string; + start_time_in_millis: number; + stop_time_in_millis: number; + } + ]; + }; +} +export interface IndexRecoveryResponse { + shards: [ + { + source: { + index: string; + repository: string; + snapshot: string; + }; + stage: string; + start_time_in_millis: number; + stop_time_in_millis: number; + } + ]; } export interface CatSnapshotWithRepoAndPolicy { diff --git a/server/services/SnapshotManagementService.ts b/server/services/SnapshotManagementService.ts index 8f31860fa..44930deb0 100644 --- a/server/services/SnapshotManagementService.ts +++ b/server/services/SnapshotManagementService.ts @@ -491,10 +491,10 @@ export default class SnapshotManagementService { context: RequestHandlerContext, request: OpenSearchDashboardsRequest, response: OpenSearchDashboardsResponseFactory - ): Promise>> => { + ): Promise>> => { try { const { callAsCurrentUser: callWithRequest } = this.osDriver.asScoped(request); - const res: GetIndexRecoveryResponse[] = await callWithRequest("indices.recovery", { + const res: GetIndexRecoveryResponse = await callWithRequest("indices.recovery", { format: "json", }); return response.custom({ From 0a7f6eee9ec49842492203505b6a292ee9777c2b Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 10:29:58 -0700 Subject: [PATCH 044/160] Implement Restore Activities with self updating until restore done Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 98 ++++++++++++------- 1 file changed, 64 insertions(+), 34 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 61c72368d..c5838264f 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiInMemoryTable } from "@elastic/eui"; +import { EuiInMemoryTable, EuiSpacer, EuiLink } from "@elastic/eui"; import _ from "lodash"; import React, { useEffect, useContext, useState } from "react"; import { IndexService, SnapshotManagementService } from "../../../../services"; @@ -20,16 +20,21 @@ interface RestoreActivitiesPanelProps { } export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { - const [restoreStatus, setRestoreStatus] = useState([]); const context = useContext(CoreServicesContext); + const [startTime, setStartTime] = useState(""); + const [stopTime, setStopTime] = useState(""); + const [stage, setStage] = useState(""); + const [indices, setIndices] = useState([{}]); useEffect(() => { - getRestoreStatus(); - // const newInterval = setInterval(() => { - // getRestoreStatus(); - // }, 5000); - // return () => clearInterval(newInterval); - }, []); + if (stage.indexOf("DONE") < 0) { + getRestoreStatus(); + const newInterval = setInterval(() => { + getRestoreStatus(); + }, 2000); + return () => clearInterval(newInterval); + } + }, [stage]); const getRestoreStatus = async () => { try { @@ -37,24 +42,9 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService if (res.ok) { const response: GetIndexRecoveryResponse = res.response; - console.log(response); - let restoreInfo: object; - let minStartTime: number | null = null; - let maxStopTime: number | null = null; - // let item: string; - for (let item in response) { - const info = response[item].shards[0]; - const stats = { - index: info.source.index, - status: info.stage, - start_time: info.start_time_in_millis, - stop_time: info.stop_time_in_millis, - }; - minStartTime = minStartTime && minStartTime < stats.start_time ? minStartTime : stats.start_time; - maxStopTime = maxStopTime && maxStopTime > stats.stop_time ? maxStopTime : stats.stop_time; - } - setRestoreStatus([{ start_time: minStartTime, stop_time: maxStopTime, snapshot: snapshotId, status: "OK", indices: 3 }]); + setRestoreStatus(response); + console.log(response); } else { context?.notifications.toasts.addDanger(res.error); } @@ -63,15 +53,51 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService } }; - // const status = response.map((item: GetIndexRecoveryResponse) => { - // return ({ - // index: item.shards[0].source.index, - // status: item.shards[0].stage, - // start_time: item.shards[0].start_time_in_millis, - // completion_time: item.shards[0].stop_time_in_millis, - // }) - // }) + const setRestoreStatus = (response: object) => { + let minStartTime: number = 0; + let maxStopTime: number = 0; + let stageIndex: number = Infinity; + let doneCount: number = 0; + const indexes: object[] = []; + const stages: string[] = ["START", "INIT", "INDEX", "FINALIZE", "DONE"]; + + for (let item in response) { + const info = response[item].shards[0]; + const stage = stages.indexOf(info.stage); + const size = `${(info.index.size.total_in_bytes / 1024 ** 2).toFixed(2)}MB`; + const time = { + start_time: info.start_time_in_millis, + stop_time: info.stop_time_in_millis, + }; + + doneCount = stage === 4 ? doneCount + 1 : doneCount; + stageIndex = stage < stageIndex ? stage : stageIndex; + minStartTime = minStartTime && minStartTime < time.start_time ? minStartTime : time.start_time; + maxStopTime = maxStopTime && maxStopTime > time.stop_time ? maxStopTime : time.stop_time; + if (info.source.index) { + indexes.push({ index: info.source.index, size: size }); + } + } + let percent = Math.floor((doneCount / indices.length) * 100); + percent = stageIndex === 4 ? 100 : percent; + + setStartTime(new Date(minStartTime).toLocaleString().replace(",", " ")); + setStopTime(new Date(maxStopTime).toLocaleString().replace(",", " ")); + setIndices(indexes); + setStage(`${stages[stageIndex]} (${percent}%)`); + }; + + const indexes = `${indices.length} Indices`; + const restoreStatus = [ + { + start_time: startTime, + stop_time: stopTime, + snapshot: snapshotId, + status: stage, + indices: indexes, + }, + ]; const columns = [ { field: "start_time", @@ -98,7 +124,11 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService return ( <> - + + + + + ); From c752956f3be3f45bf08dbc1097a8b8c1dad8d711 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 11:00:14 -0700 Subject: [PATCH 045/160] Add clickable indexes link and hello world click handler Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel/RestoreActivitiesPanel.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index c5838264f..4448ab724 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -53,6 +53,11 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService } }; + const onIndexesClick = (e: React.MouseEvent) => { + e.preventDefault(); + console.log("index clicked"); + }; + const setRestoreStatus = (response: object) => { let minStartTime: number = 0; let maxStopTime: number = 0; @@ -95,7 +100,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService stop_time: stopTime, snapshot: snapshotId, status: stage, - indices: indexes, + indexes: indexes, }, ]; const columns = [ @@ -116,8 +121,9 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService name: "Status", }, { - field: "indices", + field: "indexes", name: "Indices being restored", + render: (text: object) => {text}, }, ]; From 988c9ef622d1d7b492e19d4598c9edadb80f82f1 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 12:37:28 -0700 Subject: [PATCH 046/160] Add toast if no snapshot selected upon restore activities click Signed-off-by: Chris Hesterman Add empty flyout where restoring indices will be listed Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 12 ++++++++++-- .../Snapshots/containers/Snapshots/Snapshots.tsx | 9 ++++++++- public/utils/constants.ts | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 4448ab724..4d3194ae0 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -3,15 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiInMemoryTable, EuiSpacer, EuiLink } from "@elastic/eui"; +import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout } from "@elastic/eui"; import _ from "lodash"; import React, { useEffect, useContext, useState } from "react"; import { IndexService, SnapshotManagementService } from "../../../../services"; import { CoreServicesContext } from "../../../../components/core_services"; import { getErrorMessage } from "../../../../utils/helpers"; import { GetIndexRecoveryResponse } from "../../../../../server/models/interfaces"; +import { BREADCRUMBS } from "../../../../utils/constants"; import { ContentPanel } from "../../../../components/ContentPanel"; -import { info } from "console"; interface RestoreActivitiesPanelProps { snapshotManagementService: SnapshotManagementService; @@ -25,8 +25,10 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService const [stopTime, setStopTime] = useState(""); const [stage, setStage] = useState(""); const [indices, setIndices] = useState([{}]); + const [flyout, setFlyout] = useState(false); useEffect(() => { + context!.chrome.setBreadcrumbs([BREADCRUMBS.SNAPSHOT_MANAGEMENT, BREADCRUMBS.SNAPSHOTS, BREADCRUMBS.SNAPSHOT_RESTORE]); if (stage.indexOf("DONE") < 0) { getRestoreStatus(); const newInterval = setInterval(() => { @@ -55,9 +57,14 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService const onIndexesClick = (e: React.MouseEvent) => { e.preventDefault(); + setFlyout(true); console.log("index clicked"); }; + const onCloseFlyout = () => { + setFlyout(false); + }; + const setRestoreStatus = (response: object) => { let minStartTime: number = 0; let maxStopTime: number = 0; @@ -129,6 +136,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService return ( <> + {flyout && } diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index bfe6321f7..6c709310e 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -245,12 +245,19 @@ export default class Snapshots extends Component onClickTab = (e: React.MouseEvent) => { e.stopPropagation(); + const { selectedItems } = this.state; const target = e.currentTarget; - const snapshotPanel = target.textContent === "Snapshots" ? true : false; const prev = target.previousElementSibling; const next = target.nextElementSibling; + if (selectedItems.length === 0) { + this.context.notifications.toasts.addDanger("Please select a snapshot to view restore activities"); + return; + } + + this.context.chrome.setBreadcrumbs([BREADCRUMBS.SNAPSHOT_MANAGEMENT, BREADCRUMBS.SNAPSHOTS]); + target.ariaSelected = "true"; target.classList.add("euiTab-isSelected"); diff --git a/public/utils/constants.ts b/public/utils/constants.ts index 3e36de0fe..681bf10dd 100644 --- a/public/utils/constants.ts +++ b/public/utils/constants.ts @@ -77,6 +77,7 @@ export const BREADCRUMBS = Object.freeze({ EDIT_SNAPSHOT_POLICY: { text: "Edit snapshot policy" }, SNAPSHOTS: { text: "Snapshots", href: `#${ROUTES.SNAPSHOTS}` }, + SNAPSHOT_RESTORE: { text: "Restore activities in progress" }, CREATE_SNAPSHOT: { text: "Create repository", href: `#${ROUTES.CREATE_REPOSITORY}` }, EDIT_SNAPSHOT: { text: "Edit repository", href: `#${ROUTES.EDIT_REPOSITORY}` }, From f35c282ea6d1fe8fdfcb24ee3bcd3738a39711e0 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 12:50:04 -0700 Subject: [PATCH 047/160] Change danger toast to warning when no snapshot selected Signed-off-by: Chris Hesterman --- public/pages/Snapshots/containers/Snapshots/Snapshots.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 6c709310e..21b8781e2 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -252,7 +252,7 @@ export default class Snapshots extends Component const next = target.nextElementSibling; if (selectedItems.length === 0) { - this.context.notifications.toasts.addDanger("Please select a snapshot to view restore activities"); + this.context.notifications.toasts.addWarning("Please select a snapshot to view restore activities"); return; } From cc8afc648c7d1efe8d696d4a701e3c56a79d31eb Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 13:28:26 -0700 Subject: [PATCH 048/160] Fix bug when both custom settings and ignore settings chosen Signed-off-by: Chris Hesterman --- .../SnapshotRestoreAdvancedOptions.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx index d8a719f94..5c38f1e08 100644 --- a/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx +++ b/public/pages/Snapshots/components/SnapshotRestoreAdvancedOptions/SnapshotRestoreAdvancedOptions.tsx @@ -114,7 +114,7 @@ const SnapshotRestoreAdvancedOptions = ({ onChange={onCustomizeIndexSettingsToggle} /> - {customizeIndexSettings && } + {customizeIndexSettings && } @@ -127,7 +127,7 @@ const SnapshotRestoreAdvancedOptions = ({ onChange={onIgnoreIndexSettingsToggle} /> - {ignoreIndexSettings && } + {ignoreIndexSettings && }
); }; From 1053f95af2d44e9a0ee0da1ab9fe1a2e4d3e3738 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Tue, 13 Sep 2022 14:26:00 -0700 Subject: [PATCH 049/160] Add refresh button to restore activities page, remove auto refreshing Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 4d3194ae0..7b07c5b26 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -3,7 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout } from "@elastic/eui"; +import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout, EuiButton } from "@elastic/eui"; import _ from "lodash"; import React, { useEffect, useContext, useState } from "react"; import { IndexService, SnapshotManagementService } from "../../../../services"; @@ -29,16 +29,14 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService useEffect(() => { context!.chrome.setBreadcrumbs([BREADCRUMBS.SNAPSHOT_MANAGEMENT, BREADCRUMBS.SNAPSHOTS, BREADCRUMBS.SNAPSHOT_RESTORE]); - if (stage.indexOf("DONE") < 0) { - getRestoreStatus(); - const newInterval = setInterval(() => { - getRestoreStatus(); - }, 2000); - return () => clearInterval(newInterval); - } - }, [stage]); + getRestoreStatus(); + }, []); const getRestoreStatus = async () => { + if (stage.indexOf("DONE") >= 0) { + console.log("done"); + return; + } try { const res = await snapshotManagementService.getIndexRecovery(); @@ -100,6 +98,12 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService setStage(`${stages[stageIndex]} (${percent}%)`); }; + const actions = [ + + Refresh + , + ]; + const indexes = `${indices.length} Indices`; const restoreStatus = [ { @@ -137,7 +141,7 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService return ( <> {flyout && } - + From fb7f19e354d14a844ac288adc7bc356db84c74f3 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 14 Sep 2022 17:28:13 -0700 Subject: [PATCH 050/160] Remove unused getRepos func, add repo prop, trim state in RestoreFlyout Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 40 +++++-------------- .../containers/Snapshots/Snapshots.tsx | 1 + 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 9d7734362..b9aba4925 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -23,7 +23,7 @@ import { IndexService, SnapshotManagementService } from "../../../../services"; import { RESTORE_OPTIONS } from "../../../../models/interfaces"; import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; -import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; +import { GetSnapshot } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; @@ -39,6 +39,7 @@ interface RestoreSnapshotProps { onCloseFlyout: () => void; restoreSnapshot: (snapshotId: string, repository: string, options: object) => void; snapshotId: string; + repository: string; } interface RestoreSnapshotState { @@ -50,9 +51,6 @@ interface RestoreSnapshotState { renameReplacement: string; listIndices: boolean; - repositories: CatRepository[]; - selectedRepoValue: string; - snapshot: GetSnapshot | null; snapshotId: string; restoreSpecific: boolean; @@ -74,8 +72,6 @@ export default class RestoreSnapshotFlyout extends Component { - const { restoreSnapshot, snapshotId } = this.props; + const { restoreSnapshot, snapshotId, repository } = this.props; const { - selectedRepoValue, restoreSpecific, selectedIndexOptions, indexOptions, @@ -106,6 +100,7 @@ export default class RestoreSnapshotFlyout extends Component option.label).join(","); const allIndices = indexOptions.map((option) => option.label).join(","); + // TODO replace unintelligible regex below with (.+) and add $1 to user provided prefix then add that to renameReplacement const pattern = renameIndices === add_prefix ? "(? { @@ -162,7 +157,7 @@ export default class RestoreSnapshotFlyout extends Component { - this.getSnapshot(this.props.snapshotId, this.state.selectedRepoValue); + this.getSnapshot(this.props.snapshotId, this.props.repository); }; onCreateOption = (searchValue: string, options: Array>) => { @@ -182,21 +177,6 @@ export default class RestoreSnapshotFlyout extends Component { - try { - const { snapshotManagementService } = this.props; - const response = await snapshotManagementService.catRepositories(); - if (response.ok) { - const selectedRepoValue = response.response.length > 0 ? response.response[0].id : ""; - this.setState({ repositories: response.response, selectedRepoValue }); - } else { - this.context.notifications.toasts.addDanger(response.error); - } - } catch (err) { - this.context.notifications.toasts.addDanger(getErrorMessage(err, "There was a problem loading the snapshots.")); - } - }; - getPrefix = (prefix: string) => { this.setState({ prefix: prefix }); }; @@ -229,8 +209,8 @@ export default class RestoreSnapshotFlyout extends Component )} diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index 108693266..d8e3fbd19 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -359,6 +359,7 @@ export default class Snapshots extends Component onCloseFlyout={this.onCloseRestoreFlyout} restoreSnapshot={this.restoreSnapshot} snapshotId={selectedItems[0].id} + repository={selectedItems[0].repository} /> )} From f553dbe1f17f781875b91181d88d920f0ef90c35 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 15 Sep 2022 09:18:41 -0700 Subject: [PATCH 051/160] Add increment to 2.3.0 Signed-off-by: Chris Hesterman --- .github/workflows/cypress-workflow.yml | 4 ++-- opensearch_dashboards.json | 14 +++++++++----- package.json | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cypress-workflow.yml b/.github/workflows/cypress-workflow.yml index e6ed61a83..f4761673f 100644 --- a/.github/workflows/cypress-workflow.yml +++ b/.github/workflows/cypress-workflow.yml @@ -7,8 +7,8 @@ on: branches: - "*" env: - OPENSEARCH_DASHBOARDS_VERSION: '2.2' - OPENSEARCH_VERSION: '2.2.1-SNAPSHOT' + OPENSEARCH_DASHBOARDS_VERSION: '2.3' + OPENSEARCH_VERSION: '2.3.0-SNAPSHOT' jobs: tests: name: Run Cypress E2E tests diff --git a/opensearch_dashboards.json b/opensearch_dashboards.json index cc814397a..c1418c582 100644 --- a/opensearch_dashboards.json +++ b/opensearch_dashboards.json @@ -1,9 +1,13 @@ { "id": "indexManagementDashboards", - "version": "2.2.1.0", - "opensearchDashboardsVersion": "2.2.1", - "configPath": ["opensearch_index_management"], - "requiredPlugins": ["navigation"], + "version": "2.3.0.0", + "opensearchDashboardsVersion": "2.3.0", + "configPath": [ + "opensearch_index_management" + ], + "requiredPlugins": [ + "navigation" + ], "server": true, "ui": true -} +} \ No newline at end of file diff --git a/package.json b/package.json index 1375eaf89..4e1fb56e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opensearch_index_management_dashboards", - "version": "2.2.1.0", + "version": "2.3.0.0", "description": "Opensearch Dashboards plugin for Index Management", "main": "index.js", "license": "Apache-2.0", @@ -64,4 +64,4 @@ "engines": { "yarn": "^1.21.1" } -} +} \ No newline at end of file From 628e43138329254953c40bcfa4dc62ccf49e3173 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Thu, 15 Sep 2022 10:03:13 -0700 Subject: [PATCH 052/160] Remove index settings from options if none entered, RestoreFlyout Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 570106d1e..ba748ea50 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -50,7 +50,7 @@ interface RestoreSnapshotState { renameReplacement: string; listIndices: boolean; customIndexSettings: string; - ignoreIndexSettings: string; + ignoreIndexSettings?: string; repositories: CatRepository[]; selectedRepoValue: string; @@ -127,6 +127,12 @@ export default class RestoreSnapshotFlyout extends Component Date: Fri, 16 Sep 2022 11:54:21 -0700 Subject: [PATCH 053/160] Add rel="noopener noreferrer" to links in help text, use url from constants. Signed-off-by: Chris Hesterman --- .../Snapshots/components/RenameInput/RenameInput.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx index 768e9175b..b5ed60ffb 100644 --- a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx @@ -5,6 +5,7 @@ import { EuiFormRow, EuiFieldText, EuiSpacer, EuiText } from "@elastic/eui"; import React, { useState, ChangeEvent } from "react"; +import { RESTORE_SNAPSHOT_DOCUMENTATION_URL } from "../../../../utils/constants" interface RenameInputProps { getRenamePattern: (prefix: string) => void; getRenameReplacement: (prefix: string) => void; @@ -24,11 +25,6 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp getRenameReplacement(e.target.value); }; - const renamePatternUrl = - "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-rename-pattern"; - const renameReplacementUrl = - "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-rename-replacement"; - return ( <> @@ -41,7 +37,7 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp Use regular expression to define how index names will be renamed.
By default, input (.+) to reuse the entire index name.{" "} - + [Learn more]

@@ -62,7 +58,7 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp entire matching index name, $1 to include the content of the first
capture group, etc.{" "} - + [Learn more]

From 350f31adef2319057b808670975e2899721d924e Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 16 Sep 2022 12:03:11 -0700 Subject: [PATCH 054/160] Create CatSnapshotIndex in server/models/interfaces, apply in IndexList Signed-off-by: Chris Hesterman --- .../Snapshots/components/IndexList/IndexList.tsx | 15 ++++----------- server/models/interfaces.ts | 13 +++++++++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/public/pages/Snapshots/components/IndexList/IndexList.tsx b/public/pages/Snapshots/components/IndexList/IndexList.tsx index 951a3a721..ea462cbdb 100644 --- a/public/pages/Snapshots/components/IndexList/IndexList.tsx +++ b/public/pages/Snapshots/components/IndexList/IndexList.tsx @@ -5,16 +5,16 @@ import { EuiInMemoryTable, EuiIcon, EuiFlyoutHeader, EuiTitle } from "@elastic/eui"; import React from "react"; -import { CatIndex } from "../../../../../server/models/interfaces"; +import { CatSnapshotIndex } from "../../../../../server/models/interfaces"; interface IndexListProps { - indices: CatIndex[]; + indices: CatSnapshotIndex[]; snapshot: string; onClick: (e: React.MouseEvent) => void; } const IndexList = ({ indices, snapshot, onClick }: IndexListProps) => { - indices = indices.filter((index) => index.index.substring(0, 7) !== ".kibana"); + indices = indices.filter((index) => index.index?.substring(0, 7) !== ".kibana"); const columns = [ { @@ -30,13 +30,6 @@ const IndexList = ({ indices, snapshot, onClick }: IndexListProps) => { }, ]; - const sorting = { - sort: { - field: "index", - direction: "asc", - }, - }; - return ( <> @@ -48,7 +41,7 @@ const IndexList = ({ indices, snapshot, onClick }: IndexListProps) => {
- +
); diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index 8b380c943..0fba3096c 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -170,13 +170,13 @@ export interface IndexUpdateResponse { failedIndices: FailedIndex[]; } -export interface ApplyPolicyResponse extends IndexUpdateResponse {} +export interface ApplyPolicyResponse extends IndexUpdateResponse { } -export interface RemovePolicyResponse extends IndexUpdateResponse {} +export interface RemovePolicyResponse extends IndexUpdateResponse { } -export interface ChangePolicyResponse extends IndexUpdateResponse {} +export interface ChangePolicyResponse extends IndexUpdateResponse { } -export interface RetryManagedIndexResponse extends IndexUpdateResponse {} +export interface RetryManagedIndexResponse extends IndexUpdateResponse { } export interface RetryParams { index: string; @@ -333,6 +333,11 @@ export interface CatIndex { data_stream: string | null; } +export interface CatSnapshotIndex { + index?: string; + "store.size"?: string; +} + export interface ManagedCatIndex extends CatIndex { managed: string; } From 92d38f468d57ef77264a40c3e8b9010a3d1229a6 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 16 Sep 2022 12:21:51 -0700 Subject: [PATCH 055/160] Add rel="noopener noreferrer" to links in IndexList, add CatSnapshotIndex interface Signed-off-by: Chris Hesterman --- .../IndexSettingsInput/IndexSettingsInput.tsx | 6 ++---- .../RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx | 4 +++- server/models/interfaces.ts | 13 +++++++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx index 245e93df1..d867b7b84 100644 --- a/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx +++ b/public/pages/Snapshots/components/IndexSettingsInput/IndexSettingsInput.tsx @@ -5,6 +5,7 @@ import { EuiFormRow, EuiText, EuiTextArea, EuiSpacer } from "@elastic/eui"; import React, { useState, ChangeEvent } from "react"; +import { RESTORE_SNAPSHOT_DOCUMENTATION_URL } from "../../../../utils/constants" interface IndexSettingsInputProps { getIndexSettings: (indexSettings: string) => void; @@ -20,9 +21,6 @@ const IndexSettingsInput = ({ getIndexSettings, ignore }: IndexSettingsInputProp }; const title = ignore ? "Specify index settings to ignore" : "Specify custom index settings"; - const indexSettingsUrl = ignore - ? "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-ignore-index-settings" - : "https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restore-snapshot-api.html#restore-snapshot-api-index-settings"; const helperText = ignore ? "Specify a comma-delimited list of settings to exclude from a snapshot." : "Specify a comma-delimited list of settings to override in all restored indices."; @@ -40,7 +38,7 @@ const IndexSettingsInput = ({ getIndexSettings, ignore }: IndexSettingsInputProp

{helperText} - + [Learn more]

diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index ba748ea50..080a3aab1 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -23,7 +23,7 @@ import { IndexService, SnapshotManagementService } from "../../../../services"; import { RESTORE_OPTIONS } from "../../../../models/interfaces"; import { getErrorMessage } from "../../../../utils/helpers"; import { IndexItem } from "../../../../../models/interfaces"; -import { CatRepository, GetSnapshot } from "../../../../../server/models/interfaces"; +import { CatRepository, GetSnapshot, CatSnapshotIndex } from "../../../../../server/models/interfaces"; import CustomLabel from "../../../../components/CustomLabel"; import SnapshotRestoreAdvancedOptions from "../SnapshotRestoreAdvancedOptions"; import SnapshotRestoreOption from "../SnapshotRestoreOption"; @@ -51,6 +51,7 @@ interface RestoreSnapshotState { listIndices: boolean; customIndexSettings: string; ignoreIndexSettings?: string; + indicesList: CatSnapshotIndex[]; repositories: CatRepository[]; selectedRepoValue: string; @@ -78,6 +79,7 @@ export default class RestoreSnapshotFlyout extends Component Date: Fri, 16 Sep 2022 12:57:29 -0700 Subject: [PATCH 056/160] Changes to RestoreActivitesPanel to prep for listing indice Signed-off-by: Chris Hesterman --- .../RestoreActivitiesPanel.tsx | 45 ++++++++++--------- server/models/interfaces.ts | 13 ++++-- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx index 7b07c5b26..aefb96181 100644 --- a/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx +++ b/public/pages/Snapshots/components/RestoreActivitiesPanel/RestoreActivitiesPanel.tsx @@ -6,20 +6,20 @@ import { EuiInMemoryTable, EuiSpacer, EuiLink, EuiFlyout, EuiButton } from "@elastic/eui"; import _ from "lodash"; import React, { useEffect, useContext, useState } from "react"; -import { IndexService, SnapshotManagementService } from "../../../../services"; +import { SnapshotManagementService } from "../../../../services"; import { CoreServicesContext } from "../../../../components/core_services"; import { getErrorMessage } from "../../../../utils/helpers"; -import { GetIndexRecoveryResponse } from "../../../../../server/models/interfaces"; +import { GetIndexRecoveryResponse, CatSnapshotIndex } from "../../../../../server/models/interfaces"; import { BREADCRUMBS } from "../../../../utils/constants"; import { ContentPanel } from "../../../../components/ContentPanel"; interface RestoreActivitiesPanelProps { snapshotManagementService: SnapshotManagementService; - indexService: IndexService; snapshotId: string; + repository: string; } -export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService, snapshotId }: RestoreActivitiesPanelProps) => { +export const RestoreActivitiesPanel = ({ snapshotManagementService, snapshotId }: RestoreActivitiesPanelProps) => { const context = useContext(CoreServicesContext); const [startTime, setStartTime] = useState(""); const [stopTime, setStopTime] = useState(""); @@ -63,30 +63,33 @@ export const RestoreActivitiesPanel = ({ snapshotManagementService, indexService setFlyout(false); }; - const setRestoreStatus = (response: object) => { + const setRestoreStatus = (response: GetIndexRecoveryResponse) => { let minStartTime: number = 0; let maxStopTime: number = 0; let stageIndex: number = Infinity; let doneCount: number = 0; - const indexes: object[] = []; + const indexes: CatSnapshotIndex[] = []; const stages: string[] = ["START", "INIT", "INDEX", "FINALIZE", "DONE"]; for (let item in response) { - const info = response[item].shards[0]; - const stage = stages.indexOf(info.stage); - const size = `${(info.index.size.total_in_bytes / 1024 ** 2).toFixed(2)}MB`; - - const time = { - start_time: info.start_time_in_millis, - stop_time: info.stop_time_in_millis, - }; - - doneCount = stage === 4 ? doneCount + 1 : doneCount; - stageIndex = stage < stageIndex ? stage : stageIndex; - minStartTime = minStartTime && minStartTime < time.start_time ? minStartTime : time.start_time; - maxStopTime = maxStopTime && maxStopTime > time.stop_time ? maxStopTime : time.stop_time; - if (info.source.index) { - indexes.push({ index: info.source.index, size: size }); + if (item.indexOf("kibana") < 0) { + const info = response[item as keyof GetIndexRecoveryResponse].shards[0] + const stage = stages.indexOf(info.stage); + const size = `${(info.index.size.total_in_bytes / 1024 ** 2).toFixed(2)}mb`; + + const time = { + start_time: info.start_time_in_millis, + stop_time: info.stop_time_in_millis, + }; + + doneCount = stage === 4 ? doneCount + 1 : doneCount; + stageIndex = stage < stageIndex ? stage : stageIndex; + minStartTime = minStartTime && minStartTime < time.start_time ? minStartTime : time.start_time; + maxStopTime = maxStopTime && maxStopTime > time.stop_time ? maxStopTime : time.stop_time; + + if (info.source.index) { + indexes.push({ index: info.source.index, "store.size": size }); + } } } let percent = Math.floor((doneCount / indices.length) * 100); diff --git a/server/models/interfaces.ts b/server/models/interfaces.ts index dbe5699d0..c3f51f4af 100644 --- a/server/models/interfaces.ts +++ b/server/models/interfaces.ts @@ -171,13 +171,13 @@ export interface IndexUpdateResponse { failedIndices: FailedIndex[]; } -export interface ApplyPolicyResponse extends IndexUpdateResponse {} +export interface ApplyPolicyResponse extends IndexUpdateResponse { } -export interface RemovePolicyResponse extends IndexUpdateResponse {} +export interface RemovePolicyResponse extends IndexUpdateResponse { } -export interface ChangePolicyResponse extends IndexUpdateResponse {} +export interface ChangePolicyResponse extends IndexUpdateResponse { } -export interface RetryManagedIndexResponse extends IndexUpdateResponse {} +export interface RetryManagedIndexResponse extends IndexUpdateResponse { } export interface RetryParams { index: string; @@ -334,6 +334,11 @@ export interface CatIndex { data_stream: string | null; } +export interface CatSnapshotIndex { + index?: string; + "store.size"?: string; +} + export interface ManagedCatIndex extends CatIndex { managed: string; } From b185b41361fed944d8988446032e8ba6212c43e9 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Fri, 16 Sep 2022 14:33:50 -0700 Subject: [PATCH 057/160] Re do merge commit - forgot to save file. Signed-off-by: Chris Hesterman --- .../RestoreSnapshotFlyout.tsx | 77 ++++++------------- 1 file changed, 25 insertions(+), 52 deletions(-) diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index 902ed6d60..e1151238f 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -53,6 +53,8 @@ interface RestoreSnapshotState { listIndices: boolean; indicesList: CatIndex[]; + repositories: CatRepository[], + selectedRepoValue: string, snapshot: GetSnapshot | null; restoreSpecific: boolean; partial: boolean; @@ -73,12 +75,9 @@ export default class RestoreSnapshotFlyout extends Component>>>>>> update_branch_to_latest snapshot: null, restoreSpecific: false, partial: false, @@ -171,13 +170,9 @@ export default class RestoreSnapshotFlyout extends Component { -<<<<<<< HEAD const { snapshotId } = this.props; const { selectedRepoValue } = this.state; this.getSnapshot(snapshotId, selectedRepoValue); -======= - this.getSnapshot(this.props.snapshotId, this.props.repository); ->>>>>>> update_branch_to_latest }; onCreateOption = (searchValue: string, options: Array>) => { @@ -197,7 +192,6 @@ export default class RestoreSnapshotFlyout extends Component { try { const { snapshotManagementService } = this.props; @@ -228,8 +222,6 @@ export default class RestoreSnapshotFlyout extends Component>>>>>> update_branch_to_latest getPrefix = (prefix: string) => { this.setState({ prefix: prefix }); }; @@ -262,7 +254,6 @@ export default class RestoreSnapshotFlyout extends Component>>>>>> update_branch_to_latest const { do_not_rename, @@ -330,33 +317,19 @@ export default class RestoreSnapshotFlyout extends Component -<<<<<<< HEAD - { - restoreSpecific && ( - - ) - } -======= - {restoreSpecific && ( - - )} ->>>>>>> update_branch_to_latest + { + restoreSpecific && ( + + ) + } @@ -370,12 +343,12 @@ export default class RestoreSnapshotFlyout extends Component - { renameIndices === add_prefix && } - { - renameIndices === rename_indices && ( - - ) - } + {renameIndices === add_prefix && } + { + renameIndices === rename_indices && ( + + ) + } @@ -399,12 +372,12 @@ export default class RestoreSnapshotFlyout extends Component
- - - + + + ) - } + } ); } From 4f4e5d68b106767f144d839e2f81410d5ccd4541 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Sun, 18 Sep 2022 16:44:45 -0700 Subject: [PATCH 058/160] Snapshots testing in progress Signed-off-by: Chris Hesterman --- cypress.json | 3 +- cypress/integration/snapshots_spec.js | 86 +++++++++---------- cypress/support/commands.js | 7 +- .../containers/Snapshots/Snapshots.tsx | 2 +- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/cypress.json b/cypress.json index 676ad4cb2..ef5dce071 100644 --- a/cypress.json +++ b/cypress.json @@ -2,6 +2,7 @@ "viewportHeight": 900, "viewportWidth": 1440, "defaultCommandTimeout": 10000, + "nodeVersion": "system", "env": { "opensearch_url": "localhost:9200", "opensearch_dashboards": "http://localhost:5601", @@ -9,4 +10,4 @@ "username": "admin", "password": "admin" } -} +} \ No newline at end of file diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js index b412fbd74..5a7bf733d 100644 --- a/cypress/integration/snapshots_spec.js +++ b/cypress/integration/snapshots_spec.js @@ -6,44 +6,6 @@ import { PLUGIN_NAME } from "../support/constants"; describe("Snapshots", () => { - before(() => { - // Delete any existing indices - cy.deleteAllIndices(); - - // Load ecommerce data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - - // Load flight data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/flights`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - - // Load web log data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/logs`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - }); - beforeEach(() => { // Set welcome screen tracking to false localStorage.setItem("home:welcome:show", "false"); @@ -79,24 +41,62 @@ describe("Snapshots", () => { describe("Snapshot can be created", () => { it("successfully creates a new snapshot", () => { + // delete any existing indices + cy.deleteAllIndices(); + + // create test indices + cy.createIndex("test_index_1"); + cy.createIndex("test_index_2"); + cy.createIndex("test_index_3"); + // Click Take snapshot button cy.get("button").contains("Take snapshot").click({ force: true }); + // Confirm test_repo exists and is in the Select repo field + cy.contains("test_repo"); + // Type in Snapshot name cy.get(`input[data-test-subj="snapshotNameInput"]`).type("test_snapshot{enter}"); - // Select indexes to be included + // Select all indexes to be included cy.get(`[data-test-subj="indicesComboBoxInput"]`).type("open*{enter}"); - // Confirm test_repo exists - cy.contains("test_repo"); + // Click 'Add' button to create snapshot cy.get("button").contains("Add").click({ force: true }); + cy.wait(3000) // check for success status and snapshot name - cy.contains("In_progress"); - cy.contains("test_snapshot"); + cy.get("button").contains("Refresh").click({ force: true }); + + cy.contains("Success"); + + // remove all indices + cy.deleteAllIndices(); }); }); + + describe("Snapshot can be restored", () => { + it("Successfully restores indices from snapshot", () => { + // Select test snapshot + cy.get(`[data-test-subj="checkboxSelectRow-test_repo:test_snapshot"]`).check({ force: true }); + + // click "Restore" button + cy.get(`[data-test-subj="restoreButton"]`).click({ force: true }); + + // Check for restore flyout + cy.contains("Restore snapshot"); + + // Click restore snapshot button + cy.get("button").contains("Restore snapshot").click({ force: true }); + + // Check for success toast + cy.contains("Restored snapshot test_snapshot to repository test_repo"); + + }) + }); + + describe("Snapshot can be deleted", () => { + }) }); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index 1f021b922..0850da201 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -4,6 +4,7 @@ */ const { API, INDEX, ADMIN_AUTH } = require("./constants"); +const { NODE_API } = require("../../server/utils/constants") // *********************************************** // This example commands.js shows you how to @@ -79,7 +80,7 @@ Cypress.Commands.overwrite("request", (originalFn, ...args) => { }); Cypress.Commands.add("deleteAllIndices", () => { - cy.request("DELETE", `${Cypress.env("opensearch")}/index*,sample*,opensearch_dashboards*`); + cy.request("DELETE", `${Cypress.env("opensearch")}/index*,sample*,opensearch_dashboards*,test*`); cy.request("DELETE", `${Cypress.env("opensearch")}/.opendistro-ism*?expand_wildcards=all`); }); @@ -121,6 +122,10 @@ Cypress.Commands.add("createIndex", (index, policyID = null, settings = {}) => { } }); +Cypress.Commands.add("deleteSnapshot", (repository, snapshot) => { + cy.request("DELETE", `${Cypress.env("opensearch")}${NODE_API._SNAPSHOTS}/${repository}/${snapshot}`) +}) + Cypress.Commands.add("createRollup", (rollupId, rollupJSON) => { cy.request("PUT", `${Cypress.env("opensearch")}${API.ROLLUP_JOBS_BASE}/${rollupId}`, rollupJSON); }); diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index d83158007..f04f03dc7 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -326,7 +326,7 @@ export default class Snapshots extends Component Delete , - + Restore , From ccca9bb2d19bad28033110455ffe976b8fdd5da5 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Mon, 19 Sep 2022 09:01:29 -0700 Subject: [PATCH 059/160] Current progress, cypress testing Signed-off-by: Chris Hesterman --- cypress/integration/snapshots_spec.js | 106 +++++++++++------- .../AddPrefixInput/AddPrefixInput.tsx | 2 +- .../RestoreSnapshotFlyout.tsx | 2 +- .../containers/Snapshots/Snapshots.tsx | 2 +- 4 files changed, 66 insertions(+), 46 deletions(-) diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js index b412fbd74..844870f23 100644 --- a/cypress/integration/snapshots_spec.js +++ b/cypress/integration/snapshots_spec.js @@ -7,44 +7,6 @@ import { PLUGIN_NAME } from "../support/constants"; describe("Snapshots", () => { before(() => { - // Delete any existing indices - cy.deleteAllIndices(); - - // Load ecommerce data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/ecommerce`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - - // Load flight data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/flights`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - - // Load web log data - cy.request({ - method: "POST", - url: `${Cypress.env("opensearch_dashboards")}/api/sample_data/logs`, - headers: { - "osd-xsrf": true, - }, - }).then((response) => { - expect(response.status).equal(200); - }); - }); - - beforeEach(() => { // Set welcome screen tracking to false localStorage.setItem("home:welcome:show", "false"); @@ -79,24 +41,82 @@ describe("Snapshots", () => { describe("Snapshot can be created", () => { it("successfully creates a new snapshot", () => { + cy.visit(`${Cypress.env("opensearch_dashboards")}/app/${PLUGIN_NAME}#/snapshots`); + + // delete any existing indices + cy.deleteAllIndices(); + + // create test indices + cy.createIndex("test_index_1"); + cy.createIndex("test_index_2"); + cy.createIndex("test_index_3"); + // Click Take snapshot button cy.get("button").contains("Take snapshot").click({ force: true }); + // Confirm test_repo exists and is in the Select repo field + cy.contains("test_repo"); + // Type in Snapshot name cy.get(`input[data-test-subj="snapshotNameInput"]`).type("test_snapshot{enter}"); - // Select indexes to be included + // Select all indexes to be included cy.get(`[data-test-subj="indicesComboBoxInput"]`).type("open*{enter}"); - // Confirm test_repo exists - cy.contains("test_repo"); + // Click 'Add' button to create snapshot cy.get("button").contains("Add").click({ force: true }); + cy.wait(3000) // check for success status and snapshot name - cy.contains("In_progress"); - cy.contains("test_snapshot"); + cy.get("button").contains("Refresh").click({ force: true }); + + cy.contains("Success"); + + // remove all indices + cy.deleteAllIndices(); }); }); + + describe("Snapshot can be restored", () => { + it("Successfully restores indices from snapshot", () => { + // Select test snapshot + cy.get(`[data-test-subj="checkboxSelectRow-test_repo:test_snapshot"]`).check({ force: true }); + + // click "Restore" button + cy.get(`[data-test-subj="restoreButton"]`).click({ force: true }); + + // Check for restore flyout + cy.contains("Restore snapshot"); + + // enter a prefix + cy.get(`input[data-test-subj="prefixInput"]`).type("pre_"); + + // Click restore snapshot button + cy.get("button").contains("Restore snapshot").click({ force: true }); + + // Check for success toast + cy.contains("Restored snapshot test_snapshot to repository test_repo"); + + cy.contains("automatically").click({ force: true }) + + }); + }); + + describe("Snapshot can be deleted", () => { + it("deletes snapshot successfully", async () => { + // Select test snapshot + cy.get(`[data-test-subj="checkboxSelectRow-test_repo:test_snapshot"]`).check({ force: true }); + + // click "Delete" button + cy.get("button").contains("Delete").click({ force: true }); + + // click "Delete snapshot" button on modal + cy.get("button").contains("Delete snapshot"); + + cy.wait(3000); + + }); + }) }); diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx index 4f6dd08c3..04d98aae4 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.tsx @@ -25,7 +25,7 @@ const AddPrefixesInput = ({ getPrefix }: AddPrefixesInputProps) => { - + diff --git a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx index b9aba4925..e005909be 100644 --- a/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx +++ b/public/pages/Snapshots/components/RestoreSnapshotFlyout/RestoreSnapshotFlyout.tsx @@ -225,7 +225,7 @@ export default class RestoreSnapshotFlyout extends Component +

Restore snapshot

diff --git a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx index d8e3fbd19..607bd15e9 100644 --- a/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx +++ b/public/pages/Snapshots/containers/Snapshots/Snapshots.tsx @@ -292,7 +292,7 @@ export default class Snapshots extends Component Delete , - + Restore , From 127f6c15f612305b320eb44affbfc74b5de34d12 Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 21 Sep 2022 14:28:18 -0700 Subject: [PATCH 060/160] Add unit testing for AddPrefixInput, RenameInput components Signed-off-by: Chris Hesterman --- cypress/integration/snapshots_spec.js | 13 ++-- .../AddPrefixInput/AddPrefixInput.test.tsx | 50 +++++++++++++++ .../AddPrefixInput.test.tsx.snap | 7 +++ .../RenameInput/RenameInput.test.tsx | 62 +++++++++++++++++++ .../components/RenameInput/RenameInput.tsx | 4 +- .../__snapshots__/RenameInput.test.tsx.snap | 7 +++ 6 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx create mode 100644 public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap create mode 100644 public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx create mode 100644 public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap diff --git a/cypress/integration/snapshots_spec.js b/cypress/integration/snapshots_spec.js index 844870f23..27c307d93 100644 --- a/cypress/integration/snapshots_spec.js +++ b/cypress/integration/snapshots_spec.js @@ -91,7 +91,7 @@ describe("Snapshots", () => { cy.contains("Restore snapshot"); // enter a prefix - cy.get(`input[data-test-subj="prefixInput"]`).type("pre_"); + cy.get(`input[data-test-subj="prefixInput"]`).type("restored_"); // Click restore snapshot button cy.get("button").contains("Restore snapshot").click({ force: true }); @@ -99,8 +99,10 @@ describe("Snapshots", () => { // Check for success toast cy.contains("Restored snapshot test_snapshot to repository test_repo"); - cy.contains("automatically").click({ force: true }) + cy.contains("automatically").click({ force: true }); + cy.visit(`${Cypress.env("opensearch_dashboards")}/app/${PLUGIN_NAME}#/indices`); + cy.wait(6000); }); }); @@ -111,11 +113,12 @@ describe("Snapshots", () => { // click "Delete" button cy.get("button").contains("Delete").click({ force: true }); - + cy.wait(3000); // click "Delete snapshot" button on modal - cy.get("button").contains("Delete snapshot"); + cy.get("button").contains("Delete snapshot").click({ force: true }); - cy.wait(3000); + cy.contains("Deleted snapshot"); + cy.contains("No items found"); }); }) diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx new file mode 100644 index 000000000..870558b6d --- /dev/null +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx @@ -0,0 +1,50 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { render, screen, cleanup } from "@testing-library/react"; +// @ts-ignore +import userEvent from "@testing-library/user-event"; +import AddPrefixInput from "./AddPrefixInput"; + + +const testProps = { getPrefix: jest.fn() }; + +beforeEach(() => { + render(); +}); + +afterEach(() => { + cleanup(); +}); + +describe("AddPrefixInput component", () => { + it("renders without error", () => { + expect(screen.getByText("Specify prefix for restored index names")).toBeInTheDocument(); + expect(screen.getByTestId("prefixInput")); + + cleanup(); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it("accepts user input", () => { + // User enters text + userEvent.type(screen.getByTestId("prefixInput"), "test_prefix_"); + + expect(screen.getByTestId("prefixInput")).toHaveValue("test_prefix_"); + }); + + it("sends user input to parent component via getPrefix", () => { + // User enters text into prefix input + userEvent.type(screen.getByTestId("prefixInput"), "four"); + + // getPrefix is prop sent from parent component to retrieve user input + expect(testProps.getPrefix).toBeCalledTimes(4); + }); +}); \ No newline at end of file diff --git a/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap b/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap new file mode 100644 index 000000000..b4b8319df --- /dev/null +++ b/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AddPrefixInput component renders without error 1`] = ` +
+`; diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx new file mode 100644 index 000000000..6f6fba84b --- /dev/null +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx @@ -0,0 +1,62 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react"; +// @ts-ignore +import userEvent from "@testing-library/user-event"; +import RenameInput from "./RenameInput"; + + +const testProps = { getRenamePattern: jest.fn(), getRenameReplacement: jest.fn() }; + +beforeEach(() => { + render(); +}); + +afterEach(() => { + cleanup(); +}); + +describe("RenameInput component", () => { + it("renders without error", () => { + expect(screen.getByText("Rename Pattern")).toBeInTheDocument(); + expect(screen.getByText("Rename Replacement")).toBeInTheDocument(); + + cleanup(); + + const { container } = render(); + + expect(container.firstChild).toMatchSnapshot(); + }); + + it("accepts user input", () => { + // User enters text + userEvent.type(screen.getByTestId("renamePatternInput"), "(.+)"); + + expect(screen.getByTestId("renamePatternInput")).toHaveValue("(.+)"); + + userEvent.type(screen.getByTestId("renameReplacementInput"), "test_$1"); + + expect(screen.getByTestId("renameReplacementInput")).toHaveValue("test_$1"); + }); + + it("sends user input to parent component via getRenamePattern", () => { + // User enters text into renamePatternInput + userEvent.type(screen.getByTestId("renamePatternInput"), "(.+)"); + + // getRenamePattern is prop sent from parent component to retrieve user input + expect(testProps.getRenamePattern).toBeCalledTimes(4); + }); + + it("sends user input to parent component via getRenameReplacement", () => { + // User enters text into renamePatternInput + userEvent.type(screen.getByTestId("renameReplacementInput"), "test_$1"); + + // getRenamePattern is prop sent from parent component to retrieve user input + expect(testProps.getRenameReplacement).toBeCalledTimes(7); + }); +}); diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx index b549d1b92..c94f87353 100644 --- a/public/pages/Snapshots/components/RenameInput/RenameInput.tsx +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.tsx @@ -37,14 +37,14 @@ const RenameInput = ({ getRenamePattern, getRenameReplacement }: RenameInputProp - + - + ); diff --git a/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap b/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap new file mode 100644 index 000000000..61270c31f --- /dev/null +++ b/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`RenameInput component renders without error 1`] = ` +
+`; From 7ef5272ccc7e6f2a17aeee2145795298a9c76baf Mon Sep 17 00:00:00 2001 From: Chris Hesterman Date: Wed, 21 Sep 2022 15:06:05 -0700 Subject: [PATCH 061/160] Add unit tests for SnapshotRenameOptions component Signed-off-by: Chris Hesterman --- .../AddPrefixInput/AddPrefixInput.test.tsx | 3 +- .../AddPrefixInput.test.tsx.snap | 58 +++++++- .../RenameInput/RenameInput.test.tsx | 5 +- .../__snapshots__/RenameInput.test.tsx.snap | 105 +++++++++++++- .../SnapshotRenameOptions.test.tsx | 76 ++++++++++ .../SnapshotRenameOptions.test.tsx.snap | 132 ++++++++++++++++++ 6 files changed, 368 insertions(+), 11 deletions(-) create mode 100644 public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.test.tsx create mode 100644 public/pages/Snapshots/components/SnapshotRenameOptions/__snapshots__/SnapshotRenameOptions.test.tsx.snap diff --git a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx index 870558b6d..ab2e3e745 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx +++ b/public/pages/Snapshots/components/AddPrefixInput/AddPrefixInput.test.tsx @@ -6,7 +6,6 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; import { render, screen, cleanup } from "@testing-library/react"; -// @ts-ignore import userEvent from "@testing-library/user-event"; import AddPrefixInput from "./AddPrefixInput"; @@ -30,7 +29,7 @@ describe("AddPrefixInput component", () => { const { container } = render(); - expect(container.firstChild).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); it("accepts user input", () => { diff --git a/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap b/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap index b4b8319df..6ed185484 100644 --- a/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap +++ b/public/pages/Snapshots/components/AddPrefixInput/__snapshots__/AddPrefixInput.test.tsx.snap @@ -1,7 +1,59 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AddPrefixInput component renders without error 1`] = ` -
+
+
+
+
+
+

+ Specify prefix for restored index names +

+
+
+
+ + A prefix will be added to any restored index names. + +
+
+
+
+
+ +
+
+
+
+
+
`; diff --git a/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx b/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx index 6f6fba84b..a84ff53b2 100644 --- a/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx +++ b/public/pages/Snapshots/components/RenameInput/RenameInput.test.tsx @@ -5,8 +5,7 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; -import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react"; -// @ts-ignore +import { render, screen, cleanup } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import RenameInput from "./RenameInput"; @@ -30,7 +29,7 @@ describe("RenameInput component", () => { const { container } = render(); - expect(container.firstChild).toMatchSnapshot(); + expect(container).toMatchSnapshot(); }); it("accepts user input", () => { diff --git a/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap b/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap index 61270c31f..938fc61a6 100644 --- a/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap +++ b/public/pages/Snapshots/components/RenameInput/__snapshots__/RenameInput.test.tsx.snap @@ -1,7 +1,106 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`RenameInput component renders without error 1`] = ` -
+
+
+
+
+
+

+ Rename Pattern +

+
+
+
+ + Use regular expressiojn to define how index names will be renamed. By default, input (.+) to reuse the entire index name. [Learn more] + +
+
+
+
+
+ +
+
+
+
+
+
+
+
+

+ Rename Replacement +

+
+
+
+ + Define the format of renamed indices. Use $0 to include the entire matching index name, $1 to include the content of the first capture group, etc. [Learn more] + +
+
+
+
+
+ +
+
+
+
+
`; diff --git a/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.test.tsx b/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.test.tsx new file mode 100644 index 000000000..345d978cb --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRenameOptions/SnapshotRenameOptions.test.tsx @@ -0,0 +1,76 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import React from "react"; +import "@testing-library/jest-dom/extend-expect"; +import { render, screen, cleanup } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import SnapshotRenameOptions from "./SnapshotRenameOptions"; + + +const testProps = { + onDoNotRenameToggle: jest.fn(), + onAddPrefixToggle: jest.fn(), + onRenameIndicesToggle: jest.fn(), + width: "200" +}; + +afterEach(() => { + cleanup(); +}); + +describe("SnapshotRenameOptions component", () => { + it("renders without error", () => { + const { container } = render( + + ); + + expect(screen.getByText("Do not rename")).toBeInTheDocument(); + expect(screen.getByText("Add prefix to restored index names")).toBeInTheDocument(); + expect(screen.getByText("Rename using regular expression (Advanced)")).toBeInTheDocument(); + expect(screen.getByLabelText("Do not rename")).toBeChecked(); + expect(screen.getByLabelText("Add prefix to restored index names")).not.toBeChecked(); + expect(screen.getByLabelText("Rename using regular expression (Advanced)")).not.toBeChecked(); + + expect(container).toMatchSnapshot(); + }); + + it("accepts user input", () => { + render( + + ); + + userEvent.click(screen.getByLabelText("Add prefix to restored index names")); + + expect(testProps.onAddPrefixToggle).toBeCalled(); + + userEvent.click(screen.getByLabelText("Rename using regular expression (Advanced)")); + + expect(testProps.onRenameIndicesToggle).toBeCalled(); + + cleanup(); + + render( + + ) + + userEvent.click(screen.getByLabelText("Do not rename")); + + expect(testProps.onDoNotRenameToggle).toBeCalled(); + + }); +}); diff --git a/public/pages/Snapshots/components/SnapshotRenameOptions/__snapshots__/SnapshotRenameOptions.test.tsx.snap b/public/pages/Snapshots/components/SnapshotRenameOptions/__snapshots__/SnapshotRenameOptions.test.tsx.snap new file mode 100644 index 000000000..36f6b5d1e --- /dev/null +++ b/public/pages/Snapshots/components/SnapshotRenameOptions/__snapshots__/SnapshotRenameOptions.test.tsx.snap @@ -0,0 +1,132 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SnapshotRenameOptions component renders without error 1`] = ` +
+
+
+ Rename restored indices +
+
+
+ +
+