[Fleet][EPM] - Do cache || saved_object || network in http handler (#85331)

## Summary

1. cf0d567 - Export function which maps file path to saved object id
2. e33d7d4 - "make it work" ™️ quality version of "use cached or saved object or registry" file in HTTP handler. It's doing too much and should eventually move the logic to service method(s).
This commit is contained in:
John Schulz 2020-12-10 11:23:03 -05:00 committed by GitHub
parent 4778365fc8
commit 00c2e960b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 24 deletions

View file

@ -17,6 +17,7 @@ import {
BulkInstallPackageInfo,
BulkInstallPackagesResponse,
IBulkInstallPackageHTTPError,
ASSETS_SAVED_OBJECT_TYPE,
} from '../../../common';
import {
GetCategoriesRequestSchema,
@ -41,12 +42,13 @@ import {
removeInstallation,
getLimitedPackages,
getInstallationObject,
getInstallation,
} from '../../services/epm/packages';
import { defaultIngestErrorHandler, ingestErrorToResponseOptions } from '../../errors';
import { splitPkgKey } from '../../services/epm/registry';
import { licenseService } from '../../services';
import { getArchiveEntry } from '../../services/epm/archive/cache';
import { bufferToStream } from '../../services/epm/streams';
import { PackageAsset, assetPathToObjectId } from '../../services/epm/archive/save_to_es';
export const getCategoriesHandler: RequestHandler<
undefined,
@ -107,32 +109,46 @@ export const getFileHandler: RequestHandler<TypeOf<typeof GetFileRequestSchema.p
try {
const { pkgName, pkgVersion, filePath } = request.params;
const savedObjectsClient = context.core.savedObjects.client;
const savedObject = await getInstallationObject({ savedObjectsClient, pkgName });
const pkgInstallSource = savedObject?.attributes.install_source;
// TODO: when package storage is available, remove installSource check and check cache and storage, remove registry call
if (pkgInstallSource === 'upload' && pkgVersion === savedObject?.attributes.version) {
const headerContentType = mime.contentType(path.extname(filePath));
const installation = await getInstallation({ savedObjectsClient, pkgName });
const useLocalFile = pkgVersion === installation?.version;
if (useLocalFile) {
const archiveKey = `${pkgName}-${pkgVersion}/${filePath}`;
const archiveEntry = getArchiveEntry(archiveKey);
const assetSavedObject = await savedObjectsClient.get<PackageAsset>(
ASSETS_SAVED_OBJECT_TYPE,
assetPathToObjectId(archiveKey)
);
if (!archiveEntry && !assetSavedObject) {
return response.custom({
body: `installed package file not found: ${filePath}`,
statusCode: 404,
});
}
const headerContentType =
assetSavedObject.attributes.media_type || mime.contentType(path.extname(archiveKey));
if (!headerContentType) {
return response.custom({
body: `unknown content type for file: ${filePath}`,
statusCode: 400,
});
}
const archiveFile = getArchiveEntry(`${pkgName}-${pkgVersion}/${filePath}`);
if (!archiveFile) {
return response.custom({
body: `uploaded package file not found: ${filePath}`,
statusCode: 404,
});
}
const headers: ResponseHeaders = {
'cache-control': 'max-age=10, public',
'content-type': headerContentType,
};
const { data_base64: base64, data_utf8: utf8 } = assetSavedObject.attributes;
// if we have a local Buffer, use that
// else, create one from the saved object (try utf8 first)
const responseBody =
archiveEntry || utf8 ? Buffer.from(utf8, 'utf8') : Buffer.from(base64, 'base64');
return response.custom({
body: bufferToStream(archiveFile),
body: responseBody,
statusCode: 200,
headers,
headers: {
'cache-control': 'max-age=10, public',
'content-type': headerContentType,
},
});
} else {
const registryResponse = await getFile(`/package/${pkgName}/${pkgVersion}/${filePath}`);

View file

@ -17,10 +17,6 @@ import {
} from '../../../../common';
import { getArchiveEntry } from './index';
// uuid v5 requires a SHA-1 UUID as a namespace
// used to ensure same input produces the same id
const ID_NAMESPACE = '71403015-cdd5-404b-a5da-6c43f35cad84';
// could be anything, picked this from https://github.com/elastic/elastic-agent-client/issues/17
const MAX_ES_ASSET_BYTES = 4 * 1024 * 1024;
@ -34,6 +30,12 @@ export interface PackageAsset {
data_base64: string;
}
export function assetPathToObjectId(assetPath: string): string {
// uuid v5 requires a SHA-1 UUID as a namespace
// used to ensure same input produces the same id
return uuidv5(assetPath, '71403015-cdd5-404b-a5da-6c43f35cad84');
}
export async function archiveEntryToESDocument(opts: {
path: string;
buffer: Buffer;
@ -114,7 +116,7 @@ export async function archiveEntryToBulkCreateObject(opts: {
const { path, buffer, name, version, installSource } = opts;
const doc = await archiveEntryToESDocument({ path, buffer, name, version, installSource });
return {
id: uuidv5(doc.asset_path, ID_NAMESPACE),
id: assetPathToObjectId(doc.asset_path),
type: ASSETS_SAVED_OBJECT_TYPE,
attributes: doc,
};