[Fleet] Improve config output validation for default output (#167085)

This commit is contained in:
Nicolas Chaulet 2023-09-25 15:01:56 -04:00 committed by GitHub
parent da2695fef3
commit f73f70ccdd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 217 additions and 129 deletions

View file

@ -0,0 +1,73 @@
/*
* 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 { config } from './config';
describe('Config schema', () => {
it('should not allow to specify both default output in xpack.fleet.ouputs and xpack.fleet.agents.elasticsearch.hosts ', () => {
expect(() => {
config.schema.validate({
agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } },
outputs: [
{
id: 'test',
name: 'test output',
type: 'elasticsearch',
hosts: ['http://elasticsearch:9200'],
is_default: true,
is_default_monitoring: true,
},
],
});
}).toThrowErrorMatchingInlineSnapshot(
`"xpack.fleet.agents.elasticsearch.hosts should not be used when defining default outputs in xpack.fleet.outputs, please remove it."`
);
});
it('should allow to specify both outputs in xpack.fleet.ouputs without default outputs and xpack.fleet.agents.elasticsearch.hosts ', () => {
expect(() => {
config.schema.validate({
agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } },
outputs: [
{
id: 'test',
name: 'test output',
type: 'elasticsearch',
hosts: ['http://elasticsearch:9200'],
is_default: false,
is_default_monitoring: false,
},
],
});
}).not.toThrow();
});
it('should allow to specify default outputs only xpack.fleet.ouputs ', () => {
expect(() => {
config.schema.validate({
outputs: [
{
id: 'test',
name: 'test output',
type: 'elasticsearch',
hosts: ['http://elasticsearch:9200'],
is_default: true,
is_default_monitoring: true,
},
],
});
}).not.toThrow();
});
it('should allow to specify default output only in xpack.fleet.agents.elasticsearch.hosts ', () => {
expect(() => {
config.schema.validate({
agents: { elasticsearch: { hosts: ['https://elasticsearch:9200'] } },
});
}).not.toThrow();
});
});

View file

@ -111,142 +111,157 @@ export const config: PluginConfigDescriptor = {
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({
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'] }))),
})
),
}),
packages: PreconfiguredPackagesSchema,
agentPolicies: PreconfiguredAgentPoliciesSchema,
outputs: PreconfiguredOutputsSchema,
fleetServerHosts: PreconfiguredFleetServerHostsSchema,
proxies: PreconfiguredFleetProxiesSchema,
agentIdVerificationEnabled: schema.boolean({ defaultValue: true }),
setup: schema.maybe(
schema.object({
agentPolicySchemaUpgradeBatchSize: schema.maybe(schema.number()),
})
),
developer: schema.object({
maxAgentPoliciesWithInactivityTimeout: schema.maybe(schema.number()),
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(
', '
)}`;
}
}
},
}),
internal: schema.maybe(
schema.object({
disableILMPolicies: schema.boolean({
defaultValue: false,
ca_sha256: schema.maybe(schema.string()),
}),
disableProxies: schema.boolean({
defaultValue: false,
}),
fleetServerStandalone: schema.boolean({
defaultValue: false,
}),
onlyAllowAgentUpgradeToKnownVersions: schema.boolean({
defaultValue: false,
}),
activeAgentsSoftLimit: schema.maybe(
schema.number({
min: 0,
fleet_server: schema.maybe(
schema.object({
hosts: schema.maybe(schema.arrayOf(schema.uri({ scheme: ['http', 'https'] }))),
})
),
registry: schema.object(
{
kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }),
spec: schema.object(
{
min: schema.maybe(schema.string()),
max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }),
},
{
defaultValue: {
}),
packages: PreconfiguredPackagesSchema,
agentPolicies: PreconfiguredAgentPoliciesSchema,
outputs: PreconfiguredOutputsSchema,
fleetServerHosts: PreconfiguredFleetServerHostsSchema,
proxies: PreconfiguredFleetProxiesSchema,
agentIdVerificationEnabled: schema.boolean({ defaultValue: true }),
setup: schema.maybe(
schema.object({
agentPolicySchemaUpgradeBatchSize: schema.maybe(schema.number()),
})
),
developer: schema.object({
maxAgentPoliciesWithInactivityTimeout: schema.maybe(schema.number()),
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(
', '
)}`;
}
}
},
}),
internal: schema.maybe(
schema.object({
disableILMPolicies: schema.boolean({
defaultValue: false,
}),
disableProxies: schema.boolean({
defaultValue: false,
}),
fleetServerStandalone: schema.boolean({
defaultValue: false,
}),
onlyAllowAgentUpgradeToKnownVersions: schema.boolean({
defaultValue: false,
}),
activeAgentsSoftLimit: schema.maybe(
schema.number({
min: 0,
})
),
registry: schema.object(
{
kibanaVersionCheckEnabled: schema.boolean({ defaultValue: true }),
spec: schema.object(
{
min: schema.maybe(schema.string()),
max: schema.string({ defaultValue: REGISTRY_SPEC_MAX_VERSION }),
},
{
defaultValue: {
max: REGISTRY_SPEC_MAX_VERSION,
},
}
),
capabilities: schema.arrayOf(
schema.oneOf([
// See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113
schema.literal('apm'),
schema.literal('enterprise_search'),
schema.literal('observability'),
schema.literal('security'),
schema.literal('serverless_search'),
schema.literal('uptime'),
]),
{ defaultValue: [] }
),
},
{
defaultValue: {
kibanaVersionCheckEnabled: true,
capabilities: [],
spec: {
max: REGISTRY_SPEC_MAX_VERSION,
},
}
),
capabilities: schema.arrayOf(
schema.oneOf([
// See package-spec for the list of available capiblities https://github.com/elastic/package-spec/blob/dcc37b652690f8a2bca9cf8a12fc28fd015730a0/spec/integration/manifest.spec.yml#L113
schema.literal('apm'),
schema.literal('enterprise_search'),
schema.literal('observability'),
schema.literal('security'),
schema.literal('serverless_search'),
schema.literal('uptime'),
]),
{ defaultValue: [] }
),
},
{
defaultValue: {
kibanaVersionCheckEnabled: true,
capabilities: [],
spec: {
max: REGISTRY_SPEC_MAX_VERSION,
},
},
}
),
})
),
enabled: schema.boolean({ defaultValue: true }),
/**
* The max size of the artifacts encoded_size sum in a batch when more than one (there is at least one artifact in a batch).
* @example
* artifact1.encoded_size = 400
* artifact2.encoded_size = 600
* artifact3.encoded_size = 1_200
* and
* createArtifactsBulkBatchSize: 1_000
* then
* batch1 = [artifact1, artifact2]
* batch2 = [artifact3]
*/
createArtifactsBulkBatchSize: schema.maybe(
schema.number({
defaultValue: BULK_CREATE_MAX_ARTIFACTS_BYTES,
max: 4_000_000,
min: 400,
})
),
}),
}
),
})
),
enabled: schema.boolean({ defaultValue: true }),
/**
* The max size of the artifacts encoded_size sum in a batch when more than one (there is at least one artifact in a batch).
* @example
* artifact1.encoded_size = 400
* artifact2.encoded_size = 600
* artifact3.encoded_size = 1_200
* and
* createArtifactsBulkBatchSize: 1_000
* then
* batch1 = [artifact1, artifact2]
* batch2 = [artifact3]
*/
createArtifactsBulkBatchSize: schema.maybe(
schema.number({
defaultValue: BULK_CREATE_MAX_ARTIFACTS_BYTES,
max: 4_000_000,
min: 400,
})
),
},
{
validate: (configToValidate) => {
const hasDefaultPreconfiguredOuputs = configToValidate.outputs.some(
(o) => o.is_default || o.is_default_monitoring
);
const hasDefaulElasticsearchOutputDefined =
configToValidate.agents?.elasticsearch?.hosts?.length ?? 0 > 0;
if (hasDefaulElasticsearchOutputDefined && hasDefaultPreconfiguredOuputs) {
return 'xpack.fleet.agents.elasticsearch.hosts should not be used when defining default outputs in xpack.fleet.outputs, please remove it.';
}
},
}
),
};
export type FleetConfigType = TypeOf<typeof config.schema>;