[Fleet] Support registry filtering with spec.min and spec.max (#166733)

This commit is contained in:
Nicolas Chaulet 2023-09-20 10:59:19 -04:00 committed by GitHub
parent 82306ea110
commit e02c8740ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 165 additions and 28 deletions

View file

@ -27,7 +27,11 @@ xpack.fleet.agentIdVerificationEnabled: false
xpack.apm.serverlessOnboarding: true
# Fleet specific configuration
xpack.fleet.internal.capabilities: ['apm', 'observability']
xpack.fleet.internal.registry.capabilities: ['apm', 'observability']
xpack.fleet.internal.registry.spec.max: '3.0'
# Disabled until packages implement the new spec https://github.com/elastic/kibana/issues/166742
# xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false
# xpack.fleet.internal.registry.spec.min: '3.0'
## Required for force installation of APM Package
xpack.fleet.packages:

View file

@ -26,7 +26,11 @@ xpack.serverless.plugin.developer.projectSwitcher.currentType: 'security'
telemetry.labels.serverless: security
# Fleet specific configuration
xpack.fleet.internal.capabilities: ['security']
xpack.fleet.internal.registry.capabilities: ['security']
xpack.fleet.internal.registry.spec.max: '3.0'
# Disabled until packages implement the new spec https://github.com/elastic/kibana/issues/166742
# xpack.fleet.internal.registry.kibanaVersionCheckEnabled: false
# xpack.fleet.internal.registry.spec.min: '3.0'
# Serverless security specific options
xpack.securitySolution.enableExperimental:

View file

@ -9,7 +9,7 @@ xpack.fleet.internal.activeAgentsSoftLimit: 25000
xpack.fleet.internal.onlyAllowAgentUpgradeToKnownVersions: true
# Cloud links
xpack.cloud.base_url: "https://cloud.elastic.co"
xpack.cloud.base_url: 'https://cloud.elastic.co'
# Enable ZDT migration algorithm
migrations.algorithm: zdt
@ -86,7 +86,7 @@ xpack.spaces.allowFeatureVisibility: false
console.autocompleteDefinitions.endpointsAvailability: serverless
# Allow authentication via the Elasticsearch JWT realm with the `shared_secret` client authentication type.
elasticsearch.requestHeadersWhitelist: ["authorization", "es-client-authentication"]
elasticsearch.requestHeadersWhitelist: ['authorization', 'es-client-authentication']
# Limit maxSockets to 800 as we do in ESS, which improves reliability under high loads.
elasticsearch.maxSockets: 800

View file

@ -51,7 +51,14 @@ export interface FleetConfigType {
fleetServerStandalone: boolean;
onlyAllowAgentUpgradeToKnownVersions: boolean;
activeAgentsSoftLimit?: number;
capabilities: string[];
registry: {
kibanaVersionCheckEnabled: boolean;
capabilities: string[];
spec?: {
min?: string;
max?: string;
};
};
};
createArtifactsBulkBatchSize?: number;
}

View file

@ -29,6 +29,8 @@ import { BULK_CREATE_MAX_ARTIFACTS_BYTES } from './services/artifacts/artifacts'
const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages');
const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch');
const REGISTRY_SPEC_MAX_VERSION = '3.0';
export const config: PluginConfigDescriptor = {
exposeToBrowser: {
epm: true,
@ -185,17 +187,42 @@ export const config: PluginConfigDescriptor = {
min: 0,
})
),
capabilities: schema.arrayOf(
schema.oneOf([
// See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113
schema.literal('apm'),
schema.literal('enterprise_search'),
schema.literal('observability'),
schema.literal('security'),
schema.literal('serverless_search'),
schema.literal('uptime'),
]),
{ defaultValue: [] }
registry: schema.object(
{
kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }),
spec: schema.object(
{
min: schema.maybe(schema.string()),
max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }),
},
{
defaultValue: {
max: REGISTRY_SPEC_MAX_VERSION,
},
}
),
capabilities: schema.arrayOf(
schema.oneOf([
// See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113
schema.literal('apm'),
schema.literal('enterprise_search'),
schema.literal('observability'),
schema.literal('security'),
schema.literal('serverless_search'),
schema.literal('uptime'),
]),
{ defaultValue: [] }
),
},
{
defaultValue: {
kibanaVersionCheckEnabled: true,
capabilities: [],
spec: {
max: REGISTRY_SPEC_MAX_VERSION,
},
},
}
),
})
),

View file

@ -125,7 +125,10 @@ describe('_installPackage', () => {
disableProxies: false,
fleetServerStandalone: false,
onlyAllowAgentUpgradeToKnownVersions: false,
capabilities: [],
registry: {
kibanaVersionCheckEnabled: true,
capabilities: [],
},
},
})
);
@ -179,7 +182,10 @@ describe('_installPackage', () => {
disableILMPolicies: false,
fleetServerStandalone: false,
onlyAllowAgentUpgradeToKnownVersions: false,
capabilities: [],
registry: {
kibanaVersionCheckEnabled: true,
capabilities: [],
},
},
})
);

View file

@ -230,7 +230,9 @@ describe('fetchCategories', () => {
it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
capabilities: ['apm', 'security'],
registry: {
capabilities: ['apm', 'security'],
},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -239,6 +241,25 @@ describe('fetchCategories', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security');
});
it('call registry with spec.min spec.max if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
registry: {
spec: {
min: '3.0',
max: '3.0',
},
capabilities: [],
},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchCategories();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('spec.min')).toBe('3.0');
expect(callUrl.searchParams.get('spec.max')).toBe('3.0');
});
it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -257,7 +278,9 @@ describe('fetchList', () => {
it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
capabilities: ['apm', 'security'],
registry: {
capabilities: ['apm', 'security'],
},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -266,6 +289,25 @@ describe('fetchList', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security');
});
it('call registry with spec.min spec.max if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
registry: {
spec: {
min: '3.0',
max: '3.0',
},
},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchList();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('spec.min')).toBe('3.0');
expect(callUrl.searchParams.get('spec.max')).toBe('3.0');
});
it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -274,4 +316,32 @@ describe('fetchList', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBeNull();
});
it('does call registry with kibana.version if not explictly disabled', async () => {
mockGetConfig.mockReturnValue({
internal: {
registry: {},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchList();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('kibana.version')).not.toBeNull();
});
it('does not call registry with kibana.version with config internal.registry.kibanaVersionCheckEnabled:false', async () => {
mockGetConfig.mockReturnValue({
internal: {
registry: {
kibanaVersionCheckEnabled: false,
},
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchList();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('kibana.version')).toBeNull();
});
});

View file

@ -73,8 +73,7 @@ export async function fetchList(
}
}
setKibanaVersion(url);
setCapabilities(url);
setConstraints(url);
return fetchUrl(url.toString()).then(JSON.parse);
}
@ -106,8 +105,7 @@ async function _fetchFindLatestPackage(
);
if (!ignoreConstraints) {
setKibanaVersion(url);
setCapabilities(url);
setConstraints(url);
}
try {
@ -223,8 +221,12 @@ export async function fetchFile(filePath: string): Promise<Response> {
}
function setKibanaVersion(url: URL) {
const config = appContextService.getConfig();
const disableVersionCheck =
appContextService.getConfig()?.developer?.disableRegistryVersionCheck ?? false;
(config?.developer?.disableRegistryVersionCheck ?? false) ||
config?.internal?.registry?.kibanaVersionCheckEnabled === false;
if (disableVersionCheck) {
return;
}
@ -236,13 +238,31 @@ function setKibanaVersion(url: URL) {
}
}
function setSpecVersion(url: URL) {
const specMin = appContextService.getConfig()?.internal?.registry?.spec?.min;
const specMax = appContextService.getConfig()?.internal?.registry?.spec?.max;
if (specMin) {
url.searchParams.set('spec.min', specMin);
}
if (specMax) {
url.searchParams.set('spec.max', specMax);
}
}
function setCapabilities(url: URL) {
const capabilities = appContextService.getConfig()?.internal?.capabilities;
const capabilities = appContextService.getConfig()?.internal?.registry?.capabilities;
if (capabilities && capabilities.length > 0) {
url.searchParams.set('capabilities', capabilities.join(','));
}
}
function setConstraints(url: URL) {
setKibanaVersion(url);
setCapabilities(url);
setSpecVersion(url);
}
export async function fetchCategories(
params?: GetCategoriesRequest['query']
): Promise<CategorySummaryList> {
@ -257,8 +277,7 @@ export async function fetchCategories(
}
}
setKibanaVersion(url);
setCapabilities(url);
setConstraints(url);
return fetchUrl(url.toString()).then(JSON.parse);
}