mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[RAC] Fix index names used by RBAC, delete hardcoded map of Kibana features to index names (#109567)
**Ticket:** https://github.com/elastic/kibana/issues/102089 🚨 **This PR is critical for Observability 7.15** 🚨 ## Summary This PR introduces changes that fix the usage of alerts-as-data index naming in RBAC. It builds on top of https://github.com/elastic/kibana/pull/109346 and replaces https://github.com/elastic/kibana/pull/108872. TODO: - [x] Address https://github.com/elastic/kibana/pull/109346#pullrequestreview-735158370 - [x] Make changes to `AlertsClient.getAuthorizedAlertsIndices()` so it starts using `RuleDataService` to get index names by feature ids. - [x] Delete the hardcoded `mapConsumerToIndexName` where we had incorrect index names. - [x] Close https://github.com/elastic/kibana/pull/108872 ### Checklist Delete any items that are not applicable to this PR. - [ ] [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
811d3d779f
commit
8ce1d10791
33 changed files with 162 additions and 126 deletions
|
@ -26,17 +26,9 @@ export const AlertConsumers = {
|
||||||
export type AlertConsumers = typeof AlertConsumers[keyof typeof AlertConsumers];
|
export type AlertConsumers = typeof AlertConsumers[keyof typeof AlertConsumers];
|
||||||
export type STATUS_VALUES = 'open' | 'acknowledged' | 'closed' | 'in-progress'; // TODO: remove 'in-progress' after migration to 'acknowledged'
|
export type STATUS_VALUES = 'open' | 'acknowledged' | 'closed' | 'in-progress'; // TODO: remove 'in-progress' after migration to 'acknowledged'
|
||||||
|
|
||||||
export const mapConsumerToIndexName: Record<AlertConsumers, string | string[]> = {
|
export type ValidFeatureId = AlertConsumers;
|
||||||
apm: '.alerts-observability-apm',
|
|
||||||
logs: '.alerts-observability.logs',
|
|
||||||
infrastructure: '.alerts-observability.metrics',
|
|
||||||
observability: '.alerts-observability',
|
|
||||||
siem: '.alerts-security.alerts',
|
|
||||||
uptime: '.alerts-observability.uptime',
|
|
||||||
};
|
|
||||||
export type ValidFeatureId = keyof typeof mapConsumerToIndexName;
|
|
||||||
|
|
||||||
export const validFeatureIds = Object.keys(mapConsumerToIndexName);
|
export const validFeatureIds = Object.values(AlertConsumers).map((v) => v as string);
|
||||||
export const isValidFeatureId = (a: unknown): a is ValidFeatureId =>
|
export const isValidFeatureId = (a: unknown): a is ValidFeatureId =>
|
||||||
typeof a === 'string' && validFeatureIds.includes(a);
|
typeof a === 'string' && validFeatureIds.includes(a);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ const testIndices = [
|
||||||
'.ds-metrics-system.process.summary-default-2021.05.25-00000',
|
'.ds-metrics-system.process.summary-default-2021.05.25-00000',
|
||||||
'.kibana_shahzad_9',
|
'.kibana_shahzad_9',
|
||||||
'.kibana-felix-log-stream_8.0.0_001',
|
'.kibana-felix-log-stream_8.0.0_001',
|
||||||
'.kibana_smith_alerts-observability-apm-000001',
|
'.kibana_smith_alerts-observability.apm.alerts-000001',
|
||||||
'.ds-logs-endpoint.events.process-default-2021.05.26-000001',
|
'.ds-logs-endpoint.events.process-default-2021.05.26-000001',
|
||||||
'.kibana_dominiqueclarke54_8.0.0_001',
|
'.kibana_dominiqueclarke54_8.0.0_001',
|
||||||
'.kibana-cmarcondes-19_8.0.0_001',
|
'.kibana-cmarcondes-19_8.0.0_001',
|
||||||
|
@ -63,7 +63,7 @@ const onlySystemIndices = [
|
||||||
'.ds-metrics-system.process.summary-default-2021.05.25-00000',
|
'.ds-metrics-system.process.summary-default-2021.05.25-00000',
|
||||||
'.kibana_shahzad_9',
|
'.kibana_shahzad_9',
|
||||||
'.kibana-felix-log-stream_8.0.0_001',
|
'.kibana-felix-log-stream_8.0.0_001',
|
||||||
'.kibana_smith_alerts-observability-apm-000001',
|
'.kibana_smith_alerts-observability.apm.alerts-000001',
|
||||||
'.ds-logs-endpoint.events.process-default-2021.05.26-000001',
|
'.ds-logs-endpoint.events.process-default-2021.05.26-000001',
|
||||||
'.kibana_dominiqueclarke54_8.0.0_001',
|
'.kibana_dominiqueclarke54_8.0.0_001',
|
||||||
'.kibana-cmarcondes-19_8.0.0_001',
|
'.kibana-cmarcondes-19_8.0.0_001',
|
||||||
|
@ -85,7 +85,7 @@ const kibanaNoTaskIndices = [
|
||||||
'.kibana_shahzad_1',
|
'.kibana_shahzad_1',
|
||||||
'.kibana_shahzad_9',
|
'.kibana_shahzad_9',
|
||||||
'.kibana-felix-log-stream_8.0.0_001',
|
'.kibana-felix-log-stream_8.0.0_001',
|
||||||
'.kibana_smith_alerts-observability-apm-000001',
|
'.kibana_smith_alerts-observability.apm.alerts-000001',
|
||||||
'.kibana_dominiqueclarke54_8.0.0_001',
|
'.kibana_dominiqueclarke54_8.0.0_001',
|
||||||
'.kibana-cmarcondes-19_8.0.0_001',
|
'.kibana-cmarcondes-19_8.0.0_001',
|
||||||
'.kibana_dominiqueclarke55-alerts-8.0.0-000001',
|
'.kibana_dominiqueclarke55-alerts-8.0.0-000001',
|
||||||
|
|
|
@ -72,7 +72,6 @@ export function AlertsPage({ routeParams }: AlertsPageProps) {
|
||||||
registrationContexts: [
|
registrationContexts: [
|
||||||
'observability.apm',
|
'observability.apm',
|
||||||
'observability.logs',
|
'observability.logs',
|
||||||
'observability.infrastructure',
|
|
||||||
'observability.metrics',
|
'observability.metrics',
|
||||||
'observability.uptime',
|
'observability.uptime',
|
||||||
],
|
],
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as t from 'io-ts';
|
import * as t from 'io-ts';
|
||||||
|
import { Dataset } from '../../../rule_registry/server';
|
||||||
import { createObservabilityServerRoute } from './create_observability_server_route';
|
import { createObservabilityServerRoute } from './create_observability_server_route';
|
||||||
import { createObservabilityServerRouteRepository } from './create_observability_server_route_repository';
|
import { createObservabilityServerRouteRepository } from './create_observability_server_route_repository';
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ const alertsDynamicIndexPatternRoute = createObservabilityServerRoute({
|
||||||
const { namespace, registrationContexts } = params.query;
|
const { namespace, registrationContexts } = params.query;
|
||||||
const indexNames = registrationContexts.flatMap((registrationContext) => {
|
const indexNames = registrationContexts.flatMap((registrationContext) => {
|
||||||
const indexName = ruleDataService
|
const indexName = ruleDataService
|
||||||
.getRegisteredIndexInfo(registrationContext)
|
.findIndexByName(registrationContext, Dataset.alerts)
|
||||||
?.getPrimaryAlias(namespace);
|
?.getPrimaryAlias(namespace);
|
||||||
|
|
||||||
if (indexName != null) {
|
if (indexName != null) {
|
||||||
|
|
|
@ -73,7 +73,7 @@ await plugins.ruleRegistry.createOrUpdateComponentTemplate({
|
||||||
await plugins.ruleRegistry.createOrUpdateIndexTemplate({
|
await plugins.ruleRegistry.createOrUpdateIndexTemplate({
|
||||||
name: plugins.ruleRegistry.getFullAssetName('apm-index-template'),
|
name: plugins.ruleRegistry.getFullAssetName('apm-index-template'),
|
||||||
body: {
|
body: {
|
||||||
index_patterns: [plugins.ruleRegistry.getFullAssetName('observability-apm*')],
|
index_patterns: [plugins.ruleRegistry.getFullAssetName('observability.apm*')],
|
||||||
composed_of: [
|
composed_of: [
|
||||||
// Technical component template, required
|
// Technical component template, required
|
||||||
plugins.ruleRegistry.getFullAssetName(TECHNICAL_COMPONENT_TEMPLATE_NAME),
|
plugins.ruleRegistry.getFullAssetName(TECHNICAL_COMPONENT_TEMPLATE_NAME),
|
||||||
|
@ -85,7 +85,7 @@ await plugins.ruleRegistry.createOrUpdateIndexTemplate({
|
||||||
// Finally, create the rule data client that can be injected into rule type
|
// Finally, create the rule data client that can be injected into rule type
|
||||||
// executors and API endpoints
|
// executors and API endpoints
|
||||||
const ruleDataClient = new RuleDataClient({
|
const ruleDataClient = new RuleDataClient({
|
||||||
alias: plugins.ruleRegistry.getFullAssetName('observability-apm'),
|
alias: plugins.ruleRegistry.getFullAssetName('observability.apm'),
|
||||||
getClusterClient: async () => {
|
getClusterClient: async () => {
|
||||||
const coreStart = await getCoreStart();
|
const coreStart = await getCoreStart();
|
||||||
return coreStart.elasticsearch.client.asInternalUser;
|
return coreStart.elasticsearch.client.asInternalUser;
|
||||||
|
|
|
@ -13,14 +13,13 @@ import type {
|
||||||
getEsQueryConfig as getEsQueryConfigTyped,
|
getEsQueryConfig as getEsQueryConfigTyped,
|
||||||
getSafeSortIds as getSafeSortIdsTyped,
|
getSafeSortIds as getSafeSortIdsTyped,
|
||||||
isValidFeatureId as isValidFeatureIdTyped,
|
isValidFeatureId as isValidFeatureIdTyped,
|
||||||
mapConsumerToIndexName as mapConsumerToIndexNameTyped,
|
|
||||||
STATUS_VALUES,
|
STATUS_VALUES,
|
||||||
|
ValidFeatureId,
|
||||||
} from '@kbn/rule-data-utils';
|
} from '@kbn/rule-data-utils';
|
||||||
import {
|
import {
|
||||||
getEsQueryConfig as getEsQueryConfigNonTyped,
|
getEsQueryConfig as getEsQueryConfigNonTyped,
|
||||||
getSafeSortIds as getSafeSortIdsNonTyped,
|
getSafeSortIds as getSafeSortIdsNonTyped,
|
||||||
isValidFeatureId as isValidFeatureIdNonTyped,
|
isValidFeatureId as isValidFeatureIdNonTyped,
|
||||||
mapConsumerToIndexName as mapConsumerToIndexNameNonTyped,
|
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
} from '@kbn/rule-data-utils/target_node/alerts_as_data_rbac';
|
} from '@kbn/rule-data-utils/target_node/alerts_as_data_rbac';
|
||||||
|
|
||||||
|
@ -42,11 +41,11 @@ import {
|
||||||
SPACE_IDS,
|
SPACE_IDS,
|
||||||
} from '../../common/technical_rule_data_field_names';
|
} from '../../common/technical_rule_data_field_names';
|
||||||
import { ParsedTechnicalFields } from '../../common/parse_technical_fields';
|
import { ParsedTechnicalFields } from '../../common/parse_technical_fields';
|
||||||
|
import { Dataset, RuleDataPluginService } from '../rule_data_plugin_service';
|
||||||
|
|
||||||
const getEsQueryConfig: typeof getEsQueryConfigTyped = getEsQueryConfigNonTyped;
|
const getEsQueryConfig: typeof getEsQueryConfigTyped = getEsQueryConfigNonTyped;
|
||||||
const getSafeSortIds: typeof getSafeSortIdsTyped = getSafeSortIdsNonTyped;
|
const getSafeSortIds: typeof getSafeSortIdsTyped = getSafeSortIdsNonTyped;
|
||||||
const isValidFeatureId: typeof isValidFeatureIdTyped = isValidFeatureIdNonTyped;
|
const isValidFeatureId: typeof isValidFeatureIdTyped = isValidFeatureIdNonTyped;
|
||||||
const mapConsumerToIndexName: typeof mapConsumerToIndexNameTyped = mapConsumerToIndexNameNonTyped;
|
|
||||||
|
|
||||||
// TODO: Fix typings https://github.com/elastic/kibana/issues/101776
|
// TODO: Fix typings https://github.com/elastic/kibana/issues/101776
|
||||||
type NonNullableProps<Obj extends {}, Props extends keyof Obj> = Omit<Obj, Props> &
|
type NonNullableProps<Obj extends {}, Props extends keyof Obj> = Omit<Obj, Props> &
|
||||||
|
@ -71,6 +70,7 @@ export interface ConstructorOptions {
|
||||||
authorization: PublicMethodsOf<AlertingAuthorization>;
|
authorization: PublicMethodsOf<AlertingAuthorization>;
|
||||||
auditLogger?: AuditLogger;
|
auditLogger?: AuditLogger;
|
||||||
esClient: ElasticsearchClient;
|
esClient: ElasticsearchClient;
|
||||||
|
ruleDataService: RuleDataPluginService;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateOptions<Params extends AlertTypeParams> {
|
export interface UpdateOptions<Params extends AlertTypeParams> {
|
||||||
|
@ -115,15 +115,17 @@ export class AlertsClient {
|
||||||
private readonly authorization: PublicMethodsOf<AlertingAuthorization>;
|
private readonly authorization: PublicMethodsOf<AlertingAuthorization>;
|
||||||
private readonly esClient: ElasticsearchClient;
|
private readonly esClient: ElasticsearchClient;
|
||||||
private readonly spaceId: string | undefined;
|
private readonly spaceId: string | undefined;
|
||||||
|
private readonly ruleDataService: RuleDataPluginService;
|
||||||
|
|
||||||
constructor({ auditLogger, authorization, logger, esClient }: ConstructorOptions) {
|
constructor(options: ConstructorOptions) {
|
||||||
this.logger = logger;
|
this.logger = options.logger;
|
||||||
this.authorization = authorization;
|
this.authorization = options.authorization;
|
||||||
this.esClient = esClient;
|
this.esClient = options.esClient;
|
||||||
this.auditLogger = auditLogger;
|
this.auditLogger = options.auditLogger;
|
||||||
// If spaceId is undefined, it means that spaces is disabled
|
// If spaceId is undefined, it means that spaces is disabled
|
||||||
// Otherwise, if space is enabled and not specified, it is "default"
|
// Otherwise, if space is enabled and not specified, it is "default"
|
||||||
this.spaceId = this.authorization.getSpaceId();
|
this.spaceId = this.authorization.getSpaceId();
|
||||||
|
this.ruleDataService = options.ruleDataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getOutcome(
|
private getOutcome(
|
||||||
|
@ -666,15 +668,18 @@ export class AlertsClient {
|
||||||
authorizedFeatures.add(ruleType.producer);
|
authorizedFeatures.add(ruleType.producer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const toReturn = Array.from(authorizedFeatures).flatMap((feature) => {
|
const validAuthorizedFeatures = Array.from(authorizedFeatures).filter(
|
||||||
if (featureIds.includes(feature) && isValidFeatureId(feature)) {
|
(feature): feature is ValidFeatureId =>
|
||||||
if (feature === 'siem') {
|
featureIds.includes(feature) && isValidFeatureId(feature)
|
||||||
return `${mapConsumerToIndexName[feature]}-${this.spaceId}`;
|
);
|
||||||
} else {
|
|
||||||
return `${mapConsumerToIndexName[feature]}`;
|
const toReturn = validAuthorizedFeatures.flatMap((feature) => {
|
||||||
}
|
const indices = this.ruleDataService.findIndicesByFeature(feature, Dataset.alerts);
|
||||||
|
if (feature === 'siem') {
|
||||||
|
return indices.map((i) => `${i.baseName}-${this.spaceId}`);
|
||||||
|
} else {
|
||||||
|
return indices.map((i) => i.baseName);
|
||||||
}
|
}
|
||||||
return [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
|
|
|
@ -13,6 +13,8 @@ import { loggingSystemMock } from 'src/core/server/mocks';
|
||||||
import { securityMock } from '../../../security/server/mocks';
|
import { securityMock } from '../../../security/server/mocks';
|
||||||
import { AuditLogger } from '../../../security/server';
|
import { AuditLogger } from '../../../security/server';
|
||||||
import { alertingAuthorizationMock } from '../../../alerting/server/authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../alerting/server/authorization/alerting_authorization.mock';
|
||||||
|
import { ruleDataPluginServiceMock } from '../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||||
|
import { RuleDataPluginService } from '../rule_data_plugin_service';
|
||||||
|
|
||||||
jest.mock('./alerts_client');
|
jest.mock('./alerts_client');
|
||||||
|
|
||||||
|
@ -24,6 +26,7 @@ const alertsClientFactoryParams: AlertsClientFactoryProps = {
|
||||||
getAlertingAuthorization: (_: KibanaRequest) => alertingAuthMock,
|
getAlertingAuthorization: (_: KibanaRequest) => alertingAuthMock,
|
||||||
securityPluginSetup,
|
securityPluginSetup,
|
||||||
esClient: {} as ElasticsearchClient,
|
esClient: {} as ElasticsearchClient,
|
||||||
|
ruleDataService: (ruleDataPluginServiceMock.create() as unknown) as RuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = ({
|
const fakeRequest = ({
|
||||||
|
@ -64,6 +67,7 @@ describe('AlertsClientFactory', () => {
|
||||||
logger: alertsClientFactoryParams.logger,
|
logger: alertsClientFactoryParams.logger,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
esClient: {},
|
esClient: {},
|
||||||
|
ruleDataService: alertsClientFactoryParams.ruleDataService,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ElasticsearchClient, KibanaRequest, Logger } from 'src/core/server';
|
|
||||||
import { PublicMethodsOf } from '@kbn/utility-types';
|
import { PublicMethodsOf } from '@kbn/utility-types';
|
||||||
import { SecurityPluginSetup } from '../../../security/server';
|
import { ElasticsearchClient, KibanaRequest, Logger } from 'src/core/server';
|
||||||
import { AlertingAuthorization } from '../../../alerting/server';
|
import { AlertingAuthorization } from '../../../alerting/server';
|
||||||
|
import { SecurityPluginSetup } from '../../../security/server';
|
||||||
|
import { RuleDataPluginService } from '../rule_data_plugin_service';
|
||||||
import { AlertsClient } from './alerts_client';
|
import { AlertsClient } from './alerts_client';
|
||||||
|
|
||||||
export interface AlertsClientFactoryProps {
|
export interface AlertsClientFactoryProps {
|
||||||
|
@ -16,6 +17,7 @@ export interface AlertsClientFactoryProps {
|
||||||
esClient: ElasticsearchClient;
|
esClient: ElasticsearchClient;
|
||||||
getAlertingAuthorization: (request: KibanaRequest) => PublicMethodsOf<AlertingAuthorization>;
|
getAlertingAuthorization: (request: KibanaRequest) => PublicMethodsOf<AlertingAuthorization>;
|
||||||
securityPluginSetup: SecurityPluginSetup | undefined;
|
securityPluginSetup: SecurityPluginSetup | undefined;
|
||||||
|
ruleDataService: RuleDataPluginService | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AlertsClientFactory {
|
export class AlertsClientFactory {
|
||||||
|
@ -26,6 +28,7 @@ export class AlertsClientFactory {
|
||||||
request: KibanaRequest
|
request: KibanaRequest
|
||||||
) => PublicMethodsOf<AlertingAuthorization>;
|
) => PublicMethodsOf<AlertingAuthorization>;
|
||||||
private securityPluginSetup!: SecurityPluginSetup | undefined;
|
private securityPluginSetup!: SecurityPluginSetup | undefined;
|
||||||
|
private ruleDataService!: RuleDataPluginService | null;
|
||||||
|
|
||||||
public initialize(options: AlertsClientFactoryProps) {
|
public initialize(options: AlertsClientFactoryProps) {
|
||||||
/**
|
/**
|
||||||
|
@ -40,6 +43,7 @@ export class AlertsClientFactory {
|
||||||
this.logger = options.logger;
|
this.logger = options.logger;
|
||||||
this.esClient = options.esClient;
|
this.esClient = options.esClient;
|
||||||
this.securityPluginSetup = options.securityPluginSetup;
|
this.securityPluginSetup = options.securityPluginSetup;
|
||||||
|
this.ruleDataService = options.ruleDataService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async create(request: KibanaRequest): Promise<AlertsClient> {
|
public async create(request: KibanaRequest): Promise<AlertsClient> {
|
||||||
|
@ -50,6 +54,7 @@ export class AlertsClientFactory {
|
||||||
authorization: getAlertingAuthorization(request),
|
authorization: getAlertingAuthorization(request),
|
||||||
auditLogger: securityPluginSetup?.audit.asScoped(request),
|
auditLogger: securityPluginSetup?.audit.asScoped(request),
|
||||||
esClient: this.esClient,
|
esClient: this.esClient,
|
||||||
|
ruleDataService: this.ruleDataService!,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mo
|
||||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||||
import { AuditLogger } from '../../../../security/server';
|
import { AuditLogger } from '../../../../security/server';
|
||||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||||
|
import { ruleDataPluginServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||||
|
import { RuleDataPluginService } from '../../rule_data_plugin_service';
|
||||||
|
|
||||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||||
|
@ -30,6 +32,7 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
authorization: alertingAuthMock,
|
authorization: alertingAuthMock,
|
||||||
esClient: esClientMock,
|
esClient: esClientMock,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
ruleDataService: (ruleDataPluginServiceMock.create() as unknown) as RuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_SPACE = 'test_default_space_id';
|
const DEFAULT_SPACE = 'test_default_space_id';
|
||||||
|
@ -78,7 +81,7 @@ describe('bulkUpdate()', () => {
|
||||||
describe('ids', () => {
|
describe('ids', () => {
|
||||||
describe('audit log', () => {
|
describe('audit log', () => {
|
||||||
test('logs successful event in audit logger', async () => {
|
test('logs successful event in audit logger', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.mget.mockResolvedValueOnce(
|
esClientMock.mget.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -107,7 +110,7 @@ describe('bulkUpdate()', () => {
|
||||||
{
|
{
|
||||||
update: {
|
update: {
|
||||||
_id: fakeAlertId,
|
_id: fakeAlertId,
|
||||||
_index: '.alerts-observability-apm.alerts',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
status: 200,
|
status: 200,
|
||||||
},
|
},
|
||||||
|
@ -135,7 +138,7 @@ describe('bulkUpdate()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('audit error access if user is unauthorized for given alert', async () => {
|
test('audit error access if user is unauthorized for given alert', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.mget.mockResolvedValueOnce(
|
esClientMock.mget.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -181,7 +184,7 @@ describe('bulkUpdate()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('logs multiple error events in audit logger', async () => {
|
test('logs multiple error events in audit logger', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.mget.mockResolvedValueOnce(
|
esClientMock.mget.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -257,7 +260,7 @@ describe('bulkUpdate()', () => {
|
||||||
describe('query', () => {
|
describe('query', () => {
|
||||||
describe('audit log', () => {
|
describe('audit log', () => {
|
||||||
test('logs successful event in audit logger', async () => {
|
test('logs successful event in audit logger', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.search.mockResolvedValueOnce(
|
esClientMock.search.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -276,7 +279,7 @@ describe('bulkUpdate()', () => {
|
||||||
hits: [
|
hits: [
|
||||||
{
|
{
|
||||||
_id: fakeAlertId,
|
_id: fakeAlertId,
|
||||||
_index: '.alerts-observability-apm.alerts',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
||||||
[ALERT_RULE_CONSUMER]: 'apm',
|
[ALERT_RULE_CONSUMER]: 'apm',
|
||||||
|
@ -317,7 +320,7 @@ describe('bulkUpdate()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('audit error access if user is unauthorized for given alert', async () => {
|
test('audit error access if user is unauthorized for given alert', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.search.mockResolvedValueOnce(
|
esClientMock.search.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -336,7 +339,7 @@ describe('bulkUpdate()', () => {
|
||||||
hits: [
|
hits: [
|
||||||
{
|
{
|
||||||
_id: fakeAlertId,
|
_id: fakeAlertId,
|
||||||
_index: '.alerts-observability-apm.alerts',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: fakeRuleTypeId,
|
[ALERT_RULE_TYPE_ID]: fakeRuleTypeId,
|
||||||
[ALERT_RULE_CONSUMER]: 'apm',
|
[ALERT_RULE_CONSUMER]: 'apm',
|
||||||
|
@ -378,7 +381,7 @@ describe('bulkUpdate()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('logs multiple error events in audit logger', async () => {
|
test('logs multiple error events in audit logger', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
esClientMock.search.mockResolvedValueOnce(
|
esClientMock.search.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
|
@ -397,7 +400,7 @@ describe('bulkUpdate()', () => {
|
||||||
hits: [
|
hits: [
|
||||||
{
|
{
|
||||||
_id: successfulAuthzHit,
|
_id: successfulAuthzHit,
|
||||||
_index: '.alerts-observability-apm.alerts',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
||||||
[ALERT_RULE_CONSUMER]: 'apm',
|
[ALERT_RULE_CONSUMER]: 'apm',
|
||||||
|
@ -407,7 +410,7 @@ describe('bulkUpdate()', () => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
_id: unsuccessfulAuthzHit,
|
_id: unsuccessfulAuthzHit,
|
||||||
_index: '.alerts-observability-apm.alerts',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: fakeRuleTypeId,
|
[ALERT_RULE_TYPE_ID]: fakeRuleTypeId,
|
||||||
[ALERT_RULE_CONSUMER]: 'apm',
|
[ALERT_RULE_CONSUMER]: 'apm',
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mo
|
||||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||||
import { AuditLogger } from '../../../../security/server';
|
import { AuditLogger } from '../../../../security/server';
|
||||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||||
|
import { ruleDataPluginServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||||
|
import { RuleDataPluginService } from '../../rule_data_plugin_service';
|
||||||
|
|
||||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||||
|
@ -30,6 +32,7 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
authorization: alertingAuthMock,
|
authorization: alertingAuthMock,
|
||||||
esClient: esClientMock,
|
esClient: esClientMock,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
ruleDataService: (ruleDataPluginServiceMock.create() as unknown) as RuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_SPACE = 'test_default_space_id';
|
const DEFAULT_SPACE = 'test_default_space_id';
|
||||||
|
@ -90,7 +93,7 @@ describe('find()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -110,7 +113,7 @@ describe('find()', () => {
|
||||||
);
|
);
|
||||||
const result = await alertsClient.find({
|
const result = await alertsClient.find({
|
||||||
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
|
@ -124,7 +127,7 @@ describe('find()', () => {
|
||||||
"hits": Array [
|
"hits": Array [
|
||||||
Object {
|
Object {
|
||||||
"_id": "NoxgpHkBqbdrfX07MqXV",
|
"_id": "NoxgpHkBqbdrfX07MqXV",
|
||||||
"_index": ".alerts-observability-apm",
|
"_index": ".alerts-observability.apm.alerts",
|
||||||
"_primary_term": 2,
|
"_primary_term": 2,
|
||||||
"_seq_no": 362,
|
"_seq_no": 362,
|
||||||
"_source": Object {
|
"_source": Object {
|
||||||
|
@ -194,7 +197,7 @@ describe('find()', () => {
|
||||||
"track_total_hits": undefined,
|
"track_total_hits": undefined,
|
||||||
},
|
},
|
||||||
"ignore_unavailable": true,
|
"ignore_unavailable": true,
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"seq_no_primary_term": true,
|
"seq_no_primary_term": true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -221,7 +224,7 @@ describe('find()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -241,7 +244,7 @@ describe('find()', () => {
|
||||||
);
|
);
|
||||||
await alertsClient.find({
|
await alertsClient.find({
|
||||||
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(auditLogger.log).toHaveBeenCalledWith({
|
expect(auditLogger.log).toHaveBeenCalledWith({
|
||||||
|
@ -252,7 +255,7 @@ describe('find()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('audit error access if user is unauthorized for given alert', async () => {
|
test('audit error access if user is unauthorized for given alert', async () => {
|
||||||
const indexName = '.alerts-observability-apm';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const fakeAlertId = 'myfakeid1';
|
const fakeAlertId = 'myfakeid1';
|
||||||
// fakeRuleTypeId will cause authz to fail
|
// fakeRuleTypeId will cause authz to fail
|
||||||
const fakeRuleTypeId = 'fake.rule';
|
const fakeRuleTypeId = 'fake.rule';
|
||||||
|
@ -296,7 +299,7 @@ describe('find()', () => {
|
||||||
await expect(
|
await expect(
|
||||||
alertsClient.find({
|
alertsClient.find({
|
||||||
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
})
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find
|
"Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find
|
||||||
|
@ -326,7 +329,7 @@ describe('find()', () => {
|
||||||
await expect(
|
await expect(
|
||||||
alertsClient.find({
|
alertsClient.find({
|
||||||
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
})
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find
|
"Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find
|
||||||
|
@ -354,7 +357,7 @@ describe('find()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -378,7 +381,7 @@ describe('find()', () => {
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
const result = await alertsClient.find({
|
const result = await alertsClient.find({
|
||||||
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
query: { match: { [ALERT_WORKFLOW_STATUS]: 'open' } },
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
|
@ -393,7 +396,7 @@ describe('find()', () => {
|
||||||
"hits": Array [
|
"hits": Array [
|
||||||
Object {
|
Object {
|
||||||
"_id": "NoxgpHkBqbdrfX07MqXV",
|
"_id": "NoxgpHkBqbdrfX07MqXV",
|
||||||
"_index": ".alerts-observability-apm",
|
"_index": ".alerts-observability.apm.alerts",
|
||||||
"_primary_term": 2,
|
"_primary_term": 2,
|
||||||
"_seq_no": 362,
|
"_seq_no": 362,
|
||||||
"_source": Object {
|
"_source": Object {
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mo
|
||||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||||
import { AuditLogger } from '../../../../security/server';
|
import { AuditLogger } from '../../../../security/server';
|
||||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||||
|
import { ruleDataPluginServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||||
|
import { RuleDataPluginService } from '../../rule_data_plugin_service';
|
||||||
|
|
||||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||||
|
@ -30,6 +32,7 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
authorization: alertingAuthMock,
|
authorization: alertingAuthMock,
|
||||||
esClient: esClientMock,
|
esClient: esClientMock,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
ruleDataService: (ruleDataPluginServiceMock.create() as unknown) as RuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_SPACE = 'test_default_space_id';
|
const DEFAULT_SPACE = 'test_default_space_id';
|
||||||
|
@ -91,7 +94,7 @@ describe('get()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -109,7 +112,7 @@ describe('get()', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const result = await alertsClient.get({ id: '1', index: '.alerts-observability-apm' });
|
const result = await alertsClient.get({ id: '1', index: '.alerts-observability.apm.alerts' });
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"kibana.alert.rule.consumer": "apm",
|
"kibana.alert.rule.consumer": "apm",
|
||||||
|
@ -173,7 +176,7 @@ describe('get()', () => {
|
||||||
"track_total_hits": undefined,
|
"track_total_hits": undefined,
|
||||||
},
|
},
|
||||||
"ignore_unavailable": true,
|
"ignore_unavailable": true,
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"seq_no_primary_term": true,
|
"seq_no_primary_term": true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -200,7 +203,7 @@ describe('get()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -218,7 +221,10 @@ describe('get()', () => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await alertsClient.get({ id: 'NoxgpHkBqbdrfX07MqXV', index: '.alerts-observability-apm' });
|
await alertsClient.get({
|
||||||
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
|
index: '.alerts-observability.apm.alerts',
|
||||||
|
});
|
||||||
|
|
||||||
expect(auditLogger.log).toHaveBeenCalledWith({
|
expect(auditLogger.log).toHaveBeenCalledWith({
|
||||||
error: undefined,
|
error: undefined,
|
||||||
|
@ -228,7 +234,7 @@ describe('get()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('audit error access if user is unauthorized for given alert', async () => {
|
test('audit error access if user is unauthorized for given alert', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const fakeAlertId = 'myfakeid1';
|
const fakeAlertId = 'myfakeid1';
|
||||||
// fakeRuleTypeId will cause authz to fail
|
// fakeRuleTypeId will cause authz to fail
|
||||||
const fakeRuleTypeId = 'fake.rule';
|
const fakeRuleTypeId = 'fake.rule';
|
||||||
|
@ -269,7 +275,7 @@ describe('get()', () => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
await expect(alertsClient.get({ id: fakeAlertId, index: '.alerts-observability-apm.alerts' }))
|
await expect(alertsClient.get({ id: fakeAlertId, index: '.alerts-observability.apm.alerts' }))
|
||||||
.rejects.toThrowErrorMatchingInlineSnapshot(`
|
.rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"myfakeid1\\" or with query \\"undefined\\" and operation get
|
"Unable to retrieve alert details for alert with id of \\"myfakeid1\\" or with query \\"undefined\\" and operation get
|
||||||
Error: Error: Unauthorized for fake.rule and apm"
|
Error: Error: Unauthorized for fake.rule and apm"
|
||||||
|
@ -296,7 +302,7 @@ describe('get()', () => {
|
||||||
esClientMock.search.mockRejectedValue(error);
|
esClientMock.search.mockRejectedValue(error);
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
alertsClient.get({ id: 'NoxgpHkBqbdrfX07MqXV', index: '.alerts-observability-apm' })
|
alertsClient.get({ id: 'NoxgpHkBqbdrfX07MqXV', index: '.alerts-observability.apm.alerts' })
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"NoxgpHkBqbdrfX07MqXV\\" or with query \\"undefined\\" and operation get
|
"Unable to retrieve alert details for alert with id of \\"NoxgpHkBqbdrfX07MqXV\\" or with query \\"undefined\\" and operation get
|
||||||
Error: Error: something went wrong"
|
Error: Error: something went wrong"
|
||||||
|
@ -323,7 +329,7 @@ describe('get()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 1,
|
_version: 1,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -347,7 +353,7 @@ describe('get()', () => {
|
||||||
const alertsClient = new AlertsClient(alertsClientParams);
|
const alertsClient = new AlertsClient(alertsClientParams);
|
||||||
const result = await alertsClient.get({
|
const result = await alertsClient.get({
|
||||||
id: 'NoxgpHkBqbdrfX07MqXV',
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mo
|
||||||
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
import { alertingAuthorizationMock } from '../../../../alerting/server/authorization/alerting_authorization.mock';
|
||||||
import { AuditLogger } from '../../../../security/server';
|
import { AuditLogger } from '../../../../security/server';
|
||||||
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
import { AlertingAuthorizationEntity } from '../../../../alerting/server';
|
||||||
|
import { ruleDataPluginServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock';
|
||||||
|
import { RuleDataPluginService } from '../../rule_data_plugin_service';
|
||||||
|
|
||||||
const alertingAuthMock = alertingAuthorizationMock.create();
|
const alertingAuthMock = alertingAuthorizationMock.create();
|
||||||
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
const esClientMock = elasticsearchClientMock.createElasticsearchClient();
|
||||||
|
@ -30,6 +32,7 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = {
|
||||||
authorization: alertingAuthMock,
|
authorization: alertingAuthMock,
|
||||||
esClient: esClientMock,
|
esClient: esClientMock,
|
||||||
auditLogger,
|
auditLogger,
|
||||||
|
ruleDataService: (ruleDataPluginServiceMock.create() as unknown) as RuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_SPACE = 'test_default_space_id';
|
const DEFAULT_SPACE = 'test_default_space_id';
|
||||||
|
@ -91,7 +94,7 @@ describe('update()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
||||||
|
@ -109,7 +112,7 @@ describe('update()', () => {
|
||||||
esClientMock.update.mockResolvedValueOnce(
|
esClientMock.update.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
body: {
|
body: {
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 2,
|
_version: 2,
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
|
@ -123,12 +126,12 @@ describe('update()', () => {
|
||||||
id: '1',
|
id: '1',
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: undefined,
|
_version: undefined,
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"_id": "NoxgpHkBqbdrfX07MqXV",
|
"_id": "NoxgpHkBqbdrfX07MqXV",
|
||||||
"_index": ".alerts-observability-apm",
|
"_index": ".alerts-observability.apm.alerts",
|
||||||
"_primary_term": 1,
|
"_primary_term": 1,
|
||||||
"_seq_no": 1,
|
"_seq_no": 1,
|
||||||
"_shards": Object {
|
"_shards": Object {
|
||||||
|
@ -150,7 +153,7 @@ describe('update()', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"refresh": "wait_for",
|
"refresh": "wait_for",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -177,7 +180,7 @@ describe('update()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
||||||
|
@ -195,7 +198,7 @@ describe('update()', () => {
|
||||||
esClientMock.update.mockResolvedValueOnce(
|
esClientMock.update.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
body: {
|
body: {
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 2,
|
_version: 2,
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
|
@ -209,7 +212,7 @@ describe('update()', () => {
|
||||||
id: 'NoxgpHkBqbdrfX07MqXV',
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: undefined,
|
_version: undefined,
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(auditLogger.log).toHaveBeenCalledWith({
|
expect(auditLogger.log).toHaveBeenCalledWith({
|
||||||
|
@ -225,7 +228,7 @@ describe('update()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('audit error update if user is unauthorized for given alert', async () => {
|
test('audit error update if user is unauthorized for given alert', async () => {
|
||||||
const indexName = '.alerts-observability-apm.alerts';
|
const indexName = '.alerts-observability.apm.alerts';
|
||||||
const fakeAlertId = 'myfakeid1';
|
const fakeAlertId = 'myfakeid1';
|
||||||
// fakeRuleTypeId will cause authz to fail
|
// fakeRuleTypeId will cause authz to fail
|
||||||
const fakeRuleTypeId = 'fake.rule';
|
const fakeRuleTypeId = 'fake.rule';
|
||||||
|
@ -271,7 +274,7 @@ describe('update()', () => {
|
||||||
id: fakeAlertId,
|
id: fakeAlertId,
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: '1',
|
_version: '1',
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
})
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"myfakeid1\\" or with query \\"undefined\\" and operation update
|
"Unable to retrieve alert details for alert with id of \\"myfakeid1\\" or with query \\"undefined\\" and operation update
|
||||||
|
@ -303,7 +306,7 @@ describe('update()', () => {
|
||||||
id: 'NoxgpHkBqbdrfX07MqXV',
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: undefined,
|
_version: undefined,
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
})
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
"Unable to retrieve alert details for alert with id of \\"NoxgpHkBqbdrfX07MqXV\\" or with query \\"undefined\\" and operation update
|
"Unable to retrieve alert details for alert with id of \\"NoxgpHkBqbdrfX07MqXV\\" or with query \\"undefined\\" and operation update
|
||||||
|
@ -332,7 +335,7 @@ describe('update()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_source: {
|
_source: {
|
||||||
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
[ALERT_RULE_TYPE_ID]: 'apm.error_rate',
|
||||||
|
@ -354,7 +357,7 @@ describe('update()', () => {
|
||||||
id: 'NoxgpHkBqbdrfX07MqXV',
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: undefined,
|
_version: undefined,
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
})
|
})
|
||||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"something went wrong on update"`);
|
).rejects.toThrowErrorMatchingInlineSnapshot(`"something went wrong on update"`);
|
||||||
expect(auditLogger.log).toHaveBeenCalledWith({
|
expect(auditLogger.log).toHaveBeenCalledWith({
|
||||||
|
@ -389,7 +392,7 @@ describe('update()', () => {
|
||||||
{
|
{
|
||||||
found: true,
|
found: true,
|
||||||
_type: 'alert',
|
_type: 'alert',
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 2,
|
_version: 2,
|
||||||
_seq_no: 362,
|
_seq_no: 362,
|
||||||
|
@ -411,7 +414,7 @@ describe('update()', () => {
|
||||||
esClientMock.update.mockResolvedValueOnce(
|
esClientMock.update.mockResolvedValueOnce(
|
||||||
elasticsearchClientMock.createApiResponse({
|
elasticsearchClientMock.createApiResponse({
|
||||||
body: {
|
body: {
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 2,
|
_version: 2,
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
|
@ -429,13 +432,13 @@ describe('update()', () => {
|
||||||
id: 'NoxgpHkBqbdrfX07MqXV',
|
id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
_version: undefined,
|
_version: undefined,
|
||||||
index: '.alerts-observability-apm',
|
index: '.alerts-observability.apm.alerts',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result).toMatchInlineSnapshot(`
|
expect(result).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
"_id": "NoxgpHkBqbdrfX07MqXV",
|
"_id": "NoxgpHkBqbdrfX07MqXV",
|
||||||
"_index": ".alerts-observability-apm",
|
"_index": ".alerts-observability.apm.alerts",
|
||||||
"_primary_term": 1,
|
"_primary_term": 1,
|
||||||
"_seq_no": 1,
|
"_seq_no": 1,
|
||||||
"_shards": Object {
|
"_shards": Object {
|
||||||
|
|
|
@ -125,7 +125,7 @@ export class RuleRegistryPlugin
|
||||||
core: CoreStart,
|
core: CoreStart,
|
||||||
plugins: RuleRegistryPluginStartDependencies
|
plugins: RuleRegistryPluginStartDependencies
|
||||||
): RuleRegistryPluginStartContract {
|
): RuleRegistryPluginStartContract {
|
||||||
const { logger, alertsClientFactory, security } = this;
|
const { logger, alertsClientFactory, ruleDataService, security } = this;
|
||||||
|
|
||||||
alertsClientFactory.initialize({
|
alertsClientFactory.initialize({
|
||||||
logger,
|
logger,
|
||||||
|
@ -135,6 +135,7 @@ export class RuleRegistryPlugin
|
||||||
return plugins.alerting.getAlertingAuthorizationWithRequest(request);
|
return plugins.alerting.getAlertingAuthorizationWithRequest(request);
|
||||||
},
|
},
|
||||||
securityPluginSetup: security,
|
securityPluginSetup: security,
|
||||||
|
ruleDataService,
|
||||||
});
|
});
|
||||||
|
|
||||||
const getRacClientWithRequest = (request: KibanaRequest) => {
|
const getRacClientWithRequest = (request: KibanaRequest) => {
|
||||||
|
|
|
@ -29,6 +29,6 @@ export const getUpdateRequest = () =>
|
||||||
body: {
|
body: {
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
ids: ['alert-1'],
|
ids: ['alert-1'],
|
||||||
index: '.alerts-observability-apm*',
|
index: '.alerts-observability.apm.alerts*',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe('updateAlertByIdRoute', () => {
|
||||||
({ clients, context } = requestContextMock.createTools());
|
({ clients, context } = requestContextMock.createTools());
|
||||||
|
|
||||||
clients.rac.update.mockResolvedValue({
|
clients.rac.update.mockResolvedValue({
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 'WzM2MiwyXQ==',
|
_version: 'WzM2MiwyXQ==',
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
|
@ -37,7 +37,7 @@ describe('updateAlertByIdRoute', () => {
|
||||||
|
|
||||||
expect(response.status).toEqual(200);
|
expect(response.status).toEqual(200);
|
||||||
expect(response.body).toEqual({
|
expect(response.body).toEqual({
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
_version: 'WzM2MiwyXQ==',
|
_version: 'WzM2MiwyXQ==',
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
|
@ -58,7 +58,7 @@ describe('updateAlertByIdRoute', () => {
|
||||||
body: {
|
body: {
|
||||||
status: 'closed',
|
status: 'closed',
|
||||||
ids: 'alert-1',
|
ids: 'alert-1',
|
||||||
index: '.alerts-observability-apm*',
|
index: '.alerts-observability.apm.alerts*',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
context
|
context
|
||||||
|
@ -77,7 +77,7 @@ describe('updateAlertByIdRoute', () => {
|
||||||
body: {
|
body: {
|
||||||
notStatus: 'closed',
|
notStatus: 'closed',
|
||||||
ids: ['alert-1'],
|
ids: ['alert-1'],
|
||||||
index: '.alerts-observability-apm*',
|
index: '.alerts-observability.apm.alerts*',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
context
|
context
|
||||||
|
|
|
@ -12,18 +12,17 @@ type Schema = PublicMethodsOf<RuleDataPluginService>;
|
||||||
|
|
||||||
const createRuleDataPluginService = () => {
|
const createRuleDataPluginService = () => {
|
||||||
const mocked: jest.Mocked<Schema> = {
|
const mocked: jest.Mocked<Schema> = {
|
||||||
getRegisteredIndexInfo: jest.fn(),
|
|
||||||
getResourcePrefix: jest.fn(),
|
getResourcePrefix: jest.fn(),
|
||||||
getResourceName: jest.fn(),
|
getResourceName: jest.fn(),
|
||||||
isWriteEnabled: jest.fn(),
|
isWriteEnabled: jest.fn(),
|
||||||
initializeService: jest.fn(),
|
initializeService: jest.fn(),
|
||||||
initializeIndex: jest.fn(),
|
initializeIndex: jest.fn(),
|
||||||
|
findIndexByName: jest.fn(),
|
||||||
|
findIndicesByFeature: jest.fn(),
|
||||||
};
|
};
|
||||||
return mocked;
|
return mocked;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ruleDataPluginServiceMock: {
|
export const ruleDataPluginServiceMock = {
|
||||||
create: () => jest.Mocked<PublicMethodsOf<RuleDataPluginService>>;
|
|
||||||
} = {
|
|
||||||
create: createRuleDataPluginService,
|
create: createRuleDataPluginService,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Either, isLeft, left, right } from 'fp-ts/lib/Either';
|
import { Either, isLeft, left, right } from 'fp-ts/lib/Either';
|
||||||
|
import { ValidFeatureId } from '@kbn/rule-data-utils';
|
||||||
|
|
||||||
import { ElasticsearchClient, Logger } from 'kibana/server';
|
import { ElasticsearchClient, Logger } from 'kibana/server';
|
||||||
|
|
||||||
import { IRuleDataClient, RuleDataClient, WaitResult } from '../rule_data_client';
|
import { IRuleDataClient, RuleDataClient, WaitResult } from '../rule_data_client';
|
||||||
import { IndexInfo } from './index_info';
|
import { IndexInfo } from './index_info';
|
||||||
import { IndexOptions } from './index_options';
|
import { Dataset, IndexOptions } from './index_options';
|
||||||
import { ResourceInstaller } from './resource_installer';
|
import { ResourceInstaller } from './resource_installer';
|
||||||
import { joinWithDash } from './utils';
|
import { joinWithDash } from './utils';
|
||||||
|
|
||||||
|
@ -26,12 +27,16 @@ interface ConstructorOptions {
|
||||||
* A service for creating and using Elasticsearch indices for alerts-as-data.
|
* A service for creating and using Elasticsearch indices for alerts-as-data.
|
||||||
*/
|
*/
|
||||||
export class RuleDataPluginService {
|
export class RuleDataPluginService {
|
||||||
|
private readonly indicesByBaseName: Map<string, IndexInfo>;
|
||||||
|
private readonly indicesByFeatureId: Map<string, IndexInfo[]>;
|
||||||
private readonly resourceInstaller: ResourceInstaller;
|
private readonly resourceInstaller: ResourceInstaller;
|
||||||
private installCommonResources: Promise<Either<Error, 'ok'>>;
|
private installCommonResources: Promise<Either<Error, 'ok'>>;
|
||||||
private isInitialized: boolean;
|
private isInitialized: boolean;
|
||||||
private registeredIndices: Map<string, IndexInfo> = new Map();
|
|
||||||
|
|
||||||
constructor(private readonly options: ConstructorOptions) {
|
constructor(private readonly options: ConstructorOptions) {
|
||||||
|
this.indicesByBaseName = new Map();
|
||||||
|
this.indicesByFeatureId = new Map();
|
||||||
|
|
||||||
this.resourceInstaller = new ResourceInstaller({
|
this.resourceInstaller = new ResourceInstaller({
|
||||||
getResourceName: (name) => this.getResourceName(name),
|
getResourceName: (name) => this.getResourceName(name),
|
||||||
getClusterClient: options.getClusterClient,
|
getClusterClient: options.getClusterClient,
|
||||||
|
@ -106,7 +111,9 @@ export class RuleDataPluginService {
|
||||||
indexOptions,
|
indexOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registeredIndices.set(indexOptions.registrationContext, indexInfo);
|
const indicesAssociatedWithFeature = this.indicesByFeatureId.get(indexOptions.feature) ?? [];
|
||||||
|
this.indicesByFeatureId.set(indexOptions.feature, [...indicesAssociatedWithFeature, indexInfo]);
|
||||||
|
this.indicesByBaseName.set(indexInfo.baseName, indexInfo);
|
||||||
|
|
||||||
const waitUntilClusterClientAvailable = async (): Promise<WaitResult> => {
|
const waitUntilClusterClientAvailable = async (): Promise<WaitResult> => {
|
||||||
try {
|
try {
|
||||||
|
@ -153,11 +160,19 @@ export class RuleDataPluginService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the index information associated with the given `registrationContext`.
|
* Looks up the index information associated with the given registration context and dataset.
|
||||||
* @param registrationContext
|
|
||||||
* @returns the IndexInfo or undefined
|
|
||||||
*/
|
*/
|
||||||
public getRegisteredIndexInfo(registrationContext: string): IndexInfo | undefined {
|
public findIndexByName(registrationContext: string, dataset: Dataset): IndexInfo | null {
|
||||||
return this.registeredIndices.get(registrationContext);
|
const baseName = this.getResourceName(`${registrationContext}.${dataset}`);
|
||||||
|
return this.indicesByBaseName.get(baseName) ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up the index information associated with the given Kibana "feature".
|
||||||
|
* Note: features are used in RBAC.
|
||||||
|
*/
|
||||||
|
public findIndicesByFeature(featureId: ValidFeatureId, dataset?: Dataset): IndexInfo[] {
|
||||||
|
const foundIndices = this.indicesByFeatureId.get(featureId) ?? [];
|
||||||
|
return dataset ? foundIndices.filter((i) => i.indexOptions.dataset === dataset) : foundIndices;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,6 @@ curl -s -k \
|
||||||
-H 'kbn-xsrf: 123' \
|
-H 'kbn-xsrf: 123' \
|
||||||
-u observer:changeme \
|
-u observer:changeme \
|
||||||
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/bulk_update \
|
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/bulk_update \
|
||||||
-d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq .
|
-d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
# -d "{\"ids\": $IDS, \"query\": \"kibana.rac.alert.status: open\", \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq .
|
# -d "{\"ids\": $IDS, \"query\": \"kibana.rac.alert.status: open\", \"status\":\"$STATUS\", \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
# -d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq .
|
# -d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
|
|
|
@ -25,4 +25,4 @@ curl -s -k \
|
||||||
-H 'kbn-xsrf: 123' \
|
-H 'kbn-xsrf: 123' \
|
||||||
-u observer:changeme \
|
-u observer:changeme \
|
||||||
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/bulk_update \
|
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/bulk_update \
|
||||||
-d "{\"query\": \"$QUERY\", \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq .
|
-d "{\"query\": \"$QUERY\", \"status\":\"$STATUS\", \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
|
|
|
@ -26,4 +26,4 @@ curl -v \
|
||||||
-H 'kbn-xsrf: 123' \
|
-H 'kbn-xsrf: 123' \
|
||||||
-u observer:changeme \
|
-u observer:changeme \
|
||||||
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/find \
|
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts/find \
|
||||||
-d "{\"query\": { \"match\": { \"kibana.alert.status\": \"open\" }}, \"index\":\".alerts-observability-apm\"}" | jq .
|
-d "{\"query\": { \"match\": { \"kibana.alert.status\": \"open\" }}, \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
|
|
|
@ -19,4 +19,4 @@ cd ..
|
||||||
# Example: ./get_observability_alert.sh hunter
|
# Example: ./get_observability_alert.sh hunter
|
||||||
curl -v -k \
|
curl -v -k \
|
||||||
-u $USER:changeme \
|
-u $USER:changeme \
|
||||||
-X GET "${KIBANA_URL}${SPACE_URL}/internal/rac/alerts?id=$ID&index=.alerts-observability-apm" | jq .
|
-X GET "${KIBANA_URL}${SPACE_URL}/internal/rac/alerts?id=$ID&index=.alerts-observability.apm.alerts" | jq .
|
||||||
|
|
|
@ -25,4 +25,4 @@ curl -s -k \
|
||||||
-H 'kbn-xsrf: 123' \
|
-H 'kbn-xsrf: 123' \
|
||||||
-u observer:changeme \
|
-u observer:changeme \
|
||||||
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts \
|
-X POST ${KIBANA_URL}${SPACE_URL}/internal/rac/alerts \
|
||||||
-d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability-apm\"}" | jq .
|
-d "{\"ids\": $IDS, \"status\":\"$STATUS\", \"index\":\".alerts-observability.apm.alerts\"}" | jq .
|
||||||
|
|
|
@ -73,7 +73,7 @@ export const createRuleTypeMocks = (
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
isWriteEnabled: jest.fn(() => true),
|
isWriteEnabled: jest.fn(() => true),
|
||||||
indexName: '.alerts-observability.synthetics.alerts',
|
indexName: '.alerts-observability.uptime.alerts',
|
||||||
} as unknown) as IRuleDataClient,
|
} as unknown) as IRuleDataClient,
|
||||||
},
|
},
|
||||||
services,
|
services,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"value": {
|
"value": {
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"id": "NoxgpHkBqbdrfX07MqXV",
|
"id": "NoxgpHkBqbdrfX07MqXV",
|
||||||
"source": {
|
"source": {
|
||||||
"event.kind" : "signal",
|
"event.kind" : "signal",
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
{
|
{
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"value": {
|
"value": {
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"id": "space1alert",
|
"id": "space1alert",
|
||||||
"source": {
|
"source": {
|
||||||
"event.kind" : "signal",
|
"event.kind" : "signal",
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
{
|
{
|
||||||
"type": "doc",
|
"type": "doc",
|
||||||
"value": {
|
"value": {
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"id": "space2alert",
|
"id": "space2alert",
|
||||||
"source": {
|
"source": {
|
||||||
"event.kind" : "signal",
|
"event.kind" : "signal",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "index",
|
"type": "index",
|
||||||
"value": {
|
"value": {
|
||||||
"index": ".alerts-observability-apm",
|
"index": ".alerts-observability.apm.alerts",
|
||||||
"mappings": {
|
"mappings": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"message": {
|
"message": {
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
const SECURITY_SOLUTION_ALERT_ID = '020202';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
const ALERT_VERSION = Buffer.from(JSON.stringify([0, 1]), 'utf8').toString('base64'); // required for optimistic concurrency control
|
const ALERT_VERSION = Buffer.from(JSON.stringify([0, 1]), 'utf8').toString('base64'); // required for optimistic concurrency control
|
||||||
|
|
|
@ -38,9 +38,9 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
.set('kbn-xsrf', 'true')
|
.set('kbn-xsrf', 'true')
|
||||||
.expect(200);
|
.expect(200);
|
||||||
const observabilityIndex = indexNames?.index_name?.find(
|
const observabilityIndex = indexNames?.index_name?.find(
|
||||||
(indexName) => indexName === '.alerts-observability-apm'
|
(indexName) => indexName === '.alerts-observability.apm.alerts'
|
||||||
);
|
);
|
||||||
expect(observabilityIndex).to.eql('.alerts-observability-apm');
|
expect(observabilityIndex).to.eql('.alerts-observability.apm.alerts');
|
||||||
return observabilityIndex;
|
return observabilityIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
.set('kbn-xsrf', 'true')
|
.set('kbn-xsrf', 'true')
|
||||||
.expect(200);
|
.expect(200);
|
||||||
const observabilityIndex = indexNames?.index_name?.find(
|
const observabilityIndex = indexNames?.index_name?.find(
|
||||||
(indexName) => indexName === '.alerts-observability-apm'
|
(indexName) => indexName === '.alerts-observability.apm.alerts'
|
||||||
);
|
);
|
||||||
expect(observabilityIndex).to.eql('.alerts-observability-apm');
|
expect(observabilityIndex).to.eql('.alerts-observability.apm.alerts');
|
||||||
return observabilityIndex;
|
return observabilityIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
.expect(200);
|
.expect(200);
|
||||||
expect(omit(['_version', '_seq_no'], res.body)).to.eql({
|
expect(omit(['_version', '_seq_no'], res.body)).to.eql({
|
||||||
success: true,
|
success: true,
|
||||||
_index: '.alerts-observability-apm',
|
_index: '.alerts-observability.apm.alerts',
|
||||||
_id: 'NoxgpHkBqbdrfX07MqXV',
|
_id: 'NoxgpHkBqbdrfX07MqXV',
|
||||||
result: 'updated',
|
result: 'updated',
|
||||||
_shards: { total: 2, successful: 1, failed: 0 },
|
_shards: { total: 2, successful: 1, failed: 0 },
|
||||||
|
|
|
@ -22,7 +22,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
|
|
||||||
const getAPMIndexName = async (user: User) => {
|
const getAPMIndexName = async (user: User) => {
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default ({ getService }: FtrProviderContext) => {
|
||||||
const SPACE1 = 'space1';
|
const SPACE1 = 'space1';
|
||||||
const SPACE2 = 'space2';
|
const SPACE2 = 'space2';
|
||||||
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
const APM_ALERT_ID = 'NoxgpHkBqbdrfX07MqXV';
|
||||||
const APM_ALERT_INDEX = '.alerts-observability-apm';
|
const APM_ALERT_INDEX = '.alerts-observability.apm.alerts';
|
||||||
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
const SECURITY_SOLUTION_ALERT_INDEX = '.alerts-security.alerts';
|
||||||
const ALERT_VERSION = Buffer.from(JSON.stringify([0, 1]), 'utf8').toString('base64'); // required for optimistic concurrency control
|
const ALERT_VERSION = Buffer.from(JSON.stringify([0, 1]), 'utf8').toString('base64'); // required for optimistic concurrency control
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue