mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Fleet] Add support_agentless property in agent policy schema and preconfiguration (#182709)
Closes https://github.com/elastic/kibana/issues/180377 ## Summary Add a new `support_agentless` property in agent policy and in preconfiguration; this property is only allowed when the environment has both `isServerless` set to `true` and `agentless` feature flag enabled, otherwise policy creation/update will throw error `supports_agentless is only allowed in serverless environments that support agentless feature`. No UI change is required for now as this property will be needed as part of a wider support to agentless policies. ## Testing ### Serverless - Run serverless env configured for agentless following [this guide](https://docs.elastic.dev/security-solution/cloud-security/serverless/develop-for-kibana#agentless-local-set-up) - Make sure to have `agentless` feature flag enabled - Create an agent policy with `support_agentless` property: ``` POST kbn:/api/fleet/agent_policies { "name": "New agent policy", "namespace": "default", "supports_agentless": true } ``` - Update an existing agent policy with the new property: ``` PUT kbn:/api/fleet/agent_policies/<opolicy_id> { "name": "New agent policy", "supports_agentless": true } ``` - Create a preconfigured agent policy in kibana.dev.yml, and verify it that it's correct via `GET kbn:/api/fleet/agent_policies`: ``` xpack.fleet.agentPolicies: [ { "name": "Agentless Policy", "id": "agentless", "is_managed": true, "namespace": "default", "supports_agentless": true, }, ] ``` - Note that if `agentless` feature flag is disabled, any of the above will throw an error. ### Stateful Spin up a stateful env and verify that all of the previous commands fail with `400` and above error message. ### Checklist - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
d87e04dad2
commit
eb5e329382
14 changed files with 336 additions and 12 deletions
|
@ -182,7 +182,7 @@ export const HASH_TO_VERSION_MAP = {
|
|||
'infrastructure-monitoring-log-view|c50526fc6040c5355ed027d34d05b35c': '10.0.0',
|
||||
'infrastructure-ui-source|3d1b76c39bfb2cc8296b024d73854724': '10.0.0',
|
||||
'ingest_manager_settings|b91ffb075799c78ffd7dbd51a279c8c9': '10.1.0',
|
||||
'ingest-agent-policies|0fd93cd11c019b118e93a9157c22057b': '10.1.0',
|
||||
'ingest-agent-policies|0ab9774bc7728d0c0f37d841570f2872': '10.2.0',
|
||||
'ingest-download-sources|0b0f6828e59805bd07a650d80817c342': '10.0.0',
|
||||
'ingest-outputs|b1237f7fdc0967709e75d65d208ace05': '10.6.0',
|
||||
'ingest-package-policies|ca63c4c5a946704f045803a6b975dbc6': '10.9.0',
|
||||
|
|
|
@ -510,6 +510,7 @@
|
|||
"revision",
|
||||
"schema_version",
|
||||
"status",
|
||||
"supports_agentless",
|
||||
"unenroll_timeout",
|
||||
"updated_at",
|
||||
"updated_by"
|
||||
|
|
|
@ -1711,6 +1711,9 @@
|
|||
"status": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"supports_agentless": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"unenroll_timeout": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
|
|
@ -108,7 +108,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"infra-custom-dashboards": "1a5994f2e05bb8a1609825ddbf5012f77c5c67f3",
|
||||
"infrastructure-monitoring-log-view": "5f86709d3c27aed7a8379153b08ee5d3d90d77f5",
|
||||
"infrastructure-ui-source": "113182d6895764378dfe7fa9fa027244f3a457c4",
|
||||
"ingest-agent-policies": "d2ee0bf36a512c2ac744b0def1c822b7880f1f83",
|
||||
"ingest-agent-policies": "803dc27e106440c41e8f3c3d8ee8bbb0821bcde2",
|
||||
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
|
||||
"ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91",
|
||||
"ingest-package-policies": "d63e091b2b3cf2eecaa46ae2533bdd5214a983fc",
|
||||
|
|
|
@ -7602,6 +7602,10 @@
|
|||
"type": "object",
|
||||
"description": "Advanced settings stored in the agent policy, e.g. agent_limits_go_max_procs",
|
||||
"nullable": true
|
||||
},
|
||||
"supports_agentless": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates whether the agent policy supports agentless integrations. Only allowed in a serverless environment."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
|
@ -4894,6 +4894,11 @@ components:
|
|||
Advanced settings stored in the agent policy, e.g.
|
||||
agent_limits_go_max_procs
|
||||
nullable: true
|
||||
supports_agentless:
|
||||
type: boolean
|
||||
description: >-
|
||||
Indicates whether the agent policy supports agentless integrations.
|
||||
Only allowed in a serverless environment.
|
||||
required:
|
||||
- id
|
||||
- status
|
||||
|
|
|
@ -73,6 +73,9 @@ properties:
|
|||
type: object
|
||||
description: Advanced settings stored in the agent policy, e.g. agent_limits_go_max_procs
|
||||
nullable: true
|
||||
supports_agentless:
|
||||
type: boolean
|
||||
description: Indicates whether the agent policy supports agentless integrations. Only allowed in a serverless environment.
|
||||
required:
|
||||
- id
|
||||
- status
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface NewAgentPolicy {
|
|||
overrides?: { [key: string]: any } | null;
|
||||
advanced_settings?: { [key: string]: any } | null;
|
||||
keep_monitoring_alive?: boolean | null;
|
||||
supports_agentless?: boolean | null;
|
||||
}
|
||||
|
||||
// SO definition for this type is declared in server/types/interfaces
|
||||
|
|
|
@ -164,6 +164,7 @@ export const getSavedObjectTypes = (
|
|||
overrides: { type: 'flattened', index: false },
|
||||
keep_monitoring_alive: { type: 'boolean' },
|
||||
advanced_settings: { type: 'flattened', index: false },
|
||||
supports_agentless: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
migrations: {
|
||||
|
@ -184,6 +185,16 @@ export const getSavedObjectTypes = (
|
|||
},
|
||||
],
|
||||
},
|
||||
'2': {
|
||||
changes: [
|
||||
{
|
||||
type: 'mappings_addition',
|
||||
addedMappings: {
|
||||
supports_agentless: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[OUTPUT_SAVED_OBJECT_TYPE]: {
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
PackagePolicyRestrictionRelatedError,
|
||||
FleetUnauthorizedError,
|
||||
HostedAgentPolicyRestrictionRelatedError,
|
||||
AgentPolicyInvalidError,
|
||||
} from '../errors';
|
||||
import type {
|
||||
AgentPolicy,
|
||||
|
@ -114,7 +115,7 @@ function getAgentPolicyCreateMock() {
|
|||
return soClient;
|
||||
}
|
||||
let mockedLogger: jest.Mocked<Logger>;
|
||||
describe('agent policy', () => {
|
||||
describe('Agent policy', () => {
|
||||
beforeEach(() => {
|
||||
mockedLogger = loggerMock.create();
|
||||
mockedAppContextService.getLogger.mockReturnValue(mockedLogger);
|
||||
|
@ -228,6 +229,74 @@ describe('agent policy', () => {
|
|||
new FleetUnauthorizedError('Tamper protection requires Platinum license')
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw AgentPolicyInvalidError if support_agentless is defined in stateful', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: false } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: false } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
await expect(
|
||||
agentPolicyService.create(soClient, esClient, {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
new AgentPolicyInvalidError(
|
||||
'supports_agentless is only allowed in serverless environments that support the agentless feature'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw AgentPolicyInvalidError if agentless feature flag is disabled in serverless', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: false } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
await expect(
|
||||
agentPolicyService.create(soClient, esClient, {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
new AgentPolicyInvalidError(
|
||||
'supports_agentless is only allowed in serverless environments that support the agentless feature'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('should not throw error if support_agentless is set if agentless feature flag is set in serverless', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: true } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
await expect(
|
||||
agentPolicyService.create(soClient, esClient, {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Add more test coverage to `get` service method
|
||||
|
@ -781,6 +850,93 @@ describe('agent policy', () => {
|
|||
})
|
||||
).rejects.toThrowError(new Error('Cannot enable Agent Tamper Protection: reason'));
|
||||
});
|
||||
|
||||
it('should throw AgentPolicyInvalidError if support_agentless is defined in stateful', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: false } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: false } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
soClient.get.mockResolvedValue({
|
||||
attributes: {},
|
||||
id: 'test-id',
|
||||
type: 'mocked',
|
||||
references: [],
|
||||
});
|
||||
|
||||
await expect(
|
||||
agentPolicyService.update(soClient, esClient, 'test-id', {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
new AgentPolicyInvalidError(
|
||||
'supports_agentless is only allowed in serverless environments that support the agentless feature'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw AgentPolicyInvalidError if agentless flag is disabled in serverless', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: false } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
soClient.get.mockResolvedValue({
|
||||
attributes: {},
|
||||
id: 'test-id',
|
||||
type: 'mocked',
|
||||
references: [],
|
||||
});
|
||||
|
||||
await expect(
|
||||
agentPolicyService.update(soClient, esClient, 'test-id', {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
new AgentPolicyInvalidError(
|
||||
'supports_agentless is only allowed in serverless environments that support the agentless feature'
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('should not throw in serverless if support_agentless is set and agentless feature flag is set', async () => {
|
||||
jest
|
||||
.spyOn(appContextService, 'getExperimentalFeatures')
|
||||
.mockReturnValue({ agentless: true } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
soClient.get.mockResolvedValue({
|
||||
attributes: {},
|
||||
id: 'test-id',
|
||||
type: 'mocked',
|
||||
references: [],
|
||||
});
|
||||
|
||||
await expect(
|
||||
agentPolicyService.update(soClient, esClient, 'test-id', {
|
||||
name: 'test',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
})
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deployPolicy', () => {
|
||||
|
|
|
@ -71,13 +71,12 @@ import type {
|
|||
FetchAllAgentPoliciesOptions,
|
||||
FetchAllAgentPolicyIdsOptions,
|
||||
FleetServerPolicy,
|
||||
Installation,
|
||||
Output,
|
||||
PackageInfo,
|
||||
} from '../../common/types';
|
||||
import {
|
||||
AgentPolicyNameExistsError,
|
||||
AgentPolicyNotFoundError,
|
||||
AgentPolicyInvalidError,
|
||||
FleetError,
|
||||
FleetUnauthorizedError,
|
||||
HostedAgentPolicyRestrictionRelatedError,
|
||||
|
@ -88,6 +87,8 @@ import type { FullAgentConfigMap } from '../../common/types/models/agent_cm';
|
|||
|
||||
import { fullAgentConfigMapToYaml } from '../../common/services/agent_cm_to_yaml';
|
||||
|
||||
import { appContextService } from '.';
|
||||
|
||||
import { mapAgentPolicySavedObjectToAgentPolicy } from './agent_policies/utils';
|
||||
|
||||
import {
|
||||
|
@ -102,7 +103,6 @@ import { incrementPackagePolicyCopyName } from './package_policies';
|
|||
import { outputService } from './output';
|
||||
import { agentPolicyUpdateEventHandler } from './agent_policy_update';
|
||||
import { escapeSearchQueryPhrase, normalizeKuery } from './saved_object';
|
||||
import { appContextService } from './app_context';
|
||||
import { getFullAgentPolicy, validateOutputForPolicy } from './agent_policies';
|
||||
import { auditLoggingService } from './audit_logging';
|
||||
import { licenseService } from './license';
|
||||
|
@ -317,6 +317,8 @@ class AgentPolicyService {
|
|||
);
|
||||
}
|
||||
|
||||
this.checkAgentless(agentPolicy);
|
||||
|
||||
await this.requireUniqueName(soClient, agentPolicy);
|
||||
|
||||
await validateOutputForPolicy(soClient, agentPolicy);
|
||||
|
@ -581,6 +583,7 @@ class AgentPolicyService {
|
|||
}
|
||||
}
|
||||
this.checkTamperProtectionLicense(agentPolicy);
|
||||
this.checkAgentless(agentPolicy);
|
||||
await this.checkForValidUninstallToken(agentPolicy, id);
|
||||
|
||||
if (agentPolicy?.is_protected && !policyHasEndpointSecurity(existingAgentPolicy)) {
|
||||
|
@ -653,6 +656,7 @@ class AgentPolicyService {
|
|||
'monitoring_output_id',
|
||||
'download_source_id',
|
||||
'fleet_server_host_id',
|
||||
'supports_agentless',
|
||||
]),
|
||||
...newAgentPolicyProps,
|
||||
},
|
||||
|
@ -1474,17 +1478,26 @@ class AgentPolicyService {
|
|||
}
|
||||
}
|
||||
}
|
||||
private checkAgentless(agentPolicy: Partial<NewAgentPolicy>) {
|
||||
const cloudSetup = appContextService.getCloud();
|
||||
if (
|
||||
(!cloudSetup?.isServerlessEnabled ||
|
||||
!appContextService.getExperimentalFeatures().agentless) &&
|
||||
agentPolicy?.supports_agentless !== undefined
|
||||
) {
|
||||
throw new AgentPolicyInvalidError(
|
||||
'supports_agentless is only allowed in serverless environments that support the agentless feature'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const agentPolicyService = new AgentPolicyService();
|
||||
|
||||
// TODO: remove unused parameters
|
||||
export async function addPackageToAgentPolicy(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
packageToInstall: Installation,
|
||||
agentPolicy: AgentPolicy,
|
||||
defaultOutput: Output,
|
||||
packageInfo: PackageInfo,
|
||||
packagePolicyName?: string,
|
||||
packagePolicyId?: string | number,
|
||||
|
|
|
@ -22,6 +22,8 @@ import type { AgentPolicy, NewPackagePolicy, Output, DownloadSource } from '../t
|
|||
|
||||
import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../constants';
|
||||
|
||||
import { appContextService } from './app_context';
|
||||
|
||||
import * as agentPolicy from './agent_policy';
|
||||
|
||||
import {
|
||||
|
@ -300,6 +302,10 @@ jest.mock('./app_context', () => ({
|
|||
generateTokenForPolicyId: jest.fn(),
|
||||
}),
|
||||
getExternalCallbacks: jest.fn(),
|
||||
getCloud: jest.fn(),
|
||||
getExperimentalFeatures: jest.fn().mockReturnValue({
|
||||
agentless: false,
|
||||
}),
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -461,7 +467,7 @@ describe('policy preconfiguration', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should install prelease packages if needed', async () => {
|
||||
it('should install prerelease packages if needed', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
|
@ -845,6 +851,7 @@ describe('policy preconfiguration', () => {
|
|||
it('should not create a policy and throw an error if package is not installed for an unknown reason', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
||||
const policies: PreconfiguredAgentPolicy[] = [
|
||||
{
|
||||
name: 'Test policy',
|
||||
|
@ -875,6 +882,113 @@ describe('policy preconfiguration', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should return a non fatal error if support_agentless is defined in stateful', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({
|
||||
agentless: true,
|
||||
} as any);
|
||||
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: false } as any);
|
||||
|
||||
const policies: PreconfiguredAgentPolicy[] = [
|
||||
{
|
||||
name: 'Test policy',
|
||||
namespace: 'default',
|
||||
id: 'test-id',
|
||||
supports_agentless: true,
|
||||
package_policies: [],
|
||||
},
|
||||
];
|
||||
|
||||
const { nonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies(
|
||||
soClient,
|
||||
esClient,
|
||||
policies,
|
||||
[{ name: 'CANNOT_MATCH', version: 'x.y.z' }],
|
||||
mockDefaultOutput,
|
||||
mockDefaultDownloadService,
|
||||
DEFAULT_SPACE_ID
|
||||
);
|
||||
// @ts-ignore-next-line
|
||||
expect(nonFatalErrors[0].error.toString()).toEqual(
|
||||
'FleetError: `supports_agentless` is only allowed in serverless environments that support the agentless feature'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not return an error if support_agentless is defined in serverless and agentless is enabled', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({
|
||||
agentless: true,
|
||||
} as any);
|
||||
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const policies: PreconfiguredAgentPolicy[] = [
|
||||
{
|
||||
name: 'Test policy',
|
||||
namespace: 'default',
|
||||
id: 'test-id',
|
||||
supports_agentless: true,
|
||||
package_policies: [],
|
||||
},
|
||||
];
|
||||
|
||||
const { policies: resPolicies, nonFatalErrors } =
|
||||
await ensurePreconfiguredPackagesAndPolicies(
|
||||
soClient,
|
||||
esClient,
|
||||
policies,
|
||||
[{ name: 'CANNOT_MATCH', version: 'x.y.z' }],
|
||||
mockDefaultOutput,
|
||||
mockDefaultDownloadService,
|
||||
DEFAULT_SPACE_ID
|
||||
);
|
||||
expect(nonFatalErrors.length).toBe(0);
|
||||
expect(resPolicies[0].id).toEqual('test-id');
|
||||
});
|
||||
|
||||
it('should return an error if agentless feature flag is disabled on serverless', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({
|
||||
agentless: false,
|
||||
} as any);
|
||||
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isServerlessEnabled: true } as any);
|
||||
|
||||
const policies: PreconfiguredAgentPolicy[] = [
|
||||
{
|
||||
name: 'Test policy',
|
||||
namespace: 'default',
|
||||
id: 'test-id',
|
||||
supports_agentless: true,
|
||||
package_policies: [],
|
||||
},
|
||||
];
|
||||
|
||||
const { nonFatalErrors } = await ensurePreconfiguredPackagesAndPolicies(
|
||||
soClient,
|
||||
esClient,
|
||||
policies,
|
||||
[{ name: 'CANNOT_MATCH', version: 'x.y.z' }],
|
||||
mockDefaultOutput,
|
||||
mockDefaultDownloadService,
|
||||
DEFAULT_SPACE_ID
|
||||
);
|
||||
// @ts-ignore-next-line
|
||||
expect(nonFatalErrors[0].error.toString()).toEqual(
|
||||
'FleetError: `supports_agentless` is only allowed in serverless environments that support the agentless feature'
|
||||
);
|
||||
});
|
||||
|
||||
it('should not attempt to recreate or modify an agent policy if its ID is unchanged', async () => {
|
||||
const soClient = getPutPreconfiguredPackagesMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
|
|
@ -59,6 +59,7 @@ export async function ensurePreconfiguredPackagesAndPolicies(
|
|||
spaceId: string
|
||||
): Promise<PreconfigurationResult> {
|
||||
const logger = appContextService.getLogger();
|
||||
const cloudSetup = appContextService.getCloud();
|
||||
|
||||
// Validate configured packages to ensure there are no version conflicts
|
||||
const packageNames = groupBy(packages, (pkg) => pkg.name);
|
||||
|
@ -160,6 +161,19 @@ export async function ensurePreconfiguredPackagesAndPolicies(
|
|||
);
|
||||
}
|
||||
|
||||
if (
|
||||
(!cloudSetup?.isServerlessEnabled ||
|
||||
!appContextService.getExperimentalFeatures().agentless) &&
|
||||
preconfiguredAgentPolicy?.supports_agentless !== undefined
|
||||
) {
|
||||
throw new FleetError(
|
||||
i18n.translate('xpack.fleet.preconfiguration.support_agentless', {
|
||||
defaultMessage:
|
||||
'`supports_agentless` is only allowed in serverless environments that support the agentless feature',
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const { created, policy } = await agentPolicyService.ensurePreconfiguredAgentPolicy(
|
||||
soClient,
|
||||
esClient,
|
||||
|
@ -372,9 +386,7 @@ async function addPreconfiguredPolicyPackages(
|
|||
await addPackageToAgentPolicy(
|
||||
soClient,
|
||||
esClient,
|
||||
installedPackage,
|
||||
agentPolicy,
|
||||
defaultOutput,
|
||||
packageInfo,
|
||||
name,
|
||||
id,
|
||||
|
|
|
@ -83,6 +83,7 @@ export const AgentPolicyBaseSchema = {
|
|||
)
|
||||
),
|
||||
...getSettingsAPISchema('AGENT_POLICY_ADVANCED_SETTINGS'),
|
||||
supports_agentless: schema.maybe(schema.boolean({ defaultValue: false })),
|
||||
};
|
||||
|
||||
export const NewAgentPolicySchema = schema.object({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue