Skip to content

Commit

Permalink
Create service to restart wazuh (#4365)
Browse files Browse the repository at this point in the history
* file to be added with the restart functions

* restart calls were changed to service calls

* the restarting on time sign appears

* modal while restarting added

* countDown change of location

* cleaning

* modal redesign

* model and code update

* modified delays and designs

* change text Synchronizing cluster

* Update restart-cluster-manager-callout.tsx

* Code improvements

* suggestions implemented

* polling sync add

* Code improvements

* add endpoint

* add comment

* add close button

* suggestions implemented

* add modal wazuh restarted

* delete unnecessary toast

* Set clearState on restart error

* disabled unneeded console.log

Co-authored-by: Alex Ruiz Becerra <[email protected]>
Co-authored-by: Federico Rodriguez <[email protected]>
Co-authored-by: chantal.kelm <[email protected]>
(cherry picked from commit 6598df9)
  • Loading branch information
yenienserrano committed Sep 6, 2022
1 parent 9278ed2 commit 24331d6
Show file tree
Hide file tree
Showing 22 changed files with 945 additions and 607 deletions.
130 changes: 0 additions & 130 deletions public/components/common/restart-cluster-manager-callout.tsx

This file was deleted.

258 changes: 258 additions & 0 deletions public/components/common/restart-modal/restart-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import React, { useEffect, useState } from 'react';
import {
EuiButton,
EuiButtonEmpty,
EuiEmptyPrompt,
EuiEmptyPromptProps,
EuiFlexGroup,
EuiFlexItem,
EuiOverlayMask,
EuiProgress,
} from '@elastic/eui';
import { getHttp } from '../../../kibana-services';
import { WazuhConfig } from '../../../react-services/wazuh-config';
import { RestartHandler } from '../../../react-services/wz-restart';
import { getAssetURL, getThemeAssetURL } from '../../../utils/assets';
import { useDispatch, useSelector } from 'react-redux';
import {
updateRestartStatus,
updateRestartAttempt,
updateSyncCheckAttempt,
updateUnsynchronizedNodes,
} from '../../../redux/actions/appStateActions';
import { UI_LOGGER_LEVELS } from '../../../../common/constants';
import { UI_ERROR_SEVERITIES } from '../../../react-services/error-orchestrator/types';
import { getErrorOrchestrator } from '../../../react-services/common-services';

/**
* The restart modal to show feedback to the user.
* @param props component's props
* @returns components's body
*/
export const RestartModal = (props: { useDelay?: boolean, showWarningRestart? }) => {
// Component props
const { useDelay = false } = props;

// Use default HEALTHCHECK_DELAY
const [timeToHC, setTimeToHC] = useState(RestartHandler.HEALTHCHECK_DELAY / 1000);

// Use default SYNC_DELAY
const [syncDelay, setSyncDelay] = useState(RestartHandler.SYNC_DELAY / 1000);

// Restart polling counter
const restartAttempt = useSelector((state) => state.appStateReducers.restartAttempt);

// Cluster nodes that did not synced
const unsyncedNodes = useSelector((state) => state.appStateReducers.unsynchronizedNodes);

// Sync polling counter
const syncPollingAttempt = useSelector((state) => state.appStateReducers.syncCheckAttempt);

// Current status of the restarting process
const restartStatus = useSelector((state) => state.appStateReducers.restartStatus);

// Max attempts = MAX_SYNC_POLLING_ATTEMPTS + MAX_RESTART_POLLING_ATTEMPTS
const maxAttempts = useDelay
? RestartHandler.MAX_RESTART_POLLING_ATTEMPTS + RestartHandler.MAX_SYNC_POLLING_ATTEMPTS
: RestartHandler.MAX_RESTART_POLLING_ATTEMPTS;

// Current attempt
const attempts = useDelay ? restartAttempt + syncPollingAttempt : restartAttempt;

// Load Wazuh logo
const wzConfig = new WazuhConfig().getConfig();
const logotypeURL = getHttp().basePath.prepend(
wzConfig['customization.logo.sidebar']
? getAssetURL(wzConfig['customization.logo.sidebar'])
: getThemeAssetURL('icon.svg')
);

// Apply SYNC_DELAY if useDelay prop is enabled.
useEffect(() => {
if (useDelay) {
countdown(syncDelay, setSyncDelay);
}
}, []);

// Apply HEALTHCHECK_DELAY when the restart has failed
useEffect(() => {
restartStatus === RestartHandler.RESTART_STATES.RESTART_ERROR &&
countdown(timeToHC, setTimeToHC);

restartStatus === RestartHandler.RESTART_STATES.RESTARTED_INFO &&
restartedTimeout();
}, [restartStatus]);

// TODO
const countdown = (time: number, setState) => {
let countDown = time;

const interval = setInterval(() => {
setState(countDown);
if (countDown === 0 && setState === setTimeToHC) {
clearInterval(interval);
RestartHandler.goToHealthcheck();
} else if (countDown === 0) {
clearInterval(interval);
}

countDown--;
}, 1000 /* 1 second */);
};

const restartedTimeout = () => {
setTimeout(() => {
dispatch(updateRestartStatus(RestartHandler.RESTART_STATES.RESTARTED));
if(props.showWarningRestart){
props.showWarningRestart()
}
}, RestartHandler.INFO_RESTART_SUCCESS_DELAY);
}

// TODO review if importing these functions in wz-restart work.
const dispatch = useDispatch();
const updateRedux = {
updateRestartAttempt: (restartAttempt) => dispatch(updateRestartAttempt(restartAttempt)),
updateSyncCheckAttempt: (syncCheckAttempt) =>
dispatch(updateSyncCheckAttempt(syncCheckAttempt)),
updateUnsynchronizedNodes: (unsynchronizedNodes) =>
dispatch(updateUnsynchronizedNodes(unsynchronizedNodes)),
updateRestartStatus: (restartStatus) => dispatch(updateRestartStatus(restartStatus)),
};

const forceRestart = async () => {
try{
await RestartHandler.restartWazuh(updateRedux);
}catch(error){
const options = {
context: `${RestartModal.name}.forceRestart`,
level: UI_LOGGER_LEVELS.ERROR,
severity: UI_ERROR_SEVERITIES.BUSINESS,
error: {
error: error,
message: error.message || error,
title: error.name || error,
},
};
getErrorOrchestrator().handleError(options);
}
};


const abort = () => {
dispatch(updateRestartStatus(RestartHandler.RESTART_STATES.RESTARTED));
dispatch(updateUnsynchronizedNodes([]));
dispatch(updateRestartAttempt(0));
dispatch(updateSyncCheckAttempt(0));
}

// Build the modal depending on the restart state.
let emptyPromptProps: Partial<EuiEmptyPromptProps>;
switch (restartStatus) {
default:
case RestartHandler.RESTART_STATES.RESTARTED_INFO:
emptyPromptProps = {
title: (
<>
<img src={logotypeURL} className="wz-modal-restart-logo" alt=""></img>
<h2 className="wz-modal-restart-title">Wazuh restarted</h2>
</>
),
body: (
<>
<EuiProgress value={maxAttempts} max={maxAttempts} size="s" />
</>
),
};
break;

case RestartHandler.RESTART_STATES.RESTARTING:
emptyPromptProps = {
title: (
<>
<img src={logotypeURL} className="wz-modal-restart-logo" alt=""></img>
<h2 className="wz-modal-restart-title">Restarting Wazuh</h2>
</>
),
body: (
<>
<EuiProgress value={attempts} max={maxAttempts} size="s" />
</>
),
};
break;

case RestartHandler.RESTART_STATES.RESTART_ERROR:
emptyPromptProps = {
iconType: 'alert',
iconColor: 'danger',
title: <h2 className="wz-modal-restart-title">Unable to connect to Wazuh.</h2>,
body: <p>There was an error restarting Wazuh. The Healthcheck will run automatically.</p>,
actions: (
<EuiButton color="primary" fill href="#/health-check">
Go to Healthcheck ({timeToHC} s)
</EuiButton>
),
};
break;

case RestartHandler.RESTART_STATES.SYNC_ERROR:
emptyPromptProps = {
iconType: 'alert',
iconColor: 'danger',
title: <h2 className="wz-modal-restart-title">Synchronization failed</h2>,
body: (
<p>
The nodes {unsyncedNodes.join(', ')} did not synchronize. Restarting Wazuh might set the
cluster into an inconsistent state. Close and try again later.
</p>
),
actions: (
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButtonEmpty color='danger' flush="both" onClick={forceRestart}>
Force restart
</EuiButtonEmpty>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton color="primary" fill onClick={abort}>
Close
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
),
};
break;

case RestartHandler.RESTART_STATES.SYNCING:
emptyPromptProps = {
title: (
<>
<img src={logotypeURL} className="wz-modal-restart-logo" alt=""></img>
<h2 className="wz-modal-restart-title">Synchronizing Wazuh</h2>
</>
),
body: (
<>
<EuiProgress value={attempts} max={maxAttempts} size="s" />
</>
),
};
break;
}

//
return (
<EuiOverlayMask>
<div
className={
restartStatus === RestartHandler.RESTART_STATES.ERROR
? 'wz-modal-restart-error'
: 'wz-modal-restart'
}
>
<EuiEmptyPrompt {...emptyPromptProps} />
</div>
</EuiOverlayMask>
);
};
Loading

0 comments on commit 24331d6

Please sign in to comment.