Skip to content

Commit

Permalink
resolve any reference errors that occur on import
Browse files Browse the repository at this point in the history
  • Loading branch information
hop-dev committed Nov 30, 2021
1 parent 208f9e5 commit 8e2e1ee
Showing 1 changed file with 63 additions and 11 deletions.
74 changes: 63 additions & 11 deletions x-pack/plugins/fleet/server/services/epm/kibana/assets/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import type {
SavedObjectsBulkCreateObject,
SavedObjectsClientContract,
} from 'src/core/server';
import type { SavedObjectsImportSuccess } from 'src/core/server/types';
import type { SavedObjectsImportSuccess, SavedObjectsImportFailure } from 'src/core/server/types';

import { createListStream } from '@kbn/utils';
import { partition } from 'lodash';

import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common';
import { getAsset, getPathParts } from '../../archive';
Expand All @@ -22,6 +23,10 @@ import { savedObjectTypes } from '../../packages';
import { indexPatternTypes, getIndexPatternSavedObjects } from '../index_pattern/install';
import { appContextService } from '../../../../services';

const formatImportErrorsForLog = (errors: SavedObjectsImportFailure[]) =>
JSON.stringify(
errors.map(({ type, id, error }) => ({ type, id, error })) // discard other fields
);
const validKibanaAssetTypes = new Set(Object.values(KibanaAssetType));
type SavedObjectToBe = Required<Pick<SavedObjectsBulkCreateObject, keyof ArchiveAsset>> & {
type: KibanaSavedObjectType;
Expand Down Expand Up @@ -168,28 +173,75 @@ async function installKibanaSavedObjects({
kibanaAssets.map((asset) => createSavedObjectKibanaAsset(asset))
);

let allSuccessResults = [];

if (toBeSavedObjects.length === 0) {
return [];
} else {
const savedObjectsImporter = appContextService
.getSavedObjects()
.createImporter(savedObjectsClient);

const { successResults, errors } = await savedObjectsImporter.import({
overwrite: true,
readStream: createListStream(toBeSavedObjects),
createNewCopies: false,
});
const { successResults: importSuccessResults = [], errors: importErrors = [] } =
await savedObjectsImporter.import({
overwrite: true,
readStream: createListStream(toBeSavedObjects),
createNewCopies: false,
});

if (errors?.length) {
allSuccessResults = importSuccessResults;
const [referenceErrors, otherErrors] = partition(
importErrors,
(e) => e?.error?.type === 'missing_references'
);

if (otherErrors?.length) {
throw new Error(
`Encountered ${errors.length} errors creating saved objects: ${JSON.stringify(
errors.map(({ type, id, error }) => ({ type, id, error })) // discard other fields
)}`
`Encountered ${
otherErrors.length
} errors creating saved objects: ${formatImportErrorsForLog(otherErrors)}`
);
}

if (referenceErrors.length) {
const logger = appContextService.getLogger();

logger.debug(
`Resolving ${
referenceErrors.length
} reference errors creating saved objects: ${formatImportErrorsForLog(referenceErrors)}`
);

const idsToResolve = new Set(referenceErrors.map(({ id }) => id));

const resolveSavedObjects = toBeSavedObjects.filter(({ id }) => idsToResolve.has(id));
const retries = referenceErrors.map(({ id, type }) => ({
id,
type,
ignoreMissingReferences: true,
replaceReferences: [],
overwrite: true,
}));

const { successResults: resolveSuccessResults = [], errors: resolveErrors = [] } =
await savedObjectsImporter.resolveImportErrors({
readStream: createListStream(resolveSavedObjects),
createNewCopies: false,
retries,
});

if (resolveErrors?.length) {
throw new Error(
`Encountered ${
resolveErrors.length
} errors resolving reference errors: ${formatImportErrorsForLog(resolveErrors)}`
);
}

allSuccessResults = [...allSuccessResults, ...resolveSuccessResults];
}

return successResults || [];
return allSuccessResults;
}
}

Expand Down

0 comments on commit 8e2e1ee

Please sign in to comment.