diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index b99fa8935b692..a89469acf569b 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -241,19 +241,19 @@ export class EntityStoreDataClient { ) { const setupStartTime = moment().utc().toISOString(); const { logger, namespace, appClient, dataViewsService } = this.options; - const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); + try { + const indexPatterns = await buildIndexPatterns(namespace, appClient, dataViewsService); - const unitedDefinition = getUnitedEntityDefinition({ - indexPatterns, - entityType, - namespace, - fieldHistoryLength, - syncDelay: `${config.syncDelay.asSeconds()}s`, - frequency: `${config.frequency.asSeconds()}s`, - }); - const { entityManagerDefinition } = unitedDefinition; + const unitedDefinition = getUnitedEntityDefinition({ + indexPatterns, + entityType, + namespace, + fieldHistoryLength, + syncDelay: `${config.syncDelay.asSeconds()}s`, + frequency: `${config.frequency.asSeconds()}s`, + }); + const { entityManagerDefinition } = unitedDefinition; - try { // clean up any existing entity store await this.delete(entityType, taskManager, { deleteData: false, deleteEngine: false }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts index 0c5d86fa54800..5d0dcec11d9b6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts @@ -43,6 +43,19 @@ export default ({ getService }: FtrProviderContext) => { }); }); + describe('init error handling', () => { + afterEach(async () => { + await dataView.create('security-solution'); + await utils.cleanEngines(); + }); + + it('should return "error" when the security data view does not exist', async () => { + await dataView.delete('security-solution'); + await utils.initEntityEngineForEntityType('host'); + await utils.waitForEngineStatus('host', 'error'); + }); + }); + describe('enablement', () => { afterEach(async () => { await utils.cleanEngines(); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/data_view.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/data_view.ts index e94f7b7119ddf..716454bfbe169 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/data_view.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/data_view.ts @@ -10,7 +10,16 @@ export const dataViewRouteHelpersFactory = ( supertest: SuperTest.Agent, namespace: string = 'default' ) => ({ - create: (name: string) => { + create: async (name: string) => { + const { body: existingDataView, statusCode } = await supertest.get( + `/s/${namespace}/api/data_views/data_view/${name}-${namespace}` + ); + + if (statusCode === 200) { + // data view exists + return existingDataView; + } + return supertest .post(`/s/${namespace}/api/data_views/data_view`) .set('kbn-xsrf', 'foo') diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/entity_store.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/entity_store.ts index fff1040b81f29..0e7c94613010c 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/entity_store.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/utils/entity_store.ts @@ -51,7 +51,7 @@ export const EntityStoreUtils = ( } }; - const _initEntityEngineForEntityType = async (entityType: EntityType) => { + const initEntityEngineForEntityType = async (entityType: EntityType) => { log.info( `Initializing engine for entity type ${entityType} in namespace ${namespace || 'default'}` ); @@ -72,7 +72,7 @@ export const EntityStoreUtils = ( }; const initEntityEngineForEntityTypesAndWait = async (entityTypes: EntityType[]) => { - await Promise.all(entityTypes.map((entityType) => _initEntityEngineForEntityType(entityType))); + await Promise.all(entityTypes.map((entityType) => initEntityEngineForEntityType(entityType))); await retry.waitForWithTimeout( `Engines to start for entity types: ${entityTypes.join(', ')}`, @@ -90,6 +90,20 @@ export const EntityStoreUtils = ( ); }; + const waitForEngineStatus = async (entityType: EntityType, status: string) => { + await retry.waitForWithTimeout( + `Engine for entity type ${entityType} to be in status ${status}`, + 60_000, + async () => { + const { body } = await api + .getEntityEngine({ params: { entityType } }, namespace) + .expect(200); + log.debug(`Engine status for ${entityType}: ${body.status}`); + return body.status === status; + } + ); + }; + const enableEntityStore = async () => { const res = await api.initEntityStore({ body: {} }, namespace); if (res.status !== 200) { @@ -155,5 +169,7 @@ export const EntityStoreUtils = ( expectEngineAssetsExist, expectEngineAssetsDoNotExist, enableEntityStore, + waitForEngineStatus, + initEntityEngineForEntityType, }; };