Skip to content
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
324 changes: 324 additions & 0 deletions oas_docs/bundle.json

Large diffs are not rendered by default.

324 changes: 324 additions & 0 deletions oas_docs/bundle.serverless.json

Large diffs are not rendered by default.

216 changes: 216 additions & 0 deletions oas_docs/output/kibana.serverless.yaml

Large diffs are not rendered by default.

216 changes: 216 additions & 0 deletions oas_docs/output/kibana.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions x-pack/platform/plugins/shared/fleet/common/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export class FleetActionsClientError extends FleetError {}
export class UninstallTokenError extends FleetError {}

export class AgentRequestInvalidError extends FleetError {}
export class OutputInvalidError extends FleetError {}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ export function getDefaultFleetServerpolicyId(spaceId?: string) {
export function policyHasFleetServer(
agentPolicy: Pick<AgentPolicy, 'package_policies' | 'has_fleet_server'>
) {
if (!agentPolicy.package_policies) {
return false;
}
return (
agentPolicy.package_policies?.some((p) => p.package?.name === FLEET_SERVER_PACKAGE) ||
!!agentPolicy.has_fleet_server
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ describe('getAllowedOutputTypesForAgentPolicy', () => {
expect(res).toEqual(['elasticsearch']);
});

it('should return only elasticsearch for an agent policy with Fleet Server not yet installed', () => {
const res = getAllowedOutputTypesForAgentPolicy({
has_fleet_server: true,
} as any);

expect(res).toEqual(['elasticsearch']);
});

it('should return only elasticsearch for an agentless agent policy', () => {
const res = getAllowedOutputTypesForAgentPolicy({ supports_agentless: true } as any);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ const sameClusterRestrictedPackages = [
*/
export function getAllowedOutputTypesForAgentPolicy(agentPolicy: Partial<AgentPolicy>): string[] {
const isRestrictedToSameClusterES =
agentPolicy.package_policies &&
agentPolicy.package_policies.some(
(p) => p.package?.name && sameClusterRestrictedPackages.includes(p.package?.name)
);
agentPolicy.has_fleet_server ||
(agentPolicy.package_policies &&
agentPolicy.package_policies.some(
(p) => p.package?.name && sameClusterRestrictedPackages.includes(p.package?.name)
));

if (isRestrictedToSameClusterES) {
return [outputType.Elasticsearch];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import { useState, useCallback, useEffect, useMemo } from 'react';
import { i18n } from '@kbn/i18n';

import { OutputInvalidError } from '../../../../../../common/errors';
import { getDefaultFleetServerpolicyId } from '../../../../../../common/services/agent_policies_helpers';
import type { useComboInput, useInput, useSwitchInput } from '../../../hooks';
import {
sendCreateAgentPolicy,
sendCreateAgentPolicyForRq,
sendGetOneAgentPolicy,
useFleetStatus,
useStartServices,
Expand Down Expand Up @@ -115,23 +116,40 @@ export const useQuickStartCreateForm = (): QuickStartCreateForm => {
if (existingPolicy.data?.item) {
setFleetServerPolicyId(existingPolicy.data?.item.id);
} else {
const createPolicyResponse = await sendCreateAgentPolicy(
const createPolicyResponse = await sendCreateAgentPolicyForRq(
quickStartFleetServerPolicyFields,
{
withSysMonitoring: true,
}
);
setFleetServerPolicyId(createPolicyResponse.data?.item.id);
setFleetServerPolicyId(createPolicyResponse.item.id);
}

setStatus('success');
}
} catch (err) {
notifications.toasts.addError(err, {
title: i18n.translate('xpack.fleet.fleetServerSetup.errorAddingFleetServerHostTitle', {
defaultMessage: 'Error adding Fleet Server host',
}),
});
if (err?.attributes?.type === OutputInvalidError.name) {
notifications.toasts.addError(err, {
title: i18n.translate(
'xpack.fleet.fleetServerSetup.errorCreatingFleetServerPolicyTitle',
{
defaultMessage: 'Error creating a Fleet Server policy',
}
),
toastMessage: i18n.translate(
'xpack.fleet.fleetServerSetup.errorCreatingFleetServerPolicyMessage',
{
defaultMessage:
'Fleet Server policy creation failed as your default output is not an elasticsearch output. Use the advanced section to use an elasticsearch output to create that policy.',
}
),
});
} else {
notifications.toasts.addError(err, {
title: i18n.translate('xpack.fleet.fleetServerSetup.errorAddingFleetServerHostTitle', {
defaultMessage: 'Error adding Fleet Server host',
}),
});
}

setStatus('error');
setError(err.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function useOutputOptions(agentPolicy: Partial<NewAgentPolicy | AgentPoli
licenseService.hasAtLeast(LICENCE_FOR_PER_POLICY_OUTPUT) ||
policyHasFleetServer(agentPolicy as AgentPolicy) ||
policyHasSyntheticsIntegration(agentPolicy as AgentPolicy);

const allowedOutputTypes = useMemo(
() => getAllowedOutputTypesForAgentPolicy(agentPolicy as AgentPolicy),
[agentPolicy]
Expand Down Expand Up @@ -146,13 +147,21 @@ export function useOutputOptions(agentPolicy: Partial<NewAgentPolicy | AgentPoli
];
}, [outputsRequest, isPolicyPerOutputAllowed]);

const dataOutputValueOfSelected = agentPolicy.data_output_id || DEFAULT_SELECT_VALUE;

return useMemo(
() => ({
dataOutputOptions,
monitoringOutputOptions,
dataOutputValueOfSelected,
isLoading: outputsRequest.isLoading,
}),
[dataOutputOptions, monitoringOutputOptions, outputsRequest.isLoading]
[
dataOutputOptions,
dataOutputValueOfSelected,
monitoringOutputOptions,
outputsRequest.isLoading,
]
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =

const {
dataOutputOptions,
dataOutputValueOfSelected,
monitoringOutputOptions,
isLoading: isLoadingOptions,
} = useOutputOptions(agentPolicy);
Expand Down Expand Up @@ -657,7 +658,7 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> =
>
<EuiSuperSelect
disabled={disabled || isManagedPolicy}
valueOfSelected={agentPolicy.data_output_id || DEFAULT_SELECT_VALUE}
valueOfSelected={dataOutputValueOfSelected}
fullWidth
isLoading={isLoadingOptions}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { i18n } from '@kbn/i18n';

import { useSpaceSettingsContext } from '../../../../../hooks/use_space_settings_context';
import type { AgentPolicy, NewAgentPolicy } from '../../../types';
import { sendCreateAgentPolicy, useStartServices, useAuthz } from '../../../hooks';
import { useStartServices, useAuthz, sendCreateAgentPolicyForRq } from '../../../hooks';
import { generateNewAgentPolicyWithDefaults } from '../../../../../../common/services/generate_new_agent_policy';

import { agentPolicyFormValidation } from '.';
Expand All @@ -48,7 +48,7 @@ export const AgentPolicyCreateInlineForm: React.FunctionComponent<Props> = ({
isFleetServerPolicy,
agentPolicyName,
}) => {
const { docLinks } = useStartServices();
const { docLinks, notifications } = useStartServices();
const authz = useAuthz();
const [touchedFields, setTouchedFields] = useState<{ [key: string]: boolean }>({});

Expand Down Expand Up @@ -83,17 +83,20 @@ export const AgentPolicyCreateInlineForm: React.FunctionComponent<Props> = ({
const createAgentPolicy = useCallback(async () => {
try {
setIsLoading(true);
const resp = await sendCreateAgentPolicy(newAgentPolicy, { withSysMonitoring });
if (resp.error) throw resp.error;
if (resp.data) {
updateAgentPolicy(resp.data.item);
}
const data = await sendCreateAgentPolicyForRq(newAgentPolicy, { withSysMonitoring });

updateAgentPolicy(data.item);
} catch (e) {
notifications.toasts.addError(e, {
title: i18n.translate('xpack.fleet.agentPolicyCreateInline.errorTitle', {
defaultMessage: 'Error creating agent policy',
}),
});
updateAgentPolicy(null, mapError(e));
} finally {
setIsLoading(false);
}
}, [newAgentPolicy, withSysMonitoring, updateAgentPolicy]);
}, [newAgentPolicy, withSysMonitoring, updateAgentPolicy, notifications.toasts]);

function mapError(e: { statusCode: number }): JSX.Element | undefined {
switch (e.statusCode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@ export const sendGetOneAgentPolicy = (agentPolicyId: string) => {
});
};

export const sendCreateAgentPolicyForRq = (
body: CreateAgentPolicyRequest['body'],
{ withSysMonitoring }: { withSysMonitoring: boolean } = { withSysMonitoring: false }
) => {
return sendRequestForRq<CreateAgentPolicyResponse>({
path: agentPolicyRouteService.getCreatePath(),
method: 'post',
body: JSON.stringify(body),
query: withSysMonitoring ? { sys_monitoring: true } : {},
version: API_VERSIONS.public.v1,
});
};

/**
* @deprecated use sendCreateAgentPolicyForRq instead
*/
export const sendCreateAgentPolicy = (
body: CreateAgentPolicyRequest['body'],
{ withSysMonitoring }: { withSysMonitoring: boolean } = { withSysMonitoring: false }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
AgentlessPolicyExistsRequestError,
PackageInvalidDeploymentMode,
PackagePolicyContentPackageError,
OutputInvalidError,
} from '.';

type IngestErrorHandler = (
Expand Down Expand Up @@ -154,6 +155,13 @@ const getHTTPResponseCode = (error: FleetError): number => {
return 400; // Bad Request
};

function shouldRespondWithErrorType(error: FleetError) {
if (error instanceof OutputInvalidError) {
return true;
}
return false;
}

export function fleetErrorToResponseOptions(error: IngestErrorHandlerParams['error']) {
const logger = appContextService.getLogger();
// our "expected" errors
Expand All @@ -164,6 +172,7 @@ export function fleetErrorToResponseOptions(error: IngestErrorHandlerParams['err
statusCode: getHTTPResponseCode(error),
body: {
message: error.message,
...(shouldRespondWithErrorType(error) ? { attributes: { type: error.name } } : {}),
...(error.attributes && { attributes: error.attributes }),
},
};
Expand Down
6 changes: 4 additions & 2 deletions x-pack/platform/plugins/shared/fleet/server/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export {
} from './handlers';

export { isESClientError } from './utils';
export { FleetError as FleetError } from '../../common/errors';
export {
FleetError as FleetError,
OutputInvalidError as OutputInvalidError,
} from '../../common/errors';

export class RegistryError extends FleetError {}
export class RegistryConnectionError extends RegistryError {}
Expand Down Expand Up @@ -109,7 +112,6 @@ export class FleetNotFoundError<TMeta = unknown> extends FleetError<TMeta> {}
export class FleetTooManyRequestsError extends FleetError {}

export class OutputUnauthorizedError extends FleetError {}
export class OutputInvalidError extends FleetError {}
export class OutputLicenceError extends FleetError {}
export class DownloadSourceError extends FleetError {}
export class DeleteUnenrolledAgentsPreconfiguredError extends FleetError {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const genericErrorResponse = () =>
{
statusCode: schema.maybe(schema.number()),
error: schema.maybe(schema.string()),
errorType: schema.maybe(schema.string()),
message: schema.string(),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export async function validateOutputForPolicy(
allowedOutputTypeForPolicy: string[] = Object.values(outputType)
) {
if (
Object.keys(existingData).length !== 0 &&
newData.data_output_id === existingData.data_output_id &&
newData.monitoring_output_id === existingData.monitoring_output_id
) {
Expand All @@ -66,7 +67,15 @@ export async function validateOutputForPolicy(
allowedOutputTypeForPolicy.length !== Object.values(outputType).length;

if (isOutputTypeRestricted) {
const dataOutput = await getDataOutputForAgentPolicy(soClient, data);
const dataOutput = await getDataOutputForAgentPolicy(soClient, data).catch((err) => {
if (err instanceof OutputNotFoundError) {
return;
}
throw err;
});
if (!dataOutput) {
return;
}
if (!allowedOutputTypeForPolicy.includes(dataOutput.type)) {
throw new OutputInvalidError(
`Output of type "${dataOutput.type}" is not usable with policy "${data.name}".`
Expand Down Expand Up @@ -116,7 +125,15 @@ export async function validateAgentPolicyOutputForIntegration(
allowedOutputTypeForPolicy.length !== Object.values(outputType).length;

if (isOutputTypeRestricted) {
const dataOutput = await getDataOutputForAgentPolicy(soClient, agentPolicy);
const dataOutput = await getDataOutputForAgentPolicy(soClient, agentPolicy).catch((err) => {
if (err instanceof OutputNotFoundError) {
return;
}
throw err;
});
if (!dataOutput) {
return;
}
if (!allowedOutputTypeForPolicy.includes(dataOutput.type)) {
if (isNewPackagePolicy) {
throw new OutputInvalidError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ class AgentPolicyService {
user?: AuthenticatedUser;
authorizationHeader?: HTTPAuthorizationHeader | null;
skipDeploy?: boolean;
hasFleetServer?: boolean;
} = {}
): Promise<AgentPolicy> {
const savedObjectType = await getAgentPolicySavedObjectType();
Expand Down Expand Up @@ -412,12 +413,17 @@ class AgentPolicyService {
spaceId: soClient.getCurrentNamespace(),
namespace: agentPolicy.namespace,
});
const policyForOutputValidation = {
...agentPolicy,
has_fleet_server: options?.hasFleetServer,
};
await validateOutputForPolicy(
soClient,
agentPolicy,
policyForOutputValidation,
{},
getAllowedOutputTypesForAgentPolicy(agentPolicy)
getAllowedOutputTypesForAgentPolicy(policyForOutputValidation)
);

validateRequiredVersions(agentPolicy.name, agentPolicy.required_versions);

const newSo = await soClient.create<AgentPolicySOAttributes>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export async function createAgentPolicyWithPackages({
user,
id: agentPolicyId,
authorizationHeader,
hasFleetServer,
skipDeploy: true, // skip deploying the policy until package policies are added
});

Expand Down
Loading
Loading