diff --git a/x-pack/plugins/fleet/common/constants/epm.ts b/x-pack/plugins/fleet/common/constants/epm.ts index 131cc276fc073..734d578687bcd 100644 --- a/x-pack/plugins/fleet/common/constants/epm.ts +++ b/x-pack/plugins/fleet/common/constants/epm.ts @@ -15,6 +15,10 @@ export const FLEET_SERVER_PACKAGE = 'fleet_server'; export const FLEET_ENDPOINT_PACKAGE = 'endpoint'; export const FLEET_APM_PACKAGE = 'apm'; export const FLEET_SYNTHETICS_PACKAGE = 'synthetics'; +export const FLEET_KUBERNETES_PACKAGE = 'kubernetes'; +export const KUBERNETES_RUN_INSTRUCTIONS = + 'kubectl apply -f elastic-agent-standalone-kubernetes.yaml'; +export const STANDALONE_RUN_INSTRUCTIONS = './elastic-agent install'; /* Package rules: diff --git a/x-pack/plugins/fleet/common/services/agent_cm_to_yaml.ts b/x-pack/plugins/fleet/common/services/agent_cm_to_yaml.ts new file mode 100644 index 0000000000000..5987110d7752f --- /dev/null +++ b/x-pack/plugins/fleet/common/services/agent_cm_to_yaml.ts @@ -0,0 +1,34 @@ +/* + * 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 type { safeDump } from 'js-yaml'; + +import type { FullAgentConfigMap } from '../types/models/agent_cm'; + +const CM_KEYS_ORDER = ['apiVersion', 'kind', 'metadata', 'data']; + +export const fullAgentConfigMapToYaml = ( + policy: FullAgentConfigMap, + toYaml: typeof safeDump +): string => { + return toYaml(policy, { + skipInvalid: true, + sortKeys: (keyA: string, keyB: string) => { + const indexA = CM_KEYS_ORDER.indexOf(keyA); + const indexB = CM_KEYS_ORDER.indexOf(keyB); + if (indexA >= 0 && indexB < 0) { + return -1; + } + + if (indexA < 0 && indexB >= 0) { + return 1; + } + + return indexA - indexB; + }, + }); +}; diff --git a/x-pack/plugins/fleet/common/types/models/agent_cm.ts b/x-pack/plugins/fleet/common/types/models/agent_cm.ts new file mode 100644 index 0000000000000..bd8200c96ad88 --- /dev/null +++ b/x-pack/plugins/fleet/common/types/models/agent_cm.ts @@ -0,0 +1,29 @@ +/* + * 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 type { FullAgentPolicy } from './agent_policy'; + +export interface FullAgentConfigMap { + apiVersion: string; + kind: string; + metadata: Metadata; + data: AgentYML; +} + +interface Metadata { + name: string; + namespace: string; + labels: Labels; +} + +interface Labels { + 'k8s-app': string; +} + +interface AgentYML { + 'agent.yml': FullAgentPolicy; +} diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts index 927368694693a..0975b1e28fb8b 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent_policy.ts @@ -78,3 +78,7 @@ export interface GetFullAgentPolicyRequest { export interface GetFullAgentPolicyResponse { item: FullAgentPolicy; } + +export interface GetFullAgentConfigMapResponse { + item: string; +} diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/standalone_instructions.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/standalone_instructions.tsx index d7b9ae2aef08a..99e8809923140 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/standalone_instructions.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/standalone_instructions.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useState, useEffect } from 'react'; import { EuiSteps, EuiText, @@ -23,16 +23,27 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { safeDump } from 'js-yaml'; -import { useStartServices, useLink, sendGetOneAgentPolicyFull } from '../../hooks'; +import { + useStartServices, + useLink, + sendGetOneAgentPolicyFull, + sendGetOneAgentPolicy, +} from '../../hooks'; import { fullAgentPolicyToYaml, agentPolicyRouteService } from '../../services'; +import type { PackagePolicy } from '../../../common'; + +import { + FLEET_KUBERNETES_PACKAGE, + KUBERNETES_RUN_INSTRUCTIONS, + STANDALONE_RUN_INSTRUCTIONS, +} from '../../../common'; + import { DownloadStep, AgentPolicySelectionStep } from './steps'; import type { BaseProps } from './types'; type Props = BaseProps; -const RUN_INSTRUCTIONS = './elastic-agent install'; - export const StandaloneInstructions = React.memo(({ agentPolicy, agentPolicies }) => { const { getHref } = useLink(); const core = useStartServices(); @@ -40,12 +51,34 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol const [selectedPolicyId, setSelectedPolicyId] = useState(agentPolicy?.id); const [fullAgentPolicy, setFullAgentPolicy] = useState(); + const [isK8s, setIsK8s] = useState<'IS_LOADING' | 'IS_KUBERNETES' | 'IS_NOT_KUBERNETES'>( + 'IS_LOADING' + ); + const [yaml, setYaml] = useState(''); + const runInstructions = + isK8s === 'IS_KUBERNETES' ? KUBERNETES_RUN_INSTRUCTIONS : STANDALONE_RUN_INSTRUCTIONS; - const downloadLink = selectedPolicyId - ? core.http.basePath.prepend( - `${agentPolicyRouteService.getInfoFullDownloadPath(selectedPolicyId)}?standalone=true` - ) - : undefined; + useEffect(() => { + async function checkifK8s() { + if (!selectedPolicyId) { + return; + } + const agentPolicyRequest = await sendGetOneAgentPolicy(selectedPolicyId); + const agentPol = agentPolicyRequest.data ? agentPolicyRequest.data.item : null; + + if (!agentPol) { + setIsK8s('IS_NOT_KUBERNETES'); + return; + } + const k8s = (pkg: PackagePolicy) => pkg.package?.name === FLEET_KUBERNETES_PACKAGE; + setIsK8s( + (agentPol.package_policies as PackagePolicy[]).some(k8s) + ? 'IS_KUBERNETES' + : 'IS_NOT_KUBERNETES' + ); + } + checkifK8s(); + }, [selectedPolicyId, notifications.toasts]); useEffect(() => { async function fetchFullPolicy() { @@ -53,7 +86,11 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol if (!selectedPolicyId) { return; } - const res = await sendGetOneAgentPolicyFull(selectedPolicyId, { standalone: true }); + let query = { standalone: true, kubernetes: false }; + if (isK8s === 'IS_KUBERNETES') { + query = { standalone: true, kubernetes: true }; + } + const res = await sendGetOneAgentPolicyFull(selectedPolicyId, query); if (res.error) { throw res.error; } @@ -61,7 +98,6 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol if (!res.data) { throw new Error('No data while fetching full agent policy'); } - setFullAgentPolicy(res.data.item); } catch (error) { notifications.toasts.addError(error, { @@ -69,10 +105,86 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol }); } } - fetchFullPolicy(); - }, [selectedPolicyId, notifications.toasts]); + if (isK8s !== 'IS_LOADING') { + fetchFullPolicy(); + } + }, [selectedPolicyId, notifications.toasts, isK8s, core.http.basePath]); + + useEffect(() => { + if (isK8s === 'IS_KUBERNETES') { + if (typeof fullAgentPolicy === 'object') { + return; + } + setYaml(fullAgentPolicy); + } else { + if (typeof fullAgentPolicy === 'string') { + return; + } + setYaml(fullAgentPolicyToYaml(fullAgentPolicy, safeDump)); + } + }, [fullAgentPolicy, isK8s]); + + const policyMsg = + isK8s === 'IS_KUBERNETES' ? ( + ES_USERNAME, + ESPasswordVariable: ES_PASSWORD, + }} + /> + ) : ( + elastic-agent.yml, + ESUsernameVariable: ES_USERNAME, + ESPasswordVariable: ES_PASSWORD, + outputSection: outputs, + }} + /> + ); + + let downloadLink = ''; + if (selectedPolicyId) { + downloadLink = + isK8s === 'IS_KUBERNETES' + ? core.http.basePath.prepend( + `${agentPolicyRouteService.getInfoFullDownloadPath(selectedPolicyId)}?kubernetes=true` + ) + : core.http.basePath.prepend( + `${agentPolicyRouteService.getInfoFullDownloadPath(selectedPolicyId)}?standalone=true` + ); + } + + const downloadMsg = + isK8s === 'IS_KUBERNETES' ? ( + + ) : ( + + ); + + const applyMsg = + isK8s === 'IS_KUBERNETES' ? ( + + ) : ( + + ); - const yaml = useMemo(() => fullAgentPolicyToYaml(fullAgentPolicy, safeDump), [fullAgentPolicy]); const steps = [ DownloadStep(), !agentPolicy @@ -85,16 +197,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol children: ( <> - elastic-agent.yml, - ESUsernameVariable: ES_USERNAME, - ESPasswordVariable: ES_PASSWORD, - outputSection: outputs, - }} - /> + <>{policyMsg} @@ -111,10 +214,7 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol - + <>{downloadMsg} @@ -133,14 +233,11 @@ export const StandaloneInstructions = React.memo(({ agentPolicy, agentPol children: ( <> - + <>{applyMsg} - {RUN_INSTRUCTIONS} + {runInstructions} - + {(copy) => ( { export const sendGetOneAgentPolicyFull = ( agentPolicyId: string, - query: { standalone?: boolean } = {} + query: { standalone?: boolean; kubernetes?: boolean } = {} ) => { return sendRequest({ path: agentPolicyRouteService.getInfoFullPath(agentPolicyId), diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index b3197d918d231..c3da75183f581 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -34,6 +34,7 @@ import type { CopyAgentPolicyResponse, DeleteAgentPolicyResponse, GetFullAgentPolicyResponse, + GetFullAgentConfigMapResponse, } from '../../../common'; import { defaultIngestErrorHandler } from '../../errors'; @@ -232,27 +233,52 @@ export const getFullAgentPolicy: RequestHandler< > = async (context, request, response) => { const soClient = context.core.savedObjects.client; - try { - const fullAgentPolicy = await agentPolicyService.getFullAgentPolicy( - soClient, - request.params.agentPolicyId, - { standalone: request.query.standalone === true } - ); - if (fullAgentPolicy) { - const body: GetFullAgentPolicyResponse = { - item: fullAgentPolicy, - }; - return response.ok({ - body, - }); - } else { - return response.customError({ - statusCode: 404, - body: { message: 'Agent policy not found' }, - }); + if (request.query.kubernetes === true) { + try { + const fullAgentConfigMap = await agentPolicyService.getFullAgentConfigMap( + soClient, + request.params.agentPolicyId, + { standalone: request.query.standalone === true } + ); + if (fullAgentConfigMap) { + const body: GetFullAgentConfigMapResponse = { + item: fullAgentConfigMap, + }; + return response.ok({ + body, + }); + } else { + return response.customError({ + statusCode: 404, + body: { message: 'Agent config map not found' }, + }); + } + } catch (error) { + return defaultIngestErrorHandler({ error, response }); + } + } else { + try { + const fullAgentPolicy = await agentPolicyService.getFullAgentPolicy( + soClient, + request.params.agentPolicyId, + { standalone: request.query.standalone === true } + ); + if (fullAgentPolicy) { + const body: GetFullAgentPolicyResponse = { + item: fullAgentPolicy, + }; + return response.ok({ + body, + }); + } else { + return response.customError({ + statusCode: 404, + body: { message: 'Agent policy not found' }, + }); + } + } catch (error) { + return defaultIngestErrorHandler({ error, response }); } - } catch (error) { - return defaultIngestErrorHandler({ error, response }); } }; @@ -265,27 +291,55 @@ export const downloadFullAgentPolicy: RequestHandler< params: { agentPolicyId }, } = request; - try { - const fullAgentPolicy = await agentPolicyService.getFullAgentPolicy(soClient, agentPolicyId, { - standalone: request.query.standalone === true, - }); - if (fullAgentPolicy) { - const body = fullAgentPolicyToYaml(fullAgentPolicy, safeDump); - const headers: ResponseHeaders = { - 'content-type': 'text/x-yaml', - 'content-disposition': `attachment; filename="elastic-agent.yml"`, - }; - return response.ok({ - body, - headers, - }); - } else { - return response.customError({ - statusCode: 404, - body: { message: 'Agent policy not found' }, + if (request.query.kubernetes === true) { + try { + const fullAgentConfigMap = await agentPolicyService.getFullAgentConfigMap( + soClient, + request.params.agentPolicyId, + { standalone: request.query.standalone === true } + ); + if (fullAgentConfigMap) { + const body = fullAgentConfigMap; + const headers: ResponseHeaders = { + 'content-type': 'text/x-yaml', + 'content-disposition': `attachment; filename="elastic-agent-standalone-kubernetes.yaml"`, + }; + return response.ok({ + body, + headers, + }); + } else { + return response.customError({ + statusCode: 404, + body: { message: 'Agent config map not found' }, + }); + } + } catch (error) { + return defaultIngestErrorHandler({ error, response }); + } + } else { + try { + const fullAgentPolicy = await agentPolicyService.getFullAgentPolicy(soClient, agentPolicyId, { + standalone: request.query.standalone === true, }); + if (fullAgentPolicy) { + const body = fullAgentPolicyToYaml(fullAgentPolicy, safeDump); + const headers: ResponseHeaders = { + 'content-type': 'text/x-yaml', + 'content-disposition': `attachment; filename="elastic-agent.yml"`, + }; + return response.ok({ + body, + headers, + }); + } else { + return response.customError({ + statusCode: 404, + body: { message: 'Agent policy not found' }, + }); + } + } catch (error) { + return defaultIngestErrorHandler({ error, response }); } - } catch (error) { - return defaultIngestErrorHandler({ error, response }); } }; diff --git a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts index 561c463b998d4..60cf9c8d96257 100644 --- a/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policies/full_agent_policy.ts @@ -70,12 +70,14 @@ export async function getFullAgentPolicy( if (!monitoringOutput) { throw new Error(`Monitoring output not found ${monitoringOutputId}`); } - const fullAgentPolicy: FullAgentPolicy = { id: agentPolicy.id, outputs: { ...outputs.reduce((acc, output) => { - acc[getOutputIdForAgentPolicy(output)] = transformOutputToFullPolicyOutput(output); + acc[getOutputIdForAgentPolicy(output)] = transformOutputToFullPolicyOutput( + output, + standalone + ); return acc; }, {}), @@ -179,8 +181,8 @@ function transformOutputToFullPolicyOutput( if (standalone) { delete newOutput.api_key; - newOutput.username = 'ES_USERNAME'; - newOutput.password = 'ES_PASSWORD'; + newOutput.username = '{ES_USERNAME}'; + newOutput.password = '{ES_PASSWORD}'; } return newOutput; diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index 6ebe890aeaef2..321bc7f289594 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -13,6 +13,8 @@ import type { SavedObjectsBulkUpdateResponse, } from 'src/core/server'; +import { safeDump } from 'js-yaml'; + import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; import type { AuthenticatedUser } from '../../../security/server'; @@ -41,6 +43,12 @@ import type { } from '../../common'; import { AgentPolicyNameExistsError, HostedAgentPolicyRestrictionRelatedError } from '../errors'; +import type { FullAgentConfigMap } from '../../common/types/models/agent_cm'; + +import { fullAgentConfigMapToYaml } from '../../common/services/agent_cm_to_yaml'; + +import { elasticAgentManifest } from './elastic_agent_manifest'; + import { getPackageInfo } from './epm/packages'; import { getAgentsByKuery } from './agents'; import { packagePolicyService } from './package_policy'; @@ -49,7 +57,6 @@ import { agentPolicyUpdateEventHandler } from './agent_policy_update'; import { normalizeKuery, escapeSearchQueryPhrase } from './saved_object'; import { appContextService } from './app_context'; import { getFullAgentPolicy } from './agent_policies'; - const SAVED_OBJECT_TYPE = AGENT_POLICY_SAVED_OBJECT_TYPE; class AgentPolicyService { @@ -717,6 +724,40 @@ class AgentPolicyService { return res.body.hits.hits[0]._source; } + public async getFullAgentConfigMap( + soClient: SavedObjectsClientContract, + id: string, + options?: { standalone: boolean } + ): Promise { + const fullAgentPolicy = await getFullAgentPolicy(soClient, id, options); + if (fullAgentPolicy) { + const fullAgentConfigMap: FullAgentConfigMap = { + apiVersion: 'v1', + kind: 'ConfigMap', + metadata: { + name: 'agent-node-datastreams', + namespace: 'kube-system', + labels: { + 'k8s-app': 'elastic-agent', + }, + }, + data: { + 'agent.yml': fullAgentPolicy, + }, + }; + + const configMapYaml = fullAgentConfigMapToYaml(fullAgentConfigMap, safeDump); + const updateManifestVersion = elasticAgentManifest.replace( + 'VERSION', + appContextService.getKibanaVersion() + ); + const fixedAgentYML = configMapYaml.replace('agent.yml:', 'agent.yml: |-'); + return [fixedAgentYML, updateManifestVersion].join('\n'); + } else { + return ''; + } + } + public async getFullAgentPolicy( soClient: SavedObjectsClientContract, id: string, diff --git a/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts new file mode 100644 index 0000000000000..392ee170d02ad --- /dev/null +++ b/x-pack/plugins/fleet/server/services/elastic_agent_manifest.ts @@ -0,0 +1,222 @@ +/* + * 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. + */ + +export const elasticAgentManifest = ` +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: elastic-agent + namespace: kube-system + labels: + app: elastic-agent +spec: + selector: + matchLabels: + app: elastic-agent + template: + metadata: + labels: + app: elastic-agent + spec: + tolerations: + - key: node-role.kubernetes.io/master + effect: NoSchedule + serviceAccountName: elastic-agent + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + containers: + - name: elastic-agent + image: docker.elastic.co/beats/elastic-agent:VERSION + args: [ + "-c", "/etc/agent.yml", + "-e", + "-d", "'*'", + ] + env: + - name: ES_USERNAME + value: "elastic" + - name: ES_PASSWORD + value: "changeme" + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + securityContext: + runAsUser: 0 + resources: + limits: + memory: 500Mi + requests: + cpu: 100m + memory: 200Mi + volumeMounts: + - name: datastreams + mountPath: /etc/agent.yml + readOnly: true + subPath: agent.yml + - name: proc + mountPath: /hostfs/proc + readOnly: true + - name: cgroup + mountPath: /hostfs/sys/fs/cgroup + readOnly: true + - name: varlibdockercontainers + mountPath: /var/lib/docker/containers + readOnly: true + - name: varlog + mountPath: /var/log + readOnly: true + volumes: + - name: datastreams + configMap: + defaultMode: 0640 + name: agent-node-datastreams + - name: proc + hostPath: + path: /proc + - name: cgroup + hostPath: + path: /sys/fs/cgroup + - name: varlibdockercontainers + hostPath: + path: /var/lib/docker/containers + - name: varlog + hostPath: + path: /var/log +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: elastic-agent +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: ClusterRole + name: elastic-agent + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + namespace: kube-system + name: elastic-agent +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: Role + name: elastic-agent + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: elastic-agent-kubeadm-config + namespace: kube-system +subjects: + - kind: ServiceAccount + name: elastic-agent + namespace: kube-system +roleRef: + kind: Role + name: elastic-agent-kubeadm-config + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: elastic-agent + labels: + k8s-app: elastic-agent +rules: + - apiGroups: [""] + resources: + - nodes + - namespaces + - events + - pods + - services + - configmaps + verbs: ["get", "list", "watch"] + # Enable this rule only if planing to use kubernetes_secrets provider + #- apiGroups: [""] + # resources: + # - secrets + # verbs: ["get"] + - apiGroups: ["extensions"] + resources: + - replicasets + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: + - statefulsets + - deployments + - replicasets + verbs: ["get", "list", "watch"] + - apiGroups: ["batch"] + resources: + - jobs + verbs: ["get", "list", "watch"] + - apiGroups: + - "" + resources: + - nodes/stats + verbs: + - get + # required for apiserver + - nonResourceURLs: + - "/metrics" + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: elastic-agent + # should be the namespace where elastic-agent is running + namespace: kube-system + labels: + k8s-app: elastic-agent +rules: + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: ["get", "create", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: elastic-agent-kubeadm-config + namespace: kube-system + labels: + k8s-app: elastic-agent +rules: + - apiGroups: [""] + resources: + - configmaps + resourceNames: + - kubeadm-config + verbs: ["get"] +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: elastic-agent + namespace: kube-system + labels: + k8s-app: elastic-agent +--- +`; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts index 714ffab922dd9..64d142f150bfd 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent_policy.ts @@ -56,5 +56,6 @@ export const GetFullAgentPolicyRequestSchema = { query: schema.object({ download: schema.maybe(schema.boolean()), standalone: schema.maybe(schema.boolean()), + kubernetes: schema.maybe(schema.boolean()), }), };