mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Fleet] Send Agentless API resources (#206042)](https://github.com/elastic/kibana/pull/206042) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Amir Ben Nun","email":"34831306+amirbenun@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-01-19T10:52:10Z","message":"[Fleet] Send Agentless API resources (#206042)\n\n## Summary\n\nConclude agentless policy resources and send them to the Agentless API\non the creation request.\n- Resolves: https://github.com/elastic/kibana/issues/203371","sha":"fec5d743984b384d48ceb077e1f840cb98b5a16e","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","backport missing","Team:Fleet","v9.0.0","Team:Cloud Security","backport:prev-minor","ci:project-deploy-security"],"title":"[Fleet] Send Agentless API resources","number":206042,"url":"https://github.com/elastic/kibana/pull/206042","mergeCommit":{"message":"[Fleet] Send Agentless API resources (#206042)\n\n## Summary\n\nConclude agentless policy resources and send them to the Agentless API\non the creation request.\n- Resolves: https://github.com/elastic/kibana/issues/203371","sha":"fec5d743984b384d48ceb077e1f840cb98b5a16e"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/206042","number":206042,"mergeCommit":{"message":"[Fleet] Send Agentless API resources (#206042)\n\n## Summary\n\nConclude agentless policy resources and send them to the Agentless API\non the creation request.\n- Resolves: https://github.com/elastic/kibana/issues/203371","sha":"fec5d743984b384d48ceb077e1f840cb98b5a16e"}}]}] BACKPORT--> --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
3fd9c4d886
commit
747e766250
16 changed files with 591 additions and 3 deletions
|
@ -9578,6 +9578,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
@ -10113,6 +10129,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
data_output_id:
|
||||
nullable: true
|
||||
type: string
|
||||
|
@ -10292,6 +10324,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
@ -10846,6 +10894,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
@ -11380,6 +11444,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
@ -11914,6 +11994,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
data_output_id:
|
||||
nullable: true
|
||||
type: string
|
||||
|
@ -12093,6 +12189,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
@ -12647,6 +12759,22 @@ paths:
|
|||
- name
|
||||
- enabled
|
||||
type: array
|
||||
agentless:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
resources:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
requests:
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
cpu:
|
||||
type: string
|
||||
memory:
|
||||
type: string
|
||||
agents:
|
||||
type: number
|
||||
data_output_id:
|
||||
|
|
|
@ -481,6 +481,7 @@
|
|||
"agent_features",
|
||||
"agent_features.enabled",
|
||||
"agent_features.name",
|
||||
"agentless",
|
||||
"data_output_id",
|
||||
"description",
|
||||
"download_source_id",
|
||||
|
@ -601,6 +602,7 @@
|
|||
"agent_features",
|
||||
"agent_features.enabled",
|
||||
"agent_features.name",
|
||||
"agentless",
|
||||
"data_output_id",
|
||||
"description",
|
||||
"download_source_id",
|
||||
|
|
|
@ -1624,6 +1624,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"agentless": {
|
||||
"dynamic": false,
|
||||
"properties": {}
|
||||
},
|
||||
"data_output_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
|
@ -1994,6 +1998,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"agentless": {
|
||||
"dynamic": false,
|
||||
"properties": {}
|
||||
},
|
||||
"data_output_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
|
|
|
@ -105,7 +105,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
|
|||
"file": "6b65ae5899b60ebe08656fd163ea532e557d3c98",
|
||||
"file-upload-usage-collection-telemetry": "06e0a8c04f991e744e09d03ab2bd7f86b2088200",
|
||||
"fileShare": "5be52de1747d249a221b5241af2838264e19aaa1",
|
||||
"fleet-agent-policies": "908765a33aab066f4ac09446686b2d884aceed00",
|
||||
"fleet-agent-policies": "4a5c6477d2a61121e95ea9865ed1403a28c38706",
|
||||
"fleet-fleet-server-host": "69be15f6b6f2a2875ad3c7050ddea7a87f505417",
|
||||
"fleet-message-signing-keys": "93421f43fed2526b59092a4e3c65d64bc2266c0f",
|
||||
"fleet-package-policies": "0206c20f27286787b91814a2e7872f06dc1e8e47",
|
||||
|
@ -121,7 +121,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": "c1818c4119259908875b4c777ae62b11ba0585cd",
|
||||
"ingest-agent-policies": "57ebfb047cf0b81c6fa0ceed8586fa7199c7c5e2",
|
||||
"ingest-download-sources": "279a68147e62e4d8858c09ad1cf03bd5551ce58d",
|
||||
"ingest-outputs": "daafff49255ab700e07491376fe89f04fc998b91",
|
||||
"ingest-package-policies": "60d43f475f91417d14d9df05476acf2e63e99435",
|
||||
|
|
|
@ -44,6 +44,7 @@ export interface NewAgentPolicy {
|
|||
keep_monitoring_alive?: boolean | null;
|
||||
supports_agentless?: boolean | null;
|
||||
global_data_tags?: GlobalDataTag[];
|
||||
agentless?: AgentlessPolicy;
|
||||
monitoring_pprof_enabled?: boolean;
|
||||
monitoring_http?: {
|
||||
enabled?: boolean;
|
||||
|
@ -63,6 +64,15 @@ export interface NewAgentPolicy {
|
|||
};
|
||||
}
|
||||
|
||||
export interface AgentlessPolicy {
|
||||
resources?: {
|
||||
requests?: {
|
||||
memory?: string;
|
||||
cpu?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface GlobalDataTag {
|
||||
name: string;
|
||||
value: string | number;
|
||||
|
|
|
@ -201,6 +201,12 @@ export interface DeploymentsModesAgentless extends DeploymentsModesDefault {
|
|||
organization?: string;
|
||||
division?: string;
|
||||
team?: string;
|
||||
resources?: {
|
||||
requests: {
|
||||
cpu: string;
|
||||
memory: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
export interface DeploymentsModes {
|
||||
agentless: DeploymentsModesAgentless;
|
||||
|
|
|
@ -125,6 +125,24 @@ describe('useSetupTechnology', () => {
|
|||
inactivity_timeout: 3600,
|
||||
};
|
||||
|
||||
const packageInfoWithoutAgentless = {
|
||||
policy_templates: [
|
||||
{
|
||||
name: 'cspm',
|
||||
title: 'Template 1',
|
||||
description: '',
|
||||
deployment_modes: {
|
||||
default: {
|
||||
enabled: true,
|
||||
},
|
||||
agentless: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
] as RegistryPolicyTemplate[],
|
||||
} as PackageInfo;
|
||||
|
||||
const packageInfoMock = {
|
||||
policy_templates: [
|
||||
{
|
||||
|
@ -140,6 +158,40 @@ describe('useSetupTechnology', () => {
|
|||
organization: 'org',
|
||||
division: 'div',
|
||||
team: 'team',
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '256Mi',
|
||||
cpu: '100m',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'not-cspm',
|
||||
title: 'Template 2',
|
||||
description: '',
|
||||
deployment_modes: {
|
||||
default: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
] as RegistryPolicyTemplate[],
|
||||
} as PackageInfo;
|
||||
|
||||
const packageInfoWithoutResources = {
|
||||
policy_templates: [
|
||||
{
|
||||
name: 'cspm',
|
||||
title: 'Template 1',
|
||||
description: '',
|
||||
deployment_modes: {
|
||||
default: {
|
||||
enabled: true,
|
||||
},
|
||||
agentless: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -473,6 +525,14 @@ describe('useSetupTechnology', () => {
|
|||
{ name: 'division', value: 'div' },
|
||||
{ name: 'team', value: 'team' },
|
||||
],
|
||||
agentless: {
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '256Mi',
|
||||
cpu: '100m',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: true });
|
||||
});
|
||||
|
@ -488,6 +548,133 @@ describe('useSetupTechnology', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should have agentless resources section on the request when creating agentless policy with resources', async () => {
|
||||
(useConfig as MockFn).mockReturnValue({
|
||||
agentless: {
|
||||
enabled: true,
|
||||
api: {
|
||||
url: 'https://agentless.api.url',
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
(useStartServices as MockFn).mockReturnValue({
|
||||
cloud: {
|
||||
isCloudEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSetupTechnology({
|
||||
setNewAgentPolicy,
|
||||
newAgentPolicy: newAgentPolicyMock,
|
||||
updateAgentPolicies: updateAgentPoliciesMock,
|
||||
setSelectedPolicyTab: setSelectedPolicyTabMock,
|
||||
packagePolicy: packagePolicyMock,
|
||||
packageInfo: packageInfoMock,
|
||||
updatePackagePolicy: updatePackagePolicyMock,
|
||||
})
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(setNewAgentPolicy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
agentless: {
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '256Mi',
|
||||
cpu: '100m',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have agentless section on the request when creating agentless policy without resources', async () => {
|
||||
(useConfig as MockFn).mockReturnValue({
|
||||
agentless: {
|
||||
enabled: true,
|
||||
api: {
|
||||
url: 'https://agentless.api.url',
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
(useStartServices as MockFn).mockReturnValue({
|
||||
cloud: {
|
||||
isCloudEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSetupTechnology({
|
||||
setNewAgentPolicy,
|
||||
newAgentPolicy: newAgentPolicyMock,
|
||||
updateAgentPolicies: updateAgentPoliciesMock,
|
||||
setSelectedPolicyTab: setSelectedPolicyTabMock,
|
||||
packagePolicy: packagePolicyMock,
|
||||
packageInfo: packageInfoWithoutResources,
|
||||
updatePackagePolicy: updatePackagePolicyMock,
|
||||
})
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(setNewAgentPolicy).toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({
|
||||
agentless: {},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have agentless section on the request when creating policy with agentless disabled', async () => {
|
||||
(useConfig as MockFn).mockReturnValue({
|
||||
agentless: {
|
||||
enabled: true,
|
||||
api: {
|
||||
url: 'https://agentless.api.url',
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
(useStartServices as MockFn).mockReturnValue({
|
||||
cloud: {
|
||||
isCloudEnabled: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useSetupTechnology({
|
||||
setNewAgentPolicy,
|
||||
newAgentPolicy: newAgentPolicyMock,
|
||||
updateAgentPolicies: updateAgentPoliciesMock,
|
||||
setSelectedPolicyTab: setSelectedPolicyTabMock,
|
||||
packagePolicy: packagePolicyMock,
|
||||
packageInfo: packageInfoWithoutAgentless,
|
||||
updatePackagePolicy: updatePackagePolicyMock,
|
||||
})
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(setNewAgentPolicy).toHaveBeenCalledWith(
|
||||
expect.not.objectContaining({
|
||||
agentless: {},
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have global_data_tags with the integration team when creating agentless policy with global_data_tags', async () => {
|
||||
(useConfig as MockFn).mockReturnValue({
|
||||
agentless: {
|
||||
|
|
|
@ -129,6 +129,12 @@ export function useSetupTechnology({
|
|||
name: agentlessPolicyName,
|
||||
global_data_tags: getGlobaDataTags(packageInfo),
|
||||
};
|
||||
|
||||
const agentlessPolicy = getAgentlessPolicy(packageInfo);
|
||||
if (agentlessPolicy) {
|
||||
nextNewAgentlessPolicy.agentless = agentlessPolicy;
|
||||
}
|
||||
|
||||
setCurrentAgentPolicy(nextNewAgentlessPolicy);
|
||||
setNewAgentPolicy(nextNewAgentlessPolicy as NewAgentPolicy);
|
||||
updateAgentPolicies([nextNewAgentlessPolicy] as AgentPolicy[]);
|
||||
|
@ -204,3 +210,26 @@ const getGlobaDataTags = (packageInfo?: PackageInfo) => {
|
|||
},
|
||||
];
|
||||
};
|
||||
|
||||
const getAgentlessPolicy = (packageInfo?: PackageInfo) => {
|
||||
if (
|
||||
!packageInfo?.policy_templates &&
|
||||
!packageInfo?.policy_templates?.some((policy) => policy.deployment_modes)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const agentlessPolicyTemplate = packageInfo.policy_templates.find(
|
||||
(policy) => policy.deployment_modes
|
||||
);
|
||||
|
||||
// assumes that all the policy templates agentless deployments modes indentify have the same organization, division and team
|
||||
const agentlessInfo = agentlessPolicyTemplate?.deployment_modes?.agentless;
|
||||
|
||||
if (!agentlessInfo?.resources) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
resources: agentlessInfo.resources,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -246,6 +246,10 @@ export const getSavedObjectTypes = (
|
|||
advanced_settings: { type: 'flattened', index: false },
|
||||
supports_agentless: { type: 'boolean' },
|
||||
global_data_tags: { type: 'flattened', index: false },
|
||||
agentless: {
|
||||
dynamic: false,
|
||||
properties: {},
|
||||
},
|
||||
monitoring_pprof_enabled: { type: 'boolean', index: false },
|
||||
monitoring_http: { type: 'flattened', index: false },
|
||||
monitoring_diagnostics: { type: 'flattened', index: false },
|
||||
|
@ -313,6 +317,19 @@ export const getSavedObjectTypes = (
|
|||
},
|
||||
],
|
||||
},
|
||||
'6': {
|
||||
changes: [
|
||||
{
|
||||
type: 'mappings_addition',
|
||||
addedMappings: {
|
||||
agentless: {
|
||||
dynamic: false,
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
[AGENT_POLICY_SAVED_OBJECT_TYPE]: {
|
||||
|
@ -357,6 +374,10 @@ export const getSavedObjectTypes = (
|
|||
advanced_settings: { type: 'flattened', index: false },
|
||||
supports_agentless: { type: 'boolean' },
|
||||
global_data_tags: { type: 'flattened', index: false },
|
||||
agentless: {
|
||||
dynamic: false,
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
modelVersions: {
|
||||
|
|
|
@ -809,6 +809,7 @@ class AgentPolicyService {
|
|||
'fleet_server_host_id',
|
||||
'supports_agentless',
|
||||
'global_data_tags',
|
||||
'agentless',
|
||||
'monitoring_pprof_enabled',
|
||||
'monitoring_http',
|
||||
'monitoring_diagnostics',
|
||||
|
|
|
@ -285,6 +285,119 @@ describe('Agentless Agent service', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should create agentless agent with resources', async () => {
|
||||
const returnValue = {
|
||||
id: 'mocked',
|
||||
regional_id: 'mocked',
|
||||
};
|
||||
|
||||
(axios as jest.MockedFunction<typeof axios>).mockResolvedValueOnce(returnValue);
|
||||
const soClient = getAgentPolicyCreateMock();
|
||||
// ignore unrelated unique name constraint
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
jest.spyOn(appContextService, 'getConfig').mockReturnValue({
|
||||
agentless: {
|
||||
enabled: true,
|
||||
api: {
|
||||
url: 'http://api.agentless.com',
|
||||
tls: {
|
||||
certificate: '/path/to/cert',
|
||||
key: '/path/to/key',
|
||||
ca: '/path/to/ca',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getCloud')
|
||||
.mockReturnValue({ isCloudEnabled: true, isServerlessEnabled: true } as any);
|
||||
jest
|
||||
.spyOn(appContextService, 'getKibanaVersion')
|
||||
.mockReturnValue('mocked-kibana-version-infinite');
|
||||
mockedListFleetServerHosts.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
id: 'mocked-fleet-server-id',
|
||||
host: 'http://fleetserver:8220',
|
||||
active: true,
|
||||
is_default: true,
|
||||
host_urls: ['http://fleetserver:8220'],
|
||||
},
|
||||
],
|
||||
} as any);
|
||||
mockedListEnrollmentApiKeys.mockResolvedValue({
|
||||
items: [
|
||||
{
|
||||
id: 'mocked-fleet-enrollment-token-id',
|
||||
policy_id: 'mocked-fleet-enrollment-policy-id',
|
||||
api_key: 'mocked-fleet-enrollment-api-key',
|
||||
},
|
||||
],
|
||||
} as any);
|
||||
|
||||
const createAgentlessAgentReturnValue = await agentlessAgentService.createAgentlessAgent(
|
||||
esClient,
|
||||
soClient,
|
||||
{
|
||||
id: 'mocked-agentless-agent-policy-id',
|
||||
name: 'agentless agent policy',
|
||||
namespace: 'default',
|
||||
supports_agentless: true,
|
||||
agentless: {
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '1Gi',
|
||||
cpu: '500m',
|
||||
},
|
||||
},
|
||||
},
|
||||
global_data_tags: [
|
||||
{
|
||||
name: 'organization',
|
||||
value: 'elastic',
|
||||
},
|
||||
{
|
||||
name: 'division',
|
||||
value: 'cloud',
|
||||
},
|
||||
{
|
||||
name: 'team',
|
||||
value: 'fleet',
|
||||
},
|
||||
],
|
||||
} as AgentPolicy
|
||||
);
|
||||
|
||||
expect(axios).toHaveBeenCalledTimes(1);
|
||||
expect(createAgentlessAgentReturnValue).toEqual(returnValue);
|
||||
expect(axios).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
fleet_token: 'mocked-fleet-enrollment-api-key',
|
||||
fleet_url: 'http://fleetserver:8220',
|
||||
policy_id: 'mocked-agentless-agent-policy-id',
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '1Gi',
|
||||
cpu: '500m',
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
owner: {
|
||||
org: 'elastic',
|
||||
division: 'cloud',
|
||||
team: 'fleet',
|
||||
},
|
||||
},
|
||||
},
|
||||
headers: expect.anything(),
|
||||
httpsAgent: expect.anything(),
|
||||
method: 'POST',
|
||||
url: 'http://api.agentless.com/api/v1/serverless/deployments',
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('should create agentless agent when no labels are given', async () => {
|
||||
const returnValue = {
|
||||
id: 'mocked',
|
||||
|
|
|
@ -110,6 +110,7 @@ class AgentlessAgentService {
|
|||
policy_id: policyId,
|
||||
fleet_url: fleetUrl,
|
||||
fleet_token: fleetToken,
|
||||
resources: agentlessAgentPolicy.agentless?.resources,
|
||||
labels,
|
||||
},
|
||||
method: 'POST',
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
import type { GlobalDataTag } from '../../../common/types';
|
||||
import type { AgentlessPolicy, GlobalDataTag } from '../../../common/types';
|
||||
|
||||
import { AgentPolicyBaseSchema } from './agent_policy';
|
||||
|
||||
|
@ -91,5 +91,56 @@ describe('AgentPolicyBaseSchema', () => {
|
|||
AgentPolicyBaseSchema.global_data_tags.validate(tags);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not throw an error if provided with empty agentless resources', () => {
|
||||
const agentless: AgentlessPolicy = {};
|
||||
|
||||
expect(() => {
|
||||
AgentPolicyBaseSchema.agentless.validate(agentless);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should not throw an error if provided with valid agentless resources', () => {
|
||||
const agentless: AgentlessPolicy = {
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '1Gi',
|
||||
cpu: '1',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
AgentPolicyBaseSchema.agentless.validate(agentless);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw an error if provided with invalid agentless memory', () => {
|
||||
const agentless: AgentlessPolicy = {
|
||||
resources: {
|
||||
requests: {
|
||||
memory: '1',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
AgentPolicyBaseSchema.agentless.validate(agentless);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('should throw an error if provided with invalid agentless CPU', () => {
|
||||
const agentless: AgentlessPolicy = {
|
||||
resources: {
|
||||
requests: {
|
||||
cpu: '1CPU',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
AgentPolicyBaseSchema.agentless.validate(agentless);
|
||||
}).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -39,6 +39,20 @@ function isInteger(n: number) {
|
|||
}
|
||||
}
|
||||
|
||||
const memoryRegex = /^\d+(Mi|Gi)$/;
|
||||
function validateMemory(s: string) {
|
||||
if (!memoryRegex.test(s)) {
|
||||
return 'Invalid memory format';
|
||||
}
|
||||
}
|
||||
|
||||
const cpuRegex = /^(\d+m|\d+(\.\d+)?)$/;
|
||||
function validateCPU(s: string) {
|
||||
if (!cpuRegex.test(s)) {
|
||||
return 'Invalid CPU format';
|
||||
}
|
||||
}
|
||||
|
||||
export const AgentPolicyBaseSchema = {
|
||||
id: schema.maybe(schema.string()),
|
||||
space_ids: schema.maybe(schema.arrayOf(schema.string())),
|
||||
|
@ -102,6 +116,20 @@ export const AgentPolicyBaseSchema = {
|
|||
}
|
||||
)
|
||||
),
|
||||
agentless: schema.maybe(
|
||||
schema.object({
|
||||
resources: schema.maybe(
|
||||
schema.object({
|
||||
requests: schema.maybe(
|
||||
schema.object({
|
||||
memory: schema.maybe(schema.string({ validate: validateMemory })),
|
||||
cpu: schema.maybe(schema.string({ validate: validateCPU })),
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
})
|
||||
),
|
||||
monitoring_pprof_enabled: schema.maybe(schema.boolean()),
|
||||
monitoring_http: schema.maybe(
|
||||
schema.object({
|
||||
|
|
|
@ -17,6 +17,7 @@ import type {
|
|||
KafkaConnectionTypeType,
|
||||
AgentUpgradeDetails,
|
||||
OutputPreset,
|
||||
AgentlessPolicy,
|
||||
} from '../../common/types';
|
||||
import type { AgentType, FleetServerAgentComponent } from '../../common/types/models';
|
||||
|
||||
|
@ -65,6 +66,7 @@ export interface AgentPolicySOAttributes {
|
|||
agents?: number;
|
||||
overrides?: any | null;
|
||||
global_data_tags?: Array<{ name: string; value: string | number }>;
|
||||
agentless?: AgentlessPolicy;
|
||||
version?: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ const getAgentPolicyDataForUpdate = (
|
|||
'download_source_id',
|
||||
'fleet_server_host_id',
|
||||
'global_data_tags',
|
||||
'agentless',
|
||||
'has_fleet_server',
|
||||
'id',
|
||||
'inactivity_timeout',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue