diff --git a/.eslintignore b/.eslintignore index 4913192e81c1d9..53b3d807204390 100644 --- a/.eslintignore +++ b/.eslintignore @@ -25,7 +25,7 @@ target /src/plugins/vis_type_timelion/public/_generated_/** /src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.* /x-pack/legacy/plugins/**/__tests__/fixtures/** -/x-pack/legacy/plugins/apm/e2e/cypress/**/snapshots.js +/x-pack/plugins/apm/e2e/cypress/**/snapshots.js /x-pack/legacy/plugins/canvas/canvas_plugin /x-pack/legacy/plugins/canvas/canvas_plugin_src/lib/flot-charts /x-pack/legacy/plugins/canvas/shareable_runtime/build diff --git a/.eslintrc.js b/.eslintrc.js index 081eb049c28b70..ae6671139c8b3b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -310,7 +310,7 @@ module.exports = { { files: [ 'x-pack/test/functional/apps/**/*.js', - 'x-pack/legacy/plugins/apm/**/*.js', + 'x-pack/plugins/apm/**/*.js', 'test/*/config.ts', 'test/*/config_open.ts', 'test/*/{tests,test_suites,apis,apps}/**/*', @@ -397,7 +397,7 @@ module.exports = { 'x-pack/**/*.test.js', 'x-pack/test_utils/**/*', 'x-pack/gulpfile.js', - 'x-pack/legacy/plugins/apm/public/utils/testHelpers.js', + 'x-pack/plugins/apm/public/utils/testHelpers.js', ], rules: { 'import/no-extraneous-dependencies': [ @@ -523,7 +523,7 @@ module.exports = { * APM overrides */ { - files: ['x-pack/legacy/plugins/apm/**/*.js'], + files: ['x-pack/plugins/apm/**/*.js'], rules: { 'no-unused-vars': ['error', { ignoreRestSiblings: true }], 'no-console': ['warn', { allow: ['error'] }], @@ -531,7 +531,7 @@ module.exports = { }, { plugins: ['react-hooks'], - files: ['x-pack/legacy/plugins/apm/**/*.{ts,tsx}'], + files: ['x-pack/plugins/apm/**/*.{ts,tsx}'], rules: { 'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks 'react-hooks/exhaustive-deps': ['error', { additionalHooks: '^useFetcher$' }], diff --git a/.gitignore b/.gitignore index bd7a954f950e9f..13c7cd5fb2769d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,6 @@ package-lock.json *.sublime-* npm-debug.log* .tern-project -x-pack/legacy/plugins/apm/tsconfig.json +x-pack/plugins/apm/tsconfig.json apm.tsconfig.json -/x-pack/legacy/plugins/apm/e2e/snapshots.js +/x-pack/plugins/apm/e2e/snapshots.js diff --git a/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.test.ts b/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.test.ts new file mode 100644 index 00000000000000..dcec54f47440ae --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { decodeCloudId } from './decode_cloud_id'; + +describe('Ingest Manager - decodeCloudId', () => { + it('parses various CloudID formats', () => { + const tests = [ + { + cloudID: + 'staging:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==', + expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443', + expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443', + }, + { + cloudID: + 'dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==', + expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443', + expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443', + }, + { + cloudID: + ':dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==', + expectedEsURL: 'https://cec6f261a74bf24ce33bb8811b84294f.us-east-1.aws.found.io:443', + expectedKibanaURL: 'https://c6c2ca6d042249af0cc7d7a9e9625743.us-east-1.aws.found.io:443', + }, + { + cloudID: + 'gcp-cluster:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJDhhMDI4M2FmMDQxZjE5NWY3NzI5YmMwNGM2NmEwZmNlJDBjZDVjZDU2OGVlYmU1M2M4OWViN2NhZTViYWM4YjM3', + expectedEsURL: 'https://8a0283af041f195f7729bc04c66a0fce.us-central1.gcp.cloud.es.io:443', + expectedKibanaURL: + 'https://0cd5cd568eebe53c89eb7cae5bac8b37.us-central1.gcp.cloud.es.io:443', + }, + { + cloudID: + 'custom-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA=', + expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243', + expectedKibanaURL: + 'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9243', + }, + { + cloudID: + 'different-es-kb-port:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2OjkyNDMkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==', + expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243', + expectedKibanaURL: + 'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244', + }, + { + cloudID: + 'only-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwOjkyNDQ=', + expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443', + expectedKibanaURL: + 'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244', + }, + { + cloudID: + 'host-and-kb-set:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvOjkyNDMkYWMzMWViYjkwMjQxNzczMTU3MDQzYzM0ZmQyNmZkNDYkYTRjMDYyMzBlNDhjOGZjZTdiZTg4YTA3NGEzYmIzZTA6OTI0NA==', + expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:9243', + expectedKibanaURL: + 'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:9244', + }, + { + cloudID: + 'extra-items:dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJGFjMzFlYmI5MDI0MTc3MzE1NzA0M2MzNGZkMjZmZDQ2JGE0YzA2MjMwZTQ4YzhmY2U3YmU4OGEwNzRhM2JiM2UwJGFub3RoZXJpZCRhbmRhbm90aGVy', + expectedEsURL: 'https://ac31ebb90241773157043c34fd26fd46.us-central1.gcp.cloud.es.io:443', + expectedKibanaURL: + 'https://a4c06230e48c8fce7be88a074a3bb3e0.us-central1.gcp.cloud.es.io:443', + }, + ]; + + for (const test of tests) { + const decoded = decodeCloudId(test.cloudID); + expect(decoded).toBeTruthy(); + expect(decoded?.elasticsearchUrl === test.expectedEsURL).toBe(true); + expect(decoded?.kibanaUrl === test.expectedKibanaURL).toBe(true); + } + }); + + it('returns undefined for invalid formats', () => { + const tests = [ + { + cloudID: + 'staging:garbagedXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRjZWM2ZjI2MWE3NGJmMjRjZTMzYmI4ODExYjg0Mjk0ZiRjNmMyY2E2ZDA0MjI0OWFmMGNjN2Q3YTllOTYyNTc0Mw==', + errorMsg: 'base64 decoding failed', + }, + { + cloudID: 'dXMtY2VudHJhbDEuZ2NwLmNsb3VkLmVzLmlvJDhhMDI4M2FmMDQxZjE5NWY3NzI5YmMwNGM2NmEwZg==', + errorMsg: 'Expected at least 3 parts', + }, + ]; + + for (const test of tests) { + const decoded = decodeCloudId(test.cloudID); + expect(decoded).toBe(undefined); + // decodeCloudId currently only logs; not throws errors + } + }); +}); diff --git a/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.ts b/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.ts new file mode 100644 index 00000000000000..67389e554ed243 --- /dev/null +++ b/x-pack/plugins/ingest_manager/common/services/decode_cloud_id.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// decodeCloudId decodes the c.id into c.esURL and c.kibURL +export function decodeCloudId( + cid: string +): + | { + host: string; + defaultPort: string; + elasticsearchUrl: string; + kibanaUrl: string; + } + | undefined { + // 1. Ignore anything before `:`. + const id = cid.split(':').pop(); + if (!id) { + // throw new Error(`Unable to decode ${id}`); + // eslint-disable-next-line no-console + console.debug(`Unable to decode ${id}`); + return; + } + + // 2. base64 decode + let decoded: string | undefined; + try { + decoded = Buffer.from(id, 'base64').toString('utf8'); + } catch { + // throw new Error(`base64 decoding failed on ${id}`); + // eslint-disable-next-line no-console + console.debug(`base64 decoding failed on ${id}`); + return; + } + + // 3. separate based on `$` + const words = decoded.split('$'); + if (words.length < 3) { + // throw new Error(`Expected at least 3 parts in ${decoded}`); + // eslint-disable-next-line no-console + console.debug(`Expected at least 3 parts in ${decoded}`); + return; + } + // 4. extract port from the ES and Kibana host + const [host, defaultPort] = extractPortFromName(words[0]); + const [esId, esPort] = extractPortFromName(words[1], defaultPort); + const [kbId, kbPort] = extractPortFromName(words[2], defaultPort); + // 5. form the URLs + const esUrl = `https://${esId}.${host}:${esPort}`; + const kbUrl = `https://${kbId}.${host}:${kbPort}`; + return { + host, + defaultPort, + elasticsearchUrl: esUrl, + kibanaUrl: kbUrl, + }; +} +// extractPortFromName takes a string in the form `id:port` and returns the +// Id and the port. If there's no `:`, the default port is returned +function extractPortFromName(word: string, defaultPort = '443') { + const [host, port = defaultPort] = word.split(':'); + return [host, port]; +} diff --git a/x-pack/plugins/ingest_manager/common/services/index.ts b/x-pack/plugins/ingest_manager/common/services/index.ts index 8e704bb717257d..91dbbdd515c3e8 100644 --- a/x-pack/plugins/ingest_manager/common/services/index.ts +++ b/x-pack/plugins/ingest_manager/common/services/index.ts @@ -9,3 +9,4 @@ export * from './routes'; export { packageToConfigDatasourceInputs, packageToConfigDatasource } from './package_to_config'; export { storedDatasourceToAgentDatasource } from './datasource_to_agent_datasource'; export { AgentStatusKueryHelper }; +export { decodeCloudId } from './decode_cloud_id'; diff --git a/x-pack/plugins/ingest_manager/common/types/index.ts b/x-pack/plugins/ingest_manager/common/types/index.ts index b357d0c2d75f48..800e77a6a27427 100644 --- a/x-pack/plugins/ingest_manager/common/types/index.ts +++ b/x-pack/plugins/ingest_manager/common/types/index.ts @@ -15,7 +15,6 @@ export interface IngestManagerConfigType { fleet: { enabled: boolean; tlsCheckDisabled: boolean; - defaultOutputHost: string; kibana: { host?: string; ca_sha256?: string; diff --git a/x-pack/plugins/ingest_manager/server/index.ts b/x-pack/plugins/ingest_manager/server/index.ts index 6096af8d808010..84408b60d3edb1 100644 --- a/x-pack/plugins/ingest_manager/server/index.ts +++ b/x-pack/plugins/ingest_manager/server/index.ts @@ -32,7 +32,7 @@ export const config = { ca_sha256: schema.maybe(schema.string()), }), elasticsearch: schema.object({ - host: schema.string({ defaultValue: 'http://localhost:9200' }), + host: schema.maybe(schema.string()), ca_sha256: schema.maybe(schema.string()), }), }), diff --git a/x-pack/plugins/ingest_manager/server/plugin.ts b/x-pack/plugins/ingest_manager/server/plugin.ts index b944a50fc2193c..d70e136d67ef5d 100644 --- a/x-pack/plugins/ingest_manager/server/plugin.ts +++ b/x-pack/plugins/ingest_manager/server/plugin.ts @@ -165,6 +165,7 @@ export class IngestManagerPlugin const config = await this.config$.pipe(first()).toPromise(); // Register routes + registerSetupRoutes(router, config); registerAgentConfigRoutes(router); registerDatasourceRoutes(router); registerOutputRoutes(router); @@ -177,7 +178,6 @@ export class IngestManagerPlugin } if (config.fleet.enabled) { - registerSetupRoutes(router); registerAgentRoutes(router); registerEnrollmentApiKeyRoutes(router); registerInstallScriptRoutes({ diff --git a/x-pack/plugins/ingest_manager/server/routes/setup/index.ts b/x-pack/plugins/ingest_manager/server/routes/setup/index.ts index f408d875a80b3a..43dcf47d26c182 100644 --- a/x-pack/plugins/ingest_manager/server/routes/setup/index.ts +++ b/x-pack/plugins/ingest_manager/server/routes/setup/index.ts @@ -6,13 +6,14 @@ import { IRouter } from 'src/core/server'; import { PLUGIN_ID, FLEET_SETUP_API_ROUTES, SETUP_API_ROUTE } from '../../constants'; +import { IngestManagerConfigType } from '../../../common'; import { getFleetStatusHandler, createFleetSetupHandler, ingestManagerSetupHandler, } from './handlers'; -export const registerRoutes = (router: IRouter) => { +export const registerRoutes = (router: IRouter, config: IngestManagerConfigType) => { // Ingest manager setup router.post( { @@ -24,6 +25,11 @@ export const registerRoutes = (router: IRouter) => { }, ingestManagerSetupHandler ); + + if (!config.fleet.enabled) { + return; + } + // Get Fleet setup router.get( { diff --git a/x-pack/plugins/ingest_manager/server/services/output.ts b/x-pack/plugins/ingest_manager/server/services/output.ts index 3628c5bd9e1830..ce6f1f2e27130b 100644 --- a/x-pack/plugins/ingest_manager/server/services/output.ts +++ b/x-pack/plugins/ingest_manager/server/services/output.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract } from 'src/core/server'; import { NewOutput, Output } from '../types'; import { DEFAULT_OUTPUT, OUTPUT_SAVED_OBJECT_TYPE } from '../constants'; import { appContextService } from './app_context'; +import { decodeCloudId } from '../../common'; const SAVED_OBJECT_TYPE = OUTPUT_SAVED_OBJECT_TYPE; @@ -16,11 +17,17 @@ class OutputService { type: OUTPUT_SAVED_OBJECT_TYPE, filter: `${OUTPUT_SAVED_OBJECT_TYPE}.attributes.is_default:true`, }); + const cloud = appContextService.getCloud(); + const cloudId = cloud?.isCloudEnabled && cloud.cloudId; + const cloudUrl = cloudId && decodeCloudId(cloudId)?.elasticsearchUrl; + const flagsUrl = appContextService.getConfig()!.fleet.elasticsearch.host; + const defaultUrl = 'http://localhost:9200'; + const defaultOutputUrl = cloudUrl || flagsUrl || defaultUrl; if (!outputs.saved_objects.length) { const newDefaultOutput = { ...DEFAULT_OUTPUT, - hosts: [appContextService.getConfig()!.fleet.elasticsearch.host], + hosts: [defaultOutputUrl], ca_sha256: appContextService.getConfig()!.fleet.elasticsearch.ca_sha256, } as NewOutput; diff --git a/x-pack/plugins/ingest_manager/server/services/setup.ts b/x-pack/plugins/ingest_manager/server/services/setup.ts index 34ecfc26e0efdc..2861458fde9d79 100644 --- a/x-pack/plugins/ingest_manager/server/services/setup.ts +++ b/x-pack/plugins/ingest_manager/server/services/setup.ts @@ -19,6 +19,7 @@ import { Installation, Output, DEFAULT_AGENT_CONFIGS_PACKAGES, + decodeCloudId, } from '../../common'; import { getPackageInfo } from './epm/packages'; import { datasourceService } from './datasource'; @@ -45,7 +46,11 @@ export async function setupIngestManager( const serverInfo = http.getServerInfo(); const basePath = http.basePath; - const defaultKibanaUrl = url.format({ + const cloud = appContextService.getCloud(); + const cloudId = cloud?.isCloudEnabled && cloud.cloudId; + const cloudUrl = cloudId && decodeCloudId(cloudId)?.kibanaUrl; + const flagsUrl = appContextService.getConfig()?.fleet?.kibana?.host; + const defaultUrl = url.format({ protocol: serverInfo.protocol, hostname: serverInfo.host, port: serverInfo.port, @@ -55,7 +60,7 @@ export async function setupIngestManager( return settingsService.saveSettings(soClient, { agent_auto_upgrade: true, package_auto_upgrade: true, - kibana_url: appContextService.getConfig()?.fleet?.kibana?.host ?? defaultKibanaUrl, + kibana_url: cloudUrl || flagsUrl || defaultUrl, }); } diff --git a/x-pack/plugins/uptime/common/constants/settings_defaults.ts b/x-pack/plugins/uptime/common/constants/settings_defaults.ts index 5b5e8bacaecbbe..efa6ca79d33d8f 100644 --- a/x-pack/plugins/uptime/common/constants/settings_defaults.ts +++ b/x-pack/plugins/uptime/common/constants/settings_defaults.ts @@ -8,8 +8,6 @@ import { DynamicSettings } from '../runtime_types'; export const DYNAMIC_SETTINGS_DEFAULTS: DynamicSettings = { heartbeatIndices: 'heartbeat-7*', - certThresholds: { - expiration: 30, - age: 365, - }, + certAgeThreshold: 365, + certExpirationThreshold: 30, }; diff --git a/x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts b/x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts index da887cc5055c10..a0ec92f7d869b7 100644 --- a/x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts +++ b/x-pack/plugins/uptime/common/runtime_types/dynamic_settings.ts @@ -6,14 +6,10 @@ import * as t from 'io-ts'; -export const CertStateThresholdsType = t.type({ - age: t.number, - expiration: t.number, -}); - export const DynamicSettingsType = t.type({ heartbeatIndices: t.string, - certThresholds: CertStateThresholdsType, + certAgeThreshold: t.number, + certExpirationThreshold: t.number, }); export const DynamicSettingsSaveType = t.intersection([ @@ -27,4 +23,3 @@ export const DynamicSettingsSaveType = t.intersection([ export type DynamicSettings = t.TypeOf; export type DynamicSettingsSaveResponse = t.TypeOf; -export type CertStateThresholds = t.TypeOf; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_tls.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_tls.tsx index ab24d0fb5ee679..a2e1c1d43526c0 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_tls.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_tls.tsx @@ -18,8 +18,8 @@ export const AlertTls = () => { const { settings } = useSelector(selectDynamicSettings); return ( ); diff --git a/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap index 96d472c91680dc..36351da6f14c9d 100644 --- a/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/certificate_form.test.tsx.snap @@ -55,10 +55,8 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = fieldErrors={null} formFields={ Object { - "certThresholds": Object { - "age": 36, - "expiration": 7, - }, + "certAgeThreshold": 36, + "certExpirationThreshold": 7, "heartbeatIndices": "heartbeat-8*", } } diff --git a/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap index 3b0c6d99fd9f82..c5d077007e6502 100644 --- a/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/settings/__tests__/__snapshots__/indices_form.test.tsx.snap @@ -55,10 +55,8 @@ exports[`CertificateForm shallow renders expected elements for valid props 1`] = fieldErrors={null} formFields={ Object { - "certThresholds": Object { - "age": 36, - "expiration": 7, - }, + "certAgeThreshold": 36, + "certExpirationThreshold": 7, "heartbeatIndices": "heartbeat-8*", } } diff --git a/x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx index 3d4bd58aabe0f6..8e2348a60ddab4 100644 --- a/x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx +++ b/x-pack/plugins/uptime/public/components/settings/__tests__/certificate_form.test.tsx @@ -17,7 +17,8 @@ describe('CertificateForm', () => { onChange={jest.fn()} formFields={{ heartbeatIndices: 'heartbeat-8*', - certThresholds: { expiration: 7, age: 36 }, + certExpirationThreshold: 7, + certAgeThreshold: 36, }} fieldErrors={null} isDisabled={false} diff --git a/x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx b/x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx index 07a3bf81e39d83..68a0d96d491b64 100644 --- a/x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx +++ b/x-pack/plugins/uptime/public/components/settings/__tests__/indices_form.test.tsx @@ -17,7 +17,8 @@ describe('CertificateForm', () => { onChange={jest.fn()} formFields={{ heartbeatIndices: 'heartbeat-8*', - certThresholds: { expiration: 7, age: 36 }, + certAgeThreshold: 36, + certExpirationThreshold: 7, }} fieldErrors={null} isDisabled={false} diff --git a/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx b/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx index 209e38785e1651..06ce6b35997826 100644 --- a/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx +++ b/x-pack/plugins/uptime/public/components/settings/certificate_form.tsx @@ -17,16 +17,11 @@ import { EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import { CertStateThresholds } from '../../../common/runtime_types'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../common/constants'; +import { DynamicSettings } from '../../../common/runtime_types'; import { SettingsFormProps } from '../../pages/settings'; -interface ChangedValues { - heartbeatIndices?: string; - certThresholds?: Partial; -} - -export type OnFieldChangeType = (changedValues: ChangedValues) => void; +export type OnFieldChangeType = (changedValues: Partial) => void; export const CertificateExpirationForm: React.FC = ({ loading, @@ -70,9 +65,7 @@ export const CertificateExpirationForm: React.FC = ({ id="xpack.uptime.sourceConfiguration.expirationThresholdDefaultValue" defaultMessage="The default value is {defaultValue}" values={{ - defaultValue: ( - {DYNAMIC_SETTINGS_DEFAULTS.certThresholds.expiration} - ), + defaultValue: {DYNAMIC_SETTINGS_DEFAULTS.certExpirationThreshold}, }} /> } @@ -91,12 +84,10 @@ export const CertificateExpirationForm: React.FC = ({ fullWidth disabled={isDisabled} isLoading={loading} - value={formFields?.certThresholds?.expiration || ''} + value={formFields?.certExpirationThreshold ?? ''} onChange={e => onChange({ - certThresholds: { - expiration: Number(e.target.value), - }, + certExpirationThreshold: Number(e.target.value), }) } /> @@ -120,7 +111,7 @@ export const CertificateExpirationForm: React.FC = ({ id="xpack.uptime.sourceConfiguration.ageThresholdDefaultValue" defaultMessage="The default value is {defaultValue}" values={{ - defaultValue: {DYNAMIC_SETTINGS_DEFAULTS.certThresholds.age}, + defaultValue: {DYNAMIC_SETTINGS_DEFAULTS.certAgeThreshold}, }} /> } @@ -139,10 +130,10 @@ export const CertificateExpirationForm: React.FC = ({ fullWidth disabled={isDisabled} isLoading={loading} - value={formFields?.certThresholds?.age || ''} + value={formFields?.certAgeThreshold ?? ''} onChange={e => onChange({ - certThresholds: { age: Number(e.currentTarget.value) }, + certAgeThreshold: Number(e.currentTarget.value), }) } /> diff --git a/x-pack/plugins/uptime/public/hooks/use_cert_status.ts b/x-pack/plugins/uptime/public/hooks/use_cert_status.ts index cb54b05af9dd17..20c09e8fcc8d17 100644 --- a/x-pack/plugins/uptime/public/hooks/use_cert_status.ts +++ b/x-pack/plugins/uptime/public/hooks/use_cert_status.ts @@ -12,9 +12,9 @@ import { CERT_STATUS } from '../../common/constants'; export const useCertStatus = (expiryDate?: string, issueDate?: string) => { const dss = useSelector(selectDynamicSettings); - const expiryThreshold = dss.settings?.certThresholds?.expiration; + const expiryThreshold = dss.settings?.certExpirationThreshold; - const ageThreshold = dss.settings?.certThresholds?.age; + const ageThreshold = dss.settings?.certAgeThreshold; const certValidityDate = new Date(expiryDate ?? ''); diff --git a/x-pack/plugins/uptime/public/pages/settings.tsx b/x-pack/plugins/uptime/public/pages/settings.tsx index 549ebc8e751571..31831b25b3071d 100644 --- a/x-pack/plugins/uptime/public/pages/settings.tsx +++ b/x-pack/plugins/uptime/public/pages/settings.tsx @@ -52,10 +52,10 @@ export interface SettingsFormProps { const getFieldErrors = (formFields: DynamicSettings | null): SettingsPageFieldErrors | null => { if (formFields) { const blankStr = 'May not be blank'; - const { certThresholds: certificatesThresholds, heartbeatIndices } = formFields; + const { certAgeThreshold, certExpirationThreshold, heartbeatIndices } = formFields; const heartbeatIndErr = heartbeatIndices.match(/^\S+$/) ? '' : blankStr; - const expirationThresholdError = certificatesThresholds?.expiration ? null : blankStr; - const ageThresholdError = certificatesThresholds?.age ? null : blankStr; + const expirationThresholdError = certExpirationThreshold ? null : blankStr; + const ageThresholdError = certAgeThreshold ? null : blankStr; return { heartbeatIndices: heartbeatIndErr, certificatesThresholds: @@ -98,12 +98,8 @@ export const SettingsPage = () => { const onChangeFormField: OnFieldChangeType = changedField => { if (formFields) { setFormFields({ - heartbeatIndices: changedField.heartbeatIndices ?? formFields.heartbeatIndices, - certThresholds: Object.assign( - {}, - formFields.certThresholds, - changedField?.certThresholds ?? null - ), + ...formFields, + ...changedField, }); } }; diff --git a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts index 6991279271cf71..9f8c0a72f12625 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts @@ -87,10 +87,8 @@ describe('status check alert', () => { Object { "callES": [MockFunction], "dynamicSettings": Object { - "certThresholds": Object { - "age": 365, - "expiration": 30, - }, + "certAgeThreshold": 365, + "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-7*", }, "locations": Array [], @@ -134,10 +132,8 @@ describe('status check alert', () => { Object { "callES": [MockFunction], "dynamicSettings": Object { - "certThresholds": Object { - "age": 365, - "expiration": 30, - }, + "certAgeThreshold": 365, + "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-7*", }, "locations": Array [], diff --git a/x-pack/plugins/uptime/server/lib/alerts/tls.ts b/x-pack/plugins/uptime/server/lib/alerts/tls.ts index 518e3ed93b4249..5728db8bfcc8d7 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/tls.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/tls.ts @@ -114,10 +114,10 @@ export const tlsAlertFactory: UptimeAlertTypeFactory = (_server, libs) => ({ to: DEFAULT_TO, index: DEFAULT_INDEX, size: DEFAULT_SIZE, - notValidAfter: `now+${dynamicSettings.certThresholds?.expiration ?? - DYNAMIC_SETTINGS_DEFAULTS.certThresholds?.expiration}d`, - notValidBefore: `now-${dynamicSettings.certThresholds?.age ?? - DYNAMIC_SETTINGS_DEFAULTS.certThresholds?.age}d`, + notValidAfter: `now+${dynamicSettings?.certExpirationThreshold ?? + DYNAMIC_SETTINGS_DEFAULTS.certExpirationThreshold}d`, + notValidBefore: `now-${dynamicSettings?.certAgeThreshold ?? + DYNAMIC_SETTINGS_DEFAULTS.certAgeThreshold}d`, sortBy: 'common_name', direction: 'desc', }); @@ -127,14 +127,14 @@ export const tlsAlertFactory: UptimeAlertTypeFactory = (_server, libs) => ({ if (foundCerts) { const absoluteExpirationThreshold = moment() .add( - dynamicSettings.certThresholds?.expiration ?? - DYNAMIC_SETTINGS_DEFAULTS.certThresholds?.expiration, + dynamicSettings.certExpirationThreshold ?? + DYNAMIC_SETTINGS_DEFAULTS.certExpirationThreshold, 'd' ) .valueOf(); const absoluteAgeThreshold = moment() .subtract( - dynamicSettings.certThresholds?.age ?? DYNAMIC_SETTINGS_DEFAULTS.certThresholds?.age, + dynamicSettings.certAgeThreshold ?? DYNAMIC_SETTINGS_DEFAULTS.certAgeThreshold, 'd' ) .valueOf(); diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts index 4aec376ceadf02..689dce98859e15 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -92,7 +92,8 @@ describe('getCerts', () => { callES: mockCallES, dynamicSettings: { heartbeatIndices: 'heartbeat*', - certThresholds: DYNAMIC_SETTINGS_DEFAULTS.certThresholds, + certAgeThreshold: DYNAMIC_SETTINGS_DEFAULTS.certAgeThreshold, + certExpirationThreshold: DYNAMIC_SETTINGS_DEFAULTS.certExpirationThreshold, }, index: 1, from: 'now-2d', diff --git a/x-pack/plugins/uptime/server/lib/saved_objects.ts b/x-pack/plugins/uptime/server/lib/saved_objects.ts index 28b9eaad2cf6f0..5a61eb859c28b2 100644 --- a/x-pack/plugins/uptime/server/lib/saved_objects.ts +++ b/x-pack/plugins/uptime/server/lib/saved_objects.ts @@ -26,15 +26,11 @@ export const umDynamicSettings: SavedObjectsType = { heartbeatIndices: { type: 'keyword', }, - certThresholds: { - properties: { - expiration: { - type: 'long', - }, - age: { - type: 'long', - }, - }, + certAgeThreshold: { + type: 'long', + }, + certExpirationThreshold: { + type: 'long', }, }, }, diff --git a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts index 95caf50d1ca7a4..e4fb1fcfe6cd02 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/dynamic_settings.ts @@ -7,7 +7,10 @@ import expect from '@kbn/expect'; import { isRight } from 'fp-ts/lib/Either'; import { FtrProviderContext } from '../../../ftr_provider_context'; -import { DynamicSettingsType } from '../../../../../plugins/uptime/common/runtime_types'; +import { + DynamicSettingsType, + DynamicSettings, +} from '../../../../../plugins/uptime/common/runtime_types'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../plugins/uptime/common/constants'; export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -20,12 +23,10 @@ export default function({ getService }: FtrProviderContext) { }); it('can change the settings', async () => { - const newSettings = { + const newSettings: DynamicSettings = { heartbeatIndices: 'myIndex1*', - certThresholds: { - expiration: 5, - age: 15, - }, + certAgeThreshold: 15, + certExpirationThreshold: 5, }; const postResponse = await supertest .post(`/api/uptime/dynamic_settings`) diff --git a/x-pack/test/functional/apps/uptime/settings.ts b/x-pack/test/functional/apps/uptime/settings.ts index 7a813a5cdfb526..1286a9940c02ca 100644 --- a/x-pack/test/functional/apps/uptime/settings.ts +++ b/x-pack/test/functional/apps/uptime/settings.ts @@ -62,10 +62,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const newFieldValues: DynamicSettings = { heartbeatIndices: 'new*', - certThresholds: { - age: 365, - expiration: 30, - }, + certAgeThreshold: 365, + certExpirationThreshold: 30, }; await settings.changeHeartbeatIndicesInput(newFieldValues.heartbeatIndices); await settings.apply(); @@ -86,8 +84,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await settings.go(); - const newErrorThreshold = '5'; - await settings.changeErrorThresholdInput(newErrorThreshold); + const newExpirationThreshold = '5'; + await settings.changeErrorThresholdInput(newExpirationThreshold); await settings.apply(); await uptimePage.goToRoot(); @@ -95,16 +93,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certThresholds?.expiration).to.eql(newErrorThreshold); + expect(fields.certExpirationThreshold).to.eql(newExpirationThreshold); }); - it('changing certificate expiration warning threshold is reflected in settings page', async () => { + it('changing certificate expiration threshold is reflected in settings page', async () => { const settings = uptimeService.settings; await settings.go(); - const newWarningThreshold = '15'; - await settings.changeWarningThresholdInput(newWarningThreshold); + const newAgeThreshold = '15'; + await settings.changeWarningThresholdInput(newAgeThreshold); await settings.apply(); await uptimePage.goToRoot(); @@ -112,7 +110,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that the settings page shows the value we previously saved await settings.go(); const fields = await settings.loadFields(); - expect(fields.certThresholds?.age).to.eql(newWarningThreshold); + expect(fields.certAgeThreshold).to.eql(newAgeThreshold); }); }); }; diff --git a/x-pack/test/functional/services/uptime/settings.ts b/x-pack/test/functional/services/uptime/settings.ts index 96f5e45ce2ca47..50c5c7093f34c9 100644 --- a/x-pack/test/functional/services/uptime/settings.ts +++ b/x-pack/test/functional/services/uptime/settings.ts @@ -41,10 +41,8 @@ export function UptimeSettingsProvider({ getService }: FtrProviderContext) { return { heartbeatIndices, - certThresholds: { - age: parseInt(age, 10), - expiration: parseInt(expiration, 10), - }, + certAgeThreshold: parseInt(age, 10), + certExpirationThreshold: parseInt(expiration, 10), }; }, applyButtonIsDisabled: async () => {