[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 xpack.apm.serverlessOnboarding: true
# Fleet specific configuration # 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 ## Required for force installation of APM Package
xpack.fleet.packages: xpack.fleet.packages:

View file

@ -26,7 +26,11 @@ xpack.serverless.plugin.developer.projectSwitcher.currentType: 'security'
telemetry.labels.serverless: security telemetry.labels.serverless: security
# Fleet specific configuration # 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 # Serverless security specific options
xpack.securitySolution.enableExperimental: xpack.securitySolution.enableExperimental:

View file

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

View file

@ -51,7 +51,14 @@ export interface FleetConfigType {
fleetServerStandalone: boolean; fleetServerStandalone: boolean;
onlyAllowAgentUpgradeToKnownVersions: boolean; onlyAllowAgentUpgradeToKnownVersions: boolean;
activeAgentsSoftLimit?: number; activeAgentsSoftLimit?: number;
capabilities: string[]; registry: {
kibanaVersionCheckEnabled: boolean;
capabilities: string[];
spec?: {
min?: string;
max?: string;
};
};
}; };
createArtifactsBulkBatchSize?: number; 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_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages');
const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch'); const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch');
const REGISTRY_SPEC_MAX_VERSION = '3.0';
export const config: PluginConfigDescriptor = { export const config: PluginConfigDescriptor = {
exposeToBrowser: { exposeToBrowser: {
epm: true, epm: true,
@ -185,17 +187,42 @@ export const config: PluginConfigDescriptor = {
min: 0, min: 0,
}) })
), ),
capabilities: schema.arrayOf( registry: schema.object(
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 kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }),
schema.literal('apm'), spec: schema.object(
schema.literal('enterprise_search'), {
schema.literal('observability'), min: schema.maybe(schema.string()),
schema.literal('security'), max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }),
schema.literal('serverless_search'), },
schema.literal('uptime'), {
]), defaultValue: {
{ 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, disableProxies: false,
fleetServerStandalone: false, fleetServerStandalone: false,
onlyAllowAgentUpgradeToKnownVersions: false, onlyAllowAgentUpgradeToKnownVersions: false,
capabilities: [], registry: {
kibanaVersionCheckEnabled: true,
capabilities: [],
},
}, },
}) })
); );
@ -179,7 +182,10 @@ describe('_installPackage', () => {
disableILMPolicies: false, disableILMPolicies: false,
fleetServerStandalone: false, fleetServerStandalone: false,
onlyAllowAgentUpgradeToKnownVersions: false, onlyAllowAgentUpgradeToKnownVersions: false,
capabilities: [], registry: {
kibanaVersionCheckEnabled: true,
capabilities: [],
},
}, },
}) })
); );

View file

@ -230,7 +230,9 @@ describe('fetchCategories', () => {
it('call registry with capabilities if configured', async () => { it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({ mockGetConfig.mockReturnValue({
internal: { internal: {
capabilities: ['apm', 'security'], registry: {
capabilities: ['apm', 'security'],
},
}, },
}); });
mockFetchUrl.mockResolvedValue(JSON.stringify([])); mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -239,6 +241,25 @@ describe('fetchCategories', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]); const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security'); 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 () => { it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({}); mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([])); mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -257,7 +278,9 @@ describe('fetchList', () => {
it('call registry with capabilities if configured', async () => { it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({ mockGetConfig.mockReturnValue({
internal: { internal: {
capabilities: ['apm', 'security'], registry: {
capabilities: ['apm', 'security'],
},
}, },
}); });
mockFetchUrl.mockResolvedValue(JSON.stringify([])); mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -266,6 +289,25 @@ describe('fetchList', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]); const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security'); 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 () => { it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({}); mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([])); mockFetchUrl.mockResolvedValue(JSON.stringify([]));
@ -274,4 +316,32 @@ describe('fetchList', () => {
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]); const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBeNull(); 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); setConstraints(url);
setCapabilities(url);
return fetchUrl(url.toString()).then(JSON.parse); return fetchUrl(url.toString()).then(JSON.parse);
} }
@ -106,8 +105,7 @@ async function _fetchFindLatestPackage(
); );
if (!ignoreConstraints) { if (!ignoreConstraints) {
setKibanaVersion(url); setConstraints(url);
setCapabilities(url);
} }
try { try {
@ -223,8 +221,12 @@ export async function fetchFile(filePath: string): Promise<Response> {
} }
function setKibanaVersion(url: URL) { function setKibanaVersion(url: URL) {
const config = appContextService.getConfig();
const disableVersionCheck = const disableVersionCheck =
appContextService.getConfig()?.developer?.disableRegistryVersionCheck ?? false; (config?.developer?.disableRegistryVersionCheck ?? false) ||
config?.internal?.registry?.kibanaVersionCheckEnabled === false;
if (disableVersionCheck) { if (disableVersionCheck) {
return; 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) { function setCapabilities(url: URL) {
const capabilities = appContextService.getConfig()?.internal?.capabilities; const capabilities = appContextService.getConfig()?.internal?.registry?.capabilities;
if (capabilities && capabilities.length > 0) { if (capabilities && capabilities.length > 0) {
url.searchParams.set('capabilities', capabilities.join(',')); url.searchParams.set('capabilities', capabilities.join(','));
} }
} }
function setConstraints(url: URL) {
setKibanaVersion(url);
setCapabilities(url);
setSpecVersion(url);
}
export async function fetchCategories( export async function fetchCategories(
params?: GetCategoriesRequest['query'] params?: GetCategoriesRequest['query']
): Promise<CategorySummaryList> { ): Promise<CategorySummaryList> {
@ -257,8 +277,7 @@ export async function fetchCategories(
} }
} }
setKibanaVersion(url); setConstraints(url);
setCapabilities(url);
return fetchUrl(url.toString()).then(JSON.parse); return fetchUrl(url.toString()).then(JSON.parse);
} }