mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Telemetry] Add index metadata EBT event (#218546)
## Summary - Fix https://github.com/elastic/kibana/issues/216044 - Add a new EBT event collecting index template info ```typescript export interface IndexTemplateInfo { template_name: string; index_mode: Nullable<string>; datastream: boolean; package_name: Nullable<string>; managed_by: Nullable<string>; beat: Nullable<string>; is_managed: Nullable<boolean>; composed_of: string[]; source_enabled: Nullable<boolean>; source_includes: string[]; source_excludes: string[]; } ``` ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [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 - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed
This commit is contained in:
parent
7160b360c7
commit
c9b3a3e27b
5 changed files with 237 additions and 7 deletions
|
@ -15,6 +15,7 @@ import type {
|
|||
DataStreams,
|
||||
IlmPolicies,
|
||||
IlmsStats,
|
||||
IndexTemplatesStats,
|
||||
IndicesSettings,
|
||||
IndicesStats,
|
||||
} from '../indices.metadata.types';
|
||||
|
@ -650,6 +651,103 @@ export const TELEMETRY_ILM_STATS_EVENT: EventTypeOpts<IlmsStats> = {
|
|||
},
|
||||
};
|
||||
|
||||
export const TELEMETRY_INDEX_TEMPLATES_EVENT: EventTypeOpts<IndexTemplatesStats> = {
|
||||
eventType: 'telemetry_index_templates_event',
|
||||
schema: {
|
||||
items: {
|
||||
type: 'array',
|
||||
items: {
|
||||
properties: {
|
||||
template_name: {
|
||||
type: 'keyword',
|
||||
_meta: { description: 'The name of the template.' },
|
||||
},
|
||||
index_mode: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description: 'The index mode.',
|
||||
},
|
||||
},
|
||||
datastream: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
description: 'Datastream dataset',
|
||||
},
|
||||
},
|
||||
package_name: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description: 'The package name',
|
||||
},
|
||||
},
|
||||
managed_by: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description: 'Managed by',
|
||||
},
|
||||
},
|
||||
beat: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description: 'Shipper name',
|
||||
},
|
||||
},
|
||||
is_managed: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description: 'Whether the template is managed',
|
||||
},
|
||||
},
|
||||
composed_of: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'List of template components',
|
||||
},
|
||||
},
|
||||
_meta: { description: '' },
|
||||
},
|
||||
source_enabled: {
|
||||
type: 'boolean',
|
||||
_meta: {
|
||||
optional: true,
|
||||
description:
|
||||
'The _source field contains the original JSON document body that was provided at index time',
|
||||
},
|
||||
},
|
||||
source_includes: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: 'Fields included in _source, if enabled',
|
||||
},
|
||||
},
|
||||
_meta: { description: '' },
|
||||
},
|
||||
source_excludes: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'keyword',
|
||||
_meta: {
|
||||
description: '',
|
||||
},
|
||||
},
|
||||
_meta: { description: 'Fields excludes from _source, if enabled' },
|
||||
},
|
||||
},
|
||||
},
|
||||
_meta: { description: 'Index templates info' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const TELEMETRY_NODE_INGEST_PIPELINES_STATS_EVENT: EventTypeOpts<NodeIngestPipelinesStats> =
|
||||
{
|
||||
eventType: 'telemetry_node_ingest_pipelines_stats_event',
|
||||
|
@ -1306,6 +1404,7 @@ export const events = [
|
|||
TELEMETRY_ILM_STATS_EVENT,
|
||||
TELEMETRY_INDEX_SETTINGS_EVENT,
|
||||
TELEMETRY_INDEX_STATS_EVENT,
|
||||
TELEMETRY_INDEX_TEMPLATES_EVENT,
|
||||
TELEMETRY_NODE_INGEST_PIPELINES_STATS_EVENT,
|
||||
SIEM_MIGRATIONS_MIGRATION_SUCCESS,
|
||||
SIEM_MIGRATIONS_MIGRATION_FAILURE,
|
||||
|
|
|
@ -41,6 +41,24 @@ export interface IlmStats {
|
|||
policy_name?: string;
|
||||
}
|
||||
|
||||
export interface IndexTemplatesStats {
|
||||
items: IndexTemplateInfo[];
|
||||
}
|
||||
|
||||
export interface IndexTemplateInfo {
|
||||
template_name: string;
|
||||
index_mode: Nullable<string>;
|
||||
datastream: boolean;
|
||||
package_name: Nullable<string>;
|
||||
managed_by: Nullable<string>;
|
||||
beat: Nullable<string>;
|
||||
is_managed: Nullable<boolean>;
|
||||
composed_of: string[];
|
||||
source_enabled: Nullable<boolean>;
|
||||
source_includes: string[];
|
||||
source_excludes: string[];
|
||||
}
|
||||
|
||||
export interface IndicesStats {
|
||||
items: IndexStats[];
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import type {
|
|||
IndicesGetRequest,
|
||||
NodesStatsRequest,
|
||||
Duration,
|
||||
IndicesGetIndexTemplateRequest,
|
||||
} from '@elastic/elasticsearch/lib/api/types';
|
||||
import { ENDPOINT_ARTIFACT_LISTS } from '@kbn/securitysolution-list-constants';
|
||||
import {
|
||||
|
@ -101,6 +102,7 @@ import type {
|
|||
Index,
|
||||
IndexSettings,
|
||||
IndexStats,
|
||||
IndexTemplateInfo,
|
||||
} from './indices.metadata.types';
|
||||
import { chunkStringsByMaxLength } from './collections_helpers';
|
||||
import type {
|
||||
|
@ -265,6 +267,7 @@ export interface ITelemetryReceiver {
|
|||
getDataStreams(): Promise<DataStream[]>;
|
||||
getIndicesStats(indices: string[], chunkSize: number): AsyncGenerator<IndexStats, void, unknown>;
|
||||
getIlmsStats(indices: string[], chunkSize: number): AsyncGenerator<IlmStats, void, unknown>;
|
||||
getIndexTemplatesStats(): Promise<IndexTemplateInfo[]>;
|
||||
getIlmsPolicies(ilms: string[], chunkSize: number): AsyncGenerator<IlmPolicy, void, unknown>;
|
||||
|
||||
getIngestPipelinesStats(timeout: Duration): Promise<NodeIngestPipelinesStats[]>;
|
||||
|
@ -1373,11 +1376,11 @@ export class TelemetryReceiver implements ITelemetryReceiver {
|
|||
name: '*',
|
||||
expand_wildcards: ['open', 'hidden'],
|
||||
filter_path: [
|
||||
'data_streams.ilm_policy',
|
||||
'data_streams.indices.ilm_policy',
|
||||
'data_streams.indices.index_name',
|
||||
'data_streams.name',
|
||||
'ilm_policy',
|
||||
'template',
|
||||
'data_streams.template',
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -1509,6 +1512,54 @@ export class TelemetryReceiver implements ITelemetryReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
public async getIndexTemplatesStats(): Promise<IndexTemplateInfo[]> {
|
||||
const es = this.esClient();
|
||||
|
||||
this.logger.l('Fetching datstreams');
|
||||
|
||||
const request: IndicesGetIndexTemplateRequest = {
|
||||
name: '*',
|
||||
filter_path: [
|
||||
'index_templates.name',
|
||||
'index_templates.index_template.template.settings.index.mode',
|
||||
'index_templates.index_template.data_stream',
|
||||
'index_templates.index_template._meta.package.name',
|
||||
'index_templates.index_template._meta.managed_by',
|
||||
'index_templates.index_template._meta.beat',
|
||||
'index_templates.index_template._meta.managed',
|
||||
'index_templates.index_template.composed_of',
|
||||
'index_templates.index_template.template.mappings._source.enabled',
|
||||
'index_templates.index_template.template.mappings._source.includes',
|
||||
'index_templates.index_template.template.mappings._source.excludes',
|
||||
],
|
||||
};
|
||||
|
||||
return es.indices
|
||||
.getIndexTemplate(request)
|
||||
.then((response) =>
|
||||
response.index_templates.map((props) => {
|
||||
const datastream = props.index_template?.data_stream !== undefined;
|
||||
return {
|
||||
template_name: props.name,
|
||||
index_mode: props.index_template.template?.settings?.index?.mode,
|
||||
package_name: props.index_template._meta?.package?.name,
|
||||
datastream,
|
||||
managed_by: props.index_template._meta?.managed_by,
|
||||
beat: props.index_template._meta?.beat,
|
||||
is_managed: props.index_template._meta?.managed,
|
||||
composed_of: props.index_template.composed_of,
|
||||
source_enabled: props.index_template.template?.mappings?._source?.enabled,
|
||||
source_includes: props.index_template.template?.mappings?._source?.includes ?? [],
|
||||
source_excludes: props.index_template.template?.mappings?._source?.excludes ?? [],
|
||||
} as IndexTemplateInfo;
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
this.logger.warn('Error fetching index templates', { error_message: error } as LogMeta);
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
public async *getIlmsPolicies(ilms: string[], chunkSize: number) {
|
||||
const es = this.esClient();
|
||||
const safeChunkSize = Math.min(chunkSize, 3000);
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
TELEMETRY_ILM_STATS_EVENT,
|
||||
TELEMETRY_INDEX_SETTINGS_EVENT,
|
||||
TELEMETRY_INDEX_STATS_EVENT,
|
||||
TELEMETRY_INDEX_TEMPLATES_EVENT,
|
||||
} from '../event_based/events';
|
||||
import { telemetryConfiguration } from '../configuration';
|
||||
import type {
|
||||
|
@ -29,6 +30,8 @@ import type {
|
|||
IlmPolicies,
|
||||
IlmsStats,
|
||||
IndexSettings,
|
||||
IndexTemplateInfo,
|
||||
IndexTemplatesStats,
|
||||
IndicesSettings,
|
||||
IndicesStats,
|
||||
} from '../indices.metadata.types';
|
||||
|
@ -81,6 +84,19 @@ export function createTelemetryIndicesMetadataTaskConfig() {
|
|||
return indicesStats.items.length;
|
||||
};
|
||||
|
||||
const publishIndexTemplatesStats = async (
|
||||
indexTemplates: IndexTemplateInfo[]
|
||||
): Promise<number> => {
|
||||
const templateStats: IndexTemplatesStats = {
|
||||
items: indexTemplates,
|
||||
};
|
||||
|
||||
sender.reportEBT(TELEMETRY_INDEX_TEMPLATES_EVENT, templateStats);
|
||||
log.info(`Sent index templates`, { count: indexTemplates.length } as LogMeta);
|
||||
|
||||
return templateStats.items.length;
|
||||
};
|
||||
|
||||
const publishIndicesSettings = (settings: IndexSettings[]): number => {
|
||||
const indicesSettings: IndicesSettings = {
|
||||
items: settings,
|
||||
|
@ -137,9 +153,10 @@ export function createTelemetryIndicesMetadataTaskConfig() {
|
|||
|
||||
try {
|
||||
// 1. Get cluster stats and list of indices and datastreams
|
||||
const [indicesSettings, dataStreams] = await Promise.all([
|
||||
const [indicesSettings, dataStreams, indexTemplates] = await Promise.all([
|
||||
receiver.getIndices(),
|
||||
receiver.getDataStreams(),
|
||||
receiver.getIndexTemplatesStats(),
|
||||
]);
|
||||
|
||||
const indices = indicesSettings.map((index) => index.index_name);
|
||||
|
@ -194,11 +211,26 @@ export function createTelemetryIndicesMetadataTaskConfig() {
|
|||
return 0;
|
||||
});
|
||||
|
||||
// 7. Publish index templates
|
||||
const indexTemplatesCount: number = await publishIndexTemplatesStats(
|
||||
indexTemplates.slice(0, taskConfig.indices_threshold)
|
||||
)
|
||||
.then((count) => {
|
||||
incrementCounter(TelemetryCounter.DOCS_SENT, 'index-templates', count);
|
||||
return count;
|
||||
})
|
||||
.catch((err) => {
|
||||
log.warn(`Error getting index templates`, { error: err.message } as LogMeta);
|
||||
incrementCounter(TelemetryCounter.RUNTIME_ERROR, 'index-templates', 1);
|
||||
return 0;
|
||||
});
|
||||
|
||||
log.info(`Sent EBT events`, {
|
||||
datastreams: dsCount,
|
||||
indicesSettings: indicesSettingsCount,
|
||||
ilms: ilmNames.size,
|
||||
indices: indicesCount,
|
||||
indexTemplates: indexTemplatesCount,
|
||||
policies: policyCount,
|
||||
} as LogMeta);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ const TELEMETRY_ILM_STATS_EVENT = 'telemetry_ilm_stats_event';
|
|||
const TELEMETRY_ILM_POLICY_EVENT = 'telemetry_ilm_policy_event';
|
||||
const TELEMETRY_DATA_STREAM_EVENT = 'telemetry_data_stream_event';
|
||||
const TELEMETRY_INDEX_SETTINGS_EVENT = 'telemetry_index_settings_event';
|
||||
const TELEMETRY_INDEX_TEMPLATES_EVENT = 'telemetry_index_templates_event';
|
||||
|
||||
export default ({ getService }: FtrProviderContext) => {
|
||||
const ebtServer = getService('kibana_ebt_server');
|
||||
|
@ -42,8 +43,7 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
let defaultPipeline: string;
|
||||
let finalPipeline: string;
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/216044
|
||||
describe.skip('@ess @serverless indices metadata', () => {
|
||||
describe('@ess @serverless indices metadata', () => {
|
||||
beforeEach(async () => {
|
||||
dsName = await randomDatastream(es);
|
||||
await ensureBackingIndices(dsName, NUM_INDICES, es);
|
||||
|
@ -59,7 +59,18 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
dsName,
|
||||
});
|
||||
|
||||
expect(events.length).toEqual(1);
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should include `template` in data stream events when defined', async () => {
|
||||
const events = await launchTaskAndWaitForEvents({
|
||||
eventTypes: [TELEMETRY_DATA_STREAM_EVENT],
|
||||
dsName,
|
||||
});
|
||||
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
const event = events[0] as any;
|
||||
expect(event.template).toBeDefined();
|
||||
});
|
||||
|
||||
it('should publish index stats events', async () => {
|
||||
|
@ -89,13 +100,24 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
await cleanupIngestPipelines(es);
|
||||
});
|
||||
|
||||
it('should include `ilm_policy` in data stream events when defined', async () => {
|
||||
const events = await launchTaskAndWaitForEvents({
|
||||
eventTypes: [TELEMETRY_DATA_STREAM_EVENT],
|
||||
dsName,
|
||||
});
|
||||
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
const event = events[0] as any;
|
||||
expect(event.ilm_policy).toBeDefined();
|
||||
});
|
||||
|
||||
it('should publish ilm policy events', async () => {
|
||||
const events = await launchTaskAndWaitForEvents({
|
||||
eventTypes: [TELEMETRY_ILM_POLICY_EVENT],
|
||||
policyName,
|
||||
});
|
||||
|
||||
expect(events.length).toEqual(1);
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('should publish ilm stats events', async () => {
|
||||
|
@ -205,6 +227,14 @@ export default ({ getService }: FtrProviderContext) => {
|
|||
);
|
||||
expect(events.filter((v) => v.final_pipeline === finalPipeline)).toHaveLength(NUM_INDICES);
|
||||
});
|
||||
|
||||
it('should publish index templates', async () => {
|
||||
const events = await launchTaskAndWaitForEvents({
|
||||
eventTypes: [TELEMETRY_INDEX_TEMPLATES_EVENT],
|
||||
});
|
||||
|
||||
expect(events.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
const indexRandomDocs = async (index: string, count: number) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue