[Fleet] Improve error status code for package (#93696)

This commit is contained in:
Nicolas Chaulet 2021-03-05 13:50:14 -05:00 committed by GitHub
parent 14069d5c2c
commit 02be8c16c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 69 deletions

View file

@ -21,8 +21,13 @@ export class IngestManagerError extends Error {
}
export class RegistryError extends IngestManagerError {}
export class RegistryConnectionError extends RegistryError {}
export class RegistryResponseError extends RegistryError {}
export class RegistryResponseError extends RegistryError {
constructor(message?: string, public readonly status?: number) {
super(message);
}
}
export class PackageNotFoundError extends IngestManagerError {}
export class PackageKeyInvalidError extends IngestManagerError {}
export class PackageOutdatedError extends IngestManagerError {}
export class AgentPolicyError extends IngestManagerError {}
export class AgentPolicyNameExistsError extends AgentPolicyError {}

View file

@ -30,7 +30,12 @@ import {
} from '../archive';
import { streamToBuffer } from '../streams';
import { appContextService } from '../..';
import { PackageNotFoundError, PackageCacheError } from '../../../errors';
import {
PackageKeyInvalidError,
PackageNotFoundError,
PackageCacheError,
RegistryResponseError,
} from '../../../errors';
import { fetchUrl, getResponse, getResponseStream } from './requests';
import { getRegistryUrl } from './registry_url';
@ -53,13 +58,15 @@ export function splitPkgKey(pkgkey: string): { pkgName: string; pkgVersion: stri
// this will return an empty string if `indexOf` returns -1
const pkgName = pkgkey.substr(0, pkgkey.indexOf('-'));
if (pkgName === '') {
throw new Error('Package key parsing failed: package name was empty');
throw new PackageKeyInvalidError('Package key parsing failed: package name was empty');
}
// this will return the entire string if `indexOf` return -1
const pkgVersion = pkgkey.substr(pkgkey.indexOf('-') + 1);
if (!semverValid(pkgVersion)) {
throw new Error('Package key parsing failed: package version was not a valid semver');
throw new PackageKeyInvalidError(
'Package key parsing failed: package version was not a valid semver'
);
}
return { pkgName, pkgVersion };
}
@ -112,7 +119,16 @@ export async function fetchFindLatestPackage(packageName: string): Promise<Regis
export async function fetchInfo(pkgName: string, pkgVersion: string): Promise<RegistryPackage> {
const registryUrl = getRegistryUrl();
return fetchUrl(`${registryUrl}/package/${pkgName}/${pkgVersion}`).then(JSON.parse);
try {
const res = await fetchUrl(`${registryUrl}/package/${pkgName}/${pkgVersion}`).then(JSON.parse);
return res;
} catch (err) {
if (err instanceof RegistryResponseError && err.status === 404) {
throw new PackageNotFoundError(`${pkgName}@${pkgVersion} not found`);
}
throw err;
}
}
export async function getFile(

View file

@ -109,6 +109,7 @@ describe('setupIngestManager', () => {
await expect(promise).rejects.toThrow(
`'404 Not Found' error response from package registry at https://example.com`
);
await expect(promise).rejects.toMatchObject({ status: 404 });
expect(fetchMock).toHaveBeenCalledTimes(1);
});
@ -124,6 +125,7 @@ describe('setupIngestManager', () => {
await expect(promise).rejects.toThrow(
`'429 Too Many Requests' error response from package registry at https://example.com`
);
await expect(promise).rejects.toMatchObject({ status: 429 });
expect(fetchMock).toHaveBeenCalledTimes(1);
});
@ -139,6 +141,7 @@ describe('setupIngestManager', () => {
await expect(promise).rejects.toThrow(
`'500 Internal Server Error' error response from package registry at https://example.com`
);
await expect(promise).rejects.toMatchObject({ status: 500 });
expect(fetchMock).toHaveBeenCalledTimes(1);
});
});

View file

@ -28,7 +28,7 @@ async function registryFetch(url: string) {
const message = `'${status} ${statusText}' error response from package registry at ${
resUrl || url
}`;
const responseError = new RegistryResponseError(message);
const responseError = new RegistryResponseError(message, status);
throw new pRetry.AbortError(responseError);
}

View file

@ -9,14 +9,12 @@ import expect from '@kbn/expect';
import fs from 'fs';
import path from 'path';
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
import { warnAndSkipTest } from '../../helpers';
import { skipIfNoDockerRegistry } from '../../helpers';
export default function (providerContext: FtrProviderContext) {
const { getService } = providerContext;
const log = getService('log');
const supertest = getService('supertest');
const dockerServers = getService('dockerServers');
const server = dockerServers.get('registry');
const testPkgKey = 'apache-0.1.4';
@ -36,75 +34,60 @@ export default function (providerContext: FtrProviderContext) {
);
describe('EPM - get', () => {
skipIfNoDockerRegistry(providerContext);
it('returns package info from the registry if it was installed from the registry', async function () {
if (server.enabled) {
// this will install through the registry by default
await installPackage(testPkgKey);
const res = await supertest.get(`/api/fleet/epm/packages/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.not.equal('Apache Uploaded Test Integration');
// download property should exist
expect(packageInfo.download).to.not.equal(undefined);
await uninstallPackage(testPkgKey);
} else {
warnAndSkipTest(this, log);
}
// this will install through the registry by default
await installPackage(testPkgKey);
const res = await supertest.get(`/api/fleet/epm/packages/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.not.equal('Apache Uploaded Test Integration');
// download property should exist
expect(packageInfo.download).to.not.equal(undefined);
await uninstallPackage(testPkgKey);
});
it('returns correct package info if it was installed by upload', async function () {
if (server.enabled) {
const buf = fs.readFileSync(testPkgArchiveZip);
await supertest
.post(`/api/fleet/epm/packages`)
.set('kbn-xsrf', 'xxxx')
.type('application/zip')
.send(buf)
.expect(200);
const buf = fs.readFileSync(testPkgArchiveZip);
await supertest
.post(`/api/fleet/epm/packages`)
.set('kbn-xsrf', 'xxxx')
.type('application/zip')
.send(buf)
.expect(200);
const res = await supertest.get(`/api/fleet/epm/packages/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.equal('Apache Uploaded Test Integration');
// download property should not exist on uploaded packages
expect(packageInfo.download).to.equal(undefined);
await uninstallPackage(testPkgKey);
} else {
warnAndSkipTest(this, log);
}
const res = await supertest.get(`/api/fleet/epm/packages/${testPkgKey}`).expect(200);
const packageInfo = res.body.response;
// the uploaded version will have this description
expect(packageInfo.description).to.equal('Apache Uploaded Test Integration');
// download property should not exist on uploaded packages
expect(packageInfo.download).to.equal(undefined);
await uninstallPackage(testPkgKey);
});
it('returns correct package info from registry if a different version is installed by upload', async function () {
if (server.enabled) {
const buf = fs.readFileSync(testPkgArchiveZip);
await supertest
.post(`/api/fleet/epm/packages`)
.set('kbn-xsrf', 'xxxx')
.type('application/zip')
.send(buf)
.expect(200);
const buf = fs.readFileSync(testPkgArchiveZip);
await supertest
.post(`/api/fleet/epm/packages`)
.set('kbn-xsrf', 'xxxx')
.type('application/zip')
.send(buf)
.expect(200);
const res = await supertest.get(`/api/fleet/epm/packages/apache-0.1.3`).expect(200);
const packageInfo = res.body.response;
expect(packageInfo.description).to.equal('Apache Integration');
expect(packageInfo.download).to.not.equal(undefined);
await uninstallPackage(testPkgKey);
} else {
warnAndSkipTest(this, log);
}
const res = await supertest.get(`/api/fleet/epm/packages/apache-0.1.3`).expect(200);
const packageInfo = res.body.response;
expect(packageInfo.description).to.equal('Apache Integration');
expect(packageInfo.download).to.not.equal(undefined);
await uninstallPackage(testPkgKey);
});
it('returns a 500 for a package key without a proper name', async function () {
if (server.enabled) {
await supertest.get('/api/fleet/epm/packages/-0.1.0').expect(500);
} else {
warnAndSkipTest(this, log);
}
it('returns a 400 for a package key without a proper name', async function () {
await supertest.get('/api/fleet/epm/packages/-0.1.0').expect(400);
});
it('returns a 500 for a package key without a proper semver version', async function () {
if (server.enabled) {
await supertest.get('/api/fleet/epm/packages/endpoint-0.1.0.1.2.3').expect(500);
} else {
warnAndSkipTest(this, log);
}
it('returns a 404 for a package that do not exists', async function () {
await supertest.get('/api/fleet/epm/packages/notexists-99.99.99').expect(404);
});
it('returns a 400 for a package key without a proper semver version', async function () {
await supertest.get('/api/fleet/epm/packages/endpoint-0.1.0.1.2.3').expect(400);
});
});
}