mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Fleet] Remove fleetServerEnabled feature flag and use fleet system indices (#92422)
This commit is contained in:
parent
96c360b81d
commit
f4caf8727d
83 changed files with 2249 additions and 1720 deletions
|
@ -1678,7 +1678,32 @@
|
|||
}
|
||||
},
|
||||
"server": {
|
||||
"classes": [],
|
||||
"classes": [
|
||||
{
|
||||
"id": "def-server.AgentNotFoundError",
|
||||
"type": "Class",
|
||||
"tags": [],
|
||||
"label": "AgentNotFoundError",
|
||||
"description": [],
|
||||
"signature": [
|
||||
{
|
||||
"pluginId": "fleet",
|
||||
"scope": "server",
|
||||
"docId": "kibFleetPluginApi",
|
||||
"section": "def-server.AgentNotFoundError",
|
||||
"text": "AgentNotFoundError"
|
||||
},
|
||||
" extends ",
|
||||
"IngestManagerError"
|
||||
],
|
||||
"children": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/errors/index.ts",
|
||||
"lineNumber": 34
|
||||
},
|
||||
"initialIsOpen": false
|
||||
}
|
||||
],
|
||||
"functions": [
|
||||
{
|
||||
"id": "def-server.getRegistryUrl",
|
||||
|
@ -1714,7 +1739,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 73
|
||||
"lineNumber": 68
|
||||
},
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
|
@ -1744,7 +1769,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 74
|
||||
"lineNumber": 69
|
||||
},
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
|
@ -1774,7 +1799,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 75
|
||||
"lineNumber": 70
|
||||
},
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
|
@ -1796,7 +1821,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 76
|
||||
"lineNumber": 71
|
||||
},
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
|
@ -1821,7 +1846,7 @@
|
|||
],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 72
|
||||
"lineNumber": 67
|
||||
},
|
||||
"initialIsOpen": false
|
||||
},
|
||||
|
@ -1862,15 +1887,7 @@
|
|||
"type": "Function",
|
||||
"label": "authenticateAgentWithAccessToken",
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
"docId": "kibCoreSavedObjectsPluginApi",
|
||||
"section": "def-server.SavedObjectsClient",
|
||||
"text": "SavedObjectsClient"
|
||||
},
|
||||
", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, esClient: ",
|
||||
"(esClient: ",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
|
@ -1900,27 +1917,6 @@
|
|||
"\nAuthenticate an agent with access toekn"
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"type": "Object",
|
||||
"label": "soClient",
|
||||
"isRequired": true,
|
||||
"signature": [
|
||||
"Pick<",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
"docId": "kibCoreSavedObjectsPluginApi",
|
||||
"section": "def-server.SavedObjectsClient",
|
||||
"text": "SavedObjectsClient"
|
||||
},
|
||||
", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">"
|
||||
],
|
||||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 54
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "CompoundType",
|
||||
"label": "esClient",
|
||||
|
@ -1937,7 +1933,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 55
|
||||
"lineNumber": 54
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1957,7 +1953,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 56
|
||||
"lineNumber": 55
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -1973,15 +1969,7 @@
|
|||
"type": "Function",
|
||||
"label": "getAgentStatusById",
|
||||
"signature": [
|
||||
"(soClient: Pick<",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
"docId": "kibCoreSavedObjectsPluginApi",
|
||||
"section": "def-server.SavedObjectsClient",
|
||||
"text": "SavedObjectsClient"
|
||||
},
|
||||
", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">, esClient: ",
|
||||
"(esClient: ",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
|
@ -2003,27 +1991,6 @@
|
|||
"\nReturn the status by the Agent's id"
|
||||
],
|
||||
"children": [
|
||||
{
|
||||
"type": "Object",
|
||||
"label": "soClient",
|
||||
"isRequired": true,
|
||||
"signature": [
|
||||
"Pick<",
|
||||
{
|
||||
"pluginId": "core",
|
||||
"scope": "server",
|
||||
"docId": "kibCoreSavedObjectsPluginApi",
|
||||
"section": "def-server.SavedObjectsClient",
|
||||
"text": "SavedObjectsClient"
|
||||
},
|
||||
", \"get\" | \"delete\" | \"create\" | \"find\" | \"update\" | \"bulkCreate\" | \"bulkGet\" | \"bulkUpdate\" | \"errors\" | \"checkConflicts\" | \"resolve\" | \"addToNamespaces\" | \"deleteFromNamespaces\" | \"removeReferencesTo\" | \"openPointInTimeForType\" | \"closePointInTime\">"
|
||||
],
|
||||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 62
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "CompoundType",
|
||||
"label": "esClient",
|
||||
|
@ -2040,7 +2007,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 63
|
||||
"lineNumber": 60
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2053,7 +2020,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 64
|
||||
"lineNumber": 60
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -2061,7 +2028,7 @@
|
|||
"returnComment": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 61
|
||||
"lineNumber": 60
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2074,7 +2041,7 @@
|
|||
],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/services/index.ts",
|
||||
"lineNumber": 69
|
||||
"lineNumber": 64
|
||||
},
|
||||
"signature": [
|
||||
"typeof ",
|
||||
|
@ -2471,7 +2438,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/server/index.ts",
|
||||
"lineNumber": 75
|
||||
"lineNumber": 76
|
||||
},
|
||||
"signature": [
|
||||
"any"
|
||||
|
@ -2933,7 +2900,7 @@
|
|||
"description": [],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/common/types/index.ts",
|
||||
"lineNumber": 39
|
||||
"lineNumber": 38
|
||||
},
|
||||
"signature": [
|
||||
"<T>(o: T) => [keyof T, T[keyof T]][]"
|
||||
|
@ -5188,7 +5155,7 @@
|
|||
"lineNumber": 15
|
||||
},
|
||||
"signature": [
|
||||
"{ fleetServerEnabled: boolean; enabled: boolean; tlsCheckDisabled: boolean; pollingRequestTimeout: number; maxConcurrentConnections: number; kibana: { host?: string | string[] | undefined; ca_sha256?: string | undefined; }; elasticsearch: { host?: string | undefined; ca_sha256?: string | undefined; }; agentPolicyRolloutRateLimitIntervalMs: number; agentPolicyRolloutRateLimitRequestPerInterval: number; }"
|
||||
"{ enabled: boolean; tlsCheckDisabled: boolean; pollingRequestTimeout: number; maxConcurrentConnections: number; kibana: { host?: string | string[] | undefined; ca_sha256?: string | undefined; }; elasticsearch: { host?: string | undefined; ca_sha256?: string | undefined; }; agentPolicyRolloutRateLimitIntervalMs: number; agentPolicyRolloutRateLimitRequestPerInterval: number; }"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -13693,7 +13660,7 @@
|
|||
],
|
||||
"source": {
|
||||
"path": "x-pack/plugins/fleet/common/types/index.ts",
|
||||
"lineNumber": 44
|
||||
"lineNumber": 43
|
||||
},
|
||||
"signature": [
|
||||
"T[keyof T]"
|
||||
|
|
|
@ -45,6 +45,9 @@ import fleetObj from './fleet.json';
|
|||
### Functions
|
||||
<DocDefinitionList data={fleetObj.server.functions}/>
|
||||
|
||||
### Classes
|
||||
<DocDefinitionList data={fleetObj.server.classes}/>
|
||||
|
||||
### Interfaces
|
||||
<DocDefinitionList data={fleetObj.server.interfaces}/>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { AGENT_POLLING_THRESHOLD_MS, AGENT_SAVED_OBJECT_TYPE } from '../constants';
|
||||
import { AGENT_POLLING_THRESHOLD_MS } from '../constants';
|
||||
import type { Agent, AgentStatus } from '../types';
|
||||
|
||||
export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentStatus {
|
||||
|
@ -42,11 +42,11 @@ export function getAgentStatus(agent: Agent, now: number = Date.now()): AgentSta
|
|||
}
|
||||
|
||||
export function buildKueryForEnrollingAgents() {
|
||||
return `not (${AGENT_SAVED_OBJECT_TYPE}.last_checkin:*)`;
|
||||
return 'not (last_checkin:*)';
|
||||
}
|
||||
|
||||
export function buildKueryForUnenrollingAgents() {
|
||||
return `${AGENT_SAVED_OBJECT_TYPE}.unenrollment_started_at:*`;
|
||||
return 'unenrollment_started_at:*';
|
||||
}
|
||||
|
||||
export function buildKueryForOnlineAgents() {
|
||||
|
@ -54,17 +54,17 @@ export function buildKueryForOnlineAgents() {
|
|||
}
|
||||
|
||||
export function buildKueryForErrorAgents() {
|
||||
return `${AGENT_SAVED_OBJECT_TYPE}.last_checkin_status:error or ${AGENT_SAVED_OBJECT_TYPE}.last_checkin_status:degraded`;
|
||||
return 'last_checkin_status:error or .last_checkin_status:degraded';
|
||||
}
|
||||
|
||||
export function buildKueryForOfflineAgents() {
|
||||
return `${AGENT_SAVED_OBJECT_TYPE}.last_checkin < now-${
|
||||
return `last_checkin < now-${
|
||||
(4 * AGENT_POLLING_THRESHOLD_MS) / 1000
|
||||
}s AND not (${buildKueryForErrorAgents()}) AND not ( ${buildKueryForUpdatingAgents()} )`;
|
||||
}
|
||||
|
||||
export function buildKueryForUpgradingAgents() {
|
||||
return `(${AGENT_SAVED_OBJECT_TYPE}.upgrade_started_at:*) and not (${AGENT_SAVED_OBJECT_TYPE}.upgraded_at:*)`;
|
||||
return '(upgrade_started_at:*) and not (upgraded_at:*)';
|
||||
}
|
||||
|
||||
export function buildKueryForUpdatingAgents() {
|
||||
|
@ -72,5 +72,5 @@ export function buildKueryForUpdatingAgents() {
|
|||
}
|
||||
|
||||
export function buildKueryForInactiveAgents() {
|
||||
return `${AGENT_SAVED_OBJECT_TYPE}.active:false`;
|
||||
return `active:false`;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ export interface FleetConfigType {
|
|||
registryUrl?: string;
|
||||
registryProxyUrl?: string;
|
||||
agents: {
|
||||
fleetServerEnabled: boolean;
|
||||
enabled: boolean;
|
||||
tlsCheckDisabled: boolean;
|
||||
pollingRequestTimeout: number;
|
||||
|
|
|
@ -14,7 +14,6 @@ export const createConfigurationMock = (): FleetConfigType => {
|
|||
registryProxyUrl: '',
|
||||
agents: {
|
||||
enabled: true,
|
||||
fleetServerEnabled: false,
|
||||
tlsCheckDisabled: true,
|
||||
pollingRequestTimeout: 1000,
|
||||
maxConcurrentConnections: 100,
|
||||
|
|
|
@ -19,8 +19,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
|
||||
import { AgentPolicy } from '../../../../types';
|
||||
import { SearchBar } from '../../../../components';
|
||||
import { AGENTS_INDEX, AGENT_SAVED_OBJECT_TYPE } from '../../../../constants';
|
||||
import { useConfig } from '../../../../hooks';
|
||||
import { AGENTS_INDEX } from '../../../../constants';
|
||||
|
||||
const statusFilters = [
|
||||
{
|
||||
|
@ -78,7 +77,6 @@ export const SearchAndFilterBar: React.FunctionComponent<{
|
|||
showUpgradeable,
|
||||
onShowUpgradeableChange,
|
||||
}) => {
|
||||
const config = useConfig();
|
||||
// Policies state for filtering
|
||||
const [isAgentPoliciesFilterOpen, setIsAgentPoliciesFilterOpen] = useState<boolean>(false);
|
||||
|
||||
|
@ -112,13 +110,7 @@ export const SearchAndFilterBar: React.FunctionComponent<{
|
|||
onSubmitSearch(newSearch);
|
||||
}
|
||||
}}
|
||||
{...(config.agents.fleetServerEnabled
|
||||
? {
|
||||
indexPattern: AGENTS_INDEX,
|
||||
}
|
||||
: {
|
||||
fieldPrefix: AGENT_SAVED_OBJECT_TYPE,
|
||||
})}
|
||||
indexPattern={AGENTS_INDEX}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={2}>
|
||||
|
|
|
@ -21,10 +21,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { FormattedMessage, FormattedDate } from '@kbn/i18n/react';
|
||||
|
||||
import {
|
||||
ENROLLMENT_API_KEYS_INDEX,
|
||||
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||
} from '../../../constants';
|
||||
import { ENROLLMENT_API_KEYS_INDEX } from '../../../constants';
|
||||
import {
|
||||
useBreadcrumbs,
|
||||
usePagination,
|
||||
|
@ -33,7 +30,6 @@ import {
|
|||
sendGetOneEnrollmentAPIKey,
|
||||
useStartServices,
|
||||
sendDeleteOneEnrollmentAPIKey,
|
||||
useConfig,
|
||||
} from '../../../hooks';
|
||||
import { EnrollmentAPIKey } from '../../../types';
|
||||
import { SearchBar } from '../../../components/search_bar';
|
||||
|
@ -160,7 +156,6 @@ const DeleteButton: React.FunctionComponent<{ apiKey: EnrollmentAPIKey; refresh:
|
|||
|
||||
export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => {
|
||||
useBreadcrumbs('fleet_enrollment_tokens');
|
||||
const config = useConfig();
|
||||
const [flyoutOpen, setFlyoutOpen] = useState(false);
|
||||
const [search, setSearch] = useState('');
|
||||
const { pagination, setPagination, pageSizeOptions } = usePagination();
|
||||
|
@ -288,13 +283,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => {
|
|||
});
|
||||
setSearch(newSearch);
|
||||
}}
|
||||
{...(config.agents.fleetServerEnabled
|
||||
? {
|
||||
indexPattern: ENROLLMENT_API_KEYS_INDEX,
|
||||
}
|
||||
: {
|
||||
fieldPrefix: ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||
})}
|
||||
indexPattern={ENROLLMENT_API_KEYS_INDEX}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
|
|
|
@ -25,8 +25,7 @@ export const getAgentUsage = async (
|
|||
esClient?: ElasticsearchClient
|
||||
): Promise<AgentUsage> => {
|
||||
// TODO: unsure if this case is possible at all.
|
||||
const fleetServerMissing = config.agents.fleetServerEnabled && !(await isFleetServerSetup());
|
||||
if (!soClient || !esClient || fleetServerMissing) {
|
||||
if (!soClient || !esClient || !(await isFleetServerSetup())) {
|
||||
return {
|
||||
total: 0,
|
||||
online: 0,
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
AgentPolicyNameExistsError,
|
||||
PackageUnsupportedMediaTypeError,
|
||||
ConcurrentInstallOperationError,
|
||||
AgentNotFoundError,
|
||||
} from './index';
|
||||
|
||||
type IngestErrorHandler = (
|
||||
|
@ -78,6 +79,9 @@ const getHTTPResponseCode = (error: IngestManagerError): number => {
|
|||
if (error instanceof ConcurrentInstallOperationError) {
|
||||
return 409; // Conflict
|
||||
}
|
||||
if (error instanceof AgentNotFoundError) {
|
||||
return 404;
|
||||
}
|
||||
return 400; // Bad Request
|
||||
};
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ export class IngestManagerError extends Error {
|
|||
this.name = this.constructor.name; // for stack traces
|
||||
}
|
||||
}
|
||||
|
||||
export class RegistryError extends IngestManagerError {}
|
||||
export class RegistryConnectionError extends RegistryError {}
|
||||
export class RegistryResponseError extends RegistryError {
|
||||
|
@ -30,6 +31,7 @@ export class PackageNotFoundError extends IngestManagerError {}
|
|||
export class PackageKeyInvalidError extends IngestManagerError {}
|
||||
export class PackageOutdatedError extends IngestManagerError {}
|
||||
export class AgentPolicyError extends IngestManagerError {}
|
||||
export class AgentNotFoundError extends IngestManagerError {}
|
||||
export class AgentPolicyNameExistsError extends AgentPolicyError {}
|
||||
export class PackageUnsupportedMediaTypeError extends IngestManagerError {}
|
||||
export class PackageInvalidArchiveError extends IngestManagerError {}
|
||||
|
|
|
@ -26,15 +26,17 @@ export {
|
|||
AgentPolicyServiceInterface,
|
||||
} from './services';
|
||||
export { FleetSetupContract, FleetSetupDeps, FleetStartContract, ExternalCallback } from './plugin';
|
||||
export { AgentNotFoundError } from './errors';
|
||||
|
||||
export const config: PluginConfigDescriptor = {
|
||||
exposeToBrowser: {
|
||||
epm: true,
|
||||
agents: true,
|
||||
},
|
||||
deprecations: ({ renameFromRoot }) => [
|
||||
deprecations: ({ renameFromRoot, unused }) => [
|
||||
renameFromRoot('xpack.ingestManager', 'xpack.fleet'),
|
||||
renameFromRoot('xpack.fleet.fleet', 'xpack.fleet.agents'),
|
||||
unused('agents.fleetServerEnabled'),
|
||||
],
|
||||
schema: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
|
@ -42,7 +44,6 @@ export const config: PluginConfigDescriptor = {
|
|||
registryProxyUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })),
|
||||
agents: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
fleetServerEnabled: schema.boolean({ defaultValue: false }),
|
||||
tlsCheckDisabled: schema.boolean({ defaultValue: false }),
|
||||
pollingRequestTimeout: schema.number({
|
||||
defaultValue: AGENT_POLLING_REQUEST_TIMEOUT_MS,
|
||||
|
|
|
@ -299,10 +299,7 @@ export class FleetPlugin
|
|||
licenseService.start(this.licensing$);
|
||||
agentCheckinState.start();
|
||||
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
|
||||
// Break the promise chain, the error handling is done in startFleetServerSetup
|
||||
startFleetServerSetup();
|
||||
}
|
||||
startFleetServerSetup();
|
||||
|
||||
return {
|
||||
esIndexPatternService: new ESIndexPatternSavedObjectService(),
|
||||
|
|
|
@ -21,7 +21,7 @@ export const postAgentAcksHandlerBuilder = function (
|
|||
try {
|
||||
const soClient = ackService.getSavedObjectsClientContract(request);
|
||||
const esClient = ackService.getElasticsearchClientContract();
|
||||
const agent = await ackService.authenticateAgentWithAccessToken(soClient, esClient, request);
|
||||
const agent = await ackService.authenticateAgentWithAccessToken(esClient, request);
|
||||
const agentEvents = request.body.events as AgentEvent[];
|
||||
|
||||
// validate that all events are for the authorized agent obtained from the api key
|
||||
|
|
|
@ -27,7 +27,7 @@ export const postNewAgentActionHandlerBuilder = function (
|
|||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asInternalUser;
|
||||
|
||||
const agent = await actionsService.getAgent(soClient, esClient, request.params.agentId);
|
||||
const agent = await actionsService.getAgent(esClient, request.params.agentId);
|
||||
|
||||
const newAgentAction = request.body.action;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ export const getAgentHandler: RequestHandler<
|
|||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
try {
|
||||
const agent = await AgentService.getAgent(soClient, esClient, request.params.agentId);
|
||||
const agent = await AgentService.getAgent(esClient, request.params.agentId);
|
||||
|
||||
const body: GetOneAgentResponse = {
|
||||
item: {
|
||||
|
@ -101,11 +101,10 @@ export const getAgentEventsHandler: RequestHandler<
|
|||
export const deleteAgentHandler: RequestHandler<
|
||||
TypeOf<typeof DeleteAgentRequestSchema.params>
|
||||
> = async (context, request, response) => {
|
||||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
try {
|
||||
await AgentService.deleteAgent(soClient, esClient, request.params.agentId);
|
||||
await AgentService.deleteAgent(esClient, request.params.agentId);
|
||||
|
||||
const body = {
|
||||
action: 'deleted',
|
||||
|
@ -129,14 +128,13 @@ export const updateAgentHandler: RequestHandler<
|
|||
undefined,
|
||||
TypeOf<typeof UpdateAgentRequestSchema.body>
|
||||
> = async (context, request, response) => {
|
||||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
try {
|
||||
await AgentService.updateAgent(soClient, esClient, request.params.agentId, {
|
||||
await AgentService.updateAgent(esClient, request.params.agentId, {
|
||||
user_provided_metadata: request.body.user_provided_metadata,
|
||||
});
|
||||
const agent = await AgentService.getAgent(soClient, esClient, request.params.agentId);
|
||||
const agent = await AgentService.getAgent(esClient, request.params.agentId);
|
||||
|
||||
const body = {
|
||||
item: {
|
||||
|
@ -165,7 +163,7 @@ export const postAgentCheckinHandler: RequestHandler<
|
|||
try {
|
||||
const soClient = appContextService.getInternalUserSOClient(request);
|
||||
const esClient = appContextService.getInternalUserESClient();
|
||||
const agent = await AgentService.authenticateAgentWithAccessToken(soClient, esClient, request);
|
||||
const agent = await AgentService.authenticateAgentWithAccessToken(esClient, request);
|
||||
const abortController = new AbortController();
|
||||
request.events.aborted$.subscribe(() => {
|
||||
abortController.abort();
|
||||
|
@ -209,11 +207,7 @@ export const postAgentEnrollHandler: RequestHandler<
|
|||
const soClient = appContextService.getInternalUserSOClient(request);
|
||||
const esClient = context.core.elasticsearch.client.asInternalUser;
|
||||
const { apiKeyId } = APIKeyService.parseApiKeyFromHeaders(request.headers);
|
||||
const enrollmentAPIKey = await APIKeyService.getEnrollmentAPIKeyById(
|
||||
soClient,
|
||||
esClient,
|
||||
apiKeyId
|
||||
);
|
||||
const enrollmentAPIKey = await APIKeyService.getEnrollmentAPIKeyById(esClient, apiKeyId);
|
||||
|
||||
if (!enrollmentAPIKey || !enrollmentAPIKey.active) {
|
||||
return response.unauthorized({
|
||||
|
@ -248,11 +242,10 @@ export const getAgentsHandler: RequestHandler<
|
|||
undefined,
|
||||
TypeOf<typeof GetAgentsRequestSchema.query>
|
||||
> = async (context, request, response) => {
|
||||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
try {
|
||||
const { agents, total, page, perPage } = await AgentService.listAgents(soClient, esClient, {
|
||||
const { agents, total, page, perPage } = await AgentService.listAgents(esClient, {
|
||||
page: request.query.page,
|
||||
perPage: request.query.perPage,
|
||||
showInactive: request.query.showInactive,
|
||||
|
@ -260,7 +253,7 @@ export const getAgentsHandler: RequestHandler<
|
|||
kuery: request.query.kuery,
|
||||
});
|
||||
const totalInactive = request.query.showInactive
|
||||
? await AgentService.countInactiveAgents(soClient, esClient, {
|
||||
? await AgentService.countInactiveAgents(esClient, {
|
||||
kuery: request.query.kuery,
|
||||
})
|
||||
: 0;
|
||||
|
|
|
@ -36,7 +36,7 @@ export const postAgentUpgradeHandler: RequestHandler<
|
|||
},
|
||||
});
|
||||
}
|
||||
const agent = await getAgent(soClient, esClient, request.params.agentId);
|
||||
const agent = await getAgent(esClient, request.params.agentId);
|
||||
if (agent.unenrollment_started_at || agent.unenrolled_at) {
|
||||
return response.customError({
|
||||
statusCode: 400,
|
||||
|
|
|
@ -58,7 +58,7 @@ export const getAgentPoliciesHandler: RequestHandler<
|
|||
await bluebird.map(
|
||||
items,
|
||||
(agentPolicy: GetAgentPoliciesResponseItem) =>
|
||||
listAgents(soClient, esClient, {
|
||||
listAgents(esClient, {
|
||||
showInactive: false,
|
||||
perPage: 0,
|
||||
page: 1,
|
||||
|
|
|
@ -27,19 +27,14 @@ export const getEnrollmentApiKeysHandler: RequestHandler<
|
|||
undefined,
|
||||
TypeOf<typeof GetEnrollmentAPIKeysRequestSchema.query>
|
||||
> = async (context, request, response) => {
|
||||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
|
||||
try {
|
||||
const { items, total, page, perPage } = await APIKeyService.listEnrollmentApiKeys(
|
||||
soClient,
|
||||
esClient,
|
||||
{
|
||||
page: request.query.page,
|
||||
perPage: request.query.perPage,
|
||||
kuery: request.query.kuery,
|
||||
}
|
||||
);
|
||||
const { items, total, page, perPage } = await APIKeyService.listEnrollmentApiKeys(esClient, {
|
||||
page: request.query.page,
|
||||
perPage: request.query.perPage,
|
||||
kuery: request.query.kuery,
|
||||
});
|
||||
const body: GetEnrollmentAPIKeysResponse = { list: items, total, page, perPage };
|
||||
|
||||
return response.ok({ body });
|
||||
|
@ -93,14 +88,9 @@ export const deleteEnrollmentApiKeyHandler: RequestHandler<
|
|||
export const getOneEnrollmentApiKeyHandler: RequestHandler<
|
||||
TypeOf<typeof GetOneEnrollmentAPIKeyRequestSchema.params>
|
||||
> = async (context, request, response) => {
|
||||
const soClient = context.core.savedObjects.client;
|
||||
const esClient = context.core.elasticsearch.client.asCurrentUser;
|
||||
try {
|
||||
const apiKey = await APIKeyService.getEnrollmentAPIKey(
|
||||
soClient,
|
||||
esClient,
|
||||
request.params.keyId
|
||||
);
|
||||
const apiKey = await APIKeyService.getEnrollmentAPIKey(esClient, request.params.keyId);
|
||||
const body: GetOneEnrollmentAPIKeyResponse = { item: apiKey };
|
||||
|
||||
return response.ok({ body });
|
||||
|
|
|
@ -520,7 +520,7 @@ class AgentPolicyService {
|
|||
throw new Error('The default agent policy cannot be deleted');
|
||||
}
|
||||
|
||||
const { total } = await listAgents(soClient, esClient, {
|
||||
const { total } = await listAgents(esClient, {
|
||||
showInactive: false,
|
||||
perPage: 0,
|
||||
page: 1,
|
||||
|
@ -554,9 +554,8 @@ class AgentPolicyService {
|
|||
agentPolicyId: string
|
||||
) {
|
||||
const esClient = appContextService.getInternalUserESClient();
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
|
||||
await this.createFleetPolicyChangeFleetServer(soClient, esClient, agentPolicyId);
|
||||
}
|
||||
|
||||
await this.createFleetPolicyChangeFleetServer(soClient, esClient, agentPolicyId);
|
||||
|
||||
return this.createFleetPolicyChangeActionSO(soClient, esClient, agentPolicyId);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,6 @@ export async function agentPolicyUpdateEventHandler(
|
|||
|
||||
if (action === 'deleted') {
|
||||
await unenrollForAgentPolicyId(soClient, esClient, agentPolicyId);
|
||||
await deleteEnrollmentApiKeyForAgentPolicyId(soClient, agentPolicyId);
|
||||
await deleteEnrollmentApiKeyForAgentPolicyId(soClient, esClient, agentPolicyId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,16 +108,21 @@ describe('test agent acks services', () => {
|
|||
]
|
||||
);
|
||||
expect(mockSavedObjectsClient.bulkUpdate).not.toBeCalled();
|
||||
expect(mockSavedObjectsClient.update).toBeCalled();
|
||||
expect(mockSavedObjectsClient.update.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
expect(mockElasticsearchClient.update).toBeCalled();
|
||||
expect(mockElasticsearchClient.update.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"fleet-agents",
|
||||
"id",
|
||||
Object {
|
||||
"packages": Array [
|
||||
"system",
|
||||
],
|
||||
"policy_revision": 4,
|
||||
"body": Object {
|
||||
"doc": Object {
|
||||
"packages": Array [
|
||||
"system",
|
||||
],
|
||||
"policy_revision_idx": 4,
|
||||
},
|
||||
},
|
||||
"id": "id",
|
||||
"index": ".fleet-agents",
|
||||
"refresh": "wait_for",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
@ -170,16 +175,21 @@ describe('test agent acks services', () => {
|
|||
]
|
||||
);
|
||||
expect(mockSavedObjectsClient.bulkUpdate).not.toBeCalled();
|
||||
expect(mockSavedObjectsClient.update).toBeCalled();
|
||||
expect(mockSavedObjectsClient.update.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
expect(mockElasticsearchClient.update).toBeCalled();
|
||||
expect(mockElasticsearchClient.update.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"fleet-agents",
|
||||
"id",
|
||||
Object {
|
||||
"packages": Array [
|
||||
"system",
|
||||
],
|
||||
"policy_revision": 4,
|
||||
"body": Object {
|
||||
"doc": Object {
|
||||
"packages": Array [
|
||||
"system",
|
||||
],
|
||||
"policy_revision_idx": 4,
|
||||
},
|
||||
},
|
||||
"id": "id",
|
||||
"index": ".fleet-agents",
|
||||
"refresh": "wait_for",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
|
|
@ -92,7 +92,7 @@ export async function acknowledgeAgentActions(
|
|||
const configChangeAction = getLatestConfigChangePolicyActionIfUpdated(agent, actions);
|
||||
|
||||
if (configChangeAction) {
|
||||
await updateAgent(soClient, esClient, agent.id, {
|
||||
await updateAgent(esClient, agent.id, {
|
||||
policy_revision: configChangeAction.policy_revision,
|
||||
packages: configChangeAction?.ack_data?.packages,
|
||||
});
|
||||
|
@ -201,7 +201,6 @@ export interface AcksService {
|
|||
) => Promise<AgentAction[]>;
|
||||
|
||||
authenticateAgentWithAccessToken: (
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
request: KibanaRequest
|
||||
) => Promise<Agent>;
|
||||
|
|
|
@ -76,10 +76,7 @@ async function createAction(
|
|||
}
|
||||
);
|
||||
|
||||
if (
|
||||
appContextService.getConfig()?.agents?.fleetServerEnabled &&
|
||||
isAgentActionSavedObject(actionSO)
|
||||
) {
|
||||
if (isAgentActionSavedObject(actionSO)) {
|
||||
const body: FleetServerAgentAction = {
|
||||
'@timestamp': new Date().toISOString(),
|
||||
expiration: new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(),
|
||||
|
@ -140,7 +137,7 @@ async function bulkCreateActions(
|
|||
}))
|
||||
);
|
||||
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
|
||||
if (actionSOs.length > 0) {
|
||||
await esClient.bulk({
|
||||
index: AGENT_ACTIONS_INDEX,
|
||||
body: actionSOs.flatMap((actionSO) => {
|
||||
|
@ -371,11 +368,7 @@ export async function getLatestConfigChangeAction(
|
|||
}
|
||||
|
||||
export interface ActionsService {
|
||||
getAgent: (
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
) => Promise<Agent>;
|
||||
getAgent: (esClient: ElasticsearchClient, agentId: string) => Promise<Agent>;
|
||||
|
||||
createAgentAction: (
|
||||
soClient: SavedObjectsClientContract,
|
||||
|
|
|
@ -6,35 +6,33 @@
|
|||
*/
|
||||
|
||||
import { KibanaRequest } from 'kibana/server';
|
||||
import { savedObjectsClientMock, elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
import { elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
|
||||
import { authenticateAgentWithAccessToken } from './authenticate';
|
||||
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
describe('test agent autenticate services', () => {
|
||||
it('should succeed with a valid API key and an active agent', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockSavedObjectsClient.find.mockReturnValue(
|
||||
Promise.resolve({
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'agent1',
|
||||
type: 'agent',
|
||||
references: [],
|
||||
score: 0,
|
||||
attributes: {
|
||||
active: true,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
mockEsClient.search.mockResolvedValue({
|
||||
body: {
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
_id: 'agent1',
|
||||
_source: {
|
||||
// @ts-expect-error
|
||||
active: true,
|
||||
// @ts-expect-error
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
await authenticateAgentWithAccessToken(mockSavedObjectsClient, mockEsClient, {
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
await authenticateAgentWithAccessToken(mockEsClient, {
|
||||
auth: { isAuthenticated: true },
|
||||
headers: {
|
||||
authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==',
|
||||
|
@ -43,28 +41,28 @@ describe('test agent autenticate services', () => {
|
|||
});
|
||||
|
||||
it('should throw if the request is not authenticated', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockSavedObjectsClient.find.mockReturnValue(
|
||||
Promise.resolve({
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'agent1',
|
||||
type: 'agent',
|
||||
references: [],
|
||||
score: 0,
|
||||
attributes: {
|
||||
active: true,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
mockEsClient.search.mockResolvedValue({
|
||||
body: {
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
// @ts-expect-error
|
||||
_id: 'agent1',
|
||||
_source: {
|
||||
// @ts-expect-error
|
||||
active: true,
|
||||
// @ts-expect-error
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
authenticateAgentWithAccessToken(mockSavedObjectsClient, mockEsClient, {
|
||||
authenticateAgentWithAccessToken(mockEsClient, {
|
||||
auth: { isAuthenticated: false },
|
||||
headers: {
|
||||
authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==',
|
||||
|
@ -74,28 +72,29 @@ describe('test agent autenticate services', () => {
|
|||
});
|
||||
|
||||
it('should throw if the ApiKey headers is malformed', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockSavedObjectsClient.find.mockReturnValue(
|
||||
Promise.resolve({
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'agent1',
|
||||
type: 'agent',
|
||||
references: [],
|
||||
score: 0,
|
||||
attributes: {
|
||||
active: false,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
const hits = [
|
||||
{
|
||||
_id: 'agent1',
|
||||
_source: {
|
||||
active: true,
|
||||
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
mockEsClient.search.mockResolvedValue({
|
||||
body: {
|
||||
hits: {
|
||||
// @ts-expect-error
|
||||
hits,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
authenticateAgentWithAccessToken(mockSavedObjectsClient, mockEsClient, {
|
||||
authenticateAgentWithAccessToken(mockEsClient, {
|
||||
auth: { isAuthenticated: true },
|
||||
headers: {
|
||||
authorization: 'aaaa',
|
||||
|
@ -105,28 +104,27 @@ describe('test agent autenticate services', () => {
|
|||
});
|
||||
|
||||
it('should throw if the agent is not active', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockSavedObjectsClient.find.mockReturnValue(
|
||||
Promise.resolve({
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'agent1',
|
||||
type: 'agent',
|
||||
references: [],
|
||||
score: 0,
|
||||
attributes: {
|
||||
active: false,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
const hits = [
|
||||
{
|
||||
_id: 'agent1',
|
||||
_source: {
|
||||
active: false,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
];
|
||||
mockEsClient.search.mockResolvedValue({
|
||||
body: {
|
||||
hits: {
|
||||
// @ts-expect-error
|
||||
hits,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
authenticateAgentWithAccessToken(mockSavedObjectsClient, mockEsClient, {
|
||||
authenticateAgentWithAccessToken(mockEsClient, {
|
||||
auth: { isAuthenticated: true },
|
||||
headers: {
|
||||
authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==',
|
||||
|
@ -136,17 +134,18 @@ describe('test agent autenticate services', () => {
|
|||
});
|
||||
|
||||
it('should throw if there is no agent matching the API key', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
mockSavedObjectsClient.find.mockReturnValue(
|
||||
Promise.resolve({
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [],
|
||||
})
|
||||
);
|
||||
const mockEsClient = elasticsearchServiceMock.createInternalClient();
|
||||
|
||||
mockEsClient.search.mockResolvedValue({
|
||||
body: {
|
||||
hits: {
|
||||
// @ts-expect-error
|
||||
hits: [],
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
authenticateAgentWithAccessToken(mockSavedObjectsClient, mockEsClient, {
|
||||
authenticateAgentWithAccessToken(mockEsClient, {
|
||||
auth: { isAuthenticated: true },
|
||||
headers: {
|
||||
authorization: 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==',
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Boom from '@hapi/boom';
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server';
|
||||
import type { ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
import type { Agent } from '../../types';
|
||||
import * as APIKeyService from '../api_keys';
|
||||
|
@ -15,7 +15,6 @@ import * as APIKeyService from '../api_keys';
|
|||
import { getAgentByAccessAPIKeyId } from './crud';
|
||||
|
||||
export async function authenticateAgentWithAccessToken(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
request: KibanaRequest
|
||||
): Promise<Agent> {
|
||||
|
@ -29,7 +28,7 @@ export async function authenticateAgentWithAccessToken(
|
|||
throw Boom.unauthorized(err.message);
|
||||
}
|
||||
|
||||
const agent = await getAgentByAccessAPIKeyId(soClient, esClient, res.apiKeyId);
|
||||
const agent = await getAgentByAccessAPIKeyId(esClient, res.apiKeyId);
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export async function agentCheckin(
|
|||
}
|
||||
// Update agent only if something changed
|
||||
if (Object.keys(updateData).length > 0) {
|
||||
await updateAgent(soClient, esClient, agent.id, updateData);
|
||||
await updateAgent(esClient, agent.id, updateData);
|
||||
}
|
||||
// Check if some actions are not acknowledged
|
||||
let actions = await getAgentActionsForCheckin(soClient, agent.id);
|
||||
|
|
|
@ -5,29 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { KibanaRequest } from 'src/core/server';
|
||||
|
||||
import { appContextService } from '../../app_context';
|
||||
import { bulkUpdateAgents } from '../crud';
|
||||
|
||||
function getInternalUserSOClient() {
|
||||
const fakeRequest = ({
|
||||
headers: {},
|
||||
getBasePath: () => '',
|
||||
path: '/',
|
||||
route: { settings: {} },
|
||||
url: {
|
||||
href: '/',
|
||||
},
|
||||
raw: {
|
||||
req: {
|
||||
url: '/',
|
||||
},
|
||||
},
|
||||
} as unknown) as KibanaRequest;
|
||||
|
||||
return appContextService.getInternalUserSOClient(fakeRequest);
|
||||
}
|
||||
export function agentCheckinStateConnectedAgentsFactory() {
|
||||
const connectedAgentsIds = new Set<string>();
|
||||
let agentToUpdate = new Set<string>();
|
||||
|
@ -58,7 +38,6 @@ export function agentCheckinStateConnectedAgentsFactory() {
|
|||
return;
|
||||
}
|
||||
const esClient = appContextService.getInternalUserESClient();
|
||||
const internalSOClient = getInternalUserSOClient();
|
||||
const now = new Date().toISOString();
|
||||
const updates = [...agentToUpdate.values()].map((agentId) => ({
|
||||
agentId,
|
||||
|
@ -67,7 +46,7 @@ export function agentCheckinStateConnectedAgentsFactory() {
|
|||
},
|
||||
}));
|
||||
agentToUpdate = new Set<string>([...connectedAgentsIds.values()]);
|
||||
await bulkUpdateAgents(internalSOClient, esClient, updates);
|
||||
await bulkUpdateAgents(esClient, updates);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -124,6 +124,7 @@ describe('test agent checkin new action services', () => {
|
|||
current_error_events: [],
|
||||
packages: [],
|
||||
enrolled_at: '2020-03-14T19:45:02.620Z',
|
||||
default_api_key: 'MOCK_API_KEY',
|
||||
};
|
||||
const mockPolicyAction: AgentPolicyAction = {
|
||||
id: 'action1',
|
||||
|
|
|
@ -24,16 +24,9 @@ import {
|
|||
import { KibanaRequest } from 'src/core/server';
|
||||
import type { ElasticsearchClient, SavedObjectsClientContract } from 'src/core/server';
|
||||
|
||||
import type {
|
||||
Agent,
|
||||
AgentAction,
|
||||
AgentPolicyAction,
|
||||
AgentPolicyActionV7_9,
|
||||
AgentSOAttributes,
|
||||
} from '../../../types';
|
||||
import type { Agent, AgentAction, AgentPolicyAction, AgentPolicyActionV7_9 } from '../../../types';
|
||||
import * as APIKeysService from '../../api_keys';
|
||||
import {
|
||||
AGENT_SAVED_OBJECT_TYPE,
|
||||
AGENT_UPDATE_ACTIONS_INTERVAL_MS,
|
||||
AGENT_POLLING_REQUEST_TIMEOUT_MARGIN_MS,
|
||||
AGENT_POLICY_ROLLOUT_RATE_LIMIT_INTERVAL_MS,
|
||||
|
@ -113,17 +106,7 @@ async function getAgentDefaultOutputAPIKey(
|
|||
esClient: ElasticsearchClient,
|
||||
agent: Agent
|
||||
) {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
|
||||
return agent.default_api_key;
|
||||
} else {
|
||||
const {
|
||||
attributes: { default_api_key: defaultApiKey },
|
||||
} = await appContextService
|
||||
.getEncryptedSavedObjects()
|
||||
.getDecryptedAsInternalUser<AgentSOAttributes>(AGENT_SAVED_OBJECT_TYPE, agent.id);
|
||||
|
||||
return defaultApiKey;
|
||||
}
|
||||
return agent.default_api_key;
|
||||
}
|
||||
|
||||
async function getOrCreateAgentDefaultOutputAPIKey(
|
||||
|
@ -137,7 +120,7 @@ async function getOrCreateAgentDefaultOutputAPIKey(
|
|||
}
|
||||
|
||||
const outputAPIKey = await APIKeysService.generateOutputApiKey(soClient, 'default', agent.id);
|
||||
await updateAgent(soClient, esClient, agent.id, {
|
||||
await updateAgent(esClient, agent.id, {
|
||||
default_api_key: outputAPIKey.key,
|
||||
default_api_key_id: outputAPIKey.id,
|
||||
});
|
||||
|
@ -282,7 +265,7 @@ export function agentCheckinStateNewActionsFactory() {
|
|||
(action) => action.type === 'INTERNAL_POLICY_REASSIGN'
|
||||
);
|
||||
if (hasConfigReassign) {
|
||||
return from(getAgent(soClient, esClient, agent.id)).pipe(
|
||||
return from(getAgent(esClient, agent.id)).pipe(
|
||||
concatMap((refreshedAgent) => {
|
||||
if (!refreshedAgent.policy_id) {
|
||||
throw new Error('Agent does not have a policy assigned');
|
||||
|
|
|
@ -5,16 +5,59 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types';
|
||||
import { appContextService, agentPolicyService } from '../../services';
|
||||
import { FleetServerAgent, isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common';
|
||||
import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants';
|
||||
import { ESSearchHit } from '../../../../../typings/elasticsearch';
|
||||
import { escapeSearchQueryPhrase, normalizeKuery } from '../saved_object';
|
||||
import { esKuery, KueryNode } from '../../../../../../src/plugins/data/server';
|
||||
import { IngestManagerError, isESClientError, AgentNotFoundError } from '../../errors';
|
||||
|
||||
import * as crudServiceSO from './crud_so';
|
||||
import * as crudServiceFleetServer from './crud_fleet_server';
|
||||
import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers';
|
||||
|
||||
const ACTIVE_AGENT_CONDITION = 'active:true';
|
||||
const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`;
|
||||
|
||||
function _joinFilters(filters: Array<string | undefined | KueryNode>): KueryNode | undefined {
|
||||
try {
|
||||
return filters
|
||||
.filter((filter) => filter !== undefined)
|
||||
.reduce((acc: KueryNode | undefined, kuery: string | KueryNode | undefined):
|
||||
| KueryNode
|
||||
| undefined => {
|
||||
if (kuery === undefined) {
|
||||
return acc;
|
||||
}
|
||||
const kueryNode: KueryNode =
|
||||
typeof kuery === 'string'
|
||||
? esKuery.fromKueryExpression(removeSOAttributes(kuery))
|
||||
: kuery;
|
||||
|
||||
if (!acc) {
|
||||
return kueryNode;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'function',
|
||||
function: 'and',
|
||||
arguments: [acc, kueryNode],
|
||||
};
|
||||
}, undefined as KueryNode | undefined);
|
||||
} catch (err) {
|
||||
throw new IngestManagerError(`Kuery is malformed: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function removeSOAttributes(kuery: string) {
|
||||
return kuery.replace(/attributes\./g, '').replace(/fleet-agents\./g, '');
|
||||
}
|
||||
|
||||
export async function listAgents(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
options: ListWithKuery & {
|
||||
showInactive: boolean;
|
||||
|
@ -25,15 +68,58 @@ export async function listAgents(
|
|||
page: number;
|
||||
perPage: number;
|
||||
}> {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
const {
|
||||
page = 1,
|
||||
perPage = 20,
|
||||
sortField = 'enrolled_at',
|
||||
sortOrder = 'desc',
|
||||
kuery,
|
||||
showInactive = false,
|
||||
showUpgradeable,
|
||||
} = options;
|
||||
const filters = [];
|
||||
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.listAgents(esClient, options)
|
||||
: crudServiceSO.listAgents(soClient, options);
|
||||
if (kuery && kuery !== '') {
|
||||
filters.push(kuery);
|
||||
}
|
||||
|
||||
if (showInactive === false) {
|
||||
filters.push(ACTIVE_AGENT_CONDITION);
|
||||
}
|
||||
|
||||
const kueryNode = _joinFilters(filters);
|
||||
const body = kueryNode ? { query: esKuery.toElasticsearchQuery(kueryNode) } : {};
|
||||
|
||||
const res = await esClient.search({
|
||||
index: AGENTS_INDEX,
|
||||
from: (page - 1) * perPage,
|
||||
size: perPage,
|
||||
sort: `${sortField}:${sortOrder}`,
|
||||
track_total_hits: true,
|
||||
body,
|
||||
});
|
||||
|
||||
let agentResults: Agent[] = res.body.hits.hits.map(searchHitToAgent);
|
||||
let total = res.body.hits.total.value;
|
||||
|
||||
// filtering for a range on the version string will not work,
|
||||
// nor does filtering on a flattened field (local_metadata), so filter here
|
||||
if (showUpgradeable) {
|
||||
agentResults = agentResults.filter((agent) =>
|
||||
isAgentUpgradeable(agent, appContextService.getKibanaVersion())
|
||||
);
|
||||
total = agentResults.length;
|
||||
}
|
||||
|
||||
return {
|
||||
agents: res.body.hits.hits.map(searchHitToAgent),
|
||||
total,
|
||||
page,
|
||||
perPage,
|
||||
};
|
||||
}
|
||||
|
||||
export async function listAllAgents(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
options: Omit<ListWithKuery, 'page' | 'perPage'> & {
|
||||
showInactive: boolean;
|
||||
|
@ -42,45 +128,157 @@ export async function listAllAgents(
|
|||
agents: Agent[];
|
||||
total: number;
|
||||
}> {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
const res = await listAgents(esClient, { ...options, page: 1, perPage: SO_SEARCH_LIMIT });
|
||||
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.listAllAgents(esClient, options)
|
||||
: crudServiceSO.listAllAgents(soClient, options);
|
||||
return {
|
||||
agents: res.agents,
|
||||
total: res.total,
|
||||
};
|
||||
}
|
||||
|
||||
export async function countInactiveAgents(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
options: Pick<ListWithKuery, 'kuery'>
|
||||
): Promise<number> {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
const { kuery } = options;
|
||||
const filters = [INACTIVE_AGENT_CONDITION];
|
||||
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.countInactiveAgents(esClient, options)
|
||||
: crudServiceSO.countInactiveAgents(soClient, options);
|
||||
if (kuery && kuery !== '') {
|
||||
filters.push(normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery));
|
||||
}
|
||||
|
||||
const kueryNode = _joinFilters(filters);
|
||||
const body = kueryNode ? { query: esKuery.toElasticsearchQuery(kueryNode) } : {};
|
||||
|
||||
const res = await esClient.search({
|
||||
index: AGENTS_INDEX,
|
||||
size: 0,
|
||||
track_total_hits: true,
|
||||
body,
|
||||
});
|
||||
return res.body.hits.total.value;
|
||||
}
|
||||
|
||||
export async function getAgent(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
) {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.getAgent(esClient, agentId)
|
||||
: crudServiceSO.getAgent(soClient, agentId);
|
||||
export async function getAgent(esClient: ElasticsearchClient, agentId: string) {
|
||||
try {
|
||||
const agentHit = await esClient.get<ESSearchHit<FleetServerAgent>>({
|
||||
index: AGENTS_INDEX,
|
||||
id: agentId,
|
||||
});
|
||||
const agent = searchHitToAgent(agentHit.body);
|
||||
|
||||
return agent;
|
||||
} catch (err) {
|
||||
if (isESClientError(err) && err.meta.statusCode === 404) {
|
||||
throw new AgentNotFoundError(`Agent ${agentId} not found`);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAgents(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentIds: string[]
|
||||
): Promise<Agent[]> {
|
||||
const body = { docs: agentIds.map((_id) => ({ _id })) };
|
||||
|
||||
const res = await esClient.mget({
|
||||
body,
|
||||
index: AGENTS_INDEX,
|
||||
});
|
||||
const agents = res.body.docs.map(searchHitToAgent);
|
||||
return agents;
|
||||
}
|
||||
|
||||
export async function getAgentByAccessAPIKeyId(
|
||||
esClient: ElasticsearchClient,
|
||||
accessAPIKeyId: string
|
||||
): Promise<Agent> {
|
||||
const res = await esClient.search<SearchResponse<FleetServerAgent>>({
|
||||
index: AGENTS_INDEX,
|
||||
q: `access_api_key_id:${escapeSearchQueryPhrase(accessAPIKeyId)}`,
|
||||
});
|
||||
|
||||
const [agent] = res.body.hits.hits.map(searchHitToAgent);
|
||||
|
||||
if (!agent) {
|
||||
throw new AgentNotFoundError('Agent not found');
|
||||
}
|
||||
if (agent.access_api_key_id !== accessAPIKeyId) {
|
||||
throw new Error('Agent api key id is not matching');
|
||||
}
|
||||
if (!agent.active) {
|
||||
throw Boom.forbidden('Agent inactive');
|
||||
}
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
export async function updateAgent(
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string,
|
||||
data: Partial<AgentSOAttributes>
|
||||
) {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.getAgents(esClient, agentIds)
|
||||
: crudServiceSO.getAgents(soClient, agentIds);
|
||||
await esClient.update({
|
||||
id: agentId,
|
||||
index: AGENTS_INDEX,
|
||||
body: { doc: agentSOAttributesToFleetServerAgentDoc(data) },
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
}
|
||||
|
||||
export async function bulkUpdateAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
updateData: Array<{
|
||||
agentId: string;
|
||||
data: Partial<AgentSOAttributes>;
|
||||
}>
|
||||
) {
|
||||
if (updateData.length === 0) {
|
||||
return { items: [] };
|
||||
}
|
||||
|
||||
const body = updateData.flatMap(({ agentId, data }) => [
|
||||
{
|
||||
update: {
|
||||
_id: agentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: { ...agentSOAttributesToFleetServerAgentDoc(data) },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await esClient.bulk({
|
||||
body,
|
||||
index: AGENTS_INDEX,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return {
|
||||
items: res.body.items.map((item: { update: { _id: string; error?: Error } }) => ({
|
||||
id: item.update._id,
|
||||
success: !item.update.error,
|
||||
error: item.update.error,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteAgent(esClient: ElasticsearchClient, agentId: string) {
|
||||
try {
|
||||
await esClient.update({
|
||||
id: agentId,
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: { active: false },
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
if (isESClientError(err) && err.meta.statusCode === 404) {
|
||||
throw new AgentNotFoundError('Agent not found');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAgentPolicyForAgent(
|
||||
|
@ -88,7 +286,7 @@ export async function getAgentPolicyForAgent(
|
|||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
) {
|
||||
const agent = await getAgent(soClient, esClient, agentId);
|
||||
const agent = await getAgent(esClient, agentId);
|
||||
if (!agent.policy_id) {
|
||||
return;
|
||||
}
|
||||
|
@ -98,51 +296,3 @@ export async function getAgentPolicyForAgent(
|
|||
return agentPolicy;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAgentByAccessAPIKeyId(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
accessAPIKeyId: string
|
||||
): Promise<Agent> {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.getAgentByAccessAPIKeyId(esClient, accessAPIKeyId)
|
||||
: crudServiceSO.getAgentByAccessAPIKeyId(soClient, accessAPIKeyId);
|
||||
}
|
||||
|
||||
export async function updateAgent(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string,
|
||||
data: Partial<AgentSOAttributes>
|
||||
) {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.updateAgent(esClient, agentId, data)
|
||||
: crudServiceSO.updateAgent(soClient, agentId, data);
|
||||
}
|
||||
|
||||
export async function bulkUpdateAgents(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
data: Array<{
|
||||
agentId: string;
|
||||
data: Partial<AgentSOAttributes>;
|
||||
}>
|
||||
) {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.bulkUpdateAgents(esClient, data)
|
||||
: crudServiceSO.bulkUpdateAgents(soClient, data);
|
||||
}
|
||||
|
||||
export async function deleteAgent(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
) {
|
||||
const fleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
return fleetServerEnabled
|
||||
? crudServiceFleetServer.deleteAgent(esClient, agentId)
|
||||
: crudServiceSO.deleteAgent(soClient, agentId);
|
||||
}
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
* 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 Boom from '@hapi/boom';
|
||||
import type { SearchResponse } from 'elasticsearch';
|
||||
import type { ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
import { isAgentUpgradeable, SO_SEARCH_LIMIT } from '../../../common';
|
||||
import type { FleetServerAgent } from '../../../common';
|
||||
import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants';
|
||||
import type { ESSearchHit } from '../../../../../typings/elasticsearch';
|
||||
import type { AgentSOAttributes, Agent, ListWithKuery } from '../../types';
|
||||
import { escapeSearchQueryPhrase, normalizeKuery } from '../saved_object';
|
||||
import { appContextService } from '../../services';
|
||||
import { esKuery } from '../../../../../../src/plugins/data/server';
|
||||
import type { KueryNode } from '../../../../../../src/plugins/data/server';
|
||||
|
||||
import { searchHitToAgent, agentSOAttributesToFleetServerAgentDoc } from './helpers';
|
||||
|
||||
const ACTIVE_AGENT_CONDITION = 'active:true';
|
||||
const INACTIVE_AGENT_CONDITION = `NOT (${ACTIVE_AGENT_CONDITION})`;
|
||||
|
||||
function _joinFilters(filters: Array<string | undefined | KueryNode>): KueryNode | undefined {
|
||||
return filters
|
||||
.filter((filter) => filter !== undefined)
|
||||
.reduce((acc: KueryNode | undefined, kuery: string | KueryNode | undefined):
|
||||
| KueryNode
|
||||
| undefined => {
|
||||
if (kuery === undefined) {
|
||||
return acc;
|
||||
}
|
||||
const kueryNode: KueryNode =
|
||||
typeof kuery === 'string' ? esKuery.fromKueryExpression(removeSOAttributes(kuery)) : kuery;
|
||||
|
||||
if (!acc) {
|
||||
return kueryNode;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'function',
|
||||
function: 'and',
|
||||
arguments: [acc, kueryNode],
|
||||
};
|
||||
}, undefined as KueryNode | undefined);
|
||||
}
|
||||
|
||||
export function removeSOAttributes(kuery: string) {
|
||||
return kuery.replace(/attributes\./g, '').replace(/fleet-agents\./g, '');
|
||||
}
|
||||
|
||||
export async function listAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
options: ListWithKuery & {
|
||||
showInactive: boolean;
|
||||
}
|
||||
): Promise<{
|
||||
agents: Agent[];
|
||||
total: number;
|
||||
page: number;
|
||||
perPage: number;
|
||||
}> {
|
||||
const {
|
||||
page = 1,
|
||||
perPage = 20,
|
||||
sortField = 'enrolled_at',
|
||||
sortOrder = 'desc',
|
||||
kuery,
|
||||
showInactive = false,
|
||||
showUpgradeable,
|
||||
} = options;
|
||||
const filters = [];
|
||||
|
||||
if (kuery && kuery !== '') {
|
||||
filters.push(kuery);
|
||||
}
|
||||
|
||||
if (showInactive === false) {
|
||||
filters.push(ACTIVE_AGENT_CONDITION);
|
||||
}
|
||||
|
||||
const kueryNode = _joinFilters(filters);
|
||||
const body = kueryNode ? { query: esKuery.toElasticsearchQuery(kueryNode) } : {};
|
||||
|
||||
const res = await esClient.search({
|
||||
index: AGENTS_INDEX,
|
||||
from: (page - 1) * perPage,
|
||||
size: perPage,
|
||||
sort: `${sortField}:${sortOrder}`,
|
||||
track_total_hits: true,
|
||||
body,
|
||||
});
|
||||
|
||||
let agentResults: Agent[] = res.body.hits.hits.map(searchHitToAgent);
|
||||
let total = res.body.hits.total.value;
|
||||
|
||||
// filtering for a range on the version string will not work,
|
||||
// nor does filtering on a flattened field (local_metadata), so filter here
|
||||
if (showUpgradeable) {
|
||||
agentResults = agentResults.filter((agent) =>
|
||||
isAgentUpgradeable(agent, appContextService.getKibanaVersion())
|
||||
);
|
||||
total = agentResults.length;
|
||||
}
|
||||
|
||||
return {
|
||||
agents: res.body.hits.hits.map(searchHitToAgent),
|
||||
total,
|
||||
page,
|
||||
perPage,
|
||||
};
|
||||
}
|
||||
|
||||
export async function listAllAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
options: Omit<ListWithKuery, 'page' | 'perPage'> & {
|
||||
showInactive: boolean;
|
||||
}
|
||||
): Promise<{
|
||||
agents: Agent[];
|
||||
total: number;
|
||||
}> {
|
||||
const res = await listAgents(esClient, { ...options, page: 1, perPage: SO_SEARCH_LIMIT });
|
||||
|
||||
return {
|
||||
agents: res.agents,
|
||||
total: res.total,
|
||||
};
|
||||
}
|
||||
|
||||
export async function countInactiveAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
options: Pick<ListWithKuery, 'kuery'>
|
||||
): Promise<number> {
|
||||
const { kuery } = options;
|
||||
const filters = [INACTIVE_AGENT_CONDITION];
|
||||
|
||||
if (kuery && kuery !== '') {
|
||||
filters.push(normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery));
|
||||
}
|
||||
|
||||
const kueryNode = _joinFilters(filters);
|
||||
const body = kueryNode ? { query: esKuery.toElasticsearchQuery(kueryNode) } : {};
|
||||
|
||||
const res = await esClient.search({
|
||||
index: AGENTS_INDEX,
|
||||
size: 0,
|
||||
track_total_hits: true,
|
||||
body,
|
||||
});
|
||||
return res.body.hits.total.value;
|
||||
}
|
||||
|
||||
export async function getAgent(esClient: ElasticsearchClient, agentId: string) {
|
||||
const agentHit = await esClient.get<ESSearchHit<FleetServerAgent>>({
|
||||
index: AGENTS_INDEX,
|
||||
id: agentId,
|
||||
});
|
||||
const agent = searchHitToAgent(agentHit.body);
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
export async function getAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
agentIds: string[]
|
||||
): Promise<Agent[]> {
|
||||
const body = { docs: agentIds.map((_id) => ({ _id })) };
|
||||
|
||||
const res = await esClient.mget({
|
||||
body,
|
||||
index: AGENTS_INDEX,
|
||||
});
|
||||
|
||||
const agents = res.body.docs.map(searchHitToAgent);
|
||||
return agents;
|
||||
}
|
||||
|
||||
export async function getAgentByAccessAPIKeyId(
|
||||
esClient: ElasticsearchClient,
|
||||
accessAPIKeyId: string
|
||||
): Promise<Agent> {
|
||||
const res = await esClient.search<SearchResponse<FleetServerAgent>>({
|
||||
index: AGENTS_INDEX,
|
||||
q: `access_api_key_id:${escapeSearchQueryPhrase(accessAPIKeyId)}`,
|
||||
});
|
||||
|
||||
const [agent] = res.body.hits.hits.map(searchHitToAgent);
|
||||
|
||||
if (!agent) {
|
||||
throw Boom.notFound('Agent not found');
|
||||
}
|
||||
if (agent.access_api_key_id !== accessAPIKeyId) {
|
||||
throw new Error('Agent api key id is not matching');
|
||||
}
|
||||
if (!agent.active) {
|
||||
throw Boom.forbidden('Agent inactive');
|
||||
}
|
||||
|
||||
return agent;
|
||||
}
|
||||
|
||||
export async function updateAgent(
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string,
|
||||
data: Partial<AgentSOAttributes>
|
||||
) {
|
||||
await esClient.update({
|
||||
id: agentId,
|
||||
index: AGENTS_INDEX,
|
||||
body: { doc: agentSOAttributesToFleetServerAgentDoc(data) },
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
}
|
||||
|
||||
export async function bulkUpdateAgents(
|
||||
esClient: ElasticsearchClient,
|
||||
updateData: Array<{
|
||||
agentId: string;
|
||||
data: Partial<AgentSOAttributes>;
|
||||
}>
|
||||
) {
|
||||
const body = updateData.flatMap(({ agentId, data }) => [
|
||||
{
|
||||
update: {
|
||||
_id: agentId,
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: { ...agentSOAttributesToFleetServerAgentDoc(data) },
|
||||
},
|
||||
]);
|
||||
|
||||
const res = await esClient.bulk({
|
||||
body,
|
||||
index: AGENTS_INDEX,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return {
|
||||
items: res.body.items.map((item: { update: { _id: string; error?: Error } }) => ({
|
||||
id: item.update._id,
|
||||
success: !item.update.error,
|
||||
error: item.update.error,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteAgent(esClient: ElasticsearchClient, agentId: string) {
|
||||
await esClient.update({
|
||||
id: agentId,
|
||||
index: AGENT_SAVED_OBJECT_TYPE,
|
||||
body: {
|
||||
doc: { active: false },
|
||||
},
|
||||
});
|
||||
}
|
|
@ -12,15 +12,13 @@ import semverDiff from 'semver/functions/diff';
|
|||
import semverLte from 'semver/functions/lte';
|
||||
import type { SavedObjectsClientContract } from 'src/core/server';
|
||||
|
||||
import type { AgentType, Agent, AgentSOAttributes, FleetServerAgent } from '../../types';
|
||||
import { AGENT_SAVED_OBJECT_TYPE, AGENTS_INDEX } from '../../constants';
|
||||
import type { AgentType, Agent, FleetServerAgent } from '../../types';
|
||||
import { AGENTS_INDEX } from '../../constants';
|
||||
import { IngestManagerError } from '../../errors';
|
||||
import * as APIKeyService from '../api_keys';
|
||||
import { agentPolicyService } from '../../services';
|
||||
import { appContextService } from '../app_context';
|
||||
|
||||
import { savedObjectToAgent } from './saved_objects';
|
||||
|
||||
export async function enroll(
|
||||
soClient: SavedObjectsClientContract,
|
||||
type: AgentType,
|
||||
|
@ -35,62 +33,33 @@ export async function enroll(
|
|||
throw new IngestManagerError(`Cannot enroll in managed policy ${agentPolicyId}`);
|
||||
}
|
||||
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled) {
|
||||
const esClient = appContextService.getInternalUserESClient();
|
||||
const esClient = appContextService.getInternalUserESClient();
|
||||
|
||||
const agentId = uuid();
|
||||
const accessAPIKey = await APIKeyService.generateAccessApiKey(soClient, agentId);
|
||||
const fleetServerAgent: FleetServerAgent = {
|
||||
active: true,
|
||||
policy_id: agentPolicyId,
|
||||
type,
|
||||
enrolled_at: new Date().toISOString(),
|
||||
user_provided_metadata: metadata?.userProvided ?? {},
|
||||
local_metadata: metadata?.local ?? {},
|
||||
access_api_key_id: accessAPIKey.id,
|
||||
};
|
||||
await esClient.create({
|
||||
index: AGENTS_INDEX,
|
||||
body: fleetServerAgent,
|
||||
id: agentId,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return {
|
||||
id: agentId,
|
||||
current_error_events: [],
|
||||
packages: [],
|
||||
...fleetServerAgent,
|
||||
access_api_key: accessAPIKey.key,
|
||||
} as Agent;
|
||||
}
|
||||
|
||||
const agentData: AgentSOAttributes = {
|
||||
const agentId = uuid();
|
||||
const accessAPIKey = await APIKeyService.generateAccessApiKey(soClient, agentId);
|
||||
const fleetServerAgent: FleetServerAgent = {
|
||||
active: true,
|
||||
policy_id: agentPolicyId,
|
||||
type,
|
||||
enrolled_at: new Date().toISOString(),
|
||||
user_provided_metadata: metadata?.userProvided ?? {},
|
||||
local_metadata: metadata?.local ?? {},
|
||||
current_error_events: undefined,
|
||||
access_api_key_id: undefined,
|
||||
last_checkin: undefined,
|
||||
default_api_key: undefined,
|
||||
};
|
||||
|
||||
const agent = savedObjectToAgent(
|
||||
await soClient.create<AgentSOAttributes>(AGENT_SAVED_OBJECT_TYPE, agentData, {
|
||||
refresh: false,
|
||||
})
|
||||
);
|
||||
|
||||
const accessAPIKey = await APIKeyService.generateAccessApiKey(soClient, agent.id);
|
||||
|
||||
await soClient.update<AgentSOAttributes>(AGENT_SAVED_OBJECT_TYPE, agent.id, {
|
||||
access_api_key_id: accessAPIKey.id,
|
||||
};
|
||||
await esClient.create({
|
||||
index: AGENTS_INDEX,
|
||||
body: fleetServerAgent,
|
||||
id: agentId,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return { ...agent, access_api_key: accessAPIKey.key };
|
||||
return {
|
||||
id: agentId,
|
||||
current_error_events: [],
|
||||
packages: [],
|
||||
...fleetServerAgent,
|
||||
access_api_key: accessAPIKey.key,
|
||||
} as Agent;
|
||||
}
|
||||
|
||||
export function validateAgentVersion(
|
||||
|
|
|
@ -8,31 +8,31 @@
|
|||
import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import type { SavedObject } from 'kibana/server';
|
||||
|
||||
import type { Agent, AgentPolicy } from '../../types';
|
||||
import type { AgentPolicy } from '../../types';
|
||||
import { AgentReassignmentError } from '../../errors';
|
||||
|
||||
import { reassignAgent, reassignAgents } from './reassign';
|
||||
|
||||
const agentInManagedSO = {
|
||||
id: 'agent-in-managed-policy',
|
||||
attributes: { policy_id: 'managed-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInManagedSO2 = {
|
||||
id: 'agent-in-managed-policy2',
|
||||
attributes: { policy_id: 'managed-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInUnmanagedSO = {
|
||||
id: 'agent-in-unmanaged-policy',
|
||||
attributes: { policy_id: 'unmanaged-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInUnmanagedSO2 = {
|
||||
id: 'agent-in-unmanaged-policy2',
|
||||
attributes: { policy_id: 'unmanaged-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInManagedDoc = {
|
||||
_id: 'agent-in-managed-policy',
|
||||
_source: { policy_id: 'managed-agent-policy' },
|
||||
};
|
||||
const agentInManagedDoc2 = {
|
||||
_id: 'agent-in-managed-policy2',
|
||||
_source: { policy_id: 'managed-agent-policy' },
|
||||
};
|
||||
const agentInUnmanagedDoc = {
|
||||
_id: 'agent-in-unmanaged-policy',
|
||||
_source: { policy_id: 'unmanaged-agent-policy' },
|
||||
};
|
||||
const unmanagedAgentPolicySO = {
|
||||
id: 'unmanaged-agent-policy',
|
||||
attributes: { is_managed: false },
|
||||
} as SavedObject<AgentPolicy>;
|
||||
const unmanagedAgentPolicySO2 = {
|
||||
id: 'unmanaged-agent-policy-2',
|
||||
attributes: { is_managed: false },
|
||||
} as SavedObject<AgentPolicy>;
|
||||
const managedAgentPolicySO = {
|
||||
id: 'managed-agent-policy',
|
||||
attributes: { is_managed: true },
|
||||
|
@ -40,70 +40,70 @@ const managedAgentPolicySO = {
|
|||
|
||||
describe('reassignAgent (singular)', () => {
|
||||
it('can reassign from unmanaged policy to unmanaged', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
await reassignAgent(soClient, esClient, agentInUnmanagedSO.id, agentInUnmanagedSO2.id);
|
||||
const { soClient, esClient } = createClientsMock();
|
||||
await reassignAgent(soClient, esClient, agentInUnmanagedDoc._id, unmanagedAgentPolicySO.id);
|
||||
|
||||
// calls ES update with correct values
|
||||
expect(soClient.update).toBeCalledTimes(1);
|
||||
const calledWith = soClient.update.mock.calls[0];
|
||||
expect(calledWith[1]).toBe(agentInUnmanagedSO.id);
|
||||
expect(calledWith[2]).toHaveProperty('policy_id', agentInUnmanagedSO2.id);
|
||||
expect(esClient.update).toBeCalledTimes(1);
|
||||
const calledWith = esClient.update.mock.calls[0];
|
||||
expect(calledWith[0]?.id).toBe(agentInUnmanagedDoc._id);
|
||||
// @ts-expect-error
|
||||
expect(calledWith[0]?.body?.doc).toHaveProperty('policy_id', unmanagedAgentPolicySO.id);
|
||||
});
|
||||
|
||||
it('cannot reassign from unmanaged policy to managed', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const { soClient, esClient } = createClientsMock();
|
||||
await expect(
|
||||
reassignAgent(
|
||||
soClient,
|
||||
esClient,
|
||||
agentInUnmanagedSO.id,
|
||||
agentInManagedSO.attributes.policy_id!
|
||||
)
|
||||
reassignAgent(soClient, esClient, agentInUnmanagedDoc._id, managedAgentPolicySO.id)
|
||||
).rejects.toThrowError(AgentReassignmentError);
|
||||
|
||||
// does not call ES update
|
||||
expect(soClient.update).toBeCalledTimes(0);
|
||||
expect(esClient.update).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it('cannot reassign from managed policy', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const { soClient, esClient } = createClientsMock();
|
||||
await expect(
|
||||
reassignAgent(soClient, esClient, agentInManagedSO.id, agentInManagedSO2.id)
|
||||
reassignAgent(soClient, esClient, agentInManagedDoc._id, unmanagedAgentPolicySO.id)
|
||||
).rejects.toThrowError(AgentReassignmentError);
|
||||
// does not call ES update
|
||||
expect(soClient.update).toBeCalledTimes(0);
|
||||
expect(esClient.update).toBeCalledTimes(0);
|
||||
|
||||
await expect(
|
||||
reassignAgent(soClient, esClient, agentInManagedSO.id, agentInUnmanagedSO.id)
|
||||
reassignAgent(soClient, esClient, agentInManagedDoc._id, managedAgentPolicySO.id)
|
||||
).rejects.toThrowError(AgentReassignmentError);
|
||||
// does not call ES update
|
||||
expect(soClient.update).toBeCalledTimes(0);
|
||||
expect(esClient.update).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reassignAgents (plural)', () => {
|
||||
it('agents in managed policies are not updated', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const idsToReassign = [agentInUnmanagedSO.id, agentInManagedSO.id, agentInUnmanagedSO.id];
|
||||
await reassignAgents(soClient, esClient, { agentIds: idsToReassign }, agentInUnmanagedSO.id);
|
||||
const { soClient, esClient } = createClientsMock();
|
||||
const idsToReassign = [agentInUnmanagedDoc._id, agentInManagedDoc._id, agentInManagedDoc2._id];
|
||||
await reassignAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
{ agentIds: idsToReassign },
|
||||
unmanagedAgentPolicySO2.id
|
||||
);
|
||||
|
||||
// calls ES update with correct values
|
||||
const calledWith = soClient.bulkUpdate.mock.calls[0][0];
|
||||
const expectedResults = [agentInUnmanagedSO.id, agentInUnmanagedSO.id];
|
||||
expect(calledWith.length).toBe(expectedResults.length); // only 2 are unmanaged
|
||||
expect(calledWith.map(({ id }) => id)).toEqual(expectedResults);
|
||||
const calledWith = esClient.bulk.mock.calls[0][0];
|
||||
// only 1 are unmanaged and bulk write two line per update
|
||||
// @ts-expect-error
|
||||
expect(calledWith.body.length).toBe(2);
|
||||
// @ts-expect-error
|
||||
expect(calledWith.body[0].update._id).toEqual(agentInUnmanagedDoc._id);
|
||||
});
|
||||
});
|
||||
|
||||
function createClientMock() {
|
||||
function createClientsMock() {
|
||||
const soClientMock = savedObjectsClientMock.create();
|
||||
|
||||
// need to mock .create & bulkCreate due to (bulk)createAgentAction(s) in reassignAgent(s)
|
||||
soClientMock.create.mockResolvedValue(agentInUnmanagedSO);
|
||||
// @ts-expect-error
|
||||
soClientMock.create.mockResolvedValue({ attributes: { agent_id: 'test' } });
|
||||
soClientMock.bulkCreate.mockImplementation(async ([{ type, attributes }]) => {
|
||||
return {
|
||||
saved_objects: [await soClientMock.create(type, attributes)],
|
||||
|
@ -112,26 +112,48 @@ function createClientMock() {
|
|||
soClientMock.bulkUpdate.mockResolvedValue({
|
||||
saved_objects: [],
|
||||
});
|
||||
|
||||
soClientMock.get.mockImplementation(async (_, id) => {
|
||||
switch (id) {
|
||||
case unmanagedAgentPolicySO.id:
|
||||
return unmanagedAgentPolicySO;
|
||||
case managedAgentPolicySO.id:
|
||||
return managedAgentPolicySO;
|
||||
case agentInManagedSO.id:
|
||||
return agentInManagedSO;
|
||||
case agentInUnmanagedSO.id:
|
||||
case unmanagedAgentPolicySO2.id:
|
||||
return unmanagedAgentPolicySO2;
|
||||
default:
|
||||
return agentInUnmanagedSO;
|
||||
throw new Error('Not found');
|
||||
}
|
||||
});
|
||||
|
||||
soClientMock.bulkGet.mockImplementation(async (options) => {
|
||||
return {
|
||||
saved_objects: await Promise.all(options!.map(({ type, id }) => soClientMock.get(type, id))),
|
||||
};
|
||||
});
|
||||
|
||||
return soClientMock;
|
||||
const esClientMock = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
// @ts-expect-error
|
||||
esClientMock.mget.mockImplementation(async () => {
|
||||
return {
|
||||
body: {
|
||||
docs: [agentInManagedDoc, agentInUnmanagedDoc, agentInManagedDoc2],
|
||||
},
|
||||
};
|
||||
});
|
||||
// @ts-expect-error
|
||||
esClientMock.get.mockImplementation(async ({ id }) => {
|
||||
switch (id) {
|
||||
case agentInManagedDoc._id:
|
||||
return { body: agentInManagedDoc };
|
||||
case agentInUnmanagedDoc._id:
|
||||
return { body: agentInUnmanagedDoc };
|
||||
default:
|
||||
throw new Error('Not found');
|
||||
}
|
||||
});
|
||||
// @ts-expect-error
|
||||
esClientMock.bulk.mockResolvedValue({
|
||||
body: { items: [] },
|
||||
});
|
||||
|
||||
return { soClient: soClientMock, esClient: esClientMock };
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ export async function reassignAgent(
|
|||
|
||||
await reassignAgentIsAllowed(soClient, esClient, agentId, newAgentPolicyId);
|
||||
|
||||
await updateAgent(soClient, esClient, agentId, {
|
||||
await updateAgent(esClient, agentId, {
|
||||
policy_id: newAgentPolicyId,
|
||||
policy_revision: null,
|
||||
});
|
||||
|
@ -79,7 +79,7 @@ export async function reassignAgents(
|
|||
kuery: string;
|
||||
},
|
||||
newAgentPolicyId: string
|
||||
): Promise<{ items: Array<{ id: string; sucess: boolean; error?: Error }> }> {
|
||||
): Promise<{ items: Array<{ id: string; success: boolean; error?: Error }> }> {
|
||||
const agentPolicy = await agentPolicyService.get(soClient, newAgentPolicyId);
|
||||
if (!agentPolicy) {
|
||||
throw Boom.notFound(`Agent policy not found: ${newAgentPolicyId}`);
|
||||
|
@ -88,9 +88,9 @@ export async function reassignAgents(
|
|||
// Filter to agents that do not already use the new agent policy ID
|
||||
const agents =
|
||||
'agentIds' in options
|
||||
? await getAgents(soClient, esClient, options.agentIds)
|
||||
? await getAgents(esClient, options.agentIds)
|
||||
: (
|
||||
await listAllAgents(soClient, esClient, {
|
||||
await listAllAgents(esClient, {
|
||||
kuery: options.kuery,
|
||||
showInactive: false,
|
||||
})
|
||||
|
@ -106,7 +106,6 @@ export async function reassignAgents(
|
|||
);
|
||||
|
||||
const res = await bulkUpdateAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
agentsToUpdate.map((agent) => ({
|
||||
agentId: agent.id,
|
||||
|
|
|
@ -5,79 +5,80 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import type { SavedObject } from 'kibana/server';
|
||||
|
||||
import { AGENT_TYPE_PERMANENT } from '../../../common/constants';
|
||||
import type { AgentSOAttributes } from '../../../common/types/models';
|
||||
import { elasticsearchServiceMock } from 'src/core/server/mocks';
|
||||
|
||||
import { getAgentStatusById } from './status';
|
||||
|
||||
describe('Agent status service', () => {
|
||||
it('should return inactive when agent is not active', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const mockElasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
mockSavedObjectsClient.get = jest.fn().mockReturnValue({
|
||||
id: 'id',
|
||||
type: AGENT_TYPE_PERMANENT,
|
||||
attributes: {
|
||||
active: false,
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
// @ts-expect-error
|
||||
mockElasticsearchClient.get.mockResolvedValue({
|
||||
body: {
|
||||
_id: 'id',
|
||||
_source: {
|
||||
active: false,
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
},
|
||||
},
|
||||
} as SavedObject<AgentSOAttributes>);
|
||||
const status = await getAgentStatusById(mockSavedObjectsClient, mockElasticsearchClient, 'id');
|
||||
});
|
||||
const status = await getAgentStatusById(mockElasticsearchClient, 'id');
|
||||
expect(status).toEqual('inactive');
|
||||
});
|
||||
|
||||
it('should return online when agent is active', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const mockElasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
mockSavedObjectsClient.get = jest.fn().mockReturnValue({
|
||||
id: 'id',
|
||||
type: AGENT_TYPE_PERMANENT,
|
||||
attributes: {
|
||||
active: true,
|
||||
last_checkin: new Date().toISOString(),
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
// @ts-expect-error
|
||||
mockElasticsearchClient.get.mockResolvedValue({
|
||||
body: {
|
||||
_id: 'id',
|
||||
_source: {
|
||||
active: true,
|
||||
last_checkin: new Date().toISOString(),
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
},
|
||||
},
|
||||
} as SavedObject<AgentSOAttributes>);
|
||||
const status = await getAgentStatusById(mockSavedObjectsClient, mockElasticsearchClient, 'id');
|
||||
});
|
||||
const status = await getAgentStatusById(mockElasticsearchClient, 'id');
|
||||
expect(status).toEqual('online');
|
||||
});
|
||||
|
||||
it('should return enrolling when agent is active but never checkin', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const mockElasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
mockSavedObjectsClient.get = jest.fn().mockReturnValue({
|
||||
id: 'id',
|
||||
type: AGENT_TYPE_PERMANENT,
|
||||
attributes: {
|
||||
active: true,
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
// @ts-expect-error
|
||||
mockElasticsearchClient.get.mockResolvedValue({
|
||||
body: {
|
||||
_id: 'id',
|
||||
_source: {
|
||||
active: true,
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
},
|
||||
},
|
||||
} as SavedObject<AgentSOAttributes>);
|
||||
const status = await getAgentStatusById(mockSavedObjectsClient, mockElasticsearchClient, 'id');
|
||||
});
|
||||
const status = await getAgentStatusById(mockElasticsearchClient, 'id');
|
||||
expect(status).toEqual('enrolling');
|
||||
});
|
||||
|
||||
it('should return unenrolling when agent is unenrolling', async () => {
|
||||
const mockSavedObjectsClient = savedObjectsClientMock.create();
|
||||
const mockElasticsearchClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
mockSavedObjectsClient.get = jest.fn().mockReturnValue({
|
||||
id: 'id',
|
||||
type: AGENT_TYPE_PERMANENT,
|
||||
attributes: {
|
||||
active: true,
|
||||
last_checkin: new Date().toISOString(),
|
||||
unenrollment_started_at: new Date().toISOString(),
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
// @ts-expect-error
|
||||
mockElasticsearchClient.get.mockResolvedValue({
|
||||
body: {
|
||||
_id: 'id',
|
||||
|
||||
_source: {
|
||||
active: true,
|
||||
last_checkin: new Date().toISOString(),
|
||||
unenrollment_started_at: new Date().toISOString(),
|
||||
local_metadata: {},
|
||||
user_provided_metadata: {},
|
||||
},
|
||||
},
|
||||
} as SavedObject<AgentSOAttributes>);
|
||||
const status = await getAgentStatusById(mockSavedObjectsClient, mockElasticsearchClient, 'id');
|
||||
});
|
||||
const status = await getAgentStatusById(mockElasticsearchClient, 'id');
|
||||
expect(status).toEqual('unenrolling');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,26 +13,20 @@ import type { AgentStatus } from '../../types';
|
|||
import { AgentStatusKueryHelper } from '../../../common/services';
|
||||
import { esKuery } from '../../../../../../src/plugins/data/server';
|
||||
import type { KueryNode } from '../../../../../../src/plugins/data/server';
|
||||
import { normalizeKuery } from '../saved_object';
|
||||
import { appContextService } from '../app_context';
|
||||
|
||||
import { getAgent, listAgents } from './crud';
|
||||
import { removeSOAttributes } from './crud_fleet_server';
|
||||
import { getAgent, listAgents, removeSOAttributes } from './crud';
|
||||
|
||||
export async function getAgentStatusById(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
): Promise<AgentStatus> {
|
||||
const agent = await getAgent(soClient, esClient, agentId);
|
||||
const agent = await getAgent(esClient, agentId);
|
||||
return AgentStatusKueryHelper.getAgentStatus(agent);
|
||||
}
|
||||
|
||||
export const getAgentStatus = AgentStatusKueryHelper.getAgentStatus;
|
||||
|
||||
function joinKuerys(...kuerys: Array<string | undefined>) {
|
||||
const isFleetServerEnabled = appContextService.getConfig()?.agents?.fleetServerEnabled;
|
||||
|
||||
return kuerys
|
||||
.filter((kuery) => kuery !== undefined)
|
||||
.reduce((acc: KueryNode | undefined, kuery: string | undefined): KueryNode | undefined => {
|
||||
|
@ -40,9 +34,7 @@ function joinKuerys(...kuerys: Array<string | undefined>) {
|
|||
return acc;
|
||||
}
|
||||
const normalizedKuery: KueryNode = esKuery.fromKueryExpression(
|
||||
isFleetServerEnabled
|
||||
? removeSOAttributes(kuery || '')
|
||||
: normalizeKuery(AGENT_SAVED_OBJECT_TYPE, kuery || '')
|
||||
removeSOAttributes(kuery || '')
|
||||
);
|
||||
|
||||
if (!acc) {
|
||||
|
@ -72,7 +64,7 @@ export async function getAgentStatusForAgentPolicy(
|
|||
AgentStatusKueryHelper.buildKueryForUpdatingAgents(),
|
||||
],
|
||||
(kuery) =>
|
||||
listAgents(soClient, esClient, {
|
||||
listAgents(esClient, {
|
||||
showInactive: false,
|
||||
perPage: 0,
|
||||
page: 1,
|
||||
|
|
|
@ -8,23 +8,23 @@
|
|||
import { elasticsearchServiceMock, savedObjectsClientMock } from 'src/core/server/mocks';
|
||||
import type { SavedObject } from 'kibana/server';
|
||||
|
||||
import type { Agent, AgentPolicy } from '../../types';
|
||||
import type { AgentPolicy } from '../../types';
|
||||
import { AgentUnenrollmentError } from '../../errors';
|
||||
|
||||
import { unenrollAgent, unenrollAgents } from './unenroll';
|
||||
|
||||
const agentInManagedSO = {
|
||||
id: 'agent-in-managed-policy',
|
||||
attributes: { policy_id: 'managed-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInUnmanagedSO = {
|
||||
id: 'agent-in-unmanaged-policy',
|
||||
attributes: { policy_id: 'unmanaged-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInUnmanagedSO2 = {
|
||||
id: 'agent-in-unmanaged-policy2',
|
||||
attributes: { policy_id: 'unmanaged-agent-policy' },
|
||||
} as SavedObject<Agent>;
|
||||
const agentInManagedDoc = {
|
||||
_id: 'agent-in-managed-policy',
|
||||
_source: { policy_id: 'managed-agent-policy' },
|
||||
};
|
||||
const agentInUnmanagedDoc = {
|
||||
_id: 'agent-in-unmanaged-policy',
|
||||
_source: { policy_id: 'unmanaged-agent-policy' },
|
||||
};
|
||||
const agentInUnmanagedDoc2 = {
|
||||
_id: 'agent-in-unmanaged-policy2',
|
||||
_source: { policy_id: 'unmanaged-agent-policy' },
|
||||
};
|
||||
const unmanagedAgentPolicySO = {
|
||||
id: 'unmanaged-agent-policy',
|
||||
attributes: { is_managed: false },
|
||||
|
@ -36,57 +36,69 @@ const managedAgentPolicySO = {
|
|||
|
||||
describe('unenrollAgent (singular)', () => {
|
||||
it('can unenroll from unmanaged policy', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
await unenrollAgent(soClient, esClient, agentInUnmanagedSO.id);
|
||||
const { soClient, esClient } = createClientMock();
|
||||
await unenrollAgent(soClient, esClient, agentInUnmanagedDoc._id);
|
||||
|
||||
// calls ES update with correct values
|
||||
expect(soClient.update).toBeCalledTimes(1);
|
||||
const calledWith = soClient.update.mock.calls[0];
|
||||
expect(calledWith[1]).toBe(agentInUnmanagedSO.id);
|
||||
expect(calledWith[2]).toHaveProperty('unenrollment_started_at');
|
||||
expect(esClient.update).toBeCalledTimes(1);
|
||||
const calledWith = esClient.update.mock.calls[0];
|
||||
expect(calledWith[0]?.id).toBe(agentInUnmanagedDoc._id);
|
||||
expect(calledWith[0]?.body).toHaveProperty('doc.unenrollment_started_at');
|
||||
});
|
||||
|
||||
it('cannot unenroll from managed policy', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
await expect(unenrollAgent(soClient, esClient, agentInManagedSO.id)).rejects.toThrowError(
|
||||
const { soClient, esClient } = createClientMock();
|
||||
await expect(unenrollAgent(soClient, esClient, agentInManagedDoc._id)).rejects.toThrowError(
|
||||
AgentUnenrollmentError
|
||||
);
|
||||
// does not call ES update
|
||||
expect(soClient.update).toBeCalledTimes(0);
|
||||
expect(esClient.update).toBeCalledTimes(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('unenrollAgents (plural)', () => {
|
||||
it('can unenroll from an unmanaged policy', async () => {
|
||||
const soClient = createClientMock();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const idsToUnenroll = [agentInUnmanagedSO.id, agentInUnmanagedSO2.id];
|
||||
const { soClient, esClient } = createClientMock();
|
||||
const idsToUnenroll = [agentInUnmanagedDoc._id, agentInUnmanagedDoc2._id];
|
||||
await unenrollAgents(soClient, esClient, { agentIds: idsToUnenroll });
|
||||
|
||||
// calls ES update with correct values
|
||||
const calledWith = soClient.bulkUpdate.mock.calls[0][0];
|
||||
expect(calledWith.length).toBe(idsToUnenroll.length);
|
||||
expect(calledWith.map(({ id }) => id)).toEqual(idsToUnenroll);
|
||||
for (const params of calledWith) {
|
||||
expect(params.attributes).toHaveProperty('unenrollment_started_at');
|
||||
const calledWith = esClient.bulk.mock.calls[1][0];
|
||||
const ids = calledWith?.body
|
||||
// @ts-expect-error
|
||||
.filter((i: any) => i.update !== undefined)
|
||||
.map((i: any) => i.update._id);
|
||||
// @ts-expect-error
|
||||
const docs = calledWith?.body.filter((i: any) => i.doc).map((i: any) => i.doc);
|
||||
expect(ids).toHaveLength(2);
|
||||
expect(ids).toEqual(idsToUnenroll);
|
||||
for (const doc of docs) {
|
||||
expect(doc).toHaveProperty('unenrollment_started_at');
|
||||
}
|
||||
});
|
||||
it('cannot unenroll from a managed policy', async () => {
|
||||
const soClient = createClientMock();
|
||||
const { soClient, esClient } = createClientMock();
|
||||
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const idsToUnenroll = [agentInUnmanagedSO.id, agentInManagedSO.id, agentInUnmanagedSO2.id];
|
||||
const idsToUnenroll = [
|
||||
agentInUnmanagedDoc._id,
|
||||
agentInManagedDoc._id,
|
||||
agentInUnmanagedDoc2._id,
|
||||
];
|
||||
await unenrollAgents(soClient, esClient, { agentIds: idsToUnenroll });
|
||||
|
||||
// calls ES update with correct values
|
||||
const calledWith = soClient.bulkUpdate.mock.calls[0][0];
|
||||
const onlyUnmanaged = [agentInUnmanagedSO.id, agentInUnmanagedSO2.id];
|
||||
expect(calledWith.length).toBe(onlyUnmanaged.length);
|
||||
expect(calledWith.map(({ id }) => id)).toEqual(onlyUnmanaged);
|
||||
for (const params of calledWith) {
|
||||
expect(params.attributes).toHaveProperty('unenrollment_started_at');
|
||||
const onlyUnmanaged = [agentInUnmanagedDoc._id, agentInUnmanagedDoc2._id];
|
||||
const calledWith = esClient.bulk.mock.calls[1][0];
|
||||
const ids = calledWith?.body
|
||||
// @ts-expect-error
|
||||
.filter((i: any) => i.update !== undefined)
|
||||
.map((i: any) => i.update._id);
|
||||
// @ts-expect-error
|
||||
const docs = calledWith?.body.filter((i: any) => i.doc).map((i: any) => i.doc);
|
||||
expect(ids).toHaveLength(onlyUnmanaged.length);
|
||||
expect(ids).toEqual(onlyUnmanaged);
|
||||
for (const doc of docs) {
|
||||
expect(doc).toHaveProperty('unenrollment_started_at');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -95,7 +107,8 @@ function createClientMock() {
|
|||
const soClientMock = savedObjectsClientMock.create();
|
||||
|
||||
// need to mock .create & bulkCreate due to (bulk)createAgentAction(s) in unenrollAgent(s)
|
||||
soClientMock.create.mockResolvedValue(agentInUnmanagedSO);
|
||||
// @ts-expect-error
|
||||
soClientMock.create.mockResolvedValue({ attributes: { agent_id: 'tata' } });
|
||||
soClientMock.bulkCreate.mockImplementation(async ([{ type, attributes }]) => {
|
||||
return {
|
||||
saved_objects: [await soClientMock.create(type, attributes)],
|
||||
|
@ -111,13 +124,8 @@ function createClientMock() {
|
|||
return unmanagedAgentPolicySO;
|
||||
case managedAgentPolicySO.id:
|
||||
return managedAgentPolicySO;
|
||||
case agentInManagedSO.id:
|
||||
return agentInManagedSO;
|
||||
case agentInUnmanagedSO2.id:
|
||||
return agentInUnmanagedSO2;
|
||||
case agentInUnmanagedSO.id:
|
||||
default:
|
||||
return agentInUnmanagedSO;
|
||||
throw new Error('not found');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -127,5 +135,46 @@ function createClientMock() {
|
|||
};
|
||||
});
|
||||
|
||||
return soClientMock;
|
||||
const esClientMock = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
// @ts-expect-error
|
||||
esClientMock.get.mockImplementation(async ({ id }) => {
|
||||
switch (id) {
|
||||
case agentInManagedDoc._id:
|
||||
return { body: agentInManagedDoc };
|
||||
case agentInUnmanagedDoc2._id:
|
||||
return { body: agentInUnmanagedDoc2 };
|
||||
case agentInUnmanagedDoc._id:
|
||||
return { body: agentInUnmanagedDoc };
|
||||
default:
|
||||
throw new Error('not found');
|
||||
}
|
||||
});
|
||||
// @ts-expect-error
|
||||
esClientMock.bulk.mockResolvedValue({
|
||||
body: { items: [] },
|
||||
});
|
||||
|
||||
// @ts-expect-error
|
||||
esClientMock.mget.mockImplementation(async (params) => {
|
||||
// @ts-expect-error
|
||||
const docs = params?.body.docs.map(({ _id }) => {
|
||||
switch (_id) {
|
||||
case agentInManagedDoc._id:
|
||||
return agentInManagedDoc;
|
||||
case agentInUnmanagedDoc2._id:
|
||||
return agentInUnmanagedDoc2;
|
||||
case agentInUnmanagedDoc._id:
|
||||
return agentInUnmanagedDoc;
|
||||
default:
|
||||
throw new Error('not found');
|
||||
}
|
||||
});
|
||||
return {
|
||||
body: {
|
||||
docs,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return { soClient: soClientMock, esClient: esClientMock };
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ export async function unenrollAgent(
|
|||
created_at: now,
|
||||
type: 'UNENROLL',
|
||||
});
|
||||
await updateAgent(soClient, esClient, agentId, {
|
||||
await updateAgent(esClient, agentId, {
|
||||
unenrollment_started_at: now,
|
||||
});
|
||||
}
|
||||
|
@ -66,9 +66,9 @@ export async function unenrollAgents(
|
|||
) {
|
||||
const agents =
|
||||
'agentIds' in options
|
||||
? await getAgents(soClient, esClient, options.agentIds)
|
||||
? await getAgents(esClient, options.agentIds)
|
||||
: (
|
||||
await listAllAgents(soClient, esClient, {
|
||||
await listAllAgents(esClient, {
|
||||
kuery: options.kuery,
|
||||
showInactive: false,
|
||||
})
|
||||
|
@ -101,7 +101,6 @@ export async function unenrollAgents(
|
|||
|
||||
// Update the necessary agents
|
||||
return bulkUpdateAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
agentsToUpdate.map((agent) => ({
|
||||
agentId: agent.id,
|
||||
|
@ -117,7 +116,7 @@ export async function forceUnenrollAgent(
|
|||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
) {
|
||||
const agent = await getAgent(soClient, esClient, agentId);
|
||||
const agent = await getAgent(esClient, agentId);
|
||||
|
||||
await Promise.all([
|
||||
agent.access_api_key_id
|
||||
|
@ -128,7 +127,7 @@ export async function forceUnenrollAgent(
|
|||
: undefined,
|
||||
]);
|
||||
|
||||
await updateAgent(soClient, esClient, agentId, {
|
||||
await updateAgent(esClient, agentId, {
|
||||
active: false,
|
||||
unenrolled_at: new Date().toISOString(),
|
||||
});
|
||||
|
@ -148,9 +147,9 @@ export async function forceUnenrollAgents(
|
|||
// Filter to agents that are not already unenrolled
|
||||
const agents =
|
||||
'agentIds' in options
|
||||
? await getAgents(soClient, esClient, options.agentIds)
|
||||
? await getAgents(esClient, options.agentIds)
|
||||
: (
|
||||
await listAllAgents(soClient, esClient, {
|
||||
await listAllAgents(esClient, {
|
||||
kuery: options.kuery,
|
||||
showInactive: false,
|
||||
})
|
||||
|
@ -175,7 +174,6 @@ export async function forceUnenrollAgents(
|
|||
}
|
||||
// Update the necessary agents
|
||||
return bulkUpdateAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
agentsToUpdate.map((agent) => ({
|
||||
agentId: agent.id,
|
||||
|
|
|
@ -20,7 +20,7 @@ export async function unenrollForAgentPolicyId(
|
|||
let hasMore = true;
|
||||
let page = 1;
|
||||
while (hasMore) {
|
||||
const { agents } = await listAgents(soClient, esClient, {
|
||||
const { agents } = await listAgents(esClient, {
|
||||
kuery: `${AGENT_SAVED_OBJECT_TYPE}.policy_id:"${policyId}"`,
|
||||
page: page++,
|
||||
perPage: 1000,
|
||||
|
|
|
@ -56,7 +56,7 @@ export async function sendUpgradeAgentAction({
|
|||
ack_data: data,
|
||||
type: 'UPGRADE',
|
||||
});
|
||||
await updateAgent(soClient, esClient, agentId, {
|
||||
await updateAgent(esClient, agentId, {
|
||||
upgraded_at: null,
|
||||
upgrade_started_at: now,
|
||||
});
|
||||
|
@ -73,7 +73,7 @@ export async function ackAgentUpgraded(
|
|||
if (!ackData) throw new Error('data missing from UPGRADE action');
|
||||
const { version } = JSON.parse(ackData);
|
||||
if (!version) throw new Error('version missing from UPGRADE action');
|
||||
await updateAgent(soClient, esClient, agentAction.agent_id, {
|
||||
await updateAgent(esClient, agentAction.agent_id, {
|
||||
upgraded_at: new Date().toISOString(),
|
||||
upgrade_started_at: null,
|
||||
});
|
||||
|
@ -100,9 +100,9 @@ export async function sendUpgradeAgentsActions(
|
|||
// Filter out agents currently unenrolling, agents unenrolled, and agents not upgradeable
|
||||
const agents =
|
||||
'agentIds' in options
|
||||
? await getAgents(soClient, esClient, options.agentIds)
|
||||
? await getAgents(esClient, options.agentIds)
|
||||
: (
|
||||
await listAllAgents(soClient, esClient, {
|
||||
await listAllAgents(esClient, {
|
||||
kuery: options.kuery,
|
||||
showInactive: false,
|
||||
})
|
||||
|
@ -150,7 +150,6 @@ export async function sendUpgradeAgentsActions(
|
|||
);
|
||||
|
||||
return await bulkUpdateAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
upgradeableAgents.map((agent) => ({
|
||||
agentId: agent.id,
|
||||
|
|
|
@ -5,16 +5,21 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import uuid from 'uuid';
|
||||
import Boom from '@hapi/boom';
|
||||
import { GetResponse } from 'elasticsearch';
|
||||
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
|
||||
import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
import type { EnrollmentAPIKey } from '../../types';
|
||||
import { appContextService } from '../app_context';
|
||||
import { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch';
|
||||
import type { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types';
|
||||
import { ENROLLMENT_API_KEYS_INDEX } from '../../constants';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
import { escapeSearchQueryPhrase } from '../saved_object';
|
||||
|
||||
import * as enrollmentApiKeyServiceSO from './enrollment_api_key_so';
|
||||
import * as enrollmentApiKeyServiceFleetServer from './enrollment_api_key_fleet_server';
|
||||
import { createAPIKey, invalidateAPIKeys } from './security';
|
||||
|
||||
export async function listEnrollmentApiKeys(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
options: {
|
||||
page?: number;
|
||||
|
@ -23,22 +28,44 @@ export async function listEnrollmentApiKeys(
|
|||
showInactive?: boolean;
|
||||
}
|
||||
): Promise<{ items: EnrollmentAPIKey[]; total: any; page: any; perPage: any }> {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled === true) {
|
||||
return enrollmentApiKeyServiceFleetServer.listEnrollmentApiKeys(esClient, options);
|
||||
} else {
|
||||
return enrollmentApiKeyServiceSO.listEnrollmentApiKeys(soClient, options);
|
||||
}
|
||||
const { page = 1, perPage = 20, kuery } = options;
|
||||
|
||||
const res = await esClient.search<SearchResponse<FleetServerEnrollmentAPIKey, {}>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
from: (page - 1) * perPage,
|
||||
size: perPage,
|
||||
sort: 'created_at:desc',
|
||||
track_total_hits: true,
|
||||
q: kuery,
|
||||
});
|
||||
|
||||
const items = res.body.hits.hits.map(esDocToEnrollmentApiKey);
|
||||
|
||||
return {
|
||||
items,
|
||||
total: res.body.hits.total.value,
|
||||
page,
|
||||
perPage,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKey(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
id: string
|
||||
) {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled === true) {
|
||||
return enrollmentApiKeyServiceFleetServer.getEnrollmentAPIKey(esClient, id);
|
||||
} else {
|
||||
return enrollmentApiKeyServiceSO.getEnrollmentAPIKey(soClient, id);
|
||||
): Promise<EnrollmentAPIKey> {
|
||||
try {
|
||||
const res = await esClient.get<GetResponse<FleetServerEnrollmentAPIKey>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
id,
|
||||
});
|
||||
|
||||
return esDocToEnrollmentApiKey(res.body);
|
||||
} catch (e) {
|
||||
if (e instanceof ResponseError && e.statusCode === 404) {
|
||||
throw Boom.notFound(`Enrollment api key ${id} not found`);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,18 +79,44 @@ export async function deleteEnrollmentApiKey(
|
|||
esClient: ElasticsearchClient,
|
||||
id: string
|
||||
) {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled === true) {
|
||||
return enrollmentApiKeyServiceFleetServer.deleteEnrollmentApiKey(soClient, esClient, id);
|
||||
} else {
|
||||
return enrollmentApiKeyServiceSO.deleteEnrollmentApiKey(soClient, id);
|
||||
}
|
||||
const enrollmentApiKey = await getEnrollmentAPIKey(esClient, id);
|
||||
|
||||
await invalidateAPIKeys(soClient, [enrollmentApiKey.api_key_id]);
|
||||
|
||||
await esClient.update({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
id,
|
||||
body: {
|
||||
doc: {
|
||||
active: false,
|
||||
},
|
||||
},
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteEnrollmentApiKeyForAgentPolicyId(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentPolicyId: string
|
||||
) {
|
||||
return enrollmentApiKeyServiceSO.deleteEnrollmentApiKeyForAgentPolicyId(soClient, agentPolicyId);
|
||||
let hasMore = true;
|
||||
let page = 1;
|
||||
while (hasMore) {
|
||||
const { items } = await listEnrollmentApiKeys(esClient, {
|
||||
page: page++,
|
||||
perPage: 100,
|
||||
kuery: `policy_id:${agentPolicyId}`,
|
||||
});
|
||||
|
||||
if (items.length === 0) {
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
for (const apiKey of items) {
|
||||
await deleteEnrollmentApiKey(soClient, esClient, apiKey.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateEnrollmentAPIKey(
|
||||
|
@ -74,22 +127,91 @@ export async function generateEnrollmentAPIKey(
|
|||
expiration?: string;
|
||||
agentPolicyId?: string;
|
||||
}
|
||||
) {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled === true) {
|
||||
return enrollmentApiKeyServiceFleetServer.generateEnrollmentAPIKey(soClient, esClient, data);
|
||||
} else {
|
||||
return enrollmentApiKeyServiceSO.generateEnrollmentAPIKey(soClient, data);
|
||||
): Promise<EnrollmentAPIKey> {
|
||||
const id = uuid.v4();
|
||||
const { name: providedKeyName } = data;
|
||||
if (data.agentPolicyId) {
|
||||
await validateAgentPolicyId(soClient, data.agentPolicyId);
|
||||
}
|
||||
const agentPolicyId =
|
||||
data.agentPolicyId ?? (await agentPolicyService.getDefaultAgentPolicyId(soClient));
|
||||
const name = providedKeyName ? `${providedKeyName} (${id})` : id;
|
||||
const key = await createAPIKey(soClient, name, {
|
||||
// Useless role to avoid to have the privilege of the user that created the key
|
||||
'fleet-apikey-enroll': {
|
||||
cluster: [],
|
||||
applications: [
|
||||
{
|
||||
application: '.fleet',
|
||||
privileges: ['no-privileges'],
|
||||
resources: ['*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
throw new Error('Unable to create an enrollment api key');
|
||||
}
|
||||
|
||||
const apiKey = Buffer.from(`${key.id}:${key.api_key}`).toString('base64');
|
||||
|
||||
const body = {
|
||||
active: true,
|
||||
api_key_id: key.id,
|
||||
api_key: apiKey,
|
||||
name,
|
||||
policy_id: agentPolicyId,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const res = await esClient.create({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
body,
|
||||
id,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return {
|
||||
id: res.body._id,
|
||||
...body,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKeyById(esClient: ElasticsearchClient, apiKeyId: string) {
|
||||
const res = await esClient.search<SearchResponse<FleetServerEnrollmentAPIKey, {}>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
q: `api_key_id:${escapeSearchQueryPhrase(apiKeyId)}`,
|
||||
});
|
||||
|
||||
const [enrollmentAPIKey] = res.body.hits.hits.map(esDocToEnrollmentApiKey);
|
||||
|
||||
if (enrollmentAPIKey?.api_key_id !== apiKeyId) {
|
||||
throw new Error('find enrollmentKeyById returned an incorrect key');
|
||||
}
|
||||
|
||||
return enrollmentAPIKey;
|
||||
}
|
||||
|
||||
async function validateAgentPolicyId(soClient: SavedObjectsClientContract, agentPolicyId: string) {
|
||||
try {
|
||||
await agentPolicyService.get(soClient, agentPolicyId);
|
||||
} catch (e) {
|
||||
if (e.isBoom && e.output.statusCode === 404) {
|
||||
throw Boom.badRequest(`Agent policy ${agentPolicyId} does not exist`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKeyById(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
apiKeyId: string
|
||||
) {
|
||||
if (appContextService.getConfig()?.agents?.fleetServerEnabled === true) {
|
||||
return enrollmentApiKeyServiceFleetServer.getEnrollmentAPIKeyById(esClient, apiKeyId);
|
||||
} else {
|
||||
return enrollmentApiKeyServiceSO.getEnrollmentAPIKeyById(soClient, apiKeyId);
|
||||
}
|
||||
function esDocToEnrollmentApiKey(doc: {
|
||||
_id: string;
|
||||
_source: FleetServerEnrollmentAPIKey;
|
||||
}): EnrollmentAPIKey {
|
||||
return {
|
||||
id: doc._id,
|
||||
...doc._source,
|
||||
created_at: doc._source.created_at as string,
|
||||
active: doc._source.active || false,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* 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 uuid from 'uuid';
|
||||
import Boom from '@hapi/boom';
|
||||
import type { GetResponse } from 'elasticsearch';
|
||||
import { ResponseError } from '@elastic/elasticsearch/lib/errors';
|
||||
import type { SavedObjectsClientContract, ElasticsearchClient } from 'src/core/server';
|
||||
|
||||
import type { ESSearchResponse as SearchResponse } from '../../../../../typings/elasticsearch';
|
||||
import type { EnrollmentAPIKey, FleetServerEnrollmentAPIKey } from '../../types';
|
||||
import { ENROLLMENT_API_KEYS_INDEX } from '../../constants';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
import { escapeSearchQueryPhrase } from '../saved_object';
|
||||
|
||||
import { createAPIKey, invalidateAPIKeys } from './security';
|
||||
|
||||
export async function listEnrollmentApiKeys(
|
||||
esClient: ElasticsearchClient,
|
||||
options: {
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
kuery?: string;
|
||||
showInactive?: boolean;
|
||||
}
|
||||
): Promise<{ items: EnrollmentAPIKey[]; total: any; page: any; perPage: any }> {
|
||||
const { page = 1, perPage = 20, kuery } = options;
|
||||
|
||||
const res = await esClient.search<SearchResponse<FleetServerEnrollmentAPIKey, {}>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
from: (page - 1) * perPage,
|
||||
size: perPage,
|
||||
sort: 'created_at:desc',
|
||||
track_total_hits: true,
|
||||
q: kuery,
|
||||
});
|
||||
|
||||
const items = res.body.hits.hits.map(esDocToEnrollmentApiKey);
|
||||
|
||||
return {
|
||||
items,
|
||||
total: res.body.hits.total.value,
|
||||
page,
|
||||
perPage,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKey(
|
||||
esClient: ElasticsearchClient,
|
||||
id: string
|
||||
): Promise<EnrollmentAPIKey> {
|
||||
try {
|
||||
const res = await esClient.get<GetResponse<FleetServerEnrollmentAPIKey>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
id,
|
||||
});
|
||||
|
||||
return esDocToEnrollmentApiKey(res.body);
|
||||
} catch (e) {
|
||||
if (e instanceof ResponseError && e.statusCode === 404) {
|
||||
throw Boom.notFound(`Enrollment api key ${id} not found`);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate an api key and mark it as inactive
|
||||
* @param soClient
|
||||
* @param id
|
||||
*/
|
||||
export async function deleteEnrollmentApiKey(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
id: string
|
||||
) {
|
||||
const enrollmentApiKey = await getEnrollmentAPIKey(esClient, id);
|
||||
|
||||
await invalidateAPIKeys(soClient, [enrollmentApiKey.api_key_id]);
|
||||
|
||||
await esClient.update({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
id,
|
||||
body: {
|
||||
doc: {
|
||||
active: false,
|
||||
},
|
||||
},
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteEnrollmentApiKeyForAgentPolicyId(
|
||||
soClient: SavedObjectsClientContract,
|
||||
agentPolicyId: string
|
||||
) {
|
||||
throw new Error('NOT IMPLEMENTED');
|
||||
}
|
||||
|
||||
export async function generateEnrollmentAPIKey(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
data: {
|
||||
name?: string;
|
||||
expiration?: string;
|
||||
agentPolicyId?: string;
|
||||
}
|
||||
): Promise<EnrollmentAPIKey> {
|
||||
const id = uuid.v4();
|
||||
const { name: providedKeyName } = data;
|
||||
if (data.agentPolicyId) {
|
||||
await validateAgentPolicyId(soClient, data.agentPolicyId);
|
||||
}
|
||||
const agentPolicyId =
|
||||
data.agentPolicyId ?? (await agentPolicyService.getDefaultAgentPolicyId(soClient));
|
||||
const name = providedKeyName ? `${providedKeyName} (${id})` : id;
|
||||
const key = await createAPIKey(soClient, name, {
|
||||
// Useless role to avoid to have the privilege of the user that created the key
|
||||
'fleet-apikey-enroll': {
|
||||
cluster: [],
|
||||
applications: [
|
||||
{
|
||||
application: '.fleet',
|
||||
privileges: ['no-privileges'],
|
||||
resources: ['*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
throw new Error('Unable to create an enrollment api key');
|
||||
}
|
||||
|
||||
const apiKey = Buffer.from(`${key.id}:${key.api_key}`).toString('base64');
|
||||
|
||||
const body = {
|
||||
active: true,
|
||||
api_key_id: key.id,
|
||||
api_key: apiKey,
|
||||
name,
|
||||
policy_id: agentPolicyId,
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const res = await esClient.create({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
body,
|
||||
id,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
|
||||
return {
|
||||
id: res.body._id,
|
||||
...body,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKeyById(esClient: ElasticsearchClient, apiKeyId: string) {
|
||||
const res = await esClient.search<SearchResponse<FleetServerEnrollmentAPIKey, {}>>({
|
||||
index: ENROLLMENT_API_KEYS_INDEX,
|
||||
q: `api_key_id:${escapeSearchQueryPhrase(apiKeyId)}`,
|
||||
});
|
||||
|
||||
const [enrollmentAPIKey] = res.body.hits.hits.map(esDocToEnrollmentApiKey);
|
||||
|
||||
if (enrollmentAPIKey?.api_key_id !== apiKeyId) {
|
||||
throw new Error('find enrollmentKeyById returned an incorrect key');
|
||||
}
|
||||
|
||||
return enrollmentAPIKey;
|
||||
}
|
||||
|
||||
async function validateAgentPolicyId(soClient: SavedObjectsClientContract, agentPolicyId: string) {
|
||||
try {
|
||||
await agentPolicyService.get(soClient, agentPolicyId);
|
||||
} catch (e) {
|
||||
if (e.isBoom && e.output.statusCode === 404) {
|
||||
throw Boom.badRequest(`Agent policy ${agentPolicyId} does not exist`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function esDocToEnrollmentApiKey(doc: {
|
||||
_id: string;
|
||||
_source: FleetServerEnrollmentAPIKey;
|
||||
}): EnrollmentAPIKey {
|
||||
return {
|
||||
id: doc._id,
|
||||
...doc._source,
|
||||
created_at: doc._source.created_at as string,
|
||||
active: doc._source.active || false,
|
||||
};
|
||||
}
|
|
@ -5,17 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import uuid from 'uuid';
|
||||
import Boom from '@hapi/boom';
|
||||
import type { SavedObjectsClientContract, SavedObject } from 'src/core/server';
|
||||
|
||||
import type { EnrollmentAPIKey, EnrollmentAPIKeySOAttributes } from '../../types';
|
||||
import { ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE } from '../../constants';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
import { appContextService } from '../app_context';
|
||||
import { normalizeKuery, escapeSearchQueryPhrase } from '../saved_object';
|
||||
|
||||
import { createAPIKey, invalidateAPIKeys } from './security';
|
||||
import { normalizeKuery } from '../saved_object';
|
||||
|
||||
export async function listEnrollmentApiKeys(
|
||||
soClient: SavedObjectsClientContract,
|
||||
|
@ -61,125 +56,6 @@ export async function getEnrollmentAPIKey(soClient: SavedObjectsClientContract,
|
|||
return savedObjectToEnrollmentApiKey(so);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate an api key and mark it as inactive
|
||||
* @param soClient
|
||||
* @param id
|
||||
*/
|
||||
export async function deleteEnrollmentApiKey(soClient: SavedObjectsClientContract, id: string) {
|
||||
const enrollmentApiKey = await getEnrollmentAPIKey(soClient, id);
|
||||
|
||||
await invalidateAPIKeys(soClient, [enrollmentApiKey.api_key_id]);
|
||||
|
||||
await soClient.update(ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE, id, {
|
||||
active: false,
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteEnrollmentApiKeyForAgentPolicyId(
|
||||
soClient: SavedObjectsClientContract,
|
||||
agentPolicyId: string
|
||||
) {
|
||||
let hasMore = true;
|
||||
let page = 1;
|
||||
while (hasMore) {
|
||||
const { items } = await listEnrollmentApiKeys(soClient, {
|
||||
page: page++,
|
||||
perPage: 100,
|
||||
kuery: `${ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE}.policy_id:${agentPolicyId}`,
|
||||
});
|
||||
|
||||
if (items.length === 0) {
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
for (const apiKey of items) {
|
||||
await deleteEnrollmentApiKey(soClient, apiKey.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateEnrollmentAPIKey(
|
||||
soClient: SavedObjectsClientContract,
|
||||
data: {
|
||||
name?: string;
|
||||
expiration?: string;
|
||||
agentPolicyId?: string;
|
||||
}
|
||||
) {
|
||||
const id = uuid.v4();
|
||||
const { name: providedKeyName } = data;
|
||||
if (data.agentPolicyId) {
|
||||
await validateAgentPolicyId(soClient, data.agentPolicyId);
|
||||
}
|
||||
const agentPolicyId =
|
||||
data.agentPolicyId ?? (await agentPolicyService.getDefaultAgentPolicyId(soClient));
|
||||
const name = providedKeyName ? `${providedKeyName} (${id})` : id;
|
||||
const key = await createAPIKey(soClient, name, {
|
||||
// Useless role to avoid to have the privilege of the user that created the key
|
||||
'fleet-apikey-enroll': {
|
||||
cluster: [],
|
||||
applications: [
|
||||
{
|
||||
application: '.fleet',
|
||||
privileges: ['no-privileges'],
|
||||
resources: ['*'],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
throw new Error('Unable to create an enrollment api key');
|
||||
}
|
||||
|
||||
const apiKey = Buffer.from(`${key.id}:${key.api_key}`).toString('base64');
|
||||
|
||||
const so = await soClient.create<EnrollmentAPIKeySOAttributes>(
|
||||
ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||
{
|
||||
active: true,
|
||||
api_key_id: key.id,
|
||||
api_key: apiKey,
|
||||
name,
|
||||
policy_id: agentPolicyId,
|
||||
created_at: new Date().toISOString(),
|
||||
}
|
||||
);
|
||||
|
||||
return getEnrollmentAPIKey(soClient, so.id);
|
||||
}
|
||||
|
||||
async function validateAgentPolicyId(soClient: SavedObjectsClientContract, agentPolicyId: string) {
|
||||
try {
|
||||
await agentPolicyService.get(soClient, agentPolicyId);
|
||||
} catch (e) {
|
||||
if (e.isBoom && e.output.statusCode === 404) {
|
||||
throw Boom.badRequest(`Agent policy ${agentPolicyId} does not exist`);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getEnrollmentAPIKeyById(
|
||||
soClient: SavedObjectsClientContract,
|
||||
apiKeyId: string
|
||||
) {
|
||||
const [enrollmentAPIKey] = (
|
||||
await soClient.find<EnrollmentAPIKeySOAttributes>({
|
||||
type: ENROLLMENT_API_KEYS_SAVED_OBJECT_TYPE,
|
||||
searchFields: ['api_key_id'],
|
||||
search: escapeSearchQueryPhrase(apiKeyId),
|
||||
})
|
||||
).saved_objects.map(savedObjectToEnrollmentApiKey);
|
||||
|
||||
if (enrollmentAPIKey?.api_key_id !== apiKeyId) {
|
||||
throw new Error('find enrollmentKeyById returned an incorrect key');
|
||||
}
|
||||
|
||||
return enrollmentAPIKey;
|
||||
}
|
||||
|
||||
function savedObjectToEnrollmentApiKey({
|
||||
error,
|
||||
attributes,
|
||||
|
|
|
@ -51,18 +51,13 @@ export interface AgentService {
|
|||
* Authenticate an agent with access toekn
|
||||
*/
|
||||
authenticateAgentWithAccessToken(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
request: KibanaRequest
|
||||
): Promise<Agent>;
|
||||
/**
|
||||
* Return the status by the Agent's id
|
||||
*/
|
||||
getAgentStatusById(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
agentId: string
|
||||
): Promise<AgentStatus>;
|
||||
getAgentStatusById(esClient: ElasticsearchClient, agentId: string): Promise<AgentStatus>;
|
||||
/**
|
||||
* List agents
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,6 @@ import { settingsService } from '.';
|
|||
import { awaitIfPending } from './setup_utils';
|
||||
import { createDefaultSettings } from './settings';
|
||||
import { ensureAgentActionPolicyChangeExists } from './agents';
|
||||
import { appContextService } from './app_context';
|
||||
import { awaitIfFleetServerSetupPending } from './fleet_server';
|
||||
|
||||
const FLEET_ENROLL_USERNAME = 'fleet_enroll';
|
||||
|
@ -57,7 +56,6 @@ async function createSetupSideEffects(
|
|||
esClient: ElasticsearchClient,
|
||||
callCluster: CallESAsCurrentUser
|
||||
): Promise<SetupStatus> {
|
||||
const isFleetServerEnabled = appContextService.getConfig()?.agents.fleetServerEnabled;
|
||||
const [
|
||||
installedPackages,
|
||||
defaultOutput,
|
||||
|
@ -68,9 +66,7 @@ async function createSetupSideEffects(
|
|||
ensureInstalledDefaultPackages(soClient, callCluster),
|
||||
outputService.ensureDefaultOutput(soClient),
|
||||
agentPolicyService.ensureDefaultAgentPolicy(soClient, esClient),
|
||||
isFleetServerEnabled
|
||||
? agentPolicyService.ensureDefaultFleetServerAgentPolicy(soClient, esClient)
|
||||
: {},
|
||||
agentPolicyService.ensureDefaultFleetServerAgentPolicy(soClient, esClient),
|
||||
updateFleetRoleIfExists(callCluster),
|
||||
settingsService.getSettings(soClient).catch((e: any) => {
|
||||
if (e.isBoom && e.output.statusCode === 404) {
|
||||
|
@ -90,25 +86,23 @@ async function createSetupSideEffects(
|
|||
// packages that are stuck in the installing state.
|
||||
await ensurePackagesCompletedInstall(soClient, callCluster);
|
||||
|
||||
if (isFleetServerEnabled) {
|
||||
await awaitIfFleetServerSetupPending();
|
||||
await awaitIfFleetServerSetupPending();
|
||||
|
||||
const fleetServerPackage = await ensureInstalledPackage({
|
||||
savedObjectsClient: soClient,
|
||||
pkgName: FLEET_SERVER_PACKAGE,
|
||||
const fleetServerPackage = await ensureInstalledPackage({
|
||||
savedObjectsClient: soClient,
|
||||
pkgName: FLEET_SERVER_PACKAGE,
|
||||
callCluster,
|
||||
});
|
||||
|
||||
if (defaultFleetServerPolicyCreated) {
|
||||
await addPackageToAgentPolicy(
|
||||
soClient,
|
||||
esClient,
|
||||
callCluster,
|
||||
});
|
||||
|
||||
if (defaultFleetServerPolicyCreated) {
|
||||
await addPackageToAgentPolicy(
|
||||
soClient,
|
||||
esClient,
|
||||
callCluster,
|
||||
fleetServerPackage,
|
||||
defaultFleetServerPolicy,
|
||||
defaultOutput
|
||||
);
|
||||
}
|
||||
fleetServerPackage,
|
||||
defaultFleetServerPolicy,
|
||||
defaultOutput
|
||||
);
|
||||
}
|
||||
|
||||
// If we just created the default fleet server policy add the fleet server package
|
||||
|
|
|
@ -310,7 +310,7 @@ const fleetEnrollAgentForHost = async (
|
|||
path: ENROLLMENT_API_KEY_ROUTES.LIST_PATTERN,
|
||||
method: 'GET',
|
||||
query: {
|
||||
kuery: `fleet-enrollment-api-keys.policy_id:"${agentPolicyId}"`,
|
||||
kuery: `policy_id:"${agentPolicyId}"`,
|
||||
},
|
||||
})
|
||||
.then((apiKeysResponse) => {
|
||||
|
|
|
@ -618,12 +618,12 @@ export const EndpointList = () => {
|
|||
<LinkToApp
|
||||
appId="fleet"
|
||||
appPath={`#${pagePathGetters.fleet_agent_list({
|
||||
kuery: 'fleet-agents.packages : "endpoint"',
|
||||
kuery: 'packages : "endpoint"',
|
||||
})}`}
|
||||
href={`${services?.application?.getUrlForApp(
|
||||
'fleet'
|
||||
)}#${pagePathGetters.fleet_agent_list({
|
||||
kuery: 'fleet-agents.packages : "endpoint"',
|
||||
kuery: 'packages : "endpoint"',
|
||||
})}`}
|
||||
>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -148,7 +148,7 @@ export const sendGetFleetAgentsWithEndpoint = (
|
|||
query: {
|
||||
page: 1,
|
||||
perPage: 1,
|
||||
kuery: 'fleet-agents.packages : "endpoint"',
|
||||
kuery: 'packages : "endpoint"',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -71,23 +71,22 @@ const expectedEndpointExceptions: WrappedTranslatedExceptionList = {
|
|||
},
|
||||
],
|
||||
};
|
||||
const mockIngestSOResponse = {
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
total: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'agent1',
|
||||
type: 'agent',
|
||||
references: [],
|
||||
score: 0,
|
||||
attributes: {
|
||||
active: true,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
const mockFleetESResponse = {
|
||||
body: {
|
||||
hits: {
|
||||
hits: [
|
||||
{
|
||||
_id: 'agent1',
|
||||
_source: {
|
||||
active: true,
|
||||
access_api_key_id: 'pedTuHIBTEDt93wW0Fhr',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const AuthHeader = 'ApiKey cGVkVHVISUJURUR0OTN3VzBGaHI6TnU1U0JtbHJSeC12Rm9qQWpoSHlUZw==';
|
||||
|
||||
describe('test alerts route', () => {
|
||||
|
@ -101,6 +100,7 @@ describe('test alerts route', () => {
|
|||
let endpointAppContextService: EndpointAppContextService;
|
||||
let cache: LRU<string, Buffer>;
|
||||
let ingestSavedObjectClient: jest.Mocked<SavedObjectsClientContract>;
|
||||
let esClientMock: ReturnType<typeof elasticsearchServiceMock.createInternalClient>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockClusterClient = elasticsearchServiceMock.createLegacyClusterClient();
|
||||
|
@ -113,9 +113,12 @@ describe('test alerts route', () => {
|
|||
cache = new LRU<string, Buffer>({ max: 10, maxAge: 1000 * 60 * 60 });
|
||||
const startContract = createMockEndpointAppContextServiceStartContract();
|
||||
|
||||
// The authentication with the Fleet Plugin needs a separate scoped SO Client
|
||||
// // The authentication with the Fleet Plugin needs a separate scoped ES CLient
|
||||
esClientMock = elasticsearchServiceMock.createInternalClient();
|
||||
// @ts-expect-error
|
||||
esClientMock.search.mockResolvedValue(mockFleetESResponse);
|
||||
|
||||
ingestSavedObjectClient = savedObjectsClientMock.create();
|
||||
ingestSavedObjectClient.find.mockReturnValue(Promise.resolve(mockIngestSOResponse));
|
||||
(startContract.savedObjectsStart.getScopedClient as jest.Mock).mockReturnValue(
|
||||
ingestSavedObjectClient
|
||||
);
|
||||
|
@ -175,7 +178,7 @@ describe('test alerts route', () => {
|
|||
client: mockSavedObjectClient,
|
||||
},
|
||||
elasticsearch: {
|
||||
client: { asInternalUser: elasticsearchServiceMock.createInternalClient() },
|
||||
client: { asInternalUser: esClientMock },
|
||||
},
|
||||
},
|
||||
} as unknown) as SecuritySolutionRequestHandlerContext,
|
||||
|
@ -222,7 +225,7 @@ describe('test alerts route', () => {
|
|||
client: mockSavedObjectClient,
|
||||
},
|
||||
elasticsearch: {
|
||||
client: { asInternalUser: elasticsearchServiceMock.createInternalClient() },
|
||||
client: { asInternalUser: esClientMock },
|
||||
},
|
||||
},
|
||||
} as unknown) as SecuritySolutionRequestHandlerContext,
|
||||
|
@ -259,7 +262,7 @@ describe('test alerts route', () => {
|
|||
client: mockSavedObjectClient,
|
||||
},
|
||||
elasticsearch: {
|
||||
client: { asInternalUser: elasticsearchServiceMock.createInternalClient() },
|
||||
client: { asInternalUser: esClientMock },
|
||||
},
|
||||
},
|
||||
} as unknown) as SecuritySolutionRequestHandlerContext,
|
||||
|
@ -290,7 +293,7 @@ describe('test alerts route', () => {
|
|||
client: mockSavedObjectClient,
|
||||
},
|
||||
elasticsearch: {
|
||||
client: { asInternalUser: elasticsearchServiceMock.createInternalClient() },
|
||||
client: { asInternalUser: esClientMock },
|
||||
},
|
||||
},
|
||||
} as unknown) as SecuritySolutionRequestHandlerContext,
|
||||
|
@ -312,9 +315,8 @@ describe('test alerts route', () => {
|
|||
});
|
||||
|
||||
// Mock the SavedObjectsClient find response for verifying the API token with no results
|
||||
mockIngestSOResponse.saved_objects = [];
|
||||
mockIngestSOResponse.total = 0;
|
||||
ingestSavedObjectClient.find.mockReturnValue(Promise.resolve(mockIngestSOResponse));
|
||||
// @ts-expect-error
|
||||
esClientMock.search.mockResolvedValue({ body: { hits: { hits: [] } } });
|
||||
|
||||
[routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
|
||||
path.startsWith('/api/endpoint/artifacts/download')
|
||||
|
@ -327,7 +329,7 @@ describe('test alerts route', () => {
|
|||
client: mockSavedObjectClient,
|
||||
},
|
||||
elasticsearch: {
|
||||
client: { asInternalUser: elasticsearchServiceMock.createInternalClient() },
|
||||
client: { asInternalUser: esClientMock },
|
||||
},
|
||||
},
|
||||
} as unknown) as SecuritySolutionRequestHandlerContext,
|
||||
|
|
|
@ -55,7 +55,6 @@ export function registerDownloadArtifactRoute(
|
|||
try {
|
||||
scopedSOClient = endpointContext.service.getScopedSavedObjectsClient(req);
|
||||
await authenticateAgentWithAccessToken(
|
||||
scopedSOClient,
|
||||
context.core.elasticsearch.client.asInternalUser,
|
||||
req
|
||||
);
|
||||
|
|
|
@ -19,6 +19,7 @@ import type { SecuritySolutionRequestHandlerContext } from '../../../types';
|
|||
|
||||
import { getESQueryHostMetadataByID, kibanaRequestToMetadataListESQuery } from './query_builders';
|
||||
import { Agent, AgentStatus, PackagePolicy } from '../../../../../fleet/common/types/models';
|
||||
import { AgentNotFoundError } from '../../../../../fleet/server';
|
||||
import { EndpointAppContext, HostListQueryResult } from '../../types';
|
||||
import { GetMetadataListRequestSchema, GetMetadataRequestSchema } from './index';
|
||||
import { findAllUnenrolledAgentIds } from './support/unenroll';
|
||||
|
@ -202,16 +203,11 @@ async function findAgent(
|
|||
return await metadataRequestContext.endpointAppContextService
|
||||
?.getAgentService()
|
||||
?.getAgent(
|
||||
metadataRequestContext.requestHandlerContext.core.savedObjects.client,
|
||||
metadataRequestContext.requestHandlerContext.core.elasticsearch.client.asCurrentUser,
|
||||
hostMetadata.elastic.agent.id
|
||||
);
|
||||
} catch (e) {
|
||||
if (
|
||||
metadataRequestContext.requestHandlerContext.core.savedObjects.client.errors.isNotFoundError(
|
||||
e
|
||||
)
|
||||
) {
|
||||
if (e instanceof AgentNotFoundError) {
|
||||
metadataRequestContext.logger.warn(
|
||||
`agent with id ${hostMetadata.elastic.agent.id} not found`
|
||||
);
|
||||
|
@ -277,17 +273,12 @@ export async function enrichHostMetadata(
|
|||
const status = await metadataRequestContext.endpointAppContextService
|
||||
?.getAgentService()
|
||||
?.getAgentStatusById(
|
||||
metadataRequestContext.requestHandlerContext.core.savedObjects.client,
|
||||
metadataRequestContext.requestHandlerContext.core.elasticsearch.client.asCurrentUser,
|
||||
elasticAgentId
|
||||
);
|
||||
hostStatus = HOST_STATUS_MAPPING.get(status!) || HostStatus.ERROR;
|
||||
} catch (e) {
|
||||
if (
|
||||
metadataRequestContext.requestHandlerContext.core.savedObjects.client.errors.isNotFoundError(
|
||||
e
|
||||
)
|
||||
) {
|
||||
if (e instanceof AgentNotFoundError) {
|
||||
log.warn(`agent with id ${elasticAgentId} not found`);
|
||||
} else {
|
||||
log.error(e);
|
||||
|
@ -300,7 +291,6 @@ export async function enrichHostMetadata(
|
|||
const agent = await metadataRequestContext.endpointAppContextService
|
||||
?.getAgentService()
|
||||
?.getAgent(
|
||||
metadataRequestContext.requestHandlerContext.core.savedObjects.client,
|
||||
metadataRequestContext.requestHandlerContext.core.elasticsearch.client.asCurrentUser,
|
||||
elasticAgentId
|
||||
);
|
||||
|
|
|
@ -71,7 +71,7 @@ describe('test filtering endpoint hosts by agent status', () => {
|
|||
['offline']
|
||||
);
|
||||
const offlineKuery = AgentStatusKueryHelper.buildKueryForOfflineAgents();
|
||||
expect(mockAgentService.listAgents.mock.calls[0][2].kuery).toEqual(
|
||||
expect(mockAgentService.listAgents.mock.calls[0][1].kuery).toEqual(
|
||||
expect.stringContaining(offlineKuery)
|
||||
);
|
||||
expect(result).toBeDefined();
|
||||
|
@ -105,7 +105,7 @@ describe('test filtering endpoint hosts by agent status', () => {
|
|||
);
|
||||
const unenrollKuery = AgentStatusKueryHelper.buildKueryForUnenrollingAgents();
|
||||
const errorKuery = AgentStatusKueryHelper.buildKueryForErrorAgents();
|
||||
expect(mockAgentService.listAgents.mock.calls[0][2].kuery).toEqual(
|
||||
expect(mockAgentService.listAgents.mock.calls[0][1].kuery).toEqual(
|
||||
expect.stringContaining(`${unenrollKuery} OR ${errorKuery}`)
|
||||
);
|
||||
expect(result).toBeDefined();
|
||||
|
|
|
@ -31,7 +31,7 @@ export async function findAgentIDsByStatus(
|
|||
page: pageNum,
|
||||
perPage: pageSize,
|
||||
showInactive: true,
|
||||
kuery: `(fleet-agents.packages : "endpoint" AND (${helpers.join(' OR ')}))`,
|
||||
kuery: `(packages : "endpoint" AND (${helpers.join(' OR ')}))`,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,7 @@ export async function findAgentIDsByStatus(
|
|||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
const agents = await agentService.listAgents(soClient, esClient, searchOptions(page++));
|
||||
const agents = await agentService.listAgents(esClient, searchOptions(page++));
|
||||
result.push(...agents.agents.map((agent: Agent) => agent.id));
|
||||
hasMore = agents.agents.length > 0;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ export async function findAllUnenrolledAgentIds(
|
|||
page: pageNum,
|
||||
perPage: pageSize,
|
||||
showInactive: true,
|
||||
kuery:
|
||||
'(fleet-agents.active : false) OR (NOT fleet-agents.packages : "endpoint" AND fleet-agents.active : true)',
|
||||
kuery: '(active : false) OR (NOT packages : "endpoint" AND active : true)',
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -31,11 +30,7 @@ export async function findAllUnenrolledAgentIds(
|
|||
let hasMore = true;
|
||||
|
||||
while (hasMore) {
|
||||
const unenrolledAgents = await agentService.listAgents(
|
||||
soClient,
|
||||
esClient,
|
||||
searchOptions(page++)
|
||||
);
|
||||
const unenrolledAgents = await agentService.listAgents(esClient, searchOptions(page++));
|
||||
result.push(...unenrolledAgents.agents.map((agent: Agent) => agent.id));
|
||||
hasMore = unenrolledAgents.agents.length > 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import { GetHostPolicyResponse, HostPolicyResponse } from '../../../../common/en
|
|||
import { INITIAL_POLICY_ID } from './index';
|
||||
import { Agent } from '../../../../../fleet/common/types/models';
|
||||
import { EndpointAppContext } from '../../types';
|
||||
import { AGENT_SAVED_OBJECT_TYPE } from '../../../../../fleet/common/constants';
|
||||
|
||||
export function getESQueryPolicyResponseByAgentID(agentID: string, index: string) {
|
||||
return {
|
||||
|
@ -83,14 +82,14 @@ export async function getAgentPolicySummary(
|
|||
policyId?: string,
|
||||
pageSize: number = 1000
|
||||
): Promise<{ [key: string]: number }> {
|
||||
const agentQuery = `${AGENT_SAVED_OBJECT_TYPE}.packages:"${packageName}"`;
|
||||
const agentQuery = `packages:"${packageName}"`;
|
||||
if (policyId) {
|
||||
return transformAgentVersionMap(
|
||||
await agentVersionsMap(
|
||||
endpointAppContext,
|
||||
soClient,
|
||||
esClient,
|
||||
`${agentQuery} AND ${AGENT_SAVED_OBJECT_TYPE}.policy_id:${policyId}`,
|
||||
`${agentQuery} AND policy_id:${policyId}`,
|
||||
pageSize
|
||||
)
|
||||
);
|
||||
|
@ -123,7 +122,7 @@ export async function agentVersionsMap(
|
|||
while (hasMore) {
|
||||
const queryResult = await endpointAppContext.service
|
||||
.getAgentService()!
|
||||
.listAgents(soClient, esClient, searchOptions(page++));
|
||||
.listAgents(esClient, searchOptions(page++));
|
||||
queryResult.agents.forEach((agent: Agent) => {
|
||||
const agentVersion = agent.local_metadata?.elastic?.agent?.version;
|
||||
if (result.has(agentVersion)) {
|
||||
|
|
|
@ -13,19 +13,13 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('fleet_agent_policies', () => {
|
||||
const createdPolicyIds: string[] = [];
|
||||
after(async () => {
|
||||
const deletedPromises = createdPolicyIds.map((agentPolicyId) =>
|
||||
supertest
|
||||
.post(`/api/fleet/agent_policies/delete`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({ agentPolicyId })
|
||||
.expect(200)
|
||||
);
|
||||
await Promise.all(deletedPromises);
|
||||
});
|
||||
|
||||
describe('POST /api/fleet/agent_policies', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
it('should work with valid minimum required values', async () => {
|
||||
const {
|
||||
body: { item: createdPolicy },
|
||||
|
@ -201,6 +195,23 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
describe('PUT /api/fleet/agent_policies/{agentPolicyId}', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
const createdPolicyIds: string[] = [];
|
||||
after(async () => {
|
||||
const deletedPromises = createdPolicyIds.map((agentPolicyId) =>
|
||||
supertest
|
||||
.post(`/api/fleet/agent_policies/delete`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({ agentPolicyId })
|
||||
.expect(200)
|
||||
);
|
||||
await Promise.all(deletedPromises);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
let agentPolicyId: undefined | string;
|
||||
it('should work with valid values', async () => {
|
||||
const {
|
||||
|
@ -310,6 +321,12 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
describe('POST /api/fleet/agent_policies/delete', () => {
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
let managedPolicy: any | undefined;
|
||||
it('should prevent managed policies being deleted', async () => {
|
||||
const {
|
||||
|
|
|
@ -9,6 +9,7 @@ import expect from '@kbn/expect';
|
|||
import { skipIfNoDockerRegistry } from '../../helpers';
|
||||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
import { setupFleetAndAgents, getSupertestWithoutAuth } from '../agents/services';
|
||||
import { AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS } from '../../../../plugins/fleet/common';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
|
@ -75,6 +76,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
// Wait before agent status is updated
|
||||
return new Promise((resolve) => setTimeout(resolve, AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS));
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
});
|
||||
|
|
|
@ -14,7 +14,6 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const { getService } = providerContext;
|
||||
const esArchiver = getService('esArchiver');
|
||||
const esClient = getService('es');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
const supertestWithoutAuth = getSupertestWithoutAuth(providerContext);
|
||||
const supertest = getService('supertest');
|
||||
|
@ -33,13 +32,13 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const {
|
||||
body: { _source: agentDoc },
|
||||
} = await esClient.get({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
});
|
||||
agentDoc['fleet-agents'].access_api_key_id = apiKey.id;
|
||||
agentDoc.access_api_key_id = apiKey.id;
|
||||
await esClient.update({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
refresh: true,
|
||||
body: {
|
||||
doc: agentDoc,
|
||||
|
@ -240,11 +239,11 @@ export default function (providerContext: FtrProviderContext) {
|
|||
})
|
||||
.expect(200);
|
||||
|
||||
const res = await kibanaServer.savedObjects.get({
|
||||
type: 'fleet-agents',
|
||||
const res = await esClient.get({
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
});
|
||||
expect(res.attributes.upgraded_at).to.be.ok();
|
||||
expect(res.body._source.upgraded_at).to.be.ok();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
|
||||
describe('fleet_agents_actions', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
await esArchiver.load('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
|
@ -86,7 +86,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('should return a 404 when agent does not exist', async () => {
|
||||
const { body: apiResponse } = await supertest
|
||||
await supertest
|
||||
.post(`/api/fleet/agents/agent100/actions`)
|
||||
.set('kbn-xsrf', 'xx')
|
||||
.send({
|
||||
|
@ -96,7 +96,6 @@ export default function (providerContext: FtrProviderContext) {
|
|||
},
|
||||
})
|
||||
.expect(404);
|
||||
expect(apiResponse.message).to.eql('Saved object [fleet-agents/agent100] not found');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import uuid from 'uuid';
|
|||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
import { getSupertestWithoutAuth, setupFleetAndAgents } from './services';
|
||||
import { skipIfNoDockerRegistry } from '../../helpers';
|
||||
import { AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS } from '../../../../plugins/fleet/common';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
|
@ -34,13 +35,13 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const {
|
||||
body: { _source: agentDoc },
|
||||
} = await esClient.get({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
});
|
||||
agentDoc['fleet-agents'].access_api_key_id = apiKey.id;
|
||||
agentDoc.access_api_key_id = apiKey.id;
|
||||
await esClient.update({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
refresh: true,
|
||||
body: {
|
||||
doc: agentDoc,
|
||||
|
@ -48,6 +49,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
after(async () => {
|
||||
// Wait before agent status is updated
|
||||
return new Promise((resolve) => setTimeout(resolve, AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS));
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import expect from '@kbn/expect';
|
|||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
import { setupFleetAndAgents, getSupertestWithoutAuth } from './services';
|
||||
import { skipIfNoDockerRegistry } from '../../helpers';
|
||||
import { AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS } from '../../../../plugins/fleet/common';
|
||||
|
||||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
|
@ -23,25 +24,38 @@ export default function (providerContext: FtrProviderContext) {
|
|||
describe('fleet_agent_flow', () => {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.load('empty_kibana');
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
after(async () => {
|
||||
await esArchiver.unload('empty_kibana');
|
||||
// Wait before agent status is updated
|
||||
return new Promise((resolve) => setTimeout(resolve, AGENT_UPDATE_LAST_CHECKIN_INTERVAL_MS));
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
it('should work', async () => {
|
||||
const kibanaVersionAccessor = kibanaServer.version;
|
||||
const kibanaVersion = await kibanaVersionAccessor.get();
|
||||
|
||||
const { body: policiesRes } = await supertest.get(`/api/fleet/agent_policies`).expect(200);
|
||||
|
||||
expect(policiesRes.items).length(2);
|
||||
const { id: defaultPolicyId } = policiesRes.items.find((p: any) => p.is_default);
|
||||
|
||||
// Get enrollment token
|
||||
const { body: enrollmentApiKeysResponse } = await supertest
|
||||
.get(`/api/fleet/enrollment-api-keys`)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeysResponse.list).length(1);
|
||||
expect(enrollmentApiKeysResponse.list).length(2);
|
||||
const { id: enrollmentKeyId } = enrollmentApiKeysResponse.list.find(
|
||||
(key: any) => key.policy_id === defaultPolicyId
|
||||
);
|
||||
|
||||
const { body: enrollmentApiKeyResponse } = await supertest
|
||||
.get(`/api/fleet/enrollment-api-keys/${enrollmentApiKeysResponse.list[0].id}`)
|
||||
.get(`/api/fleet/enrollment-api-keys/${enrollmentKeyId}`)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeyResponse.item).to.have.key('api_key');
|
||||
|
@ -194,14 +208,24 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const kibanaVersionAccessor = kibanaServer.version;
|
||||
const kibanaVersion = await kibanaVersionAccessor.get();
|
||||
|
||||
// Get enrollment token
|
||||
const { body: policiesRes } = await supertest.get(`/api/fleet/agent_policies`).expect(200);
|
||||
|
||||
expect(policiesRes.items).length(2);
|
||||
const { id: defaultPolicyId } = policiesRes.items.find((p: any) => p.is_default);
|
||||
|
||||
// Get enrollment token
|
||||
const { body: enrollmentApiKeysResponse } = await supertest
|
||||
.get(`/api/fleet/enrollment-api-keys`)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeysResponse.list).length(1);
|
||||
expect(enrollmentApiKeysResponse.list).length(2);
|
||||
const { id: enrollmentKeyId } = enrollmentApiKeysResponse.list.find(
|
||||
(key: any) => key.policy_id === defaultPolicyId
|
||||
);
|
||||
|
||||
const { body: enrollmentApiKeyResponse } = await supertest
|
||||
.get(`/api/fleet/enrollment-api-keys/${enrollmentApiKeysResponse.list[0].id}`)
|
||||
.get(`/api/fleet/enrollment-api-keys/${enrollmentKeyId}`)
|
||||
.expect(200);
|
||||
|
||||
expect(enrollmentApiKeyResponse.item).to.have.key('api_key');
|
||||
|
|
|
@ -58,7 +58,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
}
|
||||
}
|
||||
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
await esArchiver.load('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
|
|
|
@ -27,7 +27,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
describe('fleet_agents_enroll', () => {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
await esArchiver.load('fleet/agents');
|
||||
|
||||
const { body: apiKeyBody } = await esClient.security.createApiKey<typeof apiKey>({
|
||||
body: {
|
||||
|
@ -38,14 +38,14 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const {
|
||||
body: { _source: enrollmentApiKeyDoc },
|
||||
} = await esClient.get({
|
||||
index: '.kibana',
|
||||
id: 'fleet-enrollment-api-keys:ed22ca17-e178-4cfe-8b02-54ea29fbd6d0',
|
||||
index: '.fleet-enrollment-api-keys',
|
||||
id: 'ed22ca17-e178-4cfe-8b02-54ea29fbd6d0',
|
||||
});
|
||||
// @ts-ignore
|
||||
enrollmentApiKeyDoc['fleet-enrollment-api-keys'].api_key_id = apiKey.id;
|
||||
enrollmentApiKeyDoc.api_key_id = apiKey.id;
|
||||
await esClient.update({
|
||||
index: '.kibana',
|
||||
id: 'fleet-enrollment-api-keys:ed22ca17-e178-4cfe-8b02-54ea29fbd6d0',
|
||||
index: '.fleet-enrollment-api-keys',
|
||||
id: 'ed22ca17-e178-4cfe-8b02-54ea29fbd6d0',
|
||||
refresh: true,
|
||||
body: {
|
||||
doc: enrollmentApiKeyDoc,
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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 expect from '@kbn/expect';
|
||||
|
||||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
|
||||
export default function ({ getService }: FtrProviderContext) {
|
||||
const esArchiver = getService('esArchiver');
|
||||
const supertest = getService('supertest');
|
||||
|
||||
describe('fleet_agents_events', () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
});
|
||||
|
||||
it('should return a 200 and the events for a given agent', async () => {
|
||||
const { body: apiResponse } = await supertest
|
||||
.get(`/api/fleet/agents/agent1/events`)
|
||||
.expect(200);
|
||||
expect(apiResponse).to.have.keys(['list', 'total', 'page']);
|
||||
expect(apiResponse.total).to.be(2);
|
||||
expect(apiResponse.page).to.be(1);
|
||||
|
||||
const event = apiResponse.list[0];
|
||||
expect(event).to.have.keys('type', 'subtype', 'message', 'payload');
|
||||
expect(event.payload).to.have.keys('previous_state');
|
||||
});
|
||||
|
||||
it('should return a 400 when given an invalid "kuery" value', async () => {
|
||||
await supertest
|
||||
.get(`/api/fleet/agents/agent1/events?kuery=m`) // missing saved object type
|
||||
.expect(400);
|
||||
});
|
||||
it('should accept a valid "kuery" value', async () => {
|
||||
const filter = encodeURIComponent('fleet-agent-events.subtype : "STOPPED"');
|
||||
const { body: apiResponse } = await supertest
|
||||
.get(`/api/fleet/agents/agent1/events?kuery=${filter}`)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse).to.have.keys(['list', 'total', 'page']);
|
||||
expect(apiResponse.total).to.be(1);
|
||||
expect(apiResponse.page).to.be(1);
|
||||
|
||||
const event = apiResponse.list[0];
|
||||
expect(event.subtype).to.eql('STOPPED');
|
||||
});
|
||||
});
|
||||
}
|
|
@ -100,9 +100,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
it('should return a 400 when given an invalid "kuery" value', async () => {
|
||||
await supertest
|
||||
.get(`/api/fleet/agents?kuery=m`) // missing saved object type
|
||||
.expect(400);
|
||||
await supertest.get(`/api/fleet/agents?kuery=.test%3A`).expect(400);
|
||||
});
|
||||
it('should accept a valid "kuery" value', async () => {
|
||||
const filter = encodeURIComponent('fleet-agents.access_api_key_id : "api-key-2"');
|
||||
|
|
|
@ -15,13 +15,19 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const supertest = getService('supertest');
|
||||
|
||||
describe('fleet_reassign_agent', () => {
|
||||
setupFleetAndAgents(providerContext);
|
||||
beforeEach(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load('fleet/agents');
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
afterEach(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
it('should allow to reassign single agent', async () => {
|
||||
await supertest
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
let accessAPIKeyId: string;
|
||||
let outputAPIKeyId: string;
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
await esArchiver.load('fleet/agents');
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
beforeEach(async () => {
|
||||
|
@ -42,19 +42,19 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const {
|
||||
body: { _source: agentDoc },
|
||||
} = await esClient.get({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
});
|
||||
// @ts-ignore
|
||||
agentDoc['fleet-agents'].access_api_key_id = accessAPIKeyId;
|
||||
agentDoc['fleet-agents'].default_api_key_id = outputAPIKeyBody.id;
|
||||
agentDoc['fleet-agents'].default_api_key = Buffer.from(
|
||||
agentDoc.access_api_key_id = accessAPIKeyId;
|
||||
agentDoc.default_api_key_id = outputAPIKeyBody.id;
|
||||
agentDoc.default_api_key = Buffer.from(
|
||||
`${outputAPIKeyBody.id}:${outputAPIKeyBody.api_key}`
|
||||
).toString('base64');
|
||||
|
||||
await esClient.update({
|
||||
index: '.kibana',
|
||||
id: 'fleet-agents:agent1',
|
||||
index: '.fleet-agents',
|
||||
id: 'agent1',
|
||||
refresh: true,
|
||||
body: {
|
||||
doc: agentDoc,
|
||||
|
|
|
@ -10,7 +10,7 @@ import semver from 'semver';
|
|||
import { FtrProviderContext } from '../../../api_integration/ftr_provider_context';
|
||||
import { setupFleetAndAgents } from './services';
|
||||
import { skipIfNoDockerRegistry } from '../../helpers';
|
||||
import { AGENT_SAVED_OBJECT_TYPE } from '../../../../plugins/fleet/common';
|
||||
import { AGENTS_INDEX } from '../../../../plugins/fleet/common';
|
||||
|
||||
const makeSnapshotVersion = (version: string) => {
|
||||
return version.endsWith('-SNAPSHOT') ? version : `${version}-SNAPSHOT`;
|
||||
|
@ -19,26 +19,33 @@ const makeSnapshotVersion = (version: string) => {
|
|||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
const esArchiver = getService('esArchiver');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
|
||||
describe('fleet upgrade agent', () => {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
setupFleetAndAgents(providerContext);
|
||||
beforeEach(async () => {
|
||||
before(async () => {
|
||||
await esArchiver.loadIfNeeded('fleet/agents');
|
||||
});
|
||||
afterEach(async () => {
|
||||
setupFleetAndAgents(providerContext);
|
||||
beforeEach(async () => {
|
||||
await esArchiver.load('fleet/agents');
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/agents');
|
||||
});
|
||||
|
||||
it('should respond 200 to upgrade agent and update the agent SO', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -56,11 +63,14 @@ export default function (providerContext: FtrProviderContext) {
|
|||
it('should respond 400 if upgrading agent with version the same as snapshot version', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
const kibanaVersionSnapshot = makeSnapshotVersion(kibanaVersion);
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: kibanaVersion } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: kibanaVersion } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -74,11 +84,14 @@ export default function (providerContext: FtrProviderContext) {
|
|||
it('should respond 200 if upgrading agent with version the same as snapshot version and force flag is passed', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
const kibanaVersionSnapshot = makeSnapshotVersion(kibanaVersion);
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: kibanaVersion } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: kibanaVersion } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -94,11 +107,14 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const kibanaVersion = await kibanaServer.version.get();
|
||||
const kibanaVersionSnapshot = makeSnapshotVersion(kibanaVersion);
|
||||
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -111,11 +127,14 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
it('should respond 200 to upgrade agent and update the agent SO without source_uri', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -156,10 +175,15 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
it('should respond 400 if trying to upgrade an agent that is unenrolled', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: { unenrolled_at: new Date().toISOString() },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
unenrolled_at: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
.post(`/api/fleet/agents/agent1/upgrade`)
|
||||
|
@ -184,19 +208,27 @@ export default function (providerContext: FtrProviderContext) {
|
|||
|
||||
it('should respond 200 to bulk upgrade upgradeable agents and update the agent SOs', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -219,19 +251,27 @@ export default function (providerContext: FtrProviderContext) {
|
|||
|
||||
it('should allow to upgrade multiple upgradeable agents by kuery', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -239,7 +279,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.post(`/api/fleet/agents/bulk_upgrade`)
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({
|
||||
agents: 'fleet-agents.active: true',
|
||||
agents: 'active:true',
|
||||
version: kibanaVersion,
|
||||
})
|
||||
.expect(200);
|
||||
|
@ -256,19 +296,23 @@ export default function (providerContext: FtrProviderContext) {
|
|||
await supertest.post(`/api/fleet/agents/agent1/unenroll`).set('kbn-xsrf', 'xxx').send({
|
||||
force: true,
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: '0.0.0' } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -288,20 +332,26 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
it('should not upgrade an unenrolled agent during bulk_upgrade', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
unenrolled_at: new Date().toISOString(),
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
unenrolled_at: new Date().toISOString(),
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: '0.0.0' } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: '0.0.0' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -321,27 +371,38 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
it('should not upgrade an non upgradeable agent during bulk_upgrade', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await es.update({
|
||||
id: 'agent3',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: false, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: false, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -362,27 +423,38 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
it('should upgrade a non upgradeable agent during bulk_upgrade with force flag', async () => {
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: { agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
await es.update({
|
||||
id: 'agent3',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: false, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: false, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -403,18 +475,24 @@ export default function (providerContext: FtrProviderContext) {
|
|||
expect(typeof agent3data.body.item.upgrade_started_at).to.be('string');
|
||||
});
|
||||
it('should respond 400 if trying to bulk upgrade to a version that does not match installed kibana version', async () => {
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await supertest
|
||||
|
@ -438,25 +516,30 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent2',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: {
|
||||
elastic: {
|
||||
agent: { upgradeable: true, version: semver.inc(kibanaVersion, 'patch') },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// attempt to upgrade agent in managed policy
|
||||
const { body } = await supertest
|
||||
.post(`/api/fleet/agents/bulk_upgrade`)
|
||||
|
@ -486,14 +569,16 @@ export default function (providerContext: FtrProviderContext) {
|
|||
});
|
||||
|
||||
const kibanaVersion = await kibanaServer.version.get();
|
||||
await kibanaServer.savedObjects.update({
|
||||
await es.update({
|
||||
id: 'agent1',
|
||||
type: AGENT_SAVED_OBJECT_TYPE,
|
||||
attributes: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
refresh: 'wait_for',
|
||||
index: AGENTS_INDEX,
|
||||
body: {
|
||||
doc: {
|
||||
local_metadata: { elastic: { agent: { upgradeable: true, version: '0.0.0' } } },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// attempt to upgrade agent in managed policy
|
||||
const { body } = await supertest
|
||||
.post(`/api/fleet/agents/agent1/upgrade`)
|
||||
|
|
|
@ -13,9 +13,20 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('fleet_agents_setup', () => {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.load('empty_kibana');
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload('empty_kibana');
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await es.security.deleteUser({
|
||||
|
|
|
@ -37,7 +37,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.get(`/api/fleet/enrollment-api-keys`)
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.total).to.be(3);
|
||||
expect(apiResponse.total).to.be(4);
|
||||
expect(apiResponse.list[0]).to.have.keys('id', 'api_key_id', 'name');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ import { setupFleetAndAgents } from '../agents/services';
|
|||
export default function (providerContext: FtrProviderContext) {
|
||||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
// use function () {} and not () => {} here
|
||||
// because `this` has to point to the Mocha context
|
||||
|
@ -20,7 +21,13 @@ export default function (providerContext: FtrProviderContext) {
|
|||
|
||||
describe('EPM - list', async function () {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
after(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
describe('list api tests', async () => {
|
||||
it('lists all packages from the registry', async function () {
|
||||
|
@ -44,6 +51,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
return response.body;
|
||||
};
|
||||
const listResponse = await fetchLimitedPackageList();
|
||||
|
||||
expect(listResponse.response).to.eql(['endpoint']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package_paths:
|
||||
- /packages/production
|
||||
- /packages/test-packages
|
||||
package_paths:
|
||||
- /packages/production
|
||||
# TODO remove temp
|
||||
- /packages/snapshot
|
||||
- /packages/test-packages
|
||||
|
|
|
@ -13,9 +13,19 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const { getService } = providerContext;
|
||||
const supertest = getService('supertest');
|
||||
const es = getService('es');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('fleet_setup', () => {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.load('empty_kibana');
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await esArchiver.unload('empty_kibana');
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await es.security.deleteUser({
|
||||
|
@ -117,7 +127,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.map((p: any) => p.name)
|
||||
.sort();
|
||||
|
||||
expect(installedPackages).to.eql(['elastic_agent', 'endpoint', 'system']);
|
||||
expect(installedPackages).to.eql(['elastic_agent', 'endpoint', 'fleet_server', 'system']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ export default function ({ loadTestFile }) {
|
|||
loadTestFile(require.resolve('./agents/enroll'));
|
||||
loadTestFile(require.resolve('./agents/unenroll'));
|
||||
loadTestFile(require.resolve('./agents/checkin'));
|
||||
loadTestFile(require.resolve('./agents/events'));
|
||||
loadTestFile(require.resolve('./agents/acks'));
|
||||
loadTestFile(require.resolve('./agents/complete_flow'));
|
||||
loadTestFile(require.resolve('./agents/actions'));
|
||||
|
|
|
@ -20,6 +20,14 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
|
||||
describe('Package Policy - create', async function () {
|
||||
let agentPolicyId: string;
|
||||
before(async () => {
|
||||
await getService('esArchiver').load('empty_kibana');
|
||||
await getService('esArchiver').load('fleet/empty_fleet_server');
|
||||
});
|
||||
after(async () => {
|
||||
await getService('esArchiver').unload('empty_kibana');
|
||||
await getService('esArchiver').unload('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
before(async function () {
|
||||
const { body: agentPolicyResponse } = await supertest
|
||||
|
|
|
@ -20,7 +20,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
skipIfNoDockerRegistry(providerContext);
|
||||
let agentPolicy: any;
|
||||
let packagePolicy: any;
|
||||
|
||||
before(async () => {
|
||||
await getService('esArchiver').load('empty_kibana');
|
||||
await getService('esArchiver').load('fleet/empty_fleet_server');
|
||||
});
|
||||
before(async function () {
|
||||
let agentPolicyResponse = await supertest
|
||||
.post(`/api/fleet/agent_policies`)
|
||||
|
@ -79,6 +82,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({ packagePolicyIds: [packagePolicy.id] });
|
||||
});
|
||||
after(async () => {
|
||||
await getService('esArchiver').unload('empty_kibana');
|
||||
await getService('esArchiver').unload('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
it('should fail on managed agent policies', async function () {
|
||||
// update existing policy to managed
|
||||
|
|
|
@ -22,6 +22,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
skipIfNoDockerRegistry(providerContext);
|
||||
let agentPolicyId: string;
|
||||
let packagePolicyId: string;
|
||||
before(async () => {
|
||||
await getService('esArchiver').load('empty_kibana');
|
||||
await getService('esArchiver').load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
before(async function () {
|
||||
if (!server.enabled) {
|
||||
|
@ -73,7 +77,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.send({ packagePolicyIds: [packagePolicyId] })
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await getService('esArchiver').unload('fleet/empty_fleet_server');
|
||||
await getService('esArchiver').unload('empty_kibana');
|
||||
});
|
||||
it('should succeed with a valid id', async function () {
|
||||
await supertest.get(`/api/fleet/package_policies/${packagePolicyId}`).expect(200);
|
||||
});
|
||||
|
|
|
@ -24,6 +24,10 @@ export default function (providerContext: FtrProviderContext) {
|
|||
let managedAgentPolicyId: string;
|
||||
let packagePolicyId: string;
|
||||
let packagePolicyId2: string;
|
||||
before(async () => {
|
||||
await getService('esArchiver').load('empty_kibana');
|
||||
await getService('esArchiver').load('fleet/empty_fleet_server');
|
||||
});
|
||||
|
||||
before(async function () {
|
||||
if (!server.enabled) {
|
||||
|
@ -106,6 +110,11 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.send({ agentPolicyId });
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await getService('esArchiver').unload('fleet/empty_fleet_server');
|
||||
await getService('esArchiver').unload('empty_kibana');
|
||||
});
|
||||
|
||||
it('should fail on managed agent policies', async function () {
|
||||
const { body } = await supertest
|
||||
.put(`/api/fleet/package_policies/${packagePolicyId}`)
|
||||
|
|
|
@ -16,9 +16,13 @@ export default function (providerContext: FtrProviderContext) {
|
|||
const supertest = getService('supertest');
|
||||
const kibanaServer = getService('kibanaServer');
|
||||
const esClient: Client = getService('legacyEs');
|
||||
const esArchiver = getService('esArchiver');
|
||||
|
||||
describe('Settings - update', async function () {
|
||||
skipIfNoDockerRegistry(providerContext);
|
||||
before(async () => {
|
||||
await esArchiver.load('fleet/empty_fleet_server');
|
||||
});
|
||||
setupFleetAndAgents(providerContext);
|
||||
|
||||
const createdAgentPolicyIds: string[] = [];
|
||||
|
@ -28,10 +32,12 @@ export default function (providerContext: FtrProviderContext) {
|
|||
.post(`/api/fleet/agent_policies/delete`)
|
||||
.set('kbn-xsrf', 'xxxx')
|
||||
.send({ agentPolicyId })
|
||||
.expect(200)
|
||||
);
|
||||
await Promise.all(deletedPromises);
|
||||
});
|
||||
after(async () => {
|
||||
await esArchiver.unload('fleet/empty_fleet_server');
|
||||
});
|
||||
it("should bump all agent policy's revision", async function () {
|
||||
const { body: testPolicy1PostRes } = await supertest
|
||||
.post(`/api/fleet/agent_policies`)
|
||||
|
|
|
@ -15,7 +15,7 @@ import { defineDockerServersConfig } from '@kbn/test';
|
|||
// example: https://beats-ci.elastic.co/blue/organizations/jenkins/Ingest-manager%2Fpackage-storage/detail/snapshot/74/pipeline/257#step-302-log-1.
|
||||
// It should be updated any time there is a new Docker image published for the Snapshot Distribution of the Package Registry.
|
||||
export const dockerImage =
|
||||
'docker.elastic.co/package-registry/distribution:99dadb957d76b704637150d34a7219345cc0aeef';
|
||||
'docker.elastic.co/package-registry/distribution:c5925eb82898dfc3e879a521871c7383513804c7';
|
||||
|
||||
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
||||
const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts'));
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agents:agent1",
|
||||
"index": ".kibana",
|
||||
"id": "agent1",
|
||||
"index": ".fleet-agents",
|
||||
"source": {
|
||||
"type": "fleet-agents",
|
||||
"fleet-agents": {
|
||||
"access_api_key_id": "api-key-1",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"fleet-agents": "7.10.0"
|
||||
}
|
||||
"access_api_key_id": "api-key-1",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +17,15 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agents:agent2",
|
||||
"index": ".kibana",
|
||||
"id": "agent2",
|
||||
"index": ".fleet-agents",
|
||||
"source": {
|
||||
"type": "fleet-agents",
|
||||
"fleet-agents": {
|
||||
"access_api_key_id": "api-key-2",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"fleet-agents": "7.10.0"
|
||||
}
|
||||
"access_api_key_id": "api-key-2",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,21 +33,15 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agents:agent3",
|
||||
"index": ".kibana",
|
||||
"id": "agent3",
|
||||
"index": ".fleet-agents",
|
||||
"source": {
|
||||
"type": "fleet-agents",
|
||||
"fleet-agents": {
|
||||
"access_api_key_id": "api-key-3",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"fleet-agents": "7.10.0"
|
||||
}
|
||||
"access_api_key_id": "api-key-3",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,21 +49,15 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agents:agent4",
|
||||
"index": ".kibana",
|
||||
"id": "agent4",
|
||||
"index": ".fleet-agents",
|
||||
"source": {
|
||||
"type": "fleet-agents",
|
||||
"fleet-agents": {
|
||||
"access_api_key_id": "api-key-4",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
},
|
||||
"migrationVersion": {
|
||||
"fleet-agents": "7.10.0"
|
||||
}
|
||||
"access_api_key_id": "api-key-4",
|
||||
"active": true,
|
||||
"policy_id": "policy1",
|
||||
"type": "PERMANENT",
|
||||
"local_metadata": {},
|
||||
"user_provided_metadata": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,79 +65,14 @@
|
|||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-enrollment-api-keys:ed22ca17-e178-4cfe-8b02-54ea29fbd6d0",
|
||||
"index": ".kibana",
|
||||
"id": "ed22ca17-e178-4cfe-8b02-54ea29fbd6d0",
|
||||
"index": ".fleet-enrollment-api-keys",
|
||||
"source": {
|
||||
"fleet-enrollment-api-keys" : {
|
||||
"created_at" : "2019-10-10T16:31:12.518Z",
|
||||
"name": "FleetEnrollmentKey:1",
|
||||
"api_key_id" : "key",
|
||||
"policy_id" : "policy1",
|
||||
"active" : true
|
||||
},
|
||||
"type" : "fleet-enrollment-api-keys",
|
||||
"references": [],
|
||||
"migrationVersion": {
|
||||
"fleet-enrollment-api-keys": "7.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agent-events:event1",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"type": "fleet-agent-events",
|
||||
"fleet-agent-events": {
|
||||
"agent_id": "agent1",
|
||||
"type": "STATE",
|
||||
"subtype": "STARTED",
|
||||
"message": "State changed from STOPPED to STARTED",
|
||||
"payload": "{\"previous_state\": \"STOPPED\"}",
|
||||
"timestamp": "2019-09-20T17:30:22.950Z"
|
||||
},
|
||||
"migrationVersion": {
|
||||
"fleet-agent-events": "7.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agent-events:event2",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"type": "fleet-agent-events",
|
||||
"fleet-agent-events": {
|
||||
"agent_id": "agent1",
|
||||
"type": "STATE",
|
||||
"subtype": "STOPPED",
|
||||
"message": "State changed from RUNNING to STOPPED",
|
||||
"payload": "{\"previous_state\": \"RUNNING\"}",
|
||||
"timestamp": "2019-09-20T17:30:25.950Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "doc",
|
||||
"value": {
|
||||
"id": "fleet-agent-actions:37ed51ff-e80f-4f2a-a62d-f4fa975e7d85",
|
||||
"index": ".kibana",
|
||||
"source": {
|
||||
"type": "fleet-agent-actions",
|
||||
"fleet-agent-actions": {
|
||||
"agent_id": "agent1",
|
||||
"created_at": "2019-09-04T15:04:07+0000",
|
||||
"type": "RESUME",
|
||||
"sent_at": "2019-09-04T15:03:07+0000"
|
||||
}
|
||||
"created_at" : "2019-10-10T16:31:12.518Z",
|
||||
"name": "FleetEnrollmentKey:1",
|
||||
"api_key_id" : "key",
|
||||
"policy_id" : "policy1",
|
||||
"active" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3081,3 +3081,444 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-actions": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-actions_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "6527beea5a4a2f33acb599585ed4710442ece7f2"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"action_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"agents": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"data": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"expiration": {
|
||||
"type": "date"
|
||||
},
|
||||
"input_type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-agents": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-agents_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "87cab95ac988d78a78d0d66bbf05361b65dcbacf"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"access_api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"action_seq_no": {
|
||||
"type": "integer"
|
||||
},
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"agent": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"default_api_key": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"default_api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"enrolled_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"last_checkin": {
|
||||
"type": "date"
|
||||
},
|
||||
"last_checkin_status": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"last_updated": {
|
||||
"type": "date"
|
||||
},
|
||||
"local_metadata": {
|
||||
"properties": {
|
||||
"elastic": {
|
||||
"properties": {
|
||||
"agent": {
|
||||
"properties": {
|
||||
"build": {
|
||||
"properties": {
|
||||
"original": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"log_level": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"upgradeable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"version": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 16,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"hostname": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 64,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"mac": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 17,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"name": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"os": {
|
||||
"properties": {
|
||||
"family": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"full": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 128,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"kernel": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 128,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"name": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"platform": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 32,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_coordinator_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_revision_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shared_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"unenrolled_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"unenrollment_started_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"upgrade_started_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"upgraded_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"user_provided_metadata": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-enrollment-api-keys": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-enrollment-api-keys_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "06bef724726f3bea9f474a09be0a7f7881c28d4a"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"api_key": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"expire_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-policies": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-policies_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "c2c2a49b19562942fa7c1ff1537e66e751cdb4fa"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"coordinator_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"data": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"default_fleet_server": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"revision_idx": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-servers": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-servers_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "e2782448c7235ec9af66ca7997e867d715ac379c"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"agent": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,440 @@
|
|||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-actions": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-actions_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "6527beea5a4a2f33acb599585ed4710442ece7f2"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"action_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"agents": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"data": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"expiration": {
|
||||
"type": "date"
|
||||
},
|
||||
"input_type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-agents": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-agents_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "87cab95ac988d78a78d0d66bbf05361b65dcbacf"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"access_api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"action_seq_no": {
|
||||
"type": "integer"
|
||||
},
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"agent": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"default_api_key": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"default_api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"enrolled_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"last_checkin": {
|
||||
"type": "date"
|
||||
},
|
||||
"last_checkin_status": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"last_updated": {
|
||||
"type": "date"
|
||||
},
|
||||
"local_metadata": {
|
||||
"properties": {
|
||||
"elastic": {
|
||||
"properties": {
|
||||
"agent": {
|
||||
"properties": {
|
||||
"build": {
|
||||
"properties": {
|
||||
"original": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"log_level": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"snapshot": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"upgradeable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"version": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 16,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"hostname": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 64,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"mac": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 17,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"name": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
},
|
||||
"os": {
|
||||
"properties": {
|
||||
"family": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"full": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 128,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"kernel": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 128,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"name": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 256,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
},
|
||||
"platform": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"fields": {
|
||||
"keyword": {
|
||||
"ignore_above": 32,
|
||||
"type": "keyword"
|
||||
}
|
||||
},
|
||||
"type": "text"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"packages": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_coordinator_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_revision_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shared_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"type": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"unenrolled_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"unenrollment_started_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"upgrade_started_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"upgraded_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"user_provided_metadata": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-enrollment-api-keys": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-enrollment-api-keys_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "06bef724726f3bea9f474a09be0a7f7881c28d4a"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"api_key": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"api_key_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"expire_at": {
|
||||
"type": "date"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "date"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-policies": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-policies_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "c2c2a49b19562942fa7c1ff1537e66e751cdb4fa"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"coordinator_idx": {
|
||||
"type": "integer"
|
||||
},
|
||||
"data": {
|
||||
"enabled": false,
|
||||
"type": "object"
|
||||
},
|
||||
"default_fleet_server": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"policy_id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"revision_idx": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"aliases": {
|
||||
".fleet-servers": {
|
||||
}
|
||||
},
|
||||
"index": ".fleet-servers_1",
|
||||
"mappings": {
|
||||
"_meta": {
|
||||
"migrationHash": "e2782448c7235ec9af66ca7997e867d715ac379c"
|
||||
},
|
||||
"dynamic": "false",
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"agent": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"properties": {
|
||||
"architecture": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"ip": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"name": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
},
|
||||
"server": {
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"version": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_replicas": "1",
|
||||
"number_of_shards": "1"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue