From 3f3a132ef59e3faaba368e87fc77c44507fa6338 Mon Sep 17 00:00:00 2001 From: Kerry Gallagher Date: Wed, 22 Apr 2020 16:37:22 +0100 Subject: [PATCH 01/35] [Logs / Metrics UI] Switch to scopedHistory and enhance useLinkProps hook (#61667) (#64190) --- .../plugins/infra/public/apps/start_app.tsx | 10 ++- .../source_configuration_settings.tsx | 13 ++-- .../public/hooks/use_link_props.test.tsx | 24 +++--- .../infra/public/hooks/use_link_props.tsx | 78 +++++++++---------- .../infra/public/utils/history_context.ts | 4 +- .../navigation_warning_prompt/context.tsx | 31 ++++++++ .../utils/navigation_warning_prompt/index.ts | 8 ++ .../navigation_warning_prompt/prompt.tsx | 25 ++++++ 8 files changed, 126 insertions(+), 67 deletions(-) create mode 100644 x-pack/plugins/infra/public/utils/navigation_warning_prompt/context.tsx create mode 100644 x-pack/plugins/infra/public/utils/navigation_warning_prompt/index.ts create mode 100644 x-pack/plugins/infra/public/utils/navigation_warning_prompt/prompt.tsx diff --git a/x-pack/plugins/infra/public/apps/start_app.tsx b/x-pack/plugins/infra/public/apps/start_app.tsx index ebf9562c38d7a..4c213700b62e6 100644 --- a/x-pack/plugins/infra/public/apps/start_app.tsx +++ b/x-pack/plugins/infra/public/apps/start_app.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createBrowserHistory } from 'history'; import React from 'react'; import ReactDOM from 'react-dom'; import { ApolloProvider } from 'react-apollo'; @@ -25,6 +24,7 @@ import { AppRouter } from '../routers'; import { TriggersAndActionsUIPublicPluginSetup } from '../../../triggers_actions_ui/public'; import { TriggersActionsProvider } from '../utils/triggers_actions_context'; import '../index.scss'; +import { NavigationWarningPromptProvider } from '../utils/navigation_warning_prompt'; export const CONTAINER_CLASSNAME = 'infra-container-element'; @@ -36,8 +36,8 @@ export async function startApp( Router: AppRouter, triggersActionsUI: TriggersAndActionsUIPublicPluginSetup ) { - const { element, appBasePath } = params; - const history = createBrowserHistory({ basename: appBasePath }); + const { element, history } = params; + const InfraPluginRoot: React.FunctionComponent = () => { const [darkMode] = useUiSetting$('theme:darkMode'); @@ -49,7 +49,9 @@ export async function startApp( - + + + diff --git a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx index 36645fa3f1f35..7f248cd103003 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/source_configuration_settings.tsx @@ -17,7 +17,6 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useCallback, useContext, useMemo } from 'react'; -import { Prompt } from 'react-router-dom'; import { Source } from '../../containers/source'; import { FieldsConfigurationPanel } from './fields_configuration_panel'; @@ -26,6 +25,7 @@ import { NameConfigurationPanel } from './name_configuration_panel'; import { LogColumnsConfigurationPanel } from './log_columns_configuration_panel'; import { useSourceConfigurationFormState } from './source_configuration_form_state'; import { SourceLoadingPage } from '../source_loading_page'; +import { Prompt } from '../../utils/navigation_warning_prompt'; interface SourceConfigurationSettingsProps { shouldAllowEdit: boolean; @@ -100,10 +100,13 @@ export const SourceConfigurationSettings = ({ data-test-subj="sourceConfigurationContent" > { const INTERNAL_APP = 'metrics'; -// Note: Memory history doesn't support basename, -// we'll work around this by re-assigning 'createHref' so that -// it includes a basename, this then acts as our browserHistory instance would. const history = createMemoryHistory(); -const originalCreateHref = history.createHref; -history.createHref = (location: LocationDescriptorObject): string => { - return `${PREFIX}${INTERNAL_APP}${originalCreateHref.call(history, location)}`; -}; +history.push(`${PREFIX}${INTERNAL_APP}`); +const scopedHistory = new ScopedHistory(history, `${PREFIX}${INTERNAL_APP}`); const ProviderWrapper: React.FC = ({ children }) => { return ( - + {children}; ); @@ -111,7 +107,7 @@ describe('useLinkProps hook', () => { pathname: '/', }); expect(result.current.href).toBe('/test-basepath/s/test-space/app/ml/'); - expect(result.current.onClick).not.toBeDefined(); + expect(result.current.onClick).toBeDefined(); }); it('Provides the correct props with pathname options', () => { @@ -127,7 +123,7 @@ describe('useLinkProps hook', () => { expect(result.current.href).toBe( '/test-basepath/s/test-space/app/ml/explorer?type=host&id=some-id&count=12345' ); - expect(result.current.onClick).not.toBeDefined(); + expect(result.current.onClick).toBeDefined(); }); it('Provides the correct props with hash options', () => { @@ -143,7 +139,7 @@ describe('useLinkProps hook', () => { expect(result.current.href).toBe( '/test-basepath/s/test-space/app/ml#/explorer?type=host&id=some-id&count=12345' ); - expect(result.current.onClick).not.toBeDefined(); + expect(result.current.onClick).toBeDefined(); }); it('Provides the correct props with more complex encoding', () => { @@ -161,7 +157,7 @@ describe('useLinkProps hook', () => { expect(result.current.href).toBe( '/test-basepath/s/test-space/app/ml#/explorer?type=host%20%2B%20host&name=this%20name%20has%20spaces%20and%20**%20and%20%25&id=some-id&count=12345&animals=dog,cat,bear' ); - expect(result.current.onClick).not.toBeDefined(); + expect(result.current.onClick).toBeDefined(); }); it('Provides the correct props with a consumer using Rison encoding for search', () => { @@ -180,7 +176,7 @@ describe('useLinkProps hook', () => { expect(result.current.href).toBe( '/test-basepath/s/test-space/app/rison-app#rison-route?type=host%20%2B%20host&state=(refreshInterval:(pause:!t,value:0),time:(from:12345,to:54321))' ); - expect(result.current.onClick).not.toBeDefined(); + expect(result.current.onClick).toBeDefined(); }); }); }); diff --git a/x-pack/plugins/infra/public/hooks/use_link_props.tsx b/x-pack/plugins/infra/public/hooks/use_link_props.tsx index e60ab32046832..8c522bb7fa764 100644 --- a/x-pack/plugins/infra/public/hooks/use_link_props.tsx +++ b/x-pack/plugins/infra/public/hooks/use_link_props.tsx @@ -9,7 +9,8 @@ import { stringify } from 'query-string'; import url from 'url'; import { url as urlUtils } from '../../../../../src/plugins/kibana_utils/public'; import { usePrefixPathWithBasepath } from './use_prefix_path_with_basepath'; -import { useHistory } from '../utils/history_context'; +import { useKibana } from '../../../../../src/plugins/kibana_react/public'; +import { useNavigationWarningPrompt } from '../utils/navigation_warning_prompt'; type Search = Record; @@ -28,31 +29,26 @@ interface LinkProps { export const useLinkProps = ({ app, pathname, hash, search }: LinkDescriptor): LinkProps => { validateParams({ app, pathname, hash, search }); - const history = useHistory(); + const { prompt } = useNavigationWarningPrompt(); const prefixer = usePrefixPathWithBasepath(); + const navigateToApp = useKibana().services.application?.navigateToApp; const encodedSearch = useMemo(() => { return search ? encodeSearch(search) : undefined; }, [search]); - const internalLinkResult = useMemo(() => { - // When the logs / metrics apps are first mounted a history instance is setup with a 'basename' equal to the - // 'appBasePath' received from Core's 'AppMountParams', e.g. /BASE_PATH/s/SPACE_ID/app/APP_ID. With internal - // linking we are using 'createHref' and 'push' on top of this history instance. So a pathname of /inventory used within - // the metrics app will ultimatey end up as /BASE_PATH/s/SPACE_ID/app/metrics/inventory. React-router responds to this - // as it is instantiated with the same history instance. - return history?.createHref({ - pathname: pathname ? formatPathname(pathname) : undefined, - search: encodedSearch, - }); - }, [history, pathname, encodedSearch]); - - const externalLinkResult = useMemo(() => { + const mergedHash = useMemo(() => { // The URI spec defines that the query should appear before the fragment // https://tools.ietf.org/html/rfc3986#section-3 (e.g. url.format()). However, in Kibana, apps that use // hash based routing expect the query to be part of the hash. This will handle that. - const mergedHash = hash && encodedSearch ? `${hash}?${encodedSearch}` : hash; + return hash && encodedSearch ? `${hash}?${encodedSearch}` : hash; + }, [hash, encodedSearch]); + + const mergedPathname = useMemo(() => { + return pathname && encodedSearch ? `${pathname}?${encodedSearch}` : pathname; + }, [pathname, encodedSearch]); + const href = useMemo(() => { const link = url.format({ pathname, hash: mergedHash, @@ -60,28 +56,36 @@ export const useLinkProps = ({ app, pathname, hash, search }: LinkDescriptor): L }); return prefixer(app, link); - }, [hash, encodedSearch, pathname, prefixer, app]); + }, [mergedHash, hash, encodedSearch, pathname, prefixer, app]); const onClick = useMemo(() => { - // If these results are equal we know we're trying to navigate within the same application - // that the current history instance is representing - if (internalLinkResult && linksAreEquivalent(externalLinkResult, internalLinkResult)) { - return (e: React.MouseEvent | React.MouseEvent) => { - e.preventDefault(); - if (history) { - history.push({ - pathname: pathname ? formatPathname(pathname) : undefined, - search: encodedSearch, - }); + return (e: React.MouseEvent | React.MouseEvent) => { + e.preventDefault(); + + const navigate = () => { + if (navigateToApp) { + const navigationPath = mergedHash ? `#${mergedHash}` : mergedPathname; + navigateToApp(app, { path: navigationPath ? navigationPath : undefined }); } }; - } else { - return undefined; - } - }, [internalLinkResult, externalLinkResult, history, pathname, encodedSearch]); + + // A component somewhere within the app hierarchy is requesting that we + // prompt the user before navigating. + if (prompt) { + const wantsToNavigate = window.confirm(prompt); + if (wantsToNavigate) { + navigate(); + } else { + return; + } + } else { + navigate(); + } + }; + }, [navigateToApp, mergedHash, mergedPathname, app, prompt]); return { - href: externalLinkResult, + href, onClick, }; }; @@ -90,10 +94,6 @@ const encodeSearch = (search: Search) => { return stringify(urlUtils.encodeQuery(search), { sort: false, encode: false }); }; -const formatPathname = (pathname: string) => { - return pathname[0] === '/' ? pathname : `/${pathname}`; -}; - const validateParams = ({ app, pathname, hash, search }: LinkDescriptor) => { if (!app && hash) { throw new Error( @@ -101,9 +101,3 @@ const validateParams = ({ app, pathname, hash, search }: LinkDescriptor) => { ); } }; - -const linksAreEquivalent = (externalLink: string, internalLink: string): boolean => { - // Compares with trailing slashes removed. This handles the case where the pathname is '/' - // and 'createHref' will include the '/' but Kibana's 'getUrlForApp' will remove it. - return externalLink.replace(/\/$/, '') === internalLink.replace(/\/$/, ''); -}; diff --git a/x-pack/plugins/infra/public/utils/history_context.ts b/x-pack/plugins/infra/public/utils/history_context.ts index fe036e3179ec1..844d5b5e8e76f 100644 --- a/x-pack/plugins/infra/public/utils/history_context.ts +++ b/x-pack/plugins/infra/public/utils/history_context.ts @@ -5,9 +5,9 @@ */ import { createContext, useContext } from 'react'; -import { History } from 'history'; +import { ScopedHistory } from 'src/core/public'; -export const HistoryContext = createContext(undefined); +export const HistoryContext = createContext(undefined); export const useHistory = () => { return useContext(HistoryContext); diff --git a/x-pack/plugins/infra/public/utils/navigation_warning_prompt/context.tsx b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/context.tsx new file mode 100644 index 0000000000000..10f8fb9e71f43 --- /dev/null +++ b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/context.tsx @@ -0,0 +1,31 @@ +/* + * 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 React, { useState } from 'react'; +import { createContext, useContext } from 'react'; + +interface ContextValues { + prompt?: string; + setPrompt: (prompt: string | undefined) => void; +} + +export const NavigationWarningPromptContext = createContext({ + setPrompt: (prompt: string | undefined) => {}, +}); + +export const useNavigationWarningPrompt = () => { + return useContext(NavigationWarningPromptContext); +}; + +export const NavigationWarningPromptProvider: React.FC = ({ children }) => { + const [prompt, setPrompt] = useState(undefined); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/infra/public/utils/navigation_warning_prompt/index.ts b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/index.ts new file mode 100644 index 0000000000000..dcdbf8e912a83 --- /dev/null +++ b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export * from './context'; +export * from './prompt'; diff --git a/x-pack/plugins/infra/public/utils/navigation_warning_prompt/prompt.tsx b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/prompt.tsx new file mode 100644 index 0000000000000..65ec4729c036d --- /dev/null +++ b/x-pack/plugins/infra/public/utils/navigation_warning_prompt/prompt.tsx @@ -0,0 +1,25 @@ +/* + * 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 React, { useEffect } from 'react'; +import { useNavigationWarningPrompt } from './context'; + +interface Props { + prompt?: string; +} + +export const Prompt: React.FC = ({ prompt }) => { + const { setPrompt } = useNavigationWarningPrompt(); + + useEffect(() => { + setPrompt(prompt); + return () => { + setPrompt(undefined); + }; + }, [prompt, setPrompt]); + + return null; +}; From cb68e227831ce9f404d25abb6b6e546e0cff76b0 Mon Sep 17 00:00:00 2001 From: gchaps <33642766+gchaps@users.noreply.github.com> Date: Wed, 22 Apr 2020 08:48:30 -0700 Subject: [PATCH 02/35] [DOCS] Fixes hierarchy in alerting and actions section (#64133) (#64202) --- .../user/alerting/action-types/email.asciidoc | 10 ++++---- .../user/alerting/action-types/index.asciidoc | 4 ++-- .../alerting/action-types/pagerduty.asciidoc | 24 +++++++++---------- .../alerting/action-types/server-log.asciidoc | 4 ++-- .../user/alerting/action-types/slack.asciidoc | 8 +++---- .../alerting/action-types/webhook.asciidoc | 6 ++--- 6 files changed, 27 insertions(+), 29 deletions(-) diff --git a/docs/user/alerting/action-types/email.asciidoc b/docs/user/alerting/action-types/email.asciidoc index be3623dd9e59c..794fc14005f2f 100644 --- a/docs/user/alerting/action-types/email.asciidoc +++ b/docs/user/alerting/action-types/email.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[email-action-type]] -== Email action type +=== Email action The email action type uses the SMTP protocol to send mail message, using an integration of https://nodemailer.com/[Nodemailer]. Email message text is sent as both plain text and html text. @@ -10,11 +10,11 @@ The email action type uses the SMTP protocol to send mail message, using an inte Email connectors have the following configuration properties: -Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. +Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. Sender:: The from address for all emails sent with this connector, specified in `user@host-name` format. -Host:: Host name of the service provider. If you are using the <> setting, make sure this hostname is whitelisted. +Host:: Host name of the service provider. If you are using the <> setting, make sure this hostname is whitelisted. Port:: The port to connect to on the service provider. -Secure:: If true the connection will use TLS when connecting to the service provider. See https://nodemailer.com/smtp/#tls-options[nodemailer TLS documentation] for more information. +Secure:: If true the connection will use TLS when connecting to the service provider. See https://nodemailer.com/smtp/#tls-options[nodemailer TLS documentation] for more information. Username:: username for 'login' type authentication. Password:: password for 'login' type authentication. @@ -26,4 +26,4 @@ Email actions have the following configuration properties: To, CC, BCC:: Each is a list of addresses. Addresses can be specified in `user@host-name` format, or in `name ` format. One of To, CC, or BCC must contain an entry. Subject:: The subject line of the email. -Message:: The message text of the email. Markdown format is supported. \ No newline at end of file +Message:: The message text of the email. Markdown format is supported. diff --git a/docs/user/alerting/action-types/index.asciidoc b/docs/user/alerting/action-types/index.asciidoc index 75d9e57b1f212..625b8f704b7c6 100644 --- a/docs/user/alerting/action-types/index.asciidoc +++ b/docs/user/alerting/action-types/index.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[index-action-type]] -== Index action type +=== Index action The index action type will index a document into {es}. @@ -21,4 +21,4 @@ Execution time field:: This field will be automatically set to the time the ale Index actions have the following properties: -Document:: The document to index in json format. \ No newline at end of file +Document:: The document to index in json format. diff --git a/docs/user/alerting/action-types/pagerduty.asciidoc b/docs/user/alerting/action-types/pagerduty.asciidoc index da34c6e0855d7..abdcc7d1ba524 100644 --- a/docs/user/alerting/action-types/pagerduty.asciidoc +++ b/docs/user/alerting/action-types/pagerduty.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[pagerduty-action-type]] -== PagerDuty action type +=== PagerDuty action The PagerDuty action type uses the https://v2.developer.pagerduty.com/docs/events-api-v2[v2 Events API] to trigger, acknowledge, and resolve PagerDuty alerts. @@ -10,7 +10,7 @@ The PagerDuty action type uses the https://v2.developer.pagerduty.com/docs/event [float] [[pagerduty-benefits]] -=== PagerDuty + Elastic integration benefits +==== PagerDuty + Elastic integration benefits By integrating PagerDuty with alerts, you can: @@ -20,7 +20,7 @@ By integrating PagerDuty with alerts, you can: [float] [[pagerduty-how-it-works]] -==== How it works +===== How it works {kib} allows you to create alerts to notify you of a significant move in your dataset. @@ -28,7 +28,7 @@ You can create alerts for all your Observability, Security, and Elastic Stack us Alerts will trigger a new incident on the corresponding PagerDuty service. [float] -==== Requirements +===== Requirements In the `kibana.yml` configuration file, you must add the <>. This is required to encrypt parameters that must be secured, for example PagerDuty’s integration key. @@ -47,18 +47,17 @@ review the <> that are available to you. [float] [[pagerduty-support]] -==== Support +===== Support If you need help with this integration, get in touch with the {kib} team by visiting https://support.elastic.co[support.elastic.co] or by using the *Ask Elastic* option in the {kib} Help menu. You can also select the {kib} category at https://discuss.elastic.co/[discuss.elastic.co]. [float] [[pagerduty-integration-walkthrough]] -==== Integration with PagerDuty walkthrough +===== Integration with PagerDuty walkthrough -[float] [[pagerduty-in-pagerduty]] -===== In PagerDuty +*In PagerDuty* . From the *Configuration* menu, select *Services*. . Add an integration to a service: @@ -83,9 +82,8 @@ image::user/alerting/images/pagerduty-integration.png[PagerDuty Integrations tab . Save this key, as you will use it when you configure the integration with Elastic in the next section. -[float] [[pagerduty-in-elastic]] -===== In Elastic +*In Elastic* . Create a PagerDuty Connector in Kibana. You can: + @@ -117,7 +115,7 @@ https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2[API v2 do [float] [[pagerduty-uninstall]] -==== How to uninstall +===== How to uninstall To remove a PagerDuty connector from an alert, simply remove it from the *Actions* section of that alert, using the remove (x) icon. This will disable the integration for the particular alert. @@ -129,7 +127,7 @@ This is an irreversible action and impacts all alerts that use this connector. [float] [[pagerduty-connector-configuration]] -=== Connector configuration +==== Connector configuration PagerDuty connectors have the following configuration properties: @@ -139,7 +137,7 @@ Routing Key:: A 32 character PagerDuty Integration Key for an integration on a [float] [[pagerduty-action-configuration]] -=== Action configuration +==== Action configuration PagerDuty actions have the following properties: diff --git a/docs/user/alerting/action-types/server-log.asciidoc b/docs/user/alerting/action-types/server-log.asciidoc index 4efbdf3bea099..8f888785626c9 100644 --- a/docs/user/alerting/action-types/server-log.asciidoc +++ b/docs/user/alerting/action-types/server-log.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[server-log-action-type]] -== Server log action type +=== Server log action This action type writes and entry to the {kib} server log. @@ -18,4 +18,4 @@ Name:: The name of the connector. The name is used to identify a connector Server log actions have the following properties: -Message:: The message to log. \ No newline at end of file +Message:: The message to log. diff --git a/docs/user/alerting/action-types/slack.asciidoc b/docs/user/alerting/action-types/slack.asciidoc index a4bacbf162e46..c0965d65bfdbe 100644 --- a/docs/user/alerting/action-types/slack.asciidoc +++ b/docs/user/alerting/action-types/slack.asciidoc @@ -1,8 +1,8 @@ [role="xpack"] [[slack-action-type]] -== Slack action type +=== Slack action -The Slack action type uses https://api.slack.com/incoming-webhooks[Slack Incoming Webhooks]. +The Slack action type uses https://api.slack.com/incoming-webhooks[Slack Incoming Webhooks]. [float] [[slack-connector-configuration]] @@ -11,7 +11,7 @@ The Slack action type uses https://api.slack.com/incoming-webhooks[Slack Incomin Slack connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. -Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messaging/webhooks#getting_started[Slack Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is whitelisted. +Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messaging/webhooks#getting_started[Slack Incoming Webhooks] for instructions on generating this URL. If you are using the <> setting, make sure the hostname is whitelisted. [float] [[slack-action-configuration]] @@ -19,4 +19,4 @@ Webhook URL:: The URL of the incoming webhook. See https://api.slack.com/messa Slack actions have the following properties: -Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. \ No newline at end of file +Message:: The message text, converted to the `text` field in the Webhook JSON payload. Currently only the text field is supported. Markdown, images, and other advanced formatting are not yet supported. diff --git a/docs/user/alerting/action-types/webhook.asciidoc b/docs/user/alerting/action-types/webhook.asciidoc index 8c211aa83af89..64bfa6a1d6364 100644 --- a/docs/user/alerting/action-types/webhook.asciidoc +++ b/docs/user/alerting/action-types/webhook.asciidoc @@ -1,6 +1,6 @@ [role="xpack"] [[webhook-action-type]] -== Webhook action type +=== Webhook action The Webhook action type uses https://github.com/axios/axios[axios] to send a POST or PUT request to a web service. @@ -11,7 +11,7 @@ The Webhook action type uses https://github.com/axios/axios[axios] to send a POS Webhook connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. -URL:: The request URL. If you are using the <> setting, make sure the hostname is whitelisted. +URL:: The request URL. If you are using the <> setting, make sure the hostname is whitelisted. Method:: HTTP request method, either `post`(default) or `put`. Headers:: A set of key-value pairs sent as headers with the request User:: An optional username. If set, HTTP basic authentication is used. Currently only basic authentication is supported. @@ -23,4 +23,4 @@ Password:: An optional password. If set, HTTP basic authentication is used. Cur Webhook actions have the following properties: -Body:: A json payload sent to the request URL. \ No newline at end of file +Body:: A json payload sent to the request URL. From ac06ad81dd9b3275eddaf3839893184a492b93e0 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 22 Apr 2020 16:57:16 +0100 Subject: [PATCH 03/35] refact(NA): remove set loop from upgrade assistant usage collector (#63977) (#64180) * refact(NA): use default telemetry obj in the set loop * chore(NA): fix typecheck * fix(NA): test run with lodash has * chore(NA): fix older lodash has * chore(NA): remove lodash has usage --- .../lib/telemetry/usage_collector.test.ts | 1 + .../server/lib/telemetry/usage_collector.ts | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts index a4833d9a3d7fe..e6cbfbb57e34d 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.test.ts @@ -51,6 +51,7 @@ describe('Upgrade Assistant Usage Collector', () => { 'ui_reindex.open': 4, 'ui_reindex.start': 2, 'ui_reindex.stop': 1, + 'ui_reindex.not_defined': 1, }, }; }, diff --git a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts index faa8146664dbd..012ef20fd9475 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/telemetry/usage_collector.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { set } from 'lodash'; +import { get } from 'lodash'; import { APICaller, ElasticsearchServiceSetup, @@ -84,16 +84,19 @@ export async function fetchUpgradeAssistantMetrics( return defaultTelemetrySavedObject; } - const upgradeAssistantTelemetrySOAttrsKeys = Object.keys( - upgradeAssistantTelemetrySavedObjectAttrs - ); - const telemetryObj = defaultTelemetrySavedObject; - - upgradeAssistantTelemetrySOAttrsKeys.forEach((key: string) => { - set(telemetryObj, key, upgradeAssistantTelemetrySavedObjectAttrs[key]); - }); - - return telemetryObj as UpgradeAssistantTelemetrySavedObject; + return { + ui_open: { + overview: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.overview', 0), + cluster: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.cluster', 0), + indices: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_open.indices', 0), + }, + ui_reindex: { + close: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.close', 0), + open: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.open', 0), + start: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.start', 0), + stop: get(upgradeAssistantTelemetrySavedObjectAttrs, 'ui_reindex.stop', 0), + }, + } as UpgradeAssistantTelemetrySavedObject; }; return { From 23bc1684d0109eecd3acfa8ed866be52e746b19c Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 22 Apr 2020 11:59:11 -0400 Subject: [PATCH 04/35] [Maps] Convert AbstractSource and AbstractLayer to TS (#63533) (#64182) --- x-pack/plugins/maps/common/constants.ts | 1 + .../descriptor_types/descriptor_types.d.ts | 28 +- .../style_property_descriptor_types.d.ts | 6 +- .../public/angular/get_initial_layers.test.js | 4 +- .../public/layers/blended_vector_layer.ts | 26 +- x-pack/plugins/maps/public/layers/layer.d.ts | 51 -- x-pack/plugins/maps/public/layers/layer.js | 373 ------------- x-pack/plugins/maps/public/layers/layer.tsx | 490 ++++++++++++++++++ .../client_file_source/geojson_file_source.js | 4 +- .../es_geo_grid_source.d.ts | 9 +- .../layers/sources/es_source/es_source.d.ts | 16 + .../es_term_source/es_term_source.d.ts | 1 + .../mvt_single_layer_vector_source.ts | 11 +- .../maps/public/layers/sources/source.d.ts | 56 -- .../maps/public/layers/sources/source.js | 159 ------ .../maps/public/layers/sources/source.ts | 195 +++++++ .../sources/xyz_tms_source/xyz_tms_source.ts | 3 +- .../public/layers/styles/abstract_style.js | 29 -- .../layers/styles/heatmap/heatmap_style.js | 2 +- .../maps/public/layers/styles/style.ts | 59 +++ .../public/layers/styles/tile/tile_style.ts | 16 + .../layers/styles/vector/vector_style.d.ts | 7 +- .../layers/styles/vector/vector_style.js | 3 +- .../maps/public/layers/tile_layer.d.ts | 4 +- .../plugins/maps/public/layers/tile_layer.js | 8 +- .../maps/public/layers/tile_layer.test.ts | 10 +- .../maps/public/layers/tiled_vector_layer.tsx | 2 +- .../maps/public/layers/vector_layer.d.ts | 6 +- .../maps/public/layers/vector_layer.js | 2 + .../maps/public/layers/vector_tile_layer.js | 3 +- 30 files changed, 861 insertions(+), 723 deletions(-) delete mode 100644 x-pack/plugins/maps/public/layers/layer.d.ts delete mode 100644 x-pack/plugins/maps/public/layers/layer.js create mode 100644 x-pack/plugins/maps/public/layers/layer.tsx delete mode 100644 x-pack/plugins/maps/public/layers/sources/source.d.ts delete mode 100644 x-pack/plugins/maps/public/layers/sources/source.js create mode 100644 x-pack/plugins/maps/public/layers/sources/source.ts delete mode 100644 x-pack/plugins/maps/public/layers/styles/abstract_style.js create mode 100644 x-pack/plugins/maps/public/layers/styles/style.ts create mode 100644 x-pack/plugins/maps/public/layers/styles/tile/tile_style.ts diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index a4006732224ce..6f9c0985f5f4a 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -166,6 +166,7 @@ export enum STYLE_TYPE { export enum LAYER_STYLE_TYPE { VECTOR = 'VECTOR', HEATMAP = 'HEATMAP', + TILE = 'TILE', } export const COLOR_MAP_TYPE = { diff --git a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts index f8175b0ed3f10..6980f14d0788a 100644 --- a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts +++ b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts @@ -5,8 +5,9 @@ */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ +import { Query } from 'src/plugins/data/public'; import { AGG_TYPE, GRID_RESOLUTION, RENDER_AS, SORT_ORDER, SCALING_TYPES } from '../constants'; -import { VectorStyleDescriptor } from './style_property_descriptor_types'; +import { StyleDescriptor, VectorStyleDescriptor } from './style_property_descriptor_types'; import { DataRequestDescriptor } from './data_request_descriptor_types'; export type AttributionDescriptor = { @@ -17,6 +18,7 @@ export type AttributionDescriptor = { export type AbstractSourceDescriptor = { id?: string; type: string; + applyGlobalQuery?: boolean; }; export type EMSTMSSourceDescriptor = AbstractSourceDescriptor & { @@ -71,17 +73,15 @@ export type ESTermSourceDescriptor = AbstractESAggSourceDescriptor & { term: string; // term field name }; -export type KibanaRegionmapSourceDescriptor = { - type: string; +export type KibanaRegionmapSourceDescriptor = AbstractSourceDescriptor & { name: string; }; -export type KibanaTilemapSourceDescriptor = { - type: string; -}; +// This is for symmetry with other sources only. +// It takes no additional configuration since all params are in the .yml. +export type KibanaTilemapSourceDescriptor = AbstractSourceDescriptor; -export type WMSSourceDescriptor = { - type: string; +export type WMSSourceDescriptor = AbstractSourceDescriptor & { serviceUrl: string; layers: string; styles: string; @@ -111,6 +111,8 @@ export type JoinDescriptor = { right: ESTermSourceDescriptor; }; +// todo : this union type is incompatible with dynamic extensibility of sources. +// Reconsider using SourceDescriptor in type signatures for top-level classes export type SourceDescriptor = | XYZTMSSourceDescriptor | WMSSourceDescriptor @@ -121,7 +123,9 @@ export type SourceDescriptor = | ESGeoGridSourceDescriptor | EMSFileSourceDescriptor | ESPewPewSourceDescriptor - | TiledSingleLayerVectorSourceDescriptor; + | TiledSingleLayerVectorSourceDescriptor + | EMSTMSSourceDescriptor + | EMSFileSourceDescriptor; export type LayerDescriptor = { __dataRequests?: DataRequestDescriptor[]; @@ -129,12 +133,14 @@ export type LayerDescriptor = { __errorMessage?: string; alpha?: number; id: string; - label?: string; + label?: string | null; minZoom?: number; maxZoom?: number; - sourceDescriptor: SourceDescriptor; + sourceDescriptor: SourceDescriptor | null; type?: string; visible?: boolean; + style?: StyleDescriptor | null; + query?: Query; }; export type VectorLayerDescriptor = LayerDescriptor & { diff --git a/x-pack/plugins/maps/common/descriptor_types/style_property_descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/style_property_descriptor_types.d.ts index 47e56ff96d623..381bc5bba01c0 100644 --- a/x-pack/plugins/maps/common/descriptor_types/style_property_descriptor_types.d.ts +++ b/x-pack/plugins/maps/common/descriptor_types/style_property_descriptor_types.d.ts @@ -182,7 +182,11 @@ export type VectorStylePropertiesDescriptor = { [VECTOR_STYLES.LABEL_BORDER_SIZE]?: LabelBorderSizeStylePropertyDescriptor; }; -export type VectorStyleDescriptor = { +export type StyleDescriptor = { + type: string; +}; + +export type VectorStyleDescriptor = StyleDescriptor & { type: LAYER_STYLE_TYPE.VECTOR; properties: VectorStylePropertiesDescriptor; }; diff --git a/x-pack/plugins/maps/public/angular/get_initial_layers.test.js b/x-pack/plugins/maps/public/angular/get_initial_layers.test.js index f41ed26b2a05d..4b5cad8d19260 100644 --- a/x-pack/plugins/maps/public/angular/get_initial_layers.test.js +++ b/x-pack/plugins/maps/public/angular/get_initial_layers.test.js @@ -52,7 +52,7 @@ describe('kibana.yml configured with map.tilemap.url', () => { sourceDescriptor: { type: 'KIBANA_TILEMAP', }, - style: {}, + style: { type: 'TILE' }, type: 'TILE', visible: true, }, @@ -96,7 +96,7 @@ describe('EMS is enabled', () => { isAutoSelect: true, type: 'EMS_TMS', }, - style: {}, + style: { type: 'TILE' }, type: 'VECTOR_TILE', visible: true, }, diff --git a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts index 9a9ea2968ceeb..1fc3ad203706f 100644 --- a/x-pack/plugins/maps/public/layers/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/layers/blended_vector_layer.ts @@ -24,7 +24,7 @@ import { } from '../../common/constants'; import { ESGeoGridSource } from './sources/es_geo_grid_source/es_geo_grid_source'; import { canSkipSourceUpdate } from './util/can_skip_fetch'; -import { IVectorLayer, VectorLayerArguments } from './vector_layer'; +import { IVectorLayer } from './vector_layer'; import { IESSource } from './sources/es_source'; import { IESAggSource } from './sources/es_agg_source'; import { ISource } from './sources/source'; @@ -36,6 +36,8 @@ import { DynamicStylePropertyOptions, VectorLayerDescriptor, } from '../../common/descriptor_types'; +import { IStyle } from './styles/style'; +import { IVectorSource } from './sources/vector_source'; const ACTIVE_COUNT_DATA_ID = 'ACTIVE_COUNT_DATA_ID'; @@ -145,6 +147,11 @@ function getClusterStyleDescriptor( return clusterStyleDescriptor; } +export interface BlendedVectorLayerArguments { + source: IVectorSource; + layerDescriptor: VectorLayerDescriptor; +} + export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { static type = LAYER_TYPE.BLENDED_VECTOR; @@ -163,11 +170,14 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { private readonly _documentSource: IESSource; private readonly _documentStyle: IVectorStyle; - constructor(options: VectorLayerArguments) { - super(options); + constructor(options: BlendedVectorLayerArguments) { + super({ + ...options, + joins: [], + }); this._documentSource = this._source as IESSource; // VectorLayer constructor sets _source as document source - this._documentStyle = this._style; // VectorLayer constructor sets _style as document source + this._documentStyle = this._style as IVectorStyle; // VectorLayer constructor sets _style as document source this._clusterSource = getClusterSource(this._documentSource, this._documentStyle); const clusterStyleDescriptor = getClusterStyleDescriptor( @@ -229,11 +239,11 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { return this._documentSource; } - getCurrentStyle() { + getCurrentStyle(): IStyle { return this._isClustered ? this._clusterStyle : this._documentStyle; } - getStyleForEditing() { + getStyleForEditing(): IStyle { return this._documentStyle; } @@ -242,8 +252,8 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { const requestToken = Symbol(`layer-active-count:${this.getId()}`); const searchFilters = this._getSearchFilters( syncContext.dataFilters, - this.getSource(), - this.getCurrentStyle() + this.getSource() as IVectorSource, + this.getCurrentStyle() as IVectorStyle ); const canSkipFetch = await canSkipSourceUpdate({ source: this.getSource(), diff --git a/x-pack/plugins/maps/public/layers/layer.d.ts b/x-pack/plugins/maps/public/layers/layer.d.ts deleted file mode 100644 index e8fc5d473626c..0000000000000 --- a/x-pack/plugins/maps/public/layers/layer.d.ts +++ /dev/null @@ -1,51 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { LayerDescriptor, MapExtent, MapFilters, MapQuery } from '../../common/descriptor_types'; -import { ISource } from './sources/source'; -import { DataRequest } from './util/data_request'; -import { SyncContext } from '../actions/map_actions'; - -export interface ILayer { - getBounds(mapFilters: MapFilters): Promise; - getDataRequest(id: string): DataRequest | undefined; - getDisplayName(source?: ISource): Promise; - getId(): string; - getSourceDataRequest(): DataRequest | undefined; - getSource(): ISource; - getSourceForEditing(): ISource; - syncData(syncContext: SyncContext): Promise; - isVisible(): boolean; - showAtZoomLevel(zoomLevel: number): boolean; - getMinZoom(): number; - getMaxZoom(): number; - getMinSourceZoom(): number; -} - -export interface ILayerArguments { - layerDescriptor: LayerDescriptor; - source: ISource; -} - -export class AbstractLayer implements ILayer { - static createDescriptor(options: Partial, mapColors?: string[]): LayerDescriptor; - constructor(layerArguments: ILayerArguments); - getBounds(mapFilters: MapFilters): Promise; - getDataRequest(id: string): DataRequest | undefined; - getDisplayName(source?: ISource): Promise; - getId(): string; - getSourceDataRequest(): DataRequest | undefined; - getSource(): ISource; - getSourceForEditing(): ISource; - syncData(syncContext: SyncContext): Promise; - isVisible(): boolean; - showAtZoomLevel(zoomLevel: number): boolean; - getMinZoom(): number; - getMaxZoom(): number; - getMinSourceZoom(): number; - getQuery(): MapQuery; - _removeStaleMbSourcesAndLayers(mbMap: unknown): void; - _requiresPrevSourceCleanup(mbMap: unknown): boolean; -} diff --git a/x-pack/plugins/maps/public/layers/layer.js b/x-pack/plugins/maps/public/layers/layer.js deleted file mode 100644 index 9362ce2c028e6..0000000000000 --- a/x-pack/plugins/maps/public/layers/layer.js +++ /dev/null @@ -1,373 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import _ from 'lodash'; -import React from 'react'; -import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; -import { DataRequest } from './util/data_request'; -import { - MAX_ZOOM, - MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, - MIN_ZOOM, - SOURCE_DATA_ID_ORIGIN, -} from '../../common/constants'; -import uuid from 'uuid/v4'; - -import { copyPersistentState } from '../reducers/util.js'; -import { i18n } from '@kbn/i18n'; - -export class AbstractLayer { - constructor({ layerDescriptor, source }) { - this._descriptor = AbstractLayer.createDescriptor(layerDescriptor); - this._source = source; - if (this._descriptor.__dataRequests) { - this._dataRequests = this._descriptor.__dataRequests.map( - dataRequest => new DataRequest(dataRequest) - ); - } else { - this._dataRequests = []; - } - } - - static getBoundDataForSource(mbMap, sourceId) { - const mbStyle = mbMap.getStyle(); - return mbStyle.sources[sourceId].data; - } - - static createDescriptor(options = {}) { - const layerDescriptor = { ...options }; - - layerDescriptor.__dataRequests = _.get(options, '__dataRequests', []); - layerDescriptor.id = _.get(options, 'id', uuid()); - layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null; - layerDescriptor.minZoom = _.get(options, 'minZoom', MIN_ZOOM); - layerDescriptor.maxZoom = _.get(options, 'maxZoom', MAX_ZOOM); - layerDescriptor.alpha = _.get(options, 'alpha', 0.75); - layerDescriptor.visible = _.get(options, 'visible', true); - layerDescriptor.style = _.get(options, 'style', {}); - - return layerDescriptor; - } - - destroy() { - if (this._source) { - this._source.destroy(); - } - } - - async cloneDescriptor() { - const clonedDescriptor = copyPersistentState(this._descriptor); - // layer id is uuid used to track styles/layers in mapbox - clonedDescriptor.id = uuid(); - const displayName = await this.getDisplayName(); - clonedDescriptor.label = `Clone of ${displayName}`; - clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor(); - if (clonedDescriptor.joins) { - clonedDescriptor.joins.forEach(joinDescriptor => { - // right.id is uuid used to track requests in inspector - joinDescriptor.right.id = uuid(); - }); - } - return clonedDescriptor; - } - - makeMbLayerId(layerNameSuffix) { - return `${this.getId()}${MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER}${layerNameSuffix}`; - } - - isJoinable() { - return this.getSource().isJoinable(); - } - - supportsElasticsearchFilters() { - return this.getSource().isESSource(); - } - - async supportsFitToBounds() { - return await this.getSource().supportsFitToBounds(); - } - - async getDisplayName(source) { - if (this._descriptor.label) { - return this._descriptor.label; - } - - const sourceDisplayName = source - ? await source.getDisplayName() - : await this.getSource().getDisplayName(); - return sourceDisplayName || `Layer ${this._descriptor.id}`; - } - - async getAttributions() { - if (!this.hasErrors()) { - return await this.getSource().getAttributions(); - } - return []; - } - - getLabel() { - return this._descriptor.label ? this._descriptor.label : ''; - } - - getCustomIconAndTooltipContent() { - return { - icon: , - }; - } - - getIconAndTooltipContent(zoomLevel, isUsingSearch) { - let icon; - let tooltipContent = null; - const footnotes = []; - if (this.hasErrors()) { - icon = ( - - ); - tooltipContent = this.getErrors(); - } else if (this.isLayerLoading()) { - icon = ; - } else if (!this.isVisible()) { - icon = ; - tooltipContent = i18n.translate('xpack.maps.layer.layerHiddenTooltip', { - defaultMessage: `Layer is hidden.`, - }); - } else if (!this.showAtZoomLevel(zoomLevel)) { - const minZoom = this.getMinZoom(); - const maxZoom = this.getMaxZoom(); - icon = ; - tooltipContent = i18n.translate('xpack.maps.layer.zoomFeedbackTooltip', { - defaultMessage: `Layer is visible between zoom levels {minZoom} and {maxZoom}.`, - values: { minZoom, maxZoom }, - }); - } else { - const customIconAndTooltipContent = this.getCustomIconAndTooltipContent(); - if (customIconAndTooltipContent) { - icon = customIconAndTooltipContent.icon; - if (!customIconAndTooltipContent.areResultsTrimmed) { - tooltipContent = customIconAndTooltipContent.tooltipContent; - } else { - footnotes.push({ - icon: , - message: customIconAndTooltipContent.tooltipContent, - }); - } - } - - if (isUsingSearch && this.getQueryableIndexPatternIds().length) { - footnotes.push({ - icon: , - message: i18n.translate('xpack.maps.layer.isUsingSearchMsg', { - defaultMessage: 'Results narrowed by search bar', - }), - }); - } - } - - return { - icon, - tooltipContent, - footnotes, - }; - } - - async hasLegendDetails() { - return false; - } - - renderLegendDetails() { - return null; - } - - getId() { - return this._descriptor.id; - } - - getSource() { - return this._source; - } - - getSourceForEditing() { - return this._source; - } - - isVisible() { - return this._descriptor.visible; - } - - showAtZoomLevel(zoom) { - return zoom >= this.getMinZoom() && zoom <= this.getMaxZoom(); - } - - getMinZoom() { - return this._descriptor.minZoom; - } - - getMaxZoom() { - return this._descriptor.maxZoom; - } - - getMinSourceZoom() { - return this._source.getMinZoom(); - } - - _requiresPrevSourceCleanup() { - return false; - } - - _removeStaleMbSourcesAndLayers(mbMap) { - if (this._requiresPrevSourceCleanup(mbMap)) { - const mbStyle = mbMap.getStyle(); - mbStyle.layers.forEach(mbLayer => { - if (this.ownsMbLayerId(mbLayer.id)) { - mbMap.removeLayer(mbLayer.id); - } - }); - Object.keys(mbStyle.sources).some(mbSourceId => { - if (this.ownsMbSourceId(mbSourceId)) { - mbMap.removeSource(mbSourceId); - } - }); - } - } - - getAlpha() { - return this._descriptor.alpha; - } - - getQuery() { - return this._descriptor.query; - } - - getCurrentStyle() { - return this._style; - } - - getStyleForEditing() { - return this._style; - } - - async getImmutableSourceProperties() { - return this.getSource().getImmutableProperties(); - } - - renderSourceSettingsEditor = ({ onChange }) => { - return this.getSourceForEditing().renderSourceSettingsEditor({ onChange }); - }; - - getPrevRequestToken(dataId) { - const prevDataRequest = this.getDataRequest(dataId); - if (!prevDataRequest) { - return; - } - - return prevDataRequest.getRequestToken(); - } - - getInFlightRequestTokens() { - if (!this._dataRequests) { - return []; - } - - const requestTokens = this._dataRequests.map(dataRequest => dataRequest.getRequestToken()); - return _.compact(requestTokens); - } - - getSourceDataRequest() { - return this.getDataRequest(SOURCE_DATA_ID_ORIGIN); - } - - getDataRequest(id) { - return this._dataRequests.find(dataRequest => dataRequest.getDataId() === id); - } - - isLayerLoading() { - return this._dataRequests.some(dataRequest => dataRequest.isLoading()); - } - - hasErrors() { - return _.get(this._descriptor, '__isInErrorState', false); - } - - getErrors() { - return this.hasErrors() ? this._descriptor.__errorMessage : ''; - } - - toLayerDescriptor() { - return this._descriptor; - } - - async syncData() { - //no-op by default - } - - getMbLayerIds() { - throw new Error('Should implement AbstractLayer#getMbLayerIds'); - } - - ownsMbLayerId() { - throw new Error('Should implement AbstractLayer#ownsMbLayerId'); - } - - ownsMbSourceId() { - throw new Error('Should implement AbstractLayer#ownsMbSourceId'); - } - - canShowTooltip() { - return false; - } - - syncLayerWithMB() { - throw new Error('Should implement AbstractLayer#syncLayerWithMB'); - } - - getLayerTypeIconName() { - throw new Error('should implement Layer#getLayerTypeIconName'); - } - - isDataLoaded() { - const sourceDataRequest = this.getSourceDataRequest(); - return sourceDataRequest && sourceDataRequest.hasData(); - } - - async getBounds(/* mapFilters: MapFilters */) { - return { - minLon: -180, - maxLon: 180, - minLat: -89, - maxLat: 89, - }; - } - - renderStyleEditor({ onStyleDescriptorChange }) { - const style = this.getStyleForEditing(); - if (!style) { - return null; - } - return style.renderEditor({ layer: this, onStyleDescriptorChange }); - } - - getIndexPatternIds() { - return []; - } - - getQueryableIndexPatternIds() { - return []; - } - - syncVisibilityWithMb(mbMap, mbLayerId) { - mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none'); - } - - getType() { - return this._descriptor.type; - } -} diff --git a/x-pack/plugins/maps/public/layers/layer.tsx b/x-pack/plugins/maps/public/layers/layer.tsx new file mode 100644 index 0000000000000..ce48793e1481b --- /dev/null +++ b/x-pack/plugins/maps/public/layers/layer.tsx @@ -0,0 +1,490 @@ +/* + * 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. + */ +/* eslint-disable @typescript-eslint/consistent-type-definitions */ + +import { Query } from 'src/plugins/data/public'; +import _ from 'lodash'; +import React, { ReactElement } from 'react'; +import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; +import uuid from 'uuid/v4'; +import { i18n } from '@kbn/i18n'; +import { FeatureCollection } from 'geojson'; +import { DataRequest } from './util/data_request'; +import { + MAX_ZOOM, + MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER, + MIN_ZOOM, + SOURCE_DATA_ID_ORIGIN, +} from '../../common/constants'; +// @ts-ignore +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { copyPersistentState } from '../reducers/util.js'; +import { + LayerDescriptor, + MapExtent, + MapFilters, + StyleDescriptor, +} from '../../common/descriptor_types'; +import { Attribution, ImmutableSourceProperty, ISource } from './sources/source'; +import { SyncContext } from '../actions/map_actions'; +import { IStyle } from './styles/style'; + +export interface ILayer { + getBounds(mapFilters: MapFilters): Promise; + getDataRequest(id: string): DataRequest | undefined; + getDisplayName(source?: ISource): Promise; + getId(): string; + getSourceDataRequest(): DataRequest | undefined; + getSource(): ISource; + getSourceForEditing(): ISource; + syncData(syncContext: SyncContext): void; + supportsElasticsearchFilters(): boolean; + supportsFitToBounds(): Promise; + getAttributions(): Promise; + getLabel(): string; + getCustomIconAndTooltipContent(): IconAndTooltipContent; + getIconAndTooltipContent(zoomLevel: number, isUsingSearch: boolean): IconAndTooltipContent; + renderLegendDetails(): ReactElement | null; + showAtZoomLevel(zoom: number): boolean; + getMinZoom(): number; + getMaxZoom(): number; + getMinSourceZoom(): number; + getAlpha(): number; + getQuery(): Query | null; + getStyle(): IStyle; + getStyleForEditing(): IStyle; + getCurrentStyle(): IStyle; + getImmutableSourceProperties(): Promise; + renderSourceSettingsEditor({ onChange }: { onChange: () => void }): ReactElement | null; + isLayerLoading(): boolean; + hasErrors(): boolean; + getErrors(): string; + toLayerDescriptor(): LayerDescriptor; + getMbLayerIds(): string[]; + ownsMbLayerId(mbLayerId: string): boolean; + ownsMbSourceId(mbSourceId: string): boolean; + canShowTooltip(): boolean; + syncLayerWithMB(mbMap: unknown): void; + getLayerTypeIconName(): string; + isDataLoaded(): boolean; + getIndexPatternIds(): string[]; + getQueryableIndexPatternIds(): string[]; + getType(): string | undefined; + isVisible(): boolean; + cloneDescriptor(): Promise; + renderStyleEditor({ + onStyleDescriptorChange, + }: { + onStyleDescriptorChange: (styleDescriptor: StyleDescriptor) => void; + }): ReactElement | null; +} +export type Footnote = { + icon: ReactElement; + message?: string | null; +}; +export type IconAndTooltipContent = { + icon?: ReactElement | null; + tooltipContent?: string | null; + footnotes?: Footnote[] | null; + areResultsTrimmed?: boolean; +}; + +export interface ILayerArguments { + layerDescriptor: LayerDescriptor; + source: ISource; + style: IStyle; +} + +export class AbstractLayer implements ILayer { + protected readonly _descriptor: LayerDescriptor; + protected readonly _source: ISource; + protected readonly _style: IStyle; + protected readonly _dataRequests: DataRequest[]; + + static createDescriptor(options: Partial): LayerDescriptor { + return { + ...options, + sourceDescriptor: options.sourceDescriptor ? options.sourceDescriptor : null, + __dataRequests: _.get(options, '__dataRequests', []), + id: _.get(options, 'id', uuid()), + label: options.label && options.label.length > 0 ? options.label : null, + minZoom: _.get(options, 'minZoom', MIN_ZOOM), + maxZoom: _.get(options, 'maxZoom', MAX_ZOOM), + alpha: _.get(options, 'alpha', 0.75), + visible: _.get(options, 'visible', true), + style: _.get(options, 'style', null), + }; + } + + destroy() { + if (this._source) { + this._source.destroy(); + } + } + + constructor({ layerDescriptor, source, style }: ILayerArguments) { + this._descriptor = AbstractLayer.createDescriptor(layerDescriptor); + this._source = source; + this._style = style; + if (this._descriptor.__dataRequests) { + this._dataRequests = this._descriptor.__dataRequests.map( + dataRequest => new DataRequest(dataRequest) + ); + } else { + this._dataRequests = []; + } + } + + static getBoundDataForSource(mbMap: unknown, sourceId: string): FeatureCollection { + // @ts-ignore + const mbStyle = mbMap.getStyle(); + return mbStyle.sources[sourceId].data; + } + + async cloneDescriptor(): Promise { + // @ts-ignore + const clonedDescriptor = copyPersistentState(this._descriptor); + // layer id is uuid used to track styles/layers in mapbox + clonedDescriptor.id = uuid(); + const displayName = await this.getDisplayName(); + clonedDescriptor.label = `Clone of ${displayName}`; + clonedDescriptor.sourceDescriptor = this.getSource().cloneDescriptor(); + + // todo: remove this + // This should not be in AbstractLayer. It relies on knowledge of VectorLayerDescriptor + // @ts-ignore + if (clonedDescriptor.joins) { + // @ts-ignore + clonedDescriptor.joins.forEach(joinDescriptor => { + // right.id is uuid used to track requests in inspector + // @ts-ignore + joinDescriptor.right.id = uuid(); + }); + } + return clonedDescriptor; + } + + makeMbLayerId(layerNameSuffix: string): string { + return `${this.getId()}${MB_SOURCE_ID_LAYER_ID_PREFIX_DELIMITER}${layerNameSuffix}`; + } + + isJoinable(): boolean { + return this.getSource().isJoinable(); + } + + supportsElasticsearchFilters(): boolean { + return this.getSource().isESSource(); + } + + async supportsFitToBounds(): Promise { + return await this.getSource().supportsFitToBounds(); + } + + async getDisplayName(source?: ISource): Promise { + if (this._descriptor.label) { + return this._descriptor.label; + } + + const sourceDisplayName = source + ? await source.getDisplayName() + : await this.getSource().getDisplayName(); + return sourceDisplayName || `Layer ${this._descriptor.id}`; + } + + async getAttributions(): Promise { + if (!this.hasErrors()) { + return await this.getSource().getAttributions(); + } + return []; + } + + getStyleForEditing(): IStyle { + return this._style; + } + + getStyle() { + return this._style; + } + + getLabel(): string { + return this._descriptor.label ? this._descriptor.label : ''; + } + + getCustomIconAndTooltipContent(): IconAndTooltipContent { + return { + icon: , + }; + } + + getIconAndTooltipContent(zoomLevel: number, isUsingSearch: boolean): IconAndTooltipContent { + let icon; + let tooltipContent = null; + const footnotes = []; + if (this.hasErrors()) { + icon = ( + + ); + tooltipContent = this.getErrors(); + } else if (this.isLayerLoading()) { + icon = ; + } else if (!this.isVisible()) { + icon = ; + tooltipContent = i18n.translate('xpack.maps.layer.layerHiddenTooltip', { + defaultMessage: `Layer is hidden.`, + }); + } else if (!this.showAtZoomLevel(zoomLevel)) { + const minZoom = this.getMinZoom(); + const maxZoom = this.getMaxZoom(); + icon = ; + tooltipContent = i18n.translate('xpack.maps.layer.zoomFeedbackTooltip', { + defaultMessage: `Layer is visible between zoom levels {minZoom} and {maxZoom}.`, + values: { minZoom, maxZoom }, + }); + } else { + const customIconAndTooltipContent = this.getCustomIconAndTooltipContent(); + if (customIconAndTooltipContent) { + icon = customIconAndTooltipContent.icon; + if (!customIconAndTooltipContent.areResultsTrimmed) { + tooltipContent = customIconAndTooltipContent.tooltipContent; + } else { + footnotes.push({ + icon: , + message: customIconAndTooltipContent.tooltipContent, + }); + } + } + + if (isUsingSearch && this.getQueryableIndexPatternIds().length) { + footnotes.push({ + icon: , + message: i18n.translate('xpack.maps.layer.isUsingSearchMsg', { + defaultMessage: 'Results narrowed by search bar', + }), + }); + } + } + + return { + icon, + tooltipContent, + footnotes, + }; + } + + async hasLegendDetails(): Promise { + return false; + } + + renderLegendDetails(): ReactElement | null { + return null; + } + + getId(): string { + return this._descriptor.id; + } + + getSource(): ISource { + return this._source; + } + + getSourceForEditing(): ISource { + return this._source; + } + + isVisible(): boolean { + return !!this._descriptor.visible; + } + + showAtZoomLevel(zoom: number): boolean { + return zoom >= this.getMinZoom() && zoom <= this.getMaxZoom(); + } + + getMinZoom(): number { + return typeof this._descriptor.minZoom === 'number' ? this._descriptor.minZoom : MIN_ZOOM; + } + + getMaxZoom(): number { + return typeof this._descriptor.maxZoom === 'number' ? this._descriptor.maxZoom : MAX_ZOOM; + } + + getMinSourceZoom(): number { + return this._source.getMinZoom(); + } + + _requiresPrevSourceCleanup(mbMap: unknown) { + return false; + } + + _removeStaleMbSourcesAndLayers(mbMap: unknown) { + if (this._requiresPrevSourceCleanup(mbMap)) { + // @ts-ignore + const mbStyle = mbMap.getStyle(); + // @ts-ignore + mbStyle.layers.forEach(mbLayer => { + // @ts-ignore + if (this.ownsMbLayerId(mbLayer.id)) { + // @ts-ignore + mbMap.removeLayer(mbLayer.id); + } + }); + // @ts-ignore + Object.keys(mbStyle.sources).some(mbSourceId => { + // @ts-ignore + if (this.ownsMbSourceId(mbSourceId)) { + // @ts-ignore + mbMap.removeSource(mbSourceId); + } + }); + } + } + + getAlpha(): number { + return typeof this._descriptor.alpha === 'number' ? this._descriptor.alpha : 1; + } + + getQuery(): Query | null { + return this._descriptor.query ? this._descriptor.query : null; + } + + getCurrentStyle(): IStyle { + return this._style; + } + + async getImmutableSourceProperties() { + const source = this.getSource(); + return await source.getImmutableProperties(); + } + + renderSourceSettingsEditor({ onChange }: { onChange: () => void }) { + const source = this.getSourceForEditing(); + return source.renderSourceSettingsEditor({ onChange }); + } + + getPrevRequestToken(dataId: string): symbol | undefined { + const prevDataRequest = this.getDataRequest(dataId); + if (!prevDataRequest) { + return; + } + + return prevDataRequest.getRequestToken(); + } + + getInFlightRequestTokens(): symbol[] { + if (!this._dataRequests) { + return []; + } + + const requestTokens = this._dataRequests.map(dataRequest => dataRequest.getRequestToken()); + + // Compact removes all the undefineds + // @ts-ignore + return _.compact(requestTokens); + } + + getSourceDataRequest(): DataRequest | undefined { + return this.getDataRequest(SOURCE_DATA_ID_ORIGIN); + } + + getDataRequest(id: string): DataRequest | undefined { + return this._dataRequests.find(dataRequest => dataRequest.getDataId() === id); + } + + isLayerLoading(): boolean { + return this._dataRequests.some(dataRequest => dataRequest.isLoading()); + } + + hasErrors(): boolean { + return _.get(this._descriptor, '__isInErrorState', false); + } + + getErrors(): string { + return this.hasErrors() && this._descriptor.__errorMessage + ? this._descriptor.__errorMessage + : ''; + } + + toLayerDescriptor(): LayerDescriptor { + return this._descriptor; + } + + async syncData(syncContext: SyncContext) { + // no-op by default + } + + getMbLayerIds(): string[] { + throw new Error('Should implement AbstractLayer#getMbLayerIds'); + } + + ownsMbLayerId(layerId: string): boolean { + throw new Error('Should implement AbstractLayer#ownsMbLayerId'); + } + + ownsMbSourceId(sourceId: string): boolean { + throw new Error('Should implement AbstractLayer#ownsMbSourceId'); + } + + canShowTooltip() { + return false; + } + + syncLayerWithMB(mbMap: unknown) { + throw new Error('Should implement AbstractLayer#syncLayerWithMB'); + } + + getLayerTypeIconName(): string { + throw new Error('should implement Layer#getLayerTypeIconName'); + } + + isDataLoaded(): boolean { + const sourceDataRequest = this.getSourceDataRequest(); + return sourceDataRequest ? sourceDataRequest.hasData() : false; + } + + async getBounds(mapFilters: MapFilters): Promise { + return { + minLon: -180, + maxLon: 180, + minLat: -89, + maxLat: 89, + }; + } + + renderStyleEditor({ + onStyleDescriptorChange, + }: { + onStyleDescriptorChange: (styleDescriptor: StyleDescriptor) => void; + }): ReactElement | null { + const style = this.getStyleForEditing(); + if (!style) { + return null; + } + return style.renderEditor({ layer: this, onStyleDescriptorChange }); + } + + getIndexPatternIds(): string[] { + return []; + } + + getQueryableIndexPatternIds(): string[] { + return []; + } + + syncVisibilityWithMb(mbMap: unknown, mbLayerId: string) { + // @ts-ignore + mbMap.setLayoutProperty(mbLayerId, 'visibility', this.isVisible() ? 'visible' : 'none'); + } + + getType(): string | undefined { + return this._descriptor.type; + } +} diff --git a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js index 137513ad7c612..36f898f723757 100644 --- a/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js +++ b/x-pack/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js @@ -21,8 +21,6 @@ import { registerSource } from '../source_registry'; export class GeojsonFileSource extends AbstractVectorSource { static type = SOURCE_TYPES.GEOJSON_FILE; - static isIndexingSource = true; - static createDescriptor(geoJson, name) { // Wrap feature as feature collection if needed let featureCollection; @@ -70,7 +68,7 @@ export class GeojsonFileSource extends AbstractVectorSource { } shouldBeIndexed() { - return GeojsonFileSource.isIndexingSource; + return true; } } diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts index 96347c444dd5b..51ee15e7ea5af 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.d.ts @@ -6,7 +6,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { ESGeoGridSourceDescriptor } from '../../../../common/descriptor_types'; -import { GRID_RESOLUTION, RENDER_AS } from '../../../../common/constants'; +import { GRID_RESOLUTION } from '../../../../common/constants'; export class ESGeoGridSource extends AbstractESAggSource { static createDescriptor({ @@ -14,12 +14,7 @@ export class ESGeoGridSource extends AbstractESAggSource { geoField, requestType, resolution, - }: { - indexPatternId: string; - geoField: string; - requestType: RENDER_AS; - resolution?: GRID_RESOLUTION; - }): ESGeoGridSourceDescriptor; + }: Partial): ESGeoGridSourceDescriptor; constructor(sourceDescriptor: ESGeoGridSourceDescriptor, inspectorAdapters: unknown); diff --git a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts index 092dc3bf0d5a8..3b41ae6bfd86b 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_source/es_source.d.ts @@ -8,6 +8,8 @@ import { AbstractVectorSource } from '../vector_source'; import { IVectorSource } from '../vector_source'; import { IndexPattern, SearchSource } from '../../../../../../../src/plugins/data/public'; import { VectorSourceRequestMeta } from '../../../../common/descriptor_types'; +import { VectorStyle } from '../../styles/vector/vector_style'; +import { IDynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; export interface IESSource extends IVectorSource { getId(): string; @@ -20,6 +22,13 @@ export interface IESSource extends IVectorSource { limit: number, initialSearchContext?: object ): Promise; + loadStylePropsMeta( + layerName: string, + style: VectorStyle, + dynamicStyleProps: IDynamicStyleProperty[], + registerCancelCallback: (requestToken: symbol, callback: () => void) => void, + searchFilters: VectorSourceRequestMeta + ): Promise; } export class AbstractESSource extends AbstractVectorSource implements IESSource { @@ -33,4 +42,11 @@ export class AbstractESSource extends AbstractVectorSource implements IESSource limit: number, initialSearchContext?: object ): Promise; + loadStylePropsMeta( + layerName: string, + style: VectorStyle, + dynamicStyleProps: IDynamicStyleProperty[], + registerCancelCallback: (requestToken: symbol, callback: () => void) => void, + searchFilters: VectorSourceRequestMeta + ): Promise; } diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts index 701bd5e2c8b5e..248ca2b9212b4 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts +++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.d.ts @@ -9,4 +9,5 @@ import { IESAggSource } from '../es_agg_source'; export interface IESTermSource extends IESAggSource { getTermField(): IField; + hasCompleteConfig(): boolean; } diff --git a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts index 0bfda6be72203..a73cfbdc0d043 100644 --- a/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts +++ b/x-pack/plugins/maps/public/layers/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.ts @@ -15,9 +15,9 @@ import { IField } from '../../fields/field'; import { registerSource } from '../source_registry'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; import { - LayerDescriptor, MapExtent, TiledSingleLayerVectorSourceDescriptor, + VectorLayerDescriptor, VectorSourceRequestMeta, VectorSourceSyncMeta, } from '../../../../common/descriptor_types'; @@ -66,12 +66,15 @@ export class MVTSingleLayerVectorSource extends AbstractSource return []; } - createDefaultLayer(options: LayerDescriptor): TiledVectorLayer { - const layerDescriptor = { + createDefaultLayer(options?: Partial): TiledVectorLayer { + const layerDescriptor: Partial = { sourceDescriptor: this._descriptor, ...options, }; - const normalizedLayerDescriptor = TiledVectorLayer.createDescriptor(layerDescriptor, []); + const normalizedLayerDescriptor: VectorLayerDescriptor = TiledVectorLayer.createDescriptor( + layerDescriptor, + [] + ); const vectorLayerArguments: VectorLayerArguments = { layerDescriptor: normalizedLayerDescriptor, source: this, diff --git a/x-pack/plugins/maps/public/layers/sources/source.d.ts b/x-pack/plugins/maps/public/layers/sources/source.d.ts deleted file mode 100644 index 5a01da02adaae..0000000000000 --- a/x-pack/plugins/maps/public/layers/sources/source.d.ts +++ /dev/null @@ -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; - * you may not use this file except in compliance with the Elastic License. - */ -/* eslint-disable @typescript-eslint/consistent-type-definitions */ - -import { AbstractSourceDescriptor, LayerDescriptor } from '../../../common/descriptor_types'; -import { ILayer } from '../layer'; - -export type ImmutableSourceProperty = { - label: string; - value: string; -}; - -export type Attribution = { - url: string; - label: string; -}; - -export interface ISource { - createDefaultLayer(options?: LayerDescriptor): ILayer; - destroy(): void; - getDisplayName(): Promise; - getInspectorAdapters(): object; - isFieldAware(): boolean; - isFilterByMapBounds(): boolean; - isGeoGridPrecisionAware(): boolean; - isQueryAware(): boolean; - isRefreshTimerAware(): Promise; - isTimeAware(): Promise; - getImmutableProperties(): Promise; - getAttributions(): Promise; - getMinZoom(): number; - getMaxZoom(): number; -} - -export class AbstractSource implements ISource { - readonly _descriptor: AbstractSourceDescriptor; - constructor(sourceDescriptor: AbstractSourceDescriptor, inspectorAdapters?: object); - - destroy(): void; - createDefaultLayer(options?: LayerDescriptor, mapColors?: string[]): ILayer; - getDisplayName(): Promise; - getInspectorAdapters(): object; - isFieldAware(): boolean; - isFilterByMapBounds(): boolean; - isGeoGridPrecisionAware(): boolean; - isQueryAware(): boolean; - isRefreshTimerAware(): Promise; - isTimeAware(): Promise; - getImmutableProperties(): Promise; - getAttributions(): Promise; - getMinZoom(): number; - getMaxZoom(): number; -} diff --git a/x-pack/plugins/maps/public/layers/sources/source.js b/x-pack/plugins/maps/public/layers/sources/source.js deleted file mode 100644 index fd93daf249b26..0000000000000 --- a/x-pack/plugins/maps/public/layers/sources/source.js +++ /dev/null @@ -1,159 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { copyPersistentState } from '../../reducers/util'; -import { MIN_ZOOM, MAX_ZOOM } from '../../../common/constants'; - -export class AbstractSource { - static isIndexingSource = false; - - static renderEditor() { - throw new Error('Must implement Source.renderEditor'); - } - - static createDescriptor() { - throw new Error('Must implement Source.createDescriptor'); - } - - constructor(descriptor, inspectorAdapters) { - this._descriptor = descriptor; - this._inspectorAdapters = inspectorAdapters; - } - - destroy() {} - - cloneDescriptor() { - return copyPersistentState(this._descriptor); - } - - async supportsFitToBounds() { - return true; - } - - /** - * return list of immutable source properties. - * Immutable source properties are properties that can not be edited by the user. - */ - async getImmutableProperties() { - return []; - } - - getInspectorAdapters() { - return this._inspectorAdapters; - } - - _createDefaultLayerDescriptor() { - throw new Error(`Source#createDefaultLayerDescriptor not implemented`); - } - - createDefaultLayer() { - throw new Error(`Source#createDefaultLayer not implemented`); - } - - async getDisplayName() { - console.warn('Source should implement Source#getDisplayName'); - return ''; - } - - /** - * return attribution for this layer as array of objects with url and label property. - * e.g. [{ url: 'example.com', label: 'foobar' }] - * @return {Promise} - */ - async getAttributions() { - return []; - } - - isFieldAware() { - return false; - } - - isRefreshTimerAware() { - return false; - } - - isGeoGridPrecisionAware() { - return false; - } - - async isTimeAware() { - return false; - } - - getFieldNames() { - return []; - } - - hasCompleteConfig() { - throw new Error(`Source#hasCompleteConfig not implemented`); - } - - renderSourceSettingsEditor() { - return null; - } - - getApplyGlobalQuery() { - return !!this._descriptor.applyGlobalQuery; - } - - getIndexPatternIds() { - return []; - } - - getQueryableIndexPatternIds() { - return []; - } - - isFilterByMapBounds() { - return false; - } - - isQueryAware() { - return false; - } - - getGeoGridPrecision() { - return 0; - } - - isJoinable() { - return false; - } - - shouldBeIndexed() { - return AbstractSource.isIndexingSource; - } - - isESSource() { - return false; - } - - // Returns geo_shape indexed_shape context for spatial quering by pre-indexed shapes - async getPreIndexedShape(/* properties */) { - return null; - } - - // Returns function used to format value - async createFieldFormatter(/* field */) { - return null; - } - - async loadStylePropsMeta() { - throw new Error(`Source#loadStylePropsMeta not implemented`); - } - - async getValueSuggestions(/* field, query */) { - return []; - } - - getMinZoom() { - return MIN_ZOOM; - } - - getMaxZoom() { - return MAX_ZOOM; - } -} diff --git a/x-pack/plugins/maps/public/layers/sources/source.ts b/x-pack/plugins/maps/public/layers/sources/source.ts new file mode 100644 index 0000000000000..1cd84010159ab --- /dev/null +++ b/x-pack/plugins/maps/public/layers/sources/source.ts @@ -0,0 +1,195 @@ +/* + * 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. + */ + +/* eslint-disable @typescript-eslint/consistent-type-definitions */ + +import { ReactElement } from 'react'; + +import { Adapters } from 'src/plugins/inspector/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +// @ts-ignore +import { copyPersistentState } from '../../reducers/util'; + +import { LayerDescriptor, SourceDescriptor } from '../../../common/descriptor_types'; +import { ILayer } from '../layer'; +import { IField } from '../fields/field'; +import { MAX_ZOOM, MIN_ZOOM } from '../../../common/constants'; + +export type ImmutableSourceProperty = { + label: string; + value: string; +}; + +export type Attribution = { + url: string; + label: string; +}; + +export type PreIndexedShape = { + index: string; + id: string | number; + path: string; +}; + +export type FieldFormatter = (value: string | number | null | undefined | boolean) => string; + +export interface ISource { + createDefaultLayer(options?: Partial): ILayer; + destroy(): void; + getDisplayName(): Promise; + getInspectorAdapters(): Adapters | undefined; + isFieldAware(): boolean; + isFilterByMapBounds(): boolean; + isGeoGridPrecisionAware(): boolean; + isQueryAware(): boolean; + isRefreshTimerAware(): boolean; + isTimeAware(): Promise; + getImmutableProperties(): Promise; + getAttributions(): Promise; + isESSource(): boolean; + renderSourceSettingsEditor({ onChange }: { onChange: () => void }): ReactElement | null; + supportsFitToBounds(): Promise; + isJoinable(): boolean; + cloneDescriptor(): SourceDescriptor; + getFieldNames(): string[]; + getApplyGlobalQuery(): boolean; + getIndexPatternIds(): string[]; + getQueryableIndexPatternIds(): string[]; + getGeoGridPrecision(zoom: number): number; + shouldBeIndexed(): boolean; + getPreIndexedShape(): Promise; + createFieldFormatter(field: IField): Promise; + getValueSuggestions(field: IField, query: string): Promise; + getMinZoom(): number; + getMaxZoom(): number; +} + +export class AbstractSource implements ISource { + readonly _descriptor: SourceDescriptor; + readonly _inspectorAdapters?: Adapters | undefined; + + constructor(descriptor: SourceDescriptor, inspectorAdapters?: Adapters) { + this._descriptor = descriptor; + this._inspectorAdapters = inspectorAdapters; + } + + destroy(): void {} + + cloneDescriptor(): SourceDescriptor { + // @ts-ignore + return copyPersistentState(this._descriptor); + } + + async supportsFitToBounds(): Promise { + return true; + } + + /** + * return list of immutable source properties. + * Immutable source properties are properties that can not be edited by the user. + */ + async getImmutableProperties(): Promise { + return []; + } + + getInspectorAdapters(): Adapters | undefined { + return this._inspectorAdapters; + } + + createDefaultLayer(options?: Partial): ILayer { + throw new Error(`Source#createDefaultLayer not implemented`); + } + + async getDisplayName(): Promise { + return ''; + } + + async getAttributions(): Promise { + return []; + } + + isFieldAware(): boolean { + return false; + } + + isRefreshTimerAware(): boolean { + return false; + } + + isGeoGridPrecisionAware(): boolean { + return false; + } + + isQueryAware(): boolean { + return false; + } + + getFieldNames(): string[] { + return []; + } + + renderSourceSettingsEditor() { + return null; + } + + getApplyGlobalQuery(): boolean { + return !!this._descriptor.applyGlobalQuery; + } + + getIndexPatternIds(): string[] { + return []; + } + + getQueryableIndexPatternIds(): string[] { + return []; + } + + getGeoGridPrecision(zoom: number): number { + return 0; + } + + isJoinable(): boolean { + return false; + } + + shouldBeIndexed(): boolean { + return false; + } + + isESSource(): boolean { + return false; + } + + // Returns geo_shape indexed_shape context for spatial quering by pre-indexed shapes + async getPreIndexedShape(/* properties */): Promise { + return null; + } + + // Returns function used to format value + async createFieldFormatter(field: IField): Promise { + return null; + } + + async getValueSuggestions(field: IField, query: string): Promise { + return []; + } + + async isTimeAware(): Promise { + return false; + } + + isFilterByMapBounds(): boolean { + return false; + } + + getMinZoom() { + return MIN_ZOOM; + } + + getMaxZoom() { + return MAX_ZOOM; + } +} diff --git a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts index 8b64480f92961..77f8d88a8c0ab 100644 --- a/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts +++ b/x-pack/plugins/maps/public/layers/sources/xyz_tms_source/xyz_tms_source.ts @@ -13,6 +13,7 @@ import { AbstractTMSSource } from '../tms_source'; import { LayerDescriptor, XYZTMSSourceDescriptor } from '../../../../common/descriptor_types'; import { Attribution, ImmutableSourceProperty } from '../source'; import { XYZTMSSourceConfig } from './xyz_tms_editor'; +import { ILayer } from '../../layer'; export const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', { defaultMessage: 'Tile Map Service', @@ -48,7 +49,7 @@ export class XYZTMSSource extends AbstractTMSSource { ]; } - createDefaultLayer(options?: LayerDescriptor): TileLayer { + createDefaultLayer(options?: LayerDescriptor): ILayer { const layerDescriptor: LayerDescriptor = TileLayer.createDescriptor({ sourceDescriptor: this._descriptor, ...options, diff --git a/x-pack/plugins/maps/public/layers/styles/abstract_style.js b/x-pack/plugins/maps/public/layers/styles/abstract_style.js deleted file mode 100644 index 3e7a3dbf7ed20..0000000000000 --- a/x-pack/plugins/maps/public/layers/styles/abstract_style.js +++ /dev/null @@ -1,29 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export class AbstractStyle { - getDescriptorWithMissingStylePropsRemoved(/* nextOrdinalFields */) { - return { - hasChanges: false, - }; - } - - async pluckStyleMetaFromSourceDataRequest(/* sourceDataRequest */) { - return {}; - } - - getDescriptor() { - return this._descriptor; - } - - renderEditor(/* { layer, onStyleDescriptorChange } */) { - return null; - } - - getSourceFieldNames() { - return []; - } -} diff --git a/x-pack/plugins/maps/public/layers/styles/heatmap/heatmap_style.js b/x-pack/plugins/maps/public/layers/styles/heatmap/heatmap_style.js index d769fe0da9ec2..1fa24943c5e51 100644 --- a/x-pack/plugins/maps/public/layers/styles/heatmap/heatmap_style.js +++ b/x-pack/plugins/maps/public/layers/styles/heatmap/heatmap_style.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { AbstractStyle } from '../abstract_style'; +import { AbstractStyle } from '../style'; import { HeatmapStyleEditor } from './components/heatmap_style_editor'; import { HeatmapLegend } from './components/legend/heatmap_legend'; import { DEFAULT_HEATMAP_COLOR_RAMP_NAME } from './components/heatmap_constants'; diff --git a/x-pack/plugins/maps/public/layers/styles/style.ts b/x-pack/plugins/maps/public/layers/styles/style.ts new file mode 100644 index 0000000000000..38fdc36904412 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/styles/style.ts @@ -0,0 +1,59 @@ +/* + * 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 { ReactElement } from 'react'; +import { StyleDescriptor, StyleMetaDescriptor } from '../../../common/descriptor_types'; +import { ILayer } from '../layer'; +import { IField } from '../fields/field'; +import { DataRequest } from '../util/data_request'; + +export interface IStyle { + getDescriptor(): StyleDescriptor | null; + getDescriptorWithMissingStylePropsRemoved( + nextFields: IField[] + ): { hasChanges: boolean; nextStyleDescriptor?: StyleDescriptor }; + pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): StyleMetaDescriptor; + renderEditor({ + layer, + onStyleDescriptorChange, + }: { + layer: ILayer; + onStyleDescriptorChange: (styleDescriptor: StyleDescriptor) => void; + }): ReactElement | null; + getSourceFieldNames(): string[]; +} + +export class AbstractStyle implements IStyle { + readonly _descriptor: StyleDescriptor | null; + + constructor(descriptor: StyleDescriptor | null) { + this._descriptor = descriptor; + } + + getDescriptorWithMissingStylePropsRemoved( + nextFields: IField[] + ): { hasChanges: boolean; nextStyleDescriptor?: StyleDescriptor } { + return { + hasChanges: false, + }; + } + + pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): StyleMetaDescriptor { + return { fieldMeta: {} }; + } + + getDescriptor(): StyleDescriptor | null { + return this._descriptor; + } + + renderEditor(/* { layer, onStyleDescriptorChange } */) { + return null; + } + + getSourceFieldNames(): string[] { + return []; + } +} diff --git a/x-pack/plugins/maps/public/layers/styles/tile/tile_style.ts b/x-pack/plugins/maps/public/layers/styles/tile/tile_style.ts new file mode 100644 index 0000000000000..f658d0821edf2 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/styles/tile/tile_style.ts @@ -0,0 +1,16 @@ +/* + * 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 { AbstractStyle } from '../style'; +import { LAYER_STYLE_TYPE } from '../../../../common/constants'; + +export class TileStyle extends AbstractStyle { + constructor() { + super({ + type: LAYER_STYLE_TYPE.TILE, + }); + } +} diff --git a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts index e010d5ac7d7a3..762322b8e09f9 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts +++ b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.d.ts @@ -7,24 +7,23 @@ import { IStyleProperty } from './properties/style_property'; import { IDynamicStyleProperty } from './properties/dynamic_style_property'; import { IVectorLayer } from '../../vector_layer'; import { IVectorSource } from '../../sources/vector_source'; +import { AbstractStyle, IStyle } from '../style'; import { VectorStyleDescriptor, VectorStylePropertiesDescriptor, } from '../../../../common/descriptor_types'; -export interface IVectorStyle { +export interface IVectorStyle extends IStyle { getAllStyleProperties(): IStyleProperty[]; - getDescriptor(): VectorStyleDescriptor; getDynamicPropertiesArray(): IDynamicStyleProperty[]; getSourceFieldNames(): string[]; } -export class VectorStyle implements IVectorStyle { +export class VectorStyle extends AbstractStyle implements IVectorStyle { static createDescriptor(properties: VectorStylePropertiesDescriptor): VectorStyleDescriptor; static createDefaultStyleProperties(mapColors: string[]): VectorStylePropertiesDescriptor; constructor(descriptor: VectorStyleDescriptor, source: IVectorSource, layer: IVectorLayer); getSourceFieldNames(): string[]; getAllStyleProperties(): IStyleProperty[]; - getDescriptor(): VectorStyleDescriptor; getDynamicPropertiesArray(): IDynamicStyleProperty[]; } diff --git a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.js b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.js index b044c98d44d41..5a4edd9c93a05 100644 --- a/x-pack/plugins/maps/public/layers/styles/vector/vector_style.js +++ b/x-pack/plugins/maps/public/layers/styles/vector/vector_style.js @@ -8,7 +8,7 @@ import _ from 'lodash'; import React from 'react'; import { VectorStyleEditor } from './components/vector_style_editor'; import { getDefaultProperties, LINE_STYLES, POLYGON_STYLES } from './vector_style_defaults'; -import { AbstractStyle } from '../abstract_style'; +import { AbstractStyle } from '../style'; import { GEO_JSON_TYPE, FIELD_ORIGIN, @@ -60,6 +60,7 @@ export class VectorStyle extends AbstractStyle { constructor(descriptor = {}, source, layer) { super(); + descriptor = descriptor === null ? {} : descriptor; this._source = source; this._layer = layer; this._descriptor = { diff --git a/x-pack/plugins/maps/public/layers/tile_layer.d.ts b/x-pack/plugins/maps/public/layers/tile_layer.d.ts index 53e8c388ee4c2..8a1ef0f172717 100644 --- a/x-pack/plugins/maps/public/layers/tile_layer.d.ts +++ b/x-pack/plugins/maps/public/layers/tile_layer.d.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AbstractLayer, ILayerArguments } from './layer'; +import { AbstractLayer } from './layer'; import { ITMSSource } from './sources/tms_source'; import { LayerDescriptor } from '../../common/descriptor_types'; -interface ITileLayerArguments extends ILayerArguments { +interface ITileLayerArguments { source: ITMSSource; layerDescriptor: LayerDescriptor; } diff --git a/x-pack/plugins/maps/public/layers/tile_layer.js b/x-pack/plugins/maps/public/layers/tile_layer.js index 2ac60e12d137a..baded3c287637 100644 --- a/x-pack/plugins/maps/public/layers/tile_layer.js +++ b/x-pack/plugins/maps/public/layers/tile_layer.js @@ -6,7 +6,8 @@ import { AbstractLayer } from './layer'; import _ from 'lodash'; -import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants'; +import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../common/constants'; +import { TileStyle } from './styles/tile/tile_style'; export class TileLayer extends AbstractLayer { static type = LAYER_TYPE.TILE; @@ -15,9 +16,14 @@ export class TileLayer extends AbstractLayer { const tileLayerDescriptor = super.createDescriptor(options, mapColors); tileLayerDescriptor.type = TileLayer.type; tileLayerDescriptor.alpha = _.get(options, 'alpha', 1); + tileLayerDescriptor.style = { type: LAYER_STYLE_TYPE.TILE }; return tileLayerDescriptor; } + constructor({ source, layerDescriptor }) { + super({ source, layerDescriptor, style: new TileStyle() }); + } + async syncData({ startLoading, stopLoading, onLoadError, dataFilters }) { if (!this.isVisible() || !this.showAtZoomLevel(dataFilters.zoom)) { return; diff --git a/x-pack/plugins/maps/public/layers/tile_layer.test.ts b/x-pack/plugins/maps/public/layers/tile_layer.test.ts index f8c2fd9db60fa..a7e8be9fc4b46 100644 --- a/x-pack/plugins/maps/public/layers/tile_layer.test.ts +++ b/x-pack/plugins/maps/public/layers/tile_layer.test.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { TileLayer } from './tile_layer'; +// eslint-disable-next-line max-classes-per-file +import { ITileLayerArguments, TileLayer } from './tile_layer'; import { SOURCE_TYPES } from '../../common/constants'; import { XYZTMSSourceDescriptor } from '../../common/descriptor_types'; import { ITMSSource, AbstractTMSSource } from './sources/tms_source'; @@ -38,10 +39,13 @@ class MockTileSource extends AbstractTMSSource implements ITMSSource { describe('TileLayer', () => { it('should use display-label from source', async () => { const source = new MockTileSource(sourceDescriptor); - const layer: ILayer = new TileLayer({ + + const args: ITileLayerArguments = { source, layerDescriptor: { id: 'layerid', sourceDescriptor }, - }); + }; + + const layer: ILayer = new TileLayer(args); expect(await source.getDisplayName()).toEqual(await layer.getDisplayName()); }); diff --git a/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx b/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx index c47cae5641e56..06c5ef579b221 100644 --- a/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx +++ b/x-pack/plugins/maps/public/layers/tiled_vector_layer.tsx @@ -20,7 +20,7 @@ export class TiledVectorLayer extends VectorLayer { static type = LAYER_TYPE.TILED_VECTOR; static createDescriptor( - descriptor: VectorLayerDescriptor, + descriptor: Partial, mapColors: string[] ): VectorLayerDescriptor { const layerDescriptor = super.createDescriptor(descriptor, mapColors); diff --git a/x-pack/plugins/maps/public/layers/vector_layer.d.ts b/x-pack/plugins/maps/public/layers/vector_layer.d.ts index 3d5b8054ff3fd..efc1f3011c687 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.d.ts +++ b/x-pack/plugins/maps/public/layers/vector_layer.d.ts @@ -19,7 +19,7 @@ import { IVectorStyle } from './styles/vector/vector_style'; import { IField } from './fields/field'; import { SyncContext } from '../actions/map_actions'; -type VectorLayerArguments = { +export type VectorLayerArguments = { source: IVectorSource; joins?: IJoin[]; layerDescriptor: VectorLayerDescriptor; @@ -33,14 +33,12 @@ export interface IVectorLayer extends ILayer { } export class VectorLayer extends AbstractLayer implements IVectorLayer { + protected readonly _style: IVectorStyle; static createDescriptor( options: Partial, mapColors?: string[] ): VectorLayerDescriptor; - protected readonly _source: IVectorSource; - protected readonly _style: IVectorStyle; - constructor(options: VectorLayerArguments); getLayerTypeIconName(): string; getFields(): Promise; diff --git a/x-pack/plugins/maps/public/layers/vector_layer.js b/x-pack/plugins/maps/public/layers/vector_layer.js index c5947a63587ea..17b7f8152d76d 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.js +++ b/x-pack/plugins/maps/public/layers/vector_layer.js @@ -484,6 +484,8 @@ export class VectorLayer extends AbstractLayer { try { startLoading(dataRequestId, requestToken, nextMeta); const layerName = await this.getDisplayName(source); + + //todo: cast source to ESSource when migrating to TS const styleMeta = await source.loadStylePropsMeta( layerName, style, diff --git a/x-pack/plugins/maps/public/layers/vector_tile_layer.js b/x-pack/plugins/maps/public/layers/vector_tile_layer.js index c620ec6c56dc3..fc7812a2c86c7 100644 --- a/x-pack/plugins/maps/public/layers/vector_tile_layer.js +++ b/x-pack/plugins/maps/public/layers/vector_tile_layer.js @@ -6,7 +6,7 @@ import { TileLayer } from './tile_layer'; import _ from 'lodash'; -import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE } from '../../common/constants'; +import { SOURCE_DATA_ID_ORIGIN, LAYER_TYPE, LAYER_STYLE_TYPE } from '../../common/constants'; import { isRetina } from '../meta'; import { addSpriteSheetToMapFromImageData, @@ -28,6 +28,7 @@ export class VectorTileLayer extends TileLayer { const tileLayerDescriptor = super.createDescriptor(options); tileLayerDescriptor.type = VectorTileLayer.type; tileLayerDescriptor.alpha = _.get(options, 'alpha', 1); + tileLayerDescriptor.style = { type: LAYER_STYLE_TYPE.TILE }; return tileLayerDescriptor; } From 578d20fba88f4b03ce167ff7b522394e5d534bd4 Mon Sep 17 00:00:00 2001 From: Henry Harding Date: Wed, 22 Apr 2020 12:22:46 -0400 Subject: [PATCH 05/35] Ingest overview page (#63214) (#63978) * use fixed table layout * added markup structure / css for overview page * add flyout and links to other pages * add "alpha" messaging at bottom of all pages * attrs instead of defaultProps on styled components * use FormattedMessage on alpha messaging component * remove leftover code * remove unused import Co-authored-by: Elastic Machine --- .../components/alpha_messaging.tsx | 37 ++++ .../ingest_manager/components/index.ts | 1 + .../ingest_manager/layouts/default.tsx | 4 + .../ingest_manager/layouts/with_header.tsx | 2 + .../ingest_manager/layouts/without_header.tsx | 2 + .../sections/overview/index.tsx | 204 +++++++++++++++++- 6 files changed, 246 insertions(+), 4 deletions(-) create mode 100644 x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx new file mode 100644 index 0000000000000..0f3ddee29fa44 --- /dev/null +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/alpha_messaging.tsx @@ -0,0 +1,37 @@ +/* + * 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 React from 'react'; +import styled from 'styled-components'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiText } from '@elastic/eui'; + +const Message = styled(EuiText).attrs(props => ({ + color: 'subdued', + textAlign: 'center', +}))` + padding: ${props => props.theme.eui.paddingSizes.m}; +`; + +export const AlphaMessaging: React.FC<{}> = () => ( + +

+ + + + + {' – '} + + +

+
+); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts index 5551bff2c8bde..bdc8f350f7108 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/components/index.ts @@ -6,3 +6,4 @@ export { Loading } from './loading'; export { Error } from './error'; export { Header, HeaderProps } from './header'; +export { AlphaMessaging } from './alpha_messaging'; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx index 26f2c85a291a3..f797c509bfca0 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/default.tsx @@ -8,6 +8,7 @@ import styled from 'styled-components'; import { EuiTabs, EuiTab, EuiFlexGroup, EuiFlexItem, EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { Section } from '../sections'; +import { AlphaMessaging } from '../components'; import { useLink, useConfig } from '../hooks'; import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH } from '../constants'; @@ -19,6 +20,8 @@ interface Props { const Container = styled.div` min-height: calc(100vh - ${props => props.theme.eui.euiHeaderChildSize}); background: ${props => props.theme.eui.euiColorEmptyShade}; + display: flex; + flex-direction: column; `; const Nav = styled.nav` @@ -80,6 +83,7 @@ export const DefaultLayout: React.FunctionComponent = ({ section, childre {children} + ); }; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx index d5ce5e17ad84e..b7ba003e32e88 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/with_header.tsx @@ -10,6 +10,8 @@ import { Header, HeaderProps } from '../components'; const Page = styled(EuiPage)` background: ${props => props.theme.eui.euiColorEmptyShade}; + flex: 1; + align-items: flex-start; `; interface Props extends HeaderProps { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/without_header.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/without_header.tsx index cad98c5a0a7e1..9f9fa03942c09 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/without_header.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/layouts/without_header.tsx @@ -9,6 +9,8 @@ import { EuiPage, EuiPageBody, EuiSpacer } from '@elastic/eui'; const Page = styled(EuiPage)` background: ${props => props.theme.eui.euiColorEmptyShade}; + flex: 1; + align-items: flex-start; `; interface Props { diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx index ea6b045f504ec..05d150fd9ae23 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/overview/index.tsx @@ -3,12 +3,71 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { + EuiButton, + EuiButtonEmpty, + EuiPanel, + EuiText, + EuiTitle, + EuiDescriptionList, + EuiDescriptionListDescription, + EuiDescriptionListTitle, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { WithHeaderLayout } from '../../layouts'; +import { useLink, useGetAgentConfigs } from '../../hooks'; +import { AgentEnrollmentFlyout } from '../fleet/agent_list_page/components'; +import { EPM_PATH, FLEET_PATH, AGENT_CONFIG_PATH } from '../../constants'; + +const OverviewPanel = styled(EuiPanel).attrs(props => ({ + paddingSize: 'm', +}))` + header { + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid ${props => props.theme.eui.euiColorLightShade}; + margin: -${props => props.theme.eui.paddingSizes.m} -${props => props.theme.eui.paddingSizes.m} + ${props => props.theme.eui.paddingSizes.m}; + padding: ${props => props.theme.eui.paddingSizes.s} ${props => props.theme.eui.paddingSizes.m}; + } + + h2 { + padding: ${props => props.theme.eui.paddingSizes.xs} 0; + } +`; + +const OverviewStats = styled(EuiDescriptionList).attrs(props => ({ + compressed: true, + textStyle: 'reverse', + type: 'column', +}))` + & > * { + margin-top: ${props => props.theme.eui.paddingSizes.s} !important; + + &:first-child, + &:nth-child(2) { + margin-top: 0 !important; + } + } +`; export const IngestManagerOverview: React.FunctionComponent = () => { + // Agent enrollment flyout state + const [isEnrollmentFlyoutOpen, setIsEnrollmentFlyoutOpen] = useState(false); + + // Agent configs required for enrollment flyout + const agentConfigsRequest = useGetAgentConfigs({ + page: 1, + perPage: 1000, + }); + const agentConfigs = agentConfigsRequest.data ? agentConfigsRequest.data.items : []; + return ( {

} - /> + rightColumn={ + + + setIsEnrollmentFlyoutOpen(true)}> + + + + + } + > + {isEnrollmentFlyoutOpen && ( + setIsEnrollmentFlyoutOpen(false)} + /> + )} + + + + +
+ +

+ +

+
+ + + +
+ + Total available + 999 + Installed + 1 + Updated available + 0 + +
+
+ + + +
+ +

+ +

+
+ + + +
+ + Total configs + 1 + Data sources + 1 + +
+
+ + + +
+ +

+ +

+
+ + + +
+ + Total agents + 0 + Active + 0 + Offline + 0 + Error + 0 + +
+
+ + + +
+ +

+ +

+
+ + + +
+ + Data streams + 0 + Name spaces + 0 + Total size + 0 MB + +
+
+
+
); }; From d06844706e833f96a56106f62e113286c2d0d776 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 22 Apr 2020 12:24:37 -0400 Subject: [PATCH 06/35] [Uptime] Add cert API request and runtime type checking (#63062) (#63914) * Add cert API request and runtime type checking. * Collapse on sha256 field instead of common_name. * Add basic wildcard search capabilities. * Support searching. * Update fields and queries, remove server response validation. * Update API to utilize x509 fields. * Add new fields to certs API request, provide defaults. * Add api test for cert api. * Add unload command to certs test. * Extract API params interface to io-ts type. * Rename a functional test. * Fix broken type. Co-authored-by: Elastic Machine --- .../uptime/common/constants/rest_api.ts | 1 + .../uptime/common/runtime_types/certs.ts | 42 + .../uptime/common/runtime_types/index.ts | 1 + .../lib/requests/__tests__/get_certs.test.ts | 208 ++ .../uptime/server/lib/requests/get_certs.ts | 135 + .../uptime/server/lib/requests/index.ts | 1 + .../server/lib/requests/uptime_requests.ts | 3 + .../plugins/uptime/server/rest_api/certs.ts | 54 + .../plugins/uptime/server/rest_api/index.ts | 2 + .../api_integration/apis/uptime/rest/certs.ts | 89 + .../api_integration/apis/uptime/rest/index.ts | 5 +- .../es_archives/uptime/blank/mappings.json | 3301 ++++++++++++----- 12 files changed, 2876 insertions(+), 966 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts create mode 100644 x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts create mode 100644 x-pack/plugins/uptime/server/lib/requests/get_certs.ts create mode 100644 x-pack/plugins/uptime/server/rest_api/certs.ts create mode 100644 x-pack/test/api_integration/apis/uptime/rest/certs.ts diff --git a/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts b/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts index 9721d396625fc..169d175f02d3b 100644 --- a/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts +++ b/x-pack/legacy/plugins/uptime/common/constants/rest_api.ts @@ -5,6 +5,7 @@ */ export enum API_URLS { + CERTS = '/api/uptime/certs', INDEX_PATTERN = `/api/uptime/index_pattern`, INDEX_STATUS = '/api/uptime/index_status', MONITOR_LIST = `/api/uptime/monitor/list`, diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts b/x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts new file mode 100644 index 0000000000000..e8be67abf3a44 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/common/runtime_types/certs.ts @@ -0,0 +1,42 @@ +/* + * 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 * as t from 'io-ts'; + +export const GetCertsParamsType = t.intersection([ + t.type({ + from: t.string, + to: t.string, + index: t.number, + size: t.number, + }), + t.partial({ + search: t.string, + }), +]); + +export type GetCertsParams = t.TypeOf; + +export const CertType = t.intersection([ + t.type({ + monitors: t.array( + t.partial({ + name: t.string, + id: t.string, + }) + ), + sha256: t.string, + }), + t.partial({ + certificate_not_valid_after: t.string, + certificate_not_valid_before: t.string, + common_name: t.string, + issuer: t.string, + sha1: t.string, + }), +]); + +export type Cert = t.TypeOf; diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts b/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts index 652d60cbe304d..78aab3806ae04 100644 --- a/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts +++ b/x-pack/legacy/plugins/uptime/common/runtime_types/index.ts @@ -5,6 +5,7 @@ */ export * from './alerts'; +export * from './certs'; export * from './common'; export * from './monitor'; export * from './overview_filters'; 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 new file mode 100644 index 0000000000000..539344dfca791 --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_certs.test.ts @@ -0,0 +1,208 @@ +/* + * 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 { getCerts } from '../get_certs'; + +describe('getCerts', () => { + let mockHits: any; + let mockCallES: jest.Mock; + + beforeEach(() => { + mockHits = [ + { + _index: 'heartbeat-8.0.0-2020.04.16-000001', + _id: 'DJwmhHEBnyP8RKDrEYVK', + _score: 0, + _source: { + tls: { + certificate_not_valid_before: '2019-08-16T01:40:25.000Z', + server: { + x509: { + subject: { + common_name: 'r2.shared.global.fastly.net', + }, + issuer: { + common_name: 'GlobalSign CloudSSL CA - SHA256 - G3', + }, + }, + hash: { + sha1: 'b7b4b89ef0d0caf39d223736f0fdbb03c7b426f1', + sha256: '12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d', + }, + }, + certificate_not_valid_after: '2020-07-16T03:15:39.000Z', + }, + monitor: { + name: 'Real World Test', + id: 'real-world-test', + }, + }, + fields: { + 'tls.server.hash.sha256': [ + '12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d', + ], + }, + inner_hits: { + monitors: { + hits: { + total: { + value: 32, + relation: 'eq', + }, + max_score: null, + hits: [ + { + _index: 'heartbeat-8.0.0-2020.04.16-000001', + _id: 'DJwmhHEBnyP8RKDrEYVK', + _score: null, + _source: { + monitor: { + name: 'Real World Test', + id: 'real-world-test', + }, + }, + fields: { + 'monitor.id': ['real-world-test'], + }, + sort: ['real-world-test'], + }, + ], + }, + }, + }, + }, + ]; + mockCallES = jest.fn(); + mockCallES.mockImplementation(() => ({ + hits: { + hits: mockHits, + }, + })); + }); + + it('parses query result and returns expected values', async () => { + const result = await getCerts({ + callES: mockCallES, + dynamicSettings: { heartbeatIndices: 'heartbeat*' }, + index: 1, + from: 'now-2d', + to: 'now+1h', + search: 'my_common_name', + size: 30, + }); + expect(result).toMatchInlineSnapshot(` + Array [ + Object { + "certificate_not_valid_after": "2020-07-16T03:15:39.000Z", + "certificate_not_valid_before": "2019-08-16T01:40:25.000Z", + "common_name": "r2.shared.global.fastly.net", + "issuer": "GlobalSign CloudSSL CA - SHA256 - G3", + "monitors": Array [ + Object { + "id": "real-world-test", + "name": "Real World Test", + }, + ], + "sha1": "b7b4b89ef0d0caf39d223736f0fdbb03c7b426f1", + "sha256": "12b00d04db0db8caa302bfde043e88f95baceb91e86ac143e93830b4bbec726d", + }, + ] + `); + expect(mockCallES.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "search", + Object { + "body": Object { + "_source": Array [ + "monitor.id", + "monitor.name", + "tls.server.x509.issuer.common_name", + "tls.server.x509.subject.common_name", + "tls.server.hash.sha1", + "tls.server.hash.sha256", + "tls.certificate_not_valid_before", + "tls.certificate_not_valid_after", + ], + "collapse": Object { + "field": "tls.server.hash.sha256", + "inner_hits": Object { + "_source": Object { + "includes": Array [ + "monitor.id", + "monitor.name", + ], + }, + "collapse": Object { + "field": "monitor.id", + }, + "name": "monitors", + "sort": Array [ + Object { + "monitor.id": "asc", + }, + ], + }, + }, + "from": 1, + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "exists": Object { + "field": "tls", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "gte": "now-2d", + "lte": "now+1h", + }, + }, + }, + ], + "should": Array [ + Object { + "wildcard": Object { + "tls.server.issuer": Object { + "value": "*my_common_name*", + }, + }, + }, + Object { + "wildcard": Object { + "tls.common_name": Object { + "value": "*my_common_name*", + }, + }, + }, + Object { + "wildcard": Object { + "monitor.id": Object { + "value": "*my_common_name*", + }, + }, + }, + Object { + "wildcard": Object { + "monitor.name": Object { + "value": "*my_common_name*", + }, + }, + }, + ], + }, + }, + "size": 30, + }, + "index": "heartbeat*", + }, + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/uptime/server/lib/requests/get_certs.ts b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts new file mode 100644 index 0000000000000..4f99fbe94d54c --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/requests/get_certs.ts @@ -0,0 +1,135 @@ +/* + * 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 { UMElasticsearchQueryFn } from '../adapters'; +import { Cert, GetCertsParams } from '../../../../../legacy/plugins/uptime/common/runtime_types'; + +export const getCerts: UMElasticsearchQueryFn = async ({ + callES, + dynamicSettings, + index, + from, + to, + search, + size, +}) => { + const searchWrapper = `*${search}*`; + const params: any = { + index: dynamicSettings.heartbeatIndices, + body: { + from: index, + size, + query: { + bool: { + filter: [ + { + exists: { + field: 'tls', + }, + }, + { + range: { + '@timestamp': { + gte: from, + lte: to, + }, + }, + }, + ], + }, + }, + _source: [ + 'monitor.id', + 'monitor.name', + 'tls.server.x509.issuer.common_name', + 'tls.server.x509.subject.common_name', + 'tls.server.hash.sha1', + 'tls.server.hash.sha256', + 'tls.certificate_not_valid_before', + 'tls.certificate_not_valid_after', + ], + collapse: { + field: 'tls.server.hash.sha256', + inner_hits: { + _source: { + includes: ['monitor.id', 'monitor.name'], + }, + collapse: { + field: 'monitor.id', + }, + name: 'monitors', + sort: [{ 'monitor.id': 'asc' }], + }, + }, + }, + }; + + if (search) { + params.body.query.bool.should = [ + { + wildcard: { + 'tls.server.issuer': { + value: searchWrapper, + }, + }, + }, + { + wildcard: { + 'tls.common_name': { + value: searchWrapper, + }, + }, + }, + { + wildcard: { + 'monitor.id': { + value: searchWrapper, + }, + }, + }, + { + wildcard: { + 'monitor.name': { + value: searchWrapper, + }, + }, + }, + ]; + } + + const result = await callES('search', params); + const formatted = (result?.hits?.hits ?? []).map((hit: any) => { + const { + _source: { + tls: { + server: { + x509: { + issuer: { common_name: issuer }, + subject: { common_name }, + }, + hash: { sha1, sha256 }, + }, + certificate_not_valid_after, + certificate_not_valid_before, + }, + }, + } = hit; + const monitors = hit.inner_hits.monitors.hits.hits.map((monitor: any) => ({ + name: monitor._source?.monitor.name, + id: monitor._source?.monitor.id, + })); + return { + monitors, + certificate_not_valid_after, + certificate_not_valid_before, + issuer, + sha1, + sha256, + common_name, + }; + }); + return formatted; +}; diff --git a/x-pack/plugins/uptime/server/lib/requests/index.ts b/x-pack/plugins/uptime/server/lib/requests/index.ts index 6317f665d377f..243bb089cc7b4 100644 --- a/x-pack/plugins/uptime/server/lib/requests/index.ts +++ b/x-pack/plugins/uptime/server/lib/requests/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +export { getCerts } from './get_certs'; export { getFilterBar, GetFilterBarParams } from './get_filter_bar'; export { getUptimeIndexPattern as getIndexPattern } from './get_index_pattern'; export { getLatestMonitor, GetLatestMonitorParams } from './get_latest_monitor'; diff --git a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts index e9a7aa94dd3aa..84154429b9188 100644 --- a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts +++ b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts @@ -9,6 +9,7 @@ import { HistogramResult, Ping, PingsResponse as PingResults, + GetCertsParams, GetPingsParams, } from '../../../../../legacy/plugins/uptime/common/runtime_types'; import { @@ -28,6 +29,7 @@ import { MonitorLocations, Snapshot, StatesIndexStatus, + Cert, } from '../../../../../legacy/plugins/uptime/common/runtime_types'; import { GetMonitorStatesResult } from './get_monitor_states'; import { GetSnapshotCountParams } from './get_snapshot_counts'; @@ -36,6 +38,7 @@ import { MonitorDurationResult } from '../../../../../legacy/plugins/uptime/comm type ESQ = UMElasticsearchQueryFn; export interface UptimeRequests { + getCerts: ESQ; getFilterBar: ESQ; getIndexPattern: ESQ<{}, {}>; getLatestMonitor: ESQ; diff --git a/x-pack/plugins/uptime/server/rest_api/certs.ts b/x-pack/plugins/uptime/server/rest_api/certs.ts new file mode 100644 index 0000000000000..31fb3f4ab96a7 --- /dev/null +++ b/x-pack/plugins/uptime/server/rest_api/certs.ts @@ -0,0 +1,54 @@ +/* + * 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 { schema } from '@kbn/config-schema'; +import { UMServerLibs } from '../lib/lib'; +import { UMRestApiRouteFactory } from '.'; +import { API_URLS } from '../../../../legacy/plugins/uptime/common/constants/rest_api'; + +const DEFAULT_INDEX = 0; +const DEFAULT_SIZE = 25; +const DEFAULT_FROM = 'now-1d'; +const DEFAULT_TO = 'now'; + +export const createGetCertsRoute: UMRestApiRouteFactory = (libs: UMServerLibs) => ({ + method: 'GET', + path: API_URLS.CERTS, + validate: { + query: schema.object({ + from: schema.maybe(schema.string()), + to: schema.maybe(schema.string()), + search: schema.maybe(schema.string()), + index: schema.maybe(schema.number()), + size: schema.maybe(schema.number()), + }), + }, + writeAccess: false, + options: { + tags: ['access:uptime-read'], + }, + handler: async ({ callES, dynamicSettings }, _context, request, response): Promise => { + const index = request.query?.index ?? DEFAULT_INDEX; + const size = request.query?.size ?? DEFAULT_SIZE; + const from = request.query?.from ?? DEFAULT_FROM; + const to = request.query?.to ?? DEFAULT_TO; + const { search } = request.query; + + return response.ok({ + body: { + certs: await libs.requests.getCerts({ + callES, + dynamicSettings, + index, + search, + size, + from, + to, + }), + }, + }); + }, +}); diff --git a/x-pack/plugins/uptime/server/rest_api/index.ts b/x-pack/plugins/uptime/server/rest_api/index.ts index ae1e499dcc26c..a7a63342d11d4 100644 --- a/x-pack/plugins/uptime/server/rest_api/index.ts +++ b/x-pack/plugins/uptime/server/rest_api/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { createGetCertsRoute } from './certs'; import { createGetOverviewFilters } from './overview_filters'; import { createGetPingHistogramRoute, createGetPingsRoute } from './pings'; import { createGetDynamicSettingsRoute, createPostDynamicSettingsRoute } from './dynamic_settings'; @@ -23,6 +24,7 @@ export { createRouteWithAuth } from './create_route_with_auth'; export { uptimeRouteWrapper } from './uptime_route_wrapper'; export const restApiRoutes: UMRestApiRouteFactory[] = [ + createGetCertsRoute, createGetOverviewFilters, createGetPingsRoute, createGetIndexPatternRoute, diff --git a/x-pack/test/api_integration/apis/uptime/rest/certs.ts b/x-pack/test/api_integration/apis/uptime/rest/certs.ts new file mode 100644 index 0000000000000..7510ea3f34d28 --- /dev/null +++ b/x-pack/test/api_integration/apis/uptime/rest/certs.ts @@ -0,0 +1,89 @@ +/* + * 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 expect from '@kbn/expect'; +import moment from 'moment'; +import { isRight } from 'fp-ts/lib/Either'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { API_URLS } from '../../../../../legacy/plugins/uptime/common/constants'; +import { CertType } from '../../../../../legacy/plugins/uptime/common/runtime_types'; +import { makeChecksWithStatus } from './helper/make_checks'; + +export default function({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const legacyEsService = getService('legacyEs'); + const esArchiver = getService('esArchiver'); + + describe('certs api', () => { + describe('empty index', async () => { + it('returns empty array for no data', async () => { + const apiResponse = await supertest.get(API_URLS.CERTS); + expect(JSON.stringify(apiResponse.body)).to.eql('{"certs":[]}'); + }); + }); + + describe('when data is present', async () => { + const now = moment(); + const cnva = now.add(6, 'months').toISOString(); + const cnvb = now.subtract(23, 'weeks').toISOString(); + const monitorId = 'monitor1'; + before(async () => { + makeChecksWithStatus( + legacyEsService, + monitorId, + 3, + 1, + 10000, + { + tls: { + certificate_not_valid_after: cnva, + certificate_not_valid_before: cnvb, + server: { + x509: { + issuer: { + common_name: 'issuer-common-name', + }, + subject: { + common_name: 'subject-common-name', + }, + }, + hash: { + sha1: 'fewjio23r3', + sha256: 'few9023fijoefw', + }, + }, + }, + }, + 'up', + (d: any) => d + ); + }); + after('unload test docs', () => { + esArchiver.unload('uptime/blank'); + }); + + it('retrieves expected cert data', async () => { + const apiResponse = await supertest.get(API_URLS.CERTS); + const { body } = apiResponse; + + expect(body.certs).not.to.be(undefined); + expect(Array.isArray(body.certs)).to.be(true); + expect(body.certs).to.have.length(1); + + const decoded = CertType.decode(body.certs[0]); + expect(isRight(decoded)).to.be(true); + + const cert = body.certs[0]; + expect(Array.isArray(cert.monitors)).to.be(true); + expect(cert.monitors[0]).to.eql({ id: monitorId }); + expect(cert.certificate_not_valid_after).to.eql(cnva); + expect(cert.certificate_not_valid_before).to.eql(cnvb); + expect(cert.common_name).to.eql('subject-common-name'); + expect(cert.issuer).to.eql('issuer-common-name'); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/uptime/rest/index.ts b/x-pack/test/api_integration/apis/uptime/rest/index.ts index 29755bbddbc86..f77c14e960ab2 100644 --- a/x-pack/test/api_integration/apis/uptime/rest/index.ts +++ b/x-pack/test/api_integration/apis/uptime/rest/index.ts @@ -37,11 +37,12 @@ export default function({ getService, loadTestFile }: FtrProviderContext) { }); describe('with generated data', () => { - before('load heartbeat data', async () => await esArchiver.load('uptime/blank')); + beforeEach('load heartbeat data', async () => await esArchiver.loadIfNeeded('uptime/blank')); after('unload', async () => await esArchiver.unload('uptime/blank')); - loadTestFile(require.resolve('./snapshot')); + loadTestFile(require.resolve('./certs')); loadTestFile(require.resolve('./dynamic_settings')); + loadTestFile(require.resolve('./snapshot')); loadTestFile(require.resolve('./monitor_states_generated')); loadTestFile(require.resolve('./telemetry_collectors')); }); diff --git a/x-pack/test/functional/es_archives/uptime/blank/mappings.json b/x-pack/test/functional/es_archives/uptime/blank/mappings.json index 716026037e8f6..c97c8611482d7 100644 --- a/x-pack/test/functional/es_archives/uptime/blank/mappings.json +++ b/x-pack/test/functional/es_archives/uptime/blank/mappings.json @@ -12,79 +12,115 @@ "beat": "heartbeat", "version": "8.0.0" }, - "date_detection": false, "dynamic_templates": [ { "labels": { + "path_match": "labels.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" + } } }, { "container.labels": { + "path_match": "container.labels.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" + } } }, { "dns.answers": { + "path_match": "dns.answers.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "log.syslog": { + "path_match": "log.syslog.*", "match_mapping_type": "string", - "path_match": "dns.answers.*" + "mapping": { + "type": "keyword" + } } }, { - "fields": { + "network.inner": { + "path_match": "network.inner.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "observer.egress": { + "path_match": "observer.egress.*", "match_mapping_type": "string", - "path_match": "fields.*" + "mapping": { + "type": "keyword" + } } }, { - "docker.container.labels": { + "observer.ingress": { + "path_match": "observer.ingress.*", + "match_mapping_type": "string", "mapping": { "type": "keyword" - }, + } + } + }, + { + "fields": { + "path_match": "fields.*", + "match_mapping_type": "string", + "mapping": { + "type": "keyword" + } + } + }, + { + "docker.container.labels": { + "path_match": "docker.container.labels.*", "match_mapping_type": "string", - "path_match": "docker.container.labels.*" + "mapping": { + "type": "keyword" + } } }, { "kubernetes.labels.*": { + "path_match": "kubernetes.labels.*", "mapping": { "type": "keyword" - }, - "path_match": "kubernetes.labels.*" + } } }, { "kubernetes.annotations.*": { + "path_match": "kubernetes.annotations.*", "mapping": { "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" + } } }, { "strings_as_keyword": { + "match_mapping_type": "string", "mapping": { "ignore_above": 1024, "type": "keyword" - }, - "match_mapping_type": "string" + } } } ], + "date_detection": false, "properties": { "@timestamp": { "type": "date" @@ -92,28 +128,28 @@ "agent": { "properties": { "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -125,8 +161,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -135,8 +177,8 @@ "client": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -146,8 +188,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -157,41 +205,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -199,8 +247,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -218,43 +266,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -265,76 +337,97 @@ "account": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "availability_zone": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "image": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "instance": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "machine": { "properties": { "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "project": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "provider": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" } } }, "container": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "image": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "tag": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -342,20 +435,20 @@ "type": "object" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "runtime": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "destination": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -365,8 +458,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -376,41 +475,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -418,8 +517,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -437,43 +536,144 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "path": { + "type": "keyword", + "ignore_above": 1024 + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 } } } @@ -484,55 +684,63 @@ "answers": { "properties": { "class": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "data": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "ttl": { "type": "long" }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "header_flags": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "op_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "question": { "properties": { "class": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "registered_domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "subdomain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -540,12 +748,12 @@ "type": "ip" }, "response_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -563,51 +771,61 @@ "ecs": { "properties": { "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "error": { "properties": { "code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "message": { - "norms": false, - "type": "text" + "type": "text", + "norms": false + }, + "stack_trace": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "event": { "properties": { "action": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "category": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "created": { "type": "date" }, "dataset": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "duration": { "type": "long" @@ -616,32 +834,39 @@ "type": "date" }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "ingested": { + "type": "date" }, "kind": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "module": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "outcome": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "provider": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 }, "risk_score": { "type": "float" @@ -659,12 +884,16 @@ "type": "date" }, "timezone": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "url": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -676,6 +905,31 @@ "accessed": { "type": "date" }, + "attributes": { + "type": "keyword", + "ignore_above": 1024 + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, "created": { "type": "date" }, @@ -683,254 +937,318 @@ "type": "date" }, "device": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "directory": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "drive_letter": { + "type": "keyword", + "ignore_above": 1 }, "extension": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "gid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "group": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "hash": { "properties": { "md5": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha1": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha256": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha512": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "inode": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "mime_type": { + "type": "keyword", + "ignore_above": 1024 }, "mode": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "mtime": { "type": "date" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "owner": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "size": { "type": "long" }, "target_path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { "properties": { "md5": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha1": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha256": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "sha512": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "host": { "properties": { "architecture": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "containerized": { "type": "boolean" }, + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "ip": { "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "os": { "properties": { "build": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "codename": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uptime": { "type": "long" @@ -938,40 +1256,56 @@ "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -987,8 +1321,14 @@ "type": "long" }, "content": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, @@ -996,12 +1336,12 @@ "type": "long" }, "method": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "referrer": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1013,18 +1353,28 @@ "type": "long" }, "content": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "bytes": { "type": "long" }, + "redirects": { + "type": "keyword", + "ignore_above": 1024 + }, "status_code": { "type": "long" } @@ -1077,8 +1427,8 @@ } }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1096,17 +1446,33 @@ } } }, + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "jolokia": { "properties": { "agent": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1116,22 +1482,22 @@ "server": { "properties": { "product": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "vendor": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "url": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1147,20 +1513,20 @@ "container": { "properties": { "image": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "deployment": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1172,42 +1538,42 @@ } }, "namespace": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "node": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "pod": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "uid": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "replicaset": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "statefulset": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } } @@ -1219,28 +1585,76 @@ "log": { "properties": { "level": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "logger": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "function": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } } } }, "message": { - "norms": false, - "type": "text" + "type": "text", + "norms": false }, "monitor": { "properties": { "check_group": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "duration": { "properties": { @@ -1250,282 +1664,766 @@ } }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "ip": { "type": "ip" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "timespan": { "type": "date_range" + }, + "type": { + "type": "keyword", + "ignore_above": 1024 } } }, "network": { "properties": { "application": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "bytes": { "type": "long" }, "community_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "direction": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "forwarded_ip": { "type": "ip" }, "iana_number": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "packets": { "type": "long" }, "protocol": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "transport": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } } } }, "observer": { "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "zone": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hostname": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "zone": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "ip": { "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, + "product": { + "type": "keyword", + "ignore_above": 1024 + }, "serial_number": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "vendor": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "organization": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, - "process": { + "package": { "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" + "architecture": { + "type": "keyword", + "ignore_above": 1024 }, - "executable": { - "ignore_above": 1024, - "type": "keyword" + "build_version": { + "type": "keyword", + "ignore_above": 1024 }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } + "checksum": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "install_scope": { + "type": "keyword", + "ignore_above": 1024 + }, + "installed": { + "type": "date" + }, + "license": { + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, - "pgid": { - "type": "long" + "path": { + "type": "keyword", + "ignore_above": 1024 }, - "pid": { - "type": "long" + "reference": { + "type": "keyword", + "ignore_above": 1024 }, - "ppid": { + "size": { "type": "long" }, - "start": { - "type": "date" + "type": { + "type": "keyword", + "ignore_above": 1024 }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "process": { + "properties": { + "args": { + "type": "keyword", + "ignore_above": 1024 + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "entity_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "executable": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "parent": { + "properties": { + "args": { + "type": "keyword", + "ignore_above": 1024 + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "entity_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "executable": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha512": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "title": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + }, + "pe": { + "properties": { + "company": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "file_version": { + "type": "keyword", + "ignore_above": 1024 + }, + "original_file_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "product": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } } }, "title": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "uptime": { "type": "long" }, "working_directory": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "type": "keyword", + "ignore_above": 1024 + }, + "strings": { + "type": "keyword", + "ignore_above": 1024 + }, + "type": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "hive": { + "type": "keyword", + "ignore_above": 1024 + }, + "key": { + "type": "keyword", + "ignore_above": 1024 + }, + "path": { + "type": "keyword", + "ignore_above": 1024 + }, + "value": { + "type": "keyword", + "ignore_above": 1024 } } }, "related": { "properties": { + "hash": { + "type": "keyword", + "ignore_above": 1024 + }, "ip": { "type": "ip" + }, + "user": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1543,11 +2441,55 @@ } } }, + "rule": { + "properties": { + "author": { + "type": "keyword", + "ignore_above": 1024 + }, + "category": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "license": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + }, + "ruleset": { + "type": "keyword", + "ignore_above": 1024 + }, + "uuid": { + "type": "keyword", + "ignore_above": 1024 + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, "server": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -1557,8 +2499,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1568,41 +2516,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1610,8 +2558,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -1629,43 +2577,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1674,28 +2646,36 @@ "service": { "properties": { "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "node": { + "properties": { + "name": { + "type": "keyword", + "ignore_above": 1024 + } + } }, "state": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "type": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1717,8 +2697,8 @@ "source": { "properties": { "address": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "as": { "properties": { @@ -1728,8 +2708,14 @@ "organization": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1739,41 +2725,41 @@ "type": "long" }, "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "geo": { "properties": { "city_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "continent_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "country_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "location": { "type": "geo_point" }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "region_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1781,8 +2767,8 @@ "type": "ip" }, "mac": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "nat": { "properties": { @@ -1800,43 +2786,67 @@ "port": { "type": "long" }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 + }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } } @@ -1853,8 +2863,8 @@ } }, "tags": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "tcp": { "properties": { @@ -1878,11 +2888,57 @@ } } }, + "threat": { + "properties": { + "framework": { + "type": "keyword", + "ignore_above": 1024 + }, + "tactic": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "technique": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } + }, "timeseries": { "properties": { "instance": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1894,6 +2950,78 @@ "certificate_not_valid_before": { "type": "date" }, + "cipher": { + "type": "keyword", + "ignore_above": 1024 + }, + "client": { + "properties": { + "certificate": { + "type": "keyword", + "ignore_above": 1024 + }, + "certificate_chain": { + "type": "keyword", + "ignore_above": 1024 + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "issuer": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja3": { + "type": "keyword", + "ignore_above": 1024 + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject": { + "type": "keyword", + "ignore_above": 1024 + }, + "supported_ciphers": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "curve": { + "type": "keyword", + "ignore_above": 1024 + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "type": "keyword", + "ignore_above": 1024 + }, + "resumed": { + "type": "boolean" + }, "rtt": { "properties": { "handshake": { @@ -1904,6 +3032,114 @@ } } } + }, + "server": { + "properties": { + "certificate": { + "type": "keyword", + "ignore_above": 1024 + }, + "certificate_chain": { + "type": "keyword", + "ignore_above": 1024 + }, + "hash": { + "properties": { + "md5": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha1": { + "type": "keyword", + "ignore_above": 1024 + }, + "sha256": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "issuer": { + "type": "keyword", + "ignore_above": 1024 + }, + "ja3s": { + "type": "keyword", + "ignore_above": 1024 + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "type": "keyword", + "ignore_above": 1024 + }, + "x509": { + "properties": { + "issuer": { + "properties": { + "common_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "distinguished_name": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "not_after": { + "type": "keyword", + "ignore_above": 1024 + }, + "not_before": { + "type": "keyword", + "ignore_above": 1024 + }, + "public_key_algorithm": { + "type": "keyword", + "ignore_above": 1024 + }, + "public_key_exponent": { + "type": "long" + }, + "public_key_size": { + "type": "long" + }, + "serial_number": { + "type": "keyword", + "ignore_above": 1024 + }, + "signature_algorithm": { + "type": "keyword", + "ignore_above": 1024 + }, + "subject": { + "properties": { + "common_name": { + "type": "keyword", + "ignore_above": 1024 + }, + "distinguished_name": { + "type": "keyword", + "ignore_above": 1024 + } + } + } + } + } + } + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + }, + "version_protocol": { + "type": "keyword", + "ignore_above": 1024 } } }, @@ -1912,16 +3148,16 @@ "trace": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "transaction": { "properties": { "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } } @@ -1930,83 +3166,123 @@ "url": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "extension": { + "type": "keyword", + "ignore_above": 1024 }, "fragment": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "password": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "path": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "port": { "type": "long" }, "query": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "registered_domain": { + "type": "keyword", + "ignore_above": 1024 }, "scheme": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 + }, + "top_level_domain": { + "type": "keyword", + "ignore_above": 1024 }, "username": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "user": { "properties": { "domain": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "email": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full_name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "group": { "properties": { + "domain": { + "type": "keyword", + "ignore_above": 1024 + }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "hash": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "id": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 } } }, @@ -2015,370 +3291,467 @@ "device": { "properties": { "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "original": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "os": { "properties": { "family": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "full": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "kernel": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "name": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 }, "platform": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } }, "version": { - "ignore_above": 1024, - "type": "keyword" + "type": "keyword", + "ignore_above": 1024 } } - } - } - }, - "settings": { - "index": { - "mapping": { - "total_fields": { - "limit": "10000" + }, + "vlan": { + "properties": { + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "name": { + "type": "keyword", + "ignore_above": 1024 + } } }, - "number_of_replicas": "1", - "number_of_shards": "1", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.original", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "process.args", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.scheme", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "agent.hostname", - "error.type", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "jolokia.agent.version", - "jolokia.agent.id", - "jolokia.server.product", - "jolokia.server.version", - "jolokia.server.vendor", - "jolokia.url", - "monitor.type", - "monitor.name", - "monitor.id", - "monitor.status", - "monitor.check_group", - "http.response.body.hash", - "fields.*" - ] - }, - "refresh_interval": "5s" + "vulnerability": { + "properties": { + "category": { + "type": "keyword", + "ignore_above": 1024 + }, + "classification": { + "type": "keyword", + "ignore_above": 1024 + }, + "description": { + "type": "keyword", + "fields": { + "text": { + "type": "text", + "norms": false + } + }, + "ignore_above": 1024 + }, + "enumeration": { + "type": "keyword", + "ignore_above": 1024 + }, + "id": { + "type": "keyword", + "ignore_above": 1024 + }, + "reference": { + "type": "keyword", + "ignore_above": 1024 + }, + "report_id": { + "type": "keyword", + "ignore_above": 1024 + }, + "scanner": { + "properties": { + "vendor": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "type": "keyword", + "ignore_above": 1024 + } + } + }, + "severity": { + "type": "keyword", + "ignore_above": 1024 + } + } + } } } + }, + "settings": { + "index": { + "mapping": { + "total_fields": { + "limit": "10000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "query": { + "default_field": [ + "message", + "tags", + "agent.ephemeral_id", + "agent.id", + "agent.name", + "agent.type", + "agent.version", + "as.organization.name", + "client.address", + "client.as.organization.name", + "client.domain", + "client.geo.city_name", + "client.geo.continent_name", + "client.geo.country_iso_code", + "client.geo.country_name", + "client.geo.name", + "client.geo.region_iso_code", + "client.geo.region_name", + "client.mac", + "client.user.domain", + "client.user.email", + "client.user.full_name", + "client.user.group.id", + "client.user.group.name", + "client.user.hash", + "client.user.id", + "client.user.name", + "cloud.account.id", + "cloud.availability_zone", + "cloud.instance.id", + "cloud.instance.name", + "cloud.machine.type", + "cloud.provider", + "cloud.region", + "container.id", + "container.image.name", + "container.image.tag", + "container.name", + "container.runtime", + "destination.address", + "destination.as.organization.name", + "destination.domain", + "destination.geo.city_name", + "destination.geo.continent_name", + "destination.geo.country_iso_code", + "destination.geo.country_name", + "destination.geo.name", + "destination.geo.region_iso_code", + "destination.geo.region_name", + "destination.mac", + "destination.user.domain", + "destination.user.email", + "destination.user.full_name", + "destination.user.group.id", + "destination.user.group.name", + "destination.user.hash", + "destination.user.id", + "destination.user.name", + "dns.answers.class", + "dns.answers.data", + "dns.answers.name", + "dns.answers.type", + "dns.header_flags", + "dns.id", + "dns.op_code", + "dns.question.class", + "dns.question.name", + "dns.question.registered_domain", + "dns.question.type", + "dns.response_code", + "dns.type", + "ecs.version", + "error.code", + "error.id", + "error.message", + "event.action", + "event.category", + "event.code", + "event.dataset", + "event.hash", + "event.id", + "event.kind", + "event.module", + "event.original", + "event.outcome", + "event.provider", + "event.timezone", + "event.type", + "file.device", + "file.directory", + "file.extension", + "file.gid", + "file.group", + "file.hash.md5", + "file.hash.sha1", + "file.hash.sha256", + "file.hash.sha512", + "file.inode", + "file.mode", + "file.name", + "file.owner", + "file.path", + "file.target_path", + "file.type", + "file.uid", + "geo.city_name", + "geo.continent_name", + "geo.country_iso_code", + "geo.country_name", + "geo.name", + "geo.region_iso_code", + "geo.region_name", + "group.id", + "group.name", + "hash.md5", + "hash.sha1", + "hash.sha256", + "hash.sha512", + "host.architecture", + "host.geo.city_name", + "host.geo.continent_name", + "host.geo.country_iso_code", + "host.geo.country_name", + "host.geo.name", + "host.geo.region_iso_code", + "host.geo.region_name", + "host.hostname", + "host.id", + "host.mac", + "host.name", + "host.os.family", + "host.os.full", + "host.os.kernel", + "host.os.name", + "host.os.platform", + "host.os.version", + "host.type", + "host.user.domain", + "host.user.email", + "host.user.full_name", + "host.user.group.id", + "host.user.group.name", + "host.user.hash", + "host.user.id", + "host.user.name", + "http.request.body.content", + "http.request.method", + "http.request.referrer", + "http.response.body.content", + "http.version", + "log.level", + "log.logger", + "log.original", + "network.application", + "network.community_id", + "network.direction", + "network.iana_number", + "network.name", + "network.protocol", + "network.transport", + "network.type", + "observer.geo.city_name", + "observer.geo.continent_name", + "observer.geo.country_iso_code", + "observer.geo.country_name", + "observer.geo.name", + "observer.geo.region_iso_code", + "observer.geo.region_name", + "observer.hostname", + "observer.mac", + "observer.os.family", + "observer.os.full", + "observer.os.kernel", + "observer.os.name", + "observer.os.platform", + "observer.os.version", + "observer.serial_number", + "observer.type", + "observer.vendor", + "observer.version", + "organization.id", + "organization.name", + "os.family", + "os.full", + "os.kernel", + "os.name", + "os.platform", + "os.version", + "process.args", + "process.executable", + "process.hash.md5", + "process.hash.sha1", + "process.hash.sha256", + "process.hash.sha512", + "process.name", + "process.thread.name", + "process.title", + "process.working_directory", + "server.address", + "server.as.organization.name", + "server.domain", + "server.geo.city_name", + "server.geo.continent_name", + "server.geo.country_iso_code", + "server.geo.country_name", + "server.geo.name", + "server.geo.region_iso_code", + "server.geo.region_name", + "server.mac", + "server.user.domain", + "server.user.email", + "server.user.full_name", + "server.user.group.id", + "server.user.group.name", + "server.user.hash", + "server.user.id", + "server.user.name", + "service.ephemeral_id", + "service.id", + "service.name", + "service.state", + "service.type", + "service.version", + "source.address", + "source.as.organization.name", + "source.domain", + "source.geo.city_name", + "source.geo.continent_name", + "source.geo.country_iso_code", + "source.geo.country_name", + "source.geo.name", + "source.geo.region_iso_code", + "source.geo.region_name", + "source.mac", + "source.user.domain", + "source.user.email", + "source.user.full_name", + "source.user.group.id", + "source.user.group.name", + "source.user.hash", + "source.user.id", + "source.user.name", + "tracing.trace.id", + "tracing.transaction.id", + "url.domain", + "url.fragment", + "url.full", + "url.original", + "url.password", + "url.path", + "url.query", + "url.scheme", + "url.username", + "user.domain", + "user.email", + "user.full_name", + "user.group.id", + "user.group.name", + "user.hash", + "user.id", + "user.name", + "user_agent.device.name", + "user_agent.name", + "user_agent.original", + "user_agent.os.family", + "user_agent.os.full", + "user_agent.os.kernel", + "user_agent.os.name", + "user_agent.os.platform", + "user_agent.os.version", + "user_agent.version", + "agent.hostname", + "error.type", + "timeseries.instance", + "cloud.project.id", + "cloud.image.id", + "host.os.build", + "host.os.codename", + "kubernetes.pod.name", + "kubernetes.pod.uid", + "kubernetes.namespace", + "kubernetes.node.name", + "kubernetes.replicaset.name", + "kubernetes.deployment.name", + "kubernetes.statefulset.name", + "kubernetes.container.name", + "kubernetes.container.image", + "jolokia.agent.version", + "jolokia.agent.id", + "jolokia.server.product", + "jolokia.server.version", + "jolokia.server.vendor", + "jolokia.url", + "monitor.type", + "monitor.name", + "monitor.id", + "monitor.status", + "monitor.check_group", + "http.response.body.hash", + "fields.*" + ] + }, + "refresh_interval": "5s" + } } } From 00ad5ec93840621d79672a2b0a76ac991d474b8b Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Wed, 22 Apr 2020 09:35:00 -0700 Subject: [PATCH 07/35] [7.x] Move CCR out of legacy (#62890) (#64191) * Convert common/services and server/lib to TypeScript. Update Jest tests. - Remove deserializeAutoFollowPattern behavior that returned an empty object if the pattern was undefined. * Localize mocks with the component integration tests. * Update API unit tests to use NP mocks. - Break up test files. - Use inline mocked ES response instead of fixture files. - Move remaining fixture files into client integration tests directory. * Make API route validation more strict. * Publish isUiDisabled as part of Remote Clusters contract. * Default trackUiMetric service to be a no-op. * Remove security dependency. - Fix license check so that CCR won't render if the license is invalid. - Fix server security check to be more precise by checking if ES has security disabled. * Render timestamp for autofollow errors. --- .eslintrc.js | 2 +- .sass-lint.yml | 1 + x-pack/.i18nrc.json | 2 +- x-pack/index.js | 2 - .../common/constants/base_path.ts | 11 - .../common/constants/index.ts | 10 - .../common/constants/settings.ts | 18 - .../follower_index_serialization.test.js.snap | 128 ------- .../auto_follow_pattern_serialization.js | 41 -- .../follower_index_serialization.test.js | 175 --------- .../fixtures/auto_follow_pattern.js | 49 --- .../fixtures/es_errors.js | 45 --- .../fixtures/follower_index.js | 216 ----------- .../fixtures/index.js | 16 - .../cross_cluster_replication/index.js | 57 --- .../public/index.scss | 13 - .../public/main.html | 3 - .../public/np_ready/app/_app.scss | 14 - .../public/np_ready/app/index.js | 25 -- .../app/services/documentation_links.ts | 22 -- .../np_ready/app/services/notifications.ts | 20 - .../np_ready/app/services/track_ui_metric.js | 27 -- .../np_ready/extend_index_management.ts | 28 -- .../public/np_ready/plugin.ts | 44 --- .../public/register_routes.js | 94 ----- .../cross_cluster_replication_data.ts | 36 -- .../server/np_ready/index.ts | 11 - .../call_with_request_factory.js | 20 - .../lib/call_with_request_factory/index.js | 7 - .../lib/check_license/check_license.js | 70 ---- .../__tests__/wrap_es_error.test.js | 33 -- .../__tests__/is_es_error_factory.js | 44 --- .../is_es_error_factory.ts | 18 - .../license_pre_routing_factory.test.ts | 64 ---- .../license_pre_routing_factory.ts | 32 -- .../lib/register_license_checker/index.js | 7 - .../register_license_checker.js | 21 -- .../server/np_ready/plugin.ts | 38 -- .../api/__jest__/auto_follow_pattern.test.js | 330 ---------------- .../api/__jest__/follower_index.test.js | 312 --------------- .../np_ready/routes/api/__jest__/helpers.ts | 37 -- .../routes/api/auto_follow_pattern.ts | 301 --------------- .../server/np_ready/routes/api/ccr.ts | 112 ------ .../np_ready/routes/api/follower_index.ts | 357 ------------------ .../routes/map_to_kibana_http_error.ts | 26 -- .../server/np_ready/routes/types.ts | 13 - .../common/constants/index.ts | 44 +++ .../follower_index_serialization.test.ts.snap | 128 +++++++ ...auto_follow_pattern_serialization.test.ts} | 16 +- .../auto_follow_pattern_serialization.ts | 38 ++ .../follower_index_serialization.test.ts | 224 +++++++++++ .../services/follower_index_serialization.ts} | 27 +- .../common/services/utils.test.ts} | 0 .../common/services/utils.ts} | 11 +- .../cross_cluster_replication/common/types.ts | 186 +++++++++ .../cross_cluster_replication/kibana.json | 17 + .../auto_follow_pattern_add.test.js | 7 +- .../auto_follow_pattern_edit.test.js | 6 +- .../auto_follow_pattern_list.test.js | 15 +- .../fixtures/auto_follow_pattern.ts | 28 ++ .../fixtures/follower_index.ts | 70 ++++ .../follower_index_add.test.js | 9 +- .../follower_index_edit.test.js | 8 +- .../follower_indices_list.test.js | 6 +- .../auto_follow_pattern_add.helpers.js | 6 +- .../auto_follow_pattern_edit.helpers.js | 6 +- .../auto_follow_pattern_list.helpers.js | 6 +- .../client_integration/helpers/constants.js | 0 .../helpers/follower_index_add.helpers.js | 6 +- .../helpers/follower_index_edit.helpers.js | 6 +- .../helpers/follower_index_list.helpers.js | 6 +- .../helpers/home.helpers.js | 8 +- .../helpers/http_requests.js | 0 .../client_integration/helpers/index.js | 0 .../helpers/setup_environment.js | 2 +- .../__jest__/client_integration/home.test.js | 6 +- .../mocks}/breadcrumbs.mock.ts | 4 +- .../client_integration/mocks}/index.ts | 3 +- .../mocks/track_ui_metric.mock.ts | 13 + .../public/app/app.tsx} | 42 +-- .../auto_follow_pattern_form.test.js.snap | 0 ...to_follow_pattern_action_menu.container.ts | 0 .../auto_follow_pattern_action_menu.tsx | 2 +- .../auto_follow_pattern_action_menu/index.ts | 0 .../auto_follow_pattern_delete_provider.d.ts | 0 .../auto_follow_pattern_delete_provider.js | 2 +- .../components/auto_follow_pattern_form.js | 12 +- .../auto_follow_pattern_form.test.js | 0 .../auto_follow_pattern_indices_preview.js | 0 .../auto_follow_pattern_page_title.js | 0 .../auto_follow_pattern_request_flyout.js | 2 +- .../follower_index_form.test.js.snap | 0 .../advanced_settings_fields.js | 0 .../follower_index_form.js | 4 +- .../follower_index_form.test.js | 0 .../follower_index_request_flyout.js | 2 +- .../components/follower_index_form/index.js | 0 .../components/follower_index_page_title.js | 0 .../follower_index_pause_provider.js | 2 +- .../follower_index_resume_provider.js | 4 +- .../follower_index_unfollow_provider.js | 2 +- .../public}/app/components/form_entry_row.js | 0 .../public/app/components/index.d.ts} | 2 +- .../public}/app/components/index.js | 0 .../components/remote_clusters_form_field.js | 4 +- .../components/remote_clusters_provider.js | 0 .../public}/app/components/section_error.js | 0 .../public}/app/components/section_loading.js | 0 .../app/components/section_unauthorized.js | 0 .../public/app/constants/api.ts} | 0 .../public/app/constants/index.ts} | 0 .../public/app/constants/sections.ts} | 0 .../public/app/constants/ui_metric.ts} | 0 .../public/app/index.tsx | 52 +++ .../auto_follow_pattern_add.container.js | 0 .../auto_follow_pattern_add.js | 0 .../sections/auto_follow_pattern_add/index.js | 0 .../auto_follow_pattern_edit.container.js | 19 +- .../auto_follow_pattern_edit.js | 2 +- .../auto_follow_pattern_edit/index.js | 0 .../follower_index_add.container.js | 0 .../follower_index_add/follower_index_add.js | 0 .../app/sections/follower_index_add/index.js | 0 .../follower_index_edit.container.js | 0 .../follower_index_edit.js | 2 +- .../app/sections/follower_index_edit/index.js | 0 .../auto_follow_pattern_list.container.js | 0 .../auto_follow_pattern_list.js | 2 +- .../auto_follow_pattern_table.container.js | 0 .../auto_follow_pattern_table.js | 6 +- .../auto_follow_pattern_table/index.js | 0 .../detail_panel/detail_panel.container.js | 0 .../components/detail_panel/detail_panel.js | 5 +- .../components/detail_panel/index.js | 0 .../components/index.js | 0 .../home/auto_follow_pattern_list/index.js | 0 .../components/context_menu/context_menu.js | 2 +- .../components/context_menu/index.js | 0 .../detail_panel/detail_panel.container.js | 0 .../components/detail_panel/detail_panel.js | 3 +- .../components/detail_panel/index.js | 0 .../follower_indices_table.container.js | 0 .../follower_indices_table.js | 6 +- .../follower_indices_table/index.js | 0 .../follower_indices_list/components/index.js | 0 .../follower_indices_list.container.js | 0 .../follower_indices_list.js | 2 +- .../home/follower_indices_list/index.js | 0 .../app/sections/home/home.container.js | 0 .../public}/app/sections/home/home.js | 4 +- .../public}/app/sections/home/index.js | 0 .../public/app/sections/index.d.ts} | 9 +- .../public}/app/sections/index.js | 0 ...uto_follow_pattern_validators.test.js.snap | 0 .../public}/app/services/api.js | 4 +- .../app/services/auto_follow_errors.js | 3 +- .../app/services/auto_follow_errors.test.js | 0 .../app/services/auto_follow_pattern.js | 0 .../app/services/auto_follow_pattern.test.js | 0 .../auto_follow_pattern_validators.js | 4 +- .../auto_follow_pattern_validators.test.js | 0 .../public}/app/services/breadcrumbs.ts | 22 +- .../app/services/documentation_links.ts | 16 + .../follower_index_default_settings.js | 2 +- .../app/services/get_remote_cluster_name.js | 0 .../public}/app/services/input_validation.js | 2 +- .../public/app/services/notifications.ts | 18 + .../public}/app/services/query_params.js | 0 .../public/app/services/routing.d.ts} | 2 +- .../public}/app/services/routing.js | 13 +- .../public/app/services/track_ui_metric.ts | 37 ++ .../public}/app/services/utils.js | 0 .../public}/app/services/utils.test.js | 0 .../public}/app/store/action_types.js | 0 .../public}/app/store/actions/api.js | 0 .../app/store/actions/auto_follow_pattern.js | 18 +- .../public}/app/store/actions/ccr.js | 0 .../app/store/actions/follower_index.js | 21 +- .../public}/app/store/actions/index.js | 0 .../public/app/store/index.d.ts} | 2 +- .../public}/app/store/index.js | 0 .../public}/app/store/reducers/api.js | 0 .../public}/app/store/reducers/api.test.js | 0 .../app/store/reducers/auto_follow_pattern.js | 0 .../app/store/reducers/follower_index.js | 0 .../public}/app/store/reducers/index.js | 0 .../public}/app/store/reducers/stats.js | 0 .../public}/app/store/selectors/index.js | 0 .../public}/app/store/store.js | 0 .../public}/index.ts | 5 +- .../public/plugin.ts | 102 +++++ .../cross_cluster_replication/public/types.ts | 25 ++ .../server/client/elasticsearch_ccr.ts} | 2 +- .../server/config.ts | 16 + .../cross_cluster_replication/server/index.ts | 19 + .../ccr_stats_serialization.test.ts.snap} | 2 + .../lib/ccr_stats_serialization.test.ts} | 2 + .../server/lib/ccr_stats_serialization.ts} | 19 +- .../server/lib/format_es_error.ts} | 13 + .../server}/lib/is_es_error.ts | 0 .../server/plugin.ts | 139 +++++++ .../routes/api/auto_follow_pattern/index.ts | 24 ++ .../register_create_route.test.ts | 74 ++++ .../register_create_route.ts | 77 ++++ .../register_delete_route.test.ts | 87 +++++ .../register_delete_route.ts | 67 ++++ .../register_fetch_route.test.ts | 69 ++++ .../register_fetch_route.ts | 43 +++ .../register_get_route.test.ts | 67 ++++ .../auto_follow_pattern/register_get_route.ts | 54 +++ .../register_pause_route.test.ts | 86 +++++ .../register_pause_route.ts | 66 ++++ .../register_resume_route.test.ts | 86 +++++ .../register_resume_route.ts | 66 ++++ .../register_update_route.test.ts | 64 ++++ .../register_update_route.ts | 60 +++ .../api/cross_cluster_replication/index.ts | 14 + .../register_permissions_route.ts | 70 ++++ .../register_stats_route.ts | 42 +++ .../server/routes/api/follower_index/index.ts | 24 ++ .../register_create_route.test.ts | 54 +++ .../follower_index/register_create_route.ts | 65 ++++ .../register_fetch_route.test.ts | 160 ++++++++ .../follower_index/register_fetch_route.ts | 62 +++ .../follower_index/register_get_route.test.ts | 159 ++++++++ .../api/follower_index/register_get_route.ts | 78 ++++ .../register_pause_route.test.ts | 86 +++++ .../follower_index/register_pause_route.ts | 64 ++++ .../register_resume_route.test.ts | 86 +++++ .../follower_index/register_resume_route.ts | 64 ++++ .../register_unfollow_route.test.ts | 109 ++++++ .../follower_index/register_unfollow_route.ts | 95 +++++ .../follower_index/register_update_route.ts | 93 +++++ .../server/routes/api/test_lib.ts | 23 ++ .../server/routes/index.ts} | 13 +- .../server/services/add_base_path.ts} | 6 +- .../server/services}/index.ts | 3 +- .../server/services/license.ts | 93 +++++ .../cross_cluster_replication/server/types.ts | 28 ++ .../application/services/notification.ts | 8 +- .../plugins/remote_clusters/public/index.ts | 3 + .../plugins/remote_clusters/public/plugin.ts | 11 +- .../plugins/remote_clusters/server/index.ts | 1 + .../plugins/remote_clusters/server/plugin.ts | 18 +- .../translations/translations/ja-JP.json | 5 +- .../translations/translations/zh-CN.json | 5 +- .../auto_follow_pattern.helpers.js | 20 +- .../auto_follow_pattern.js | 57 +-- .../cross_cluster_replication/fixtures.js | 7 - .../follower_indices.js | 8 +- .../management/index_management/indices.js | 8 +- 251 files changed, 3968 insertions(+), 3230 deletions(-) delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/constants/base_path.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/constants/index.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/constants/settings.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.js.snap delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/fixtures/auto_follow_pattern.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/fixtures/es_errors.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/fixtures/follower_index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/fixtures/index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/index.scss delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/main.html delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/_app.scss delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/documentation_links.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/notifications.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/track_ui_metric.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/public/register_routes.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/cross_cluster_replication_data.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/index.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/call_with_request_factory.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/check_license/check_license.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/__tests__/wrap_es_error.test.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/__tests__/is_es_error_factory.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/is_es_error_factory.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/__jest__/license_pre_routing_factory.test.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/license_pre_routing_factory.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/index.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/register_license_checker.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/auto_follow_pattern.test.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/follower_index.test.js delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/helpers.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/auto_follow_pattern.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/ccr.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/follower_index.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/map_to_kibana_http_error.ts delete mode 100644 x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/types.ts create mode 100644 x-pack/plugins/cross_cluster_replication/common/constants/index.ts create mode 100644 x-pack/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.ts.snap rename x-pack/{legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.js => plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.ts} (85%) create mode 100644 x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.ts create mode 100644 x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.ts rename x-pack/{legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.js => plugins/cross_cluster_replication/common/services/follower_index_serialization.ts} (87%) rename x-pack/{legacy/plugins/cross_cluster_replication/common/services/utils.test.js => plugins/cross_cluster_replication/common/services/utils.test.ts} (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/common/services/utils.js => plugins/cross_cluster_replication/common/services/utils.ts} (62%) create mode 100644 x-pack/plugins/cross_cluster_replication/common/types.ts create mode 100644 x-pack/plugins/cross_cluster_replication/kibana.json rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/auto_follow_pattern_add.test.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/auto_follow_pattern_edit.test.js (95%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/auto_follow_pattern_list.test.js (97%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts create mode 100644 x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/follower_index_add.test.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/follower_index_edit.test.js (95%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/follower_indices_list.test.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js (76%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js (82%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js (92%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/constants.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/follower_index_add.helpers.js (79%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/follower_index_edit.helpers.js (84%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/follower_index_list.helpers.js (90%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/home.helpers.js (68%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/http_requests.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/helpers/setup_environment.js (91%) rename x-pack/{legacy/plugins/cross_cluster_replication => plugins/cross_cluster_replication/public}/__jest__/client_integration/home.test.js (93%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/services => plugins/cross_cluster_replication/public/__jest__/client_integration/mocks}/breadcrumbs.mock.ts (70%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory => plugins/cross_cluster_replication/public/__jest__/client_integration/mocks}/index.ts (79%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/track_ui_metric.mock.ts rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/app.js => plugins/cross_cluster_replication/public/app/app.tsx} (89%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/__snapshots__/auto_follow_pattern_form.test.js.snap (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.container.ts (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_action_menu/auto_follow_pattern_action_menu.tsx (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_action_menu/index.ts (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_delete_provider.d.ts (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_delete_provider.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_form.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_form.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_indices_preview.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_page_title.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/auto_follow_pattern_request_flyout.js (96%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/__snapshots__/follower_index_form.test.js.snap (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/advanced_settings_fields.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/follower_index_form.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/follower_index_form.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/follower_index_request_flyout.js (96%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_form/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_page_title.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_pause_provider.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_resume_provider.js (97%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/follower_index_unfollow_provider.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/form_entry_row.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/index.ts => plugins/cross_cluster_replication/public/app/components/index.d.ts} (83%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/remote_clusters_form_field.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/remote_clusters_provider.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/section_error.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/section_loading.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/components/section_unauthorized.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/api.js => plugins/cross_cluster_replication/public/app/constants/api.ts} (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/index.js => plugins/cross_cluster_replication/public/app/constants/index.ts} (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/sections.js => plugins/cross_cluster_replication/public/app/constants/sections.ts} (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/ui_metric.js => plugins/cross_cluster_replication/public/app/constants/ui_metric.ts} (100%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/app/index.tsx rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_add/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js (80%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/auto_follow_pattern_edit/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_add/follower_index_add.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_add/follower_index_add.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_add/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_edit/follower_index_edit.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_edit/follower_index_edit.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/follower_index_edit/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js (97%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/detail_panel/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/components/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/auto_follow_pattern_list/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/context_menu/context_menu.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/context_menu/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/detail_panel/detail_panel.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/detail_panel/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/follower_indices_table/follower_indices_table.js (97%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/follower_indices_table/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/components/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/follower_indices_list.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/follower_indices_list.js (99%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/follower_indices_list/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/home.container.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/home.js (96%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/home/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/common/constants/app.ts => plugins/cross_cluster_replication/public/app/sections/index.d.ts} (50%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/sections/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/__snapshots__/auto_follow_pattern_validators.test.js.snap (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/api.js (98%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_errors.js (92%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_errors.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_pattern.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_pattern.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_pattern_validators.js (97%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/auto_follow_pattern_validators.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/breadcrumbs.ts (62%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/app/services/documentation_links.ts rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/follower_index_default_settings.js (89%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/get_remote_cluster_name.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/input_validation.js (97%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/app/services/notifications.ts rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/query_params.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/index.js => plugins/cross_cluster_replication/public/app/services/routing.d.ts} (87%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/routing.js (93%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/app/services/track_ui_metric.ts rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/utils.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/services/utils.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/action_types.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/actions/api.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/actions/auto_follow_pattern.js (95%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/actions/ccr.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/actions/follower_index.js (94%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/actions/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/check_license/index.js => plugins/cross_cluster_replication/public/app/store/index.d.ts} (83%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/api.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/api.test.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/auto_follow_pattern.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/follower_index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/reducers/stats.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/selectors/index.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/app/store/store.js (100%) rename x-pack/{legacy/plugins/cross_cluster_replication/public/np_ready => plugins/cross_cluster_replication/public}/index.ts (61%) create mode 100644 x-pack/plugins/cross_cluster_replication/public/plugin.ts create mode 100644 x-pack/plugins/cross_cluster_replication/public/types.ts rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/client/elasticsearch_ccr.js => plugins/cross_cluster_replication/server/client/elasticsearch_ccr.ts} (97%) create mode 100644 x-pack/plugins/cross_cluster_replication/server/config.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/index.ts rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/__snapshots__/ccr_stats_serialization.test.js.snap => plugins/cross_cluster_replication/server/lib/__snapshots__/ccr_stats_serialization.test.ts.snap} (93%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/ccr_stats_serialization.test.js => plugins/cross_cluster_replication/server/lib/ccr_stats_serialization.test.ts} (95%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/ccr_stats_serialization.js => plugins/cross_cluster_replication/server/lib/ccr_stats_serialization.ts} (77%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/wrap_es_error.ts => plugins/cross_cluster_replication/server/lib/format_es_error.ts} (90%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready => plugins/cross_cluster_replication/server}/lib/is_es_error.ts (100%) create mode 100644 x-pack/plugins/cross_cluster_replication/server/plugin.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/index.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_create_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_create_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_delete_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_delete_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_fetch_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_fetch_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_get_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_get_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_pause_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_pause_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_resume_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_resume_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_update_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/auto_follow_pattern/register_update_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/cross_cluster_replication/index.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/cross_cluster_replication/register_permissions_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/cross_cluster_replication/register_stats_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/index.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_create_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_create_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_fetch_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_fetch_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_get_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_get_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_pause_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_pause_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_resume_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_resume_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_unfollow_route.test.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_unfollow_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/follower_index/register_update_route.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/routes/api/test_lib.ts rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/routes/register_routes.ts => plugins/cross_cluster_replication/server/routes/index.ts} (52%) rename x-pack/{legacy/plugins/cross_cluster_replication/common/constants/plugin.ts => plugins/cross_cluster_replication/server/services/add_base_path.ts} (64%) rename x-pack/{legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory => plugins/cross_cluster_replication/server/services}/index.ts (74%) create mode 100644 x-pack/plugins/cross_cluster_replication/server/services/license.ts create mode 100644 x-pack/plugins/cross_cluster_replication/server/types.ts diff --git a/.eslintrc.js b/.eslintrc.js index bb978d629caca..89396e8252839 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -102,7 +102,7 @@ module.exports = { }, }, { - files: ['x-pack/legacy/plugins/cross_cluster_replication/**/*.{js,ts,tsx}'], + files: ['x-pack/plugins/cross_cluster_replication/**/*.{js,ts,tsx}'], rules: { 'jsx-a11y/click-events-have-key-events': 'off', }, diff --git a/.sass-lint.yml b/.sass-lint.yml index 677cafe576e62..6ee4b2143b052 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -9,6 +9,7 @@ files: - 'x-pack/legacy/plugins/canvas/**/*.s+(a|c)ss' - 'x-pack/plugins/triggers_actions_ui/**/*.s+(a|c)ss' - 'x-pack/plugins/lens/**/*.s+(a|c)ss' + - 'x-pack/plugins/cross_cluster_replication/**/*.s+(a|c)ss' - 'x-pack/legacy/plugins/maps/**/*.s+(a|c)ss' - 'x-pack/plugins/maps/**/*.s+(a|c)ss' ignore: diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index c8715ac3447bd..8e5563e4ff674 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -8,7 +8,7 @@ "xpack.apm": ["legacy/plugins/apm", "plugins/apm"], "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", - "xpack.crossClusterReplication": "legacy/plugins/cross_cluster_replication", + "xpack.crossClusterReplication": "plugins/cross_cluster_replication", "xpack.dashboardMode": "legacy/plugins/dashboard_mode", "xpack.data": "plugins/data_enhanced", "xpack.drilldowns": "plugins/drilldowns", diff --git a/x-pack/index.js b/x-pack/index.js index 1a78c24b1221b..43ae5c3e5c5dd 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -21,7 +21,6 @@ import { taskManager } from './legacy/plugins/task_manager'; import { rollup } from './legacy/plugins/rollup'; import { siem } from './legacy/plugins/siem'; import { remoteClusters } from './legacy/plugins/remote_clusters'; -import { crossClusterReplication } from './legacy/plugins/cross_cluster_replication'; import { upgradeAssistant } from './legacy/plugins/upgrade_assistant'; import { uptime } from './legacy/plugins/uptime'; import { encryptedSavedObjects } from './legacy/plugins/encrypted_saved_objects'; @@ -49,7 +48,6 @@ module.exports = function(kibana) { rollup(kibana), siem(kibana), remoteClusters(kibana), - crossClusterReplication(kibana), upgradeAssistant(kibana), uptime(kibana), encryptedSavedObjects(kibana), diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/base_path.ts b/x-pack/legacy/plugins/cross_cluster_replication/common/constants/base_path.ts deleted file mode 100644 index 0a948793e07db..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/base_path.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export const BASE_PATH = '/management/elasticsearch/cross_cluster_replication'; -export const BASE_PATH_REMOTE_CLUSTERS = '/management/elasticsearch/remote_clusters'; -export const API_BASE_PATH = '/api/cross_cluster_replication'; -export const API_REMOTE_CLUSTERS_BASE_PATH = '/api/remote_clusters'; -export const API_INDEX_MANAGEMENT_BASE_PATH = '/api/index_management'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/index.ts b/x-pack/legacy/plugins/cross_cluster_replication/common/constants/index.ts deleted file mode 100644 index 300afb4e2d2ff..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/index.ts +++ /dev/null @@ -1,10 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export * from './plugin'; -export * from './base_path'; -export * from './app'; -export * from './settings'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/settings.ts b/x-pack/legacy/plugins/cross_cluster_replication/common/constants/settings.ts deleted file mode 100644 index 0993a74c8f1fd..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/constants/settings.ts +++ /dev/null @@ -1,18 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export const FOLLOWER_INDEX_ADVANCED_SETTINGS = { - maxReadRequestOperationCount: 5120, - maxOutstandingReadRequests: 12, - maxReadRequestSize: '32mb', - maxWriteRequestOperationCount: 5120, - maxWriteRequestSize: '9223372036854775807b', - maxOutstandingWriteRequests: 9, - maxWriteBufferCount: 2147483647, - maxWriteBufferSize: '512mb', - maxRetryDelay: '500ms', - readPollTimeout: '1m', -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.js.snap b/x-pack/legacy/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.js.snap deleted file mode 100644 index d001459e8234d..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.js.snap +++ /dev/null @@ -1,128 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`[CCR] follower index serialization deserializeFollowerIndex() deserializes Elasticsearch follower index object 1`] = ` -Object { - "leaderIndex": undefined, - "maxOutstandingReadRequests": undefined, - "maxOutstandingWriteRequests": undefined, - "maxReadRequestOperationCount": undefined, - "maxReadRequestSize": undefined, - "maxRetryDelay": undefined, - "maxWriteBufferCount": undefined, - "maxWriteBufferSize": undefined, - "maxWriteRequestOperationCount": undefined, - "maxWriteRequestSize": undefined, - "name": undefined, - "readPollTimeout": undefined, - "remoteCluster": undefined, - "shards": Array [ - Object { - "bytesReadCount": undefined, - "failedReadRequestsCount": undefined, - "failedWriteRequestsCount": undefined, - "followerGlobalCheckpoint": undefined, - "followerMappingVersion": undefined, - "followerMaxSequenceNum": undefined, - "followerSettingsVersion": undefined, - "id": "shard 1", - "lastRequestedSequenceNum": undefined, - "leaderGlobalCheckpoint": undefined, - "leaderIndex": undefined, - "leaderMaxSequenceNum": undefined, - "operationsReadCount": undefined, - "operationsWrittenCount": undefined, - "outstandingReadRequestsCount": undefined, - "outstandingWriteRequestsCount": undefined, - "readExceptions": undefined, - "remoteCluster": undefined, - "successfulReadRequestCount": undefined, - "successfulWriteRequestsCount": undefined, - "timeSinceLastReadMs": undefined, - "totalReadRemoteExecTimeMs": undefined, - "totalReadTimeMs": undefined, - "totalWriteTimeMs": undefined, - "writeBufferOperationsCount": undefined, - "writeBufferSizeBytes": undefined, - }, - Object { - "bytesReadCount": undefined, - "failedReadRequestsCount": undefined, - "failedWriteRequestsCount": undefined, - "followerGlobalCheckpoint": undefined, - "followerMappingVersion": undefined, - "followerMaxSequenceNum": undefined, - "followerSettingsVersion": undefined, - "id": "shard 2", - "lastRequestedSequenceNum": undefined, - "leaderGlobalCheckpoint": undefined, - "leaderIndex": undefined, - "leaderMaxSequenceNum": undefined, - "operationsReadCount": undefined, - "operationsWrittenCount": undefined, - "outstandingReadRequestsCount": undefined, - "outstandingWriteRequestsCount": undefined, - "readExceptions": undefined, - "remoteCluster": undefined, - "successfulReadRequestCount": undefined, - "successfulWriteRequestsCount": undefined, - "timeSinceLastReadMs": undefined, - "totalReadRemoteExecTimeMs": undefined, - "totalReadTimeMs": undefined, - "totalWriteTimeMs": undefined, - "writeBufferOperationsCount": undefined, - "writeBufferSizeBytes": undefined, - }, - ], - "status": "active", -} -`; - -exports[`[CCR] follower index serialization deserializeShard() deserializes shard 1`] = ` -Object { - "bytesReadCount": "bytes read", - "failedReadRequestsCount": "failed read requests", - "failedWriteRequestsCount": "failed write requests", - "followerGlobalCheckpoint": "follower global checkpoint", - "followerMappingVersion": "follower mapping version", - "followerMaxSequenceNum": "follower max seq no", - "followerSettingsVersion": "follower settings version", - "id": "shard id", - "lastRequestedSequenceNum": "last requested seq no", - "leaderGlobalCheckpoint": "leader global checkpoint", - "leaderIndex": "leader index", - "leaderMaxSequenceNum": "leader max seq no", - "operationsReadCount": "operations read", - "operationsWrittenCount": "operations written", - "outstandingReadRequestsCount": "outstanding read requests", - "outstandingWriteRequestsCount": "outstanding write requests", - "readExceptions": Array [ - "read exception", - ], - "remoteCluster": "remote cluster", - "successfulReadRequestCount": "successful read requests", - "successfulWriteRequestsCount": "successful write requests", - "timeSinceLastReadMs": "time since last read millis", - "totalReadRemoteExecTimeMs": "total read remote exec time millis", - "totalReadTimeMs": "total read time millis", - "totalWriteTimeMs": "total write time millis", - "writeBufferOperationsCount": "write buffer operation count", - "writeBufferSizeBytes": "write buffer size in bytes", -} -`; - -exports[`[CCR] follower index serialization serializeFollowerIndex() serializes object to Elasticsearch follower index object 1`] = ` -Object { - "leader_index": "leader index", - "max_outstanding_read_requests": "foo", - "max_outstanding_write_requests": "foo", - "max_read_request_operation_count": "foo", - "max_read_request_size": "foo", - "max_retry_delay": "foo", - "max_write_buffer_count": "foo", - "max_write_buffer_size": "foo", - "max_write_request_operation_count": "foo", - "max_write_request_size": "foo", - "read_poll_timeout": "foo", - "remote_cluster": "remote cluster", -} -`; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.js b/x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.js deleted file mode 100644 index ae13c625a7d80..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.js +++ /dev/null @@ -1,41 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export const deserializeAutoFollowPattern = ( - { - name, - pattern: { - active, - // eslint-disable-next-line camelcase - remote_cluster, - // eslint-disable-next-line camelcase - leader_index_patterns, - // eslint-disable-next-line camelcase - follow_index_pattern, - }, - } = { - pattern: {}, - } -) => ({ - name, - active, - remoteCluster: remote_cluster, - leaderIndexPatterns: leader_index_patterns, - followIndexPattern: follow_index_pattern, -}); - -export const deserializeListAutoFollowPatterns = autoFollowPatterns => - autoFollowPatterns.map(deserializeAutoFollowPattern); - -export const serializeAutoFollowPattern = ({ - remoteCluster, - leaderIndexPatterns, - followIndexPattern, -}) => ({ - remote_cluster: remoteCluster, - leader_index_patterns: leaderIndexPatterns, - follow_index_pattern: followIndexPattern, -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.js b/x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.js deleted file mode 100644 index e1df917d899ad..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.js +++ /dev/null @@ -1,175 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - deserializeShard, - deserializeFollowerIndex, - deserializeListFollowerIndices, - serializeFollowerIndex, -} from './follower_index_serialization'; - -describe('[CCR] follower index serialization', () => { - describe('deserializeShard()', () => { - it('deserializes shard', () => { - const serializedShard = { - remote_cluster: 'remote cluster', - leader_index: 'leader index', - shard_id: 'shard id', - leader_global_checkpoint: 'leader global checkpoint', - leader_max_seq_no: 'leader max seq no', - follower_global_checkpoint: 'follower global checkpoint', - follower_max_seq_no: 'follower max seq no', - last_requested_seq_no: 'last requested seq no', - outstanding_read_requests: 'outstanding read requests', - outstanding_write_requests: 'outstanding write requests', - write_buffer_operation_count: 'write buffer operation count', - write_buffer_size_in_bytes: 'write buffer size in bytes', - follower_mapping_version: 'follower mapping version', - follower_settings_version: 'follower settings version', - total_read_time_millis: 'total read time millis', - total_read_remote_exec_time_millis: 'total read remote exec time millis', - successful_read_requests: 'successful read requests', - failed_read_requests: 'failed read requests', - operations_read: 'operations read', - bytes_read: 'bytes read', - total_write_time_millis: 'total write time millis', - successful_write_requests: 'successful write requests', - failed_write_requests: 'failed write requests', - operations_written: 'operations written', - read_exceptions: ['read exception'], - time_since_last_read_millis: 'time since last read millis', - }; - - expect(deserializeShard(serializedShard)).toMatchSnapshot(); - }); - }); - - describe('deserializeFollowerIndex()', () => { - it('deserializes Elasticsearch follower index object', () => { - const serializedFollowerIndex = { - index: 'follower index name', - status: 'active', - shards: [ - { - shard_id: 'shard 1', - }, - { - shard_id: 'shard 2', - }, - ], - }; - - expect(deserializeFollowerIndex(serializedFollowerIndex)).toMatchSnapshot(); - }); - }); - - describe('deserializeListFollowerIndices()', () => { - it('deserializes list of Elasticsearch follower index objects', () => { - const serializedFollowerIndexList = [ - { - follower_index: 'follower index 1', - remote_cluster: 'cluster 1', - leader_index: 'leader 1', - status: 'active', - parameters: { - max_read_request_operation_count: 1, - max_outstanding_read_requests: 1, - max_read_request_size: 1, - max_write_request_operation_count: 1, - max_write_request_size: 1, - max_outstanding_write_requests: 1, - max_write_buffer_count: 1, - max_write_buffer_size: 1, - max_retry_delay: 1, - read_poll_timeout: 1, - }, - shards: [], - }, - { - follower_index: 'follower index 2', - remote_cluster: 'cluster 2', - leader_index: 'leader 2', - status: 'paused', - parameters: { - max_read_request_operation_count: 2, - max_outstanding_read_requests: 2, - max_read_request_size: 2, - max_write_request_operation_count: 2, - max_write_request_size: 2, - max_outstanding_write_requests: 2, - max_write_buffer_count: 2, - max_write_buffer_size: 2, - max_retry_delay: 2, - read_poll_timeout: 2, - }, - shards: [], - }, - ]; - - const deserializedFollowerIndexList = [ - { - name: 'follower index 1', - remoteCluster: 'cluster 1', - leaderIndex: 'leader 1', - status: 'active', - maxReadRequestOperationCount: 1, - maxOutstandingReadRequests: 1, - maxReadRequestSize: 1, - maxWriteRequestOperationCount: 1, - maxWriteRequestSize: 1, - maxOutstandingWriteRequests: 1, - maxWriteBufferCount: 1, - maxWriteBufferSize: 1, - maxRetryDelay: 1, - readPollTimeout: 1, - shards: [], - }, - { - name: 'follower index 2', - remoteCluster: 'cluster 2', - leaderIndex: 'leader 2', - status: 'paused', - maxReadRequestOperationCount: 2, - maxOutstandingReadRequests: 2, - maxReadRequestSize: 2, - maxWriteRequestOperationCount: 2, - maxWriteRequestSize: 2, - maxOutstandingWriteRequests: 2, - maxWriteBufferCount: 2, - maxWriteBufferSize: 2, - maxRetryDelay: 2, - readPollTimeout: 2, - shards: [], - }, - ]; - - expect(deserializeListFollowerIndices(serializedFollowerIndexList)).toEqual( - deserializedFollowerIndexList - ); - }); - }); - - describe('serializeFollowerIndex()', () => { - it('serializes object to Elasticsearch follower index object', () => { - const deserializedFollowerIndex = { - remoteCluster: 'remote cluster', - leaderIndex: 'leader index', - maxReadRequestOperationCount: 'foo', - maxOutstandingReadRequests: 'foo', - maxReadRequestSize: 'foo', - maxWriteRequestOperationCount: 'foo', - maxWriteRequestSize: 'foo', - maxOutstandingWriteRequests: 'foo', - maxWriteBufferCount: 'foo', - maxWriteBufferSize: 'foo', - maxRetryDelay: 'foo', - readPollTimeout: 'foo', - }; - - expect(serializeFollowerIndex(deserializedFollowerIndex)).toMatchSnapshot(); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/auto_follow_pattern.js b/x-pack/legacy/plugins/cross_cluster_replication/fixtures/auto_follow_pattern.js deleted file mode 100644 index 804fe80cd27b4..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/auto_follow_pattern.js +++ /dev/null @@ -1,49 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getRandomString } from '../../../../test_utils'; - -export const getAutoFollowPatternMock = ( - name = getRandomString(), - remoteCluster = getRandomString(), - leaderIndexPatterns = [getRandomString()], - followIndexPattern = getRandomString() -) => ({ - name, - pattern: { - remote_cluster: remoteCluster, - leader_index_patterns: leaderIndexPatterns, - follow_index_pattern: followIndexPattern, - }, -}); - -export const getAutoFollowPatternListMock = (total = 3) => { - const list = { - patterns: [], - }; - - let i = total; - while (i--) { - list.patterns.push(getAutoFollowPatternMock()); - } - - return list; -}; - -// ----------------- -// Client test mock -// ----------------- -export const getAutoFollowPatternClientMock = ({ - name = getRandomString(), - remoteCluster = getRandomString(), - leaderIndexPatterns = [`${getRandomString()}-*`], - followIndexPattern = getRandomString(), -}) => ({ - name, - remoteCluster, - leaderIndexPatterns, - followIndexPattern, -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/es_errors.js b/x-pack/legacy/plugins/cross_cluster_replication/fixtures/es_errors.js deleted file mode 100644 index a042375e82715..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/es_errors.js +++ /dev/null @@ -1,45 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -/** - * Errors mocks to throw during development to help visualizing - * the different flows in the UI - * - * TODO: Consult the ES team and make sure the error shapes are correct - * for each statusCode. - */ - -const error400 = new Error('Something went wrong'); -error400.statusCode = 400; -error400.response = ` - { - "error": { - "root_cause": [ - { - "type": "x_content_parse_exception", - "reason": "[2:3] [put_auto_follow_pattern_request] unknown field [remote_clusterxxxxx], parser not found" - } - ], - "type": "x_content_parse_exception", - "reason": "[2:3] [put_auto_follow_pattern_request] unknown field [remote_clusterxxxxx], parser not found" - }, - "status": 400 -}`; - -const error403 = new Error('Unauthorized'); -error403.statusCode = 403; -error403.response = ` - { - "acknowledged": true, - "trial_was_started": false, - "error_message": "Operation failed: Trial was already activated." - } -`; - -export const esErrors = { - 400: error400, - 403: error403, -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/follower_index.js b/x-pack/legacy/plugins/cross_cluster_replication/fixtures/follower_index.js deleted file mode 100644 index 6c535a665978c..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/follower_index.js +++ /dev/null @@ -1,216 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -const Chance = require('chance'); // eslint-disable-line import/no-extraneous-dependencies -const chance = new Chance(); -import { getRandomString } from '../../../../test_utils'; - -const serializeShard = ({ - id, - remoteCluster, - leaderIndex, - leaderGlobalCheckpoint, - leaderMaxSequenceNum, - followerGlobalCheckpoint, - followerMaxSequenceNum, - lastRequestedSequenceNum, - outstandingReadRequestsCount, - outstandingWriteRequestsCount, - writeBufferOperationsCount, - writeBufferSizeBytes, - followerMappingVersion, - followerSettingsVersion, - totalReadTimeMs, - totalReadRemoteExecTimeMs, - successfulReadRequestCount, - failedReadRequestsCount, - operationsReadCount, - bytesReadCount, - totalWriteTimeMs, - successfulWriteRequestsCount, - failedWriteRequestsCount, - operationsWrittenCount, - readExceptions, - timeSinceLastReadMs, -}) => ({ - shard_id: id, - remote_cluster: remoteCluster, - leader_index: leaderIndex, - leader_global_checkpoint: leaderGlobalCheckpoint, - leader_max_seq_no: leaderMaxSequenceNum, - follower_global_checkpoint: followerGlobalCheckpoint, - follower_max_seq_no: followerMaxSequenceNum, - last_requested_seq_no: lastRequestedSequenceNum, - outstanding_read_requests: outstandingReadRequestsCount, - outstanding_write_requests: outstandingWriteRequestsCount, - write_buffer_operation_count: writeBufferOperationsCount, - write_buffer_size_in_bytes: writeBufferSizeBytes, - follower_mapping_version: followerMappingVersion, - follower_settings_version: followerSettingsVersion, - total_read_time_millis: totalReadTimeMs, - total_read_remote_exec_time_millis: totalReadRemoteExecTimeMs, - successful_read_requests: successfulReadRequestCount, - failed_read_requests: failedReadRequestsCount, - operations_read: operationsReadCount, - bytes_read: bytesReadCount, - total_write_time_millis: totalWriteTimeMs, - successful_write_requests: successfulWriteRequestsCount, - failed_write_requests: failedWriteRequestsCount, - operations_written: operationsWrittenCount, - read_exceptions: readExceptions, - time_since_last_read_millis: timeSinceLastReadMs, -}); - -export const getFollowerIndexStatsMock = ( - name = chance.string(), - shards = [ - { - id: chance.string(), - remoteCluster: chance.string(), - leaderIndex: chance.string(), - leaderGlobalCheckpoint: chance.integer(), - leaderMaxSequenceNum: chance.integer(), - followerGlobalCheckpoint: chance.integer(), - followerMaxSequenceNum: chance.integer(), - lastRequestedSequenceNum: chance.integer(), - outstandingReadRequestsCount: chance.integer(), - outstandingWriteRequestsCount: chance.integer(), - writeBufferOperationsCount: chance.integer(), - writeBufferSizeBytes: chance.integer(), - followerMappingVersion: chance.integer(), - followerSettingsVersion: chance.integer(), - totalReadTimeMs: chance.integer(), - totalReadRemoteExecTimeMs: chance.integer(), - successfulReadRequestCount: chance.integer(), - failedReadRequestsCount: chance.integer(), - operationsReadCount: chance.integer(), - bytesReadCount: chance.integer(), - totalWriteTimeMs: chance.integer(), - successfulWriteRequestsCount: chance.integer(), - failedWriteRequestsCount: chance.integer(), - operationsWrittenCount: chance.integer(), - readExceptions: [chance.string()], - timeSinceLastReadMs: chance.integer(), - }, - ] -) => ({ - index: name, - shards: shards.map(serializeShard), -}); - -export const getFollowerIndexListStatsMock = (total = 3, names) => { - const list = { - follow_stats: { - indices: [], - }, - }; - - for (let i = 0; i < total; i++) { - list.follow_stats.indices.push(getFollowerIndexStatsMock(names[i])); - } - - return list; -}; - -export const getFollowerIndexInfoMock = ( - name = chance.string(), - status = chance.string(), - parameters = { - maxReadRequestOperationCount: chance.string(), - maxOutstandingReadRequests: chance.string(), - maxReadRequestSize: chance.string(), - maxWriteRequestOperationCount: chance.string(), - maxWriteRequestSize: chance.string(), - maxOutstandingWriteRequests: chance.string(), - maxWriteBufferCount: chance.string(), - maxWriteBufferSize: chance.string(), - maxRetryDelay: chance.string(), - readPollTimeout: chance.string(), - } -) => { - return { - follower_index: name, - status, - max_read_request_operation_count: parameters.maxReadRequestOperationCount, - max_outstanding_read_requests: parameters.maxOutstandingReadRequests, - max_read_request_size: parameters.maxReadRequestSize, - max_write_request_operation_count: parameters.maxWriteRequestOperationCount, - max_write_request_size: parameters.maxWriteRequestSize, - max_outstanding_write_requests: parameters.maxOutstandingWriteRequests, - max_write_buffer_count: parameters.maxWriteBufferCount, - max_write_buffer_size: parameters.maxWriteBufferSize, - max_retry_delay: parameters.maxRetryDelay, - read_poll_timeout: parameters.readPollTimeout, - }; -}; - -export const getFollowerIndexListInfoMock = (total = 3) => { - const list = { - follower_indices: [], - }; - - for (let i = 0; i < total; i++) { - list.follower_indices.push(getFollowerIndexInfoMock()); - } - - return list; -}; - -// ----------------- -// Client test mock -// ----------------- - -export const getFollowerIndexMock = ({ - name = getRandomString(), - remoteCluster = getRandomString(), - leaderIndex = getRandomString(), - status = 'Active', -} = {}) => ({ - name, - remoteCluster, - leaderIndex, - status, - maxReadRequestOperationCount: chance.integer(), - maxOutstandingReadRequests: chance.integer(), - maxReadRequestSize: getRandomString({ length: 5 }), - maxWriteRequestOperationCount: chance.integer(), - maxWriteRequestSize: '9223372036854775807b', - maxOutstandingWriteRequests: chance.integer(), - maxWriteBufferCount: chance.integer(), - maxWriteBufferSize: getRandomString({ length: 5 }), - maxRetryDelay: getRandomString({ length: 5 }), - readPollTimeout: getRandomString({ length: 5 }), - shards: [ - { - id: 0, - remoteCluster: remoteCluster, - leaderIndex: leaderIndex, - leaderGlobalCheckpoint: chance.integer(), - leaderMaxSequenceNum: chance.integer(), - followerGlobalCheckpoint: chance.integer(), - followerMaxSequenceNum: chance.integer(), - lastRequestedSequenceNum: chance.integer(), - outstandingReadRequestsCount: chance.integer(), - outstandingWriteRequestsCount: chance.integer(), - writeBufferOperationsCount: chance.integer(), - writeBufferSizeBytes: chance.integer(), - followerMappingVersion: chance.integer(), - followerSettingsVersion: chance.integer(), - totalReadTimeMs: chance.integer(), - totalReadRemoteExecTimeMs: chance.integer(), - successfulReadRequestCount: chance.integer(), - failedReadRequestsCount: chance.integer(), - operationsReadCount: chance.integer(), - bytesReadCount: chance.integer(), - totalWriteTimeMs: chance.integer(), - successfulWriteRequestsCount: chance.integer(), - failedWriteRequestsCount: chance.integer(), - operationsWrittenCount: chance.integer(), - readExceptions: [], - timeSinceLastReadMs: chance.integer(), - }, - ], -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/index.js b/x-pack/legacy/plugins/cross_cluster_replication/fixtures/index.js deleted file mode 100644 index ccfdf8b19f3ee..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/fixtures/index.js +++ /dev/null @@ -1,16 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { getAutoFollowPatternMock, getAutoFollowPatternListMock } from './auto_follow_pattern'; - -export { esErrors } from './es_errors'; - -export { - getFollowerIndexStatsMock, - getFollowerIndexListStatsMock, - getFollowerIndexInfoMock, - getFollowerIndexListInfoMock, -} from './follower_index'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/index.js b/x-pack/legacy/plugins/cross_cluster_replication/index.js deleted file mode 100644 index aff4cc5b56738..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/index.js +++ /dev/null @@ -1,57 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { resolve } from 'path'; -import { PLUGIN } from './common/constants'; -import { plugin } from './server/np_ready'; - -export function crossClusterReplication(kibana) { - return new kibana.Plugin({ - id: PLUGIN.ID, - configPrefix: 'xpack.ccr', - publicDir: resolve(__dirname, 'public'), - require: ['kibana', 'elasticsearch', 'xpack_main', 'remoteClusters', 'index_management'], - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - managementSections: ['plugins/cross_cluster_replication'], - injectDefaultVars(server) { - const config = server.config(); - return { - ccrUiEnabled: - config.get('xpack.ccr.ui.enabled') && config.get('xpack.remote_clusters.ui.enabled'), - }; - }, - }, - - config(Joi) { - return Joi.object({ - // display menu item - ui: Joi.object({ - enabled: Joi.boolean().default(true), - }).default(), - - // enable plugin - enabled: Joi.boolean().default(true), - }).default(); - }, - isEnabled(config) { - return ( - config.get('xpack.ccr.enabled') && - config.get('xpack.index_management.enabled') && - config.get('xpack.remote_clusters.enabled') - ); - }, - init: function initCcrPlugin(server) { - plugin({}).setup(server.newPlatform.setup.core, { - indexManagement: server.newPlatform.setup.plugins.indexManagement, - __LEGACY: { - server, - ccrUIEnabled: server.config().get('xpack.ccr.ui.enabled'), - }, - }); - }, - }); -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/index.scss b/x-pack/legacy/plugins/cross_cluster_replication/public/index.scss deleted file mode 100644 index 31317e16e3e9f..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/index.scss +++ /dev/null @@ -1,13 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -// Cross-Cluster Replication plugin styles - -// Prefix all styles with "ccr" to avoid conflicts. -// Examples -// ccrChart -// ccrChart__legend -// ccrChart__legend--small -// ccrChart__legend-isLoading - -@import 'np_ready/app/app'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/main.html b/x-pack/legacy/plugins/cross_cluster_replication/public/main.html deleted file mode 100644 index 2129f26267827..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/main.html +++ /dev/null @@ -1,3 +0,0 @@ - -
-
diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/_app.scss b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/_app.scss deleted file mode 100644 index 5ee862b1d9e44..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/_app.scss +++ /dev/null @@ -1,14 +0,0 @@ -.ccrFollowerIndicesFormRow { - padding-bottom: 0; -} - -.ccrFollowerIndicesHelpText { - transform: translateY(-3px); -} - -/** - * 1. Prevent context menu popover appearing above confirmation modal - */ -.ccrFollowerIndicesDetailPanel { - z-index: $euiZMask - 1; /* 1 */ -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/index.js b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/index.js deleted file mode 100644 index cc81fce4eebe7..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/index.js +++ /dev/null @@ -1,25 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import React from 'react'; -import { render } from 'react-dom'; -import { Provider } from 'react-redux'; -import { HashRouter } from 'react-router-dom'; - -import { App } from './app'; -import { ccrStore } from './store'; - -export const renderReact = async (elem, I18nContext) => { - render( - - - - - - - , - elem - ); -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/documentation_links.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/documentation_links.ts deleted file mode 100644 index f17926d2bee10..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/documentation_links.ts +++ /dev/null @@ -1,22 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -let esBase: string; - -export const setDocLinks = ({ - DOC_LINK_VERSION, - ELASTIC_WEBSITE_URL, -}: { - ELASTIC_WEBSITE_URL: string; - DOC_LINK_VERSION: string; -}) => { - esBase = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}`; -}; - -export const getAutoFollowPatternUrl = () => `${esBase}/ccr-put-auto-follow-pattern.html`; -export const getFollowerIndexUrl = () => `${esBase}/ccr-put-follow.html`; -export const getByteUnitsUrl = () => `${esBase}/common-options.html#byte-units`; -export const getTimeUnitsUrl = () => `${esBase}/common-options.html#time-units`; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/notifications.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/notifications.ts deleted file mode 100644 index 5e1c3e9e99437..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/notifications.ts +++ /dev/null @@ -1,20 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { NotificationsSetup, IToasts, FatalErrorsSetup } from 'src/core/public'; - -let _notifications: IToasts; -let _fatalErrors: FatalErrorsSetup; - -export const setNotifications = ( - notifications: NotificationsSetup, - fatalErrorsSetup: FatalErrorsSetup -) => { - _notifications = notifications.toasts; - _fatalErrors = fatalErrorsSetup; -}; - -export const getNotifications = () => _notifications; -export const getFatalErrors = () => _fatalErrors; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/track_ui_metric.js b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/track_ui_metric.js deleted file mode 100644 index 36b9c185b487d..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/track_ui_metric.js +++ /dev/null @@ -1,27 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - createUiStatsReporter, - METRIC_TYPE, -} from '../../../../../../../../src/legacy/core_plugins/ui_metric/public'; -import { UIM_APP_NAME } from '../constants'; - -export const trackUiMetric = createUiStatsReporter(UIM_APP_NAME); -export { METRIC_TYPE }; -/** - * Transparently return provided request Promise, while allowing us to track - * a successful completion of the request. - */ -export function trackUserRequest(request, actionType) { - // Only track successful actions. - return request.then(response => { - trackUiMetric(METRIC_TYPE.LOADED, actionType); - // We return the response immediately without waiting for the tracking request to resolve, - // to avoid adding additional latency. - return response; - }); -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts deleted file mode 100644 index 4ffe0db4e3c4e..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/extend_index_management.ts +++ /dev/null @@ -1,28 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { get } from 'lodash'; -import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/public'; - -const propertyPath = 'isFollowerIndex'; - -const followerBadgeExtension = { - matchIndex: (index: any) => { - return get(index, propertyPath); - }, - label: i18n.translate('xpack.crossClusterReplication.indexMgmtBadge.followerLabel', { - defaultMessage: 'Follower', - }), - color: 'default', - filterExpression: 'isFollowerIndex:true', -}; - -export const extendIndexManagement = (indexManagement?: IndexManagementPluginSetup) => { - if (indexManagement) { - indexManagement.extensionsService.addBadge(followerBadgeExtension); - } -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts b/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts deleted file mode 100644 index 46259c698b282..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/plugin.ts +++ /dev/null @@ -1,44 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { - ChromeBreadcrumb, - CoreSetup, - Plugin, - PluginInitializerContext, - DocLinksStart, -} from 'src/core/public'; - -import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/public'; - -// @ts-ignore; -import { setHttpClient } from './app/services/api'; -import { setBreadcrumbSetter } from './app/services/breadcrumbs'; -import { setDocLinks } from './app/services/documentation_links'; -import { setNotifications } from './app/services/notifications'; -import { extendIndexManagement } from './extend_index_management'; - -interface PluginDependencies { - indexManagement: IndexManagementPluginSetup; - __LEGACY: { - chrome: any; - MANAGEMENT_BREADCRUMB: ChromeBreadcrumb; - docLinks: DocLinksStart; - }; -} - -export class CrossClusterReplicationUIPlugin implements Plugin { - // @ts-ignore - constructor(private readonly ctx: PluginInitializerContext) {} - setup({ http, notifications, fatalErrors }: CoreSetup, deps: PluginDependencies) { - setHttpClient(http); - setBreadcrumbSetter(deps); - setDocLinks(deps.__LEGACY.docLinks); - setNotifications(notifications, fatalErrors); - extendIndexManagement(deps.indexManagement); - } - - start() {} -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/register_routes.js b/x-pack/legacy/plugins/cross_cluster_replication/public/register_routes.js deleted file mode 100644 index 838939f46e523..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/register_routes.js +++ /dev/null @@ -1,94 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { unmountComponentAtNode } from 'react-dom'; -import chrome from 'ui/chrome'; -import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; -import { npSetup, npStart } from 'ui/new_platform'; -import routes from 'ui/routes'; -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import { i18n } from '@kbn/i18n'; - -import template from './main.html'; -import { BASE_PATH } from '../common/constants'; - -import { plugin } from './np_ready'; - -/** - * TODO: When this file is deleted, use the management section for rendering - */ -import { renderReact } from './np_ready/app'; - -const isAvailable = xpackInfo.get('features.crossClusterReplication.isAvailable'); -const isActive = xpackInfo.get('features.crossClusterReplication.isActive'); -const isLicenseOK = isAvailable && isActive; -const isCcrUiEnabled = chrome.getInjected('ccrUiEnabled'); - -if (isLicenseOK && isCcrUiEnabled) { - const esSection = management.getSection('elasticsearch'); - - esSection.register('ccr', { - visible: true, - display: i18n.translate('xpack.crossClusterReplication.appTitle', { - defaultMessage: 'Cross-Cluster Replication', - }), - order: 4, - url: `#${BASE_PATH}`, - }); - - let elem; - - const CCR_REACT_ROOT = 'ccrReactRoot'; - - plugin({}).setup(npSetup.core, { - ...npSetup.plugins, - __LEGACY: { - chrome, - docLinks: npStart.core.docLinks, - MANAGEMENT_BREADCRUMB, - }, - }); - - const unmountReactApp = () => elem && unmountComponentAtNode(elem); - - routes.when(`${BASE_PATH}/:section?/:subsection?/:view?/:id?`, { - template, - controllerAs: 'ccr', - controller: class CrossClusterReplicationController { - constructor($scope, $route) { - // React-router's does not play well with the angular router. It will cause this controller - // to re-execute without the $destroy handler being called. This means that the app will be mounted twice - // creating a memory leak when leaving (only 1 app will be unmounted). - // To avoid this, we unmount the React app each time we enter the controller. - unmountReactApp(); - - $scope.$$postDigest(() => { - elem = document.getElementById(CCR_REACT_ROOT); - renderReact(elem, npStart.core.i18n.Context); - - // Angular Lifecycle - const appRoute = $route.current; - const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; - - // When we navigate within CCR, prevent Angular from re-matching the route and rebuild the app - if (isNavigationInApp) { - $route.current = appRoute; - } else { - // Any clean up when User leaves the CCR - } - - $scope.$on('$destroy', () => { - stopListeningForLocationChange && stopListeningForLocationChange(); - unmountReactApp(); - }); - }); - }); - } - }, - }); -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/cross_cluster_replication_data.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/cross_cluster_replication_data.ts deleted file mode 100644 index ae15073b979e1..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/cross_cluster_replication_data.ts +++ /dev/null @@ -1,36 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { APICaller } from 'src/core/server'; -import { Index } from '../../../../../plugins/index_management/server'; - -export const ccrDataEnricher = async (indicesList: Index[], callWithRequest: APICaller) => { - if (!indicesList?.length) { - return indicesList; - } - const params = { - path: '/_all/_ccr/info', - method: 'GET', - }; - try { - const { follower_indices: followerIndices } = await callWithRequest( - 'transport.request', - params - ); - return indicesList.map(index => { - const isFollowerIndex = !!followerIndices.find( - (followerIndex: { follower_index: string }) => { - return followerIndex.follower_index === index.name; - } - ); - return { - ...index, - isFollowerIndex, - }; - }); - } catch (e) { - return indicesList; - } -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/index.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/index.ts deleted file mode 100644 index 7a38d024d99a2..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/index.ts +++ /dev/null @@ -1,11 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { PluginInitializerContext } from 'src/core/server'; -import { CrossClusterReplicationServerPlugin } from './plugin'; - -export const plugin = (ctx: PluginInitializerContext) => - new CrossClusterReplicationServerPlugin(ctx); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/call_with_request_factory.js deleted file mode 100644 index 99d72ce1a0e6e..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/call_with_request_factory.js +++ /dev/null @@ -1,20 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { once } from 'lodash'; -import { elasticsearchJsPlugin } from '../../client/elasticsearch_ccr'; - -const callWithRequest = once(server => { - const config = { plugins: [elasticsearchJsPlugin] }; - const cluster = server.plugins.elasticsearch.createCluster('ccr', config); - return cluster.callWithRequest; -}); - -export const callWithRequestFactory = (server, request) => { - return (...args) => { - return callWithRequest(server)(request, ...args); - }; -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/index.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/index.js deleted file mode 100644 index 787814d87dff9..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/call_with_request_factory/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { callWithRequestFactory } from './call_with_request_factory'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/check_license/check_license.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/check_license/check_license.js deleted file mode 100644 index 6cf12896fa472..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/check_license/check_license.js +++ /dev/null @@ -1,70 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export function checkLicense(xpackLicenseInfo) { - const pluginName = 'Cross-Cluster Replication'; - - // If, for some reason, we cannot get the license information - // from Elasticsearch, assume worst case and disable - if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) { - return { - isAvailable: false, - showLinks: true, - enableLinks: false, - message: i18n.translate( - 'xpack.crossClusterReplication.checkLicense.errorUnavailableMessage', - { - defaultMessage: - 'You cannot use {pluginName} because license information is not available at this time.', - values: { pluginName }, - } - ), - }; - } - - const VALID_LICENSE_MODES = ['trial', 'platinum', 'enterprise']; - - const isLicenseModeValid = xpackLicenseInfo.license.isOneOf(VALID_LICENSE_MODES); - const isLicenseActive = xpackLicenseInfo.license.isActive(); - const licenseType = xpackLicenseInfo.license.getType(); - - // License is not valid - if (!isLicenseModeValid) { - return { - isAvailable: false, - isActive: false, - message: i18n.translate( - 'xpack.crossClusterReplication.checkLicense.errorUnsupportedMessage', - { - defaultMessage: - 'Your {licenseType} license does not support {pluginName}. Please upgrade your license.', - values: { licenseType, pluginName }, - } - ), - }; - } - - // License is valid but not active - if (!isLicenseActive) { - return { - isAvailable: true, - isActive: false, - message: i18n.translate('xpack.crossClusterReplication.checkLicense.errorExpiredMessage', { - defaultMessage: - 'You cannot use {pluginName} because your {licenseType} license has expired', - values: { licenseType, pluginName }, - }), - }; - } - - // License is valid and active - return { - isAvailable: true, - isActive: true, - }; -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/__tests__/wrap_es_error.test.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/__tests__/wrap_es_error.test.js deleted file mode 100644 index 11a6fd4e1d816..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/error_wrappers/__tests__/wrap_es_error.test.js +++ /dev/null @@ -1,33 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { wrapEsError } from '../wrap_es_error'; - -describe('wrap_es_error', () => { - describe('#wrapEsError', () => { - let originalError; - beforeEach(() => { - originalError = new Error('I am an error'); - originalError.statusCode = 404; - originalError.response = '{}'; - }); - - it('should return the correct object', () => { - const wrappedError = wrapEsError(originalError); - - expect(wrappedError.statusCode).to.be(originalError.statusCode); - expect(wrappedError.message).to.be(originalError.message); - }); - - it('should return the correct object with custom message', () => { - const wrappedError = wrapEsError(originalError, { 404: 'No encontrado!' }); - - expect(wrappedError.statusCode).to.be(originalError.statusCode); - expect(wrappedError.message).to.be('No encontrado!'); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/__tests__/is_es_error_factory.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/__tests__/is_es_error_factory.js deleted file mode 100644 index 5f2141cce9395..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/__tests__/is_es_error_factory.js +++ /dev/null @@ -1,44 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import expect from '@kbn/expect'; -import { isEsErrorFactory } from '../is_es_error_factory'; -import { set } from 'lodash'; - -class MockAbstractEsError {} - -describe('is_es_error_factory', () => { - let mockServer; - let isEsError; - - beforeEach(() => { - const mockEsErrors = { - _Abstract: MockAbstractEsError, - }; - mockServer = {}; - set(mockServer, 'plugins.elasticsearch.getCluster', () => ({ errors: mockEsErrors })); - - isEsError = isEsErrorFactory(mockServer); - }); - - describe('#isEsErrorFactory', () => { - it('should return a function', () => { - expect(isEsError).to.be.a(Function); - }); - - describe('returned function', () => { - it('should return true if passed-in err is a known esError', () => { - const knownEsError = new MockAbstractEsError(); - expect(isEsError(knownEsError)).to.be(true); - }); - - it('should return false if passed-in err is not a known esError', () => { - const unknownEsError = {}; - expect(isEsError(unknownEsError)).to.be(false); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/is_es_error_factory.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/is_es_error_factory.ts deleted file mode 100644 index fc6405b8e7513..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/is_es_error_factory.ts +++ /dev/null @@ -1,18 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { memoize } from 'lodash'; - -const esErrorsFactory = memoize((server: any) => { - return server.plugins.elasticsearch.getCluster('admin').errors; -}); - -export function isEsErrorFactory(server: any) { - const esErrors = esErrorsFactory(server); - return function isEsError(err: any) { - return err instanceof esErrors._Abstract; - }; -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/__jest__/license_pre_routing_factory.test.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/__jest__/license_pre_routing_factory.test.ts deleted file mode 100644 index d22505f0e315a..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/__jest__/license_pre_routing_factory.test.ts +++ /dev/null @@ -1,64 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { kibanaResponseFactory } from '../../../../../../../../../src/core/server'; -import { licensePreRoutingFactory } from '../license_pre_routing_factory'; - -describe('license_pre_routing_factory', () => { - describe('#reportingFeaturePreRoutingFactory', () => { - let mockDeps: any; - let mockLicenseCheckResults: any; - - const anyContext: any = {}; - const anyRequest: any = {}; - - beforeEach(() => { - mockDeps = { - __LEGACY: { - server: { - plugins: { - xpack_main: { - info: { - feature: () => ({ - getLicenseCheckResults: () => mockLicenseCheckResults, - }), - }, - }, - }, - }, - }, - requestHandler: jest.fn(), - }; - }); - - describe('isAvailable is false', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: false, - }; - }); - - it('replies with 403', async () => { - const licensePreRouting = licensePreRoutingFactory(mockDeps); - const response = await licensePreRouting(anyContext, anyRequest, kibanaResponseFactory); - expect(response.status).toBe(403); - }); - }); - - describe('isAvailable is true', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: true, - }; - }); - - it('it calls the wrapped handler', async () => { - const licensePreRouting = licensePreRoutingFactory(mockDeps); - await licensePreRouting(anyContext, anyRequest, kibanaResponseFactory); - expect(mockDeps.requestHandler).toHaveBeenCalledTimes(1); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/license_pre_routing_factory.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/license_pre_routing_factory.ts deleted file mode 100644 index c47faa940a650..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/license_pre_routing_factory/license_pre_routing_factory.ts +++ /dev/null @@ -1,32 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { RequestHandler } from 'src/core/server'; -import { PLUGIN } from '../../../../common/constants'; - -export const licensePreRoutingFactory = ({ - __LEGACY, - requestHandler, -}: { - __LEGACY: { server: any }; - requestHandler: RequestHandler; -}) => { - const xpackMainPlugin = __LEGACY.server.plugins.xpack_main; - - // License checking and enable/disable logic - const licensePreRouting: RequestHandler = (ctx, request, response) => { - const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN.ID).getLicenseCheckResults(); - if (!licenseCheckResults.isAvailable) { - return response.forbidden({ - body: licenseCheckResults.message, - }); - } else { - return requestHandler(ctx, request, response); - } - }; - - return licensePreRouting; -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/index.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/index.js deleted file mode 100644 index 7b0f97c38d129..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/index.js +++ /dev/null @@ -1,7 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -export { registerLicenseChecker } from './register_license_checker'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/register_license_checker.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/register_license_checker.js deleted file mode 100644 index b9bb34a80ce79..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/register_license_checker/register_license_checker.js +++ /dev/null @@ -1,21 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { mirrorPluginStatus } from '../../../../../../server/lib/mirror_plugin_status'; -import { PLUGIN } from '../../../../common/constants'; -import { checkLicense } from '../check_license'; - -export function registerLicenseChecker(__LEGACY) { - const xpackMainPlugin = __LEGACY.server.plugins.xpack_main; - const ccrPluggin = __LEGACY.server.plugins[PLUGIN.ID]; - - mirrorPluginStatus(xpackMainPlugin, ccrPluggin); - xpackMainPlugin.status.once('green', () => { - // Register a function that is called whenever the xpack info changes, - // to re-compute the license check results for this plugin - xpackMainPlugin.info.feature(PLUGIN.ID).registerLicenseCheckResultsGenerator(checkLicense); - }); -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts deleted file mode 100644 index 829de10ad0177..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/plugin.ts +++ /dev/null @@ -1,38 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Plugin, PluginInitializerContext, CoreSetup } from 'src/core/server'; - -import { IndexManagementPluginSetup } from '../../../../../plugins/index_management/server'; - -// @ts-ignore -import { registerLicenseChecker } from './lib/register_license_checker'; -// @ts-ignore -import { registerRoutes } from './routes/register_routes'; -import { ccrDataEnricher } from './cross_cluster_replication_data'; - -interface PluginDependencies { - indexManagement: IndexManagementPluginSetup; - __LEGACY: { - server: any; - ccrUIEnabled: boolean; - }; -} - -export class CrossClusterReplicationServerPlugin implements Plugin { - // @ts-ignore - constructor(private readonly ctx: PluginInitializerContext) {} - setup({ http }: CoreSetup, { indexManagement, __LEGACY }: PluginDependencies) { - registerLicenseChecker(__LEGACY); - - const router = http.createRouter(); - registerRoutes({ router, __LEGACY }); - if (__LEGACY.ccrUIEnabled && indexManagement && indexManagement.indexDataEnricher) { - indexManagement.indexDataEnricher.add(ccrDataEnricher); - } - } - start() {} -} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/auto_follow_pattern.test.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/auto_follow_pattern.test.js deleted file mode 100644 index f3024515c7213..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/auto_follow_pattern.test.js +++ /dev/null @@ -1,330 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { deserializeAutoFollowPattern } from '../../../../../common/services/auto_follow_pattern_serialization'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../../lib/is_es_error_factory'; -import { getAutoFollowPatternMock, getAutoFollowPatternListMock } from '../../../../../fixtures'; -import { registerAutoFollowPatternRoutes } from '../auto_follow_pattern'; - -import { createRouter, callRoute } from './helpers'; - -jest.mock('../../../lib/call_with_request_factory'); -jest.mock('../../../lib/is_es_error_factory'); -jest.mock('../../../lib/license_pre_routing_factory', () => ({ - licensePreRoutingFactory: ({ requestHandler }) => requestHandler, -})); - -const DESERIALIZED_KEYS = Object.keys(deserializeAutoFollowPattern(getAutoFollowPatternMock())); - -let routeRegistry; - -/** - * Helper to extract all the different server route handler so we can easily call them in our tests. - * - * Important: This method registers the handlers in the order that they appear in the file, so - * if a "server.route()" call is moved or deleted, then the HANDLER_INDEX_TO_ACTION must be updated here. - */ -const registerHandlers = () => { - const HANDLER_INDEX_TO_ACTION = { - 0: 'list', - 1: 'create', - 2: 'update', - 3: 'get', - 4: 'delete', - 5: 'pause', - 6: 'resume', - }; - - routeRegistry = createRouter(HANDLER_INDEX_TO_ACTION); - - registerAutoFollowPatternRoutes({ - __LEGACY: {}, - router: routeRegistry.router, - }); -}; - -/** - * Queue to save request response and errors - * It allows us to fake multiple responses from the - * callWithRequestFactory() when the request handler call it - * multiple times. - */ -let requestResponseQueue = []; - -/** - * Helper to mock the response from the call to Elasticsearch - * - * @param {*} err The mock error to throw - * @param {*} response The response to return - */ -const setHttpRequestResponse = (error, response) => { - requestResponseQueue.push({ error, response }); -}; - -const resetHttpRequestResponses = () => (requestResponseQueue = []); - -const getNextResponseFromQueue = () => { - if (!requestResponseQueue.length) { - return null; - } - - const next = requestResponseQueue.shift(); - if (next.error) { - return Promise.reject(next.error); - } - return Promise.resolve(next.response); -}; - -describe('[CCR API Routes] Auto Follow Pattern', () => { - let routeHandler; - - beforeAll(() => { - isEsErrorFactory.mockReturnValue(() => false); - callWithRequestFactory.mockReturnValue(getNextResponseFromQueue); - registerHandlers(); - }); - - describe('list()', () => { - beforeEach(() => { - routeHandler = routeRegistry.getRoutes().list; - }); - - it('should deserialize the response from Elasticsearch', async () => { - const totalResult = 2; - setHttpRequestResponse(null, getAutoFollowPatternListMock(totalResult)); - - const { - options: { body: response }, - } = await callRoute(routeHandler); - const autoFollowPattern = response.patterns[0]; - - expect(response.patterns.length).toEqual(totalResult); - expect(Object.keys(autoFollowPattern)).toEqual(DESERIALIZED_KEYS); - }); - }); - - describe('create()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().create; - }); - - it('should throw a 409 conflict error if id already exists', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute( - routeHandler, - {}, - { - body: { - id: 'some-id', - foo: 'bar', - }, - } - ); - - expect(response.status).toEqual(409); - }); - - it('should return 200 status when the id does not exist', async () => { - const error = new Error('Resource not found.'); - error.statusCode = 404; - setHttpRequestResponse(error); - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute( - routeHandler, - {}, - { - body: { - id: 'some-id', - foo: 'bar', - }, - } - ); - - expect(response).toEqual({ acknowledge: true }); - }); - }); - - describe('update()', () => { - beforeEach(() => { - routeHandler = routeRegistry.getRoutes().update; - }); - - it('should serialize the payload before sending it to Elasticsearch', async () => { - callWithRequestFactory.mockReturnValueOnce((_, payload) => payload); - - const request = { - params: { id: 'foo' }, - body: { - remoteCluster: 'bar1', - leaderIndexPatterns: ['bar2'], - followIndexPattern: 'bar3', - }, - }; - - const response = await callRoute(routeHandler, {}, request); - - expect(response.options.body).toEqual({ - id: 'foo', - body: { - remote_cluster: 'bar1', - leader_index_patterns: ['bar2'], - follow_index_pattern: 'bar3', - }, - }); - }); - }); - - describe('get()', () => { - beforeEach(() => { - routeHandler = routeRegistry.getRoutes().get; - }); - - it('should return a single resource even though ES return an array with 1 item', async () => { - const autoFollowPattern = getAutoFollowPatternMock(); - const esResponse = { patterns: [autoFollowPattern] }; - - setHttpRequestResponse(null, esResponse); - - const response = await callRoute(routeHandler, {}, { params: { id: 1 } }); - expect(Object.keys(response.options.body)).toEqual(DESERIALIZED_KEYS); - }); - }); - - describe('delete()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().delete; - }); - - it('should delete a single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a' } }); - - expect(response.itemsDeleted).toEqual(['a']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of ids to delete', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: 'a,b,c' } }); - - expect(response.options.body.itemsDeleted).toEqual(['a', 'b', 'c']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a,b' } }); - - expect(response.itemsDeleted).toEqual(['a']); - expect(response.errors[0].id).toEqual('b'); - }); - }); - - describe('pause()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().pause; - }); - - it('accept a single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a' } }); - - expect(response.itemsPaused).toEqual(['a']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of items to pause', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: 'a,b,c' } }); - - expect(response.options.body.itemsPaused).toEqual(['a', 'b', 'c']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a,b' } }); - - expect(response.itemsPaused).toEqual(['a']); - expect(response.errors[0].id).toEqual('b'); - }); - }); - - describe('resume()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().resume; - }); - - it('accept a single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a' } }); - - expect(response.itemsResumed).toEqual(['a']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of items to pause', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: 'a,b,c' } }); - - expect(response.options.body.itemsResumed).toEqual(['a', 'b', 'c']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: 'a,b' } }); - - expect(response.itemsResumed).toEqual(['a']); - expect(response.errors[0].id).toEqual('b'); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/follower_index.test.js b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/follower_index.test.js deleted file mode 100644 index f0139e5bd7011..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/follower_index.test.js +++ /dev/null @@ -1,312 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { deserializeFollowerIndex } from '../../../../../common/services/follower_index_serialization'; -import { - getFollowerIndexStatsMock, - getFollowerIndexListStatsMock, - getFollowerIndexInfoMock, - getFollowerIndexListInfoMock, -} from '../../../../../fixtures'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { isEsErrorFactory } from '../../../lib/is_es_error_factory'; -import { registerFollowerIndexRoutes } from '../follower_index'; -import { createRouter, callRoute } from './helpers'; - -jest.mock('../../../lib/call_with_request_factory'); -jest.mock('../../../lib/is_es_error_factory'); -jest.mock('../../../lib/license_pre_routing_factory', () => ({ - licensePreRoutingFactory: ({ requestHandler }) => requestHandler, -})); - -const DESERIALIZED_KEYS = Object.keys( - deserializeFollowerIndex({ - ...getFollowerIndexInfoMock(), - ...getFollowerIndexStatsMock(), - }) -); - -let routeRegistry; - -/** - * Helper to extract all the different server route handler so we can easily call them in our tests. - * - * Important: This method registers the handlers in the order that they appear in the file, so - * if a 'server.route()' call is moved or deleted, then the HANDLER_INDEX_TO_ACTION must be updated here. - */ -const registerHandlers = () => { - const HANDLER_INDEX_TO_ACTION = { - 0: 'list', - 1: 'get', - 2: 'create', - 3: 'edit', - 4: 'pause', - 5: 'resume', - 6: 'unfollow', - }; - - routeRegistry = createRouter(HANDLER_INDEX_TO_ACTION); - registerFollowerIndexRoutes({ - __LEGACY: {}, - router: routeRegistry.router, - }); -}; - -/** - * Queue to save request response and errors - * It allows us to fake multiple responses from the - * callWithRequestFactory() when the request handler call it - * multiple times. - */ -let requestResponseQueue = []; - -/** - * Helper to mock the response from the call to Elasticsearch - * - * @param {*} err The mock error to throw - * @param {*} response The response to return - */ -const setHttpRequestResponse = (error, response) => { - requestResponseQueue.push({ error, response }); -}; - -const resetHttpRequestResponses = () => (requestResponseQueue = []); - -const getNextResponseFromQueue = () => { - if (!requestResponseQueue.length) { - return null; - } - - const next = requestResponseQueue.shift(); - if (next.error) { - return Promise.reject(next.error); - } - return Promise.resolve(next.response); -}; - -describe('[CCR API Routes] Follower Index', () => { - let routeHandler; - - beforeAll(() => { - isEsErrorFactory.mockReturnValue(() => false); - callWithRequestFactory.mockReturnValue(getNextResponseFromQueue); - registerHandlers(); - }); - - describe('list()', () => { - beforeEach(() => { - routeHandler = routeRegistry.getRoutes().list; - }); - - it('deserializes the response from Elasticsearch', async () => { - const totalResult = 2; - const infoResult = getFollowerIndexListInfoMock(totalResult); - const statsResult = getFollowerIndexListStatsMock( - totalResult, - infoResult.follower_indices.map(index => index.follower_index) - ); - setHttpRequestResponse(null, infoResult); - setHttpRequestResponse(null, statsResult); - - const { - options: { body: response }, - } = await callRoute(routeHandler); - const followerIndex = response.indices[0]; - - expect(response.indices.length).toEqual(totalResult); - expect(Object.keys(followerIndex)).toEqual(DESERIALIZED_KEYS); - }); - }); - - describe('get()', () => { - beforeEach(() => { - routeHandler = routeRegistry.getRoutes().get; - }); - - it('should return a single resource even though ES return an array with 1 item', async () => { - const mockId = 'test1'; - const followerIndexInfo = getFollowerIndexInfoMock(mockId); - const followerIndexStats = getFollowerIndexStatsMock(mockId); - - setHttpRequestResponse(null, { follower_indices: [followerIndexInfo] }); - setHttpRequestResponse(null, { indices: [followerIndexStats] }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: mockId } }); - expect(Object.keys(response)).toEqual(DESERIALIZED_KEYS); - }); - }); - - describe('create()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().create; - }); - - it('should return 200 status when follower index is created', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute( - routeHandler, - {}, - { - body: { - name: 'follower_index', - remoteCluster: 'remote_cluster', - leaderIndex: 'leader_index', - }, - } - ); - - expect(response.options.body).toEqual({ acknowledge: true }); - }); - }); - - describe('pause()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().pause; - }); - - it('should pause a single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1' } }); - - expect(response.itemsPaused).toEqual(['1']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of ids to pause', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: '1,2,3' } }); - - expect(response.options.body.itemsPaused).toEqual(['1', '2', '3']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1,2' } }); - - expect(response.itemsPaused).toEqual(['1']); - expect(response.errors[0].id).toEqual('2'); - }); - }); - - describe('resume()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().resume; - }); - - it('should resume a single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1' } }); - - expect(response.itemsResumed).toEqual(['1']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of ids to resume', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: '1,2,3' } }); - - expect(response.options.body.itemsResumed).toEqual(['1', '2', '3']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1,2' } }); - - expect(response.itemsResumed).toEqual(['1']); - expect(response.errors[0].id).toEqual('2'); - }); - }); - - describe('unfollow()', () => { - beforeEach(() => { - resetHttpRequestResponses(); - routeHandler = routeRegistry.getRoutes().unfollow; - }); - - it('should unfollow await single item', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1' } }); - - expect(response.itemsUnfollowed).toEqual(['1']); - expect(response.errors).toEqual([]); - }); - - it('should accept a list of ids to unfollow', async () => { - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - - const response = await callRoute(routeHandler, {}, { params: { id: '1,2,3' } }); - - expect(response.options.body.itemsUnfollowed).toEqual(['1', '2', '3']); - }); - - it('should catch error and return them in array', async () => { - const error = new Error('something went wrong'); - error.response = '{ "error": {} }'; - - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(null, { acknowledge: true }); - setHttpRequestResponse(error); - - const { - options: { body: response }, - } = await callRoute(routeHandler, {}, { params: { id: '1,2' } }); - - expect(response.itemsUnfollowed).toEqual(['1']); - expect(response.errors[0].id).toEqual('2'); - }); - }); -}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/helpers.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/helpers.ts deleted file mode 100644 index 555fc0937c0ad..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/__jest__/helpers.ts +++ /dev/null @@ -1,37 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { RequestHandler } from 'src/core/server'; -import { kibanaResponseFactory } from '../../../../../../../../../src/core/server'; - -export const callRoute = ( - route: RequestHandler, - ctx = {}, - request = {}, - response = kibanaResponseFactory -) => { - return route(ctx as any, request as any, response); -}; - -export const createRouter = (indexToActionMap: Record) => { - let index = 0; - const routeHandlers: Record> = {}; - const addHandler = (ignoreCtxForNow: any, handler: RequestHandler) => { - // Save handler and increment index - routeHandlers[indexToActionMap[index]] = handler; - index++; - }; - - return { - getRoutes: () => routeHandlers, - router: { - get: addHandler, - post: addHandler, - put: addHandler, - delete: addHandler, - }, - }; -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/auto_follow_pattern.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/auto_follow_pattern.ts deleted file mode 100644 index d458f1ccb354b..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/auto_follow_pattern.ts +++ /dev/null @@ -1,301 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { schema } from '@kbn/config-schema'; -// @ts-ignore -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { isEsError } from '../../lib/is_es_error'; -// @ts-ignore -import { - deserializeAutoFollowPattern, - deserializeListAutoFollowPatterns, - serializeAutoFollowPattern, - // @ts-ignore -} from '../../../../common/services/auto_follow_pattern_serialization'; - -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; -import { API_BASE_PATH } from '../../../../common/constants'; - -import { RouteDependencies } from '../types'; -import { mapErrorToKibanaHttpResponse } from '../map_to_kibana_http_error'; - -export const registerAutoFollowPatternRoutes = ({ router, __LEGACY }: RouteDependencies) => { - /** - * Returns a list of all auto-follow patterns - */ - router.get( - { - path: `${API_BASE_PATH}/auto_follow_patterns`, - validate: false, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - - try { - const result = await callWithRequest('ccr.autoFollowPatterns'); - return response.ok({ - body: { - patterns: deserializeListAutoFollowPatterns(result.patterns), - }, - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Create an auto-follow pattern - */ - router.post( - { - path: `${API_BASE_PATH}/auto_follow_patterns`, - validate: { - body: schema.object( - { - id: schema.string(), - }, - { unknowns: 'allow' } - ), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id, ...rest } = request.body; - const body = serializeAutoFollowPattern(rest); - - /** - * First let's make sur that an auto-follow pattern with - * the same id does not exist. - */ - try { - await callWithRequest('ccr.autoFollowPattern', { id }); - // If we get here it means that an auto-follow pattern with the same id exists - return response.conflict({ - body: `An auto-follow pattern with the name "${id}" already exists.`, - }); - } catch (err) { - if (err.statusCode !== 404) { - return mapErrorToKibanaHttpResponse(err); - } - } - - try { - return response.ok({ - body: await callWithRequest('ccr.saveAutoFollowPattern', { id, body }), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Update an auto-follow pattern - */ - router.put( - { - path: `${API_BASE_PATH}/auto_follow_patterns/{id}`, - validate: { - params: schema.object({ - id: schema.string(), - }), - body: schema.object({}, { unknowns: 'allow' }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const body = serializeAutoFollowPattern(request.body); - - try { - return response.ok({ - body: await callWithRequest('ccr.saveAutoFollowPattern', { id, body }), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Returns a single auto-follow pattern - */ - router.get( - { - path: `${API_BASE_PATH}/auto_follow_patterns/{id}`, - validate: { - params: schema.object({ - id: schema.string(), - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - - try { - const result = await callWithRequest('ccr.autoFollowPattern', { id }); - const autoFollowPattern = result.patterns[0]; - - return response.ok({ - body: deserializeAutoFollowPattern(autoFollowPattern), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Delete an auto-follow pattern - */ - router.delete( - { - path: `${API_BASE_PATH}/auto_follow_patterns/{id}`, - validate: { - params: schema.object({ - id: schema.string(), - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsDeleted: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(_id => - callWithRequest('ccr.deleteAutoFollowPattern', { id: _id }) - .then(() => itemsDeleted.push(_id)) - .catch((err: Error) => { - if (isEsError(err)) { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } else { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } - }) - ) - ); - - return response.ok({ - body: { - itemsDeleted, - errors, - }, - }); - }, - }) - ); - - /** - * Pause auto-follow pattern(s) - */ - router.post( - { - path: `${API_BASE_PATH}/auto_follow_patterns/{id}/pause`, - validate: { - params: schema.object({ - id: schema.string(), - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsPaused: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(_id => - callWithRequest('ccr.pauseAutoFollowPattern', { id: _id }) - .then(() => itemsPaused.push(_id)) - .catch((err: Error) => { - if (isEsError(err)) { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } else { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } - }) - ) - ); - - return response.ok({ - body: { - itemsPaused, - errors, - }, - }); - }, - }) - ); - - /** - * Resume auto-follow pattern(s) - */ - router.post( - { - path: `${API_BASE_PATH}/auto_follow_patterns/{id}/resume`, - validate: { - params: schema.object({ - id: schema.string(), - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsResumed: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(_id => - callWithRequest('ccr.resumeAutoFollowPattern', { id: _id }) - .then(() => itemsResumed.push(_id)) - .catch((err: Error) => { - if (isEsError(err)) { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } else { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } - }) - ) - ); - - return response.ok({ - body: { - itemsResumed, - errors, - }, - }); - }, - }) - ); -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/ccr.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/ccr.ts deleted file mode 100644 index b08b056ad2c8a..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/ccr.ts +++ /dev/null @@ -1,112 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { API_BASE_PATH } from '../../../../common/constants'; -// @ts-ignore -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -// @ts-ignore -import { deserializeAutoFollowStats } from '../../lib/ccr_stats_serialization'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; - -import { mapErrorToKibanaHttpResponse } from '../map_to_kibana_http_error'; -import { RouteDependencies } from '../types'; - -export const registerCcrRoutes = ({ router, __LEGACY }: RouteDependencies) => { - /** - * Returns Auto-follow stats - */ - router.get( - { - path: `${API_BASE_PATH}/stats/auto_follow`, - validate: false, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - - try { - const { auto_follow_stats: autoFollowStats } = await callWithRequest('ccr.stats'); - - return response.ok({ - body: deserializeAutoFollowStats(autoFollowStats), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Returns whether the user has CCR permissions - */ - router.get( - { - path: `${API_BASE_PATH}/permissions`, - validate: false, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const xpackMainPlugin = __LEGACY.server.plugins.xpack_main; - const xpackInfo = xpackMainPlugin && xpackMainPlugin.info; - - if (!xpackInfo) { - // xpackInfo is updated via poll, so it may not be available until polling has begun. - // In this rare situation, tell the client the service is temporarily unavailable. - return response.customError({ - statusCode: 503, - body: 'Security info unavailable', - }); - } - - const securityInfo = xpackInfo && xpackInfo.isAvailable() && xpackInfo.feature('security'); - if (!securityInfo || !securityInfo.isAvailable() || !securityInfo.isEnabled()) { - // If security isn't enabled or available (in the case where security is enabled but license reverted to Basic) let the user use CCR. - return response.ok({ - body: { - hasPermission: true, - missingClusterPrivileges: [], - }, - }); - } - - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - - try { - const { has_all_requested: hasPermission, cluster } = await callWithRequest( - 'ccr.permissions', - { - body: { - cluster: ['manage', 'manage_ccr'], - }, - } - ); - - const missingClusterPrivileges = Object.keys(cluster).reduce( - (permissions: any, permissionName: any) => { - if (!cluster[permissionName]) { - permissions.push(permissionName); - return permissions; - } - }, - [] as any[] - ); - - return response.ok({ - body: { - hasPermission, - missingClusterPrivileges, - }, - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/follower_index.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/follower_index.ts deleted file mode 100644 index 1d7dacf4a8688..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/api/follower_index.ts +++ /dev/null @@ -1,357 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { schema } from '@kbn/config-schema'; -import { - deserializeFollowerIndex, - deserializeListFollowerIndices, - serializeFollowerIndex, - serializeAdvancedSettings, - // @ts-ignore -} from '../../../../common/services/follower_index_serialization'; -import { API_BASE_PATH } from '../../../../common/constants'; -// @ts-ignore -import { removeEmptyFields } from '../../../../common/services/utils'; -// @ts-ignore -import { callWithRequestFactory } from '../../lib/call_with_request_factory'; -import { licensePreRoutingFactory } from '../../lib/license_pre_routing_factory'; - -import { RouteDependencies } from '../types'; -import { mapErrorToKibanaHttpResponse } from '../map_to_kibana_http_error'; - -export const registerFollowerIndexRoutes = ({ router, __LEGACY }: RouteDependencies) => { - /** - * Returns a list of all follower indices - */ - router.get( - { - path: `${API_BASE_PATH}/follower_indices`, - validate: false, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - - try { - const { follower_indices: followerIndices } = await callWithRequest('ccr.info', { - id: '_all', - }); - - const { - follow_stats: { indices: followerIndicesStats }, - } = await callWithRequest('ccr.stats'); - - const followerIndicesStatsMap = followerIndicesStats.reduce((map: any, stats: any) => { - map[stats.index] = stats; - return map; - }, {}); - - const collatedFollowerIndices = followerIndices.map((followerIndex: any) => { - return { - ...followerIndex, - ...followerIndicesStatsMap[followerIndex.follower_index], - }; - }); - - return response.ok({ - body: { - indices: deserializeListFollowerIndices(collatedFollowerIndices), - }, - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Returns a single follower index pattern - */ - router.get( - { - path: `${API_BASE_PATH}/follower_indices/{id}`, - validate: { - params: schema.object({ - id: schema.string(), - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - - try { - const { follower_indices: followerIndices } = await callWithRequest('ccr.info', { id }); - - const followerIndexInfo = followerIndices && followerIndices[0]; - - if (!followerIndexInfo) { - return response.notFound({ - body: `The follower index "${id}" does not exist.`, - }); - } - - // If this follower is paused, skip call to ES stats api since it will return 404 - if (followerIndexInfo.status === 'paused') { - return response.ok({ - body: deserializeFollowerIndex({ - ...followerIndexInfo, - }), - }); - } else { - const { - indices: followerIndicesStats, - } = await callWithRequest('ccr.followerIndexStats', { id }); - - return response.ok({ - body: deserializeFollowerIndex({ - ...followerIndexInfo, - ...(followerIndicesStats ? followerIndicesStats[0] : {}), - }), - }); - } - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Create a follower index - */ - router.post( - { - path: `${API_BASE_PATH}/follower_indices`, - validate: { - body: schema.object( - { - name: schema.string(), - }, - { unknowns: 'allow' } - ), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { name, ...rest } = request.body; - const body = removeEmptyFields(serializeFollowerIndex(rest)); - - try { - return response.ok({ - body: await callWithRequest('ccr.saveFollowerIndex', { name, body }), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Edit a follower index - */ - router.put( - { - path: `${API_BASE_PATH}/follower_indices/{id}`, - validate: { - params: schema.object({ id: schema.string() }), - body: schema.object({ - maxReadRequestOperationCount: schema.maybe(schema.number()), - maxOutstandingReadRequests: schema.maybe(schema.number()), - maxReadRequestSize: schema.maybe(schema.string()), // byte value - maxWriteRequestOperationCount: schema.maybe(schema.number()), - maxWriteRequestSize: schema.maybe(schema.string()), // byte value - maxOutstandingWriteRequests: schema.maybe(schema.number()), - maxWriteBufferCount: schema.maybe(schema.number()), - maxWriteBufferSize: schema.maybe(schema.string()), // byte value - maxRetryDelay: schema.maybe(schema.string()), // time value - readPollTimeout: schema.maybe(schema.string()), // time value - }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - - // We need to first pause the follower and then resume it passing the advanced settings - try { - const { follower_indices: followerIndices } = await callWithRequest('ccr.info', { id }); - const followerIndexInfo = followerIndices && followerIndices[0]; - if (!followerIndexInfo) { - return response.notFound({ body: `The follower index "${id}" does not exist.` }); - } - - // Retrieve paused state instead of pulling it from the payload to ensure it's not stale. - const isPaused = followerIndexInfo.status === 'paused'; - // Pause follower if not already paused - if (!isPaused) { - await callWithRequest('ccr.pauseFollowerIndex', { id }); - } - - // Resume follower - const body = removeEmptyFields(serializeAdvancedSettings(request.body)); - return response.ok({ - body: await callWithRequest('ccr.resumeFollowerIndex', { id, body }), - }); - } catch (err) { - return mapErrorToKibanaHttpResponse(err); - } - }, - }) - ); - - /** - * Pauses a follower index - */ - router.put( - { - path: `${API_BASE_PATH}/follower_indices/{id}/pause`, - validate: { - params: schema.object({ id: schema.string() }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsPaused: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(_id => - callWithRequest('ccr.pauseFollowerIndex', { id: _id }) - .then(() => itemsPaused.push(_id)) - .catch((err: Error) => { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - }) - ) - ); - - return response.ok({ - body: { - itemsPaused, - errors, - }, - }); - }, - }) - ); - - /** - * Resumes a follower index - */ - router.put( - { - path: `${API_BASE_PATH}/follower_indices/{id}/resume`, - validate: { - params: schema.object({ id: schema.string() }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsResumed: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(_id => - callWithRequest('ccr.resumeFollowerIndex', { id: _id }) - .then(() => itemsResumed.push(_id)) - .catch((err: Error) => { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - }) - ) - ); - - return response.ok({ - body: { - itemsResumed, - errors, - }, - }); - }, - }) - ); - - /** - * Unfollow follower index's leader index - */ - router.put( - { - path: `${API_BASE_PATH}/follower_indices/{id}/unfollow`, - validate: { - params: schema.object({ id: schema.string() }), - }, - }, - licensePreRoutingFactory({ - __LEGACY, - requestHandler: async (ctx, request, response) => { - const callWithRequest = callWithRequestFactory(__LEGACY.server, request); - const { id } = request.params; - const ids = id.split(','); - - const itemsUnfollowed: string[] = []; - const itemsNotOpen: string[] = []; - const errors: Array<{ id: string; error: any }> = []; - - await Promise.all( - ids.map(async _id => { - try { - // Try to pause follower, let it fail silently since it may already be paused - try { - await callWithRequest('ccr.pauseFollowerIndex', { id: _id }); - } catch (e) { - // Swallow errors - } - - // Close index - await callWithRequest('indices.close', { index: _id }); - - // Unfollow leader - await callWithRequest('ccr.unfollowLeaderIndex', { id: _id }); - - // Try to re-open the index, store failures in a separate array to surface warnings in the UI - // This will allow users to query their index normally after unfollowing - try { - await callWithRequest('indices.open', { index: _id }); - } catch (e) { - itemsNotOpen.push(_id); - } - - // Push success - itemsUnfollowed.push(_id); - } catch (err) { - errors.push({ id: _id, error: mapErrorToKibanaHttpResponse(err) }); - } - }) - ); - - return response.ok({ - body: { - itemsUnfollowed, - itemsNotOpen, - errors, - }, - }); - }, - }) - ); -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/map_to_kibana_http_error.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/map_to_kibana_http_error.ts deleted file mode 100644 index 6a81bd26dc47d..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/map_to_kibana_http_error.ts +++ /dev/null @@ -1,26 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { kibanaResponseFactory } from '../../../../../../../src/core/server'; -// @ts-ignore -import { wrapEsError } from '../lib/error_wrappers'; -import { isEsError } from '../lib/is_es_error'; - -export const mapErrorToKibanaHttpResponse = (err: any) => { - if (isEsError(err)) { - const { statusCode, message, body } = wrapEsError(err); - return kibanaResponseFactory.customError({ - statusCode, - body: { - message, - attributes: { - cause: body?.cause, - }, - }, - }); - } - return kibanaResponseFactory.internalError(err); -}; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/types.ts b/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/types.ts deleted file mode 100644 index 7f57c20c536e0..0000000000000 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/routes/types.ts +++ /dev/null @@ -1,13 +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; - * you may not use this file except in compliance with the Elastic License. - */ -import { IRouter } from 'src/core/server'; - -export interface RouteDependencies { - router: IRouter; - __LEGACY: { - server: any; - }; -} diff --git a/x-pack/plugins/cross_cluster_replication/common/constants/index.ts b/x-pack/plugins/cross_cluster_replication/common/constants/index.ts new file mode 100644 index 0000000000000..797141b0996af --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/common/constants/index.ts @@ -0,0 +1,44 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +import { LicenseType } from '../../../licensing/common/types'; + +const platinumLicense: LicenseType = 'platinum'; + +export const PLUGIN = { + ID: 'crossClusterReplication', + TITLE: i18n.translate('xpack.crossClusterReplication.appTitle', { + defaultMessage: 'Cross-Cluster Replication', + }), + minimumLicenseType: platinumLicense, +}; + +export const APPS = { + CCR_APP: 'ccr', + REMOTE_CLUSTER_APP: 'remote_cluster', +}; + +export const MANAGEMENT_ID = 'cross_cluster_replication'; +export const BASE_PATH = `/management/elasticsearch/${MANAGEMENT_ID}`; +export const BASE_PATH_REMOTE_CLUSTERS = '/management/elasticsearch/remote_clusters'; +export const API_BASE_PATH = '/api/cross_cluster_replication'; +export const API_REMOTE_CLUSTERS_BASE_PATH = '/api/remote_clusters'; +export const API_INDEX_MANAGEMENT_BASE_PATH = '/api/index_management'; + +export const FOLLOWER_INDEX_ADVANCED_SETTINGS = { + maxReadRequestOperationCount: 5120, + maxOutstandingReadRequests: 12, + maxReadRequestSize: '32mb', + maxWriteRequestOperationCount: 5120, + maxWriteRequestSize: '9223372036854775807b', + maxOutstandingWriteRequests: 9, + maxWriteBufferCount: 2147483647, + maxWriteBufferSize: '512mb', + maxRetryDelay: '500ms', + readPollTimeout: '1m', +}; diff --git a/x-pack/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.ts.snap b/x-pack/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.ts.snap new file mode 100644 index 0000000000000..c20556fe1434d --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/common/services/__snapshots__/follower_index_serialization.test.ts.snap @@ -0,0 +1,128 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`[CCR] follower index serialization deserializeFollowerIndex() deserializes Elasticsearch follower index object 1`] = ` +Object { + "leaderIndex": "leader 1", + "maxOutstandingReadRequests": 1, + "maxOutstandingWriteRequests": 1, + "maxReadRequestOperationCount": 1, + "maxReadRequestSize": "1b", + "maxRetryDelay": "1s", + "maxWriteBufferCount": 1, + "maxWriteBufferSize": "1b", + "maxWriteRequestOperationCount": 1, + "maxWriteRequestSize": "1b", + "name": "follower index 1", + "readPollTimeout": "1s", + "remoteCluster": "cluster 1", + "shards": Array [ + Object { + "bytesReadCount": 1, + "failedReadRequestsCount": 1, + "failedWriteRequestsCount": 1, + "followerGlobalCheckpoint": 1, + "followerMappingVersion": 1, + "followerMaxSequenceNum": 1, + "followerSettingsVersion": 1, + "id": 1, + "lastRequestedSequenceNum": 1, + "leaderGlobalCheckpoint": 1, + "leaderIndex": "leader 1", + "leaderMaxSequenceNum": 1, + "operationsReadCount": 1, + "operationsWrittenCount": 1, + "outstandingReadRequestsCount": 1, + "outstandingWriteRequestsCount": 1, + "readExceptions": Array [], + "remoteCluster": "cluster 1", + "successfulReadRequestCount": 1, + "successfulWriteRequestsCount": 1, + "timeSinceLastReadMs": 1, + "totalReadRemoteExecTimeMs": 1, + "totalReadTimeMs": 1, + "totalWriteTimeMs": 1, + "writeBufferOperationsCount": 1, + "writeBufferSizeBytes": 1, + }, + Object { + "bytesReadCount": undefined, + "failedReadRequestsCount": undefined, + "failedWriteRequestsCount": undefined, + "followerGlobalCheckpoint": undefined, + "followerMappingVersion": undefined, + "followerMaxSequenceNum": undefined, + "followerSettingsVersion": undefined, + "id": "shard 2", + "lastRequestedSequenceNum": undefined, + "leaderGlobalCheckpoint": undefined, + "leaderIndex": "leader_index 2", + "leaderMaxSequenceNum": undefined, + "operationsReadCount": undefined, + "operationsWrittenCount": undefined, + "outstandingReadRequestsCount": undefined, + "outstandingWriteRequestsCount": undefined, + "readExceptions": undefined, + "remoteCluster": "remote_cluster 2", + "successfulReadRequestCount": undefined, + "successfulWriteRequestsCount": undefined, + "timeSinceLastReadMs": undefined, + "totalReadRemoteExecTimeMs": undefined, + "totalReadTimeMs": undefined, + "totalWriteTimeMs": undefined, + "writeBufferOperationsCount": undefined, + "writeBufferSizeBytes": undefined, + }, + ], + "status": "active", +} +`; + +exports[`[CCR] follower index serialization deserializeShard() deserializes shard 1`] = ` +Object { + "bytesReadCount": 1, + "failedReadRequestsCount": 1, + "failedWriteRequestsCount": 1, + "followerGlobalCheckpoint": 1, + "followerMappingVersion": 1, + "followerMaxSequenceNum": 1, + "followerSettingsVersion": 1, + "id": 1, + "lastRequestedSequenceNum": 1, + "leaderGlobalCheckpoint": 1, + "leaderIndex": "leader index", + "leaderMaxSequenceNum": 1, + "operationsReadCount": 1, + "operationsWrittenCount": 1, + "outstandingReadRequestsCount": 1, + "outstandingWriteRequestsCount": 1, + "readExceptions": Array [ + "read exception", + ], + "remoteCluster": "remote cluster", + "successfulReadRequestCount": 1, + "successfulWriteRequestsCount": 1, + "timeSinceLastReadMs": 1, + "totalReadRemoteExecTimeMs": 1, + "totalReadTimeMs": 1, + "totalWriteTimeMs": 1, + "writeBufferOperationsCount": 1, + "writeBufferSizeBytes": 1, +} +`; + +exports[`[CCR] follower index serialization serializeFollowerIndex() serializes object to Elasticsearch follower index object 1`] = ` +Object { + "leader_index": "leader index", + "max_outstanding_read_requests": 1, + "max_outstanding_write_requests": 1, + "max_read_request_operation_count": 1, + "max_read_request_size": "1b", + "max_retry_delay": "1s", + "max_write_buffer_count": 1, + "max_write_buffer_size": "1b", + "max_write_request_operation_count": 1, + "max_write_request_size": "1b", + "read_poll_timeout": "1s", + "remote_cluster": "remote cluster", +} +`; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.js b/x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.ts similarity index 85% rename from x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.js rename to x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.ts index eef87a6cc4c89..fe3e59f21ee23 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.js +++ b/x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.test.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AutoFollowPattern, AutoFollowPatternFromEs } from '../types'; + import { deserializeAutoFollowPattern, deserializeListAutoFollowPatterns, @@ -12,13 +14,10 @@ import { describe('[CCR] auto-follow_serialization', () => { describe('deserializeAutoFollowPattern()', () => { - it('should return empty object if name or esObject are not provided', () => { - expect(deserializeAutoFollowPattern()).toEqual({}); - }); - it('should deserialize Elasticsearch object', () => { const expected = { name: 'some-name', + active: true, remoteCluster: 'foo', leaderIndexPatterns: ['foo-*'], followIndexPattern: 'bar', @@ -27,13 +26,14 @@ describe('[CCR] auto-follow_serialization', () => { const esObject = { name: 'some-name', pattern: { + active: true, remote_cluster: expected.remoteCluster, leader_index_patterns: expected.leaderIndexPatterns, follow_index_pattern: expected.followIndexPattern, }, }; - expect(deserializeAutoFollowPattern(esObject)).toEqual(expected); + expect(deserializeAutoFollowPattern(esObject as AutoFollowPatternFromEs)).toEqual(expected); }); }); @@ -78,7 +78,9 @@ describe('[CCR] auto-follow_serialization', () => { ], }; - expect(deserializeListAutoFollowPatterns(esObjects.patterns)).toEqual(expected); + expect( + deserializeListAutoFollowPatterns(esObjects.patterns as AutoFollowPatternFromEs[]) + ).toEqual(expected); }); }); @@ -96,7 +98,7 @@ describe('[CCR] auto-follow_serialization', () => { followIndexPattern: expected.follow_index_pattern, }; - expect(serializeAutoFollowPattern(object)).toEqual(expected); + expect(serializeAutoFollowPattern(object as AutoFollowPattern)).toEqual(expected); }); }); }); diff --git a/x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.ts b/x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.ts new file mode 100644 index 0000000000000..265af0ede1462 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/common/services/auto_follow_pattern_serialization.ts @@ -0,0 +1,38 @@ +/* + * 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 { AutoFollowPattern, AutoFollowPatternFromEs, AutoFollowPatternToEs } from '../types'; + +export const deserializeAutoFollowPattern = ( + autoFollowPattern: AutoFollowPatternFromEs +): AutoFollowPattern => { + const { + name, + pattern: { active, remote_cluster, leader_index_patterns, follow_index_pattern }, + } = autoFollowPattern; + + return { + name, + active, + remoteCluster: remote_cluster, + leaderIndexPatterns: leader_index_patterns, + followIndexPattern: follow_index_pattern, + }; +}; + +export const deserializeListAutoFollowPatterns = ( + autoFollowPatterns: AutoFollowPatternFromEs[] +): AutoFollowPattern[] => autoFollowPatterns.map(deserializeAutoFollowPattern); + +export const serializeAutoFollowPattern = ({ + remoteCluster, + leaderIndexPatterns, + followIndexPattern, +}: AutoFollowPattern): AutoFollowPatternToEs => ({ + remote_cluster: remoteCluster, + leader_index_patterns: leaderIndexPatterns, + follow_index_pattern: followIndexPattern, +}); diff --git a/x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.ts b/x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.ts new file mode 100644 index 0000000000000..bfe3e1b3443e6 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.test.ts @@ -0,0 +1,224 @@ +/* + * 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 { ShardFromEs, FollowerIndexFromEs, FollowerIndex } from '../types'; + +import { + deserializeShard, + deserializeFollowerIndex, + deserializeListFollowerIndices, + serializeFollowerIndex, +} from './follower_index_serialization'; + +describe('[CCR] follower index serialization', () => { + describe('deserializeShard()', () => { + it('deserializes shard', () => { + const serializedShard = { + remote_cluster: 'remote cluster', + leader_index: 'leader index', + shard_id: 1, + leader_global_checkpoint: 1, + leader_max_seq_no: 1, + follower_global_checkpoint: 1, + follower_max_seq_no: 1, + last_requested_seq_no: 1, + outstanding_read_requests: 1, + outstanding_write_requests: 1, + write_buffer_operation_count: 1, + write_buffer_size_in_bytes: 1, + follower_mapping_version: 1, + follower_settings_version: 1, + total_read_time_millis: 1, + total_read_remote_exec_time_millis: 1, + successful_read_requests: 1, + failed_read_requests: 1, + operations_read: 1, + bytes_read: 1, + total_write_time_millis: 1, + successful_write_requests: 1, + failed_write_requests: 1, + operations_written: 1, + read_exceptions: ['read exception'], + time_since_last_read_millis: 1, + }; + + expect(deserializeShard(serializedShard as ShardFromEs)).toMatchSnapshot(); + }); + }); + + describe('deserializeFollowerIndex()', () => { + it('deserializes Elasticsearch follower index object', () => { + const serializedFollowerIndex = { + follower_index: 'follower index 1', + remote_cluster: 'cluster 1', + leader_index: 'leader 1', + status: 'active', + parameters: { + max_read_request_operation_count: 1, + max_outstanding_read_requests: 1, + max_read_request_size: '1b', + max_write_request_operation_count: 1, + max_write_request_size: '1b', + max_outstanding_write_requests: 1, + max_write_buffer_count: 1, + max_write_buffer_size: '1b', + max_retry_delay: '1s', + read_poll_timeout: '1s', + }, + shards: [ + { + remote_cluster: 'cluster 1', + leader_index: 'leader 1', + shard_id: 1, + leader_global_checkpoint: 1, + leader_max_seq_no: 1, + follower_global_checkpoint: 1, + follower_max_seq_no: 1, + last_requested_seq_no: 1, + outstanding_read_requests: 1, + outstanding_write_requests: 1, + write_buffer_operation_count: 1, + write_buffer_size_in_bytes: 1, + follower_mapping_version: 1, + follower_settings_version: 1, + total_read_time_millis: 1, + total_read_remote_exec_time_millis: 1, + successful_read_requests: 1, + failed_read_requests: 1, + operations_read: 1, + bytes_read: 1, + total_write_time_millis: 1, + successful_write_requests: 1, + failed_write_requests: 1, + operations_written: 1, + // This is an array of exception objects + read_exceptions: [], + time_since_last_read_millis: 1, + }, + { + remote_cluster: 'remote_cluster 2', + leader_index: 'leader_index 2', + shard_id: 'shard 2', + }, + ], + }; + + expect( + deserializeFollowerIndex(serializedFollowerIndex as FollowerIndexFromEs) + ).toMatchSnapshot(); + }); + }); + + describe('deserializeListFollowerIndices()', () => { + it('deserializes list of Elasticsearch follower index objects', () => { + const serializedFollowerIndexList = [ + { + follower_index: 'follower index 1', + remote_cluster: 'cluster 1', + leader_index: 'leader 1', + status: 'active', + parameters: { + max_read_request_operation_count: 1, + max_outstanding_read_requests: 1, + max_read_request_size: '1b', + max_write_request_operation_count: 1, + max_write_request_size: '1b', + max_outstanding_write_requests: 1, + max_write_buffer_count: 1, + max_write_buffer_size: '1b', + max_retry_delay: '1s', + read_poll_timeout: '1s', + }, + shards: [], + }, + { + follower_index: 'follower index 2', + remote_cluster: 'cluster 2', + leader_index: 'leader 2', + status: 'paused', + parameters: { + max_read_request_operation_count: 2, + max_outstanding_read_requests: 2, + max_read_request_size: '2b', + max_write_request_operation_count: 2, + max_write_request_size: '2b', + max_outstanding_write_requests: 2, + max_write_buffer_count: 2, + max_write_buffer_size: '2b', + max_retry_delay: '2s', + read_poll_timeout: '2s', + }, + shards: [], + }, + ]; + + const deserializedFollowerIndexList = [ + { + name: 'follower index 1', + remoteCluster: 'cluster 1', + leaderIndex: 'leader 1', + status: 'active', + maxReadRequestOperationCount: 1, + maxOutstandingReadRequests: 1, + maxReadRequestSize: '1b', + maxWriteRequestOperationCount: 1, + maxWriteRequestSize: '1b', + maxOutstandingWriteRequests: 1, + maxWriteBufferCount: 1, + maxWriteBufferSize: '1b', + maxRetryDelay: '1s', + readPollTimeout: '1s', + shards: [], + }, + { + name: 'follower index 2', + remoteCluster: 'cluster 2', + leaderIndex: 'leader 2', + status: 'paused', + maxReadRequestOperationCount: 2, + maxOutstandingReadRequests: 2, + maxReadRequestSize: '2b', + maxWriteRequestOperationCount: 2, + maxWriteRequestSize: '2b', + maxOutstandingWriteRequests: 2, + maxWriteBufferCount: 2, + maxWriteBufferSize: '2b', + maxRetryDelay: '2s', + readPollTimeout: '2s', + shards: [], + }, + ]; + + expect(deserializeListFollowerIndices(serializedFollowerIndexList)).toEqual( + deserializedFollowerIndexList + ); + }); + }); + + describe('serializeFollowerIndex()', () => { + it('serializes object to Elasticsearch follower index object', () => { + const deserializedFollowerIndex = { + name: 'test', + status: 'active', + shards: [], + remoteCluster: 'remote cluster', + leaderIndex: 'leader index', + maxReadRequestOperationCount: 1, + maxOutstandingReadRequests: 1, + maxReadRequestSize: '1b', + maxWriteRequestOperationCount: 1, + maxWriteRequestSize: '1b', + maxOutstandingWriteRequests: 1, + maxWriteBufferCount: 1, + maxWriteBufferSize: '1b', + maxRetryDelay: '1s', + readPollTimeout: '1s', + }; + + expect(serializeFollowerIndex(deserializedFollowerIndex as FollowerIndex)).toMatchSnapshot(); + }); + }); +}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.js b/x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.ts similarity index 87% rename from x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.js rename to x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.ts index c41fde8f7818d..df476a0b2db89 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/follower_index_serialization.js +++ b/x-pack/plugins/cross_cluster_replication/common/services/follower_index_serialization.ts @@ -4,7 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable camelcase */ +import { + ShardFromEs, + Shard, + FollowerIndexFromEs, + FollowerIndex, + FollowerIndexToEs, + FollowerIndexAdvancedSettings, + FollowerIndexAdvancedSettingsToEs, +} from '../types'; + export const deserializeShard = ({ remote_cluster, leader_index, @@ -32,7 +41,7 @@ export const deserializeShard = ({ operations_written, read_exceptions, time_since_last_read_millis, -}) => ({ +}: ShardFromEs): Shard => ({ id: shard_id, remoteCluster: remote_cluster, leaderIndex: leader_index, @@ -61,9 +70,7 @@ export const deserializeShard = ({ readExceptions: read_exceptions, timeSinceLastReadMs: time_since_last_read_millis, }); -/* eslint-enable camelcase */ -/* eslint-disable camelcase */ export const deserializeFollowerIndex = ({ follower_index, remote_cluster, @@ -82,7 +89,7 @@ export const deserializeFollowerIndex = ({ read_poll_timeout, } = {}, shards, -}) => ({ +}: FollowerIndexFromEs): FollowerIndex => ({ name: follower_index, remoteCluster: remote_cluster, leaderIndex: leader_index, @@ -99,10 +106,10 @@ export const deserializeFollowerIndex = ({ readPollTimeout: read_poll_timeout, shards: shards && shards.map(deserializeShard), }); -/* eslint-enable camelcase */ -export const deserializeListFollowerIndices = followerIndices => - followerIndices.map(deserializeFollowerIndex); +export const deserializeListFollowerIndices = ( + followerIndices: FollowerIndexFromEs[] +): FollowerIndex[] => followerIndices.map(deserializeFollowerIndex); export const serializeAdvancedSettings = ({ maxReadRequestOperationCount, @@ -115,7 +122,7 @@ export const serializeAdvancedSettings = ({ maxWriteBufferSize, maxRetryDelay, readPollTimeout, -}) => ({ +}: FollowerIndexAdvancedSettings): FollowerIndexAdvancedSettingsToEs => ({ max_read_request_operation_count: maxReadRequestOperationCount, max_outstanding_read_requests: maxOutstandingReadRequests, max_read_request_size: maxReadRequestSize, @@ -128,7 +135,7 @@ export const serializeAdvancedSettings = ({ read_poll_timeout: readPollTimeout, }); -export const serializeFollowerIndex = followerIndex => ({ +export const serializeFollowerIndex = (followerIndex: FollowerIndex): FollowerIndexToEs => ({ remote_cluster: followerIndex.remoteCluster, leader_index: followerIndex.leaderIndex, ...serializeAdvancedSettings(followerIndex), diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/utils.test.js b/x-pack/plugins/cross_cluster_replication/common/services/utils.test.ts similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/common/services/utils.test.js rename to x-pack/plugins/cross_cluster_replication/common/services/utils.test.ts diff --git a/x-pack/legacy/plugins/cross_cluster_replication/common/services/utils.js b/x-pack/plugins/cross_cluster_replication/common/services/utils.ts similarity index 62% rename from x-pack/legacy/plugins/cross_cluster_replication/common/services/utils.js rename to x-pack/plugins/cross_cluster_replication/common/services/utils.ts index 3d8c97f45327c..dda6732254cc3 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/common/services/utils.js +++ b/x-pack/plugins/cross_cluster_replication/common/services/utils.ts @@ -3,14 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -export const arrify = val => (Array.isArray(val) ? val : [val]); +export const arrify = (val: any): any[] => (Array.isArray(val) ? val : [val]); /** * Utilty to add some latency in a Promise chain * * @param {number} time Time in millisecond to wait */ -export const wait = (time = 1000) => data => { +export const wait = (time = 1000) => (data: any): Promise => { return new Promise(resolve => { setTimeout(() => resolve(data), time); }); @@ -19,8 +19,11 @@ export const wait = (time = 1000) => data => { /** * Utility to remove empty fields ("") from a request body */ -export const removeEmptyFields = body => - Object.entries(body).reduce((acc, [key, value]) => { +export const removeEmptyFields = (body: Record): Record => + Object.entries(body).reduce((acc: Record, [key, value]: [string, any]): Record< + string, + any + > => { if (value !== '') { acc[key] = value; } diff --git a/x-pack/plugins/cross_cluster_replication/common/types.ts b/x-pack/plugins/cross_cluster_replication/common/types.ts new file mode 100644 index 0000000000000..4932d6c570297 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/common/types.ts @@ -0,0 +1,186 @@ +/* + * 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. + */ + +export interface AutoFollowPattern { + name: string; + active: boolean; + remoteCluster: string; + leaderIndexPatterns: string[]; + followIndexPattern: string; +} + +export interface AutoFollowPatternFromEs { + name: string; + pattern: { + active: boolean; + remote_cluster: string; + leader_index_patterns: string[]; + follow_index_pattern: string; + }; +} + +export interface AutoFollowPatternToEs { + remote_cluster: string; + leader_index_patterns: string[]; + follow_index_pattern: string; +} + +export interface ShardFromEs { + remote_cluster: string; + leader_index: string; + shard_id: number; + leader_global_checkpoint: number; + leader_max_seq_no: number; + follower_global_checkpoint: number; + follower_max_seq_no: number; + last_requested_seq_no: number; + outstanding_read_requests: number; + outstanding_write_requests: number; + write_buffer_operation_count: number; + write_buffer_size_in_bytes: number; + follower_mapping_version: number; + follower_settings_version: number; + total_read_time_millis: number; + total_read_remote_exec_time_millis: number; + successful_read_requests: number; + failed_read_requests: number; + operations_read: number; + bytes_read: number; + total_write_time_millis: number; + successful_write_requests: number; + failed_write_requests: number; + operations_written: number; + // This is an array of exception objects + read_exceptions: any[]; + time_since_last_read_millis: number; +} + +export interface Shard { + remoteCluster: string; + leaderIndex: string; + id: number; + leaderGlobalCheckpoint: number; + leaderMaxSequenceNum: number; + followerGlobalCheckpoint: number; + followerMaxSequenceNum: number; + lastRequestedSequenceNum: number; + outstandingReadRequestsCount: number; + outstandingWriteRequestsCount: number; + writeBufferOperationsCount: number; + writeBufferSizeBytes: number; + followerMappingVersion: number; + followerSettingsVersion: number; + totalReadTimeMs: number; + totalReadRemoteExecTimeMs: number; + successfulReadRequestCount: number; + failedReadRequestsCount: number; + operationsReadCount: number; + bytesReadCount: number; + totalWriteTimeMs: number; + successfulWriteRequestsCount: number; + failedWriteRequestsCount: number; + operationsWrittenCount: number; + // This is an array of exception objects + readExceptions: any[]; + timeSinceLastReadMs: number; +} + +export interface FollowerIndexFromEs { + follower_index: string; + remote_cluster: string; + leader_index: string; + status: string; + // Once https://github.com/elastic/elasticsearch/issues/54996 is resolved so that paused follower + // indices contain this information, we can removed this optional typing as well as the optional + // typing in FollowerIndexAdvancedSettings and FollowerIndexAdvancedSettingsToEs. + parameters?: FollowerIndexAdvancedSettingsToEs; + shards: ShardFromEs[]; +} + +export interface FollowerIndex extends FollowerIndexAdvancedSettings { + name: string; + remoteCluster: string; + leaderIndex: string; + status: string; + shards: Shard[]; +} + +export interface FollowerIndexToEs extends FollowerIndexAdvancedSettingsToEs { + remote_cluster: string; + leader_index: string; +} + +export interface FollowerIndexAdvancedSettings { + maxReadRequestOperationCount?: number; + maxOutstandingReadRequests?: number; + maxReadRequestSize?: string; // byte value + maxWriteRequestOperationCount?: number; + maxWriteRequestSize?: string; // byte value + maxOutstandingWriteRequests?: number; + maxWriteBufferCount?: number; + maxWriteBufferSize?: string; // byte value + maxRetryDelay?: string; // time value + readPollTimeout?: string; // time value +} + +export interface FollowerIndexAdvancedSettingsToEs { + max_read_request_operation_count?: number; + max_outstanding_read_requests?: number; + max_read_request_size?: string; // byte value + max_write_request_operation_count?: number; + max_write_request_size?: string; // byte value + max_outstanding_write_requests?: number; + max_write_buffer_count?: number; + max_write_buffer_size?: string; // byte value + max_retry_delay?: string; // time value + read_poll_timeout?: string; // time value +} + +export interface RecentAutoFollowError { + timestamp: number; + leaderIndex: string; + autoFollowException: { + type: string; + reason: string; + }; +} + +export interface RecentAutoFollowErrorFromEs { + timestamp: number; + leader_index: string; + auto_follow_exception: { + type: string; + reason: string; + }; +} + +export interface AutoFollowedCluster { + clusterName: string; + timeSinceLastCheckMillis: number; + lastSeenMetadataVersion: number; +} + +export interface AutoFollowedClusterFromEs { + cluster_name: string; + time_since_last_check_millis: number; + last_seen_metadata_version: number; +} + +export interface AutoFollowStats { + numberOfFailedFollowIndices: number; + numberOfFailedRemoteClusterStateRequests: number; + numberOfSuccessfulFollowIndices: number; + recentAutoFollowErrors: RecentAutoFollowError[]; + autoFollowedClusters: AutoFollowedCluster[]; +} + +export interface AutoFollowStatsFromEs { + number_of_failed_follow_indices: number; + number_of_failed_remote_cluster_state_requests: number; + number_of_successful_follow_indices: number; + recent_auto_follow_errors: RecentAutoFollowErrorFromEs[]; + auto_followed_clusters: AutoFollowedClusterFromEs[]; +} diff --git a/x-pack/plugins/cross_cluster_replication/kibana.json b/x-pack/plugins/cross_cluster_replication/kibana.json new file mode 100644 index 0000000000000..ccf98f41def47 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/kibana.json @@ -0,0 +1,17 @@ +{ + "id": "crossClusterReplication", + "version": "kibana", + "server": true, + "ui": true, + "requiredPlugins": [ + "home", + "licensing", + "management", + "remoteClusters", + "indexManagement" + ], + "optionalPlugins": [ + "usageCollection" + ], + "configPath": ["xpack", "ccr"] +} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_add.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_add.test.js similarity index 98% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_add.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_add.test.js index 2be00e70f6f84..db1430d157183 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_add.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_add.test.js @@ -3,11 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; -import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers'; -import { indexPatterns } from '../../../../../../src/plugins/data/public'; -jest.mock('ui/new_platform'); +import { indexPatterns } from '../../../../../../src/plugins/data/public'; +import './mocks'; +import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers'; const { setup } = pageHelpers.autoFollowPatternAdd; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_edit.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_edit.test.js similarity index 95% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_edit.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_edit.test.js index abc3e5dc9def2..170bce7b82085 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_edit.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_edit.test.js @@ -4,13 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; -import { AutoFollowPatternForm } from '../../public/np_ready/app/components/auto_follow_pattern_form'; +import { AutoFollowPatternForm } from '../../app/components/auto_follow_pattern_form'; +import './mocks'; import { setupEnvironment, pageHelpers, nextTick } from './helpers'; import { AUTO_FOLLOW_PATTERN_EDIT } from './helpers/constants'; -jest.mock('ui/new_platform'); - const { setup } = pageHelpers.autoFollowPatternEdit; const { setup: setupAutoFollowPatternAdd } = pageHelpers.autoFollowPatternAdd; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_list.test.js similarity index 97% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_list.test.js index 20e982856dc19..190400e988634 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/auto_follow_pattern_list.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/auto_follow_pattern_list.test.js @@ -4,13 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; +import { getAutoFollowPatternMock } from './fixtures/auto_follow_pattern'; +import './mocks'; import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers'; -import { getAutoFollowPatternClientMock } from '../../fixtures/auto_follow_pattern'; - -jest.mock('ui/new_platform'); - const { setup } = pageHelpers.autoFollowPatternList; describe('', () => { @@ -79,11 +76,11 @@ describe('', () => { const testPrefix = 'prefix_'; const testSuffix = '_suffix'; - const autoFollowPattern1 = getAutoFollowPatternClientMock({ + const autoFollowPattern1 = getAutoFollowPatternMock({ name: `a${getRandomString()}`, followIndexPattern: `${testPrefix}{{leader_index}}${testSuffix}`, }); - const autoFollowPattern2 = getAutoFollowPatternClientMock({ + const autoFollowPattern2 = getAutoFollowPatternMock({ name: `b${getRandomString()}`, followIndexPattern: '{{leader_index}}', // no prefix nor suffix }); @@ -305,10 +302,12 @@ describe('', () => { const message = 'bar'; const recentAutoFollowErrors = [ { + timestamp: 1587081600021, leaderIndex: `${autoFollowPattern1.name}:my-leader-test`, autoFollowException: { type: 'exception', reason: message }, }, { + timestamp: 1587081600021, leaderIndex: `${autoFollowPattern2.name}:my-leader-test`, autoFollowException: { type: 'exception', reason: message }, }, @@ -327,7 +326,7 @@ describe('', () => { expect(exists('autoFollowPatternDetail.errors')).toBe(true); expect(exists('autoFollowPatternDetail.titleErrors')).toBe(true); expect(find('autoFollowPatternDetail.recentError').map(error => error.text())).toEqual([ - message, + 'April 16th, 2020 8:00:00 PM: bar', ]); }); }); diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts new file mode 100644 index 0000000000000..e6444c37e8590 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/auto_follow_pattern.ts @@ -0,0 +1,28 @@ +/* + * 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 { getRandomString } from '../../../../../../test_utils'; +import { AutoFollowPattern } from '../../../../common/types'; + +export const getAutoFollowPatternMock = ({ + name = getRandomString(), + active = false, + remoteCluster = getRandomString(), + leaderIndexPatterns = [`${getRandomString()}-*`], + followIndexPattern = getRandomString(), +}: { + name: string; + active: boolean; + remoteCluster: string; + leaderIndexPatterns: string[]; + followIndexPattern: string; +}): AutoFollowPattern => ({ + name, + active, + remoteCluster, + leaderIndexPatterns, + followIndexPattern, +}); diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts new file mode 100644 index 0000000000000..ff051d470531b --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/fixtures/follower_index.ts @@ -0,0 +1,70 @@ +/* + * 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 { getRandomString } from '../../../../../../test_utils'; +import { FollowerIndex } from '../../../../common/types'; + +const Chance = require('chance'); // eslint-disable-line import/no-extraneous-dependencies, @typescript-eslint/no-var-requires +const chance = new Chance(); + +interface FollowerIndexMock { + name: string; + remoteCluster: string; + leaderIndex: string; + status: string; +} + +export const getFollowerIndexMock = ({ + name = getRandomString(), + remoteCluster = getRandomString(), + leaderIndex = getRandomString(), + status = 'Active', +}: FollowerIndexMock): FollowerIndex => ({ + name, + remoteCluster, + leaderIndex, + status, + maxReadRequestOperationCount: chance.integer(), + maxOutstandingReadRequests: chance.integer(), + maxReadRequestSize: getRandomString({ length: 5 }), + maxWriteRequestOperationCount: chance.integer(), + maxWriteRequestSize: '9223372036854775807b', + maxOutstandingWriteRequests: chance.integer(), + maxWriteBufferCount: chance.integer(), + maxWriteBufferSize: getRandomString({ length: 5 }), + maxRetryDelay: getRandomString({ length: 5 }), + readPollTimeout: getRandomString({ length: 5 }), + shards: [ + { + id: 0, + remoteCluster, + leaderIndex, + leaderGlobalCheckpoint: chance.integer(), + leaderMaxSequenceNum: chance.integer(), + followerGlobalCheckpoint: chance.integer(), + followerMaxSequenceNum: chance.integer(), + lastRequestedSequenceNum: chance.integer(), + outstandingReadRequestsCount: chance.integer(), + outstandingWriteRequestsCount: chance.integer(), + writeBufferOperationsCount: chance.integer(), + writeBufferSizeBytes: chance.integer(), + followerMappingVersion: chance.integer(), + followerSettingsVersion: chance.integer(), + totalReadTimeMs: chance.integer(), + totalReadRemoteExecTimeMs: chance.integer(), + successfulReadRequestCount: chance.integer(), + failedReadRequestsCount: chance.integer(), + operationsReadCount: chance.integer(), + bytesReadCount: chance.integer(), + totalWriteTimeMs: chance.integer(), + successfulWriteRequestsCount: chance.integer(), + failedWriteRequestsCount: chance.integer(), + operationsWrittenCount: chance.integer(), + readExceptions: [], + timeSinceLastReadMs: chance.integer(), + }, + ], +}); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_add.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_add.test.js similarity index 98% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_add.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_add.test.js index 7680be9d858a4..4c99339e16952 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_add.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_add.test.js @@ -4,13 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; -import { RemoteClustersFormField } from '../../public/np_ready/app/components'; - import { indexPatterns } from '../../../../../../src/plugins/data/public'; - -jest.mock('ui/new_platform'); +import './mocks'; +import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { RemoteClustersFormField } from '../../app/components'; const { setup } = pageHelpers.followerIndexAdd; const { setup: setupAutoFollowPatternAdd } = pageHelpers.autoFollowPatternAdd; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_edit.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js similarity index 95% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_edit.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js index cfa37ff2e0358..f4bda2af653aa 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_index_edit.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_index_edit.test.js @@ -4,12 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; -import { setupEnvironment, pageHelpers, nextTick } from './helpers'; -import { FollowerIndexForm } from '../../public/np_ready/app/components/follower_index_form/follower_index_form'; +import { FollowerIndexForm } from '../../app/components/follower_index_form/follower_index_form'; +import './mocks'; import { FOLLOWER_INDEX_EDIT } from './helpers/constants'; - -jest.mock('ui/new_platform'); +import { setupEnvironment, pageHelpers, nextTick } from './helpers'; const { setup } = pageHelpers.followerIndexEdit; const { setup: setupFollowerIndexAdd } = pageHelpers.followerIndexAdd; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_indices_list.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js similarity index 99% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_indices_list.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js index dde31d1d166f9..f98a1dafbbcbf 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/follower_indices_list.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/follower_indices_list.test.js @@ -4,12 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import { getFollowerIndexMock } from './fixtures/follower_index'; +import './mocks'; import { setupEnvironment, pageHelpers, nextTick, getRandomString } from './helpers'; -import { getFollowerIndexMock } from '../../fixtures/follower_index'; - -jest.mock('ui/new_platform'); - const { setup } = pageHelpers.followerIndexList; describe('', () => { diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js similarity index 76% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js index 1f64e589bc4c1..1cb4e7c7725df 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_add.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { AutoFollowPatternAdd } from '../../../public/np_ready/app/sections/auto_follow_pattern_add'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { AutoFollowPatternAdd } from '../../../app/sections/auto_follow_pattern_add'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; const testBedConfig = { store: ccrStore, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js similarity index 82% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js index 2b110c6552072..9cad61893c409 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_edit.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { AutoFollowPatternEdit } from '../../../public/np_ready/app/sections/auto_follow_pattern_edit'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { AutoFollowPatternEdit } from '../../../app/sections/auto_follow_pattern_edit'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; import { AUTO_FOLLOW_PATTERN_EDIT_NAME } from './constants'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js similarity index 92% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js index 1d3e8ad6dff83..450feed49f9f2 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/auto_follow_pattern_list.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed, findTestSubject } from '../../../../../../test_utils'; -import { AutoFollowPatternList } from '../../../public/np_ready/app/sections/home/auto_follow_pattern_list'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { AutoFollowPatternList } from '../../../app/sections/home/auto_follow_pattern_list'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; const testBedConfig = { store: ccrStore, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/constants.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/constants.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/constants.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/constants.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_add.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_add.helpers.js similarity index 79% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_add.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_add.helpers.js index f74baa1b2ad0a..856b09f3f3cba 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_add.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_add.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { FollowerIndexAdd } from '../../../public/np_ready/app/sections/follower_index_add'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { FollowerIndexAdd } from '../../../app/sections/follower_index_add'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; const testBedConfig = { store: ccrStore, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_edit.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_edit.helpers.js similarity index 84% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_edit.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_edit.helpers.js index 47f8539bb593b..893d01f151bc2 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_edit.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_edit.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { FollowerIndexEdit } from '../../../public/np_ready/app/sections/follower_index_edit'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { FollowerIndexEdit } from '../../../app/sections/follower_index_edit'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; import { FOLLOWER_INDEX_EDIT_NAME } from './constants'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_list.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_list.helpers.js similarity index 90% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_list.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_list.helpers.js index 2154e11e17b1f..52f4267594cc1 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/follower_index_list.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/follower_index_list.helpers.js @@ -5,9 +5,9 @@ */ import { registerTestBed, findTestSubject } from '../../../../../../test_utils'; -import { FollowerIndicesList } from '../../../public/np_ready/app/sections/home/follower_indices_list'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; +import { FollowerIndicesList } from '../../../app/sections/home/follower_indices_list'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; const testBedConfig = { store: ccrStore, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/home.helpers.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/home.helpers.js similarity index 68% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/home.helpers.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/home.helpers.js index 664ad909ba8e7..56dfa765bfa4f 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/home.helpers.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/home.helpers.js @@ -5,10 +5,10 @@ */ import { registerTestBed } from '../../../../../../test_utils'; -import { CrossClusterReplicationHome } from '../../../public/np_ready/app/sections/home/home'; -import { ccrStore } from '../../../public/np_ready/app/store'; -import routing from '../../../public/np_ready/app/services/routing'; -import { BASE_PATH } from '../../../common/constants'; +import { BASE_PATH } from '../../../../common/constants'; +import { CrossClusterReplicationHome } from '../../../app/sections/home/home'; +import { ccrStore } from '../../../app/store'; +import { routing } from '../../../app/services/routing'; const testBedConfig = { store: ccrStore, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/http_requests.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/http_requests.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/http_requests.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/index.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/index.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/setup_environment.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/setup_environment.js similarity index 91% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/setup_environment.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/setup_environment.js index 3562ad0df5b51..6dedbbfa79b19 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/helpers/setup_environment.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/helpers/setup_environment.js @@ -7,7 +7,7 @@ import axios from 'axios'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; -import { setHttpClient } from '../../../public/np_ready/app/services/api'; +import { setHttpClient } from '../../../app/services/api'; import { init as initHttpRequests } from './http_requests'; export const setupEnvironment = () => { diff --git a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/home.test.js b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/home.test.js similarity index 93% rename from x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/home.test.js rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/home.test.js index 2c536d069ef53..18d8b4eb9dbe0 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/__jest__/client_integration/home.test.js +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/home.test.js @@ -4,11 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../public/np_ready/app/services/breadcrumbs.mock'; +import './mocks'; import { setupEnvironment, pageHelpers, nextTick } from './helpers'; -jest.mock('ui/new_platform'); - const { setup } = pageHelpers.home; describe('', () => { @@ -36,7 +34,7 @@ describe('', () => { ({ exists, find, component } = setup()); }); - test('should set the correct an app title', () => { + test('should set the correct app title', () => { expect(exists('appTitle')).toBe(true); expect(find('appTitle').text()).toEqual('Cross-Cluster Replication'); }); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/breadcrumbs.mock.ts b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/breadcrumbs.mock.ts similarity index 70% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/breadcrumbs.mock.ts rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/breadcrumbs.mock.ts index b7c75108d4ef0..60a196254d408 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/services/breadcrumbs.mock.ts +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/breadcrumbs.mock.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('./breadcrumbs', () => ({ - ...jest.requireActual('./breadcrumbs'), +jest.mock('../../../app/services/breadcrumbs', () => ({ + ...jest.requireActual('../../../app/services/breadcrumbs'), setBreadcrumbs: jest.fn(), })); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/index.ts b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/index.ts similarity index 79% rename from x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/index.ts rename to x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/index.ts index 441648a8701e0..cff9c003f3e80 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/server/np_ready/lib/is_es_error_factory/index.ts +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { isEsErrorFactory } from './is_es_error_factory'; +import './breadcrumbs.mock'; +import './track_ui_metric.mock'; diff --git a/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/track_ui_metric.mock.ts b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/track_ui_metric.mock.ts new file mode 100644 index 0000000000000..016e259343285 --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/public/__jest__/client_integration/mocks/track_ui_metric.mock.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +jest.mock('../../../app/services/track_ui_metric', () => ({ + ...jest.requireActual('../../../app/services/track_ui_metric'), + trackUiMetric: jest.fn(), + trackUserRequest: (request: Promise) => { + return request.then(response => response); + }, +})); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/app.js b/x-pack/plugins/cross_cluster_replication/public/app/app.tsx similarity index 89% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/app.js rename to x-pack/plugins/cross_cluster_replication/public/app/app.tsx index 968646a4bd1b0..ec349ccd6f2c7 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/app.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/app.tsx @@ -5,8 +5,8 @@ */ import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { Route, Switch, Redirect, withRouter } from 'react-router-dom'; +import { Route, Switch, Redirect, withRouter, RouteComponentProps } from 'react-router-dom'; +import { History } from 'history'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -20,12 +20,14 @@ import { EuiTitle, } from '@elastic/eui'; -import { BASE_PATH } from '../../../common/constants'; +import { BASE_PATH } from '../../common/constants'; import { getFatalErrors } from './services/notifications'; import { SectionError } from './components'; -import routing from './services/routing'; +import { routing } from './services/routing'; +// @ts-ignore import { loadPermissions } from './services/api'; +// @ts-ignore import { CrossClusterReplicationHome, AutoFollowPatternAdd, @@ -34,16 +36,21 @@ import { FollowerIndexEdit, } from './sections'; -class AppComponent extends Component { - static propTypes = { - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired, - }).isRequired, - }; +interface AppProps { + history: History; + location: any; +} + +interface AppState { + isFetchingPermissions: boolean; + fetchPermissionError: any; + hasPermission: boolean; + missingClusterPrivileges: any[]; +} - constructor(...args) { - super(...args); +class AppComponent extends Component { + constructor(props: any) { + super(props); this.registerRouter(); this.state = { @@ -54,18 +61,10 @@ class AppComponent extends Component { }; } - UNSAFE_componentWillMount() { - routing.userHasLeftApp = false; - } - componentDidMount() { this.checkPermissions(); } - componentWillUnmount() { - routing.userHasLeftApp = true; - } - async checkPermissions() { this.setState({ isFetchingPermissions: true, @@ -163,7 +162,6 @@ class AppComponent extends Component { - + ( diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/remote_clusters_provider.js b/x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_provider.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/remote_clusters_provider.js rename to x-pack/plugins/cross_cluster_replication/public/app/components/remote_clusters_provider.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_error.js b/x-pack/plugins/cross_cluster_replication/public/app/components/section_error.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_error.js rename to x-pack/plugins/cross_cluster_replication/public/app/components/section_error.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_loading.js b/x-pack/plugins/cross_cluster_replication/public/app/components/section_loading.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_loading.js rename to x-pack/plugins/cross_cluster_replication/public/app/components/section_loading.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_unauthorized.js b/x-pack/plugins/cross_cluster_replication/public/app/components/section_unauthorized.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/components/section_unauthorized.js rename to x-pack/plugins/cross_cluster_replication/public/app/components/section_unauthorized.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/api.js b/x-pack/plugins/cross_cluster_replication/public/app/constants/api.ts similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/api.js rename to x-pack/plugins/cross_cluster_replication/public/app/constants/api.ts diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/index.js b/x-pack/plugins/cross_cluster_replication/public/app/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/constants/index.ts diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/sections.js b/x-pack/plugins/cross_cluster_replication/public/app/constants/sections.ts similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/sections.js rename to x-pack/plugins/cross_cluster_replication/public/app/constants/sections.ts diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/ui_metric.js b/x-pack/plugins/cross_cluster_replication/public/app/constants/ui_metric.ts similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/constants/ui_metric.js rename to x-pack/plugins/cross_cluster_replication/public/app/constants/ui_metric.ts diff --git a/x-pack/plugins/cross_cluster_replication/public/app/index.tsx b/x-pack/plugins/cross_cluster_replication/public/app/index.tsx new file mode 100644 index 0000000000000..79569b587f97f --- /dev/null +++ b/x-pack/plugins/cross_cluster_replication/public/app/index.tsx @@ -0,0 +1,52 @@ +/* + * 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 React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { Provider } from 'react-redux'; +import { HashRouter } from 'react-router-dom'; +import { I18nStart } from 'kibana/public'; +import { UnmountCallback } from 'src/core/public'; + +import { init as initBreadcrumbs, SetBreadcrumbs } from './services/breadcrumbs'; +import { init as initDocumentation } from './services/documentation_links'; +import { App } from './app'; +import { ccrStore } from './store'; + +const renderApp = (element: Element, I18nContext: I18nStart['Context']): UnmountCallback => { + render( + + + + + + + , + element + ); + + return () => unmountComponentAtNode(element); +}; + +export async function mountApp({ + element, + setBreadcrumbs, + I18nContext, + ELASTIC_WEBSITE_URL, + DOC_LINK_VERSION, +}: { + element: Element; + setBreadcrumbs: SetBreadcrumbs; + I18nContext: I18nStart['Context']; + ELASTIC_WEBSITE_URL: string; + DOC_LINK_VERSION: string; +}): Promise { + // Import and initialize additional services here instead of in plugin.ts to reduce the size of the + // initial bundle as much as possible. + initBreadcrumbs(setBreadcrumbs); + initDocumentation(`${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/`); + + return renderApp(element, I18nContext); +} diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/auto_follow_pattern_add.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/index.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_add/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_add/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js similarity index 80% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js index 2c90456076f85..be470edc07537 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.container.js @@ -39,8 +39,23 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ getAutoFollowPattern: id => dispatch(getAutoFollowPattern(id)), selectAutoFollowPattern: id => dispatch(selectEditAutoFollowPattern(id)), - saveAutoFollowPattern: (id, autoFollowPattern) => - dispatch(saveAutoFollowPattern(id, autoFollowPattern, true)), + saveAutoFollowPattern: (id, autoFollowPattern) => { + // Strip out errors. + const { active, remoteCluster, leaderIndexPatterns, followIndexPattern } = autoFollowPattern; + + dispatch( + saveAutoFollowPattern( + id, + { + active, + remoteCluster, + leaderIndexPatterns, + followIndexPattern, + }, + true + ) + ); + }, clearApiError: () => { dispatch(clearApiError(`${scope}-get`)); dispatch(clearApiError(`${scope}-save`)); diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js similarity index 99% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js index 4cd3617abd989..387d7817a0357 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/auto_follow_pattern_edit.js @@ -12,7 +12,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiPageContent, EuiSpacer } from '@elastic/eui'; import { listBreadcrumb, editBreadcrumb, setBreadcrumbs } from '../../services/breadcrumbs'; -import routing from '../../services/routing'; +import { routing } from '../../services/routing'; import { AutoFollowPatternForm, AutoFollowPatternPageTitle, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/index.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/auto_follow_pattern_edit/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/auto_follow_pattern_edit/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/follower_index_add.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/follower_index_add.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/follower_index_add.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/follower_index_add.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/follower_index_add.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/index.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_add/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_add/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/follower_index_edit.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/follower_index_edit.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/follower_index_edit.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js similarity index 99% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/follower_index_edit.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js index 21493602c12a7..22f9a7338384b 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/follower_index_edit.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/follower_index_edit.js @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { setBreadcrumbs, listBreadcrumb, editBreadcrumb } from '../../services/breadcrumbs'; -import routing from '../../services/routing'; +import { routing } from '../../services/routing'; import { FollowerIndexForm, FollowerIndexPageTitle, diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/index.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/follower_index_edit/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/follower_index_edit/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js similarity index 99% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js index e9e14f57e814f..c8cf94842aa68 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/auto_follow_pattern_list.js @@ -17,7 +17,7 @@ import { EuiSpacer, } from '@elastic/eui'; -import routing from '../../../services/routing'; +import { routing } from '../../../services/routing'; import { extractQueryParams } from '../../../services/query_params'; import { trackUiMetric, METRIC_TYPE } from '../../../services/track_ui_metric'; import { API_STATUS, UIM_AUTO_FOLLOW_PATTERN_LIST_LOAD } from '../../../constants'; diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js similarity index 97% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js index 956a9f10d810b..eb90e59e99fee 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/auto_follow_pattern_table.js @@ -20,8 +20,8 @@ import { AutoFollowPatternDeleteProvider, AutoFollowPatternActionMenu, } from '../../../../../components'; -import routing from '../../../../../services/routing'; -import { trackUiMetric, METRIC_TYPE } from '../../../../../services/track_ui_metric'; +import { routing } from '../../../../../services/routing'; +import { trackUiMetric } from '../../../../../services/track_ui_metric'; export class AutoFollowPatternTable extends PureComponent { static propTypes = { @@ -86,7 +86,7 @@ export class AutoFollowPatternTable extends PureComponent { return ( { - trackUiMetric(METRIC_TYPE.CLICK, UIM_AUTO_FOLLOW_PATTERN_SHOW_DETAILS_CLICK); + trackUiMetric('click', UIM_AUTO_FOLLOW_PATTERN_SHOW_DETAILS_CLICK); selectAutoFollowPattern(name); }} data-test-subj="autoFollowPatternLink" diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/auto_follow_pattern_table/index.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.js similarity index 100% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.container.js diff --git a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js similarity index 98% rename from x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js rename to x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js index 1a6d5e6efe35a..3f2ed82420ff1 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/public/np_ready/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js +++ b/x-pack/plugins/cross_cluster_replication/public/app/sections/home/auto_follow_pattern_list/components/detail_panel/detail_panel.js @@ -7,7 +7,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n/react'; -import { getIndexListUri } from '../../../../../../../../../../../plugins/index_management/public'; +import moment from 'moment'; + +import { getIndexListUri } from '../../../../../../../../../plugins/index_management/public'; import { EuiButtonEmpty, @@ -247,6 +249,7 @@ export class DetailPanel extends Component {