mirror of
https://github.com/elastic/kibana.git
synced 2025-04-25 02:09:32 -04:00
[Security Solution] Introduce method to clean up/delete Risk Scoring resources (#184509)
## Summary Create a method that deletes all resources created by the risk engine. The method returns a list of errors and an empty array for the success scenario. Signature: ```js const errors = await riskEngineDataClient.tearDown({ taskManager, riskScoreDataClient, }); ``` # How to test it? 1. Enable the risk engine 2. Call the method 3. It should return an empty array ----- 1. On a clean instance 2. Call the method 4. It should return a list of errors ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
a0096cef0c
commit
aa95692deb
6 changed files with 152 additions and 0 deletions
|
@ -352,6 +352,51 @@ describe('RiskEngineDataClient', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('tearDownRiskEngine', () => {
|
||||||
|
const mockTaskManagerStart = taskManagerMock.createStart();
|
||||||
|
|
||||||
|
it('should delete the risk engine object and task if it exists', async () => {
|
||||||
|
mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration());
|
||||||
|
const riskScoreDataClient = riskScoreDataClientMock.create();
|
||||||
|
await riskEngineDataClient.tearDown({
|
||||||
|
taskManager: mockTaskManagerStart,
|
||||||
|
riskScoreDataClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockSavedObjectClient.delete).toHaveBeenCalledTimes(1);
|
||||||
|
expect(mockTaskManagerStart.remove).toHaveBeenCalledTimes(1);
|
||||||
|
expect(riskScoreDataClient.tearDown).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return errors when exception is thrown ', async () => {
|
||||||
|
const error = new Error('testError');
|
||||||
|
mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration());
|
||||||
|
mockTaskManagerStart.remove.mockRejectedValueOnce(error);
|
||||||
|
mockSavedObjectClient.delete.mockRejectedValueOnce(error);
|
||||||
|
|
||||||
|
const errors = await riskEngineDataClient.tearDown({
|
||||||
|
taskManager: mockTaskManagerStart,
|
||||||
|
riskScoreDataClient: riskScoreDataClientMock.create(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(errors).toEqual([error, error]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return errors from riskScoreDataClient.tearDown ', async () => {
|
||||||
|
const error = new Error('testError');
|
||||||
|
mockSavedObjectClient.find.mockResolvedValueOnce(getSavedObjectConfiguration());
|
||||||
|
const riskScoreDataClient = riskScoreDataClientMock.create();
|
||||||
|
riskScoreDataClient.tearDown.mockResolvedValueOnce([error]);
|
||||||
|
|
||||||
|
const errors = await riskEngineDataClient.tearDown({
|
||||||
|
taskManager: mockTaskManagerStart,
|
||||||
|
riskScoreDataClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(errors).toEqual([error]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
getConfiguration,
|
getConfiguration,
|
||||||
initSavedObjects,
|
initSavedObjects,
|
||||||
getEnabledRiskEngineAmount,
|
getEnabledRiskEngineAmount,
|
||||||
|
deleteSavedObjects,
|
||||||
} from './utils/saved_object_configuration';
|
} from './utils/saved_object_configuration';
|
||||||
import { bulkDeleteSavedObjects } from '../../risk_score/prebuilt_saved_objects/helpers/bulk_delete_saved_objects';
|
import { bulkDeleteSavedObjects } from '../../risk_score/prebuilt_saved_objects/helpers/bulk_delete_saved_objects';
|
||||||
import type { RiskScoreDataClient } from '../risk_score/risk_score_data_client';
|
import type { RiskScoreDataClient } from '../risk_score/risk_score_data_client';
|
||||||
|
@ -30,6 +31,11 @@ interface InitOpts {
|
||||||
riskScoreDataClient: RiskScoreDataClient;
|
riskScoreDataClient: RiskScoreDataClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TearDownParams {
|
||||||
|
taskManager: TaskManagerStartContract;
|
||||||
|
riskScoreDataClient: RiskScoreDataClient;
|
||||||
|
}
|
||||||
|
|
||||||
interface RiskEngineDataClientOpts {
|
interface RiskEngineDataClientOpts {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
kibanaVersion: string;
|
kibanaVersion: string;
|
||||||
|
@ -193,6 +199,29 @@ export class RiskEngineDataClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all risk engine resources.
|
||||||
|
*
|
||||||
|
* It returns an array of errors that occurred during the deletion.
|
||||||
|
*
|
||||||
|
* WARNING: It will remove all data.
|
||||||
|
*/
|
||||||
|
public async tearDown({ taskManager, riskScoreDataClient }: TearDownParams) {
|
||||||
|
const errors: Error[] = [];
|
||||||
|
const addError = (e: Error) => errors.push(e);
|
||||||
|
|
||||||
|
await removeRiskScoringTask({
|
||||||
|
namespace: this.options.namespace,
|
||||||
|
taskManager,
|
||||||
|
logger: this.options.logger,
|
||||||
|
}).catch(addError);
|
||||||
|
|
||||||
|
await deleteSavedObjects({ savedObjectsClient: this.options.soClient }).catch(addError);
|
||||||
|
const riskScoreErrors = await riskScoreDataClient.tearDown();
|
||||||
|
|
||||||
|
return errors.concat(riskScoreErrors);
|
||||||
|
}
|
||||||
|
|
||||||
public async disableLegacyRiskEngine({ namespace }: { namespace: string }) {
|
public async disableLegacyRiskEngine({ namespace }: { namespace: string }) {
|
||||||
const legacyRiskEngineStatus = await this.getLegacyStatus({ namespace });
|
const legacyRiskEngineStatus = await this.getLegacyStatus({ namespace });
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,15 @@ export const initSavedObjects = async ({
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const deleteSavedObjects = async ({
|
||||||
|
savedObjectsClient,
|
||||||
|
}: SavedObjectsClientArg): Promise<void> => {
|
||||||
|
const configuration = await getConfigurationSavedObject({ savedObjectsClient });
|
||||||
|
if (configuration) {
|
||||||
|
await savedObjectsClient.delete(riskEngineConfigurationTypeName, configuration.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getConfiguration = async ({
|
export const getConfiguration = async ({
|
||||||
savedObjectsClient,
|
savedObjectsClient,
|
||||||
}: SavedObjectsClientArg): Promise<RiskEngineConfiguration | null> => {
|
}: SavedObjectsClientArg): Promise<RiskEngineConfiguration | null> => {
|
||||||
|
|
|
@ -11,6 +11,7 @@ const createRiskScoreDataClientMock = () =>
|
||||||
({
|
({
|
||||||
getWriter: jest.fn().mockResolvedValue({ bulk: jest.fn().mockResolvedValue({ errors: [] }) }),
|
getWriter: jest.fn().mockResolvedValue({ bulk: jest.fn().mockResolvedValue({ errors: [] }) }),
|
||||||
init: jest.fn(),
|
init: jest.fn(),
|
||||||
|
tearDown: jest.fn(),
|
||||||
getRiskInputsIndex: jest.fn(),
|
getRiskInputsIndex: jest.fn(),
|
||||||
upgradeIfNeeded: jest.fn(),
|
upgradeIfNeeded: jest.fn(),
|
||||||
} as unknown as jest.Mocked<RiskScoreDataClient>);
|
} as unknown as jest.Mocked<RiskScoreDataClient>);
|
||||||
|
|
|
@ -463,4 +463,29 @@ describe('RiskScoreDataClient', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('tearDown', () => {
|
||||||
|
it('deletes all resources', async () => {
|
||||||
|
const errors = await riskScoreDataClient.tearDown();
|
||||||
|
|
||||||
|
expect(esClient.transform.deleteTransform).toHaveBeenCalledTimes(1);
|
||||||
|
expect(esClient.indices.deleteDataStream).toHaveBeenCalledTimes(1);
|
||||||
|
expect(esClient.indices.deleteIndexTemplate).toHaveBeenCalledTimes(1);
|
||||||
|
expect(esClient.cluster.deleteComponentTemplate).toHaveBeenCalledTimes(1);
|
||||||
|
expect(errors).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns errors when promises are rejected', async () => {
|
||||||
|
const error = new Error('test error');
|
||||||
|
|
||||||
|
esClient.transform.deleteTransform.mockRejectedValueOnce(error);
|
||||||
|
esClient.indices.deleteDataStream.mockRejectedValueOnce(error);
|
||||||
|
esClient.indices.deleteIndexTemplate.mockRejectedValueOnce(error);
|
||||||
|
esClient.cluster.deleteComponentTemplate.mockRejectedValueOnce(error);
|
||||||
|
|
||||||
|
const errors = await riskScoreDataClient.tearDown();
|
||||||
|
|
||||||
|
expect(errors).toEqual([error, error, error, error]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -179,6 +179,49 @@ export class RiskScoreDataClient {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all resources created by init().
|
||||||
|
* It returns an array of errors that occurred during the deletion.
|
||||||
|
*
|
||||||
|
* WARNING: It will remove all data.
|
||||||
|
*/
|
||||||
|
public async tearDown() {
|
||||||
|
const namespace = this.options.namespace;
|
||||||
|
const esClient = this.options.esClient;
|
||||||
|
const indexPatterns = getIndexPatternDataStream(namespace);
|
||||||
|
const errors: Error[] = [];
|
||||||
|
const addError = (e: Error) => errors.push(e);
|
||||||
|
|
||||||
|
await esClient.transform
|
||||||
|
.deleteTransform({
|
||||||
|
transform_id: getLatestTransformId(namespace),
|
||||||
|
delete_dest_index: true,
|
||||||
|
force: true,
|
||||||
|
})
|
||||||
|
.catch(addError);
|
||||||
|
|
||||||
|
await esClient.indices
|
||||||
|
.deleteDataStream({
|
||||||
|
name: indexPatterns.alias,
|
||||||
|
})
|
||||||
|
.catch(addError);
|
||||||
|
|
||||||
|
await esClient.indices
|
||||||
|
.deleteIndexTemplate({
|
||||||
|
name: indexPatterns.template,
|
||||||
|
})
|
||||||
|
.catch(addError);
|
||||||
|
|
||||||
|
await esClient.cluster
|
||||||
|
.deleteComponentTemplate({
|
||||||
|
name: mappingComponentName,
|
||||||
|
})
|
||||||
|
.catch(addError);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that configuration migrations for risk score indices are seamlessly handled across Kibana upgrades.
|
* Ensures that configuration migrations for risk score indices are seamlessly handled across Kibana upgrades.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue