Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add data node migration wizard #17768

Merged
merged 98 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
75f59b1
Add data node migration wizard
ousmaneo Dec 21, 2023
c2d528c
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 2, 2024
40db6cd
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 3, 2024
37295bd
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 11, 2024
142ec3e
update useMigrationStep
ousmaneo Jan 11, 2024
c4d593c
add compatibility details
ousmaneo Jan 11, 2024
1f17d0d
add CA and cert renewal steps
ousmaneo Jan 11, 2024
9bf793f
add compatibility check test
ousmaneo Jan 11, 2024
a433d94
add default param to useDatanodes
ousmaneo Jan 11, 2024
0f08a01
update help text
ousmaneo Jan 11, 2024
e83063b
use migrationStep hook in wizard
ousmaneo Jan 11, 2024
51d2a3e
update types
ousmaneo Jan 11, 2024
7190681
remove WIP
ousmaneo Jan 11, 2024
abe971d
add license header
ousmaneo Jan 12, 2024
b278954
use mobilitycheck api
ousmaneo Jan 12, 2024
c0abd73
add test
ousmaneo Jan 15, 2024
48143ff
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 15, 2024
2f17c7a
add datanode list, and skip check to welcome step
ousmaneo Jan 16, 2024
541448a
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 17, 2024
9bac193
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 19, 2024
a215d8d
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 23, 2024
e737a4d
add migration state machine api hooks
ousmaneo Jan 23, 2024
8075800
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 25, 2024
e49e84d
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 25, 2024
b6f302b
Merge branch 'master' into datanode-migration-ui
ousmaneo Jan 29, 2024
f3e8c32
integrate state machine
ousmaneo Jan 31, 2024
3a242e2
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 1, 2024
76f9e5d
refactor wizard to use new statemachine state
ousmaneo Feb 2, 2024
0b1795a
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 2, 2024
c736a12
Add shutdown and finish to wizard
ousmaneo Feb 2, 2024
85dd54e
add changelog
ousmaneo Feb 2, 2024
a84edae
refactor wizard
ousmaneo Feb 5, 2024
43cce0a
Merge branch 'master' into datanode-migration-ui
gally47 Feb 8, 2024
5c01040
Merge branch 'master' into datanode-migration-ui
gally47 Feb 8, 2024
d3a0738
update compatibility check
ousmaneo Feb 8, 2024
b34dc7f
initial component setup
gally47 Feb 8, 2024
9a0c214
initial setup RemoteReindexingMigration component
gally47 Feb 8, 2024
5379a43
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 9, 2024
f7ee73e
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 12, 2024
ed0fcb0
added useRemoteReindexMigrationStatus hook
gally47 Feb 12, 2024
7031f3f
Remote reindexing migration steps polishing
gally47 Feb 12, 2024
24b1608
Merge branch 'master' into datanode-migration-ui
gally47 Feb 13, 2024
ef71b4b
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 13, 2024
8b36ae2
refaor wizard to use generic next step buttons
ousmaneo Feb 13, 2024
731455b
changes to remote reindexing steps
gally47 Feb 13, 2024
0dea2d3
fix tests eslint issues
gally47 Feb 13, 2024
fc50bad
integrated new wizard changes
gally47 Feb 13, 2024
7478246
cleanup
gally47 Feb 14, 2024
1b599cc
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 15, 2024
b1b78af
integrate provisioning through statemachine
ousmaneo Feb 15, 2024
5b8229c
extrat journal warning alert
ousmaneo Feb 15, 2024
a8977a7
Merge branch 'master' into datanode-migration-ui
gally47 Feb 15, 2024
aeeea8a
integrated new changes
gally47 Feb 15, 2024
874fdc6
cleanup and refactor
ousmaneo Feb 16, 2024
4502df8
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 16, 2024
b827af1
fix linter
ousmaneo Feb 16, 2024
0e4c27c
Merge branch 'master' into datanode-migration-ui
gally47 Feb 16, 2024
6ef5d7c
fix useTriggerMigrationState
ousmaneo Feb 16, 2024
c41f7a5
Merge branch 'master' into datanode-migration-ui
gally47 Feb 16, 2024
6cd0600
remote reindex new steps and actions integration
gally47 Feb 16, 2024
8df978f
fix eslint issues
gally47 Feb 16, 2024
3efb174
Merge branch 'master' into datanode-migration-ui
gally47 Feb 16, 2024
dfba6e4
cleanup
gally47 Feb 16, 2024
dcc91e4
cleanup MigrateExistingData
gally47 Feb 16, 2024
6e1e72d
integrate new step and fix typo
ousmaneo Feb 16, 2024
5d9968f
add replace cluster component
ousmaneo Feb 16, 2024
f7cebe8
ConnectionStringRemovalStep change
gally47 Feb 16, 2024
fa1fba9
cleanup RemoteReindexRunning step
gally47 Feb 16, 2024
d6bce5c
added response and error_message to MigrationState type
gally47 Feb 16, 2024
ae3f08e
fix eslint issues
gally47 Feb 16, 2024
0397499
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 19, 2024
0a68056
fix test
ousmaneo Feb 19, 2024
634885e
Merge branch 'master' into datanode-migration-ui
ousmaneo Feb 19, 2024
2285005
fix types
ousmaneo Feb 19, 2024
89386de
check for provisioning state instead of data node state as data node …
moesterheld Feb 19, 2024
37c869b
fix buttons overflow
gally47 Feb 19, 2024
3eb527c
add restart graylog step
ousmaneo Feb 19, 2024
8358919
handle errors
ousmaneo Feb 20, 2024
713ab56
Merge branch 'master' into datanode-migration-ui
moesterheld Feb 20, 2024
6387fd8
fix data node startup trigger
moesterheld Feb 20, 2024
af6c496
finalized RemoteReindexRunning step
gally47 Feb 20, 2024
10ba05a
Merge branch 'master' into datanode-migration-ui
gally47 Feb 20, 2024
b1c07ac
fix eslint issue
gally47 Feb 20, 2024
1a5d6e6
Merge branch 'master' into datanode-migration-ui
gally47 Feb 20, 2024
75189d3
Merge branch 'master' into datanode-migration-ui
janheise Feb 20, 2024
799a539
Merge branch 'master' into datanode-migration-ui
gally47 Feb 21, 2024
c9971d0
show stop opensearch warning
ousmaneo Feb 21, 2024
2d4b564
added ResetMigrationButton
gally47 Feb 21, 2024
a45d109
fix review comments
ousmaneo Feb 21, 2024
e1a1898
add CA form type
ousmaneo Feb 21, 2024
a49163a
add reset migration button
ousmaneo Feb 21, 2024
28b95b9
fix review
ousmaneo Feb 21, 2024
218fe47
fix review Remote reindexing errors on first steps
gally47 Feb 21, 2024
acf8dba
Merge branch 'master' into datanode-migration-ui
gally47 Feb 21, 2024
fe67c50
fix review wording
gally47 Feb 21, 2024
e5023bf
fix typos
gally47 Feb 21, 2024
b31b1bf
fix review typos
gally47 Feb 22, 2024
0701acd
Merge branch 'master' into datanode-migration-ui
gally47 Feb 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/pr-18079.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type = "added"
message = "add datanode migration ui"

issues = [""]
pulls = ["18079"]

Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,15 @@ public void provisionAndStartDataNodes() {

@Override
public boolean provisioningFinished() {
return nodeService.allActive().values().stream().allMatch(node -> node.getDataNodeStatus() == DataNodeStatus.PREPARED);
return nodeService.allActive().values().stream().allMatch(node -> dataNodeProvisioningService.getPreflightConfigFor(node.getNodeId())
.map(dn -> dn.state() == DataNodeProvisioningConfig.State.STARTUP_PREPARED)
.orElse(false));
}

@Override
public void startDataNodes() {
final Map<String, DataNodeDto> activeDataNodes = nodeService.allActive();
activeDataNodes.values().forEach(node -> dataNodeProvisioningService.changeState(node.getNodeId(), DataNodeProvisioningConfig.State.STARTUP_REQUESTED));
activeDataNodes.values().forEach(node -> dataNodeProvisioningService.changeState(node.getNodeId(), DataNodeProvisioningConfig.State.STARTUP_TRIGGER));
}

@Override
Expand Down
200 changes: 200 additions & 0 deletions graylog2-web-interface/src/components/datanode/Constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/

export const MIGRATION_STEP = {
CA_CONFIGURATION: {
key: 'CA_CONFIGURATION',
description: 'Configure a certificate authority',
},
RENEWAL_POLICY_CONFIGURATION: {
key: 'RENEWAL_POLICY_CONFIGURATION',
description: 'Configure a renewal policy',
},
COMPATIBILITY_CHECK: {
key: 'COMPATIBILITY_CHECK',
description: 'Check OpenSearch compatibility with datanode',
},
MANUAL_MIGRATION_STEP: {
key: 'MANUAL_MIGRATION_STEP',
description: 'Migration steps.',
},
MIGRATION_FINISHED: {
key: 'MIGRATION_FINISHED',
description: 'Migration finished',
},
} as const;

export const MIGRATION_STATE = {
NEW: {
key: 'NEW',
description: 'Migration',
},
MIGRATION_WELCOME_PAGE: {
key: 'MIGRATION_WELCOME_PAGE',
description: 'Welcome',
},
CA_CREATION_PAGE: {
key: 'CA_CREATION_PAGE',
description: 'Certificate authority',
},
RENEWAL_POLICY_CREATION_PAGE: {
key: 'RENEWAL_POLICY_CREATION_PAGE',
description: 'Certificate renewal policy',
},
MIGRATION_SELECTION_PAGE: {
key: 'MIGRATION_SELECTION_PAGE',
description: 'Migration steps',
},
ROLLING_UPGRADE_MIGRATION_WELCOME_PAGE: {
key: 'ROLLING_UPGRADE_MIGRATION_WELCOME_PAGE',
description: 'Welcome to Rolling upgrade migration',
},
ASK_TO_SHUTDOWN_OLD_CLUSTER: {
key: 'ASK_TO_SHUTDOWN_OLD_CLUSTER',
description: 'Shut down old cluster',
},
MANUALLY_REMOVE_OLD_CONNECTION_STRING_FROM_CONFIG: {
key: 'MANUALLY_REMOVE_OLD_CONNECTION_STRING_FROM_CONFIG',
description: 'Remove connection string',
},
MESSAGE_PROCESSING_STOP: {
key: 'MESSAGE_PROCESSING_STOP',
description: 'Stop message processing',
},
REPLACE_CLUSTER: {
key: 'REPLACE_CLUSTER',
description: 'Replace existing cluster',
},
RESTART_GRAYLOG: {
key: 'RESTART_GRAYLOG',
description: 'Update configuration file and restart Graylog',
},
REMOTE_REINDEX_WELCOME_PAGE: {
key: 'REMOTE_REINDEX_WELCOME_PAGE',
description: 'Remote reindexing migration',
},
PROVISION_DATANODE_CERTIFICATES_PAGE: {
key: 'PROVISION_DATANODE_CERTIFICATES_PAGE',
description: 'Provision Data Node with certificates',
},
PROVISION_DATANODE_CERTIFICATES_RUNNING: {
key: 'PROVISION_DATANODE_CERTIFICATES_RUNNING',
description: 'Provision Data Node with certificates running',
},
EXISTING_DATA_MIGRATION_QUESTION_PAGE: {
key: 'EXISTING_DATA_MIGRATION_QUESTION_PAGE',
description: 'Migrate existing data question',
},
MIGRATE_EXISTING_DATA: {
key: 'MIGRATE_EXISTING_DATA',
description: 'Migrate existing data',
},
REMOTE_REINDEX_RUNNING: {
key: 'REMOTE_REINDEX_RUNNING',
description: 'Remote reindexing migration running',
},
DIRECTORY_COMPATIBILITY_CHECK_PAGE: {
key: 'DIRECTORY_COMPATIBILITY_CHECK_PAGE',
description: 'Directory compatibility check',
},
DIRECTORY_COMPATIBILITY_CHECK_PAGE2: {
key: 'DIRECTORY_COMPATIBILITY_CHECK_PAGE2',
description: 'Directory compatibility check',
},
PROVISION_ROLLING_UPGRADE_NODES_WITH_CERTIFICATES: {
key: 'PROVISION_ROLLING_UPGRADE_NODES_WITH_CERTIFICATES',
description: 'Certificate provisioning overview',
},
PROVISION_ROLLING_UPGRADE_NODES_RUNNING: {
key: 'PROVISION_ROLLING_UPGRADE_NODES_RUNNING',
description: 'Provisionning Data Nodes certificate.',
},
JOURNAL_SIZE_DOWNTIME_WARNING: {
key: 'JOURNAL_SIZE_DOWNTIME_WARNING',
description: 'Journal size downtime warning',
},
FAILED: {
key: 'FAILED',
description: 'Migration failed',
},
FINISHED: {
key: 'FINISHED',
description: 'Migration finished',
},
} as const;

export const ROLLING_UPGRADE_MIGRATION_STEPS = [
MIGRATION_STATE.ROLLING_UPGRADE_MIGRATION_WELCOME_PAGE.key,
MIGRATION_STATE.DIRECTORY_COMPATIBILITY_CHECK_PAGE2.key,
MIGRATION_STATE.PROVISION_ROLLING_UPGRADE_NODES_WITH_CERTIFICATES.key,
MIGRATION_STATE.PROVISION_ROLLING_UPGRADE_NODES_RUNNING.key,
MIGRATION_STATE.JOURNAL_SIZE_DOWNTIME_WARNING.key,
MIGRATION_STATE.MESSAGE_PROCESSING_STOP.key,
MIGRATION_STATE.RESTART_GRAYLOG.key,
];
export const REMOTE_REINDEXING_MIGRATION_STEPS = [
MIGRATION_STATE.REMOTE_REINDEX_WELCOME_PAGE.key,
MIGRATION_STATE.PROVISION_DATANODE_CERTIFICATES_PAGE.key,
MIGRATION_STATE.PROVISION_DATANODE_CERTIFICATES_RUNNING.key,
MIGRATION_STATE.EXISTING_DATA_MIGRATION_QUESTION_PAGE.key,
MIGRATION_STATE.MIGRATE_EXISTING_DATA.key,
MIGRATION_STATE.REMOTE_REINDEX_RUNNING.key,
MIGRATION_STATE.ASK_TO_SHUTDOWN_OLD_CLUSTER.key,
MIGRATION_STATE.MANUALLY_REMOVE_OLD_CONNECTION_STRING_FROM_CONFIG.key,
];

export const MIGRATION_WIZARD_STEPS = [
MIGRATION_STATE.NEW.key,
MIGRATION_STATE.MIGRATION_WELCOME_PAGE.key,
MIGRATION_STATE.DIRECTORY_COMPATIBILITY_CHECK_PAGE.key,
MIGRATION_STATE.CA_CREATION_PAGE.key,
MIGRATION_STATE.RENEWAL_POLICY_CREATION_PAGE.key,
MIGRATION_STATE.MIGRATION_SELECTION_PAGE.key,
MIGRATION_STATE.FINISHED.key,
];

export const MIGRATION_ACTIONS = {
SHOW_DIRECTORY_COMPATIBILITY_CHECK: {
key: 'SHOW_DIRECTORY_COMPATIBILITY_CHECK',
label: 'Directory compatibility check',
},
SKIP_DIRECTORY_COMPATIBILITY_CHECK: {
key: 'SKIP_DIRECTORY_COMPATIBILITY_CHECK',
label: 'Skip directory compatibility check',
},
SHOW_RENEWAL_POLICY_CREATION: {
key: 'SHOW_RENEWAL_POLICY_CREATION',
label: 'Configure certificat renewal policy',
},
SHOW_MIGRATION_SELECTION: {
key: 'SHOW_MIGRATION_SELECTION',
label: 'Go to migration steps',
},
PROVISION_DATANODE_CERTIFICATES: {
key: 'PROVISION_DATANODE_CERTIFICATES',
label: 'Provision Data Nodes with certificates',
},
SKIP_EXISTING_DATA_MIGRATION: {
key: 'SKIP_EXISTING_DATA_MIGRATION',
label: 'Skip existing data migration',
},
RETRY_MIGRATE_EXISTING_DATA: {
key: 'RETRY_MIGRATE_EXISTING_DATA',
label: 'Retry migrate existing data',
},
};
export default MIGRATION_STEP;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import React from 'react';

import { Tabs, Tab } from 'components/bootstrap';
import CACreateForm from 'components/datanode/DataNodeConfiguration/CACreateForm';
import CAUpload from 'components/datanode/DataNodeConfiguration/CAUpload';

const TAB_KEYS = ['create', 'upload'];
const CAConfiguration = () => (
<>
<h2>Configure Certificate Authority</h2>
<p>
In this first step you can either upload or create a new certificate authority.<br />
Using it we can provision your Data Nodes with certificates easily.
</p>
<Tabs defaultActiveKey={TAB_KEYS[0]} id="ca-configurations">
<Tab eventKey={TAB_KEYS[0]} title="Create new CA">
<CACreateForm />
</Tab>
<Tab eventKey={TAB_KEYS[1]} title="Upload CA">
<CAUpload />
</Tab>
</Tabs>
</>
);
export default CAConfiguration;
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import React from 'react';
import { render, screen, waitFor } from 'wrappedTestingLibrary';
import userEvent from '@testing-library/user-event';
import DefaultQueryClientProvider from 'DefaultQueryClientProvider';

import { asMock, StoreMock as MockStore } from 'helpers/mocking';
import fetch from 'logic/rest/FetchProvider';
import UserNotification from 'util/UserNotification';

import CACreateForm from './CACreateForm';

jest.mock('logic/rest/FetchProvider', () => jest.fn(() => Promise.resolve()));
jest.mock('stores/sessions/SessionStore', () => ({ SessionStore: MockStore(['isLoggedIn', jest.fn()]) }));
jest.mock('stores/system/SystemStore', () => ({ SystemStore: MockStore() }));

jest.mock('util/UserNotification', () => ({
error: jest.fn(),
success: jest.fn(),
}));

const logger = {
// eslint-disable-next-line no-console
log: console.log,
// eslint-disable-next-line no-console
warn: console.warn,
error: () => {},
};

describe('CACreateForm', () => {
beforeEach(() => {
asMock(fetch).mockReturnValue(Promise.resolve());
});

const submitForm = async () => {
userEvent.click(await screen.findByRole('button', { name: /Create CA/i }));
};

it('should create CA', async () => {
render(<CACreateForm />);

await submitForm();

await waitFor(() => expect(fetch).toHaveBeenCalledWith(
'POST',
expect.stringContaining('/ca/create'),
{ organization: 'Graylog CA' },
false,
));

expect(UserNotification.success).toHaveBeenCalledWith('CA created successfully');
});

it('should show error when CA creation fails', async () => {
asMock(fetch).mockImplementation(() => Promise.reject(new Error('Error')));

render((
<DefaultQueryClientProvider options={{ logger }}>
<CACreateForm />
</DefaultQueryClientProvider>
));

await submitForm();

await waitFor(() => expect(fetch).toHaveBeenCalledWith(
'POST',
expect.stringContaining('/ca/create'),
{ organization: 'Graylog CA' },
false,
));

expect(UserNotification.error).toHaveBeenCalledWith('CA creation failed with error: Error: Error');
});
});
Loading
Loading