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] Add agent policy inactivity_timeoutexperimental setting #147432

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"index-pattern": "48e77ca393c254e93256f11a7cdc0232dd754c08",
"infrastructure-monitoring-log-view": "e2c78c1076bd35e57d7c5fa1b410e5c126d12327",
"infrastructure-ui-source": "7c8dbbc0a608911f1b683a944f4a65383f6153ed",
"ingest-agent-policies": "9170cdad95d887c036b87adf0ff38a3f12800c05",
"ingest-agent-policies": "54d586fdafae83ba326e47d1a3727b0d9c910a12",
"ingest-download-sources": "1e69dabd6db5e320fe08c5bda8f35f29bafc6b54",
"ingest-outputs": "4888b16d55a452bf5fff2bb407e0361567eae63a",
"ingest-package-policies": "d93048bf153f9043946e8965065a88014f7ccb41",
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/common/experimental_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const allowedExperimentalValues = Object.freeze({
packageVerification: true,
showDevtoolsRequest: true,
diagnosticFileUploadEnabled: false,
inactivityTimeout: false,
});

type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
10 changes: 9 additions & 1 deletion x-pack/plugins/fleet/common/openapi/bundled.json
Original file line number Diff line number Diff line change
Expand Up @@ -5230,6 +5230,14 @@
"download_source_id": {
"type": "string",
"nullable": true
},
"unenroll_timeout": {
"type": "number",
"nullable": true
},
"inactivity_timeout": {
"type": "number",
"nullable": true
}
},
"required": [
Expand Down Expand Up @@ -5514,7 +5522,7 @@
},
"policy_id": {
"type": "string",
"description": "Agent policy ID to which the package policy will be added",
"description": "Agent policy ID where that package policy will be added",
"example": "agent-policy-id"
},
"package": {
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/fleet/common/openapi/bundled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3327,6 +3327,12 @@ components:
download_source_id:
type: string
nullable: true
unenroll_timeout:
type: number
nullable: true
inactivity_timeout:
type: number
nullable: true
required:
- name
- namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ properties:
download_source_id:
type: string
nullable: true
unenroll_timeout:
type: number
nullable: true
inactivity_timeout:
type: number
nullable: true
required:
- name
- namespace
5 changes: 5 additions & 0 deletions x-pack/plugins/fleet/common/types/models/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface NewAgentPolicy {
is_managed?: boolean; // Optional when creating a policy
monitoring_enabled?: MonitoringType;
unenroll_timeout?: number;
inactivity_timeout?: number;
is_preconfigured?: boolean;
// Nullable to allow user to reset to default outputs
data_output_id?: string | null;
Expand Down Expand Up @@ -165,4 +166,8 @@ export interface FleetServerPolicy {
* Auto unenroll any Elastic Agents which have not checked in for this many seconds
*/
unenroll_timeout?: number;
/**
* Mark agents as inactive if they have not checked in for this many seconds
*/
inactivity_timeout?: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { AgentPolicyPackageBadge } from '../../../../components';
import { AgentPolicyDeleteProvider } from '../agent_policy_delete_provider';
import type { ValidationResults } from '../agent_policy_validation';

import { policyHasFleetServer } from '../../../../services';
import { ExperimentalFeaturesService, policyHasFleetServer } from '../../../../services';

import {
useOutputOptions,
Expand Down Expand Up @@ -76,6 +76,8 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
'package_policies' in agentPolicy &&
agentPolicy?.package_policies?.some((packagePolicy) => packagePolicy.is_managed);

const { inactivityTimeout: inactivityTimeoutEnabled } = ExperimentalFeaturesService.get();

return (
<>
<EuiDescribedFormGroup
Expand Down Expand Up @@ -300,6 +302,48 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
/>
</EuiFormRow>
</EuiDescribedFormGroup>
{inactivityTimeoutEnabled && (
<EuiDescribedFormGroup
title={
<h4>
<FormattedMessage
id="xpack.fleet.agentPolicyForm.inactivityTimeoutLabel"
defaultMessage="Inactivity timeout"
/>
</h4>
}
description={
<FormattedMessage
id="xpack.fleet.agentPolicyForm.inactivityTimeoutDescription"
defaultMessage="An optional timeout in seconds. If provided, an agent will automatically change to inactive status and be filtered out of the agents list."
/>
}
>
<EuiFormRow
fullWidth
error={
touchedFields.inactivity_timeout && validation.inactivity_timeout
? validation.inactivity_timeout
: null
}
isInvalid={Boolean(touchedFields.inactivity_timeout && validation.inactivity_timeout)}
>
<EuiFieldNumber
fullWidth
disabled={agentPolicy.is_managed === true}
value={agentPolicy.inactivity_timeout || ''}
min={0}
onChange={(e) => {
updateAgentPolicy({
inactivity_timeout: e.target.value ? Number(e.target.value) : 0,
});
}}
isInvalid={Boolean(touchedFields.inactivity_timeout && validation.inactivity_timeout)}
onBlur={() => setTouchedFields({ ...touchedFields, inactivity_timeout: true })}
/>
</EuiFormRow>
</EuiDescribedFormGroup>
)}
<EuiDescribedFormGroup
title={
<h4>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,12 @@ describe('Agent Policy form validation', () => {
});
expect(result.unenroll_timeout).toBeDefined();
});
it('should return error when agentPolicy has negative inactivity timeout', () => {
const result = agentPolicyFormValidation({
namespace: 'Default',
name: 'policy',
inactivity_timeout: -1,
});
expect(result.inactivity_timeout).toBeDefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ export const agentPolicyFormValidation = (
errors.unenroll_timeout = [
<FormattedMessage
id="xpack.fleet.agentPolicyForm.unenrollTimeoutMinValueErrorMessage"
defaultMessage="Timeout must be greater than zero."
defaultMessage="Unenroll timeout must be greater than zero."
/>,
];
}

if (agentPolicy.inactivity_timeout && agentPolicy.inactivity_timeout < 0) {
errors.inactivity_timeout = [
<FormattedMessage
id="xpack.fleet.agentPolicyForm.inactivityTimeoutMinValueErrorMessage"
defaultMessage="Inactivity timeout must be greater than zero."
/>,
];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>(
// eslint-disable-next-line @typescript-eslint/naming-convention
unenroll_timeout,
// eslint-disable-next-line @typescript-eslint/naming-convention
inactivity_timeout,
// eslint-disable-next-line @typescript-eslint/naming-convention
data_output_id,
// eslint-disable-next-line @typescript-eslint/naming-convention
monitoring_output_id,
Expand All @@ -100,6 +102,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>(
namespace,
monitoring_enabled,
unenroll_timeout,
inactivity_timeout,
data_output_id,
monitoring_output_id,
download_source_id,
Expand Down Expand Up @@ -145,6 +148,7 @@ export const SettingsView = memo<{ agentPolicy: AgentPolicy }>(
'namespace',
'monitoring_enabled',
'unenroll_timeout',
'inactivity_timeout',
'data_output_id',
'monitoring_output_id',
'download_source_id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,8 @@ const TestComponent = (props: any) => (

describe('SearchAndFilterBar', () => {
beforeAll(() => {
ExperimentalFeaturesService.init({
createPackagePolicyMultiPageLayout: true,
packageVerification: true,
showDevtoolsRequest: false,
diagnosticFileUploadEnabled: false,
});
// @ts-ignore - prevents us needing to mock the entire service
ExperimentalFeaturesService.init({});
});
it('should show no Actions button when no agent is selected', async () => {
const selectedAgents: Agent[] = [];
Expand Down
9 changes: 3 additions & 6 deletions x-pack/plugins/fleet/public/mock/create_test_renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import type { ScopedHistory } from '@kbn/core/public';
import { CoreScopedHistory } from '@kbn/core/public';

import { allowedExperimentalValues } from '../../common/experimental_features';

import { FleetAppContext } from '../applications/fleet/app';
import { IntegrationsAppContext } from '../applications/integrations/app';
import type { FleetConfigType } from '../plugin';
Expand Down Expand Up @@ -64,12 +66,7 @@ export const createFleetTestRendererMock = (): TestRenderer => {
const history = createMemoryHistory({ initialEntries: [basePath] });
const mountHistory = new CoreScopedHistory(history, basePath);

ExperimentalFeaturesService.init({
createPackagePolicyMultiPageLayout: true,
packageVerification: true,
showDevtoolsRequest: false,
diagnosticFileUploadEnabled: false,
});
ExperimentalFeaturesService.init(allowedExperimentalValues);

const HookWrapper = memo(({ children }) => {
return (
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/saved_objects/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ const getSavedObjectTypes = (
is_default_fleet_server: { type: 'boolean' },
status: { type: 'keyword' },
unenroll_timeout: { type: 'integer' },
inactivity_timeout: { type: 'integer' },
Copy link
Member

Choose a reason for hiding this comment

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

Q: Are we planning to query this field? If not, I'd add index: false to avoid mapping field explosion in the .kibana index.

Suggested change
inactivity_timeout: { type: 'integer' },
inactivity_timeout: { type: 'integer', index: false },

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey, thanks for the comment, I'll be searching and aggregating on it in a following PR 👍

Copy link
Member

Choose a reason for hiding this comment

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

Awesome! Thanks for confirming! Changes LGTM then

updated_at: { type: 'date' },
updated_by: { type: 'keyword' },
revision: { type: 'integer' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ describe('comparePreconfiguredPolicyToCurrent', () => {
name: 'Test policy',
description: 'This is a test policy',
unenroll_timeout: 60,
inactivity_timeout: 60,
is_preconfigured: true,
status: 'active',
is_managed: true,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/fleet/server/types/models/agent_policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const AgentPolicyBaseSchema = {
is_default: schema.maybe(schema.boolean()),
is_default_fleet_server: schema.maybe(schema.boolean()),
unenroll_timeout: schema.maybe(schema.number({ min: 0 })),
inactivity_timeout: schema.maybe(schema.number({ min: 0 })),
monitoring_enabled: schema.maybe(
schema.arrayOf(
schema.oneOf([schema.literal(dataTypes.Logs), schema.literal(dataTypes.Metrics)])
Expand Down