diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index bbbcc062786b0..b3744f7cf93ab 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -24,7 +24,7 @@ "xpack.lens": "legacy/plugins/lens", "xpack.licenseMgmt": "plugins/license_management", "xpack.licensing": "plugins/licensing", - "xpack.logstash": "legacy/plugins/logstash", + "xpack.logstash": ["plugins/logstash", "legacy/plugins/logstash"], "xpack.main": "legacy/plugins/xpack_main", "xpack.maps": ["plugins/maps", "legacy/plugins/maps"], "xpack.ml": ["plugins/ml", "legacy/plugins/ml"], diff --git a/x-pack/legacy/plugins/logstash/index.js b/x-pack/legacy/plugins/logstash/index.js index ae8571d1c19c3..29f01032f3413 100755 --- a/x-pack/legacy/plugins/logstash/index.js +++ b/x-pack/legacy/plugins/logstash/index.js @@ -5,12 +5,8 @@ */ import { resolve } from 'path'; -import { registerLogstashPipelinesRoutes } from './server/routes/api/pipelines'; -import { registerLogstashPipelineRoutes } from './server/routes/api/pipeline'; -import { registerLogstashUpgradeRoutes } from './server/routes/api/upgrade'; -import { registerLogstashClusterRoutes } from './server/routes/api/cluster'; import { registerLicenseChecker } from './server/lib/register_license_checker'; -import { PLUGIN } from './common/constants'; +import { PLUGIN } from '../../../plugins/logstash/common/constants'; export const logstash = kibana => new kibana.Plugin({ @@ -32,9 +28,5 @@ export const logstash = kibana => }, init: server => { registerLicenseChecker(server); - registerLogstashPipelinesRoutes(server); - registerLogstashPipelineRoutes(server); - registerLogstashUpgradeRoutes(server); - registerLogstashClusterRoutes(server); }, }); diff --git a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js b/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js index 43ca656e0827c..5e430ccbd8ceb 100644 --- a/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js +++ b/x-pack/legacy/plugins/logstash/public/components/pipeline_editor/pipeline_editor.js @@ -13,7 +13,7 @@ import 'brace/mode/plain_text'; import 'brace/theme/github'; import { isEmpty } from 'lodash'; -import { TOOLTIPS } from '../../../common/constants/tooltips'; +import { TOOLTIPS } from '../../../../../../plugins/logstash/common/constants/tooltips'; import { EuiButton, EuiButtonEmpty, diff --git a/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts b/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts index e943656120d5e..2e1ee2afb9ce6 100644 --- a/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts +++ b/x-pack/legacy/plugins/logstash/public/lib/register_home_feature.ts @@ -10,7 +10,7 @@ import { npSetup } from 'ui/new_platform'; import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; import { FeatureCatalogueCategory } from '../../../../../../src/plugins/home/public'; // @ts-ignore -import { PLUGIN } from '../../common/constants'; +import { PLUGIN } from '../../../../../plugins/logstash/common/constants'; const { plugins: { home }, diff --git a/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js b/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js index 14900fdaa7cdc..06d01a05bac27 100755 --- a/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js +++ b/x-pack/legacy/plugins/logstash/public/models/pipeline_list_item/pipeline_list_item.js @@ -8,7 +8,7 @@ import { pick, capitalize } from 'lodash'; import { getSearchValue } from 'plugins/logstash/lib/get_search_value'; import { getMoment } from 'plugins/logstash/../common/lib/get_moment'; -import { PIPELINE } from '../../../common/constants'; +import { PIPELINE } from '../../../../../../plugins/logstash/common/constants'; /** * Represents the model for listing pipelines in the UI diff --git a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js b/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js index 4bad4f48cc61d..e89c2fe7d11bf 100755 --- a/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/cluster/cluster_service.js @@ -5,7 +5,7 @@ */ import chrome from 'ui/chrome'; -import { ROUTES } from '../../../common/constants'; +import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; import { Cluster } from 'plugins/logstash/models/cluster'; export class ClusterService { diff --git a/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js b/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js index 97b336ec0728b..69cc8614a6ae2 100755 --- a/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/license/logstash_license_service.js @@ -7,7 +7,7 @@ import React from 'react'; import { toastNotifications } from 'ui/notify'; import { MarkdownSimple } from '../../../../../../../src/plugins/kibana_react/public'; -import { PLUGIN } from '../../../common/constants'; +import { PLUGIN } from '../../../../../../plugins/logstash/common/constants'; export class LogstashLicenseService { constructor(xpackInfoService, kbnUrlService, $timeout) { diff --git a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js b/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js index 8a267e38db738..6103e730c2171 100755 --- a/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/monitoring/monitoring_service.js @@ -6,7 +6,7 @@ import moment from 'moment'; import chrome from 'ui/chrome'; -import { ROUTES, MONITORING } from '../../../common/constants'; +import { ROUTES, MONITORING } from '../../../../../../plugins/logstash/common/constants'; import { PipelineListItem } from 'plugins/logstash/models/pipeline_list_item'; export class MonitoringService { diff --git a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js b/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js index 0696bf9d83256..b5d0dbeb852d5 100755 --- a/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/pipeline/pipeline_service.js @@ -5,7 +5,7 @@ */ import chrome from 'ui/chrome'; -import { ROUTES } from '../../../common/constants'; +import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; import { Pipeline } from 'plugins/logstash/models/pipeline'; export class PipelineService { diff --git a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js b/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js index 5a43cf07eba41..d70c8be06fde4 100755 --- a/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/pipelines/pipelines_service.js @@ -5,7 +5,7 @@ */ import chrome from 'ui/chrome'; -import { ROUTES, MONITORING } from '../../../common/constants'; +import { ROUTES, MONITORING } from '../../../../../../plugins/logstash/common/constants'; import { PipelineListItem } from 'plugins/logstash/models/pipeline_list_item'; const RECENTLY_DELETED_PIPELINE_IDS_STORAGE_KEY = 'xpack.logstash.recentlyDeletedPipelines'; diff --git a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js b/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js index 7870a495d07a3..2019bdc1bf1aa 100755 --- a/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js +++ b/x-pack/legacy/plugins/logstash/public/services/upgrade/upgrade_service.js @@ -5,7 +5,7 @@ */ import chrome from 'ui/chrome'; -import { ROUTES } from '../../../common/constants'; +import { ROUTES } from '../../../../../../plugins/logstash/common/constants'; export class UpgradeService { constructor($http) { diff --git a/x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/call_with_request_factory.js b/x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/call_with_request_factory.js deleted file mode 100755 index 8dc09d394e973..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/call_with_request_factory.js +++ /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 { once } from 'lodash'; - -const callWithRequest = once(server => { - const cluster = server.plugins.elasticsearch.createCluster('logstash'); - return cluster.callWithRequest; -}); - -export const callWithRequestFactory = (server, request) => { - return (...args) => { - return callWithRequest(server)(request, ...args); - }; -}; diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_custom_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_custom_error.js deleted file mode 100755 index f9c102be7a1ff..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_custom_error.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 expect from '@kbn/expect'; -import { wrapCustomError } from '../wrap_custom_error'; - -describe('wrap_custom_error', () => { - describe('#wrapCustomError', () => { - it('should return a Boom object', () => { - const originalError = new Error('I am an error'); - const statusCode = 404; - const wrappedError = wrapCustomError(originalError, statusCode); - - expect(wrappedError.isBoom).to.be(true); - expect(wrappedError.output.statusCode).to.equal(statusCode); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_es_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_es_error.js deleted file mode 100755 index cab25cd0b1b10..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_es_error.js +++ /dev/null @@ -1,42 +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; - }); - - it('should return a Boom object', () => { - const wrappedError = wrapEsError(originalError); - - expect(wrappedError.isBoom).to.be(true); - }); - - it('should return the correct Boom object', () => { - const wrappedError = wrapEsError(originalError); - - expect(wrappedError.output.statusCode).to.be(originalError.statusCode); - expect(wrappedError.output.payload.message).to.be(originalError.message); - }); - - it('should return invalid permissions message for 403 errors', () => { - const securityError = new Error('I am an error'); - securityError.statusCode = 403; - const wrappedError = wrapEsError(securityError); - - expect(wrappedError.isBoom).to.be(true); - expect(wrappedError.message).to.be( - 'Insufficient user permissions for managing Logstash pipelines' - ); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_unknown_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_unknown_error.js deleted file mode 100755 index 85e0b2b3033ad..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/__tests__/wrap_unknown_error.js +++ /dev/null @@ -1,19 +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 { wrapUnknownError } from '../wrap_unknown_error'; - -describe('wrap_unknown_error', () => { - describe('#wrapUnknownError', () => { - it('should return a Boom object', () => { - const originalError = new Error('I am an error'); - const wrappedError = wrapUnknownError(originalError); - - expect(wrappedError.isBoom).to.be(true); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_custom_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_custom_error.js deleted file mode 100755 index 3295113d38ee5..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_custom_error.js +++ /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 Boom from 'boom'; - -/** - * Wraps a custom error into a Boom error response and returns it - * - * @param err Object error - * @param statusCode Error status code - * @return Object Boom error response - */ -export function wrapCustomError(err, statusCode) { - return Boom.boomify(err, { statusCode }); -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_es_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_es_error.js deleted file mode 100755 index 41819179bde55..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_es_error.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 Boom from 'boom'; -import { i18n } from '@kbn/i18n'; - -/** - * Wraps ES errors into a Boom error response and returns it - * This also handles the permissions issue gracefully - * - * @param err Object ES error - * @return Object Boom error response - */ -export function wrapEsError(err) { - const statusCode = err.statusCode; - if (statusCode === 403) { - return Boom.forbidden( - i18n.translate('xpack.logstash.insufficientUserPermissionsDescription', { - defaultMessage: 'Insufficient user permissions for managing Logstash pipelines', - }) - ); - } - return Boom.boomify(err, { statusCode: err.statusCode }); -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_unknown_error.js b/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_unknown_error.js deleted file mode 100755 index ffd915c513362..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/wrap_unknown_error.js +++ /dev/null @@ -1,17 +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 Boom from 'boom'; - -/** - * Wraps an unknown error into a Boom error response and returns it - * - * @param err Object Unknown error - * @return Object Boom error response - */ -export function wrapUnknownError(err) { - return Boom.boomify(err); -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js b/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js deleted file mode 100755 index b1593fb1ba355..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/__tests__/fetch_all_from_scroll.js +++ /dev/null @@ -1,88 +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 sinon from 'sinon'; -import { fetchAllFromScroll } from '../fetch_all_from_scroll'; -import { set } from 'lodash'; - -describe('fetch_all_from_scroll', () => { - let mockResponse; - let stubCallWithRequest; - - beforeEach(() => { - mockResponse = {}; - - stubCallWithRequest = sinon.stub(); - stubCallWithRequest.onCall(0).returns( - new Promise(resolve => { - const mockInnerResponse = { - hits: { - hits: ['newhit'], - }, - _scroll_id: 'newScrollId', - }; - return resolve(mockInnerResponse); - }) - ); - - stubCallWithRequest.onCall(1).returns( - new Promise(resolve => { - const mockInnerResponse = { - hits: { - hits: [], - }, - }; - return resolve(mockInnerResponse); - }) - ); - }); - - describe('#fetchAllFromScroll', () => { - describe('when the passed-in response has no hits', () => { - beforeEach(() => { - set(mockResponse, 'hits.hits', []); - }); - - it('should return an empty array of hits', () => { - return fetchAllFromScroll(mockResponse).then(hits => { - expect(hits).to.eql([]); - }); - }); - - it('should not call callWithRequest', () => { - return fetchAllFromScroll(mockResponse, stubCallWithRequest).then(() => { - expect(stubCallWithRequest.called).to.be(false); - }); - }); - }); - - describe('when the passed-in response has some hits', () => { - beforeEach(() => { - set(mockResponse, 'hits.hits', ['foo', 'bar']); - set(mockResponse, '_scroll_id', 'originalScrollId'); - }); - - it('should return the hits from the response', () => { - return fetchAllFromScroll(mockResponse, stubCallWithRequest).then(hits => { - expect(hits).to.eql(['foo', 'bar', 'newhit']); - }); - }); - - it('should call callWithRequest', () => { - return fetchAllFromScroll(mockResponse, stubCallWithRequest).then(() => { - expect(stubCallWithRequest.calledTwice).to.be(true); - - const firstCallWithRequestCallArgs = stubCallWithRequest.args[0]; - expect(firstCallWithRequestCallArgs[1].body.scroll_id).to.eql('originalScrollId'); - - const secondCallWithRequestCallArgs = stubCallWithRequest.args[1]; - expect(secondCallWithRequestCallArgs[1].body.scroll_id).to.eql('newScrollId'); - }); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.js b/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.js deleted file mode 100755 index 835ef0090a5d2..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.js +++ /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 { get } from 'lodash'; -import { ES_SCROLL_SETTINGS } from '../../../common/constants'; - -export function fetchAllFromScroll(response, callWithRequest, hits = []) { - const newHits = get(response, 'hits.hits', []); - const scrollId = get(response, '_scroll_id'); - - if (newHits.length > 0) { - hits.push(...newHits); - - return callWithRequest('scroll', { - body: { - scroll: ES_SCROLL_SETTINGS.KEEPALIVE, - scroll_id: scrollId, - }, - }).then(innerResponse => { - return fetchAllFromScroll(innerResponse, callWithRequest, hits); - }); - } - - return Promise.resolve(hits); -} diff --git a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js b/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js deleted file mode 100755 index 1dc1df922acf7..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/__tests__/license_pre_routing_factory.js +++ /dev/null @@ -1,69 +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 { licensePreRoutingFactory } from '../license_pre_routing_factory'; - -describe('license_pre_routing_factory', () => { - describe('#logstashFeaturePreRoutingFactory', () => { - let mockServer; - let mockLicenseCheckResults; - - beforeEach(() => { - mockServer = { - plugins: { - xpack_main: { - info: { - feature: () => ({ - getLicenseCheckResults: () => mockLicenseCheckResults, - }), - }, - }, - }, - }; - }); - - it('only instantiates one instance per server', () => { - const firstInstance = licensePreRoutingFactory(mockServer); - const secondInstance = licensePreRoutingFactory(mockServer); - - expect(firstInstance).to.be(secondInstance); - }); - - describe('isAvailable is false', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: false, - }; - }); - - it('replies with 403', () => { - const licensePreRouting = licensePreRoutingFactory(mockServer); - const stubRequest = {}; - expect(() => licensePreRouting(stubRequest)).to.throwException(response => { - expect(response).to.be.an(Error); - expect(response.isBoom).to.be(true); - expect(response.output.statusCode).to.be(403); - }); - }); - }); - - describe('isAvailable is true', () => { - beforeEach(() => { - mockLicenseCheckResults = { - isAvailable: true, - }; - }); - - it('replies with nothing', () => { - const licensePreRouting = licensePreRoutingFactory(mockServer); - const stubRequest = {}; - const response = licensePreRouting(stubRequest); - expect(response).to.be(null); - }); - }); - }); -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/license_pre_routing_factory.js b/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/license_pre_routing_factory.js deleted file mode 100755 index 05402a56a52d8..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/license_pre_routing_factory.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 { once } from 'lodash'; -import { wrapCustomError } from '../error_wrappers'; -import { PLUGIN } from '../../../common/constants'; - -export const licensePreRoutingFactory = once(server => { - const xpackMainPlugin = server.plugins.xpack_main; - - // License checking and enable/disable logic - function licensePreRouting() { - const licenseCheckResults = xpackMainPlugin.info.feature(PLUGIN.ID).getLicenseCheckResults(); - if (!licenseCheckResults.isAvailable) { - const error = new Error(licenseCheckResults.message); - const statusCode = 403; - throw wrapCustomError(error, statusCode); - } - - return null; - } - - return licensePreRouting; -}); diff --git a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js b/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js index 8a17fb2eea497..a0d06e77b410d 100755 --- a/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js +++ b/x-pack/legacy/plugins/logstash/server/lib/register_license_checker/register_license_checker.js @@ -6,7 +6,7 @@ import { mirrorPluginStatus } from '../../../../../server/lib/mirror_plugin_status'; import { checkLicense } from '../check_license'; -import { PLUGIN } from '../../../common/constants'; +import { PLUGIN } from '../../../../../../plugins/logstash/common/constants'; export function registerLicenseChecker(server) { const xpackMainPlugin = server.plugins.xpack_main; diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_cluster_routes.js b/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_cluster_routes.js deleted file mode 100755 index 86e18b02ddce2..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_cluster_routes.js +++ /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 { registerLoadRoute } from './register_load_route'; - -export function registerLogstashClusterRoutes(server) { - registerLoadRoute(server); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_load_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_load_route.js deleted file mode 100755 index 663b60cc8c1d1..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/register_load_route.js +++ /dev/null @@ -1,40 +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 Boom from 'boom'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { Cluster } from '../../../models/cluster'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function fetchCluster(callWithRequest) { - return callWithRequest('info'); -} - -export function registerLoadRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/cluster', - method: 'GET', - handler: (request, h) => { - const callWithRequest = callWithRequestFactory(server, request); - - return fetchCluster(callWithRequest) - .then(responseFromES => ({ - cluster: Cluster.fromUpstreamJSON(responseFromES).downstreamJSON, - })) - .catch(e => { - if (e.status === 403) { - return h.response(); - } - throw Boom.internal(e); - }); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_delete_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_delete_route.js deleted file mode 100755 index 232ee4207541c..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_delete_route.js +++ /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 { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { wrapEsError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function deletePipeline(callWithRequest, pipelineId) { - return callWithRequest('delete', { - index: INDEX_NAMES.PIPELINES, - id: pipelineId, - refresh: 'wait_for', - }); -} - -export function registerDeleteRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/pipeline/{id}', - method: 'DELETE', - handler: (request, h) => { - const callWithRequest = callWithRequestFactory(server, request); - const pipelineId = request.params.id; - - return deletePipeline(callWithRequest, pipelineId) - .then(() => h.response().code(204)) - .catch(e => wrapEsError(e)); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_load_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_load_route.js deleted file mode 100755 index 796bf939d747f..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_load_route.js +++ /dev/null @@ -1,47 +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 Boom from 'boom'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { Pipeline } from '../../../models/pipeline'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function fetchPipeline(callWithRequest, pipelineId) { - return callWithRequest('get', { - index: INDEX_NAMES.PIPELINES, - id: pipelineId, - _source: ['description', 'username', 'pipeline', 'pipeline_settings'], - ignore: [404], - }); -} - -export function registerLoadRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/pipeline/{id}', - method: 'GET', - handler: request => { - const callWithRequest = callWithRequestFactory(server, request); - const pipelineId = request.params.id; - - return fetchPipeline(callWithRequest, pipelineId) - .then(pipelineResponseFromES => { - if (!pipelineResponseFromES.found) { - throw Boom.notFound(); - } - - const pipeline = Pipeline.fromUpstreamJSON(pipelineResponseFromES); - return pipeline.downstreamJSON; - }) - .catch(e => Boom.boomify(e)); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_pipeline_routes.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_pipeline_routes.js deleted file mode 100755 index 9966cd2ca2139..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_pipeline_routes.js +++ /dev/null @@ -1,15 +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 { registerLoadRoute } from './register_load_route'; -import { registerDeleteRoute } from './register_delete_route'; -import { registerSaveRoute } from './register_save_route'; - -export function registerLogstashPipelineRoutes(server) { - registerLoadRoute(server); - registerDeleteRoute(server); - registerSaveRoute(server); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_save_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_save_route.js deleted file mode 100755 index 50f62dc0a0ddd..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/register_save_route.js +++ /dev/null @@ -1,48 +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 { get } from 'lodash'; -import { wrapEsError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { Pipeline } from '../../../models/pipeline'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function savePipeline(callWithRequest, pipelineId, pipelineBody) { - return callWithRequest('index', { - index: INDEX_NAMES.PIPELINES, - id: pipelineId, - body: pipelineBody, - refresh: 'wait_for', - }); -} - -export function registerSaveRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/pipeline/{id}', - method: 'PUT', - handler: async (request, h) => { - let username; - if (server.plugins.security) { - const user = await server.plugins.security.getUser(request); - username = get(user, 'username'); - } - - const callWithRequest = callWithRequestFactory(server, request); - const pipelineId = request.params.id; - - const pipeline = Pipeline.fromDownstreamJSON(request.payload, pipelineId, username); - return savePipeline(callWithRequest, pipeline.id, pipeline.upstreamJSON) - .then(() => h.response().code(204)) - .catch(e => wrapEsError(e)); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/index.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/index.js deleted file mode 100755 index db275b5a3ea79..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/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 { registerLogstashPipelinesRoutes } from './register_pipelines_routes'; diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_delete_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_delete_route.js deleted file mode 100755 index 8ccd792d5a876..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_delete_route.js +++ /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 { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { wrapUnknownError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function deletePipelines(callWithRequest, pipelineIds) { - const deletePromises = pipelineIds.map(pipelineId => { - return callWithRequest('delete', { - index: INDEX_NAMES.PIPELINES, - id: pipelineId, - refresh: 'wait_for', - }) - .then(success => ({ success })) - .catch(error => ({ error })); - }); - - return Promise.all(deletePromises).then(results => { - const successes = results.filter(result => Boolean(result.success)); - const errors = results.filter(result => Boolean(result.error)); - - return { - numSuccesses: successes.length, - numErrors: errors.length, - }; - }); -} - -export function registerDeleteRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/pipelines/delete', - method: 'POST', - handler: request => { - const callWithRequest = callWithRequestFactory(server, request); - - return deletePipelines(callWithRequest, request.payload.pipelineIds) - .then(results => ({ results })) - .catch(err => wrapUnknownError(err)); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_list_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_list_route.js deleted file mode 100755 index 43ce1c3e8f6f6..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_list_route.js +++ /dev/null @@ -1,52 +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 { wrapEsError } from '../../../lib/error_wrappers'; -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { fetchAllFromScroll } from '../../../lib/fetch_all_from_scroll'; -import { INDEX_NAMES, ES_SCROLL_SETTINGS } from '../../../../common/constants'; -import { PipelineListItem } from '../../../models/pipeline_list_item'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function fetchPipelines(callWithRequest) { - const params = { - index: INDEX_NAMES.PIPELINES, - scroll: ES_SCROLL_SETTINGS.KEEPALIVE, - body: { - size: ES_SCROLL_SETTINGS.PAGE_SIZE, - }, - ignore: [404], - }; - - return callWithRequest('search', params).then(response => - fetchAllFromScroll(response, callWithRequest) - ); -} - -export function registerListRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/pipelines', - method: 'GET', - handler: request => { - const callWithRequest = callWithRequestFactory(server, request); - - return fetchPipelines(callWithRequest) - .then((pipelinesHits = []) => { - const pipelines = pipelinesHits.map(pipeline => { - return PipelineListItem.fromUpstreamJSON(pipeline).downstreamJSON; - }); - - return { pipelines }; - }) - .catch(e => wrapEsError(e)); - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_pipelines_routes.js b/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_pipelines_routes.js deleted file mode 100755 index 6d25f3acb9bf9..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipelines/register_pipelines_routes.js +++ /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 { registerListRoute } from './register_list_route'; -import { registerDeleteRoute } from './register_delete_route'; - -export function registerLogstashPipelinesRoutes(server) { - registerListRoute(server); - registerDeleteRoute(server); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/index.js b/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/index.js deleted file mode 100755 index d616349dd6566..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/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 { registerLogstashUpgradeRoutes } from './register_upgrade_routes'; diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_execute_route.js b/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_execute_route.js deleted file mode 100755 index 16f97930ae25e..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_execute_route.js +++ /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. - */ - -import { callWithRequestFactory } from '../../../lib/call_with_request_factory'; -import { wrapUnknownError } from '../../../lib/error_wrappers'; -import { INDEX_NAMES } from '../../../../common/constants'; -import { licensePreRoutingFactory } from '../../../lib/license_pre_routing_factory'; - -function doesIndexExist(callWithRequest) { - return callWithRequest('indices.exists', { - index: INDEX_NAMES.PIPELINES, - }); -} - -async function executeUpgrade(callWithRequest) { - // If index doesn't exist yet, there is no mapping to upgrade - if (!(await doesIndexExist(callWithRequest))) { - return; - } - - return callWithRequest('indices.putMapping', { - index: INDEX_NAMES.PIPELINES, - body: { - properties: { - pipeline_settings: { - dynamic: false, - type: 'object', - }, - }, - }, - }); -} - -export function registerExecuteRoute(server) { - const licensePreRouting = licensePreRoutingFactory(server); - - server.route({ - path: '/api/logstash/upgrade', - method: 'POST', - handler: async request => { - const callWithRequest = callWithRequestFactory(server, request); - try { - await executeUpgrade(callWithRequest); - return { is_upgraded: true }; - } catch (err) { - throw wrapUnknownError(err); - } - }, - config: { - pre: [licensePreRouting], - }, - }); -} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_upgrade_routes.js b/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_upgrade_routes.js deleted file mode 100755 index a198f82613e37..0000000000000 --- a/x-pack/legacy/plugins/logstash/server/routes/api/upgrade/register_upgrade_routes.js +++ /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 { registerExecuteRoute } from './register_execute_route'; - -export function registerLogstashUpgradeRoutes(server) { - registerExecuteRoute(server); -} diff --git a/x-pack/plugins/licensing/common/licensing.mock.ts b/x-pack/plugins/licensing/common/licensing.mock.ts index bf8b85e3e981b..4a6b27255587a 100644 --- a/x-pack/plugins/licensing/common/licensing.mock.ts +++ b/x-pack/plugins/licensing/common/licensing.mock.ts @@ -53,6 +53,7 @@ const createLicenseMock = () => { }; mock.check.mockReturnValue({ state: 'valid' }); mock.hasAtLeast.mockReturnValue(true); + mock.getFeature.mockReturnValue({ isAvailable: true, isEnabled: true }); return mock; }; export const licenseMock = { diff --git a/x-pack/plugins/licensing/server/index.ts b/x-pack/plugins/licensing/server/index.ts index 0e14ead7c6c57..76e65afc595c4 100644 --- a/x-pack/plugins/licensing/server/index.ts +++ b/x-pack/plugins/licensing/server/index.ts @@ -12,3 +12,4 @@ export const plugin = (context: PluginInitializerContext) => new LicensingPlugin export * from '../common/types'; export * from './types'; export { config } from './licensing_config'; +export { CheckLicense, wrapRouteWithLicenseCheck } from './wrap_route_with_license_check'; diff --git a/x-pack/plugins/licensing/server/wrap_route_with_license_check.test.ts b/x-pack/plugins/licensing/server/wrap_route_with_license_check.test.ts new file mode 100644 index 0000000000000..7abdd3f6190ce --- /dev/null +++ b/x-pack/plugins/licensing/server/wrap_route_with_license_check.test.ts @@ -0,0 +1,71 @@ +/* + * 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 { httpServerMock } from 'src/core/server/mocks'; + +import { wrapRouteWithLicenseCheck, CheckLicense } from './wrap_route_with_license_check'; + +const context = { + licensing: { + license: {}, + }, +} as any; +const request = httpServerMock.createKibanaRequest(); + +describe('wrapRouteWithLicenseCheck', () => { + it('calls route handler if checkLicense returns "valid": true', async () => { + const checkLicense: CheckLicense = () => ({ valid: true, message: null }); + const routeHandler = jest.fn(); + const wrapper = wrapRouteWithLicenseCheck(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await wrapper(context, request, response); + + expect(routeHandler).toHaveBeenCalledTimes(1); + expect(routeHandler).toHaveBeenCalledWith(context, request, response); + }); + + it('does not call route handler if checkLicense returns "valid": false', async () => { + const checkLicense: CheckLicense = () => ({ valid: false, message: 'reason' }); + const routeHandler = jest.fn(); + const wrapper = wrapRouteWithLicenseCheck(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await wrapper(context, request, response); + + expect(routeHandler).toHaveBeenCalledTimes(0); + expect(response.forbidden).toHaveBeenCalledTimes(1); + expect(response.forbidden).toHaveBeenCalledWith({ body: 'reason' }); + }); + + it('allows an exception to bubble up if handler throws', async () => { + const checkLicense: CheckLicense = () => ({ valid: true, message: null }); + const routeHandler = () => { + throw new Error('reason'); + }; + const wrapper = wrapRouteWithLicenseCheck(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await expect(wrapper(context, request, response)).rejects.toThrowErrorMatchingInlineSnapshot( + `"reason"` + ); + }); + + it('allows an exception to bubble up if "checkLicense" throws', async () => { + const checkLicense: CheckLicense = () => { + throw new Error('reason'); + }; + const routeHandler = jest.fn(); + const wrapper = wrapRouteWithLicenseCheck(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await expect(wrapper(context, request, response)).rejects.toThrowErrorMatchingInlineSnapshot( + `"reason"` + ); + + expect(routeHandler).toHaveBeenCalledTimes(0); + }); +}); diff --git a/x-pack/plugins/licensing/server/wrap_route_with_license_check.ts b/x-pack/plugins/licensing/server/wrap_route_with_license_check.ts new file mode 100644 index 0000000000000..e0cac8d9db208 --- /dev/null +++ b/x-pack/plugins/licensing/server/wrap_route_with_license_check.ts @@ -0,0 +1,40 @@ +/* + * 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, + RequestHandlerContext, + KibanaRequest, + RouteMethod, + KibanaResponseFactory, +} from 'src/core/server'; + +import { ILicense } from '../common/types'; + +export type CheckLicense = ( + license: ILicense +) => { valid: false; message: string } | { valid: true; message: null }; + +export function wrapRouteWithLicenseCheck( + checkLicense: CheckLicense, + handler: RequestHandler +): RequestHandler { + return async ( + context: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) => { + const licenseCheckResult = checkLicense(context.licensing.license); + + if (licenseCheckResult.valid) { + return handler(context, request, response); + } else { + return response.forbidden({ + body: licenseCheckResult.message, + }); + } + }; +} diff --git a/x-pack/legacy/plugins/logstash/common/constants/es_scroll_settings.js b/x-pack/plugins/logstash/common/constants/es_scroll_settings.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/es_scroll_settings.js rename to x-pack/plugins/logstash/common/constants/es_scroll_settings.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/index.js b/x-pack/plugins/logstash/common/constants/index.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/index.js rename to x-pack/plugins/logstash/common/constants/index.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/index_names.js b/x-pack/plugins/logstash/common/constants/index_names.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/index_names.js rename to x-pack/plugins/logstash/common/constants/index_names.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/monitoring.js b/x-pack/plugins/logstash/common/constants/monitoring.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/monitoring.js rename to x-pack/plugins/logstash/common/constants/monitoring.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/pagination.js b/x-pack/plugins/logstash/common/constants/pagination.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/pagination.js rename to x-pack/plugins/logstash/common/constants/pagination.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/pipeline.js b/x-pack/plugins/logstash/common/constants/pipeline.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/pipeline.js rename to x-pack/plugins/logstash/common/constants/pipeline.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/plugin.js b/x-pack/plugins/logstash/common/constants/plugin.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/plugin.js rename to x-pack/plugins/logstash/common/constants/plugin.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/routes.js b/x-pack/plugins/logstash/common/constants/routes.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/routes.js rename to x-pack/plugins/logstash/common/constants/routes.ts diff --git a/x-pack/legacy/plugins/logstash/common/constants/tooltips.js b/x-pack/plugins/logstash/common/constants/tooltips.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/common/constants/tooltips.js rename to x-pack/plugins/logstash/common/constants/tooltips.ts diff --git a/x-pack/plugins/logstash/kibana.json b/x-pack/plugins/logstash/kibana.json new file mode 100644 index 0000000000000..bcc926535d3c2 --- /dev/null +++ b/x-pack/plugins/logstash/kibana.json @@ -0,0 +1,12 @@ +{ + "id": "logstash", + "version": "0.0.1", + "kibanaVersion": "kibana", + "configPath": ["xpack", "logstash"], + "requiredPlugins": [ + "licensing" + ], + "optionalPlugins": ["security"], + "server": true, + "ui": false +} diff --git a/x-pack/plugins/logstash/server/index.ts b/x-pack/plugins/logstash/server/index.ts new file mode 100644 index 0000000000000..cc65184a1f3a0 --- /dev/null +++ b/x-pack/plugins/logstash/server/index.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 { schema } from '@kbn/config-schema'; +import { PluginInitializerContext, PluginConfigDescriptor } from 'src/core/server'; +import { LogstashPlugin } from './plugin'; + +export const plugin = (context: PluginInitializerContext) => new LogstashPlugin(context); + +export const config: PluginConfigDescriptor = { + schema: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), +}; diff --git a/x-pack/plugins/logstash/server/lib/check_license/check_license.test.ts b/x-pack/plugins/logstash/server/lib/check_license/check_license.test.ts new file mode 100755 index 0000000000000..324e0a22ff378 --- /dev/null +++ b/x-pack/plugins/logstash/server/lib/check_license/check_license.test.ts @@ -0,0 +1,60 @@ +/* + * 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 { licensingMock } from '../../../../licensing/server/mocks'; +import { checkLicense } from './check_license'; + +describe('check_license', function() { + describe('returns "valid": false & message when', () => { + it('license information is not available', () => { + const license = licensingMock.createLicenseMock(); + license.isAvailable = false; + + const { valid, message } = checkLicense(license); + + expect(valid).toBe(false); + expect(message).toStrictEqual(expect.any(String)); + }); + + it('license level is not enough', () => { + const license = licensingMock.createLicenseMock(); + license.hasAtLeast.mockReturnValue(false); + + const { valid, message } = checkLicense(license); + + expect(valid).toBe(false); + expect(message).toStrictEqual(expect.any(String)); + }); + + it('license is expired', () => { + const license = licensingMock.createLicenseMock(); + license.isActive = false; + + const { valid, message } = checkLicense(license); + + expect(valid).toBe(false); + expect(message).toStrictEqual(expect.any(String)); + }); + + it('elasticsearch security is disabled', () => { + const license = licensingMock.createLicenseMock(); + license.getFeature.mockReturnValue({ isEnabled: false, isAvailable: false }); + + const { valid, message } = checkLicense(license); + + expect(valid).toBe(false); + expect(message).toStrictEqual(expect.any(String)); + }); + }); + + it('returns "valid": true without message otherwise', () => { + const license = licensingMock.createLicenseMock(); + + const { valid, message } = checkLicense(license); + + expect(valid).toBe(true); + expect(message).toBe(null); + }); +}); diff --git a/x-pack/plugins/logstash/server/lib/check_license/check_license.ts b/x-pack/plugins/logstash/server/lib/check_license/check_license.ts new file mode 100644 index 0000000000000..4eef2eb9b0681 --- /dev/null +++ b/x-pack/plugins/logstash/server/lib/check_license/check_license.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +import { CheckLicense } from '../../../../licensing/server'; + +export const checkLicense: CheckLicense = license => { + if (!license.isAvailable) { + return { + valid: false, + message: i18n.translate( + 'xpack.logstash.managementSection.notPossibleToManagePipelinesMessage', + { + defaultMessage: + 'You cannot manage Logstash pipelines because license information is not available at this time.', + } + ), + }; + } + + if (!license.hasAtLeast('standard')) { + return { + valid: false, + message: i18n.translate('xpack.logstash.managementSection.licenseDoesNotSupportDescription', { + defaultMessage: + 'Your {licenseType} license does not support Logstash pipeline management features. Please upgrade your license.', + values: { licenseType: license.type }, + }), + }; + } + + if (!license.isActive) { + return { + valid: false, + message: i18n.translate( + 'xpack.logstash.managementSection.pipelineCrudOperationsNotAllowedDescription', + { + defaultMessage: + 'You cannot edit, create, or delete your Logstash pipelines because your {licenseType} license has expired.', + values: { licenseType: license.type }, + } + ), + }; + } + + if (!license.getFeature('security').isEnabled) { + return { + valid: false, + message: i18n.translate('xpack.logstash.managementSection.enableSecurityDescription', { + defaultMessage: + 'Security must be enabled in order to use Logstash pipeline management features.' + + ' Please set xpack.security.enabled: true in your elasticsearch.yml.', + }), + }; + } + + return { + valid: true, + message: null, + }; +}; diff --git a/x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/index.js b/x-pack/plugins/logstash/server/lib/check_license/index.ts old mode 100755 new mode 100644 similarity index 77% rename from x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/index.js rename to x-pack/plugins/logstash/server/lib/check_license/index.ts index 787814d87dff9..f2c070fd44b6e --- a/x-pack/legacy/plugins/logstash/server/lib/call_with_request_factory/index.js +++ b/x-pack/plugins/logstash/server/lib/check_license/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { callWithRequestFactory } from './call_with_request_factory'; +export { checkLicense } from './check_license'; diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts new file mode 100755 index 0000000000000..8cd6b70d47570 --- /dev/null +++ b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.test.ts @@ -0,0 +1,71 @@ +/* + * 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 { fetchAllFromScroll } from './fetch_all_from_scroll'; + +describe('fetch_all_from_scroll', () => { + let stubCallWithRequest: jest.Mock; + + beforeEach(() => { + stubCallWithRequest = jest.fn(); + stubCallWithRequest + .mockResolvedValueOnce({ + hits: { + hits: ['newhit'], + }, + _scroll_id: 'newScrollId', + }) + .mockResolvedValueOnce({ + hits: { + hits: [], + }, + }); + }); + + describe('#fetchAllFromScroll', () => { + describe('when the passed-in response has no hits', () => { + const mockResponse = { + hits: { + hits: [], + }, + }; + + it('should return an empty array of hits', async () => { + const hits = await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); + expect(hits).toEqual([]); + }); + + it('should not call callWithRequest', async () => { + await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); + expect(stubCallWithRequest).toHaveBeenCalledTimes(0); + }); + }); + + describe('when the passed-in response has some hits', () => { + const mockResponse = { + hits: { + hits: ['foo', 'bar'], + }, + _scroll_id: 'originalScrollId', + }; + + it('should return the hits from the response', async () => { + const hits = await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); + expect(hits).toEqual(['foo', 'bar', 'newhit']); + }); + + it('should call callWithRequest', async () => { + await fetchAllFromScroll(mockResponse as any, stubCallWithRequest); + expect(stubCallWithRequest).toHaveBeenCalledTimes(2); + + const firstCallWithRequestCallArgs = stubCallWithRequest.mock.calls[0]; + expect(firstCallWithRequestCallArgs[1].body.scroll_id).toBe('originalScrollId'); + + const secondCallWithRequestCallArgs = stubCallWithRequest.mock.calls[1]; + expect(secondCallWithRequestCallArgs[1].body.scroll_id).toBe('newScrollId'); + }); + }); + }); +}); diff --git a/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts new file mode 100755 index 0000000000000..060cf188a4c60 --- /dev/null +++ b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/fetch_all_from_scroll.ts @@ -0,0 +1,34 @@ +/* + * 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 { SearchResponse } from 'elasticsearch'; + +import { ES_SCROLL_SETTINGS } from '../../../common/constants'; +import { Hits } from '../../types'; + +export async function fetchAllFromScroll( + response: SearchResponse, + callWithRequest: APICaller, + hits: Hits = [] +): Promise { + const newHits = response.hits?.hits || []; + const scrollId = response._scroll_id; + + if (newHits.length > 0) { + hits.push(...newHits); + + const innerResponse = await callWithRequest('scroll', { + body: { + scroll: ES_SCROLL_SETTINGS.KEEPALIVE, + scroll_id: scrollId, + }, + }); + + return await fetchAllFromScroll(innerResponse, callWithRequest, hits); + } + + return hits; +} diff --git a/x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/index.js b/x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/index.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/server/lib/fetch_all_from_scroll/index.js rename to x-pack/plugins/logstash/server/lib/fetch_all_from_scroll/index.ts diff --git a/x-pack/legacy/plugins/logstash/server/models/cluster/__tests__/cluster.js b/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts similarity index 81% rename from x-pack/legacy/plugins/logstash/server/models/cluster/__tests__/cluster.js rename to x-pack/plugins/logstash/server/models/cluster/cluster.test.ts index 08a447a160a1a..63f9f1e58f6ec 100755 --- a/x-pack/legacy/plugins/logstash/server/models/cluster/__tests__/cluster.js +++ b/x-pack/plugins/logstash/server/models/cluster/cluster.test.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; -import { Cluster } from '../cluster'; +import { Cluster } from './cluster'; describe('cluster', () => { describe('Cluster', () => { @@ -16,7 +15,7 @@ describe('cluster', () => { it('returns correct Cluster instance', () => { const cluster = Cluster.fromUpstreamJSON(upstreamJSON); - expect(cluster.uuid).to.be(upstreamJSON.cluster_uuid); + expect(cluster.uuid).toEqual(upstreamJSON.cluster_uuid); }); }); }); diff --git a/x-pack/legacy/plugins/logstash/server/models/cluster/cluster.js b/x-pack/plugins/logstash/server/models/cluster/cluster.ts similarity index 68% rename from x-pack/legacy/plugins/logstash/server/models/cluster/cluster.js rename to x-pack/plugins/logstash/server/models/cluster/cluster.ts index b114162fb0986..54f03605e14d6 100755 --- a/x-pack/legacy/plugins/logstash/server/models/cluster/cluster.js +++ b/x-pack/plugins/logstash/server/models/cluster/cluster.ts @@ -10,11 +10,12 @@ import { get } from 'lodash'; * This model deals with a cluster object from ES and converts it to Kibana downstream */ export class Cluster { - constructor(props) { - this.uuid = props.uuid; + public readonly uuid: string; + constructor({ uuid }: { uuid: string }) { + this.uuid = uuid; } - get downstreamJSON() { + public get downstreamJSON() { const json = { uuid: this.uuid, }; @@ -23,8 +24,8 @@ export class Cluster { } // generate Pipeline object from elasticsearch response - static fromUpstreamJSON(upstreamCluster) { - const uuid = get(upstreamCluster, 'cluster_uuid'); + static fromUpstreamJSON(upstreamCluster: Record) { + const uuid = get(upstreamCluster, 'cluster_uuid'); return new Cluster({ uuid }); } } diff --git a/x-pack/legacy/plugins/logstash/server/models/cluster/index.js b/x-pack/plugins/logstash/server/models/cluster/index.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/server/models/cluster/index.js rename to x-pack/plugins/logstash/server/models/cluster/index.ts diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline/index.js b/x-pack/plugins/logstash/server/models/pipeline/index.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/server/models/pipeline/index.js rename to x-pack/plugins/logstash/server/models/pipeline/index.ts diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline/__tests__/pipeline.js b/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts similarity index 74% rename from x-pack/legacy/plugins/logstash/server/models/pipeline/__tests__/pipeline.js rename to x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts index 41869c22271f0..82ce0d72e2052 100755 --- a/x-pack/legacy/plugins/logstash/server/models/pipeline/__tests__/pipeline.js +++ b/x-pack/plugins/logstash/server/models/pipeline/pipeline.test.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; -import { Pipeline } from '../pipeline'; +import { Pipeline } from './pipeline'; describe('pipeline', () => { describe('Pipeline', () => { @@ -25,10 +24,10 @@ describe('pipeline', () => { it('returns correct Pipeline instance', () => { const pipeline = Pipeline.fromUpstreamJSON(upstreamJSON); - expect(pipeline.id).to.be(upstreamJSON._id); - expect(pipeline.description).to.be(upstreamJSON._source.description); - expect(pipeline.username).to.be(upstreamJSON._source.username); - expect(pipeline.pipeline).to.be(upstreamJSON._source.pipeline); + expect(pipeline.id).toBe(upstreamJSON._id); + expect(pipeline.description).toBe(upstreamJSON._source.description); + expect(pipeline.username).toBe(upstreamJSON._source.username); + expect(pipeline.pipeline).toBe(upstreamJSON._source.pipeline); }); it('throws if pipeline argument does not contain an id property', () => { @@ -39,7 +38,7 @@ describe('pipeline', () => { const testFromUpstreamJsonError = () => { return Pipeline.fromUpstreamJSON(badJSON); }; - expect(testFromUpstreamJsonError).to.throwError( + expect(testFromUpstreamJsonError).toThrowError( /upstreamPipeline argument must contain an id property/i ); }); @@ -64,12 +63,12 @@ describe('pipeline', () => { pipeline: 'input {} filter { grok {} }\n output {}', }; // can't do an object level comparison because modified field is always `now` - expect(pipeline.upstreamJSON.last_modified).to.be.a('string'); - expect(pipeline.upstreamJSON.description).to.be(expectedUpstreamJSON.description); - expect(pipeline.upstreamJSON.pipeline_metadata).to.eql( + expect(pipeline.upstreamJSON.last_modified).toStrictEqual(expect.any(String)); + expect(pipeline.upstreamJSON.description).toBe(expectedUpstreamJSON.description); + expect(pipeline.upstreamJSON.pipeline_metadata).toEqual( expectedUpstreamJSON.pipeline_metadata ); - expect(pipeline.upstreamJSON.pipeline).to.be(expectedUpstreamJSON.pipeline); + expect(pipeline.upstreamJSON.pipeline).toBe(expectedUpstreamJSON.pipeline); }); }); }); diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline/pipeline.js b/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts similarity index 59% rename from x-pack/legacy/plugins/logstash/server/models/pipeline/pipeline.js rename to x-pack/plugins/logstash/server/models/pipeline/pipeline.ts index f02d303cb0380..3f2debeebeb46 100755 --- a/x-pack/legacy/plugins/logstash/server/models/pipeline/pipeline.js +++ b/x-pack/plugins/logstash/server/models/pipeline/pipeline.ts @@ -9,19 +9,38 @@ import { badRequest } from 'boom'; import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; +interface PipelineOptions { + id: string; + description: string; + pipeline: string; + username?: string; + settings?: Record; +} + +interface DownstreamPipeline { + description: string; + pipeline: string; + settings?: Record; +} /** * This model deals with a pipeline object from ES and converts it to Kibana downstream */ export class Pipeline { - constructor(props) { - this.id = props.id; - this.description = props.description; - this.username = props.username; - this.pipeline = props.pipeline; - this.settings = props.settings || {}; + public readonly id: string; + public readonly description: string; + public readonly username?: string; + public readonly pipeline: string; + private readonly settings: Record; + + constructor(options: PipelineOptions) { + this.id = options.id; + this.description = options.description; + this.username = options.username; + this.pipeline = options.pipeline; + this.settings = options.settings || {}; } - get downstreamJSON() { + public get downstreamJSON() { const json = { id: this.id, description: this.description, @@ -41,7 +60,7 @@ export class Pipeline { * pipeline_metadata.type is the Logstash config type (future: LIR, json, etc) * @return {[JSON]} [Elasticsearch JSON] */ - get upstreamJSON() { + public get upstreamJSON() { return { description: this.description, last_modified: moment().toISOString(), @@ -56,7 +75,11 @@ export class Pipeline { } // generate Pipeline object from kibana response - static fromDownstreamJSON(downstreamPipeline, pipelineId, username) { + static fromDownstreamJSON( + downstreamPipeline: DownstreamPipeline, + pipelineId: string, + username?: string + ) { const opts = { id: pipelineId, description: downstreamPipeline.description, @@ -69,7 +92,7 @@ export class Pipeline { } // generate Pipeline object from elasticsearch response - static fromUpstreamJSON(upstreamPipeline) { + static fromUpstreamJSON(upstreamPipeline: Record) { if (!upstreamPipeline._id) { throw badRequest( i18n.translate( @@ -80,13 +103,13 @@ export class Pipeline { ) ); } - const id = get(upstreamPipeline, '_id'); - const description = get(upstreamPipeline, '_source.description'); - const username = get(upstreamPipeline, '_source.username'); - const pipeline = get(upstreamPipeline, '_source.pipeline'); - const settings = get(upstreamPipeline, '_source.pipeline_settings'); + const id = get(upstreamPipeline, '_id'); + const description = get(upstreamPipeline, '_source.description'); + const username = get(upstreamPipeline, '_source.username'); + const pipeline = get(upstreamPipeline, '_source.pipeline'); + const settings = get>(upstreamPipeline, '_source.pipeline_settings'); - const opts = { id, description, username, pipeline, settings }; + const opts: PipelineOptions = { id, description, username, pipeline, settings }; return new Pipeline(opts); } diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/index.js b/x-pack/plugins/logstash/server/models/pipeline_list_item/index.ts similarity index 100% rename from x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/index.js rename to x-pack/plugins/logstash/server/models/pipeline_list_item/index.ts diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/__tests__/pipeline_list_item.js b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts similarity index 72% rename from x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/__tests__/pipeline_list_item.js rename to x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts index 4f3a447f030c7..c557e84443b02 100755 --- a/x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/__tests__/pipeline_list_item.js +++ b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.test.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import expect from '@kbn/expect'; -import { PipelineListItem } from '../pipeline_list_item'; +import { PipelineListItem } from './pipeline_list_item'; describe('pipeline_list_item', () => { describe('PipelineListItem', () => { @@ -21,15 +20,18 @@ describe('pipeline_list_item', () => { username: 'elastic', pipeline: 'input {} filter { grok {} }\n output {}', }, + _index: 'index', + _type: 'type', + _score: 100, }; describe('fromUpstreamJSON factory method', () => { it('returns correct PipelineListItem instance', () => { const pipelineListItem = PipelineListItem.fromUpstreamJSON(upstreamJSON); - expect(pipelineListItem.id).to.be(upstreamJSON._id); - expect(pipelineListItem.description).to.be(upstreamJSON._source.description); - expect(pipelineListItem.username).to.be(upstreamJSON._source.username); - expect(pipelineListItem.last_modified).to.be(upstreamJSON._source.last_modified); + expect(pipelineListItem.id).toBe(upstreamJSON._id); + expect(pipelineListItem.description).toBe(upstreamJSON._source.description); + expect(pipelineListItem.username).toBe(upstreamJSON._source.username); + expect(pipelineListItem.last_modified).toBe(upstreamJSON._source.last_modified); }); }); @@ -42,7 +44,7 @@ describe('pipeline_list_item', () => { username: 'elastic', last_modified: '2017-05-14T02:50:51.250Z', }; - expect(pipelineListItem.downstreamJSON).to.eql(expectedDownstreamJSON); + expect(pipelineListItem.downstreamJSON).toEqual(expectedDownstreamJSON); }); }); }); diff --git a/x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.js b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts similarity index 50% rename from x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.js rename to x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts index bbb506766897e..98c91fca1fcca 100755 --- a/x-pack/legacy/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.js +++ b/x-pack/plugins/logstash/server/models/pipeline_list_item/pipeline_list_item.ts @@ -5,16 +5,21 @@ */ import { get } from 'lodash'; +import { Hit, PipelineListItemOptions } from '../../types'; export class PipelineListItem { - constructor(props) { - this.id = props.id; - this.description = props.description; - this.last_modified = props.last_modified; - this.username = props.username; + public readonly id: string; + public readonly description: string; + public readonly last_modified: string; + public readonly username: string; + constructor(options: PipelineListItemOptions) { + this.id = options.id; + this.description = options.description; + this.last_modified = options.last_modified; + this.username = options.username; } - get downstreamJSON() { + public get downstreamJSON() { const json = { id: this.id, description: this.description, @@ -29,12 +34,12 @@ export class PipelineListItem { * Takes the json GET response from ES and constructs a pipeline model to be used * in Kibana downstream */ - static fromUpstreamJSON(pipeline) { + static fromUpstreamJSON(pipeline: Hit) { const opts = { id: pipeline._id, - description: get(pipeline, '_source.description'), - last_modified: get(pipeline, '_source.last_modified'), - username: get(pipeline, '_source.username'), + description: get(pipeline, '_source.description'), + last_modified: get(pipeline, '_source.last_modified'), + username: get(pipeline, '_source.username'), }; return new PipelineListItem(opts); diff --git a/x-pack/plugins/logstash/server/plugin.ts b/x-pack/plugins/logstash/server/plugin.ts new file mode 100644 index 0000000000000..c048dd13bfb0c --- /dev/null +++ b/x-pack/plugins/logstash/server/plugin.ts @@ -0,0 +1,51 @@ +/* + * 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 { + CoreSetup, + CoreStart, + ICustomClusterClient, + Logger, + Plugin, + PluginInitializerContext, +} from 'src/core/server'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { SecurityPluginSetup } from '../../security/server'; + +import { registerRoutes } from './routes'; + +interface SetupDeps { + licensing: LicensingPluginSetup; + security?: SecurityPluginSetup; +} + +export class LogstashPlugin implements Plugin { + private readonly logger: Logger; + private esClient?: ICustomClusterClient; + private coreSetup?: CoreSetup; + constructor(context: PluginInitializerContext) { + this.logger = context.logger.get(); + } + + setup(core: CoreSetup, deps: SetupDeps) { + this.logger.debug('Setting up Logstash plugin'); + + this.coreSetup = core; + registerRoutes(core.http.createRouter(), deps.security); + } + + start(core: CoreStart) { + const esClient = core.elasticsearch.legacy.createClient('logstash'); + + this.coreSetup!.http.registerRouteHandlerContext('logstash', async (context, request) => { + return { esClient: esClient.asScoped(request) }; + }); + } + stop() { + if (this.esClient) { + this.esClient.close(); + } + } +} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/index.js b/x-pack/plugins/logstash/server/routes/cluster/index.ts old mode 100755 new mode 100644 similarity index 76% rename from x-pack/legacy/plugins/logstash/server/routes/api/cluster/index.js rename to x-pack/plugins/logstash/server/routes/cluster/index.ts index b129d8524b573..c43c409cf5a17 --- a/x-pack/legacy/plugins/logstash/server/routes/api/cluster/index.js +++ b/x-pack/plugins/logstash/server/routes/cluster/index.ts @@ -3,5 +3,4 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -export { registerLogstashClusterRoutes } from './register_cluster_routes'; +export { registerClusterLoadRoute } from './load'; diff --git a/x-pack/plugins/logstash/server/routes/cluster/load.ts b/x-pack/plugins/logstash/server/routes/cluster/load.ts new file mode 100644 index 0000000000000..18fe21f3da675 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/cluster/load.ts @@ -0,0 +1,34 @@ +/* + * 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'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; +import { Cluster } from '../../models/cluster'; +import { checkLicense } from '../../lib/check_license'; + +export function registerClusterLoadRoute(router: IRouter) { + router.get( + { + path: '/api/logstash/cluster', + validate: false, + }, + wrapRouteWithLicenseCheck(checkLicense, async (context, request, response) => { + try { + const client = context.logstash!.esClient; + const info = await client.callAsCurrentUser('info'); + return response.ok({ + body: { + cluster: Cluster.fromUpstreamJSON(info).downstreamJSON, + }, + }); + } catch (err) { + if (err.status === 403) { + return response.ok(); + } + return response.internalError(); + } + }) + ); +} diff --git a/x-pack/plugins/logstash/server/routes/index.ts b/x-pack/plugins/logstash/server/routes/index.ts new file mode 100644 index 0000000000000..0c7183b409055 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/index.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 { IRouter } from 'src/core/server'; +import { SecurityPluginSetup } from '../../../security/server'; +import { registerClusterLoadRoute } from './cluster'; +import { + registerPipelineDeleteRoute, + registerPipelineLoadRoute, + registerPipelineSaveRoute, +} from './pipeline'; +import { registerPipelinesListRoute, registerPipelinesDeleteRoute } from './pipelines'; +import { registerUpgradeRoute } from './upgrade'; + +export function registerRoutes(router: IRouter, security?: SecurityPluginSetup) { + registerClusterLoadRoute(router); + + registerPipelineDeleteRoute(router); + registerPipelineLoadRoute(router); + registerPipelineSaveRoute(router, security); + + registerPipelinesListRoute(router); + registerPipelinesDeleteRoute(router); + + registerUpgradeRoute(router); +} diff --git a/x-pack/plugins/logstash/server/routes/pipeline/delete.ts b/x-pack/plugins/logstash/server/routes/pipeline/delete.ts new file mode 100644 index 0000000000000..4aeae3e0ae2d5 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/pipeline/delete.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 { schema } from '@kbn/config-schema'; +import { IRouter } from 'src/core/server'; +import { INDEX_NAMES } from '../../../common/constants'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; + +import { checkLicense } from '../../lib/check_license'; + +export function registerPipelineDeleteRoute(router: IRouter) { + router.delete( + { + path: '/api/logstash/pipeline/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + const client = context.logstash!.esClient; + + await client.callAsCurrentUser('delete', { + index: INDEX_NAMES.PIPELINES, + id: request.params.id, + refresh: 'wait_for', + }); + + return response.noContent(); + }) + ) + ); +} diff --git a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/index.js b/x-pack/plugins/logstash/server/routes/pipeline/index.ts old mode 100755 new mode 100644 similarity index 60% rename from x-pack/legacy/plugins/logstash/server/lib/error_wrappers/index.js rename to x-pack/plugins/logstash/server/routes/pipeline/index.ts index f275f15637091..e7db6e18ddaf3 --- a/x-pack/legacy/plugins/logstash/server/lib/error_wrappers/index.js +++ b/x-pack/plugins/logstash/server/routes/pipeline/index.ts @@ -3,7 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -export { wrapCustomError } from './wrap_custom_error'; -export { wrapEsError } from './wrap_es_error'; -export { wrapUnknownError } from './wrap_unknown_error'; +export { registerPipelineDeleteRoute } from './delete'; +export { registerPipelineLoadRoute } from './load'; +export { registerPipelineSaveRoute } from './save'; diff --git a/x-pack/plugins/logstash/server/routes/pipeline/load.ts b/x-pack/plugins/logstash/server/routes/pipeline/load.ts new file mode 100644 index 0000000000000..fec9097114d26 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/pipeline/load.ts @@ -0,0 +1,46 @@ +/* + * 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 { IRouter } from 'src/core/server'; + +import { INDEX_NAMES } from '../../../common/constants'; +import { Pipeline } from '../../models/pipeline'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; +import { checkLicense } from '../../lib/check_license'; + +export function registerPipelineLoadRoute(router: IRouter) { + router.get( + { + path: '/api/logstash/pipeline/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + }, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + const client = context.logstash!.esClient; + + const result = await client.callAsCurrentUser('get', { + index: INDEX_NAMES.PIPELINES, + id: request.params.id, + _source: ['description', 'username', 'pipeline', 'pipeline_settings'], + ignore: [404], + }); + + if (!result.found) { + return response.notFound(); + } + + return response.ok({ + body: Pipeline.fromUpstreamJSON(result).downstreamJSON, + }); + }) + ) + ); +} diff --git a/x-pack/plugins/logstash/server/routes/pipeline/save.ts b/x-pack/plugins/logstash/server/routes/pipeline/save.ts new file mode 100644 index 0000000000000..556c281944a85 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/pipeline/save.ts @@ -0,0 +1,69 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { IRouter } from 'src/core/server'; + +import { INDEX_NAMES } from '../../../common/constants'; +import { Pipeline } from '../../models/pipeline'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; +import { SecurityPluginSetup } from '../../../../security/server'; +import { checkLicense } from '../../lib/check_license'; + +export function registerPipelineSaveRoute(router: IRouter, security?: SecurityPluginSetup) { + router.put( + { + path: '/api/logstash/pipeline/{id}', + validate: { + params: schema.object({ + id: schema.string(), + }), + body: schema.object({ + id: schema.string(), + description: schema.string(), + pipeline: schema.string(), + username: schema.string(), + settings: schema.maybe(schema.object({}, { unknowns: 'allow' })), + }), + }, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + try { + let username: string | undefined; + if (security) { + const user = await security.authc.getCurrentUser(request); + username = user?.username; + } + + const client = context.logstash!.esClient; + const pipeline = Pipeline.fromDownstreamJSON(request.body, request.params.id, username); + + await client.callAsCurrentUser('index', { + index: INDEX_NAMES.PIPELINES, + id: pipeline.id, + body: pipeline.upstreamJSON, + refresh: 'wait_for', + }); + + return response.noContent(); + } catch (err) { + const statusCode = err.statusCode; + // handles the permissions issue of Elasticsearch + if (statusCode === 403) { + return response.forbidden({ + body: i18n.translate('xpack.logstash.insufficientUserPermissionsDescription', { + defaultMessage: 'Insufficient user permissions for managing Logstash pipelines', + }), + }); + } + throw err; + } + }) + ) + ); +} diff --git a/x-pack/plugins/logstash/server/routes/pipelines/delete.ts b/x-pack/plugins/logstash/server/routes/pipelines/delete.ts new file mode 100644 index 0000000000000..ac3097ac0424b --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/pipelines/delete.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 { APICaller, IRouter } from 'src/core/server'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; + +import { INDEX_NAMES } from '../../../common/constants'; +import { checkLicense } from '../../lib/check_license'; + +async function deletePipelines(callWithRequest: APICaller, pipelineIds: string[]) { + const deletePromises = pipelineIds.map(pipelineId => { + return callWithRequest('delete', { + index: INDEX_NAMES.PIPELINES, + id: pipelineId, + refresh: 'wait_for', + }) + .then(success => ({ success })) + .catch(error => ({ error })); + }); + + const results = await Promise.all(deletePromises); + const successes = results.filter(result => Reflect.has(result, 'success')); + const errors = results.filter(result => Reflect.has(result, 'error')); + + return { + numSuccesses: successes.length, + numErrors: errors.length, + }; +} + +export function registerPipelinesDeleteRoute(router: IRouter) { + router.post( + { + path: '/api/logstash/pipelines/delete', + validate: { + body: schema.object({ + pipelineIds: schema.arrayOf(schema.string()), + }), + }, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + const client = context.logstash!.esClient; + const results = await deletePipelines(client.callAsCurrentUser, request.body.pipelineIds); + + return response.ok({ body: { results } }); + }) + ) + ); +} diff --git a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/index.js b/x-pack/plugins/logstash/server/routes/pipelines/index.ts old mode 100755 new mode 100644 similarity index 68% rename from x-pack/legacy/plugins/logstash/server/routes/api/pipeline/index.js rename to x-pack/plugins/logstash/server/routes/pipelines/index.ts index 643a405ced919..36681502cfc70 --- a/x-pack/legacy/plugins/logstash/server/routes/api/pipeline/index.js +++ b/x-pack/plugins/logstash/server/routes/pipelines/index.ts @@ -3,5 +3,5 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -export { registerLogstashPipelineRoutes } from './register_pipeline_routes'; +export { registerPipelinesListRoute } from './list'; +export { registerPipelinesDeleteRoute } from './delete'; diff --git a/x-pack/plugins/logstash/server/routes/pipelines/list.ts b/x-pack/plugins/logstash/server/routes/pipelines/list.ts new file mode 100644 index 0000000000000..bc477a25a7988 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/pipelines/list.ts @@ -0,0 +1,63 @@ +/* + * 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 { SearchResponse } from 'elasticsearch'; +import { APICaller, IRouter } from 'src/core/server'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; + +import { INDEX_NAMES, ES_SCROLL_SETTINGS } from '../../../common/constants'; +import { PipelineListItem } from '../../models/pipeline_list_item'; +import { fetchAllFromScroll } from '../../lib/fetch_all_from_scroll'; +import { checkLicense } from '../../lib/check_license'; + +async function fetchPipelines(callWithRequest: APICaller) { + const params = { + index: INDEX_NAMES.PIPELINES, + scroll: ES_SCROLL_SETTINGS.KEEPALIVE, + body: { + size: ES_SCROLL_SETTINGS.PAGE_SIZE, + }, + ignore: [404], + }; + + const response = await callWithRequest>('search', params); + return fetchAllFromScroll(response, callWithRequest); +} + +export function registerPipelinesListRoute(router: IRouter) { + router.get( + { + path: '/api/logstash/pipelines', + validate: false, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + try { + const client = context.logstash!.esClient; + const pipelinesHits = await fetchPipelines(client.callAsCurrentUser); + + const pipelines = pipelinesHits.map(pipeline => { + return PipelineListItem.fromUpstreamJSON(pipeline).downstreamJSON; + }); + + return response.ok({ body: { pipelines } }); + } catch (err) { + const statusCode = err.statusCode; + // handles the permissions issue of Elasticsearch + if (statusCode === 403) { + return response.forbidden({ + body: i18n.translate('xpack.logstash.insufficientUserPermissionsDescription', { + defaultMessage: 'Insufficient user permissions for managing Logstash pipelines', + }), + }); + } + throw err; + } + }) + ) + ); +} diff --git a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/index.js b/x-pack/plugins/logstash/server/routes/upgrade/index.ts old mode 100755 new mode 100644 similarity index 76% rename from x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/index.js rename to x-pack/plugins/logstash/server/routes/upgrade/index.ts index 0743e443955f4..3a5b0868b446b --- a/x-pack/legacy/plugins/logstash/server/lib/license_pre_routing_factory/index.js +++ b/x-pack/plugins/logstash/server/routes/upgrade/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { licensePreRoutingFactory } from './license_pre_routing_factory'; +export { registerUpgradeRoute } from './upgrade'; diff --git a/x-pack/plugins/logstash/server/routes/upgrade/upgrade.ts b/x-pack/plugins/logstash/server/routes/upgrade/upgrade.ts new file mode 100644 index 0000000000000..2bd2c0f89e190 --- /dev/null +++ b/x-pack/plugins/logstash/server/routes/upgrade/upgrade.ts @@ -0,0 +1,46 @@ +/* + * 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'; +import { wrapRouteWithLicenseCheck } from '../../../../licensing/server'; + +import { INDEX_NAMES } from '../../../common/constants'; +import { checkLicense } from '../../lib/check_license'; + +export function registerUpgradeRoute(router: IRouter) { + router.post( + { + path: '/api/logstash/upgrade', + validate: false, + }, + wrapRouteWithLicenseCheck( + checkLicense, + router.handleLegacyErrors(async (context, request, response) => { + const client = context.logstash!.esClient; + + const doesIndexExist = await client.callAsCurrentUser('indices.exists', { + index: INDEX_NAMES.PIPELINES, + }); + + // If index doesn't exist yet, there is no mapping to upgrade + if (doesIndexExist) { + await client.callAsCurrentUser('indices.putMapping', { + index: INDEX_NAMES.PIPELINES, + body: { + properties: { + pipeline_settings: { + dynamic: false, + type: 'object', + }, + }, + }, + }); + } + + return response.ok({ body: { is_upgraded: true } }); + }) + ) + ); +} diff --git a/x-pack/plugins/logstash/server/types.ts b/x-pack/plugins/logstash/server/types.ts new file mode 100644 index 0000000000000..2b266b2f27708 --- /dev/null +++ b/x-pack/plugins/logstash/server/types.ts @@ -0,0 +1,27 @@ +/* + * 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 { SearchResponse } from 'elasticsearch'; +import { IScopedClusterClient } from 'src/core/server'; + +type UnwrapArray = T extends Array ? U : never; + +export type Hits = SearchResponse['hits']['hits']; +export type Hit = UnwrapArray; + +export interface PipelineListItemOptions { + id: string; + description: string; + last_modified: string; + username: string; +} + +declare module 'src/core/server' { + interface RequestHandlerContext { + logstash?: { + esClient: IScopedClusterClient; + }; + } +} diff --git a/x-pack/plugins/security/common/licensing/license_service.test.ts b/x-pack/plugins/security/common/licensing/license_service.test.ts index dfc94042ef930..5bdfa7d4886aa 100644 --- a/x-pack/plugins/security/common/licensing/license_service.test.ts +++ b/x-pack/plugins/security/common/licensing/license_service.test.ts @@ -78,14 +78,14 @@ describe('license features', function() { expect(subscriptionHandler.mock.calls[1]).toMatchInlineSnapshot(` Array [ Object { - "allowLogin": false, - "allowRbac": false, - "allowRoleDocumentLevelSecurity": false, - "allowRoleFieldLevelSecurity": false, - "allowSubFeaturePrivileges": false, - "showLinks": false, - "showLogin": false, - "showRoleMappingsManagement": false, + "allowLogin": true, + "allowRbac": true, + "allowRoleDocumentLevelSecurity": true, + "allowRoleFieldLevelSecurity": true, + "allowSubFeaturePrivileges": true, + "showLinks": true, + "showLogin": true, + "showRoleMappingsManagement": true, }, ] `); diff --git a/x-pack/test/api_integration/apis/logstash/cluster/index.js b/x-pack/test/api_integration/apis/logstash/cluster/index.ts similarity index 71% rename from x-pack/test/api_integration/apis/logstash/cluster/index.js rename to x-pack/test/api_integration/apis/logstash/cluster/index.ts index f016fde97ee4b..1d4fbd40b252b 100644 --- a/x-pack/test/api_integration/apis/logstash/cluster/index.js +++ b/x-pack/test/api_integration/apis/logstash/cluster/index.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ loadTestFile }) { +export default function({ loadTestFile }: FtrProviderContext) { describe('cluster', () => { loadTestFile(require.resolve('./load')); }); diff --git a/x-pack/test/api_integration/apis/logstash/cluster/load.js b/x-pack/test/api_integration/apis/logstash/cluster/load.ts similarity index 83% rename from x-pack/test/api_integration/apis/logstash/cluster/load.js rename to x-pack/test/api_integration/apis/logstash/cluster/load.ts index a348c6e4857b1..0678c5faf82dc 100644 --- a/x-pack/test/api_integration/apis/logstash/cluster/load.js +++ b/x-pack/test/api_integration/apis/logstash/cluster/load.ts @@ -5,8 +5,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ getService }) { +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const es = getService('legacyEs'); diff --git a/x-pack/test/api_integration/apis/logstash/index.js b/x-pack/test/api_integration/apis/logstash/index.ts similarity index 76% rename from x-pack/test/api_integration/apis/logstash/index.js rename to x-pack/test/api_integration/apis/logstash/index.ts index 53293e5ff9423..582bef5a53bf2 100644 --- a/x-pack/test/api_integration/apis/logstash/index.js +++ b/x-pack/test/api_integration/apis/logstash/index.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../ftr_provider_context'; -export default function({ loadTestFile }) { +export default function({ loadTestFile }: FtrProviderContext) { describe('logstash', () => { loadTestFile(require.resolve('./pipelines')); loadTestFile(require.resolve('./pipeline')); diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/delete.js b/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts similarity index 90% rename from x-pack/test/api_integration/apis/logstash/pipeline/delete.js rename to x-pack/test/api_integration/apis/logstash/pipeline/delete.ts index 85813f4ed04d1..cdbf5a3e6a1fe 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/delete.js +++ b/x-pack/test/api_integration/apis/logstash/pipeline/delete.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ getService }) { +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('delete', () => { diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/index.js b/x-pack/test/api_integration/apis/logstash/pipeline/index.ts similarity index 76% rename from x-pack/test/api_integration/apis/logstash/pipeline/index.js rename to x-pack/test/api_integration/apis/logstash/pipeline/index.ts index dcc8a01378e37..2697f7f428f5f 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/index.js +++ b/x-pack/test/api_integration/apis/logstash/pipeline/index.ts @@ -3,8 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -export default function({ loadTestFile }) { +import { FtrProviderContext } from '../../../ftr_provider_context'; +export default function({ loadTestFile }: FtrProviderContext) { describe('pipeline', () => { loadTestFile(require.resolve('./load')); loadTestFile(require.resolve('./save')); diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/load.js b/x-pack/test/api_integration/apis/logstash/pipeline/load.ts similarity index 82% rename from x-pack/test/api_integration/apis/logstash/pipeline/load.js rename to x-pack/test/api_integration/apis/logstash/pipeline/load.ts index eb2ab6500a9dc..a892f527a6e61 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/load.js +++ b/x-pack/test/api_integration/apis/logstash/pipeline/load.ts @@ -5,9 +5,11 @@ */ import expect from '@kbn/expect'; -import pipeline from './fixtures/load'; +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ getService }) { +import pipeline from './fixtures/load.json'; + +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('list', () => { diff --git a/x-pack/test/api_integration/apis/logstash/pipeline/save.js b/x-pack/test/api_integration/apis/logstash/pipeline/save.ts similarity index 90% rename from x-pack/test/api_integration/apis/logstash/pipeline/save.js rename to x-pack/test/api_integration/apis/logstash/pipeline/save.ts index ad35ee21f00fc..2ca9fbe7d68e0 100644 --- a/x-pack/test/api_integration/apis/logstash/pipeline/save.js +++ b/x-pack/test/api_integration/apis/logstash/pipeline/save.ts @@ -5,8 +5,9 @@ */ import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ getService }) { +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('save', () => { diff --git a/x-pack/test/api_integration/apis/logstash/pipelines/delete.js b/x-pack/test/api_integration/apis/logstash/pipelines/delete.ts similarity index 90% rename from x-pack/test/api_integration/apis/logstash/pipelines/delete.js rename to x-pack/test/api_integration/apis/logstash/pipelines/delete.ts index 98ff5b99ea744..e71dc7f08ddc9 100644 --- a/x-pack/test/api_integration/apis/logstash/pipelines/delete.js +++ b/x-pack/test/api_integration/apis/logstash/pipelines/delete.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ getService }) { +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('delete', () => { diff --git a/x-pack/test/api_integration/apis/logstash/pipelines/index.js b/x-pack/test/api_integration/apis/logstash/pipelines/index.ts similarity index 73% rename from x-pack/test/api_integration/apis/logstash/pipelines/index.js rename to x-pack/test/api_integration/apis/logstash/pipelines/index.ts index 3abe2ee5ac43d..510bd625b54a0 100644 --- a/x-pack/test/api_integration/apis/logstash/pipelines/index.js +++ b/x-pack/test/api_integration/apis/logstash/pipelines/index.ts @@ -3,8 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function({ loadTestFile }) { +export default function({ loadTestFile }: FtrProviderContext) { describe('pipelines', () => { loadTestFile(require.resolve('./list')); loadTestFile(require.resolve('./delete')); diff --git a/x-pack/test/api_integration/apis/logstash/pipelines/list.js b/x-pack/test/api_integration/apis/logstash/pipelines/list.ts similarity index 82% rename from x-pack/test/api_integration/apis/logstash/pipelines/list.js rename to x-pack/test/api_integration/apis/logstash/pipelines/list.ts index fe5c3222a2ab1..a4ef52791ab70 100644 --- a/x-pack/test/api_integration/apis/logstash/pipelines/list.js +++ b/x-pack/test/api_integration/apis/logstash/pipelines/list.ts @@ -5,9 +5,10 @@ */ import expect from '@kbn/expect'; -import pipelineList from './fixtures/list'; +import { FtrProviderContext } from '../../../ftr_provider_context'; +import pipelineList from './fixtures/list.json'; -export default function({ getService }) { +export default function({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); describe('list', () => {