mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Fleet] Fix xpack.agents.* to not be editable in UI if defined in kibana.yml (#135669)
This commit is contained in:
parent
840ce5b850
commit
818f33fe62
12 changed files with 407 additions and 176 deletions
|
@ -15,6 +15,7 @@ export interface BaseSettings {
|
|||
|
||||
export interface Settings extends BaseSettings {
|
||||
id: string;
|
||||
preconfigured_fields?: Array<'fleet_server_hosts'>;
|
||||
}
|
||||
|
||||
export interface SettingsSOAttributes extends BaseSettings, SavedObjectAttributes {}
|
||||
|
|
5
x-pack/plugins/fleet/cypress/fixtures/example.json
Normal file
5
x-pack/plugins/fleet/cypress/fixtures/example.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
|
@ -27,7 +27,7 @@ export const SettingsPage: React.FunctionComponent<SettingsPageProps> = ({
|
|||
return (
|
||||
<>
|
||||
<EuiSpacer size="m" />
|
||||
<SettingsSection fleetServerHosts={settings.fleet_server_hosts} />
|
||||
<SettingsSection settings={settings} />
|
||||
<EuiSpacer size="m" />
|
||||
<OutputSection outputs={outputs} deleteOutput={deleteOutput} />
|
||||
</>
|
||||
|
|
|
@ -30,7 +30,13 @@ const args: Args = {
|
|||
export const SettingsSection = ({ width, fleetServerHosts }: Args) => {
|
||||
return (
|
||||
<div style={{ width }}>
|
||||
<Component fleetServerHosts={fleetServerHosts} />
|
||||
<Component
|
||||
settings={{
|
||||
id: 'default-settings',
|
||||
fleet_server_hosts: fleetServerHosts,
|
||||
preconfigured_fields: [],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,20 +6,27 @@
|
|||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { EuiTitle, EuiLink, EuiText, EuiSpacer, EuiBasicTable, EuiButtonEmpty } from '@elastic/eui';
|
||||
import {
|
||||
EuiTitle,
|
||||
EuiLink,
|
||||
EuiText,
|
||||
EuiSpacer,
|
||||
EuiBasicTable,
|
||||
EuiButtonEmpty,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import type { EuiBasicTableColumn } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import type { Settings } from '../../../../types';
|
||||
import { useLink, useStartServices } from '../../../../hooks';
|
||||
|
||||
export interface SettingsSectionProps {
|
||||
fleetServerHosts: string[];
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
export const SettingsSection: React.FunctionComponent<SettingsSectionProps> = ({
|
||||
fleetServerHosts,
|
||||
}) => {
|
||||
export const SettingsSection: React.FunctionComponent<SettingsSectionProps> = ({ settings }) => {
|
||||
const { docLinks } = useStartServices();
|
||||
const { getHref } = useLink();
|
||||
|
||||
|
@ -34,6 +41,26 @@ export const SettingsSection: React.FunctionComponent<SettingsSectionProps> = ({
|
|||
];
|
||||
}, []);
|
||||
|
||||
const isEditDisabled = settings.preconfigured_fields?.includes('fleet_server_hosts') ?? false;
|
||||
const BtnWrapper = useMemo((): React.FunctionComponent => {
|
||||
if (!isEditDisabled) {
|
||||
return ({ children }) => <>{children}</>;
|
||||
}
|
||||
|
||||
return ({ children }) => (
|
||||
<EuiToolTip
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.settings.fleetServerHostsPreconfiguredTooltipContent"
|
||||
defaultMessage="Fleet Server hosts are configured outside of Fleet. Refer to your kibana config for more details."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<>{children}</>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}, [isEditDisabled]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiTitle size="s">
|
||||
|
@ -62,18 +89,21 @@ export const SettingsSection: React.FunctionComponent<SettingsSectionProps> = ({
|
|||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiBasicTable columns={columns} items={fleetServerHosts} />
|
||||
<EuiBasicTable columns={columns} items={settings.fleet_server_hosts} />
|
||||
<EuiSpacer size="s" />
|
||||
<EuiButtonEmpty
|
||||
iconType="pencil"
|
||||
href={getHref('settings_edit_fleet_server_hosts')}
|
||||
data-test-subj="editHostsBtn"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.settings.fleetServerHostEditButtonLabel"
|
||||
defaultMessage="Edit hosts"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
<BtnWrapper>
|
||||
<EuiButtonEmpty
|
||||
iconType="pencil"
|
||||
href={getHref('settings_edit_fleet_server_hosts')}
|
||||
data-test-subj="editHostsBtn"
|
||||
disabled={isEditDisabled}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.fleet.settings.fleetServerHostEditButtonLabel"
|
||||
defaultMessage="Edit hosts"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
</BtnWrapper>
|
||||
<EuiSpacer size="m" />
|
||||
</>
|
||||
);
|
||||
|
|
148
x-pack/plugins/fleet/server/config.ts
Normal file
148
x-pack/plugins/fleet/server/config.ts
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* 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 path from 'path';
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { TypeOf } from '@kbn/config-schema';
|
||||
import type { PluginConfigDescriptor } from '@kbn/core/server';
|
||||
|
||||
import { getExperimentalAllowedValues, isValidExperimentalValue } from '../common';
|
||||
const allowedExperimentalValues = getExperimentalAllowedValues();
|
||||
|
||||
import {
|
||||
PreconfiguredPackagesSchema,
|
||||
PreconfiguredAgentPoliciesSchema,
|
||||
PreconfiguredOutputsSchema,
|
||||
} from './types';
|
||||
|
||||
const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages');
|
||||
const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch');
|
||||
|
||||
export const config: PluginConfigDescriptor = {
|
||||
exposeToBrowser: {
|
||||
epm: true,
|
||||
agents: {
|
||||
enabled: true,
|
||||
},
|
||||
enableExperimental: true,
|
||||
},
|
||||
deprecations: ({ renameFromRoot, unused, unusedFromRoot }) => [
|
||||
// Unused settings before Fleet server exists
|
||||
unused('agents.kibana', { level: 'critical' }),
|
||||
unused('agents.maxConcurrentConnections', { level: 'critical' }),
|
||||
unused('agents.agentPolicyRolloutRateLimitIntervalMs', { level: 'critical' }),
|
||||
unused('agents.agentPolicyRolloutRateLimitRequestPerInterval', { level: 'critical' }),
|
||||
unused('agents.pollingRequestTimeout', { level: 'critical' }),
|
||||
unused('agents.tlsCheckDisabled', { level: 'critical' }),
|
||||
unused('agents.fleetServerEnabled', { level: 'critical' }),
|
||||
// Deprecate default policy flags
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
if (
|
||||
(fullConfig?.xpack?.fleet?.agentPolicies || []).find((policy: any) => policy.is_default)
|
||||
) {
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agentPolicies.is_default',
|
||||
message: `Config key [xpack.fleet.agentPolicies.is_default] is deprecated.`,
|
||||
correctiveActions: {
|
||||
manualSteps: [`Create a dedicated policy instead through the UI or API.`],
|
||||
},
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
return fullConfig;
|
||||
},
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
if (
|
||||
(fullConfig?.xpack?.fleet?.agentPolicies || []).find(
|
||||
(policy: any) => policy.is_default_fleet_server
|
||||
)
|
||||
) {
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agentPolicies.is_default_fleet_server',
|
||||
message: `Config key [xpack.fleet.agentPolicies.is_default_fleet_server] is deprecated.`,
|
||||
correctiveActions: {
|
||||
manualSteps: [`Create a dedicated fleet server policy instead through the UI or API.`],
|
||||
},
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
return fullConfig;
|
||||
},
|
||||
// Renaming elasticsearch.host => elasticsearch.hosts
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
const oldValue = fullConfig?.xpack?.fleet?.agents?.elasticsearch?.host;
|
||||
if (oldValue) {
|
||||
delete fullConfig.xpack.fleet.agents.elasticsearch.host;
|
||||
fullConfig.xpack.fleet.agents.elasticsearch.hosts = [oldValue];
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agents.elasticsearch.host',
|
||||
message: `Config key [xpack.fleet.agents.elasticsearch.host] is deprecated and replaced by [xpack.fleet.agents.elasticsearch.hosts]`,
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
`Use [xpack.fleet.agents.elasticsearch.hosts] with an array of host instead.`,
|
||||
],
|
||||
},
|
||||
level: 'critical',
|
||||
});
|
||||
}
|
||||
|
||||
return fullConfig;
|
||||
},
|
||||
],
|
||||
schema: schema.object({
|
||||
registryUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })),
|
||||
registryProxyUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })),
|
||||
agents: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
elasticsearch: schema.object({
|
||||
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
|
||||
ca_sha256: schema.maybe(schema.string()),
|
||||
}),
|
||||
fleet_server: schema.maybe(
|
||||
schema.object({
|
||||
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
|
||||
})
|
||||
),
|
||||
}),
|
||||
packages: PreconfiguredPackagesSchema,
|
||||
agentPolicies: PreconfiguredAgentPoliciesSchema,
|
||||
outputs: PreconfiguredOutputsSchema,
|
||||
agentIdVerificationEnabled: schema.boolean({ defaultValue: true }),
|
||||
developer: schema.object({
|
||||
disableRegistryVersionCheck: schema.boolean({ defaultValue: false }),
|
||||
allowAgentUpgradeSourceUri: schema.boolean({ defaultValue: false }),
|
||||
bundledPackageLocation: schema.string({ defaultValue: DEFAULT_BUNDLED_PACKAGE_LOCATION }),
|
||||
}),
|
||||
packageVerification: schema.object({
|
||||
gpgKeyPath: schema.string({ defaultValue: DEFAULT_GPG_KEY_PATH }),
|
||||
}),
|
||||
/**
|
||||
* For internal use. A list of string values (comma delimited) that will enable experimental
|
||||
* type of functionality that is not yet released.
|
||||
*
|
||||
* @example
|
||||
* xpack.fleet.enableExperimental:
|
||||
* - feature1
|
||||
* - feature2
|
||||
*/
|
||||
enableExperimental: schema.arrayOf(schema.string(), {
|
||||
defaultValue: () => [],
|
||||
validate(list) {
|
||||
for (const key of list) {
|
||||
if (!isValidExperimentalValue(key)) {
|
||||
return `[${key}] is not allowed. Allowed values are: ${allowedExperimentalValues.join(
|
||||
', '
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
export type FleetConfigType = TypeOf<typeof config.schema>;
|
|
@ -5,20 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
import type { TypeOf } from '@kbn/config-schema';
|
||||
import type { PluginConfigDescriptor, PluginInitializerContext } from '@kbn/core/server';
|
||||
|
||||
import { getExperimentalAllowedValues, isValidExperimentalValue } from '../common';
|
||||
const allowedExperimentalValues = getExperimentalAllowedValues();
|
||||
|
||||
import {
|
||||
PreconfiguredPackagesSchema,
|
||||
PreconfiguredAgentPoliciesSchema,
|
||||
PreconfiguredOutputsSchema,
|
||||
} from './types';
|
||||
import type { PluginInitializerContext } from '@kbn/core/server';
|
||||
|
||||
import { FleetPlugin } from './plugin';
|
||||
|
||||
|
@ -45,133 +32,8 @@ export type {
|
|||
PostPackagePolicyPostCreateCallback,
|
||||
} from './types';
|
||||
export { AgentNotFoundError, FleetUnauthorizedError } from './errors';
|
||||
|
||||
const DEFAULT_BUNDLED_PACKAGE_LOCATION = path.join(__dirname, '../target/bundled_packages');
|
||||
const DEFAULT_GPG_KEY_PATH = path.join(__dirname, '../target/keys/GPG-KEY-elasticsearch');
|
||||
|
||||
export const config: PluginConfigDescriptor = {
|
||||
exposeToBrowser: {
|
||||
epm: true,
|
||||
agents: {
|
||||
enabled: true,
|
||||
},
|
||||
enableExperimental: true,
|
||||
},
|
||||
deprecations: ({ renameFromRoot, unused, unusedFromRoot }) => [
|
||||
// Unused settings before Fleet server exists
|
||||
unused('agents.kibana', { level: 'critical' }),
|
||||
unused('agents.maxConcurrentConnections', { level: 'critical' }),
|
||||
unused('agents.agentPolicyRolloutRateLimitIntervalMs', { level: 'critical' }),
|
||||
unused('agents.agentPolicyRolloutRateLimitRequestPerInterval', { level: 'critical' }),
|
||||
unused('agents.pollingRequestTimeout', { level: 'critical' }),
|
||||
unused('agents.tlsCheckDisabled', { level: 'critical' }),
|
||||
unused('agents.fleetServerEnabled', { level: 'critical' }),
|
||||
// Deprecate default policy flags
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
if (
|
||||
(fullConfig?.xpack?.fleet?.agentPolicies || []).find((policy: any) => policy.is_default)
|
||||
) {
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agentPolicies.is_default',
|
||||
message: `Config key [xpack.fleet.agentPolicies.is_default] is deprecated.`,
|
||||
correctiveActions: {
|
||||
manualSteps: [`Create a dedicated policy instead through the UI or API.`],
|
||||
},
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
return fullConfig;
|
||||
},
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
if (
|
||||
(fullConfig?.xpack?.fleet?.agentPolicies || []).find(
|
||||
(policy: any) => policy.is_default_fleet_server
|
||||
)
|
||||
) {
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agentPolicies.is_default_fleet_server',
|
||||
message: `Config key [xpack.fleet.agentPolicies.is_default_fleet_server] is deprecated.`,
|
||||
correctiveActions: {
|
||||
manualSteps: [`Create a dedicated fleet server policy instead through the UI or API.`],
|
||||
},
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
return fullConfig;
|
||||
},
|
||||
// Renaming elasticsearch.host => elasticsearch.hosts
|
||||
(fullConfig, fromPath, addDeprecation) => {
|
||||
const oldValue = fullConfig?.xpack?.fleet?.agents?.elasticsearch?.host;
|
||||
if (oldValue) {
|
||||
delete fullConfig.xpack.fleet.agents.elasticsearch.host;
|
||||
fullConfig.xpack.fleet.agents.elasticsearch.hosts = [oldValue];
|
||||
addDeprecation({
|
||||
configPath: 'xpack.fleet.agents.elasticsearch.host',
|
||||
message: `Config key [xpack.fleet.agents.elasticsearch.host] is deprecated and replaced by [xpack.fleet.agents.elasticsearch.hosts]`,
|
||||
correctiveActions: {
|
||||
manualSteps: [
|
||||
`Use [xpack.fleet.agents.elasticsearch.hosts] with an array of host instead.`,
|
||||
],
|
||||
},
|
||||
level: 'critical',
|
||||
});
|
||||
}
|
||||
|
||||
return fullConfig;
|
||||
},
|
||||
],
|
||||
schema: schema.object({
|
||||
registryUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })),
|
||||
registryProxyUrl: schema.maybe(schema.uri({ scheme: ['http', 'https'] })),
|
||||
agents: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
elasticsearch: schema.object({
|
||||
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
|
||||
ca_sha256: schema.maybe(schema.string()),
|
||||
}),
|
||||
fleet_server: schema.maybe(
|
||||
schema.object({
|
||||
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
|
||||
})
|
||||
),
|
||||
}),
|
||||
packages: PreconfiguredPackagesSchema,
|
||||
agentPolicies: PreconfiguredAgentPoliciesSchema,
|
||||
outputs: PreconfiguredOutputsSchema,
|
||||
agentIdVerificationEnabled: schema.boolean({ defaultValue: true }),
|
||||
developer: schema.object({
|
||||
disableRegistryVersionCheck: schema.boolean({ defaultValue: false }),
|
||||
allowAgentUpgradeSourceUri: schema.boolean({ defaultValue: false }),
|
||||
bundledPackageLocation: schema.string({ defaultValue: DEFAULT_BUNDLED_PACKAGE_LOCATION }),
|
||||
}),
|
||||
packageVerification: schema.object({
|
||||
gpgKeyPath: schema.string({ defaultValue: DEFAULT_GPG_KEY_PATH }),
|
||||
}),
|
||||
/**
|
||||
* For internal use. A list of string values (comma delimited) that will enable experimental
|
||||
* type of functionality that is not yet released.
|
||||
*
|
||||
* @example
|
||||
* xpack.fleet.enableExperimental:
|
||||
* - feature1
|
||||
* - feature2
|
||||
*/
|
||||
enableExperimental: schema.arrayOf(schema.string(), {
|
||||
defaultValue: () => [],
|
||||
validate(list) {
|
||||
for (const key of list) {
|
||||
if (!isValidExperimentalValue(key)) {
|
||||
return `[${key}] is not allowed. Allowed values are: ${allowedExperimentalValues.join(
|
||||
', '
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
},
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
export type FleetConfigType = TypeOf<typeof config.schema>;
|
||||
export { config } from './config';
|
||||
export type { FleetConfigType } from './config';
|
||||
|
||||
export type { PackagePolicyServiceInterface } from './services/package_policy';
|
||||
|
||||
|
|
|
@ -13,7 +13,11 @@ import type { Output } from '../../types';
|
|||
import * as agentPolicy from '../agent_policy';
|
||||
import { outputService } from '../output';
|
||||
|
||||
import { createOrUpdatePreconfiguredOutputs, cleanPreconfiguredOutputs } from './outputs';
|
||||
import {
|
||||
createOrUpdatePreconfiguredOutputs,
|
||||
cleanPreconfiguredOutputs,
|
||||
getPreconfiguredOutputFromConfig,
|
||||
} from './outputs';
|
||||
|
||||
jest.mock('../agent_policy_update');
|
||||
jest.mock('../output');
|
||||
|
@ -64,6 +68,31 @@ describe('output preconfiguration', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should generate a preconfigured output if elasticsearch.hosts is set in the config', async () => {
|
||||
expect(
|
||||
getPreconfiguredOutputFromConfig({
|
||||
agents: {
|
||||
elasticsearch: { hosts: ['http://elasticsearc:9201'] },
|
||||
},
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
Object {
|
||||
"ca_sha256": undefined,
|
||||
"hosts": Array [
|
||||
"http://elasticsearc:9201",
|
||||
],
|
||||
"id": "fleet-default-output",
|
||||
"is_default": true,
|
||||
"is_default_monitoring": true,
|
||||
"is_preconfigured": true,
|
||||
"name": "default",
|
||||
"type": "elasticsearch",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should create preconfigured output that does not exists', async () => {
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
|
|
|
@ -11,11 +11,33 @@ import { safeDump } from 'js-yaml';
|
|||
|
||||
import type { PreconfiguredOutput, Output } from '../../../common';
|
||||
import { normalizeHostsForAgents } from '../../../common';
|
||||
import type { FleetConfigType } from '../../config';
|
||||
import { DEFAULT_OUTPUT_ID, DEFAULT_OUTPUT } from '../../constants';
|
||||
import { outputService } from '../output';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
|
||||
import { appContextService } from '../app_context';
|
||||
|
||||
export function getPreconfiguredOutputFromConfig(config?: FleetConfigType) {
|
||||
const { outputs: outputsOrUndefined } = config;
|
||||
|
||||
const outputs: PreconfiguredOutput[] = (outputsOrUndefined || []).concat([
|
||||
...(config?.agents.elasticsearch.hosts
|
||||
? [
|
||||
{
|
||||
...DEFAULT_OUTPUT,
|
||||
id: DEFAULT_OUTPUT_ID,
|
||||
hosts: config?.agents.elasticsearch.hosts,
|
||||
ca_sha256: config?.agents.elasticsearch.ca_sha256,
|
||||
is_preconfigured: true,
|
||||
} as PreconfiguredOutput,
|
||||
]
|
||||
: []),
|
||||
]);
|
||||
|
||||
return outputs;
|
||||
}
|
||||
|
||||
export async function ensurePreconfiguredOutputs(
|
||||
soClient: SavedObjectsClientContract,
|
||||
esClient: ElasticsearchClient,
|
||||
|
|
|
@ -58,6 +58,7 @@ describe('getCloudFleetServersHosts', () => {
|
|||
describe('settingsSetup', () => {
|
||||
afterEach(() => {
|
||||
mockedAppContextService.getCloud.mockReset();
|
||||
mockedAppContextService.getConfig.mockReset();
|
||||
});
|
||||
it('should create settings if there is no settings', async () => {
|
||||
const soClientMock = savedObjectsClientMock.create();
|
||||
|
@ -158,7 +159,113 @@ describe('settingsSetup', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('should not update settings if there is settings with fleet server hosts and default fleet server hosts', async () => {
|
||||
it('should update settings if there is a new fleet server host in the config', async () => {
|
||||
const soClientMock = savedObjectsClientMock.create();
|
||||
mockedAppContextService.getCloud.mockReturnValue({
|
||||
cloudId:
|
||||
'test:dGVzdC5mcjo5MjQzJGRhM2I2YjNkYWY5ZDRjODE4ZjI4ZmEzNDdjMzgzODViJDgxMmY4NWMxZjNjZTQ2YTliYjgxZjFjMWIxMzRjNmRl',
|
||||
isCloudEnabled: true,
|
||||
deploymentId: 'deployment-id-1',
|
||||
apm: {},
|
||||
});
|
||||
mockedAppContextService.getConfig.mockReturnValue({
|
||||
agents: {
|
||||
fleet_server: { hosts: ['http://fleetserverupdated.fr:8220'] },
|
||||
},
|
||||
} as any);
|
||||
|
||||
soClientMock.find.mockResolvedValue({
|
||||
total: 1,
|
||||
page: 0,
|
||||
per_page: 10,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'defaultsettings',
|
||||
attributes: {
|
||||
fleet_server_hosts: ['https://deployment-id-1.fleet.test.fr:9243'],
|
||||
},
|
||||
type: 'so_type',
|
||||
references: [],
|
||||
score: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
soClientMock.update.mockResolvedValue({
|
||||
id: 'updated',
|
||||
attributes: {},
|
||||
references: [],
|
||||
type: 'so_type',
|
||||
});
|
||||
|
||||
soClientMock.create.mockResolvedValue({
|
||||
id: 'created',
|
||||
attributes: {},
|
||||
references: [],
|
||||
type: 'so_type',
|
||||
});
|
||||
|
||||
await settingsSetup(soClientMock);
|
||||
|
||||
expect(soClientMock.create).not.toBeCalled();
|
||||
expect(soClientMock.update).toBeCalledWith('ingest_manager_settings', 'defaultsettings', {
|
||||
fleet_server_hosts: ['http://fleetserverupdated.fr:8220'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should update settings if there is no new fleet server hosts in the config', async () => {
|
||||
const soClientMock = savedObjectsClientMock.create();
|
||||
mockedAppContextService.getCloud.mockReturnValue({
|
||||
cloudId:
|
||||
'test:dGVzdC5mcjo5MjQzJGRhM2I2YjNkYWY5ZDRjODE4ZjI4ZmEzNDdjMzgzODViJDgxMmY4NWMxZjNjZTQ2YTliYjgxZjFjMWIxMzRjNmRl',
|
||||
isCloudEnabled: true,
|
||||
deploymentId: 'deployment-id-1',
|
||||
apm: {},
|
||||
});
|
||||
mockedAppContextService.getConfig.mockReturnValue({
|
||||
agents: {
|
||||
fleet_server: { hosts: ['http://fleetserverupdated.fr:8220'] },
|
||||
},
|
||||
} as any);
|
||||
|
||||
soClientMock.find.mockResolvedValue({
|
||||
total: 1,
|
||||
page: 0,
|
||||
per_page: 10,
|
||||
saved_objects: [
|
||||
{
|
||||
id: 'defaultsettings',
|
||||
attributes: {
|
||||
fleet_server_hosts: ['http://fleetserverupdated.fr:8220'],
|
||||
},
|
||||
type: 'so_type',
|
||||
references: [],
|
||||
score: 0,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
soClientMock.update.mockResolvedValue({
|
||||
id: 'updated',
|
||||
attributes: {},
|
||||
references: [],
|
||||
type: 'so_type',
|
||||
});
|
||||
|
||||
soClientMock.create.mockResolvedValue({
|
||||
id: 'created',
|
||||
attributes: {},
|
||||
references: [],
|
||||
type: 'so_type',
|
||||
});
|
||||
|
||||
await settingsSetup(soClientMock);
|
||||
|
||||
expect(soClientMock.create).not.toBeCalled();
|
||||
expect(soClientMock.update).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('should not update settings with cloud settings if there is settings with fleet server hosts and default fleet server hosts', async () => {
|
||||
const soClientMock = savedObjectsClientMock.create();
|
||||
mockedAppContextService.getCloud.mockReturnValue({
|
||||
cloudId:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import Boom from '@hapi/boom';
|
||||
import { isEqual } from 'lodash';
|
||||
import type { SavedObjectsClientContract } from '@kbn/core/server';
|
||||
|
||||
import {
|
||||
|
@ -31,20 +32,28 @@ export async function getSettings(soClient: SavedObjectsClientContract): Promise
|
|||
id: settingsSo.id,
|
||||
...settingsSo.attributes,
|
||||
fleet_server_hosts: settingsSo.attributes.fleet_server_hosts || [],
|
||||
preconfigured_fields: getConfigFleetServerHosts() ? ['fleet_server_hosts'] : [],
|
||||
};
|
||||
}
|
||||
|
||||
export async function settingsSetup(soClient: SavedObjectsClientContract) {
|
||||
try {
|
||||
const settings = await getSettings(soClient);
|
||||
const defaultSettings = createDefaultSettings();
|
||||
|
||||
const fleetServerHostsIsPreconfigured = getConfigFleetServerHosts()?.length ?? 0 > 0;
|
||||
|
||||
const fleetServerHostsShouldBeUpdated =
|
||||
!settings.fleet_server_hosts ||
|
||||
settings.fleet_server_hosts.length === 0 ||
|
||||
(fleetServerHostsIsPreconfigured &&
|
||||
!isEqual(settings.fleet_server_hosts, defaultSettings.fleet_server_hosts));
|
||||
|
||||
// Migration for < 7.13 Kibana
|
||||
if (!settings.fleet_server_hosts || settings.fleet_server_hosts.length === 0) {
|
||||
const defaultSettings = createDefaultSettings();
|
||||
if (defaultSettings.fleet_server_hosts.length > 0) {
|
||||
return saveSettings(soClient, {
|
||||
fleet_server_hosts: defaultSettings.fleet_server_hosts,
|
||||
});
|
||||
}
|
||||
if (defaultSettings.fleet_server_hosts.length > 0 && fleetServerHostsShouldBeUpdated) {
|
||||
return saveSettings(soClient, {
|
||||
fleet_server_hosts: defaultSettings.fleet_server_hosts,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (e.isBoom && e.output.statusCode === 404) {
|
||||
|
@ -103,8 +112,15 @@ export async function saveSettings(
|
|||
}
|
||||
}
|
||||
|
||||
function getConfigFleetServerHosts() {
|
||||
const config = appContextService.getConfig();
|
||||
return config?.agents?.fleet_server?.hosts && config.agents.fleet_server.hosts.length > 0
|
||||
? config?.agents?.fleet_server?.hosts
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function createDefaultSettings(): BaseSettings {
|
||||
const configFleetServerHosts = appContextService.getConfig()?.agents?.fleet_server?.hosts;
|
||||
const configFleetServerHosts = getConfigFleetServerHosts();
|
||||
const cloudFleetServerHosts = getCloudFleetServersHosts();
|
||||
|
||||
const fleetServerHosts = configFleetServerHosts ?? cloudFleetServerHosts ?? [];
|
||||
|
|
|
@ -23,7 +23,10 @@ import { SO_SEARCH_LIMIT } from '../constants';
|
|||
import { appContextService } from './app_context';
|
||||
import { agentPolicyService } from './agent_policy';
|
||||
import { ensurePreconfiguredPackagesAndPolicies } from './preconfiguration';
|
||||
import { ensurePreconfiguredOutputs } from './preconfiguration/outputs';
|
||||
import {
|
||||
ensurePreconfiguredOutputs,
|
||||
getPreconfiguredOutputFromConfig,
|
||||
} from './preconfiguration/outputs';
|
||||
import { outputService } from './output';
|
||||
import { downloadSourceService } from './download_source';
|
||||
|
||||
|
@ -60,18 +63,20 @@ async function createSetupSideEffects(
|
|||
const logger = appContextService.getLogger();
|
||||
logger.info('Beginning fleet setup');
|
||||
|
||||
const {
|
||||
agentPolicies: policiesOrUndefined,
|
||||
packages: packagesOrUndefined,
|
||||
outputs: outputsOrUndefined,
|
||||
} = appContextService.getConfig() ?? {};
|
||||
const { agentPolicies: policiesOrUndefined, packages: packagesOrUndefined } =
|
||||
appContextService.getConfig() ?? {};
|
||||
|
||||
const policies = policiesOrUndefined ?? [];
|
||||
let packages = packagesOrUndefined ?? [];
|
||||
|
||||
logger.debug('Setting up Fleet outputs');
|
||||
|
||||
await Promise.all([
|
||||
ensurePreconfiguredOutputs(soClient, esClient, outputsOrUndefined ?? []),
|
||||
ensurePreconfiguredOutputs(
|
||||
soClient,
|
||||
esClient,
|
||||
getPreconfiguredOutputFromConfig(appContextService.getConfig())
|
||||
),
|
||||
settingsService.settingsSetup(soClient),
|
||||
]);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue