Skip to content

Commit

Permalink
Revert "[Fleet] Allow snake cased Kibana assets (#77515)"
Browse files Browse the repository at this point in the history
This reverts commit 1cd477a.
  • Loading branch information
Corey Robertson committed Nov 5, 2020
1 parent db8f98c commit 488f074
Show file tree
Hide file tree
Showing 16 changed files with 48 additions and 219 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Ingest Manager - packageToPackagePolicy', () => {
dashboard: [],
visualization: [],
search: [],
index_pattern: [],
'index-pattern': [],
map: [],
},
},
Expand Down
16 changes: 1 addition & 15 deletions x-pack/plugins/ingest_manager/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,7 @@ export type ServiceName = 'kibana' | 'elasticsearch';
export type AgentAssetType = typeof agentAssetTypes;
export type AssetType = KibanaAssetType | ElasticsearchAssetType | ValueOf<AgentAssetType>;

/*
Enum mapping of a saved object asset type to how it would appear in a package file path (snake cased)
*/
export enum KibanaAssetType {
dashboard = 'dashboard',
visualization = 'visualization',
search = 'search',
indexPattern = 'index_pattern',
map = 'map',
}

/*
Enum of saved object types that are allowed to be installed
*/
export enum KibanaSavedObjectType {
dashboard = 'dashboard',
visualization = 'visualization',
search = 'search',
Expand Down Expand Up @@ -285,7 +271,7 @@ export type NotInstalled<T = {}> = T & {
export type AssetReference = KibanaAssetReference | EsAssetReference;

export type KibanaAssetReference = Pick<SavedObjectReference, 'id'> & {
type: KibanaSavedObjectType;
type: KibanaAssetType;
};
export type EsAssetReference = Pick<SavedObjectReference, 'id'> & {
type: ElasticsearchAssetType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const AssetTitleMap: Record<AssetType, string> = {
ilm_policy: 'ILM Policy',
ingest_pipeline: 'Ingest Pipeline',
transform: 'Transform',
index_pattern: 'Index Pattern',
'index-pattern': 'Index Pattern',
index_template: 'Index Template',
component_template: 'Component Template',
search: 'Saved Search',
Expand All @@ -36,7 +36,7 @@ export const ServiceTitleMap: Record<ServiceName, string> = {

export const AssetIcons: Record<KibanaAssetType, IconType> = {
dashboard: 'dashboardApp',
index_pattern: 'indexPatternApp',
'index-pattern': 'indexPatternApp',
search: 'searchProfilerApp',
visualization: 'visualizeApp',
map: 'mapApp',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/
import { RequestHandler, SavedObjectsClientContract } from 'src/core/server';
import { DataStream } from '../../types';
import { GetDataStreamsResponse, KibanaAssetType, KibanaSavedObjectType } from '../../../common';
import { GetDataStreamsResponse, KibanaAssetType } from '../../../common';
import { getPackageSavedObjects, getKibanaSavedObject } from '../../services/epm/packages/get';
import { defaultIngestErrorHandler } from '../../errors';

Expand Down Expand Up @@ -124,7 +124,7 @@ export const getListHandler: RequestHandler = async (context, request, response)
// then pick the dashboards from the package saved object
const dashboards =
pkgSavedObject[0].attributes?.installed_kibana?.filter(
(o) => o.type === KibanaSavedObjectType.dashboard
(o) => o.type === KibanaAssetType.dashboard
) || [];
// and then pick the human-readable titles from the dashboard saved objects
const enhancedDashboards = await getEnhancedDashboards(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,49 +11,17 @@ import {
} from 'src/core/server';
import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common';
import * as Registry from '../../registry';
import {
AssetType,
KibanaAssetType,
AssetReference,
AssetParts,
KibanaSavedObjectType,
} from '../../../../types';
import { AssetType, KibanaAssetType, AssetReference } from '../../../../types';
import { savedObjectTypes } from '../../packages';
import { indexPatternTypes } from '../index_pattern/install';

type SavedObjectToBe = Required<Pick<SavedObjectsBulkCreateObject, keyof ArchiveAsset>> & {
type: KibanaSavedObjectType;
type: AssetType;
};
export type ArchiveAsset = Pick<
SavedObject,
'id' | 'attributes' | 'migrationVersion' | 'references'
> & {
type: KibanaSavedObjectType;
};

// KibanaSavedObjectTypes are used to ensure saved objects being created for a given
// KibanaAssetType have the correct type
const KibanaSavedObjectTypeMapping: Record<KibanaAssetType, KibanaSavedObjectType> = {
[KibanaAssetType.dashboard]: KibanaSavedObjectType.dashboard,
[KibanaAssetType.indexPattern]: KibanaSavedObjectType.indexPattern,
[KibanaAssetType.map]: KibanaSavedObjectType.map,
[KibanaAssetType.search]: KibanaSavedObjectType.search,
[KibanaAssetType.visualization]: KibanaSavedObjectType.visualization,
};

// Define how each asset type will be installed
const AssetInstallers: Record<
KibanaAssetType,
(args: {
savedObjectsClient: SavedObjectsClientContract;
kibanaAssets: ArchiveAsset[];
}) => Promise<Array<SavedObject<unknown>>>
> = {
[KibanaAssetType.dashboard]: installKibanaSavedObjects,
[KibanaAssetType.indexPattern]: installKibanaIndexPatterns,
[KibanaAssetType.map]: installKibanaSavedObjects,
[KibanaAssetType.search]: installKibanaSavedObjects,
[KibanaAssetType.visualization]: installKibanaSavedObjects,
type: AssetType;
};

export async function getKibanaAsset(key: string): Promise<ArchiveAsset> {
Expand All @@ -79,22 +47,16 @@ export function createSavedObjectKibanaAsset(asset: ArchiveAsset): SavedObjectTo
export async function installKibanaAssets(options: {
savedObjectsClient: SavedObjectsClientContract;
pkgName: string;
kibanaAssets: Record<KibanaAssetType, ArchiveAsset[]>;
kibanaAssets: ArchiveAsset[];
}): Promise<SavedObject[]> {
const { savedObjectsClient, kibanaAssets } = options;

// install the assets
const kibanaAssetTypes = Object.values(KibanaAssetType);
const installedAssets = await Promise.all(
kibanaAssetTypes.map((assetType) => {
if (kibanaAssets[assetType]) {
return AssetInstallers[assetType]({
savedObjectsClient,
kibanaAssets: kibanaAssets[assetType],
});
}
return [];
})
kibanaAssetTypes.map((assetType) =>
installKibanaSavedObjects({ savedObjectsClient, assetType, kibanaAssets })
)
);
return installedAssets.flat();
}
Expand All @@ -112,50 +74,25 @@ export const deleteKibanaInstalledRefs = async (
installed_kibana: installedAssetsToSave,
});
};
export async function getKibanaAssets(
paths: string[]
): Promise<Record<KibanaAssetType, ArchiveAsset[]>> {
const kibanaAssetTypes = Object.values(KibanaAssetType);
const isKibanaAssetType = (path: string) => {
const parts = Registry.pathParts(path);

return parts.service === 'kibana' && (kibanaAssetTypes as string[]).includes(parts.type);
};

const filteredPaths = paths
.filter(isKibanaAssetType)
.map<[string, AssetParts]>((path) => [path, Registry.pathParts(path)]);

const assetArrays: Array<Promise<ArchiveAsset[]>> = [];
for (const assetType of kibanaAssetTypes) {
const matching = filteredPaths.filter(([path, parts]) => parts.type === assetType);

assetArrays.push(Promise.all(matching.map(([path]) => path).map(getKibanaAsset)));
}

const resolvedAssets = await Promise.all(assetArrays);

const result = {} as Record<KibanaAssetType, ArchiveAsset[]>;

for (const [index, assetType] of kibanaAssetTypes.entries()) {
const expectedType = KibanaSavedObjectTypeMapping[assetType];
const properlyTypedAssets = resolvedAssets[index].filter(({ type }) => type === expectedType);

result[assetType] = properlyTypedAssets;
}

return result;
export async function getKibanaAssets(paths: string[]) {
const isKibanaAssetType = (path: string) => Registry.pathParts(path).type in KibanaAssetType;
const filteredPaths = paths.filter(isKibanaAssetType);
const kibanaAssets = await Promise.all(filteredPaths.map((path) => getKibanaAsset(path)));
return kibanaAssets;
}

async function installKibanaSavedObjects({
savedObjectsClient,
assetType,
kibanaAssets,
}: {
savedObjectsClient: SavedObjectsClientContract;
assetType: KibanaAssetType;
kibanaAssets: ArchiveAsset[];
}) {
const isSameType = (asset: ArchiveAsset) => assetType === asset.type;
const filteredKibanaAssets = kibanaAssets.filter((asset) => isSameType(asset));
const toBeSavedObjects = await Promise.all(
kibanaAssets.map((asset) => createSavedObjectKibanaAsset(asset))
filteredKibanaAssets.map((asset) => createSavedObjectKibanaAsset(asset))
);

if (toBeSavedObjects.length === 0) {
Expand All @@ -168,23 +105,8 @@ async function installKibanaSavedObjects({
}
}

async function installKibanaIndexPatterns({
savedObjectsClient,
kibanaAssets,
}: {
savedObjectsClient: SavedObjectsClientContract;
kibanaAssets: ArchiveAsset[];
}) {
// Filter out any reserved index patterns
const reservedPatterns = indexPatternTypes.map((pattern) => `${pattern}-*`);

const nonReservedPatterns = kibanaAssets.filter((asset) => !reservedPatterns.includes(asset.id));

return installKibanaSavedObjects({ savedObjectsClient, kibanaAssets: nonReservedPatterns });
}

export function toAssetReference({ id, type }: SavedObject) {
const reference: AssetReference = { id, type: type as KibanaSavedObjectType };
const reference: AssetReference = { id, type: type as KibanaAssetType };

return reference;
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export interface IndexPatternField {
readFromDocValues: boolean;
}

export const indexPatternTypes = Object.values(dataTypes);
// TODO: use a function overload and make pkgName and pkgVersion required for install/update
// and not for an update removal. or separate out the functions
export async function installIndexPatterns(
Expand Down Expand Up @@ -117,6 +116,7 @@ export async function installIndexPatterns(
const packageVersionsInfo = await Promise.all(packageVersionsFetchInfoPromise);

// for each index pattern type, create an index pattern
const indexPatternTypes = Object.values(dataTypes);
indexPatternTypes.forEach(async (indexPatternType) => {
// if this is an update because a package is being uninstalled (no pkgkey argument passed) and no other packages are installed, remove the index pattern
if (!pkgName && installedPackages.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types';
import { ElasticsearchAssetType, Installation, KibanaAssetType } from '../../../types';
import { SavedObject, SavedObjectsClientContract } from 'src/core/server';

jest.mock('./install');
Expand Down Expand Up @@ -41,7 +41,7 @@ const mockInstallation: SavedObject<Installation> = {
type: 'epm-packages',
attributes: {
id: 'test-pkg',
installed_kibana: [{ type: KibanaSavedObjectType.dashboard, id: 'dashboard-1' }],
installed_kibana: [{ type: KibanaAssetType.dashboard, id: 'dashboard-1' }],
installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }],
es_index_patterns: { pattern: 'pattern-name' },
name: 'test package',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { SavedObject } from 'src/core/server';
import { ElasticsearchAssetType, Installation, KibanaSavedObjectType } from '../../../types';
import { ElasticsearchAssetType, Installation, KibanaAssetType } from '../../../types';
import { getInstallType } from './install';

const mockInstallation: SavedObject<Installation> = {
Expand All @@ -13,7 +13,7 @@ const mockInstallation: SavedObject<Installation> = {
type: 'epm-packages',
attributes: {
id: 'test-pkg',
installed_kibana: [{ type: KibanaSavedObjectType.dashboard, id: 'dashboard-1' }],
installed_kibana: [{ type: KibanaAssetType.dashboard, id: 'dashboard-1' }],
installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }],
es_index_patterns: { pattern: 'pattern-name' },
name: 'test packagek',
Expand All @@ -30,7 +30,7 @@ const mockInstallationUpdateFail: SavedObject<Installation> = {
type: 'epm-packages',
attributes: {
id: 'test-pkg',
installed_kibana: [{ type: KibanaSavedObjectType.dashboard, id: 'dashboard-1' }],
installed_kibana: [{ type: KibanaAssetType.dashboard, id: 'dashboard-1' }],
installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }],
es_index_patterns: { pattern: 'pattern-name' },
name: 'test packagek',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import {
KibanaAssetReference,
EsAssetReference,
InstallType,
KibanaAssetType,
} from '../../../types';
import * as Registry from '../registry';
import {
Expand Down Expand Up @@ -365,9 +364,9 @@ export async function createInstallation(options: {
export const saveKibanaAssetsRefs = async (
savedObjectsClient: SavedObjectsClientContract,
pkgName: string,
kibanaAssets: Record<KibanaAssetType, ArchiveAsset[]>
kibanaAssets: ArchiveAsset[]
) => {
const assetRefs = Object.values(kibanaAssets).flat().map(toAssetReference);
const assetRefs = kibanaAssets.map(toAssetReference);
await savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, {
installed_kibana: assetRefs,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ import {
AssetType,
CallESAsCurrentUser,
ElasticsearchAssetType,
EsAssetReference,
KibanaAssetReference,
Installation,
} from '../../../types';
import { getInstallation, savedObjectTypes } from './index';
import { deletePipeline } from '../elasticsearch/ingest_pipeline/';
Expand Down Expand Up @@ -49,7 +46,7 @@ export async function removeInstallation(options: {

// Delete the installed assets
const installedAssets = [...installation.installed_kibana, ...installation.installed_es];
await deleteAssets(installation, savedObjectsClient, callCluster);
await deleteAssets(installedAssets, savedObjectsClient, callCluster);

// Delete the manager saved object with references to the asset objects
// could also update with [] or some other state
Expand All @@ -67,43 +64,26 @@ export async function removeInstallation(options: {
// successful delete's in SO client return {}. return something more useful
return installedAssets;
}

function deleteKibanaAssets(
installedObjects: KibanaAssetReference[],
savedObjectsClient: SavedObjectsClientContract
async function deleteAssets(
installedObjects: AssetReference[],
savedObjectsClient: SavedObjectsClientContract,
callCluster: CallESAsCurrentUser
) {
return installedObjects.map(async ({ id, type }) => {
return savedObjectsClient.delete(type, id);
});
}

function deleteESAssets(installedObjects: EsAssetReference[], callCluster: CallESAsCurrentUser) {
return installedObjects.map(async ({ id, type }) => {
const logger = appContextService.getLogger();
const deletePromises = installedObjects.map(async ({ id, type }) => {
const assetType = type as AssetType;
if (assetType === ElasticsearchAssetType.ingestPipeline) {
if (savedObjectTypes.includes(assetType)) {
return savedObjectsClient.delete(assetType, id);
} else if (assetType === ElasticsearchAssetType.ingestPipeline) {
return deletePipeline(callCluster, id);
} else if (assetType === ElasticsearchAssetType.indexTemplate) {
return deleteTemplate(callCluster, id);
} else if (assetType === ElasticsearchAssetType.transform) {
return deleteTransforms(callCluster, [id]);
}
});
}

async function deleteAssets(
{ installed_es: installedEs, installed_kibana: installedKibana }: Installation,
savedObjectsClient: SavedObjectsClientContract,
callCluster: CallESAsCurrentUser
) {
const logger = appContextService.getLogger();

const deletePromises: Array<Promise<unknown>> = [
...deleteESAssets(installedEs, callCluster),
...deleteKibanaAssets(installedKibana, savedObjectsClient),
];

try {
await Promise.all(deletePromises);
await Promise.all([...deletePromises]);
} catch (err) {
logger.error(err);
}
Expand Down
Loading

0 comments on commit 488f074

Please sign in to comment.