Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fleet] Allow to preconfigure alternative ES outputs (on the same cluster) #111002

Merged
merged 25 commits into from
Sep 21, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e0bfc4f
[Fleet] Allow to preconfigure multiple ES outputs
nchaulet Sep 2, 2021
0a8ad75
Support multiple output permissions
nchaulet Sep 2, 2021
6fcfb80
Add is_preconfigured flag
nchaulet Sep 3, 2021
57f8fb3
Merge branch 'master' of github.com:elastic/kibana into feature-outpu…
nchaulet Sep 7, 2021
6f97c02
Add fleet_server.service_token to output
nchaulet Sep 7, 2021
e1a1efd
More tests and refacto
nchaulet Sep 8, 2021
2bd4a36
Fix default hosts
nchaulet Sep 8, 2021
255aeaa
Clean preconfigured output
nchaulet Sep 8, 2021
0ed4842
Fix doc
nchaulet Sep 9, 2021
5e75149
Encrypt fleet_server in output saved object
nchaulet Sep 10, 2021
30c46c6
Merge branch 'master' of github.com:elastic/kibana into feature-outpu…
nchaulet Sep 10, 2021
9dfe244
Merge branch 'master' into feature-outputs-preconfigure
kibanamachine Sep 15, 2021
a711b08
[Fleet] Remove support for external ES and only support one output pe…
nchaulet Sep 16, 2021
9a2eb8c
Remove saved object output property .fleet_server
nchaulet Sep 16, 2021
7755da8
Fix tests
nchaulet Sep 16, 2021
021d641
Merge branch 'master' of github.com:elastic/kibana into feature-outpu…
nchaulet Sep 20, 2021
52b57e1
Update after codereview
nchaulet Sep 20, 2021
28f7946
Merge branch 'master' of github.com:elastic/kibana into feature-outpu…
nchaulet Sep 20, 2021
d014dc8
Update after codereview
nchaulet Sep 20, 2021
c48dbb8
fix unhandled promise and default output id
nchaulet Sep 20, 2021
bf9a7e3
Merge branch 'master' of github.com:elastic/kibana into feature-outpu…
nchaulet Sep 20, 2021
6e9364f
Fix lint errors
nchaulet Sep 20, 2021
aef2a44
Update tests
nchaulet Sep 20, 2021
8548b80
Bump policies when preconfigred output are updated
nchaulet Sep 21, 2021
5fb80b3
Add basic unit test for bumpAllAgentPolciesForOutput
nchaulet Sep 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions x-pack/plugins/fleet/server/services/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,38 @@ class AgentPolicyService {
return res;
}

public async bumpAllAgentPoliciesForOutput(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's go ahead and add a unit test for this logic to verify the correct policies are updated.

soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
outputId: string,
options?: { user?: AuthenticatedUser }
): Promise<SavedObjectsBulkUpdateResponse<AgentPolicy>> {
const currentPolicies = await soClient.find<AgentPolicySOAttributes>({
type: SAVED_OBJECT_TYPE,
fields: ['revision', 'data_output_id', 'monitoring_output_id'],
searchFields: ['data_output_id', 'monitoring_output_id'],
search: escapeSearchQueryPhrase(outputId),
});
const bumpedPolicies = currentPolicies.saved_objects.map((policy) => {
policy.attributes = {
...policy.attributes,
revision: policy.attributes.revision + 1,
updated_at: new Date().toISOString(),
updated_by: options?.user ? options.user.username : 'system',
};
return policy;
});
const res = await soClient.bulkUpdate<AgentPolicySOAttributes>(bumpedPolicies);

await Promise.all(
currentPolicies.saved_objects.map((policy) =>
this.triggerAgentPolicyUpdatedEvent(soClient, esClient, 'updated', policy.id)
)
);

return res;
}

public async bumpAllAgentPolicies(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
Expand Down
20 changes: 16 additions & 4 deletions x-pack/plugins/fleet/server/services/preconfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,17 @@ jest.mock('./app_context', () => ({
}));

const spyAgentPolicyServiceUpdate = jest.spyOn(agentPolicy.agentPolicyService, 'update');
const spyAgentPolicyServicBumpAllAgentPoliciesForOutput = jest.spyOn(
agentPolicy.agentPolicyService,
'bumpAllAgentPoliciesForOutput'
);

describe('policy preconfiguration', () => {
beforeEach(() => {
mockInstalledPackages.clear();
mockConfiguredPolicies.clear();
spyAgentPolicyServiceUpdate.mockClear();
spyAgentPolicyServicBumpAllAgentPoliciesForOutput.mockClear();
});

it('should perform a no-op when passed no policies or packages', async () => {
Expand Down Expand Up @@ -509,7 +514,8 @@ describe('output preconfiguration', () => {

it('should create preconfigured output that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
await ensurePreconfiguredOutputs(soClient, [
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await ensurePreconfiguredOutputs(soClient, esClient, [
{
id: 'non-existing-output-1',
name: 'Output 1',
Expand All @@ -521,11 +527,13 @@ describe('output preconfiguration', () => {

expect(mockedOutputService.create).toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).not.toBeCalled();
});

it('should set default hosts if hosts is not set output that does not exists', async () => {
const soClient = savedObjectsClientMock.create();
await ensurePreconfiguredOutputs(soClient, [
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await ensurePreconfiguredOutputs(soClient, esClient, [
{
id: 'non-existing-output-1',
name: 'Output 1',
Expand All @@ -540,7 +548,9 @@ describe('output preconfiguration', () => {

it('should update output if preconfigured output exists and changed', async () => {
const soClient = savedObjectsClientMock.create();
await ensurePreconfiguredOutputs(soClient, [
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
soClient.find.mockResolvedValue({ saved_objects: [], page: 0, per_page: 0, total: 0 });
await ensurePreconfiguredOutputs(soClient, esClient, [
{
id: 'existing-output-1',
is_default: false,
Expand All @@ -552,6 +562,7 @@ describe('output preconfiguration', () => {

expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).toBeCalled();
expect(spyAgentPolicyServicBumpAllAgentPoliciesForOutput).toBeCalled();
});

const SCENARIOS: Array<{ name: string; data: PreconfiguredOutput }> = [
Expand Down Expand Up @@ -580,7 +591,8 @@ describe('output preconfiguration', () => {
const { data, name } = scenario;
it(`should do nothing if preconfigured output exists and did not changed (${name})`, async () => {
const soClient = savedObjectsClientMock.create();
await ensurePreconfiguredOutputs(soClient, [data]);
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
await ensurePreconfiguredOutputs(soClient, esClient, [data]);

expect(mockedOutputService.create).not.toBeCalled();
expect(mockedOutputService.update).not.toBeCalled();
Expand Down
11 changes: 9 additions & 2 deletions x-pack/plugins/fleet/server/services/preconfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function isPreconfiguredOutputDifferentFromCurrent(

export async function ensurePreconfiguredOutputs(
soClient: SavedObjectsClientContract,
esClient: ElasticsearchClient,
outputs: PreconfiguredOutput[]
) {
if (outputs.length === 0) {
Expand Down Expand Up @@ -94,9 +95,15 @@ export async function ensurePreconfiguredOutputs(
}

if (!existingOutput) {
return outputService.create(soClient, data, { id, overwrite: true });
await outputService.create(soClient, data, { id, overwrite: true });
} else if (isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)) {
return outputService.update(soClient, id, data);
await outputService.update(soClient, id, data);
// Bump revision of all policies using that output
if (outputData.is_default) {
await agentPolicyService.bumpAllAgentPolicies(soClient, esClient);
} else {
await agentPolicyService.bumpAllAgentPoliciesForOutput(soClient, esClient, id);
}
}
})
);
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/fleet/server/services/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async function createSetupSideEffects(
let packages = packagesOrUndefined ?? [];

await Promise.all([
ensurePreconfiguredOutputs(soClient, outputsOrUndefined ?? []),
ensurePreconfiguredOutputs(soClient, esClient, outputsOrUndefined ?? []),
settingsService.settingsSetup(soClient),
]);

Expand Down