Skip to content

Commit f207c20

Browse files
[Fleet] Move Fleet Setup to start lifecycle (#117552) (#118554)
* Call setup on fleet start, remove API calls * Fix unused import * Revert removal of setup API call * Restructor fleetSetupCompleted promise * Add logging + handle setup failures * Restructure logging to mix of debug/info * Maybe fix failing tests * Try fixing tests again * Fix another dashboard test * Re-add output logs after merge * Log non-fatal errors during Fleet setup on boot * Don't rely on fleetSetupCompleted to be called * Fix failing test * Track fleet setup status to avoid double calls * Use IIFE in place of Promise ctor * Remove unnecessary fleetSetupStatus value * Move non-error logs into setupFleet method * Remove unused formatNonFatalErrors import Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kyle Pollich <kyle.pollich@elastic.co>
1 parent a216558 commit f207c20

File tree

8 files changed

+74
-22
lines changed

8 files changed

+74
-22
lines changed

test/accessibility/apps/dashboard.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
4545
});
4646

4747
it('add a visualization', async () => {
48+
await testSubjects.setValue('savedObjectFinderSearchInput', '[Flights]');
4849
await testSubjects.click('savedObjectTitle[Flights]-Delay-Buckets');
4950
await a11y.testAppSnapshot();
5051
});
@@ -85,6 +86,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
8586
});
8687

8788
it('Add one more saved object to cancel it', async () => {
89+
await testSubjects.setValue('savedObjectFinderSearchInput', '[Flights]');
8890
await testSubjects.click('savedObjectTitle[Flights]-Destination-Weather');
8991
await a11y.testAppSnapshot();
9092
});

test/examples/embeddables/adding_children.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
2323
await testSubjects.click('embeddablePanelToggleMenuIcon');
2424
await testSubjects.click('embeddablePanelAction-ACTION_ADD_PANEL');
2525
await testSubjects.waitForDeleted('savedObjectFinderLoadingIndicator');
26+
await testSubjects.click('savedObjectFinderFilterButton');
27+
await testSubjects.click('savedObjectFinderFilter-todo');
2628
await testSubjects.click('savedObjectTitleGarbage');
2729
await testSubjects.moveMouseTo('euiFlyoutCloseButton');
2830
await flyout.ensureClosed('dashboardAddPanel');

test/functional/apps/management/_mgmt_import_saved_objects.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default function ({ getService, getPageObjects }) {
3939
await PageObjects.savedObjects.clickConfirmChanges();
4040
await PageObjects.savedObjects.clickImportDone();
4141
await PageObjects.savedObjects.waitTableIsLoaded();
42+
await PageObjects.savedObjects.searchForObject('mysaved');
4243

4344
//instead of asserting on count- am asserting on the titles- which is more accurate than count.
4445
const objects = await PageObjects.savedObjects.getRowTitles();

x-pack/plugins/fleet/server/plugin.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
2020

2121
import type { TelemetryPluginSetup, TelemetryPluginStart } from 'src/plugins/telemetry/server';
2222

23-
import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server';
23+
import { DEFAULT_APP_CATEGORIES, SavedObjectsClient } from '../../../../src/core/server';
2424
import type { PluginStart as DataPluginStart } from '../../../../src/plugins/data/server';
2525
import type { LicensingPluginSetup, ILicense } from '../../licensing/server';
2626
import type {
@@ -83,6 +83,7 @@ import { RouterWrappers } from './routes/security';
8383
import { FleetArtifactsClient } from './services/artifacts';
8484
import type { FleetRouter } from './types/request_context';
8585
import { TelemetryEventsSender } from './telemetry/sender';
86+
import { setupFleet } from './services/setup';
8687

8788
export interface FleetSetupDeps {
8889
licensing: LicensingPluginSetup;
@@ -332,8 +333,22 @@ export class FleetPlugin
332333

333334
this.telemetryEventsSender.start(plugins.telemetry, core);
334335

336+
const logger = appContextService.getLogger();
337+
338+
const fleetSetupPromise = (async () => {
339+
try {
340+
await setupFleet(
341+
new SavedObjectsClient(core.savedObjects.createInternalRepository()),
342+
core.elasticsearch.client.asInternalUser
343+
);
344+
} catch (error) {
345+
logger.warn('Fleet setup failed');
346+
logger.warn(error);
347+
}
348+
})();
349+
335350
return {
336-
fleetSetupCompleted: () => Promise.resolve(),
351+
fleetSetupCompleted: () => fleetSetupPromise,
337352
esIndexPatternService: new ESIndexPatternSavedObjectService(),
338353
packageService: {
339354
getInstallation,

x-pack/plugins/fleet/server/routes/setup/handlers.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { fleetSetupHandler } from './handlers';
1818

1919
jest.mock('../../services/setup', () => {
2020
return {
21+
...jest.requireActual('../../services/setup'),
2122
setupFleet: jest.fn(),
2223
};
2324
});

x-pack/plugins/fleet/server/routes/setup/handlers.ts

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { appContextService } from '../../services';
99
import type { GetFleetStatusResponse, PostFleetSetupResponse } from '../../../common';
10-
import { setupFleet } from '../../services/setup';
10+
import { formatNonFatalErrors, setupFleet } from '../../services/setup';
1111
import { hasFleetServers } from '../../services/fleet_server';
1212
import { defaultIngestErrorHandler } from '../../errors';
1313
import type { FleetRequestHandler } from '../../types';
@@ -50,24 +50,8 @@ export const fleetSetupHandler: FleetRequestHandler = async (context, request, r
5050
const setupStatus = await setupFleet(soClient, esClient);
5151
const body: PostFleetSetupResponse = {
5252
...setupStatus,
53-
nonFatalErrors: setupStatus.nonFatalErrors.flatMap((e) => {
54-
// JSONify the error object so it can be displayed properly in the UI
55-
if ('error' in e) {
56-
return {
57-
name: e.error.name,
58-
message: e.error.message,
59-
};
60-
} else {
61-
return e.errors.map((upgradePackagePolicyError: any) => {
62-
return {
63-
name: upgradePackagePolicyError.key,
64-
message: upgradePackagePolicyError.message,
65-
};
66-
});
67-
}
68-
}),
53+
nonFatalErrors: formatNonFatalErrors(setupStatus.nonFatalErrors),
6954
};
70-
7155
return response.ok({ body });
7256
} catch (error) {
7357
return defaultIngestErrorHandler({ error, response });

x-pack/plugins/fleet/server/services/preconfiguration.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export async function ensurePreconfiguredOutputs(
7373
esClient: ElasticsearchClient,
7474
outputs: PreconfiguredOutput[]
7575
) {
76+
const logger = appContextService.getLogger();
77+
7678
if (outputs.length === 0) {
7779
return;
7880
}
@@ -106,8 +108,10 @@ export async function ensurePreconfiguredOutputs(
106108
existingOutput && isPreconfiguredOutputDifferentFromCurrent(existingOutput, data);
107109

108110
if (isCreate) {
111+
logger.debug(`Creating output ${output.id}`);
109112
await outputService.create(soClient, data, { id, fromPreconfiguration: true });
110113
} else if (isUpdateWithNewData) {
114+
logger.debug(`Updating output ${output.id}`);
111115
await outputService.update(soClient, id, data, { fromPreconfiguration: true });
112116
// Bump revision of all policies using that output
113117
if (outputData.is_default || outputData.is_default_monitoring) {
@@ -335,7 +339,7 @@ export async function ensurePreconfiguredPackagesAndPolicies(
335339
await soClient
336340
.delete(AGENT_POLICY_SAVED_OBJECT_TYPE, policy!.id)
337341
// swallow error
338-
.catch((deleteErr) => appContextService.getLogger().error(deleteErr));
342+
.catch((deleteErr) => logger.error(deleteErr));
339343

340344
throw err;
341345
}

x-pack/plugins/fleet/server/services/setup.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ async function createSetupSideEffects(
5151
soClient: SavedObjectsClientContract,
5252
esClient: ElasticsearchClient
5353
): Promise<SetupStatus> {
54+
const logger = appContextService.getLogger();
55+
logger.info('Beginning fleet setup');
56+
5457
const {
5558
agentPolicies: policiesOrUndefined,
5659
packages: packagesOrUndefined,
@@ -60,6 +63,7 @@ async function createSetupSideEffects(
6063
const policies = policiesOrUndefined ?? [];
6164
let packages = packagesOrUndefined ?? [];
6265

66+
logger.debug('Setting up Fleet outputs');
6367
await Promise.all([
6468
ensurePreconfiguredOutputs(soClient, esClient, outputsOrUndefined ?? []),
6569
settingsService.settingsSetup(soClient),
@@ -68,6 +72,7 @@ async function createSetupSideEffects(
6872
const defaultOutput = await outputService.ensureDefaultOutput(soClient);
6973

7074
if (appContextService.getConfig()?.agentIdVerificationEnabled) {
75+
logger.debug('Setting up Fleet Elasticsearch assets');
7176
await ensureFleetGlobalEsAssets(soClient, esClient);
7277
}
7378

@@ -91,6 +96,8 @@ async function createSetupSideEffects(
9196
...autoUpdateablePackages.filter((pkg) => !preconfiguredPackageNames.has(pkg.name)),
9297
];
9398

99+
logger.debug('Setting up initial Fleet packages');
100+
94101
const { nonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies(
95102
soClient,
96103
esClient,
@@ -99,11 +106,22 @@ async function createSetupSideEffects(
99106
defaultOutput
100107
);
101108

109+
logger.debug('Cleaning up Fleet outputs');
102110
await cleanPreconfiguredOutputs(soClient, outputsOrUndefined ?? []);
103111

112+
logger.debug('Setting up Fleet enrollment keys');
104113
await ensureDefaultEnrollmentAPIKeysExists(soClient, esClient);
114+
115+
logger.debug('Setting up Fleet Server agent policies');
105116
await ensureFleetServerAgentPoliciesExists(soClient, esClient);
106117

118+
if (nonFatalErrors.length > 0) {
119+
logger.info('Encountered non fatal errors during Fleet setup');
120+
formatNonFatalErrors(nonFatalErrors).forEach((error) => logger.info(JSON.stringify(error)));
121+
}
122+
123+
logger.info('Fleet setup completed');
124+
107125
return {
108126
isInitialized: true,
109127
nonFatalErrors,
@@ -119,6 +137,7 @@ export async function ensureFleetGlobalEsAssets(
119137
) {
120138
const logger = appContextService.getLogger();
121139
// Ensure Global Fleet ES assets are installed
140+
logger.debug('Creating Fleet component template and ingest pipeline');
122141
const globalAssetsRes = await Promise.all([
123142
ensureDefaultComponentTemplate(esClient),
124143
ensureFleetFinalPipelineIsInstalled(esClient),
@@ -141,7 +160,7 @@ export async function ensureFleetGlobalEsAssets(
141160
savedObjectsClient: soClient,
142161
pkgkey: pkgToPkgKey({ name: installation.name, version: installation.version }),
143162
esClient,
144-
// Force install the pacakge will update the index template and the datastream write indices
163+
// Force install the package will update the index template and the datastream write indices
145164
force: true,
146165
}).catch((err) => {
147166
logger.error(
@@ -187,3 +206,27 @@ export async function ensureDefaultEnrollmentAPIKeysExists(
187206
})
188207
);
189208
}
209+
210+
/**
211+
* Maps the `nonFatalErrors` object returned by the setup process to a more readable
212+
* and predictable format suitable for logging output or UI presentation.
213+
*/
214+
export function formatNonFatalErrors(
215+
nonFatalErrors: SetupStatus['nonFatalErrors']
216+
): Array<{ name: string; message: string }> {
217+
return nonFatalErrors.flatMap((e) => {
218+
if ('error' in e) {
219+
return {
220+
name: e.error.name,
221+
message: e.error.message,
222+
};
223+
} else {
224+
return e.errors.map((upgradePackagePolicyError: any) => {
225+
return {
226+
name: upgradePackagePolicyError.key,
227+
message: upgradePackagePolicyError.message,
228+
};
229+
});
230+
}
231+
});
232+
}

0 commit comments

Comments
 (0)