Skip to content

Commit

Permalink
[Fleet] Support package capabilities filtering (#162435)
Browse files Browse the repository at this point in the history
  • Loading branch information
nchaulet authored Jul 28, 2023
1 parent 1dbd736 commit 9b89502
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 16 deletions.
3 changes: 3 additions & 0 deletions config/serverless.es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ telemetry.labels.serverless: search

# Alerts config
xpack.actions.enabledActionTypes: ['.email', '.index', '.slack', '.jira', '.webhook', '.teams']

# Fleet specific configuration
xpack.fleet.internal.capabilities: ['serverless_search']
3 changes: 3 additions & 0 deletions config/serverless.oblt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ xpack.fleet.agentIdVerificationEnabled: false
## APM Serverless Onboarding flow
xpack.apm.serverlessOnboarding: true

# Fleet specific configuration
xpack.fleet.internal.capabilities: ['apm', 'uptime', 'observability']

## Required for force installation of APM Package
xpack.fleet.packages:
- name: apm
Expand Down
6 changes: 4 additions & 2 deletions config/serverless.security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ xpack.serverless.plugin.developer.projectSwitcher.currentType: 'security'
# Specify in telemetry the project type
telemetry.labels.serverless: security

# Fleet specific configuration
xpack.fleet.internal.capabilities: ['security']

# Serverless security specific options
xpack.securitySolution.enableExperimental:
- discoverInTimeline

- discoverInTimeline
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export interface FleetConfigType {
disableProxies: boolean;
fleetServerStandalone: boolean;
activeAgentsSoftLimit?: number;
capabilities: string[];
};
createArtifactsBulkBatchSize?: number;
}
Expand Down
12 changes: 12 additions & 0 deletions x-pack/plugins/fleet/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@ 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: [] }
),
})
),
enabled: schema.boolean({ defaultValue: true }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ describe('_installPackage', () => {
disableILMPolicies: true,
disableProxies: false,
fleetServerStandalone: false,
capabilities: [],
},
})
);
Expand Down Expand Up @@ -176,6 +177,7 @@ describe('_installPackage', () => {
disableProxies: false,
disableILMPolicies: false,
fleetServerStandalone: false,
capabilities: [],
},
})
);
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/fleet/server/services/epm/packages/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type {
RegistryPackage,
EpmPackageAdditions,
GetCategoriesRequest,
GetPackagesRequest,
} from '../../../../common/types';
import type { Installation, PackageInfo, PackagePolicySOAttributes } from '../../../types';
import {
Expand All @@ -61,7 +62,6 @@ import { getFilteredSearchPackages } from '../filtered_packages';

import { createInstallableFrom } from '.';

export type { SearchParams } from '../registry';
export { getFile } from '../registry';

function nameAsTitle(name: string) {
Expand All @@ -76,7 +76,7 @@ export async function getPackages(
options: {
savedObjectsClient: SavedObjectsClientContract;
excludeInstallStatus?: boolean;
} & Registry.SearchParams
} & GetPackagesRequest['query']
) {
const {
savedObjectsClient,
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/fleet/server/services/epm/packages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { KibanaAssetType } from '../../../types';
import type { AssetType, Installable, Installation } from '../../../types';

export { bulkInstallPackages, isBulkInstallError } from './bulk_install_packages';
export type { SearchParams } from './get';
export {
getCategories,
getFile,
Expand Down
60 changes: 58 additions & 2 deletions x-pack/plugins/fleet/server/services/epm/registry/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import { loggingSystemMock } from '@kbn/core-logging-server-mocks';

import { PackageNotFoundError, RegistryResponseError } from '../../../errors';

import * as Archive from '../archive';

import {
Expand All @@ -17,10 +16,13 @@ import {
fetchFindLatestPackageOrThrow,
fetchInfo,
getLicensePath,
fetchCategories,
fetchList,
} from '.';

const mockLoggerFactory = loggingSystemMock.create();
const mockLogger = mockLoggerFactory.get('mock logger');
const mockGetConfig = jest.fn();

const mockGetBundledPackageByName = jest.fn();
const mockFetchUrl = jest.fn();
Expand All @@ -34,7 +36,7 @@ jest.mock('../..', () => ({
getLogger: () => mockLogger,
getKibanaBranch: () => 'main',
getKibanaVersion: () => '99.0.0',
getConfig: () => ({}),
getConfig: () => mockGetConfig(),
getIsProductionMode: () => false,
},
}));
Expand Down Expand Up @@ -219,3 +221,57 @@ describe('fetchInfo', () => {
}
});
});

describe('fetchCategories', () => {
beforeEach(() => {
mockFetchUrl.mockReset();
mockGetConfig.mockReset();
});
it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
capabilities: ['apm', 'security'],
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchCategories();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security');
});
it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchCategories();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBeNull();
});
});

describe('fetchList', () => {
beforeEach(() => {
mockFetchUrl.mockReset();
mockGetConfig.mockReset();
});
it('call registry with capabilities if configured', async () => {
mockGetConfig.mockReturnValue({
internal: {
capabilities: ['apm', 'security'],
},
});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchList();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBe('apm,security');
});
it('does not call registry with capabilities if none are configured', async () => {
mockGetConfig.mockReturnValue({});
mockFetchUrl.mockResolvedValue(JSON.stringify([]));
await fetchList();
expect(mockFetchUrl).toBeCalledTimes(1);
const callUrl = new URL(mockFetchUrl.mock.calls[0][0]);
expect(callUrl.searchParams.get('capabilities')).toBeNull();
});
});
23 changes: 14 additions & 9 deletions x-pack/plugins/fleet/server/services/epm/registry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import { splitPkgKey as split } from '../../../../common/services';
import { KibanaAssetType } from '../../../types';
import type {
AssetsGroupedByServiceByType,
CategoryId,
CategorySummaryList,
RegistryPackage,
RegistrySearchResults,
GetCategoriesRequest,
GetPackagesRequest,
PackageVerificationResult,
ArchivePackage,
BundledPackage,
Expand Down Expand Up @@ -54,19 +54,14 @@ import { verifyPackageArchiveSignature } from '../packages/package_verification'
import { fetchUrl, getResponse, getResponseStream } from './requests';
import { getRegistryUrl } from './registry_url';

export interface SearchParams {
category?: CategoryId;
prerelease?: boolean;
// deprecated
experimental?: boolean;
}

export const splitPkgKey = split;

export const pkgToPkgKey = ({ name, version }: { name: string; version: string }) =>
`${name}-${version}`;

export async function fetchList(params?: SearchParams): Promise<RegistrySearchResults> {
export async function fetchList(
params?: GetPackagesRequest['query']
): Promise<RegistrySearchResults> {
const registryUrl = getRegistryUrl();
const url = new URL(`${registryUrl}/search`);
if (params) {
Expand All @@ -79,6 +74,7 @@ export async function fetchList(params?: SearchParams): Promise<RegistrySearchRe
}

setKibanaVersion(url);
setCapabilities(url);

return fetchUrl(url.toString()).then(JSON.parse);
}
Expand Down Expand Up @@ -111,6 +107,7 @@ async function _fetchFindLatestPackage(

if (!ignoreConstraints) {
setKibanaVersion(url);
setCapabilities(url);
}

try {
Expand Down Expand Up @@ -239,6 +236,13 @@ function setKibanaVersion(url: URL) {
}
}

function setCapabilities(url: URL) {
const capabilities = appContextService.getConfig()?.internal?.capabilities;
if (capabilities && capabilities.length > 0) {
url.searchParams.set('capabilities', capabilities.join(','));
}
}

export async function fetchCategories(
params?: GetCategoriesRequest['query']
): Promise<CategorySummaryList> {
Expand All @@ -254,6 +258,7 @@ export async function fetchCategories(
}

setKibanaVersion(url);
setCapabilities(url);

return fetchUrl(url.toString()).then(JSON.parse);
}
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/types/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export type {
InstallSource,
InstallResult,
GetCategoriesRequest,
GetPackagesRequest,
DataType,
FleetServerEnrollmentAPIKey,
FleetServerAgent,
Expand Down

0 comments on commit 9b89502

Please sign in to comment.