[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:
parent
4778365fc8
commit
00c2e960b6
|
@ -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}`);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue