Skip to content

Commit

Permalink
[Fleet] Add preconfiguration to kibana config (#96588) (#97136)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zacqary authored Apr 14, 2021
1 parent ee283bc commit 1f685e5
Show file tree
Hide file tree
Showing 17 changed files with 199 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ kibana_vars=(
xpack.fleet.agents.elasticsearch.host
xpack.fleet.agents.kibana.host
xpack.fleet.agents.tlsCheckDisabled
xpack.fleet.agentPolicies
xpack.fleet.packages
xpack.fleet.registryUrl
xpack.graph.canEditDrillDownUrls
xpack.graph.enabled
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export * from './epm';
export * from './output';
export * from './enrollment_api_key';
export * from './settings';
export * from './preconfiguration';

// TODO: This is the default `index.max_result_window` ES setting, which dictates
// the maximum amount of results allowed to be returned from a search. It's possible
Expand Down
9 changes: 9 additions & 0 deletions x-pack/plugins/fleet/common/constants/preconfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

export const PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE =
'fleet-preconfiguration-deletion-record';
3 changes: 3 additions & 0 deletions x-pack/plugins/fleet/common/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

export * from './models';
export * from './rest_spec';
import type { PreconfiguredAgentPolicy, PreconfiguredPackage } from './models/preconfiguration';

export interface FleetConfigType {
enabled: boolean;
Expand All @@ -32,6 +33,8 @@ export interface FleetConfigType {
agentPolicyRolloutRateLimitIntervalMs: number;
agentPolicyRolloutRateLimitRequestPerInterval: number;
};
agentPolicies?: PreconfiguredAgentPolicy[];
packages?: PreconfiguredPackage[];
}

// Calling Object.entries(PackagesGroupedByStatus) gave `status: string`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@

export interface PostIngestSetupResponse {
isInitialized: boolean;
preconfigurationError?: { name: string; message: string };
}
11 changes: 10 additions & 1 deletion x-pack/plugins/fleet/public/applications/fleet/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
sendSetup,
useBreadcrumbs,
useConfig,
useStartServices,
} from './hooks';
import { Error, Loading } from './components';
import { IntraAppStateProvider } from './hooks/use_intra_app_state';
Expand Down Expand Up @@ -59,6 +60,7 @@ const Panel = styled(EuiPanel)`

export const WithPermissionsAndSetup: React.FC = memo(({ children }) => {
useBreadcrumbs('base');
const { notifications } = useStartServices();

const [isPermissionsLoading, setIsPermissionsLoading] = useState<boolean>(false);
const [permissionsError, setPermissionsError] = useState<string>();
Expand All @@ -81,6 +83,13 @@ export const WithPermissionsAndSetup: React.FC = memo(({ children }) => {
if (setupResponse.error) {
setInitializationError(setupResponse.error);
}
if (setupResponse.data.preconfigurationError) {
notifications.toasts.addError(setupResponse.data.preconfigurationError, {
title: i18n.translate('xpack.fleet.setup.uiPreconfigurationErrorTitle', {
defaultMessage: 'Configuration error',
}),
});
}
} catch (err) {
setInitializationError(err);
}
Expand All @@ -92,7 +101,7 @@ export const WithPermissionsAndSetup: React.FC = memo(({ children }) => {
setPermissionsError('REQUEST_ERROR');
}
})();
}, []);
}, [notifications.toasts]);

if (isPermissionsLoading || permissionsError) {
return (
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ export {
// Fleet Server index
ENROLLMENT_API_KEYS_INDEX,
AGENTS_INDEX,
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
} from '../../common';
4 changes: 4 additions & 0 deletions x-pack/plugins/fleet/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
AGENT_POLLING_REQUEST_TIMEOUT_MS,
} from '../common';

import { PreconfiguredPackagesSchema, PreconfiguredAgentPoliciesSchema } from './types';

import { FleetPlugin } from './plugin';

export { default as apm } from 'elastic-apm-node';
Expand Down Expand Up @@ -77,6 +79,8 @@ export const config: PluginConfigDescriptor = {
defaultValue: AGENT_POLICY_ROLLOUT_RATE_LIMIT_REQUEST_PER_INTERVAL,
}),
}),
packages: schema.maybe(PreconfiguredPackagesSchema),
agentPolicies: schema.maybe(PreconfiguredAgentPoliciesSchema),
}),
};

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/fleet/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import {
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
} from './constants';
import { registerSavedObjects, registerEncryptedSavedObjects } from './saved_objects';
import {
Expand Down Expand Up @@ -133,6 +134,7 @@ const allSavedObjectTypes = [
AGENT_SAVED_OBJECT_TYPE,
AGENT_EVENT_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
];

/**
Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/fleet/server/routes/setup/handlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ describe('FleetSetupHandler', () => {
});

it('POST /setup succeeds w/200 and body of resolved value', async () => {
mockSetupIngestManager.mockImplementation(() => Promise.resolve({ isIntialized: true }));
mockSetupIngestManager.mockImplementation(() =>
Promise.resolve({ isInitialized: true, preconfigurationError: undefined })
);
await FleetSetupHandler(context, request, response);

const expectedBody: PostIngestSetupResponse = { isInitialized: true };
Expand Down
7 changes: 3 additions & 4 deletions x-pack/plugins/fleet/server/routes/setup/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ export const createFleetSetupHandler: RequestHandler<
try {
const soClient = context.core.savedObjects.client;
const esClient = context.core.elasticsearch.client.asCurrentUser;
await setupIngestManager(soClient, esClient);
const body = await setupIngestManager(soClient, esClient);
await setupFleet(soClient, esClient, {
forceRecreate: request.body?.forceRecreate ?? false,
});

return response.ok({
body: { isInitialized: true },
body,
});
} catch (error) {
return defaultIngestErrorHandler({ error, response });
Expand All @@ -81,8 +81,7 @@ export const FleetSetupHandler: RequestHandler = async (context, request, respon
const esClient = context.core.elasticsearch.client.asCurrentUser;

try {
const body: PostIngestSetupResponse = { isInitialized: true };
await setupIngestManager(soClient, esClient);
const body: PostIngestSetupResponse = await setupIngestManager(soClient, esClient);
return response.ok({
body,
});
Expand Down
14 changes: 14 additions & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
AGENT_ACTION_SAVED_OBJECT_TYPE,
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
GLOBAL_SETTINGS_SAVED_OBJECT_TYPE,
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
} from '../constants';

import {
Expand Down Expand Up @@ -358,6 +359,19 @@ const getSavedObjectTypes = (
},
},
},
[PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE]: {
name: PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
hidden: false,
namespaceType: 'agnostic',
management: {
importableAndExportable: false,
},
mappings: {
properties: {
preconfiguration_id: { type: 'keyword' },
},
},
},
});

export function registerSavedObjects(
Expand Down
11 changes: 10 additions & 1 deletion x-pack/plugins/fleet/server/services/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DEFAULT_AGENT_POLICY,
AGENT_POLICY_SAVED_OBJECT_TYPE,
AGENT_SAVED_OBJECT_TYPE,
PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE,
} from '../constants';
import type {
PackagePolicy,
Expand Down Expand Up @@ -150,7 +151,7 @@ class AgentPolicyService {
config: PreconfiguredAgentPolicy
): Promise<{
created: boolean;
policy: AgentPolicy;
policy?: AgentPolicy;
}> {
const { id, ...preconfiguredAgentPolicy } = omit(config, 'package_policies');
const preconfigurationId = String(id);
Expand Down Expand Up @@ -582,6 +583,13 @@ class AgentPolicyService {
}
);
}

if (agentPolicy.preconfiguration_id) {
await soClient.create(PRECONFIGURATION_DELETION_RECORD_SAVED_OBJECT_TYPE, {
preconfiguration_id: String(agentPolicy.preconfiguration_id),
});
}

await soClient.delete(SAVED_OBJECT_TYPE, id);
await this.triggerAgentPolicyUpdatedEvent(soClient, esClient, 'deleted', id);
return {
Expand Down Expand Up @@ -819,5 +827,6 @@ export async function addPackageToAgentPolicy(

await packagePolicyService.create(soClient, esClient, newPackagePolicy, {
bumpRevision: false,
skipEnsureInstalled: true,
});
}
39 changes: 26 additions & 13 deletions x-pack/plugins/fleet/server/services/package_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ class PackagePolicyService {
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
packagePolicy: NewPackagePolicy,
options?: { id?: string; user?: AuthenticatedUser; bumpRevision?: boolean; force?: boolean }
options?: {
id?: string;
user?: AuthenticatedUser;
bumpRevision?: boolean;
force?: boolean;
skipEnsureInstalled?: boolean;
}
): Promise<PackagePolicy> {
// Check that its agent policy does not have a package policy with the same name
const parentAgentPolicy = await agentPolicyService.get(soClient, packagePolicy.policy_id);
Expand Down Expand Up @@ -90,18 +96,25 @@ class PackagePolicyService {

// Make sure the associated package is installed
if (packagePolicy.package?.name) {
const [, pkgInfo] = await Promise.all([
ensureInstalledPackage({
savedObjectsClient: soClient,
pkgName: packagePolicy.package.name,
esClient,
}),
getPackageInfo({
savedObjectsClient: soClient,
pkgName: packagePolicy.package.name,
pkgVersion: packagePolicy.package.version,
}),
]);
const pkgInfoPromise = getPackageInfo({
savedObjectsClient: soClient,
pkgName: packagePolicy.package.name,
pkgVersion: packagePolicy.package.version,
});

let pkgInfo;
if (options?.skipEnsureInstalled) pkgInfo = await pkgInfoPromise;
else {
const [, packageInfo] = await Promise.all([
ensureInstalledPackage({
savedObjectsClient: soClient,
pkgName: packagePolicy.package.name,
esClient,
}),
pkgInfoPromise,
]);
pkgInfo = packageInfo;
}

// Check if it is a limited package, and if so, check that the corresponding agent policy does not
// already contain a package policy for this package
Expand Down
49 changes: 26 additions & 23 deletions x-pack/plugins/fleet/server/services/preconfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/serve
import type { PreconfiguredAgentPolicy } from '../../common/types';
import type { AgentPolicy, NewPackagePolicy, Output } from '../types';

import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../constants';

import { ensurePreconfiguredPackagesAndPolicies } from './preconfiguration';

const mockInstalledPackages = new Map();
Expand All @@ -27,30 +29,31 @@ const mockDefaultOutput: Output = {
function getPutPreconfiguredPackagesMock() {
const soClient = savedObjectsClientMock.create();
soClient.find.mockImplementation(async ({ type, search }) => {
const attributes = mockConfiguredPolicies.get(search!.replace(/"/g, ''));
if (attributes) {
return {
saved_objects: [
{
id: `mocked-${attributes.preconfiguration_id}`,
attributes,
type: type as string,
score: 1,
references: [],
},
],
total: 1,
page: 1,
per_page: 1,
};
} else {
return {
saved_objects: [],
total: 0,
page: 1,
per_page: 0,
};
if (type === AGENT_POLICY_SAVED_OBJECT_TYPE) {
const attributes = mockConfiguredPolicies.get(search!.replace(/"/g, ''));
if (attributes) {
return {
saved_objects: [
{
id: `mocked-${attributes.preconfiguration_id}`,
attributes,
type: type as string,
score: 1,
references: [],
},
],
total: 1,
page: 1,
per_page: 1,
};
}
}
return {
saved_objects: [],
total: 0,
page: 1,
per_page: 0,
};
});
soClient.create.mockImplementation(async (type, policy) => {
const attributes = policy as AgentPolicy;
Expand Down
Loading

0 comments on commit 1f685e5

Please sign in to comment.