mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* wip * wip * wip * wip * wip * wip * wip * wip * adds initial discovery rule for `include-vmargs elastic.apm.attach=true` * adds support for type descriptions * adding java_attacher_agent_version field * fixing some stuff * adding link to doc * adding internationalization * updating user description * fixing default version * setting to null when disabled * - fixes encoding and decoding discovery rules yaml - adds workaround for extra 'elasticsearch' field on integration policy updates - updates migration package version from 7.16.0 to 8.0.0-dev4 * addressing pr comments * fixing ci * fixing elements not visible while dragging * addressing PR changes * beta * adding tooltip back * addressing pr comments Co-authored-by: cauemarcondes <caue.marcondes@elastic.co> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Oliver Gupte <ogupte@users.noreply.github.com> Co-authored-by: cauemarcondes <caue.marcondes@elastic.co>
This commit is contained in:
parent
04fee5b82b
commit
848705a1f2
13 changed files with 1853 additions and 76 deletions
|
@ -8,7 +8,7 @@ import semverParse from 'semver/functions/parse';
|
|||
|
||||
export const POLICY_ELASTIC_AGENT_ON_CLOUD = 'policy-elastic-agent-on-cloud';
|
||||
|
||||
export const SUPPORTED_APM_PACKAGE_VERSION = '7.16.0';
|
||||
export const SUPPORTED_APM_PACKAGE_VERSION = '8.0.0-dev4'; // TODO update to just '8.0.0' once published
|
||||
|
||||
export function isPrereleaseVersion(version: string) {
|
||||
return semverParse(version)?.prerelease?.length ?? 0 > 0;
|
||||
|
|
|
@ -12,19 +12,29 @@ import {
|
|||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiCodeBlock,
|
||||
EuiTabbedContent,
|
||||
EuiBetaBadge,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { CreateAgentInstructions } from './agent_instructions_mappings';
|
||||
import React, { ComponentType } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
AgentRuntimeAttachmentProps,
|
||||
CreateAgentInstructions,
|
||||
} from './agent_instructions_mappings';
|
||||
import {
|
||||
Markdown,
|
||||
useKibana,
|
||||
} from '../../../../../../../src/plugins/kibana_react/public';
|
||||
import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent';
|
||||
import { AgentIcon } from '../../shared/agent_icon';
|
||||
import { NewPackagePolicy } from '../apm_policy_form/typings';
|
||||
import type {
|
||||
NewPackagePolicy,
|
||||
PackagePolicy,
|
||||
PackagePolicyEditExtensionComponentProps,
|
||||
} from '../apm_policy_form/typings';
|
||||
import { getCommands } from '../../../tutorial/config_agent/commands/get_commands';
|
||||
import { replaceTemplateStrings } from './replace_template_strings';
|
||||
import { renderMustache } from './render_mustache';
|
||||
|
||||
function AccordionButtonContent({
|
||||
agentName,
|
||||
|
@ -97,96 +107,175 @@ function TutorialConfigAgent({
|
|||
}
|
||||
|
||||
interface Props {
|
||||
policy: PackagePolicy;
|
||||
newPolicy: NewPackagePolicy;
|
||||
onChange: PackagePolicyEditExtensionComponentProps['onChange'];
|
||||
agentName: AgentName;
|
||||
title: string;
|
||||
variantId: string;
|
||||
createAgentInstructions: CreateAgentInstructions;
|
||||
AgentRuntimeAttachment?: ComponentType<AgentRuntimeAttachmentProps>;
|
||||
}
|
||||
|
||||
const StyledEuiAccordion = styled(EuiAccordion)`
|
||||
// This is an alternative fix suggested by the EUI team to fix drag elements inside EuiAccordion
|
||||
// This Issue tracks the fix on the Eui side https://github.com/elastic/eui/issues/3548#issuecomment-639041283
|
||||
.euiAccordion__childWrapper {
|
||||
transform: none;
|
||||
}
|
||||
`;
|
||||
|
||||
export function AgentInstructionsAccordion({
|
||||
policy,
|
||||
newPolicy,
|
||||
onChange,
|
||||
agentName,
|
||||
title,
|
||||
createAgentInstructions,
|
||||
variantId,
|
||||
AgentRuntimeAttachment,
|
||||
}: Props) {
|
||||
const docLinks = useKibana().services.docLinks;
|
||||
const vars = newPolicy?.inputs?.[0]?.vars;
|
||||
const apmServerUrl = vars?.url.value;
|
||||
const secretToken = vars?.secret_token.value;
|
||||
const steps = createAgentInstructions(apmServerUrl, secretToken);
|
||||
const stepsElements = steps.map(
|
||||
(
|
||||
{ title: stepTitle, textPre, textPost, customComponentName, commands },
|
||||
index
|
||||
) => {
|
||||
const commandBlock = commands
|
||||
? renderMustache({
|
||||
text: commands,
|
||||
docLinks,
|
||||
})
|
||||
: '';
|
||||
|
||||
return (
|
||||
<section key={index}>
|
||||
<EuiText>
|
||||
<h4>{stepTitle}</h4>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText color="subdued" size="s">
|
||||
{textPre && (
|
||||
<InstructionsContent
|
||||
markdown={renderMustache({ text: textPre, docLinks })}
|
||||
/>
|
||||
)}
|
||||
{commandBlock && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock isCopyable language="bash">
|
||||
{commandBlock}
|
||||
</EuiCodeBlock>
|
||||
</>
|
||||
)}
|
||||
{customComponentName === 'TutorialConfigAgent' && (
|
||||
<TutorialConfigAgent
|
||||
variantId={variantId}
|
||||
apmServerUrl={apmServerUrl}
|
||||
secretToken={secretToken}
|
||||
/>
|
||||
)}
|
||||
{customComponentName === 'TutorialConfigAgentRumScript' && (
|
||||
<TutorialConfigAgent
|
||||
variantId="js_script"
|
||||
apmServerUrl={apmServerUrl}
|
||||
secretToken={secretToken}
|
||||
/>
|
||||
)}
|
||||
{textPost && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<InstructionsContent
|
||||
markdown={renderMustache({ text: textPost, docLinks })}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const manualInstrumentationContent = (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
{stepsElements}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiAccordion
|
||||
<StyledEuiAccordion
|
||||
id={agentName}
|
||||
buttonContent={
|
||||
<AccordionButtonContent agentName={agentName} title={title} />
|
||||
}
|
||||
>
|
||||
<EuiSpacer />
|
||||
{steps.map(
|
||||
(
|
||||
{
|
||||
title: stepTitle,
|
||||
textPre,
|
||||
textPost,
|
||||
customComponentName,
|
||||
commands,
|
||||
},
|
||||
index
|
||||
) => {
|
||||
const commandBlock = replaceTemplateStrings(
|
||||
Array.isArray(commands) ? commands.join('\n') : commands || '',
|
||||
docLinks
|
||||
);
|
||||
return (
|
||||
<section key={index}>
|
||||
<EuiText>
|
||||
<h4>{stepTitle}</h4>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText color="subdued" size="s">
|
||||
{textPre && (
|
||||
<InstructionsContent
|
||||
markdown={replaceTemplateStrings(textPre, docLinks)}
|
||||
/>
|
||||
)}
|
||||
{commandBlock && (
|
||||
<>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiCodeBlock isCopyable language="bash">
|
||||
{commandBlock}
|
||||
</EuiCodeBlock>
|
||||
</>
|
||||
)}
|
||||
{customComponentName === 'TutorialConfigAgent' && (
|
||||
<TutorialConfigAgent
|
||||
variantId={variantId}
|
||||
apmServerUrl={apmServerUrl}
|
||||
secretToken={secretToken}
|
||||
/>
|
||||
)}
|
||||
{customComponentName === 'TutorialConfigAgentRumScript' && (
|
||||
<TutorialConfigAgent
|
||||
variantId="js_script"
|
||||
apmServerUrl={apmServerUrl}
|
||||
secretToken={secretToken}
|
||||
/>
|
||||
)}
|
||||
{textPost && (
|
||||
{AgentRuntimeAttachment ? (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiTabbedContent
|
||||
tabs={[
|
||||
{
|
||||
id: 'manual-instrumentation',
|
||||
name: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.manualInstrumentation',
|
||||
{ defaultMessage: 'Manual instrumentation' }
|
||||
),
|
||||
content: manualInstrumentationContent,
|
||||
},
|
||||
{
|
||||
id: 'auto-attachment',
|
||||
name: (
|
||||
<EuiFlexGroup
|
||||
justifyContent="flexStart"
|
||||
alignItems="baseline"
|
||||
gutterSize="s"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
{i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.autoAttachment',
|
||||
{ defaultMessage: 'Auto-Attachment' }
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBetaBadge
|
||||
label={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.betaBadge.label',
|
||||
{ defaultMessage: 'BETA' }
|
||||
)}
|
||||
tooltipContent={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.betaBadge.tooltipContent',
|
||||
{
|
||||
defaultMessage:
|
||||
'Auto-attachment for Java is not GA. Please help us by reporting any bugs.',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
),
|
||||
content: (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<InstructionsContent
|
||||
markdown={replaceTemplateStrings(textPost, docLinks)}
|
||||
<AgentRuntimeAttachment
|
||||
policy={policy}
|
||||
newPolicy={newPolicy}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</EuiText>
|
||||
<EuiSpacer />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
manualInstrumentationContent
|
||||
)}
|
||||
</EuiAccordion>
|
||||
</StyledEuiAccordion>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ComponentType } from 'react';
|
||||
import {
|
||||
createDotNetAgentInstructions,
|
||||
createDjangoAgentInstructions,
|
||||
|
@ -18,6 +19,18 @@ import {
|
|||
createRackAgentInstructions,
|
||||
} from '../../../../common/tutorial/instructions/apm_agent_instructions';
|
||||
import { AgentName } from '../../../../typings/es_schemas/ui/fields/agent';
|
||||
import { JavaRuntimeAttachment } from './runtime_attachment/supported_agents/java_runtime_attachment';
|
||||
import {
|
||||
NewPackagePolicy,
|
||||
PackagePolicy,
|
||||
PackagePolicyEditExtensionComponentProps,
|
||||
} from '../apm_policy_form/typings';
|
||||
|
||||
export interface AgentRuntimeAttachmentProps {
|
||||
policy: PackagePolicy;
|
||||
newPolicy: NewPackagePolicy;
|
||||
onChange: PackagePolicyEditExtensionComponentProps['onChange'];
|
||||
}
|
||||
|
||||
export type CreateAgentInstructions = (
|
||||
apmServerUrl?: string,
|
||||
|
@ -35,12 +48,14 @@ export const ApmAgentInstructionsMappings: Array<{
|
|||
title: string;
|
||||
variantId: string;
|
||||
createAgentInstructions: CreateAgentInstructions;
|
||||
AgentRuntimeAttachment?: ComponentType<AgentRuntimeAttachmentProps>;
|
||||
}> = [
|
||||
{
|
||||
agentName: 'java',
|
||||
title: 'Java',
|
||||
variantId: 'java',
|
||||
createAgentInstructions: createJavaAgentInstructions,
|
||||
AgentRuntimeAttachment: JavaRuntimeAttachment,
|
||||
},
|
||||
{
|
||||
agentName: 'rum-js',
|
||||
|
|
|
@ -21,19 +21,28 @@ interface Props {
|
|||
onChange: PackagePolicyEditExtensionComponentProps['onChange'];
|
||||
}
|
||||
|
||||
export function ApmAgents({ newPolicy }: Props) {
|
||||
export function ApmAgents({ policy, newPolicy, onChange }: Props) {
|
||||
return (
|
||||
<div>
|
||||
{ApmAgentInstructionsMappings.map(
|
||||
({ agentName, title, createAgentInstructions, variantId }) => (
|
||||
({
|
||||
agentName,
|
||||
title,
|
||||
createAgentInstructions,
|
||||
variantId,
|
||||
AgentRuntimeAttachment,
|
||||
}) => (
|
||||
<Fragment key={agentName}>
|
||||
<EuiPanel>
|
||||
<AgentInstructionsAccordion
|
||||
agentName={agentName}
|
||||
title={title}
|
||||
newPolicy={newPolicy}
|
||||
createAgentInstructions={createAgentInstructions}
|
||||
variantId={variantId}
|
||||
AgentRuntimeAttachment={AgentRuntimeAttachment}
|
||||
policy={policy}
|
||||
newPolicy={newPolicy}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</EuiPanel>
|
||||
<EuiSpacer />
|
||||
|
|
|
@ -10,12 +10,17 @@ import Mustache from 'mustache';
|
|||
|
||||
const TEMPLATE_TAGS = ['{', '}'];
|
||||
|
||||
export function replaceTemplateStrings(
|
||||
text: string,
|
||||
docLinks?: CoreStart['docLinks']
|
||||
) {
|
||||
Mustache.parse(text, TEMPLATE_TAGS);
|
||||
return Mustache.render(text, {
|
||||
export function renderMustache({
|
||||
text,
|
||||
docLinks,
|
||||
}: {
|
||||
text: string | string[];
|
||||
docLinks?: CoreStart['docLinks'];
|
||||
}) {
|
||||
const template = Array.isArray(text) ? text.join('\n') : text;
|
||||
|
||||
Mustache.parse(template, TEMPLATE_TAGS);
|
||||
return Mustache.render(template, {
|
||||
config: {
|
||||
docs: {
|
||||
base_url: docLinks?.ELASTIC_WEBSITE_URL,
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
EuiBadge,
|
||||
} from '@elastic/eui';
|
||||
import React from 'react';
|
||||
|
||||
export function DefaultDiscoveryRule() {
|
||||
return (
|
||||
<EuiPanel paddingSize="m" style={{ margin: 4 }} hasBorder={true}>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false} style={{ marginLeft: 100 }}>
|
||||
<EuiBadge color="danger">Exclude</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s">Everything else</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
EuiText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiBadge,
|
||||
EuiPanel,
|
||||
DraggableProvidedDragHandleProps,
|
||||
EuiButtonIcon,
|
||||
} from '@elastic/eui';
|
||||
import React, { useMemo } from 'react';
|
||||
import { Operation } from '.';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
order: number;
|
||||
operation: string;
|
||||
type: string;
|
||||
probe: string;
|
||||
providedDragHandleProps?: DraggableProvidedDragHandleProps;
|
||||
onDelete: (discoveryItemId: string) => void;
|
||||
onEdit: (discoveryItemId: string) => void;
|
||||
operationTypes: Operation[];
|
||||
}
|
||||
|
||||
export function DiscoveryRule({
|
||||
id,
|
||||
order,
|
||||
operation,
|
||||
type,
|
||||
probe,
|
||||
providedDragHandleProps,
|
||||
onDelete,
|
||||
onEdit,
|
||||
operationTypes,
|
||||
}: Props) {
|
||||
const operationTypesLabels = useMemo(() => {
|
||||
return operationTypes.reduce<{
|
||||
[operationValue: string]: {
|
||||
label: string;
|
||||
types: { [typeValue: string]: string };
|
||||
};
|
||||
}>((acc, current) => {
|
||||
return {
|
||||
...acc,
|
||||
[current.operation.value]: {
|
||||
label: current.operation.label,
|
||||
types: current.types.reduce((memo, { value, label }) => {
|
||||
return { ...memo, [value]: label };
|
||||
}, {}),
|
||||
},
|
||||
};
|
||||
}, {});
|
||||
}, [operationTypes]);
|
||||
return (
|
||||
<EuiPanel paddingSize="m" hasBorder={true}>
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<div
|
||||
{...providedDragHandleProps}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.discoveryRule.DragHandle',
|
||||
{ defaultMessage: 'Drag Handle' }
|
||||
)}
|
||||
>
|
||||
<EuiIcon type="grab" />
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup alignItems="baseline">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBadge>{order}</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiBadge color={operation === 'exclude' ? 'danger' : 'success'}>
|
||||
{operationTypesLabels[operation].label}
|
||||
</EuiBadge>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>
|
||||
<h4>{operationTypesLabels[operation].types[type]}</h4>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText>{probe}</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ marginLeft: 'auto' }}>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="pencil"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
onEdit(id);
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="trash"
|
||||
color="danger"
|
||||
onClick={() => {
|
||||
onDelete(id);
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
EuiFormFieldset,
|
||||
EuiSelect,
|
||||
EuiFieldText,
|
||||
EuiFormRow,
|
||||
EuiSuperSelect,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import {
|
||||
Operation,
|
||||
DISCOVERY_RULE_TYPE_ALL,
|
||||
STAGED_DISCOVERY_RULE_ID,
|
||||
} from '.';
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
onChangeOperation: (discoveryItemId: string) => void;
|
||||
operation: string;
|
||||
onChangeType: (discoveryItemId: string) => void;
|
||||
type: string;
|
||||
onChangeProbe: (discoveryItemId: string) => void;
|
||||
probe: string;
|
||||
onCancel: () => void;
|
||||
onSubmit: () => void;
|
||||
operationTypes: Operation[];
|
||||
}
|
||||
|
||||
export function EditDiscoveryRule({
|
||||
id,
|
||||
onChangeOperation,
|
||||
operation,
|
||||
onChangeType,
|
||||
type,
|
||||
onChangeProbe,
|
||||
probe,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
operationTypes,
|
||||
}: Props) {
|
||||
return (
|
||||
<EuiPanel paddingSize="m" hasBorder={true}>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFormFieldset
|
||||
legend={{
|
||||
children: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.editDisacoveryRule.operation',
|
||||
{ defaultMessage: 'Operation' }
|
||||
),
|
||||
}}
|
||||
>
|
||||
<EuiSelect
|
||||
options={operationTypes.map((item) => ({
|
||||
text: item.operation.label,
|
||||
value: item.operation.value,
|
||||
}))}
|
||||
value={operation}
|
||||
onChange={(e) => {
|
||||
onChangeOperation(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</EuiFormFieldset>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormFieldset
|
||||
legend={{
|
||||
children: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.editDisacoveryRule.type',
|
||||
{ defaultMessage: 'Type' }
|
||||
),
|
||||
}}
|
||||
>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
helpText={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.editRule.helpText',
|
||||
{
|
||||
defaultMessage: 'Choose from allowed parameters',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<EuiSuperSelect
|
||||
hasDividers
|
||||
fullWidth
|
||||
options={
|
||||
operationTypes
|
||||
.find(
|
||||
({ operation: definedOperation }) =>
|
||||
definedOperation.value === operation
|
||||
)
|
||||
?.types.map((item) => ({
|
||||
inputDisplay: item.label,
|
||||
value: item.value,
|
||||
dropdownDisplay: (
|
||||
<>
|
||||
<strong>{item.label}</strong>
|
||||
<EuiText size="s" color="subdued">
|
||||
<p>{item.description}</p>
|
||||
</EuiText>
|
||||
</>
|
||||
),
|
||||
})) ?? []
|
||||
}
|
||||
valueOfSelected={type}
|
||||
onChange={onChangeType}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFormFieldset>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
{type !== DISCOVERY_RULE_TYPE_ALL && (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormFieldset
|
||||
legend={{
|
||||
children: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.editDisacoveryRule.probe',
|
||||
{ defaultMessage: 'Probe' }
|
||||
),
|
||||
}}
|
||||
>
|
||||
<EuiFormRow
|
||||
fullWidth
|
||||
helpText={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.editRule.probeValue',
|
||||
{
|
||||
defaultMessage: 'Enter the probe value',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<EuiFieldText
|
||||
fullWidth
|
||||
value={probe}
|
||||
onChange={(e) => onChangeProbe(e.target.value)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFormFieldset>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
)}
|
||||
<EuiFlexGroup justifyContent="flexEnd">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonEmpty onClick={onCancel}>Cancel</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={onSubmit}
|
||||
fill
|
||||
disabled={type === DISCOVERY_RULE_TYPE_ALL ? false : probe === ''}
|
||||
>
|
||||
{id === STAGED_DISCOVERY_RULE_ID
|
||||
? i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.editRule.add',
|
||||
{ defaultMessage: 'Add' }
|
||||
)
|
||||
: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.editRule.save',
|
||||
{ defaultMessage: 'Save' }
|
||||
)}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* 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 {
|
||||
htmlIdGenerator,
|
||||
euiDragDropReorder,
|
||||
DropResult,
|
||||
EuiComboBoxOptionOption,
|
||||
} from '@elastic/eui';
|
||||
import React, { useState, useCallback, ReactNode } from 'react';
|
||||
import { RuntimeAttachment as RuntimeAttachmentStateless } from './runtime_attachment';
|
||||
|
||||
export const STAGED_DISCOVERY_RULE_ID = 'STAGED_DISCOVERY_RULE_ID';
|
||||
export const DISCOVERY_RULE_TYPE_ALL = 'all';
|
||||
|
||||
export interface IDiscoveryRule {
|
||||
operation: string;
|
||||
type: string;
|
||||
probe: string;
|
||||
}
|
||||
|
||||
export type IDiscoveryRuleList = Array<{
|
||||
id: string;
|
||||
discoveryRule: IDiscoveryRule;
|
||||
}>;
|
||||
|
||||
export interface RuntimeAttachmentSettings {
|
||||
enabled: boolean;
|
||||
discoveryRules: IDiscoveryRule[];
|
||||
version: string | null;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onChange?: (runtimeAttachmentSettings: RuntimeAttachmentSettings) => void;
|
||||
toggleDescription: ReactNode;
|
||||
discoveryRulesDescription: ReactNode;
|
||||
showUnsavedWarning?: boolean;
|
||||
initialIsEnabled?: boolean;
|
||||
initialDiscoveryRules?: IDiscoveryRule[];
|
||||
operationTypes: Operation[];
|
||||
selectedVersion: string;
|
||||
versions: string[];
|
||||
}
|
||||
|
||||
interface Option {
|
||||
value: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface Operation {
|
||||
operation: Option;
|
||||
types: Option[];
|
||||
}
|
||||
|
||||
const versionRegex = new RegExp(/^\d+\.\d+\.\d+$/);
|
||||
function validateVersion(version: string) {
|
||||
return versionRegex.test(version);
|
||||
}
|
||||
|
||||
export function RuntimeAttachment(props: Props) {
|
||||
const { initialDiscoveryRules = [], onChange = () => {} } = props;
|
||||
const [isEnabled, setIsEnabled] = useState(Boolean(props.initialIsEnabled));
|
||||
const [discoveryRuleList, setDiscoveryRuleList] =
|
||||
useState<IDiscoveryRuleList>(
|
||||
initialDiscoveryRules.map((discoveryRule) => ({
|
||||
id: generateId(),
|
||||
discoveryRule,
|
||||
}))
|
||||
);
|
||||
const [editDiscoveryRuleId, setEditDiscoveryRuleId] = useState<null | string>(
|
||||
null
|
||||
);
|
||||
const [version, setVersion] = useState(props.selectedVersion);
|
||||
const [versions, setVersions] = useState(props.versions);
|
||||
const [isValidVersion, setIsValidVersion] = useState(
|
||||
validateVersion(version)
|
||||
);
|
||||
|
||||
const onToggleEnable = useCallback(() => {
|
||||
const nextIsEnabled = !isEnabled;
|
||||
setIsEnabled(nextIsEnabled);
|
||||
onChange({
|
||||
enabled: nextIsEnabled,
|
||||
discoveryRules: nextIsEnabled
|
||||
? discoveryRuleList.map(({ discoveryRule }) => discoveryRule)
|
||||
: [],
|
||||
version: nextIsEnabled ? version : null,
|
||||
});
|
||||
}, [isEnabled, onChange, discoveryRuleList, version]);
|
||||
|
||||
const onDelete = useCallback(
|
||||
(discoveryRuleId: string) => {
|
||||
const filteredDiscoveryRuleList = discoveryRuleList.filter(
|
||||
({ id }) => id !== discoveryRuleId
|
||||
);
|
||||
setDiscoveryRuleList(filteredDiscoveryRuleList);
|
||||
onChange({
|
||||
enabled: isEnabled,
|
||||
discoveryRules: filteredDiscoveryRuleList.map(
|
||||
({ discoveryRule }) => discoveryRule
|
||||
),
|
||||
version,
|
||||
});
|
||||
},
|
||||
[isEnabled, discoveryRuleList, onChange, version]
|
||||
);
|
||||
|
||||
const onEdit = useCallback(
|
||||
(discoveryRuleId: string) => {
|
||||
const editingDiscoveryRule = discoveryRuleList.find(
|
||||
({ id }) => id === discoveryRuleId
|
||||
);
|
||||
if (editingDiscoveryRule) {
|
||||
const {
|
||||
discoveryRule: { operation, type, probe },
|
||||
} = editingDiscoveryRule;
|
||||
setStagedOperationText(operation);
|
||||
setStagedTypeText(type);
|
||||
setStagedProbeText(probe);
|
||||
setEditDiscoveryRuleId(discoveryRuleId);
|
||||
}
|
||||
},
|
||||
[discoveryRuleList]
|
||||
);
|
||||
|
||||
const [stagedOperationText, setStagedOperationText] = useState('');
|
||||
const [stagedTypeText, setStagedTypeText] = useState('');
|
||||
const [stagedProbeText, setStagedProbeText] = useState('');
|
||||
|
||||
const onChangeOperation = useCallback(
|
||||
(operationText: string) => {
|
||||
setStagedOperationText(operationText);
|
||||
const selectedOperationTypes = props.operationTypes.find(
|
||||
({ operation }) => operationText === operation.value
|
||||
);
|
||||
const selectedTypeAvailable = selectedOperationTypes?.types.some(
|
||||
({ value }) => stagedTypeText === value
|
||||
);
|
||||
if (!selectedTypeAvailable) {
|
||||
setStagedTypeText(selectedOperationTypes?.types[0].value ?? '');
|
||||
}
|
||||
},
|
||||
[props.operationTypes, stagedTypeText]
|
||||
);
|
||||
|
||||
const onChangeType = useCallback((operationText: string) => {
|
||||
setStagedTypeText(operationText);
|
||||
if (operationText === DISCOVERY_RULE_TYPE_ALL) {
|
||||
setStagedProbeText('');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onChangeProbe = useCallback((operationText: string) => {
|
||||
setStagedProbeText(operationText);
|
||||
}, []);
|
||||
|
||||
const onCancel = useCallback(() => {
|
||||
if (editDiscoveryRuleId === STAGED_DISCOVERY_RULE_ID) {
|
||||
onDelete(STAGED_DISCOVERY_RULE_ID);
|
||||
}
|
||||
setEditDiscoveryRuleId(null);
|
||||
}, [editDiscoveryRuleId, onDelete]);
|
||||
|
||||
const onSubmit = useCallback(() => {
|
||||
const editDiscoveryRuleIndex = discoveryRuleList.findIndex(
|
||||
({ id }) => id === editDiscoveryRuleId
|
||||
);
|
||||
const editDiscoveryRule = discoveryRuleList[editDiscoveryRuleIndex];
|
||||
const nextDiscoveryRuleList = [
|
||||
...discoveryRuleList.slice(0, editDiscoveryRuleIndex),
|
||||
{
|
||||
id:
|
||||
editDiscoveryRule.id === STAGED_DISCOVERY_RULE_ID
|
||||
? generateId()
|
||||
: editDiscoveryRule.id,
|
||||
discoveryRule: {
|
||||
operation: stagedOperationText,
|
||||
type: stagedTypeText,
|
||||
probe: stagedProbeText,
|
||||
},
|
||||
},
|
||||
...discoveryRuleList.slice(editDiscoveryRuleIndex + 1),
|
||||
];
|
||||
setDiscoveryRuleList(nextDiscoveryRuleList);
|
||||
setEditDiscoveryRuleId(null);
|
||||
onChange({
|
||||
enabled: isEnabled,
|
||||
discoveryRules: nextDiscoveryRuleList.map(
|
||||
({ discoveryRule }) => discoveryRule
|
||||
),
|
||||
version,
|
||||
});
|
||||
}, [
|
||||
isEnabled,
|
||||
editDiscoveryRuleId,
|
||||
stagedOperationText,
|
||||
stagedTypeText,
|
||||
stagedProbeText,
|
||||
discoveryRuleList,
|
||||
onChange,
|
||||
version,
|
||||
]);
|
||||
|
||||
const onAddRule = useCallback(() => {
|
||||
const firstOperationType = props.operationTypes[0];
|
||||
const operationText = firstOperationType.operation.value;
|
||||
const typeText = firstOperationType.types[0].value;
|
||||
const valueText = '';
|
||||
setStagedOperationText(operationText);
|
||||
setStagedTypeText(typeText);
|
||||
setStagedProbeText(valueText);
|
||||
const nextDiscoveryRuleList = [
|
||||
{
|
||||
id: STAGED_DISCOVERY_RULE_ID,
|
||||
discoveryRule: {
|
||||
operation: operationText,
|
||||
type: typeText,
|
||||
probe: valueText,
|
||||
},
|
||||
},
|
||||
...discoveryRuleList,
|
||||
];
|
||||
setDiscoveryRuleList(nextDiscoveryRuleList);
|
||||
setEditDiscoveryRuleId(STAGED_DISCOVERY_RULE_ID);
|
||||
}, [discoveryRuleList, props.operationTypes]);
|
||||
|
||||
const onDragEnd = useCallback(
|
||||
({ source, destination }: DropResult) => {
|
||||
if (source && destination) {
|
||||
const nextDiscoveryRuleList = euiDragDropReorder(
|
||||
discoveryRuleList,
|
||||
source.index,
|
||||
destination.index
|
||||
);
|
||||
setDiscoveryRuleList(nextDiscoveryRuleList);
|
||||
onChange({
|
||||
enabled: isEnabled,
|
||||
discoveryRules: nextDiscoveryRuleList.map(
|
||||
({ discoveryRule }) => discoveryRule
|
||||
),
|
||||
version,
|
||||
});
|
||||
}
|
||||
},
|
||||
[isEnabled, discoveryRuleList, onChange, version]
|
||||
);
|
||||
|
||||
function onChangeVersion(nextVersion?: string) {
|
||||
if (!nextVersion) {
|
||||
return;
|
||||
}
|
||||
setVersion(nextVersion);
|
||||
onChange({
|
||||
enabled: isEnabled,
|
||||
discoveryRules: isEnabled
|
||||
? discoveryRuleList.map(({ discoveryRule }) => discoveryRule)
|
||||
: [],
|
||||
version: nextVersion,
|
||||
});
|
||||
}
|
||||
|
||||
function onCreateNewVersion(
|
||||
newVersion: string,
|
||||
flattenedOptions: Array<EuiComboBoxOptionOption<string>>
|
||||
) {
|
||||
const normalizedNewVersion = newVersion.trim().toLowerCase();
|
||||
const isNextVersionValid = validateVersion(normalizedNewVersion);
|
||||
setIsValidVersion(isNextVersionValid);
|
||||
if (!normalizedNewVersion || !isNextVersionValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the option if it doesn't exist.
|
||||
if (
|
||||
flattenedOptions.findIndex(
|
||||
(option) => option.label.trim().toLowerCase() === normalizedNewVersion
|
||||
) === -1
|
||||
) {
|
||||
setVersions([...versions, newVersion]);
|
||||
}
|
||||
|
||||
onChangeVersion(newVersion);
|
||||
}
|
||||
|
||||
return (
|
||||
<RuntimeAttachmentStateless
|
||||
isEnabled={isEnabled}
|
||||
onToggleEnable={onToggleEnable}
|
||||
discoveryRuleList={discoveryRuleList}
|
||||
setDiscoveryRuleList={setDiscoveryRuleList}
|
||||
onDelete={onDelete}
|
||||
editDiscoveryRuleId={editDiscoveryRuleId}
|
||||
onEdit={onEdit}
|
||||
onChangeOperation={onChangeOperation}
|
||||
stagedOperationText={stagedOperationText}
|
||||
onChangeType={onChangeType}
|
||||
stagedTypeText={stagedTypeText}
|
||||
onChangeProbe={onChangeProbe}
|
||||
stagedProbeText={stagedProbeText}
|
||||
onCancel={onCancel}
|
||||
onSubmit={onSubmit}
|
||||
onAddRule={onAddRule}
|
||||
operationTypes={props.operationTypes}
|
||||
toggleDescription={props.toggleDescription}
|
||||
discoveryRulesDescription={props.discoveryRulesDescription}
|
||||
showUnsavedWarning={props.showUnsavedWarning}
|
||||
onDragEnd={onDragEnd}
|
||||
selectedVersion={version}
|
||||
versions={versions}
|
||||
onChangeVersion={(selectedVersions) => {
|
||||
const nextVersion: string | undefined = selectedVersions[0]?.label;
|
||||
const isNextVersionValid = validateVersion(nextVersion);
|
||||
setIsValidVersion(isNextVersionValid);
|
||||
onChangeVersion(nextVersion);
|
||||
}}
|
||||
onCreateNewVersion={onCreateNewVersion}
|
||||
isValidVersion={isValidVersion}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const generateId = htmlIdGenerator();
|
|
@ -0,0 +1,484 @@
|
|||
/*
|
||||
* 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 { Meta, Story } from '@storybook/react';
|
||||
import React, { useState } from 'react';
|
||||
import { RuntimeAttachment } from '.';
|
||||
import { JavaRuntimeAttachment } from './supported_agents/java_runtime_attachment';
|
||||
|
||||
const stories: Meta<{}> = {
|
||||
title: 'fleet/Runtime agent attachment',
|
||||
component: RuntimeAttachment,
|
||||
decorators: [
|
||||
(StoryComponent) => {
|
||||
return (
|
||||
<div style={{ width: 700 }}>
|
||||
<StoryComponent />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
],
|
||||
};
|
||||
export default stories;
|
||||
|
||||
const excludeOptions = [
|
||||
{ value: 'main', label: 'main class / jar name' },
|
||||
{ value: 'vmarg', label: 'vmarg' },
|
||||
{ value: 'user', label: 'user' },
|
||||
];
|
||||
const includeOptions = [{ value: 'all', label: 'All' }, ...excludeOptions];
|
||||
|
||||
const versions = ['1.27.1', '1.27.0', '1.26.0', '1.25.0'];
|
||||
|
||||
export const RuntimeAttachmentExample: Story = () => {
|
||||
const [runtimeAttachmentSettings, setRuntimeAttachmentSettings] = useState(
|
||||
{}
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<RuntimeAttachment
|
||||
operationTypes={[
|
||||
{
|
||||
operation: { value: 'include', label: 'Include' },
|
||||
types: includeOptions,
|
||||
},
|
||||
{
|
||||
operation: { value: 'exclude', label: 'Exclude' },
|
||||
types: excludeOptions,
|
||||
},
|
||||
]}
|
||||
onChange={(settings: any) => {
|
||||
setRuntimeAttachmentSettings(settings);
|
||||
}}
|
||||
toggleDescription="Attach the Java agent to running and starting Java applications."
|
||||
discoveryRulesDescription="For every running JVM, the discovery rules are evaluated in the order they are provided. The first matching rule determines the outcome. Learn more in the docs"
|
||||
showUnsavedWarning={true}
|
||||
initialIsEnabled={true}
|
||||
initialDiscoveryRules={[
|
||||
{
|
||||
operation: 'include',
|
||||
type: 'main',
|
||||
probe: 'java-opbeans-10010',
|
||||
},
|
||||
{
|
||||
operation: 'exclude',
|
||||
type: 'vmarg',
|
||||
probe: '10948653898867',
|
||||
},
|
||||
]}
|
||||
versions={versions}
|
||||
selectedVersion={versions[0]}
|
||||
/>
|
||||
<hr />
|
||||
<pre>{JSON.stringify(runtimeAttachmentSettings, null, 4)}</pre>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const JavaRuntimeAttachmentExample: Story = () => {
|
||||
return (
|
||||
<JavaRuntimeAttachment
|
||||
policy={policy}
|
||||
newPolicy={newPolicy}
|
||||
onChange={() => {}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const policy = {
|
||||
id: 'cc380ec5-d84e-40e1-885a-d706edbdc968',
|
||||
version: 'WzM0MzA2LDJd',
|
||||
name: 'apm-1',
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
policy_id: 'policy-elastic-agent-on-cloud',
|
||||
enabled: true,
|
||||
output_id: '',
|
||||
inputs: [
|
||||
{
|
||||
type: 'apm',
|
||||
policy_template: 'apmserver',
|
||||
enabled: true,
|
||||
streams: [],
|
||||
vars: {
|
||||
host: {
|
||||
value: 'localhost:8200',
|
||||
type: 'text',
|
||||
},
|
||||
url: {
|
||||
value: 'http://localhost:8200',
|
||||
type: 'text',
|
||||
},
|
||||
secret_token: {
|
||||
type: 'text',
|
||||
},
|
||||
api_key_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
enable_rum: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
anonymous_enabled: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
anonymous_allow_agent: {
|
||||
value: ['rum-js', 'js-base', 'iOS/swift'],
|
||||
type: 'text',
|
||||
},
|
||||
anonymous_allow_service: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
anonymous_rate_limit_event_limit: {
|
||||
value: 10,
|
||||
type: 'integer',
|
||||
},
|
||||
anonymous_rate_limit_ip_limit: {
|
||||
value: 10000,
|
||||
type: 'integer',
|
||||
},
|
||||
default_service_environment: {
|
||||
type: 'text',
|
||||
},
|
||||
rum_allow_origins: {
|
||||
value: ['"*"'],
|
||||
type: 'text',
|
||||
},
|
||||
rum_allow_headers: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
rum_response_headers: {
|
||||
type: 'yaml',
|
||||
},
|
||||
rum_library_pattern: {
|
||||
value: '"node_modules|bower_components|~"',
|
||||
type: 'text',
|
||||
},
|
||||
rum_exclude_from_grouping: {
|
||||
value: '"^/webpack"',
|
||||
type: 'text',
|
||||
},
|
||||
api_key_limit: {
|
||||
value: 100,
|
||||
type: 'integer',
|
||||
},
|
||||
max_event_bytes: {
|
||||
value: 307200,
|
||||
type: 'integer',
|
||||
},
|
||||
capture_personal_data: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
max_header_bytes: {
|
||||
value: 1048576,
|
||||
type: 'integer',
|
||||
},
|
||||
idle_timeout: {
|
||||
value: '45s',
|
||||
type: 'text',
|
||||
},
|
||||
read_timeout: {
|
||||
value: '3600s',
|
||||
type: 'text',
|
||||
},
|
||||
shutdown_timeout: {
|
||||
value: '30s',
|
||||
type: 'text',
|
||||
},
|
||||
write_timeout: {
|
||||
value: '30s',
|
||||
type: 'text',
|
||||
},
|
||||
max_connections: {
|
||||
value: 0,
|
||||
type: 'integer',
|
||||
},
|
||||
response_headers: {
|
||||
type: 'yaml',
|
||||
},
|
||||
expvar_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
tls_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
tls_certificate: {
|
||||
type: 'text',
|
||||
},
|
||||
tls_key: {
|
||||
type: 'text',
|
||||
},
|
||||
tls_supported_protocols: {
|
||||
value: ['TLSv1.0', 'TLSv1.1', 'TLSv1.2'],
|
||||
type: 'text',
|
||||
},
|
||||
tls_cipher_suites: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
tls_curve_types: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
tail_sampling_policies: {
|
||||
type: 'yaml',
|
||||
},
|
||||
tail_sampling_interval: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
config: {
|
||||
'apm-server': {
|
||||
value: {
|
||||
rum: {
|
||||
source_mapping: {
|
||||
metadata: [],
|
||||
},
|
||||
},
|
||||
agent_config: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
compiled_input: {
|
||||
'apm-server': {
|
||||
auth: {
|
||||
anonymous: {
|
||||
allow_agent: ['rum-js', 'js-base', 'iOS/swift'],
|
||||
allow_service: null,
|
||||
enabled: true,
|
||||
rate_limit: {
|
||||
event_limit: 10,
|
||||
ip_limit: 10000,
|
||||
},
|
||||
},
|
||||
api_key: {
|
||||
enabled: false,
|
||||
limit: 100,
|
||||
},
|
||||
secret_token: null,
|
||||
},
|
||||
capture_personal_data: true,
|
||||
idle_timeout: '45s',
|
||||
default_service_environment: null,
|
||||
'expvar.enabled': false,
|
||||
host: 'localhost:8200',
|
||||
max_connections: 0,
|
||||
max_event_size: 307200,
|
||||
max_header_size: 1048576,
|
||||
read_timeout: '3600s',
|
||||
response_headers: null,
|
||||
rum: {
|
||||
allow_headers: null,
|
||||
allow_origins: ['*'],
|
||||
enabled: true,
|
||||
exclude_from_grouping: '^/webpack',
|
||||
library_pattern: 'node_modules|bower_components|~',
|
||||
response_headers: null,
|
||||
},
|
||||
shutdown_timeout: '30s',
|
||||
write_timeout: '30s',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
package: {
|
||||
name: 'apm',
|
||||
title: 'Elastic APM',
|
||||
version: '7.16.0',
|
||||
},
|
||||
elasticsearch: {
|
||||
privileges: {
|
||||
cluster: ['cluster:monitor/main'],
|
||||
},
|
||||
},
|
||||
revision: 1,
|
||||
created_at: '2021-11-18T02:14:55.758Z',
|
||||
created_by: 'admin',
|
||||
updated_at: '2021-11-18T02:14:55.758Z',
|
||||
updated_by: 'admin',
|
||||
};
|
||||
|
||||
const newPolicy = {
|
||||
version: 'WzM0MzA2LDJd',
|
||||
name: 'apm-1',
|
||||
description: '',
|
||||
namespace: 'default',
|
||||
policy_id: 'policy-elastic-agent-on-cloud',
|
||||
enabled: true,
|
||||
output_id: '',
|
||||
package: {
|
||||
name: 'apm',
|
||||
title: 'Elastic APM',
|
||||
version: '8.0.0-dev2',
|
||||
},
|
||||
elasticsearch: {
|
||||
privileges: {
|
||||
cluster: ['cluster:monitor/main'],
|
||||
},
|
||||
},
|
||||
inputs: [
|
||||
{
|
||||
type: 'apm',
|
||||
policy_template: 'apmserver',
|
||||
enabled: true,
|
||||
vars: {
|
||||
host: {
|
||||
value: 'localhost:8200',
|
||||
type: 'text',
|
||||
},
|
||||
url: {
|
||||
value: 'http://localhost:8200',
|
||||
type: 'text',
|
||||
},
|
||||
secret_token: {
|
||||
type: 'text',
|
||||
},
|
||||
api_key_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
enable_rum: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
anonymous_enabled: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
anonymous_allow_agent: {
|
||||
value: ['rum-js', 'js-base', 'iOS/swift'],
|
||||
type: 'text',
|
||||
},
|
||||
anonymous_allow_service: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
anonymous_rate_limit_event_limit: {
|
||||
value: 10,
|
||||
type: 'integer',
|
||||
},
|
||||
anonymous_rate_limit_ip_limit: {
|
||||
value: 10000,
|
||||
type: 'integer',
|
||||
},
|
||||
default_service_environment: {
|
||||
type: 'text',
|
||||
},
|
||||
rum_allow_origins: {
|
||||
value: ['"*"'],
|
||||
type: 'text',
|
||||
},
|
||||
rum_allow_headers: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
rum_response_headers: {
|
||||
type: 'yaml',
|
||||
},
|
||||
rum_library_pattern: {
|
||||
value: '"node_modules|bower_components|~"',
|
||||
type: 'text',
|
||||
},
|
||||
rum_exclude_from_grouping: {
|
||||
value: '"^/webpack"',
|
||||
type: 'text',
|
||||
},
|
||||
api_key_limit: {
|
||||
value: 100,
|
||||
type: 'integer',
|
||||
},
|
||||
max_event_bytes: {
|
||||
value: 307200,
|
||||
type: 'integer',
|
||||
},
|
||||
capture_personal_data: {
|
||||
value: true,
|
||||
type: 'bool',
|
||||
},
|
||||
max_header_bytes: {
|
||||
value: 1048576,
|
||||
type: 'integer',
|
||||
},
|
||||
idle_timeout: {
|
||||
value: '45s',
|
||||
type: 'text',
|
||||
},
|
||||
read_timeout: {
|
||||
value: '3600s',
|
||||
type: 'text',
|
||||
},
|
||||
shutdown_timeout: {
|
||||
value: '30s',
|
||||
type: 'text',
|
||||
},
|
||||
write_timeout: {
|
||||
value: '30s',
|
||||
type: 'text',
|
||||
},
|
||||
max_connections: {
|
||||
value: 0,
|
||||
type: 'integer',
|
||||
},
|
||||
response_headers: {
|
||||
type: 'yaml',
|
||||
},
|
||||
expvar_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
tls_enabled: {
|
||||
value: false,
|
||||
type: 'bool',
|
||||
},
|
||||
tls_certificate: {
|
||||
type: 'text',
|
||||
},
|
||||
tls_key: {
|
||||
type: 'text',
|
||||
},
|
||||
tls_supported_protocols: {
|
||||
value: ['TLSv1.0', 'TLSv1.1', 'TLSv1.2'],
|
||||
type: 'text',
|
||||
},
|
||||
tls_cipher_suites: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
tls_curve_types: {
|
||||
value: [],
|
||||
type: 'text',
|
||||
},
|
||||
tail_sampling_policies: {
|
||||
type: 'yaml',
|
||||
},
|
||||
tail_sampling_interval: {
|
||||
type: 'text',
|
||||
},
|
||||
},
|
||||
config: {
|
||||
'apm-server': {
|
||||
value: {
|
||||
rum: {
|
||||
source_mapping: {
|
||||
metadata: [],
|
||||
},
|
||||
},
|
||||
agent_config: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
streams: [],
|
||||
},
|
||||
],
|
||||
};
|
|
@ -0,0 +1,235 @@
|
|||
/*
|
||||
* 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 {
|
||||
EuiCallOut,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButton,
|
||||
EuiDragDropContext,
|
||||
EuiDroppable,
|
||||
EuiDraggable,
|
||||
EuiIcon,
|
||||
DropResult,
|
||||
EuiComboBox,
|
||||
EuiComboBoxProps,
|
||||
EuiFormRow,
|
||||
} from '@elastic/eui';
|
||||
import React, { ReactNode } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { DiscoveryRule } from './discovery_rule';
|
||||
import { DefaultDiscoveryRule } from './default_discovery_rule';
|
||||
import { EditDiscoveryRule } from './edit_discovery_rule';
|
||||
import { IDiscoveryRuleList, Operation } from '.';
|
||||
|
||||
interface Props {
|
||||
isEnabled: boolean;
|
||||
onToggleEnable: () => void;
|
||||
discoveryRuleList: IDiscoveryRuleList;
|
||||
setDiscoveryRuleList: (discoveryRuleItems: IDiscoveryRuleList) => void;
|
||||
onDelete: (discoveryItemId: string) => void;
|
||||
editDiscoveryRuleId: null | string;
|
||||
onEdit: (discoveryItemId: string) => void;
|
||||
onChangeOperation: (operationText: string) => void;
|
||||
stagedOperationText: string;
|
||||
onChangeType: (typeText: string) => void;
|
||||
stagedTypeText: string;
|
||||
onChangeProbe: (probeText: string) => void;
|
||||
stagedProbeText: string;
|
||||
onCancel: () => void;
|
||||
onSubmit: () => void;
|
||||
onAddRule: () => void;
|
||||
operationTypes: Operation[];
|
||||
toggleDescription: ReactNode;
|
||||
discoveryRulesDescription: ReactNode;
|
||||
showUnsavedWarning?: boolean;
|
||||
onDragEnd: (dropResult: DropResult) => void;
|
||||
selectedVersion: string;
|
||||
versions: string[];
|
||||
onChangeVersion: EuiComboBoxProps<string>['onChange'];
|
||||
onCreateNewVersion: EuiComboBoxProps<string>['onCreateOption'];
|
||||
isValidVersion: boolean;
|
||||
}
|
||||
|
||||
export function RuntimeAttachment({
|
||||
isEnabled,
|
||||
onToggleEnable,
|
||||
discoveryRuleList,
|
||||
setDiscoveryRuleList,
|
||||
onDelete,
|
||||
editDiscoveryRuleId,
|
||||
onEdit,
|
||||
onChangeOperation,
|
||||
stagedOperationText,
|
||||
onChangeType,
|
||||
stagedTypeText,
|
||||
onChangeProbe,
|
||||
stagedProbeText,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
onAddRule,
|
||||
operationTypes,
|
||||
toggleDescription,
|
||||
discoveryRulesDescription,
|
||||
showUnsavedWarning,
|
||||
onDragEnd,
|
||||
selectedVersion,
|
||||
versions,
|
||||
onChangeVersion,
|
||||
onCreateNewVersion,
|
||||
isValidVersion,
|
||||
}: Props) {
|
||||
return (
|
||||
<div>
|
||||
{showUnsavedWarning && (
|
||||
<>
|
||||
<EuiCallOut
|
||||
title={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.unsavedRules',
|
||||
{
|
||||
defaultMessage:
|
||||
'You have unsaved changes. Click "Save integration" to sync changes to the integration.',
|
||||
}
|
||||
)}
|
||||
color="warning"
|
||||
iconType="iInCircle"
|
||||
size="s"
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</>
|
||||
)}
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiSwitch
|
||||
label={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.enableRuntimeAttachement',
|
||||
{ defaultMessage: 'Enable runtime attachment' }
|
||||
)}
|
||||
checked={isEnabled}
|
||||
onChange={onToggleEnable}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText color="subdued" size="s">
|
||||
<p>{toggleDescription}</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
{isEnabled && versions && (
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow
|
||||
label={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.version',
|
||||
{ defaultMessage: 'Version' }
|
||||
)}
|
||||
isInvalid={!isValidVersion}
|
||||
error={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.version.invalid',
|
||||
{ defaultMessage: 'Invalid version' }
|
||||
)}
|
||||
>
|
||||
<EuiComboBox
|
||||
selectedOptions={[{ label: selectedVersion }]}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.version.placeHolder',
|
||||
{ defaultMessage: 'Select or add a version' }
|
||||
)}
|
||||
options={versions.map((_version) => ({ label: _version }))}
|
||||
onChange={onChangeVersion}
|
||||
onCreateOption={onCreateNewVersion}
|
||||
singleSelection
|
||||
isClearable={false}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
{isEnabled && (
|
||||
<>
|
||||
<EuiSpacer size="l" />
|
||||
<EuiText size="s">
|
||||
<h3>
|
||||
{i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.discoveryRules',
|
||||
{ defaultMessage: 'Discovery rules' }
|
||||
)}
|
||||
</h3>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="iInCircle" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiText size="xs">
|
||||
<p>{discoveryRulesDescription}</p>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
iconType="plusInCircle"
|
||||
disabled={editDiscoveryRuleId !== null}
|
||||
onClick={onAddRule}
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.apm.fleetIntegration.apmAgent.runtimeAttachment.addRule',
|
||||
{ defaultMessage: 'Add rule' }
|
||||
)}
|
||||
</EuiButton>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiDragDropContext onDragEnd={onDragEnd}>
|
||||
<EuiDroppable droppableId="RUNTIME_ATTACHMENT_DROPPABLE">
|
||||
{discoveryRuleList.map(({ discoveryRule, id }, idx) => (
|
||||
<EuiDraggable
|
||||
spacing="m"
|
||||
key={id}
|
||||
index={idx}
|
||||
draggableId={id}
|
||||
customDragHandle={true}
|
||||
>
|
||||
{(provided) =>
|
||||
id === editDiscoveryRuleId ? (
|
||||
<EditDiscoveryRule
|
||||
id={editDiscoveryRuleId}
|
||||
onChangeOperation={onChangeOperation}
|
||||
operation={stagedOperationText}
|
||||
onChangeType={onChangeType}
|
||||
type={stagedTypeText}
|
||||
onChangeProbe={onChangeProbe}
|
||||
probe={stagedProbeText}
|
||||
onCancel={onCancel}
|
||||
onSubmit={onSubmit}
|
||||
operationTypes={operationTypes}
|
||||
/>
|
||||
) : (
|
||||
<DiscoveryRule
|
||||
id={id}
|
||||
order={idx + 1}
|
||||
operation={discoveryRule.operation}
|
||||
type={discoveryRule.type}
|
||||
probe={discoveryRule.probe}
|
||||
providedDragHandleProps={provided.dragHandleProps}
|
||||
onDelete={onDelete}
|
||||
onEdit={onEdit}
|
||||
operationTypes={operationTypes}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</EuiDraggable>
|
||||
))}
|
||||
</EuiDroppable>
|
||||
</EuiDragDropContext>
|
||||
<DefaultDiscoveryRule />
|
||||
</>
|
||||
)}
|
||||
<EuiSpacer size="s" />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* 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 yaml from 'js-yaml';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import React, { useCallback, useState, useMemo } from 'react';
|
||||
import {
|
||||
RuntimeAttachment,
|
||||
RuntimeAttachmentSettings,
|
||||
IDiscoveryRule,
|
||||
} from '..';
|
||||
import type {
|
||||
NewPackagePolicy,
|
||||
PackagePolicy,
|
||||
PackagePolicyEditExtensionComponentProps,
|
||||
} from '../../../apm_policy_form/typings';
|
||||
|
||||
interface Props {
|
||||
policy: PackagePolicy;
|
||||
newPolicy: NewPackagePolicy;
|
||||
onChange: PackagePolicyEditExtensionComponentProps['onChange'];
|
||||
}
|
||||
|
||||
const excludeOptions = [
|
||||
{
|
||||
value: 'main',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.main',
|
||||
{ defaultMessage: 'main' }
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.mainDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'A regular expression of fully qualified main class names or paths to JARs of applications the java agent should be attached to. Performs a partial match so that foo matches /bin/foo.jar.',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 'vmarg',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.vmarg',
|
||||
{ defaultMessage: 'vmarg' }
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.vmargDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'A regular expression matched against the arguments passed to the JVM, such as system properties. Performs a partial match so that attach=true matches the system property -Dattach=true.',
|
||||
}
|
||||
),
|
||||
},
|
||||
{
|
||||
value: 'user',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.user',
|
||||
{ defaultMessage: 'user' }
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude.options.userDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'A username that is matched against the operating system user that runs the JVM.',
|
||||
}
|
||||
),
|
||||
},
|
||||
];
|
||||
const includeOptions = [
|
||||
{
|
||||
value: 'all',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.include.options.all',
|
||||
{ defaultMessage: 'All' }
|
||||
),
|
||||
description: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.include.options.allDescription',
|
||||
{ defaultMessage: 'Includes all JVMs for attachment.' }
|
||||
),
|
||||
},
|
||||
...excludeOptions,
|
||||
];
|
||||
|
||||
const versions = [
|
||||
'1.27.1',
|
||||
'1.27.0',
|
||||
'1.26.0',
|
||||
'1.25.0',
|
||||
'1.24.0',
|
||||
'1.23.0',
|
||||
'1.22.0',
|
||||
'1.21.0',
|
||||
'1.20.0',
|
||||
'1.19.0',
|
||||
'1.18.1',
|
||||
'1.18.0',
|
||||
'1.18.0.RC1',
|
||||
'1.17.0',
|
||||
'1.16.0',
|
||||
'1.15.0',
|
||||
'1.14.0',
|
||||
'1.13.0',
|
||||
'1.12.0',
|
||||
'1.11.0',
|
||||
'1.10.0',
|
||||
'1.9.0',
|
||||
'1.8.0',
|
||||
'1.7.0',
|
||||
'1.6.1',
|
||||
'1.6.0',
|
||||
'1.5.0',
|
||||
'1.4.0',
|
||||
'1.3.0',
|
||||
'1.2.0',
|
||||
];
|
||||
|
||||
function getApmVars(newPolicy: NewPackagePolicy) {
|
||||
return newPolicy.inputs.find(({ type }) => type === 'apm')?.vars;
|
||||
}
|
||||
|
||||
export function JavaRuntimeAttachment({ newPolicy, onChange }: Props) {
|
||||
const [isDirty, setIsDirty] = useState(false);
|
||||
const onChangePolicy = useCallback(
|
||||
(runtimeAttachmentSettings: RuntimeAttachmentSettings) => {
|
||||
const apmInputIdx = newPolicy.inputs.findIndex(
|
||||
({ type }) => type === 'apm'
|
||||
);
|
||||
onChange({
|
||||
isValid: true,
|
||||
updatedPolicy: {
|
||||
...newPolicy,
|
||||
inputs: [
|
||||
...newPolicy.inputs.slice(0, apmInputIdx),
|
||||
{
|
||||
...newPolicy.inputs[apmInputIdx],
|
||||
vars: {
|
||||
...newPolicy.inputs[apmInputIdx].vars,
|
||||
java_attacher_enabled: {
|
||||
value: runtimeAttachmentSettings.enabled,
|
||||
type: 'bool',
|
||||
},
|
||||
java_attacher_discovery_rules: {
|
||||
type: 'yaml',
|
||||
value: encodeDiscoveryRulesYaml(
|
||||
runtimeAttachmentSettings.discoveryRules
|
||||
),
|
||||
},
|
||||
java_attacher_agent_version: {
|
||||
type: 'text',
|
||||
value: runtimeAttachmentSettings.version,
|
||||
},
|
||||
},
|
||||
},
|
||||
...newPolicy.inputs.slice(apmInputIdx + 1),
|
||||
],
|
||||
},
|
||||
});
|
||||
setIsDirty(true);
|
||||
},
|
||||
[newPolicy, onChange]
|
||||
);
|
||||
|
||||
const apmVars = useMemo(() => getApmVars(newPolicy), [newPolicy]);
|
||||
|
||||
return (
|
||||
<RuntimeAttachment
|
||||
operationTypes={[
|
||||
{
|
||||
operation: {
|
||||
value: 'include',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.include',
|
||||
{ defaultMessage: 'Include' }
|
||||
),
|
||||
},
|
||||
types: includeOptions,
|
||||
},
|
||||
{
|
||||
operation: {
|
||||
value: 'exclude',
|
||||
label: i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.operationType.exclude',
|
||||
{ defaultMessage: 'Exclude' }
|
||||
),
|
||||
},
|
||||
types: excludeOptions,
|
||||
},
|
||||
]}
|
||||
onChange={onChangePolicy}
|
||||
toggleDescription={i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.toggleDescription',
|
||||
{
|
||||
defaultMessage:
|
||||
'Attach the Java agent to running and starting Java applications.',
|
||||
}
|
||||
)}
|
||||
discoveryRulesDescription={
|
||||
<FormattedMessage
|
||||
id="xpack.apm.fleetIntegration.javaRuntime.discoveryRulesDescription"
|
||||
defaultMessage="For every running JVM, the discovery rules are evaluated in the order they are provided. The first matching rule determines the outcome. Learn more in the {docLink}."
|
||||
values={{
|
||||
docLink: (
|
||||
<a
|
||||
href="https://www.elastic.co/guide/en/apm/agent/java/current/setup-attach-cli.html"
|
||||
target="_blank"
|
||||
>
|
||||
{i18n.translate(
|
||||
'xpack.apm.fleetIntegration.javaRuntime.discoveryRulesDescription.docLink',
|
||||
{ defaultMessage: 'docs' }
|
||||
)}
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
}
|
||||
showUnsavedWarning={isDirty}
|
||||
initialIsEnabled={apmVars?.java_attacher_enabled?.value}
|
||||
initialDiscoveryRules={decodeDiscoveryRulesYaml(
|
||||
apmVars?.java_attacher_discovery_rules?.value ?? '[]\n',
|
||||
[initialDiscoveryRule]
|
||||
)}
|
||||
selectedVersion={
|
||||
apmVars?.java_attacher_agent_version?.value || versions[0]
|
||||
}
|
||||
versions={versions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const initialDiscoveryRule = {
|
||||
operation: 'include',
|
||||
type: 'vmarg',
|
||||
probe: 'elastic.apm.attach=true',
|
||||
};
|
||||
|
||||
type DiscoveryRulesParsedYaml = Array<{ [operationType: string]: string }>;
|
||||
|
||||
function decodeDiscoveryRulesYaml(
|
||||
discoveryRulesYaml: string,
|
||||
defaultDiscoveryRules: IDiscoveryRule[] = []
|
||||
): IDiscoveryRule[] {
|
||||
try {
|
||||
const parsedYaml: DiscoveryRulesParsedYaml =
|
||||
yaml.load(discoveryRulesYaml) ?? [];
|
||||
|
||||
if (parsedYaml.length === 0) {
|
||||
return defaultDiscoveryRules;
|
||||
}
|
||||
|
||||
// transform into array of discovery rules
|
||||
return parsedYaml.map((discoveryRuleMap) => {
|
||||
const [operationType, probe] = Object.entries(discoveryRuleMap)[0];
|
||||
return {
|
||||
operation: operationType.split('-')[0],
|
||||
type: operationType.split('-')[1],
|
||||
probe,
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
return defaultDiscoveryRules;
|
||||
}
|
||||
}
|
||||
|
||||
function encodeDiscoveryRulesYaml(discoveryRules: IDiscoveryRule[]): string {
|
||||
// transform into list of key,value objects for expected yaml result
|
||||
const mappedDiscoveryRules: DiscoveryRulesParsedYaml = discoveryRules.map(
|
||||
({ operation, type, probe }) => ({
|
||||
[`${operation}-${type}`]: probe,
|
||||
})
|
||||
);
|
||||
return yaml.dump(mappedDiscoveryRules);
|
||||
}
|
|
@ -348,7 +348,8 @@ export const EditPackagePolicyForm = memo<{
|
|||
const [formState, setFormState] = useState<PackagePolicyFormState>('INVALID');
|
||||
const savePackagePolicy = async () => {
|
||||
setFormState('LOADING');
|
||||
const result = await sendUpdatePackagePolicy(packagePolicyId, packagePolicy);
|
||||
const { elasticsearch, ...restPackagePolicy } = packagePolicy; // ignore 'elasticsearch' property since it fails route validation
|
||||
const result = await sendUpdatePackagePolicy(packagePolicyId, restPackagePolicy);
|
||||
setFormState('SUBMITTED');
|
||||
return result;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue