diff --git a/x-pack/plugins/ml/common/util/errors.test.ts b/x-pack/plugins/ml/common/util/errors.test.ts deleted file mode 100644 index 00af27248ccce..0000000000000 --- a/x-pack/plugins/ml/common/util/errors.test.ts +++ /dev/null @@ -1,78 +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 { - BoomResponse, - extractErrorMessage, - MLCustomHttpResponseOptions, - MLResponseError, -} from './errors'; -import { ResponseError } from 'kibana/server'; - -describe('ML - error message utils', () => { - describe('extractErrorMessage', () => { - test('returns just the error message', () => { - const testMsg = 'Saved object [index-pattern/blahblahblah] not found'; - - const bodyWithNestedErrorMsg: MLCustomHttpResponseOptions = { - body: { - message: { - msg: testMsg, - }, - }, - statusCode: 404, - }; - expect(extractErrorMessage(bodyWithNestedErrorMsg)).toBe(testMsg); - - const bodyWithStringMsg: MLCustomHttpResponseOptions = { - body: { - msg: testMsg, - }, - statusCode: 404, - }; - expect(extractErrorMessage(bodyWithStringMsg)).toBe(testMsg); - - const bodyWithStringMessage: MLCustomHttpResponseOptions = { - body: { - message: testMsg, - }, - statusCode: 404, - }; - expect(extractErrorMessage(bodyWithStringMessage)).toBe(testMsg); - - const bodyWithString: MLCustomHttpResponseOptions = { - body: testMsg, - statusCode: 404, - }; - expect(extractErrorMessage(bodyWithString)).toBe(testMsg); - - const bodyWithError: MLCustomHttpResponseOptions = { - body: new Error(testMsg), - statusCode: 404, - }; - expect(extractErrorMessage(bodyWithError)).toBe(testMsg); - - const bodyWithBoomError: MLCustomHttpResponseOptions = { - statusCode: 404, - body: { - data: [], - isBoom: true, - isServer: false, - output: { - statusCode: 404, - payload: { - statusCode: 404, - error: testMsg, - message: testMsg, - }, - headers: {}, - }, - }, - }; - expect(extractErrorMessage(bodyWithBoomError)).toBe(testMsg); - }); - }); -}); diff --git a/x-pack/plugins/ml/common/util/errors.ts b/x-pack/plugins/ml/common/util/errors.ts index e165e15d7c64e..4446624bf2e7f 100644 --- a/x-pack/plugins/ml/common/util/errors.ts +++ b/x-pack/plugins/ml/common/util/errors.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ResponseError, ResponseHeaders } from 'kibana/server'; import { isErrorResponse } from '../types/errors'; export function getErrorMessage(error: any) { @@ -18,77 +17,3 @@ export function getErrorMessage(error: any) { return JSON.stringify(error); } - -// Adding temporary types until Kibana ResponseError is updated - -export interface BoomResponse { - data: any; - isBoom: boolean; - isServer: boolean; - output: { - statusCode: number; - payload: { - statusCode: number; - error: string; - message: string; - }; - headers: {}; - }; -} -export type MLResponseError = - | { - message: { - msg: string; - }; - } - | { msg: string }; - -export interface MLCustomHttpResponseOptions< - T extends ResponseError | MLResponseError | BoomResponse -> { - /** HTTP message to send to the client */ - body?: T; - /** HTTP Headers with additional information about response */ - headers?: ResponseHeaders; - statusCode: number; -} - -export const extractErrorMessage = ( - error: - | MLCustomHttpResponseOptions - | undefined - | string -): string => { - // extract only the error message within the response error coming from Kibana, Elasticsearch, and our own ML messages - - if (typeof error === 'string') { - return error; - } - if (error?.body === undefined) return ''; - - if (typeof error.body === 'string') { - return error.body; - } - if ( - typeof error.body === 'object' && - 'output' in error.body && - error.body.output.payload.message - ) { - return error.body.output.payload.message; - } - - if (typeof error.body === 'object' && 'msg' in error.body && typeof error.body.msg === 'string') { - return error.body.msg; - } - - if (typeof error.body === 'object' && 'message' in error.body) { - if (typeof error.body.message === 'string') { - return error.body.message; - } - if (!(error.body.message instanceof Error) && typeof (error.body.message.msg === 'string')) { - return error.body.message.msg; - } - } - // If all else fail return an empty message instead of JSON.stringify - return ''; -}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_delete.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_delete.tsx index 38ef00914e8fb..2d433f6b18484 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_delete.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_delete.tsx @@ -18,7 +18,6 @@ import { } from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/common'; import { FormattedMessage } from '@kbn/i18n/react'; -import { extractErrorMessage } from '../../../../../../../common/util/errors'; import { deleteAnalytics, deleteAnalyticsAndDestIndex, @@ -30,6 +29,7 @@ import { } from '../../../../../capabilities/check_capabilities'; import { useMlKibana } from '../../../../../contexts/kibana'; import { isDataFrameAnalyticsRunning, DataFrameAnalyticsListRow } from './common'; +import { extractErrorMessage } from '../../../../../util/error_utils'; interface DeleteActionProps { item: DataFrameAnalyticsListRow; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts index ebd3fa8982604..26cefff0a3f59 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/services/analytics_service/delete_analytics.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; -import { extractErrorMessage } from '../../../../../../../common/util/errors'; import { getToastNotifications } from '../../../../../util/dependency_cache'; import { ml } from '../../../../../services/ml_api_service'; import { refreshAnalyticsList$, REFRESH_ANALYTICS_LIST_STATE } from '../../../../common'; @@ -12,6 +11,7 @@ import { isDataFrameAnalyticsFailed, DataFrameAnalyticsListRow, } from '../../components/analytics_list/common'; +import { extractErrorMessage } from '../../../../../util/error_utils'; export const deleteAnalytics = async (d: DataFrameAnalyticsListRow) => { const toastNotifications = getToastNotifications(); diff --git a/x-pack/plugins/ml/public/application/util/error_utils.ts b/x-pack/plugins/ml/public/application/util/error_utils.ts new file mode 100644 index 0000000000000..2ce8f4ffc583a --- /dev/null +++ b/x-pack/plugins/ml/public/application/util/error_utils.ts @@ -0,0 +1,32 @@ +/* + * 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 { CustomHttpResponseOptions, ResponseError } from 'kibana/server'; + +export const extractErrorMessage = ( + error: CustomHttpResponseOptions | undefined | string +): string | undefined => { + if (typeof error === 'string') { + return error; + } + + if (error?.body) { + if (typeof error.body === 'string') { + return error.body; + } + if (typeof error.body === 'object' && 'message' in error.body) { + if (typeof error.body.message === 'string') { + return error.body.message; + } + // @ts-ignore + if (typeof (error.body.message?.msg === 'string')) { + // @ts-ignore + return error.body.message?.msg; + } + } + } + return undefined; +}; diff --git a/x-pack/plugins/ml/public/shared.ts b/x-pack/plugins/ml/public/shared.ts index ff83d79adff67..6821cb7ef0f94 100644 --- a/x-pack/plugins/ml/public/shared.ts +++ b/x-pack/plugins/ml/public/shared.ts @@ -14,7 +14,6 @@ export * from '../common/types/audit_message'; export * from '../common/util/anomaly_utils'; export * from '../common/util/errors'; - export * from '../common/util/validators'; export * from './application/formatters/metric_change_description'; diff --git a/x-pack/plugins/transform/common/index.ts b/x-pack/plugins/transform/common/index.ts index 79ff6298a2ca2..d7a791e78b3ab 100644 --- a/x-pack/plugins/transform/common/index.ts +++ b/x-pack/plugins/transform/common/index.ts @@ -38,20 +38,3 @@ export interface ResultData { export interface TransformEndpointResult { [key: string]: ResultData; } - -export interface DeleteTransformEndpointRequest { - transformsInfo: TransformEndpointRequest[]; - deleteDestIndex?: boolean; - deleteDestIndexPattern?: boolean; -} - -export interface DeleteTransformStatus { - transformDeleted: ResultData; - destIndexDeleted?: ResultData; - destIndexPatternDeleted?: ResultData; - destinationIndex?: string | undefined; -} - -export interface DeleteTransformEndpointResult { - [key: string]: DeleteTransformStatus; -} diff --git a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx index 3f664cf8bb09b..1044081670523 100644 --- a/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx +++ b/x-pack/plugins/transform/public/app/components/toast_notification_text.tsx @@ -29,14 +29,9 @@ const MAX_SIMPLE_MESSAGE_LENGTH = 140; interface ToastNotificationTextProps { overlays: CoreStart['overlays']; text: any; - previewTextLength?: number; } -export const ToastNotificationText: FC = ({ - overlays, - text, - previewTextLength, -}) => { +export const ToastNotificationText: FC = ({ overlays, text }) => { if (typeof text === 'string' && text.length <= MAX_SIMPLE_MESSAGE_LENGTH) { return text; } @@ -51,9 +46,8 @@ export const ToastNotificationText: FC = ({ const unformattedText = text.message ? text.message : text; const formattedText = typeof unformattedText === 'object' ? JSON.stringify(text, null, 2) : text; - const textLength = previewTextLength ?? 140; - const previewText = `${formattedText.substring(0, textLength)}${ - formattedText.length > textLength ? ' ...' : '' + const previewText = `${formattedText.substring(0, 140)}${ + formattedText.length > 140 ? ' ...' : '' }`; const openModal = () => { diff --git a/x-pack/plugins/transform/public/app/hooks/index.ts b/x-pack/plugins/transform/public/app/hooks/index.ts index b439afe2b2165..a36550bcd8e57 100644 --- a/x-pack/plugins/transform/public/app/hooks/index.ts +++ b/x-pack/plugins/transform/public/app/hooks/index.ts @@ -6,7 +6,7 @@ export { useApi } from './use_api'; export { useGetTransforms } from './use_get_transforms'; -export { useDeleteTransforms, useDeleteIndexAndTargetIndex } from './use_delete_transform'; +export { useDeleteTransforms } from './use_delete_transform'; export { useStartTransforms } from './use_start_transform'; export { useStopTransforms } from './use_stop_transform'; export { useRequest } from './use_request'; diff --git a/x-pack/plugins/transform/public/app/hooks/use_api.ts b/x-pack/plugins/transform/public/app/hooks/use_api.ts index 5d7839cf5fba7..f3c35d358f1f2 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_api.ts +++ b/x-pack/plugins/transform/public/app/hooks/use_api.ts @@ -5,12 +5,7 @@ */ import { useMemo } from 'react'; -import { - TransformId, - TransformEndpointRequest, - TransformEndpointResult, - DeleteTransformEndpointResult, -} from '../../../common'; +import { TransformEndpointRequest, TransformEndpointResult, TransformId } from '../../../common'; import { API_BASE_PATH } from '../../../common/constants'; import { useAppDependencies } from '../app_dependencies'; @@ -45,12 +40,10 @@ export const useApi = () => { }); }, deleteTransforms( - transformsInfo: TransformEndpointRequest[], - deleteDestIndex: boolean | undefined, - deleteDestIndexPattern: boolean | undefined - ): Promise { + transformsInfo: TransformEndpointRequest[] + ): Promise { return http.post(`${API_BASE_PATH}delete_transforms`, { - body: JSON.stringify({ transformsInfo, deleteDestIndex, deleteDestIndexPattern }), + body: JSON.stringify(transformsInfo), }); }, getTransformsPreview(obj: PreviewRequestBody): Promise { diff --git a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx index 1f395e67b7d31..0215d723188b1 100644 --- a/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx +++ b/x-pack/plugins/transform/public/app/hooks/use_delete_transform.tsx @@ -4,257 +4,52 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React from 'react'; + import { i18n } from '@kbn/i18n'; import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; -import { - TransformEndpointRequest, - DeleteTransformEndpointResult, - DeleteTransformStatus, -} from '../../../common'; -import { getErrorMessage, extractErrorMessage } from '../../shared_imports'; -import { useAppDependencies, useToastNotifications } from '../app_dependencies'; -import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; -import { ToastNotificationText } from '../components'; -import { useApi } from './use_api'; -import { indexService } from '../services/es_index_service'; -export const useDeleteIndexAndTargetIndex = (items: TransformListRow[]) => { - const { http, savedObjects } = useAppDependencies(); - const toastNotifications = useToastNotifications(); - - const [deleteDestIndex, setDeleteDestIndex] = useState(true); - const [deleteIndexPattern, setDeleteIndexPattern] = useState(true); - const [userCanDeleteIndex, setUserCanDeleteIndex] = useState(false); - const [indexPatternExists, setIndexPatternExists] = useState(false); - const toggleDeleteIndex = useCallback(() => setDeleteDestIndex(!deleteDestIndex), [ - deleteDestIndex, - ]); - const toggleDeleteIndexPattern = useCallback(() => setDeleteIndexPattern(!deleteIndexPattern), [ - deleteIndexPattern, - ]); +import { TransformEndpointRequest, TransformEndpointResult } from '../../../common'; - const checkIndexPatternExists = useCallback( - async (indexName: string) => { - try { - if (await indexService.indexPatternExists(savedObjects.client, indexName)) { - setIndexPatternExists(true); - } - } catch (e) { - const error = extractErrorMessage(e); - - toastNotifications.addDanger( - i18n.translate( - 'xpack.transform.deleteTransform.errorWithCheckingIfIndexPatternExistsNotificationErrorMessage', - { - defaultMessage: - 'An error occurred checking if index pattern {indexPattern} exists: {error}', - values: { indexPattern: indexName, error }, - } - ) - ); - } - }, - [savedObjects.client, toastNotifications] - ); - - const checkUserIndexPermission = useCallback(async () => { - try { - const userCanDelete = await indexService.canDeleteIndex(http); - if (userCanDelete) { - setUserCanDeleteIndex(true); - } - } catch (e) { - toastNotifications.addDanger( - i18n.translate( - 'xpack.transform.transformList.errorWithCheckingIfUserCanDeleteIndexNotificationErrorMessage', - { - defaultMessage: 'An error occurred checking if user can delete destination index', - } - ) - ); - } - }, [http, toastNotifications]); - - useEffect(() => { - checkUserIndexPermission(); - - if (items.length === 1) { - const config = items[0].config; - const destinationIndex = Array.isArray(config.dest.index) - ? config.dest.index[0] - : config.dest.index; - checkIndexPatternExists(destinationIndex); - } else { - setIndexPatternExists(true); - } - }, [checkIndexPatternExists, checkUserIndexPermission, items]); +import { getErrorMessage } from '../../shared_imports'; - return { - userCanDeleteIndex, - deleteDestIndex, - indexPatternExists, - deleteIndexPattern, - toggleDeleteIndex, - toggleDeleteIndexPattern, - }; -}; +import { useAppDependencies, useToastNotifications } from '../app_dependencies'; +import { TransformListRow, refreshTransformList$, REFRESH_TRANSFORM_LIST_STATE } from '../common'; +import { ToastNotificationText } from '../components'; -type SuccessCountField = keyof Omit; +import { useApi } from './use_api'; export const useDeleteTransforms = () => { const { overlays } = useAppDependencies(); const toastNotifications = useToastNotifications(); const api = useApi(); - return async ( - transforms: TransformListRow[], - shouldDeleteDestIndex: boolean, - shouldDeleteDestIndexPattern: boolean - ) => { + return async (transforms: TransformListRow[]) => { const transformsInfo: TransformEndpointRequest[] = transforms.map((tf) => ({ id: tf.config.id, state: tf.stats.state, })); try { - const results: DeleteTransformEndpointResult = await api.deleteTransforms( - transformsInfo, - shouldDeleteDestIndex, - shouldDeleteDestIndexPattern - ); - const isBulk = Object.keys(results).length > 1; - const successCount: Record = { - transformDeleted: 0, - destIndexDeleted: 0, - destIndexPatternDeleted: 0, - }; + const results: TransformEndpointResult = await api.deleteTransforms(transformsInfo); for (const transformId in results) { // hasOwnProperty check to ensure only properties on object itself, and not its prototypes if (results.hasOwnProperty(transformId)) { - const status = results[transformId]; - const destinationIndex = status.destinationIndex; - - // if we are only deleting one transform, show the success toast messages - if (!isBulk && status.transformDeleted) { - if (status.transformDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { - defaultMessage: 'Request to delete transform {transformId} acknowledged.', - values: { transformId }, - }) - ); - } - if (status.destIndexDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexSuccessMessage', - { - defaultMessage: - 'Request to delete destination index {destinationIndex} acknowledged.', - values: { destinationIndex }, - } - ) - ); - } - if (status.destIndexPatternDeleted?.success) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexPatternSuccessMessage', - { - defaultMessage: - 'Request to delete index pattern {destinationIndex} acknowledged.', - values: { destinationIndex }, - } - ) - ); - } + if (results[transformId].success === true) { + toastNotifications.addSuccess( + i18n.translate('xpack.transform.transformList.deleteTransformSuccessMessage', { + defaultMessage: 'Request to delete transform {transformId} acknowledged.', + values: { transformId }, + }) + ); } else { - (Object.keys(successCount) as SuccessCountField[]).forEach((key) => { - if (status[key]?.success) { - successCount[key] = successCount[key] + 1; - } - }); - } - if (status.transformDeleted?.error) { - const error = extractErrorMessage(status.transformDeleted.error); - toastNotifications.addDanger({ - title: i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { + toastNotifications.addDanger( + i18n.translate('xpack.transform.transformList.deleteTransformErrorMessage', { defaultMessage: 'An error occurred deleting the transform {transformId}', values: { transformId }, - }), - text: toMountPoint( - - ), - }); + }) + ); } - - if (status.destIndexDeleted?.error) { - const error = extractErrorMessage(status.destIndexDeleted.error); - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexErrorMessage', - { - defaultMessage: 'An error occurred deleting destination index {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - - ), - }); - } - - if (status.destIndexPatternDeleted?.error) { - const error = extractErrorMessage(status.destIndexPatternDeleted.error); - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.transform.deleteTransform.deleteAnalyticsWithIndexPatternErrorMessage', - { - defaultMessage: 'An error occurred deleting index pattern {destinationIndex}', - values: { destinationIndex }, - } - ), - text: toMountPoint( - - ), - }); - } - } - } - - // if we are deleting multiple transforms, combine the success messages - if (isBulk) { - if (successCount.transformDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteTransformSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} {count, plural, one {transform} other {transforms}}.', - values: { count: successCount.transformDeleted }, - }) - ); - } - - if (successCount.destIndexDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate('xpack.transform.transformList.bulkDeleteDestIndexSuccessMessage', { - defaultMessage: - 'Successfully deleted {count} destination {count, plural, one {index} other {indices}}.', - values: { count: successCount.destIndexDeleted }, - }) - ); - } - if (successCount.destIndexPatternDeleted > 0) { - toastNotifications.addSuccess( - i18n.translate( - 'xpack.transform.transformList.bulkDeleteDestIndexPatternSuccessMessage', - { - defaultMessage: - 'Successfully deleted {count} destination index {count, plural, one {pattern} other {patterns}}.', - values: { count: successCount.destIndexPatternDeleted }, - } - ) - ); } } @@ -264,13 +59,7 @@ export const useDeleteTransforms = () => { title: i18n.translate('xpack.transform.transformList.deleteTransformGenericErrorMessage', { defaultMessage: 'An error occurred calling the API endpoint to delete transforms.', }), - text: toMountPoint( - - ), + text: toMountPoint(), }); } }; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx index d7db55990d333..c20feba29f582 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/action_delete.tsx @@ -12,14 +12,11 @@ import { EuiOverlayMask, EuiToolTip, EUI_MODAL_CONFIRM_BUTTON, - EuiFlexGroup, - EuiFlexItem, - EuiSwitch, - EuiSpacer, } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; + import { TRANSFORM_STATE } from '../../../../../../common'; -import { useDeleteTransforms, useDeleteIndexAndTargetIndex } from '../../../../hooks'; + +import { useDeleteTransforms } from '../../../../hooks'; import { createCapabilityFailureMessage, AuthorizationContext, @@ -38,25 +35,13 @@ export const DeleteAction: FC = ({ items, forceDisable }) => const { canDeleteTransform } = useContext(AuthorizationContext).capabilities; const deleteTransforms = useDeleteTransforms(); - const { - userCanDeleteIndex, - deleteDestIndex, - indexPatternExists, - deleteIndexPattern, - toggleDeleteIndex, - toggleDeleteIndexPattern, - } = useDeleteIndexAndTargetIndex(items); const [isModalVisible, setModalVisible] = useState(false); const closeModal = () => setModalVisible(false); const deleteAndCloseModal = () => { setModalVisible(false); - - const shouldDeleteDestIndex = userCanDeleteIndex && deleteDestIndex; - const shouldDeleteDestIndexPattern = - userCanDeleteIndex && indexPatternExists && deleteIndexPattern; - deleteTransforms(items, shouldDeleteDestIndex, shouldDeleteDestIndexPattern); + deleteTransforms(items); }; const openModal = () => setModalVisible(true); @@ -86,96 +71,17 @@ export const DeleteAction: FC = ({ items, forceDisable }) => defaultMessage: 'Delete {transformId}', values: { transformId: items[0] && items[0].config.id }, }); - const bulkDeleteModalContent = ( - <> -

- -

- - - { - - } - - - - { - - } - - - - ); - - const deleteModalContent = ( - <> -

- -

- - - {userCanDeleteIndex && ( - - )} - - {userCanDeleteIndex && indexPatternExists && ( - - - - - )} - - + const bulkDeleteModalMessage = i18n.translate( + 'xpack.transform.transformList.bulkDeleteModalBody', + { + defaultMessage: + "Are you sure you want to delete {count, plural, one {this} other {these}} {count} {count, plural, one {transform} other {transforms}}? The transform's destination index and optional Kibana index pattern will not be deleted.", + values: { count: items.length }, + } ); + const deleteModalMessage = i18n.translate('xpack.transform.transformList.deleteModalBody', { + defaultMessage: `Are you sure you want to delete this transform? The transform's destination index and optional Kibana index pattern will not be deleted.`, + }); let deleteButton = ( = ({ items, forceDisable }) => if (disabled || !canDeleteTransform) { let content; if (disabled) { - content = isBulkAction ? bulkDeleteButtonDisabledText : deleteButtonDisabledText; + content = isBulkAction === true ? bulkDeleteButtonDisabledText : deleteButtonDisabledText; } else { content = createCapabilityFailureMessage('canDeleteTransform'); } @@ -211,7 +117,7 @@ export const DeleteAction: FC = ({ items, forceDisable }) => {isModalVisible && ( = ({ items, forceDisable }) => defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} buttonColor="danger" > - {isBulkAction ? bulkDeleteModalContent : deleteModalContent} +

{isBulkAction === true ? bulkDeleteModalMessage : deleteModalMessage}

)} diff --git a/x-pack/plugins/transform/public/app/services/es_index_service.ts b/x-pack/plugins/transform/public/app/services/es_index_service.ts deleted file mode 100644 index 491213d0ddbe7..0000000000000 --- a/x-pack/plugins/transform/public/app/services/es_index_service.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { HttpSetup, SavedObjectsClientContract } from 'kibana/public'; -import { API_BASE_PATH } from '../../../common/constants'; -import { IIndexPattern } from '../../../../../../src/plugins/data/common/index_patterns'; - -export class IndexService { - async canDeleteIndex(http: HttpSetup) { - const privilege = await http.get(`${API_BASE_PATH}privileges`); - if (!privilege) { - return false; - } - return privilege.hasAllPrivileges; - } - - async indexPatternExists(savedObjectsClient: SavedObjectsClientContract, indexName: string) { - const response = await savedObjectsClient.find({ - type: 'index-pattern', - perPage: 1, - search: `"${indexName}"`, - searchFields: ['title'], - fields: ['title'], - }); - const ip = response.savedObjects.find((obj) => obj.attributes.title === indexName); - return ip !== undefined; - } -} - -export const indexService = new IndexService(); diff --git a/x-pack/plugins/transform/public/shared_imports.ts b/x-pack/plugins/transform/public/shared_imports.ts index ca3fb52cc02c3..56be8d7bb7de7 100644 --- a/x-pack/plugins/transform/public/shared_imports.ts +++ b/x-pack/plugins/transform/public/shared_imports.ts @@ -15,7 +15,6 @@ export { export { getErrorMessage, - extractErrorMessage, getDataGridSchemaFromKibanaFieldType, getFieldsFromKibanaIndexPattern, multiColumnSortFactory, diff --git a/x-pack/plugins/transform/server/routes/api/error_utils.ts b/x-pack/plugins/transform/server/routes/api/error_utils.ts index 5a479e4f429f6..295375794c04e 100644 --- a/x-pack/plugins/transform/server/routes/api/error_utils.ts +++ b/x-pack/plugins/transform/server/routes/api/error_utils.ts @@ -10,11 +10,7 @@ import { i18n } from '@kbn/i18n'; import { ResponseError, CustomHttpResponseOptions } from 'src/core/server'; -import { - TransformEndpointRequest, - TransformEndpointResult, - DeleteTransformEndpointResult, -} from '../../../common'; +import { TransformEndpointRequest, TransformEndpointResult } from '../../../common'; const REQUEST_TIMEOUT = 'RequestTimeout'; @@ -23,7 +19,7 @@ export function isRequestTimeout(error: any) { } interface Params { - results: TransformEndpointResult | DeleteTransformEndpointResult; + results: TransformEndpointResult; id: string; items: TransformEndpointRequest[]; action: string; @@ -63,7 +59,7 @@ export function fillResultsWithTimeouts({ results, id, items, action }: Params) }, }; - const newResults: TransformEndpointResult | DeleteTransformEndpointResult = {}; + const newResults: TransformEndpointResult = {}; return items.reduce((accumResults, currentVal) => { if (results[currentVal.id] === undefined) { diff --git a/x-pack/plugins/transform/server/routes/api/schema.ts b/x-pack/plugins/transform/server/routes/api/schema.ts index cf39f2e3829ea..0b994406d324d 100644 --- a/x-pack/plugins/transform/server/routes/api/schema.ts +++ b/x-pack/plugins/transform/server/routes/api/schema.ts @@ -14,17 +14,3 @@ export const schemaTransformId = { export interface SchemaTransformId { transformId: string; } - -export const deleteTransformSchema = schema.object({ - /** - * Delete Transform & Destination Index - */ - transformsInfo: schema.arrayOf( - schema.object({ - id: schema.string(), - state: schema.maybe(schema.string()), - }) - ), - deleteDestIndex: schema.maybe(schema.boolean()), - deleteDestIndexPattern: schema.maybe(schema.boolean()), -}); diff --git a/x-pack/plugins/transform/server/routes/api/transforms.ts b/x-pack/plugins/transform/server/routes/api/transforms.ts index 93fda56d319ad..55b2469a7f3a7 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms.ts @@ -5,12 +5,7 @@ */ import { schema } from '@kbn/config-schema'; -import { - KibanaResponseFactory, - RequestHandler, - RequestHandlerContext, - SavedObjectsClientContract, -} from 'kibana/server'; +import { RequestHandler } from 'kibana/server'; import { CallCluster } from 'src/legacy/core_plugins/elasticsearch'; import { wrapEsError } from '../../../../../legacy/server/lib/create_router/error_wrappers'; @@ -19,9 +14,6 @@ import { TransformEndpointResult, TransformId, TRANSFORM_STATE, - DeleteTransformEndpointRequest, - DeleteTransformStatus, - ResultData, } from '../../../common'; import { RouteDependencies } from '../../types'; @@ -29,9 +21,8 @@ import { RouteDependencies } from '../../types'; import { addBasePath } from '../index'; import { isRequestTimeout, fillResultsWithTimeouts, wrapError } from './error_utils'; -import { deleteTransformSchema, schemaTransformId, SchemaTransformId } from './schema'; +import { schemaTransformId, SchemaTransformId } from './schema'; import { registerTransformsAuditMessagesRoutes } from './transforms_audit_messages'; -import { IIndexPattern } from '../../../../../../src/plugins/data/common/index_patterns'; enum TRANSFORM_ACTIONS { STOP = 'stop', @@ -182,37 +173,15 @@ export function registerTransformsRoutes(routeDependencies: RouteDependencies) { { path: addBasePath('delete_transforms'), validate: { - body: deleteTransformSchema, + body: schema.maybe(schema.any()), }, }, license.guardApiRoute(async (ctx, req, res) => { - const { - transformsInfo, - deleteDestIndex, - deleteDestIndexPattern, - } = req.body as DeleteTransformEndpointRequest; + const transformsInfo = req.body as TransformEndpointRequest[]; try { - const body = await deleteTransforms( - transformsInfo, - deleteDestIndex, - deleteDestIndexPattern, - ctx, - license, - res - ); - - if (body && body.status) { - if (body.status === 404) { - return res.notFound(); - } - if (body.status === 403) { - return res.forbidden(); - } - } - return res.ok({ - body, + body: await deleteTransforms(transformsInfo, ctx.transform!.dataClient.callAsCurrentUser), }); } catch (e) { return res.customError(wrapError(wrapEsError(e))); @@ -269,51 +238,18 @@ const getTransforms = async (options: { transformId?: string }, callAsCurrentUse return await callAsCurrentUser('transform.getTransforms', options); }; -async function getIndexPatternId( - indexName: string, - savedObjectsClient: SavedObjectsClientContract -) { - const response = await savedObjectsClient.find({ - type: 'index-pattern', - perPage: 1, - search: `"${indexName}"`, - searchFields: ['title'], - fields: ['title'], - }); - const ip = response.saved_objects.find((obj) => obj.attributes.title === indexName); - return ip?.id; -} - -async function deleteDestIndexPatternById( - indexPatternId: string, - savedObjectsClient: SavedObjectsClientContract -) { - return await savedObjectsClient.delete('index-pattern', indexPatternId); -} - async function deleteTransforms( transformsInfo: TransformEndpointRequest[], - deleteDestIndex: boolean | undefined, - deleteDestIndexPattern: boolean | undefined, - ctx: RequestHandlerContext, - license: RouteDependencies['license'], - response: KibanaResponseFactory + callAsCurrentUser: CallCluster ) { - const tempResults: TransformEndpointResult = {}; - const results: Record = {}; + const results: TransformEndpointResult = {}; for (const transformInfo of transformsInfo) { - let destinationIndex: string | undefined; - const transformDeleted: ResultData = { success: false }; - const destIndexDeleted: ResultData = { success: false }; - const destIndexPatternDeleted: ResultData = { - success: false, - }; const transformId = transformInfo.id; try { if (transformInfo.state === TRANSFORM_STATE.FAILED) { try { - await ctx.transform!.dataClient.callAsCurrentUser('transform.stopTransform', { + await callAsCurrentUser('transform.stopTransform', { transformId, force: true, waitForCompletion: true, @@ -321,7 +257,7 @@ async function deleteTransforms( } catch (e) { if (isRequestTimeout(e)) { return fillResultsWithTimeouts({ - results: tempResults, + results, id: transformId, items: transformsInfo, action: TRANSFORM_ACTIONS.DELETE, @@ -329,75 +265,9 @@ async function deleteTransforms( } } } - // Grab destination index info to delete - try { - const transformConfigs = await getTransforms( - { transformId }, - ctx.transform!.dataClient.callAsCurrentUser - ); - const transformConfig = transformConfigs.transforms[0]; - destinationIndex = Array.isArray(transformConfig.dest.index) - ? transformConfig.dest.index[0] - : transformConfig.dest.index; - } catch (getTransformConfigError) { - transformDeleted.error = wrapError(getTransformConfigError); - results[transformId] = { - transformDeleted, - destIndexDeleted, - destIndexPatternDeleted, - destinationIndex, - }; - continue; - } - - // If user checks box to delete the destinationIndex associated with the job - if (destinationIndex && deleteDestIndex) { - try { - // If user does have privilege to delete the index, then delete the index - // if no permission then return 403 forbidden - await ctx.transform!.dataClient.callAsCurrentUser('indices.delete', { - index: destinationIndex, - }); - destIndexDeleted.success = true; - } catch (deleteIndexError) { - destIndexDeleted.error = wrapError(deleteIndexError); - } - } - - // Delete the index pattern if there's an index pattern that matches the name of dest index - if (destinationIndex && deleteDestIndexPattern) { - try { - const indexPatternId = await getIndexPatternId( - destinationIndex, - ctx.core.savedObjects.client - ); - if (indexPatternId) { - await deleteDestIndexPatternById(indexPatternId, ctx.core.savedObjects.client); - destIndexPatternDeleted.success = true; - } - } catch (deleteDestIndexPatternError) { - destIndexPatternDeleted.error = wrapError(deleteDestIndexPatternError); - } - } - try { - await ctx.transform!.dataClient.callAsCurrentUser('transform.deleteTransform', { - transformId, - }); - transformDeleted.success = true; - } catch (deleteTransformJobError) { - transformDeleted.error = wrapError(deleteTransformJobError); - if (transformDeleted.error.statusCode === 403) { - return response.forbidden(); - } - } - - results[transformId] = { - transformDeleted, - destIndexDeleted, - destIndexPatternDeleted, - destinationIndex, - }; + await callAsCurrentUser('transform.deleteTransform', { transformId }); + results[transformId] = { success: true }; } catch (e) { if (isRequestTimeout(e)) { return fillResultsWithTimeouts({ @@ -407,7 +277,7 @@ async function deleteTransforms( action: TRANSFORM_ACTIONS.DELETE, }); } - results[transformId] = { transformDeleted: { success: false, error: JSON.stringify(e) } }; + results[transformId] = { success: false, error: JSON.stringify(e) }; } } return results; diff --git a/x-pack/test/api_integration/apis/index.js b/x-pack/test/api_integration/apis/index.js index b79dc3f3ffe59..2719486d0c502 100644 --- a/x-pack/test/api_integration/apis/index.js +++ b/x-pack/test/api_integration/apis/index.js @@ -30,6 +30,5 @@ export default function ({ loadTestFile }) { loadTestFile(require.resolve('./ingest_manager')); loadTestFile(require.resolve('./endpoint')); loadTestFile(require.resolve('./ml')); - loadTestFile(require.resolve('./transform')); }); } diff --git a/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts b/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts index dc0ccfdc53a18..23bff0d0c2855 100644 --- a/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts +++ b/x-pack/test/api_integration/apis/ml/data_frame_analytics/delete.ts @@ -197,7 +197,7 @@ export default ({ getService }: FtrProviderContext) => { await ml.testResources.deleteIndexPattern(destinationIndex); }); - it('should delete job, target index, and index pattern by id', async () => { + it('deletes job, target index, and index pattern by id', async () => { const { body } = await supertest .delete(`/api/ml/data_frame/analytics/${analyticsId}`) .query({ deleteDestIndex: true, deleteDestIndexPattern: true }) diff --git a/x-pack/test/api_integration/apis/transform/delete_transforms.ts b/x-pack/test/api_integration/apis/transform/delete_transforms.ts deleted file mode 100644 index 40300c981ee2e..0000000000000 --- a/x-pack/test/api_integration/apis/transform/delete_transforms.ts +++ /dev/null @@ -1,318 +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 { TransformEndpointRequest } from '../../../../plugins/transform/common'; -import { FtrProviderContext } from '../../ftr_provider_context'; -import { COMMON_REQUEST_HEADERS } from '../../../functional/services/ml/common'; -import { USER } from '../../../functional/services/transform/security_common'; - -async function asyncForEach(array: any[], callback: Function) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array); - } -} - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); - const supertest = getService('supertestWithoutAuth'); - const transform = getService('transform'); - - function generateDestIndex(transformId: string): string { - return `user-${transformId}`; - } - - async function createTransform(transformId: string, destinationIndex: string) { - const config = { - id: transformId, - source: { index: ['farequote-*'] }, - pivot: { - group_by: { airline: { terms: { field: 'airline' } } }, - aggregations: { '@timestamp.value_count': { value_count: { field: '@timestamp' } } }, - }, - dest: { index: destinationIndex }, - }; - - await transform.api.createTransform(config); - } - - describe('delete_transforms', function () { - before(async () => { - await esArchiver.loadIfNeeded('ml/farequote'); - await transform.testResources.setKibanaTimeZoneToUTC(); - }); - - after(async () => { - await transform.api.cleanTransformIndices(); - }); - - describe('single transform deletion', function () { - const transformId = 'test1'; - const destinationIndex = generateDestIndex(transformId); - - beforeEach(async () => { - await createTransform(transformId, destinationIndex); - await transform.api.createIndices(destinationIndex); - }); - - afterEach(async () => { - await transform.api.deleteIndices(destinationIndex); - }); - - it('should delete transform by transformId', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: transformId }]; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - }) - .expect(200); - - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(false); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(false); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesToExist(destinationIndex); - }); - - it('should return 403 for unauthorized user', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: transformId }]; - await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_VIEWER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_VIEWER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - }) - .expect(403); - await transform.api.waitForTransformToExist(transformId); - await transform.api.waitForIndicesToExist(destinationIndex); - }); - }); - - describe('single transform deletion with invalid transformId', function () { - it('should return 200 with error in response if invalid transformId', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: 'invalid_transform_id' }]; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - }) - .expect(200); - expect(body.invalid_transform_id.transformDeleted.success).to.eql(false); - expect(body.invalid_transform_id.transformDeleted).to.have.property('error'); - }); - }); - - describe('bulk deletion', function () { - const transformsInfo: TransformEndpointRequest[] = [ - { id: 'bulk_delete_test_1' }, - { id: 'bulk_delete_test_2' }, - ]; - const destinationIndices = transformsInfo.map((d) => generateDestIndex(d.id)); - - beforeEach(async () => { - await asyncForEach(transformsInfo, async ({ id }: { id: string }, idx: number) => { - await createTransform(id, destinationIndices[idx]); - await transform.api.createIndices(destinationIndices[idx]); - }); - }); - - afterEach(async () => { - await asyncForEach(destinationIndices, async (destinationIndex: string) => { - await transform.api.deleteIndices(destinationIndex); - }); - }); - - it('should delete multiple transforms by transformIds', async () => { - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - }) - .expect(200); - - await asyncForEach( - transformsInfo, - async ({ id: transformId }: { id: string }, idx: number) => { - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(false); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(false); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesToExist(destinationIndices[idx]); - } - ); - }); - - it('should delete multiple transforms by transformIds, even if one of the transformIds is invalid', async () => { - const invalidTransformId = 'invalid_transform_id'; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo: [ - { id: transformsInfo[0].id }, - { id: invalidTransformId }, - { id: transformsInfo[1].id }, - ], - }) - .expect(200); - - await asyncForEach( - transformsInfo, - async ({ id: transformId }: { id: string }, idx: number) => { - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(false); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(false); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesToExist(destinationIndices[idx]); - } - ); - - expect(body[invalidTransformId].transformDeleted.success).to.eql(false); - expect(body[invalidTransformId].transformDeleted).to.have.property('error'); - }); - }); - - describe('with deleteDestIndex setting', function () { - const transformId = 'test2'; - const destinationIndex = generateDestIndex(transformId); - - before(async () => { - await createTransform(transformId, destinationIndex); - await transform.api.createIndices(destinationIndex); - }); - - after(async () => { - await transform.api.deleteIndices(destinationIndex); - }); - - it('should delete transform and destination index', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: transformId }]; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - deleteDestIndex: true, - }) - .expect(200); - - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(true); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(false); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesNotToExist(destinationIndex); - }); - }); - - describe('with deleteDestIndexPattern setting', function () { - const transformId = 'test3'; - const destinationIndex = generateDestIndex(transformId); - - before(async () => { - await createTransform(transformId, destinationIndex); - await transform.api.createIndices(destinationIndex); - await transform.testResources.createIndexPatternIfNeeded(destinationIndex); - }); - - after(async () => { - await transform.api.deleteIndices(destinationIndex); - await transform.testResources.deleteIndexPattern(destinationIndex); - }); - - it('should delete transform and destination index pattern', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: transformId }]; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - deleteDestIndex: false, - deleteDestIndexPattern: true, - }) - .expect(200); - - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(false); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(true); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesToExist(destinationIndex); - await transform.testResources.assertIndexPatternNotExist(destinationIndex); - }); - }); - - describe('with deleteDestIndex & deleteDestIndexPattern setting', function () { - const transformId = 'test4'; - const destinationIndex = generateDestIndex(transformId); - - before(async () => { - await createTransform(transformId, destinationIndex); - await transform.api.createIndices(destinationIndex); - await transform.testResources.createIndexPatternIfNeeded(destinationIndex); - }); - - after(async () => { - await transform.api.deleteIndices(destinationIndex); - await transform.testResources.deleteIndexPattern(destinationIndex); - }); - - it('should delete transform, destination index, & destination index pattern', async () => { - const transformsInfo: TransformEndpointRequest[] = [{ id: transformId }]; - const { body } = await supertest - .post(`/api/transform/delete_transforms`) - .auth( - USER.TRANSFORM_POWERUSER, - transform.securityCommon.getPasswordForUser(USER.TRANSFORM_POWERUSER) - ) - .set(COMMON_REQUEST_HEADERS) - .send({ - transformsInfo, - deleteDestIndex: true, - deleteDestIndexPattern: true, - }) - .expect(200); - - expect(body[transformId].transformDeleted.success).to.eql(true); - expect(body[transformId].destIndexDeleted.success).to.eql(true); - expect(body[transformId].destIndexPatternDeleted.success).to.eql(true); - await transform.api.waitForTransformNotToExist(transformId); - await transform.api.waitForIndicesNotToExist(destinationIndex); - await transform.testResources.assertIndexPatternNotExist(destinationIndex); - }); - }); - }); -}; diff --git a/x-pack/test/api_integration/apis/transform/index.ts b/x-pack/test/api_integration/apis/transform/index.ts deleted file mode 100644 index 93a951a55ece1..0000000000000 --- a/x-pack/test/api_integration/apis/transform/index.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ getService, loadTestFile }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const transform = getService('transform'); - - describe('Machine Learning', function () { - this.tags(['transform']); - - before(async () => { - await transform.securityCommon.createTransformRoles(); - await transform.securityCommon.createTransformUsers(); - }); - - after(async () => { - await transform.securityCommon.cleanTransformUsers(); - await transform.securityCommon.cleanTransformRoles(); - - await esArchiver.unload('ml/farequote'); - - await transform.testResources.resetKibanaTimeZone(); - }); - - loadTestFile(require.resolve('./delete_transforms')); - }); -} diff --git a/x-pack/test/api_integration/services/index.ts b/x-pack/test/api_integration/services/index.ts index 2a0327ff57104..e7e166237c602 100644 --- a/x-pack/test/api_integration/services/index.ts +++ b/x-pack/test/api_integration/services/index.ts @@ -28,7 +28,6 @@ import { InfraLogSourceConfigurationProvider } from './infra_log_source_configur import { MachineLearningProvider } from './ml'; import { IngestManagerProvider } from './ingest_manager'; import { ResolverGeneratorProvider } from './resolver'; -import { TransformProvider } from './transform'; export const services = { ...commonServices, @@ -49,5 +48,4 @@ export const services = { ml: MachineLearningProvider, ingestManager: IngestManagerProvider, resolverGenerator: ResolverGeneratorProvider, - transform: TransformProvider, }; diff --git a/x-pack/test/api_integration/services/transform.ts b/x-pack/test/api_integration/services/transform.ts deleted file mode 100644 index 1403d5d2d67f0..0000000000000 --- a/x-pack/test/api_integration/services/transform.ts +++ /dev/null @@ -1,23 +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 { FtrProviderContext } from '../../functional/ftr_provider_context'; - -import { TransformAPIProvider } from '../../functional/services/transform/api'; -import { TransformSecurityCommonProvider } from '../../functional/services/transform/security_common'; -import { MachineLearningTestResourcesProvider } from '../../functional/services/ml/test_resources'; - -export function TransformProvider(context: FtrProviderContext) { - const api = TransformAPIProvider(context); - const securityCommon = TransformSecurityCommonProvider(context); - const testResources = MachineLearningTestResourcesProvider(context); - - return { - api, - securityCommon, - testResources, - }; -} diff --git a/x-pack/test/functional/services/transform/api.ts b/x-pack/test/functional/services/transform/api.ts index 697020fafb196..a805f5a3b6013 100644 --- a/x-pack/test/functional/services/transform/api.ts +++ b/x-pack/test/functional/services/transform/api.ts @@ -20,21 +20,6 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { const esSupertest = getService('esSupertest'); return { - async createIndices(indices: string) { - log.debug(`Creating indices: '${indices}'...`); - if ((await es.indices.exists({ index: indices, allowNoIndices: false })) === true) { - log.debug(`Indices '${indices}' already exist. Nothing to create.`); - return; - } - - const createResponse = await es.indices.create({ index: indices }); - expect(createResponse) - .to.have.property('acknowledged') - .eql(true, 'Response for create request indices should be acknowledged.'); - - await this.waitForIndicesToExist(indices, `expected ${indices} to be created`); - }, - async deleteIndices(indices: string) { log.debug(`Deleting indices: '${indices}'...`); if ((await es.indices.exists({ index: indices, allowNoIndices: false })) === false) { @@ -49,25 +34,11 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { .to.have.property('acknowledged') .eql(true, 'Response for delete request should be acknowledged'); - await this.waitForIndicesNotToExist(indices, `expected indices '${indices}' to be deleted`); - }, - - async waitForIndicesToExist(indices: string, errorMsg?: string) { - await retry.tryForTime(30 * 1000, async () => { - if ((await es.indices.exists({ index: indices, allowNoIndices: false })) === true) { - return true; - } else { - throw new Error(errorMsg || `indices '${indices}' should exist`); - } - }); - }, - - async waitForIndicesNotToExist(indices: string, errorMsg?: string) { - await retry.tryForTime(30 * 1000, async () => { + await retry.waitForWithTimeout(`'${indices}' indices to be deleted`, 30 * 1000, async () => { if ((await es.indices.exists({ index: indices, allowNoIndices: false })) === false) { return true; } else { - throw new Error(errorMsg || `indices '${indices}' should not exist`); + throw new Error(`expected indices '${indices}' to be deleted`); } }); }, @@ -92,7 +63,9 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { async getTransformState(transformId: string): Promise { const stats = await this.getTransformStats(transformId); - return stats.state; + const state: TRANSFORM_STATE = stats.state; + + return state; }, async waitForTransformState(transformId: string, expectedState: TRANSFORM_STATE) { @@ -123,8 +96,8 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { }); }, - async getTransform(transformId: string, expectedCode = 200) { - return await esSupertest.get(`/_transform/${transformId}`).expect(expectedCode); + async getTransform(transformId: string) { + return await esSupertest.get(`/_transform/${transformId}`).expect(200); }, async createTransform(transformConfig: TransformPivotConfig) { @@ -132,27 +105,11 @@ export function TransformAPIProvider({ getService }: FtrProviderContext) { log.debug(`Creating transform with id '${transformId}'...`); await esSupertest.put(`/_transform/${transformId}`).send(transformConfig).expect(200); - await this.waitForTransformToExist( - transformId, - `expected transform '${transformId}' to be created` - ); - }, - - async waitForTransformToExist(transformId: string, errorMsg?: string) { - await retry.waitForWithTimeout(`'${transformId}' to exist`, 5 * 1000, async () => { - if (await this.getTransform(transformId, 200)) { - return true; - } else { - throw new Error(errorMsg || `expected transform '${transformId}' to exist`); - } - }); - }, - async waitForTransformNotToExist(transformId: string, errorMsg?: string) { - await retry.waitForWithTimeout(`'${transformId}' to exist`, 5 * 1000, async () => { - if (await this.getTransform(transformId, 404)) { + await retry.waitForWithTimeout(`'${transformId}' to be created`, 5 * 1000, async () => { + if (await this.getTransform(transformId)) { return true; } else { - throw new Error(errorMsg || `expected transform '${transformId}' to not exist`); + throw new Error(`expected transform '${transformId}' to be created`); } }); },