Skip to content

Commit

Permalink
[Fleet] add ilm policy per data stream (elastic#85492) (elastic#85865)
Browse files Browse the repository at this point in the history
Co-authored-by: kevinlog <kevin.logan@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: nnamdifrankie <56440728+nnamdifrankie@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 14, 2020
1 parent c5bd996 commit 7fa2e9d
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 1 deletion.
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export enum ElasticsearchAssetType {
indexTemplate = 'index_template',
ilmPolicy = 'ilm_policy',
transform = 'transform',
dataStreamIlmPolicy = 'data_stream_ilm_policy',
}

export type DataType = typeof dataTypes;
Expand Down Expand Up @@ -207,6 +208,7 @@ export type ElasticsearchAssetTypeToParts = Record<

export interface RegistryDataStream {
type: string;
ilm_policy?: string;
hidden?: boolean;
dataset: string;
title: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const AssetTitleMap: Record<AssetType, string> = {
visualization: 'Visualization',
input: 'Agent input',
map: 'Map',
data_stream_ilm_policy: 'Data Stream ILM Policy',
};

export const ServiceTitleMap: Record<Extract<ServiceName, 'kibana'>, string> = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectsClientContract } from 'kibana/server';
import {
ElasticsearchAssetType,
EsAssetReference,
InstallablePackage,
RegistryDataStream,
} from '../../../../../common/types/models';
import { CallESAsCurrentUser } from '../../../../types';
import { getInstallation } from '../../packages';
import { deleteIlmRefs, deleteIlms } from './remove';
import { saveInstalledEsRefs } from '../../packages/install';
import { getAsset } from '../transform/common';

interface IlmInstallation {
installationName: string;
content: string;
}

interface IlmPathDataset {
path: string;
dataStream: RegistryDataStream;
}

export const installIlmForDataStream = async (
registryPackage: InstallablePackage,
paths: string[],
callCluster: CallESAsCurrentUser,
savedObjectsClient: SavedObjectsClientContract
) => {
const installation = await getInstallation({ savedObjectsClient, pkgName: registryPackage.name });
let previousInstalledIlmEsAssets: EsAssetReference[] = [];
if (installation) {
previousInstalledIlmEsAssets = installation.installed_es.filter(
({ type, id }) => type === ElasticsearchAssetType.dataStreamIlmPolicy
);
}

// delete all previous ilm
await deleteIlms(
callCluster,
previousInstalledIlmEsAssets.map((asset) => asset.id)
);
// install the latest dataset
const dataStreams = registryPackage.data_streams;
if (!dataStreams?.length) return [];
const dataStreamIlmPaths = paths.filter((path) => isDataStreamIlm(path));
let installedIlms: EsAssetReference[] = [];
if (dataStreamIlmPaths.length > 0) {
const ilmPathDatasets = dataStreams.reduce<IlmPathDataset[]>((acc, dataStream) => {
dataStreamIlmPaths.forEach((path) => {
if (isDatasetIlm(path, dataStream.path)) {
acc.push({ path, dataStream });
}
});
return acc;
}, []);

const ilmRefs = ilmPathDatasets.reduce<EsAssetReference[]>((acc, ilmPathDataset) => {
if (ilmPathDataset) {
acc.push({
id: getIlmNameForInstallation(ilmPathDataset),
type: ElasticsearchAssetType.dataStreamIlmPolicy,
});
}
return acc;
}, []);

await saveInstalledEsRefs(savedObjectsClient, registryPackage.name, ilmRefs);

const ilmInstallations: IlmInstallation[] = ilmPathDatasets.map(
(ilmPathDataset: IlmPathDataset) => {
return {
installationName: getIlmNameForInstallation(ilmPathDataset),
content: getAsset(ilmPathDataset.path).toString('utf-8'),
};
}
);

const installationPromises = ilmInstallations.map(async (ilmInstallation) => {
return handleIlmInstall({ callCluster, ilmInstallation });
});

installedIlms = await Promise.all(installationPromises).then((results) => results.flat());
}

if (previousInstalledIlmEsAssets.length > 0) {
const currentInstallation = await getInstallation({
savedObjectsClient,
pkgName: registryPackage.name,
});

// remove the saved object reference
await deleteIlmRefs(
savedObjectsClient,
currentInstallation?.installed_es || [],
registryPackage.name,
previousInstalledIlmEsAssets.map((asset) => asset.id),
installedIlms.map((installed) => installed.id)
);
}
return installedIlms;
};

async function handleIlmInstall({
callCluster,
ilmInstallation,
}: {
callCluster: CallESAsCurrentUser;
ilmInstallation: IlmInstallation;
}): Promise<EsAssetReference> {
await callCluster('transport.request', {
method: 'PUT',
path: `/_ilm/policy/${ilmInstallation.installationName}`,
body: ilmInstallation.content,
});

return { id: ilmInstallation.installationName, type: ElasticsearchAssetType.dataStreamIlmPolicy };
}

const isDataStreamIlm = (path: string) => {
return new RegExp('(?<package>.*)/data_stream/(?<dataset>.*)/elasticsearch/ilm/*.*').test(path);
};

const isDatasetIlm = (path: string, datasetName: string) => {
return new RegExp(`(?<package>.*)/data_stream\\/${datasetName}/elasticsearch/ilm/*.*`).test(path);
};

const getIlmNameForInstallation = (ilmPathDataset: IlmPathDataset) => {
const filename = ilmPathDataset?.path.split('/')?.pop()?.split('.')[0];
return `${ilmPathDataset.dataStream.type}-${ilmPathDataset.dataStream.package}.${ilmPathDataset.dataStream.path}-${filename}`;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectsClientContract } from 'kibana/server';
import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types';
import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants';

export const deleteIlms = async (callCluster: CallESAsCurrentUser, ilmPolicyIds: string[]) => {
await Promise.all(
ilmPolicyIds.map(async (ilmPolicyId) => {
await callCluster('transport.request', {
method: 'DELETE',
path: `_ilm/policy/${ilmPolicyId}`,
ignore: [404, 400],
});
})
);
};

export const deleteIlmRefs = async (
savedObjectsClient: SavedObjectsClientContract,
installedEsAssets: EsAssetReference[],
pkgName: string,
installedEsIdToRemove: string[],
currentInstalledEsIlmIds: string[]
) => {
const seen = new Set<string>();
const filteredAssets = installedEsAssets.filter(({ type, id }) => {
if (type !== ElasticsearchAssetType.dataStreamIlmPolicy) return true;
const add =
(currentInstalledEsIlmIds.includes(id) || !installedEsIdToRemove.includes(id)) &&
!seen.has(id);
seen.add(id);
return add;
});
return savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, {
installed_es: filteredAssets,
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ export async function installTemplate({
pipelineName,
packageName,
composedOfTemplates,
ilmPolicy: dataStream.ilm_policy,
hidden: dataStream.hidden,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function getTemplate({
pipelineName,
packageName,
composedOfTemplates,
ilmPolicy,
hidden,
}: {
type: string;
Expand All @@ -53,6 +54,7 @@ export function getTemplate({
pipelineName?: string | undefined;
packageName: string;
composedOfTemplates: string[];
ilmPolicy?: string | undefined;
hidden?: boolean;
}): IndexTemplate {
const template = getBaseTemplate(
Expand All @@ -61,6 +63,7 @@ export function getTemplate({
mappings,
packageName,
composedOfTemplates,
ilmPolicy,
hidden
);
if (pipelineName) {
Expand Down Expand Up @@ -263,6 +266,7 @@ function getBaseTemplate(
mappings: IndexTemplateMappings,
packageName: string,
composedOfTemplates: string[],
ilmPolicy?: string | undefined,
hidden?: boolean
): IndexTemplate {
// Meta information to identify Ingest Manager's managed templates and indices
Expand All @@ -287,7 +291,7 @@ function getBaseTemplate(
index: {
// ILM Policy must be added here, for now point to the default global ILM policy name
lifecycle: {
name: type,
name: ilmPolicy ? ilmPolicy : type,
},
// What should be our default for the compression?
codec: 'best_compression',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { updateCurrentWriteIndices } from '../elasticsearch/template/template';
import { deleteKibanaSavedObjectsAssets } from './remove';
import { installTransform } from '../elasticsearch/transform/install';
import { createInstallation, saveKibanaAssetsRefs, updateVersion } from './install';
import { installIlmForDataStream } from '../elasticsearch/datastream_ilm/install';
import { saveArchiveEntries } from '../archive/storage';
import { ConcurrentInstallOperationError } from '../../../errors';

Expand Down Expand Up @@ -134,6 +135,13 @@ export async function _installPackage({
// per data stream and we should then save them
await installILMPolicy(paths, callCluster);

const installedDataStreamIlm = await installIlmForDataStream(
packageInfo,
paths,
callCluster,
savedObjectsClient
);

// installs versionized pipelines without removing currently installed ones
const installedPipelines = await installPipelines(
packageInfo,
Expand Down Expand Up @@ -212,6 +220,7 @@ export async function _installPackage({
return [
...installedKibanaAssetsRefs,
...installedPipelines,
...installedDataStreamIlm,
...installedTemplateRefs,
...installedTransforms,
];
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/fleet/server/services/epm/packages/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { deleteTransforms } from '../elasticsearch/transform/remove';
import { packagePolicyService, appContextService } from '../..';
import { splitPkgKey } from '../registry';
import { deletePackageCache } from '../archive';
import { deleteIlms } from '../elasticsearch/datastream_ilm/remove';
import { removeArchiveEntries } from '../archive/storage';

export async function removeInstallation(options: {
Expand Down Expand Up @@ -93,6 +94,8 @@ function deleteESAssets(installedObjects: EsAssetReference[], callCluster: CallE
return deleteTemplate(callCluster, id);
} else if (assetType === ElasticsearchAssetType.transform) {
return deleteTransforms(callCluster, [id]);
} else if (assetType === ElasticsearchAssetType.dataStreamIlmPolicy) {
return deleteIlms(callCluster, [id]);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,14 @@ const expectAssetsInstalled = ({
},
],
installed_es: [
{
id: 'logs-all_assets.test_logs-all_assets',
type: 'data_stream_ilm_policy',
},
{
id: 'metrics-all_assets.test_metrics-all_assets',
type: 'data_stream_ilm_policy',
},
{
id: 'logs-all_assets.test_logs',
type: 'index_template',
Expand Down Expand Up @@ -496,6 +504,7 @@ const expectAssetsInstalled = ({
{ id: '96c6eb85-fe2e-56c6-84be-5fda976796db', type: 'epm-packages-assets' },
{ id: '2d73a161-fa69-52d0-aa09-1bdc691b95bb', type: 'epm-packages-assets' },
{ id: '0a00c2d2-ce63-5b9c-9aa0-0cf1938f7362', type: 'epm-packages-assets' },
{ id: '691f0505-18c5-57a6-9f40-06e8affbdf7a', type: 'epm-packages-assets' },
{ id: 'b36e6dd0-58f7-5dd0-a286-8187e4019274', type: 'epm-packages-assets' },
{ id: 'f839c76e-d194-555a-90a1-3265a45789e4', type: 'epm-packages-assets' },
{ id: '9af7bbb3-7d8a-50fa-acc9-9dde6f5efca2', type: 'epm-packages-assets' },
Expand Down
4 changes: 4 additions & 0 deletions x-pack/test/fleet_api_integration/apis/epm/update_assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,10 @@ export default function (providerContext: FtrProviderContext) {
},
],
installed_es: [
{
id: 'logs-all_assets.test_logs-all_assets',
type: 'data_stream_ilm_policy',
},
{
id: 'logs-all_assets.test_logs-0.2.0',
type: 'ingest_pipeline',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50gb",
"max_age": "30d"
}
}
}
}
}
}

0 comments on commit 7fa2e9d

Please sign in to comment.