[Fleet] Limit pagination size when retrieving full policy or withAgentCount (#196887)

This commit is contained in:
Nicolas Chaulet 2024-10-21 14:44:32 -04:00 committed by GitHub
parent 399aed9b19
commit ce7616ad59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 222 additions and 55 deletions

View file

@ -7121,14 +7121,26 @@
}
},
{
"description": "use withAgentCount instead",
"in": "query",
"name": "noAgentCount",
"required": false,
"schema": {
"deprecated": true,
"type": "boolean"
}
},
{
"description": "get policies with agent count",
"in": "query",
"name": "withAgentCount",
"required": false,
"schema": {
"type": "boolean"
}
},
{
"description": "get full policies with package policies populated",
"in": "query",
"name": "full",
"required": false,

View file

@ -7121,14 +7121,26 @@
}
},
{
"description": "use withAgentCount instead",
"in": "query",
"name": "noAgentCount",
"required": false,
"schema": {
"deprecated": true,
"type": "boolean"
}
},
{
"description": "get policies with agent count",
"in": "query",
"name": "withAgentCount",
"required": false,
"schema": {
"type": "boolean"
}
},
{
"description": "get full policies with package policies populated",
"in": "query",
"name": "full",
"required": false,

View file

@ -10428,12 +10428,21 @@ paths:
required: false
schema:
type: string
- in: query
- description: use withAgentCount instead
in: query
name: noAgentCount
required: false
schema:
deprecated: true
type: boolean
- in: query
- description: get policies with agent count
in: query
name: withAgentCount
required: false
schema:
type: boolean
- description: get full policies with package policies populated
in: query
name: full
required: false
schema:

View file

@ -10428,12 +10428,21 @@ paths:
required: false
schema:
type: string
- in: query
- description: use withAgentCount instead
in: query
name: noAgentCount
required: false
schema:
deprecated: true
type: boolean
- in: query
- description: get policies with agent count
in: query
name: withAgentCount
required: false
schema:
type: boolean
- description: get full policies with package policies populated
in: query
name: full
required: false
schema:

View file

@ -13857,12 +13857,21 @@ paths:
required: false
schema:
type: string
- in: query
- description: use withAgentCount instead
in: query
name: noAgentCount
required: false
schema:
deprecated: true
type: boolean
- in: query
- description: get policies with agent count
in: query
name: withAgentCount
required: false
schema:
type: boolean
- description: get full policies with package policies populated
in: query
name: full
required: false
schema:

View file

@ -13857,12 +13857,21 @@ paths:
required: false
schema:
type: string
- in: query
- description: use withAgentCount instead
in: query
name: noAgentCount
required: false
schema:
deprecated: true
type: boolean
- in: query
- description: get policies with agent count
in: query
name: withAgentCount
required: false
schema:
type: boolean
- description: get full policies with package policies populated
in: query
name: full
required: false
schema:

View file

@ -12,6 +12,7 @@ import type { ListResult, ListWithKuery, BulkGetResult } from './common';
export interface GetAgentPoliciesRequest {
query: ListWithKuery & {
noAgentCount?: boolean;
withAgentCount?: boolean;
full?: boolean;
};
}

View file

@ -8,19 +8,19 @@
import { request } from './common';
export function cleanupAgentPolicies(spaceId?: string) {
request({ url: `${spaceId ? `/s/${spaceId}` : ''}/api/fleet/agent_policies` }).then(
(response: any) => {
response.body.items
.filter((policy: any) => policy.agents === 0)
.forEach((policy: any) => {
request({
method: 'POST',
url: `${spaceId ? `/s/${spaceId}` : ''}/api/fleet/agent_policies/delete`,
body: { agentPolicyId: policy.id },
});
request({
url: `${spaceId ? `/s/${spaceId}` : ''}/api/fleet/agent_policies?withAgentCount=true`,
}).then((response: any) => {
response.body.items
.filter((policy: any) => policy.agents === 0)
.forEach((policy: any) => {
request({
method: 'POST',
url: `${spaceId ? `/s/${spaceId}` : ''}/api/fleet/agent_policies/delete`,
body: { agentPolicyId: policy.id },
});
}
);
});
});
}
export function unenrollAgent() {

View file

@ -98,7 +98,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => {
sortField: sorting?.field,
sortOrder: sorting?.direction,
kuery: search,
noAgentCount: false, // Explicitly fetch agent count
withAgentCount: true, // Explicitly fetch agent count
full: true,
});

View file

@ -22,7 +22,6 @@ import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { sendGetAgentPolicies, useLink } from '../../../hooks';
import { SO_SEARCH_LIMIT } from '../../../constants';
import { policyHasFleetServer } from '../../../services';
import type { AgentPolicy } from '../../../types';
@ -35,7 +34,7 @@ import { CodeBlock } from './code_block';
const fetchAgentPolicies = async () => {
const response = await sendGetAgentPolicies({
full: true,
perPage: SO_SEARCH_LIMIT,
perPage: 100,
sortOrder: 'asc',
});

View file

@ -29,7 +29,7 @@ import {
useLink,
useStartServices,
} from '../../../hooks';
import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT } from '../../../constants';
import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../constants';
import { queryClient } from '..';
import { CodeBlock } from './code_block';
@ -37,7 +37,7 @@ import { CodeBlock } from './code_block';
const fetchPreconfiguredPolicies = async () => {
const kuery = `${LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE}.is_preconfigured:true`;
const response = await sendGetAgentPolicies({ kuery, perPage: SO_SEARCH_LIMIT, full: true });
const response = await sendGetAgentPolicies({ kuery, perPage: 100, full: true });
if (response.error) {
throw new Error(response.error.message);

View file

@ -133,7 +133,8 @@ export const getAgentPoliciesHandler: FleetRequestHandler<
const esClient = coreContext.elasticsearch.client.asInternalUser;
const {
full: withPackagePolicies = false,
noAgentCount = false,
noAgentCount,
withAgentCount,
format,
...restOfQuery
} = request.query;
@ -150,7 +151,7 @@ export const getAgentPoliciesHandler: FleetRequestHandler<
let { items } = agentPoliciesResponse;
const { total, page, perPage } = agentPoliciesResponse;
if (fleetContext.authz.fleet.readAgents && !noAgentCount) {
if (fleetContext.authz.fleet.readAgents && (noAgentCount === false || withAgentCount)) {
await populateAssignedAgentsCount(fleetContext.agentClient.asCurrentUser, items);
}

View file

@ -0,0 +1,78 @@
/*
* 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.
*/
import { GetAgentPoliciesRequestSchema } from './agent_policy';
describe('GetAgentPoliciesRequestSchema.query', () => {
it('should work without query parameters', () => {
expect(() => GetAgentPoliciesRequestSchema.query.validate({})).not.toThrow();
});
it('should work with perPage being less than 100', () => {
expect(() => GetAgentPoliciesRequestSchema.query.validate({ perPage: 50 })).not.toThrow();
});
it('should work with perPage being more than 100', () => {
expect(() => GetAgentPoliciesRequestSchema.query.validate({ perPage: 500 })).not.toThrow();
});
it('should work with perPage being less than 100 and agentCount and full', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({ perPage: 50, full: true, noAgentCount: false })
).not.toThrow();
});
it('should work with perPage being less than 100 and agentCount', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({ perPage: 50, noAgentCount: true })
).not.toThrow();
});
it('should work with perPage being less than 100 and no agentCount and full', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({ perPage: 50, full: true, noAgentCount: false })
).not.toThrow();
});
it('should throw with perPage being more than 100 and noagentCount', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({
perPage: 500,
noAgentCount: false,
})
).toThrow(/perPage should be less or equal to 100 when fetching full policies or agent count./);
});
it('should throw with perPage being more than 100 and withAgentCount', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({
perPage: 500,
withAgentCount: true,
})
).toThrow(/perPage should be less or equal to 100 when fetching full policies or agent count./);
});
it('should throw without perPage being more than 100 and full', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({
perPage: 500,
noAgentCount: true,
full: true,
})
).toThrow(/perPage should be less or equal to 100 when fetching full policies or agent count./);
});
it('should not throw with perPage being more than 100 and no agentCount and no full', () => {
expect(() =>
GetAgentPoliciesRequestSchema.query.validate({
perPage: 500,
full: false,
noAgentCount: true,
})
).not.toThrow();
});
});

View file

@ -20,33 +20,59 @@ import { validateKuery } from '../../routes/utils/filter_utils';
import { BulkRequestBodySchema } from './common';
export const GetAgentPoliciesRequestSchema = {
query: schema.object({
page: schema.maybe(schema.number({ defaultValue: 1 })),
perPage: schema.maybe(schema.number({ defaultValue: 20 })),
sortField: schema.maybe(schema.string()),
sortOrder: schema.maybe(schema.oneOf([schema.literal('desc'), schema.literal('asc')])),
showUpgradeable: schema.maybe(schema.boolean()),
kuery: schema.maybe(
schema.string({
validate: (value: string) => {
const validationObj = validateKuery(
value,
[LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE],
AGENT_POLICY_MAPPINGS,
true
);
if (validationObj?.error) {
return validationObj?.error;
}
},
})
),
noAgentCount: schema.maybe(schema.boolean()),
full: schema.maybe(schema.boolean()),
format: schema.maybe(
schema.oneOf([schema.literal(inputsFormat.Simplified), schema.literal(inputsFormat.Legacy)])
),
}),
query: schema.object(
{
page: schema.maybe(schema.number({ defaultValue: 1 })),
perPage: schema.maybe(schema.number({ defaultValue: 20 })),
sortField: schema.maybe(schema.string()),
sortOrder: schema.maybe(schema.oneOf([schema.literal('desc'), schema.literal('asc')])),
showUpgradeable: schema.maybe(schema.boolean()),
kuery: schema.maybe(
schema.string({
validate: (value: string) => {
const validationObj = validateKuery(
value,
[LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE],
AGENT_POLICY_MAPPINGS,
true
);
if (validationObj?.error) {
return validationObj?.error;
}
},
})
),
noAgentCount: schema.maybe(
schema.boolean({
meta: { description: 'use withAgentCount instead', deprecated: true },
})
), //
withAgentCount: schema.maybe(
schema.boolean({
meta: { description: 'get policies with agent count' },
})
),
full: schema.maybe(
schema.boolean({
meta: { description: 'get full policies with package policies populated' },
})
),
format: schema.maybe(
schema.oneOf([schema.literal(inputsFormat.Simplified), schema.literal(inputsFormat.Legacy)])
),
},
{
validate: (query) => {
if (
query.perPage &&
query.perPage > 100 &&
(query.full || query.noAgentCount === false || query.withAgentCount === true)
) {
return 'perPage should be less or equal to 100 when fetching full policies or agent count.';
}
},
}
),
};
export const BulkGetAgentPoliciesRequestSchema = {

View file

@ -120,7 +120,9 @@ export default function (providerContext: FtrProviderContext) {
})
.expect(200);
const { body } = await supertest
.get(`/api/fleet/agent_policies?kuery=ingest-agent-policies.name:TEST`)
.get(
`/api/fleet/agent_policies?kuery=ingest-agent-policies.name:TEST&withAgentCount=true`
)
.set('kbn-xsrf', 'xxxx')
.expect(200);
expect(body.items.length).to.eql(1);