From 1c436260065f73e58303aabc5fd1e18d636080b7 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 14 Mar 2022 11:55:57 -0400 Subject: [PATCH] [Upgrade Assistant] Add deprecation logging as step on overview page (#126693) --- .../translations/translations/ja-JP.json | 3 - .../translations/translations/zh-CN.json | 3 - .../overview/logs_step/logs_step.test.tsx | 159 ++++++++++++ .../fix_deprecation_logs/index.ts | 1 + .../components/es_deprecation_logs/index.ts | 1 + .../fix_issues_step/fix_issues_step.tsx | 53 +--- .../components/overview/logs_step/index.ts | 8 + .../overview/logs_step/logs_step.tsx | 243 ++++++++++++++++++ .../components/overview/overview.tsx | 8 +- .../page_objects/upgrade_assistant_page.ts | 6 +- 10 files changed, 425 insertions(+), 60 deletions(-) create mode 100644 x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/logs_step/logs_step.test.tsx create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/index.ts create mode 100644 x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/logs_step.tsx diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index eac8f27215627..d0ec673fa45c5 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28379,7 +28379,6 @@ "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "他のスタック廃止予定については、{overviewButton}を確認してください。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "概要ページ", "xpack.upgradeAssistant.noPartialDeprecationsMessage": "なし", - "xpack.upgradeAssistant.overview.accessEsDeprecationLogsLabel": "Elasticsearch APIを呼び出すアプリケーションコードがある場合は、{esDeprecationLogsLink}を確認して、廃止予定のAPIを使用していないことを確かめてください。", "xpack.upgradeAssistant.overview.analyzeTitle": "廃止予定ログを分析", "xpack.upgradeAssistant.overview.apiCompatibilityNoteBody": "アップグレード前にすべての廃止予定の問題を解決することをお勧めします。必要に応じて、廃止予定の機能を使用する要求にAPI互換性ヘッダーを適用できます。{learnMoreLink}。", "xpack.upgradeAssistant.overview.apiCompatibilityNoteLink": "詳細", @@ -28405,8 +28404,6 @@ "xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "廃止予定の問題を解決して変更を検証", "xpack.upgradeAssistant.overview.documentationLinkText": "ドキュメント", "xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "アップグレードステータスの取得中にエラーが発生しました", - "xpack.upgradeAssistant.overview.esDeprecationLogsLink": "Elasticsearchの廃止予定ログ", - "xpack.upgradeAssistant.overview.fixIssuesStepDescription": "Elastic 8.xにアップグレードする前に、重大なElasticsearchおよびKibana構成の問題を解決する必要があります。警告を無視すると、アップグレード後に動作が変更される場合があります。{accessDeprecationLogsMessage}", "xpack.upgradeAssistant.overview.fixIssuesStepTitle": "廃止予定設定を確認し、問題を解決", "xpack.upgradeAssistant.overview.loadingLogsLabel": "廃止予定ログ収集状態を読み込んでいます...", "xpack.upgradeAssistant.overview.loadingUpgradeStatus": "アップグレードステータスを読み込んでいます", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 909fbe46321bd..88c0a67ecf1b7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28412,7 +28412,6 @@ "xpack.upgradeAssistant.noDeprecationsPrompt.nextStepsDescription": "查看{overviewButton}以了解其他 Stack 弃用。", "xpack.upgradeAssistant.noDeprecationsPrompt.overviewLinkText": "“概览”页面", "xpack.upgradeAssistant.noPartialDeprecationsMessage": "无", - "xpack.upgradeAssistant.overview.accessEsDeprecationLogsLabel": "如果有应用程序代码调用 Elasticsearch API,请复查 {esDeprecationLogsLink}以确保您未使用已弃用的 API。", "xpack.upgradeAssistant.overview.analyzeTitle": "分析弃用日志", "xpack.upgradeAssistant.overview.apiCompatibilityNoteBody": "建议您在升级之前解决所有弃用问题。如果需要,您可以将 API 兼容性标头应用于使用过时功能的请求。{learnMoreLink}。", "xpack.upgradeAssistant.overview.apiCompatibilityNoteLink": "了解详情", @@ -28438,8 +28437,6 @@ "xpack.upgradeAssistant.overview.deprecationsCountCheckpointTitle": "解决弃用问题并验证您的更改", "xpack.upgradeAssistant.overview.documentationLinkText": "文档", "xpack.upgradeAssistant.overview.errorLoadingUpgradeStatus": "检索升级状态时出错", - "xpack.upgradeAssistant.overview.esDeprecationLogsLink": "Elasticsearch 弃用日志", - "xpack.upgradeAssistant.overview.fixIssuesStepDescription": "在升级到 Elastic 8.x 之前,必须解决任何严重的 Elasticsearch 和 Kibana 配置问题。在您升级后,忽略警告可能会导致行为差异。{accessDeprecationLogsMessage}", "xpack.upgradeAssistant.overview.fixIssuesStepTitle": "复查已弃用设置并解决问题", "xpack.upgradeAssistant.overview.loadingLogsLabel": "正在加载弃用日志收集状态……", "xpack.upgradeAssistant.overview.loadingUpgradeStatus": "正在加载升级状态", diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/logs_step/logs_step.test.tsx b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/logs_step/logs_step.test.tsx new file mode 100644 index 0000000000000..31cbb8ebef456 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/overview/logs_step/logs_step.test.tsx @@ -0,0 +1,159 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { DEPRECATION_LOGS_INDEX } from '../../../../common/constants'; +import { setupEnvironment } from '../../helpers'; +import { OverviewTestBed, setupOverviewPage } from '../overview.helpers'; + +describe('Overview - Logs Step', () => { + let testBed: OverviewTestBed; + + const { server, httpRequestsMockHelpers } = setupEnvironment(); + + afterAll(() => { + server.restore(); + }); + + describe('error state', () => { + beforeEach(async () => { + const error = { + statusCode: 500, + error: 'Internal server error', + message: 'Internal server error', + }; + + httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse(undefined, error); + + await act(async () => { + testBed = await setupOverviewPage(); + }); + + testBed.component.update(); + }); + + test('is rendered', () => { + const { exists } = testBed; + expect(exists('deprecationLogsErrorCallout')).toBe(true); + expect(exists('deprecationLogsRetryButton')).toBe(true); + }); + }); + + describe('success state', () => { + describe('logging enabled', () => { + beforeEach(() => { + httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ + isDeprecationLogIndexingEnabled: true, + isDeprecationLoggingEnabled: true, + }); + }); + + test('renders step as complete when a user has 0 logs', async () => { + httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ + count: 0, + }); + + await act(async () => { + testBed = await setupOverviewPage(); + }); + + const { component, exists } = testBed; + + component.update(); + + expect(exists('logsStep-complete')).toBe(true); + }); + + test('renders step as incomplete when a user has >0 logs', async () => { + httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ + count: 10, + }); + + await act(async () => { + testBed = await setupOverviewPage(); + }); + + const { component, exists } = testBed; + + component.update(); + + expect(exists('logsStep-incomplete')).toBe(true); + }); + + test('renders deprecation issue count and button to view logs', async () => { + httpRequestsMockHelpers.setLoadDeprecationLogsCountResponse({ + count: 10, + }); + + await act(async () => { + testBed = await setupOverviewPage(); + }); + + const { component, find } = testBed; + + component.update(); + + expect(find('logsCountDescription').text()).toContain('You have 10 deprecation issues'); + expect(find('viewLogsLink').text()).toContain('View logs'); + }); + }); + + describe('logging disabled', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ + isDeprecationLogIndexingEnabled: false, + isDeprecationLoggingEnabled: true, + }); + + await act(async () => { + testBed = await setupOverviewPage(); + }); + + const { component } = testBed; + + component.update(); + }); + + test('renders button to enable logs', () => { + const { find, exists } = testBed; + + expect(exists('logsCountDescription')).toBe(false); + expect(find('enableLogsLink').text()).toContain('Enable logging'); + }); + }); + }); + + describe('privileges', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadDeprecationLoggingResponse({ + isDeprecationLogIndexingEnabled: true, + isDeprecationLoggingEnabled: true, + }); + + await act(async () => { + testBed = await setupOverviewPage({ + privileges: { + hasAllPrivileges: true, + missingPrivileges: { + index: [DEPRECATION_LOGS_INDEX], + }, + }, + }); + }); + + const { component } = testBed; + + component.update(); + }); + + test('warns the user of missing index privileges', () => { + const { exists } = testBed; + + expect(exists('missingPrivilegesCallout')).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/fix_deprecation_logs/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/fix_deprecation_logs/index.ts index c0af5524e3a14..ffc1a60e8a2fb 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/fix_deprecation_logs/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/fix_deprecation_logs/index.ts @@ -6,3 +6,4 @@ */ export { FixDeprecationLogs } from './fix_deprecation_logs'; +export { useDeprecationLogging } from './use_deprecation_logging'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/index.ts index 336aa14642f7d..978fb18cbe2a7 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/index.ts +++ b/x-pack/plugins/upgrade_assistant/public/application/components/es_deprecation_logs/index.ts @@ -6,3 +6,4 @@ */ export { EsDeprecationLogs } from './es_deprecation_logs'; +export { useDeprecationLogging } from './fix_deprecation_logs'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx index aa3fe2cf3602d..9ae309fc79336 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/fix_issues_step/fix_issues_step.tsx @@ -7,13 +7,11 @@ import React, { FunctionComponent, useState, useEffect } from 'react'; -import { EuiText, EuiFlexItem, EuiFlexGroup, EuiSpacer, EuiLink } from '@elastic/eui'; +import { EuiText, EuiFlexItem, EuiFlexGroup, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; -import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants'; -import { WithPrivileges } from '../../../../shared_imports'; import type { OverviewStepProps } from '../../types'; import { EsDeprecationIssuesPanel, KibanaDeprecationIssuesPanel } from './components'; @@ -51,48 +49,10 @@ const FixIssuesStep: FunctionComponent = ({ setIsComplete }) => { ); }; -interface CustomProps { - navigateToEsDeprecationLogs: () => void; -} - -const AccessDeprecationLogsMessage = ({ navigateToEsDeprecationLogs }: CustomProps) => { - return ( - - {({ hasPrivileges, isLoading }) => { - if (isLoading || !hasPrivileges) { - // Don't show the message with the link to access deprecation logs - // to users who can't access the UI anyways. - return null; - } - - return ( - - {i18n.translate('xpack.upgradeAssistant.overview.esDeprecationLogsLink', { - defaultMessage: 'Elasticsearch deprecation logs', - })} - - ), - }} - /> - ); - }} - - ); -}; - export const getFixIssuesStep = ({ isComplete, setIsComplete, - navigateToEsDeprecationLogs, -}: OverviewStepProps & CustomProps): EuiStepProps => { +}: OverviewStepProps): EuiStepProps => { const status = isComplete ? 'complete' : 'incomplete'; return { @@ -105,14 +65,7 @@ export const getFixIssuesStep = ({

- ), - }} + defaultMessage="You must resolve any critical Elasticsearch and Kibana configuration issues before upgrading to Elastic 8.x. Ignoring warnings might result in differences in behavior after you upgrade." />

diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/index.ts b/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/index.ts new file mode 100644 index 0000000000000..96e6cf4d71c08 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getLogsStep } from './logs_step'; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/logs_step.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/logs_step.tsx new file mode 100644 index 0000000000000..bc073ef81f21e --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/logs_step/logs_step.tsx @@ -0,0 +1,243 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import { + EuiText, + EuiSpacer, + EuiButton, + EuiCallOut, + EuiLoadingContent, + EuiCode, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedDate, FormattedTime, FormattedMessage } from '@kbn/i18n-react'; +import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; + +import { DEPRECATION_LOGS_INDEX } from '../../../../../common/constants'; +import { WithPrivileges, MissingPrivileges } from '../../../../shared_imports'; +import { useAppContext } from '../../../app_context'; +import { loadLogsCheckpoint } from '../../../lib/logs_checkpoint'; +import type { OverviewStepProps } from '../../types'; +import { useDeprecationLogging } from '../../es_deprecation_logs'; + +const i18nTexts = { + logsStepTitle: i18n.translate('xpack.upgradeAssistant.overview.logsStep.title', { + defaultMessage: 'Address API deprecations', + }), + logsStepDescription: i18n.translate('xpack.upgradeAssistant.overview.logsStep.description', { + defaultMessage: `Review the Elasticsearch deprecation logs to ensure you're not using deprecated APIs.`, + }), + viewLogsButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.overview.logsStep.viewLogsButtonLabel', + { + defaultMessage: 'View logs', + } + ), + enableLogsButtonLabel: i18n.translate( + 'xpack.upgradeAssistant.overview.logsStep.enableLogsButtonLabel', + { + defaultMessage: 'Enable logging', + } + ), + logsCountDescription: (deprecationCount: number, checkpoint: string) => ( + + {' '} + + + ), + }} + /> + ), + missingPrivilegesTitle: i18n.translate( + 'xpack.upgradeAssistant.overview.logsStep.missingPrivilegesTitle', + { + defaultMessage: 'You require index privileges to analyze the deprecation logs', + } + ), + missingPrivilegesDescription: (privilegesMissing: MissingPrivileges) => ( + {privilegesMissing?.index?.join(', ')} + ), + privilegesCount: privilegesMissing?.index?.length, + }} + /> + ), + loadingError: i18n.translate('xpack.upgradeAssistant.overview.logsStep.loadingError', { + defaultMessage: 'An error occurred while retrieving the deprecation log count', + }), + retryButton: i18n.translate('xpack.upgradeAssistant.overview.logsStep.retryButton', { + defaultMessage: 'Try again', + }), +}; + +interface LogStepProps { + setIsComplete: (isComplete: boolean) => void; + hasPrivileges: boolean; + privilegesMissing: MissingPrivileges; + navigateToEsDeprecationLogs: () => void; +} + +const LogStepDescription = () => ( + +

{i18nTexts.logsStepDescription}

+
+); + +const LogsStep = ({ + setIsComplete, + hasPrivileges, + privilegesMissing, + navigateToEsDeprecationLogs, +}: LogStepProps) => { + const { + services: { api }, + } = useAppContext(); + + const { isDeprecationLogIndexingEnabled } = useDeprecationLogging(); + + const checkpoint = loadLogsCheckpoint(); + + const { + data: logsCount, + error, + isLoading, + resendRequest, + isInitialRequest, + } = api.getDeprecationLogsCount(checkpoint); + + useEffect(() => { + if (!isDeprecationLogIndexingEnabled) { + setIsComplete(false); + } + + setIsComplete(logsCount?.count === 0); + + // Depending upon setIsComplete would create an infinite loop. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isDeprecationLogIndexingEnabled, logsCount]); + + if (hasPrivileges === false && isDeprecationLogIndexingEnabled) { + return ( + <> + + + + + +

{i18nTexts.missingPrivilegesDescription(privilegesMissing)}

+
+ + ); + } + + if (isLoading && isInitialRequest) { + return ; + } + + if (hasPrivileges && error) { + return ( + +

+ {error.statusCode} - {error.message} +

+ + + {i18nTexts.retryButton} + +
+ ); + } + + return ( + <> + + + {isDeprecationLogIndexingEnabled && logsCount ? ( + <> + + + +

+ {i18nTexts.logsCountDescription(logsCount.count, checkpoint)} +

+
+ + + + + {i18nTexts.viewLogsButtonLabel} + + + ) : ( + <> + + + + {i18nTexts.enableLogsButtonLabel} + + + )} + + + ); +}; + +interface CustomProps { + navigateToEsDeprecationLogs: () => void; +} + +export const getLogsStep = ({ + isComplete, + setIsComplete, + navigateToEsDeprecationLogs, +}: OverviewStepProps & CustomProps): EuiStepProps => { + const status = isComplete ? 'complete' : 'incomplete'; + + return { + status, + title: i18nTexts.logsStepTitle, + 'data-test-subj': `logsStep-${status}`, + children: ( + + {({ hasPrivileges, isLoading, privilegesMissing }) => ( + + )} + + ), + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index 93dcc162aa6fe..99bee6ec8f4b9 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -28,8 +28,9 @@ import { getBackupStep } from './backup_step'; import { getFixIssuesStep } from './fix_issues_step'; import { getUpgradeStep } from './upgrade_step'; import { getMigrateSystemIndicesStep } from './migrate_system_indices'; +import { getLogsStep } from './logs_step'; -type OverviewStep = 'backup' | 'migrate_system_indices' | 'fix_issues'; +type OverviewStep = 'backup' | 'migrate_system_indices' | 'fix_issues' | 'logs'; export const Overview = withRouter(({ history }: RouteComponentProps) => { const { @@ -52,6 +53,7 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => { backup: false, migrate_system_indices: false, fix_issues: false, + logs: false, }); const isStepComplete = (step: OverviewStep) => completedStepsMap[step]; @@ -114,6 +116,10 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => { getFixIssuesStep({ isComplete: isStepComplete('fix_issues'), setIsComplete: setCompletedStep.bind(null, 'fix_issues'), + }), + getLogsStep({ + isComplete: isStepComplete('logs'), + setIsComplete: setCompletedStep.bind(null, 'logs'), navigateToEsDeprecationLogs: () => history.push('/es_deprecation_logs'), }), getUpgradeStep(), diff --git a/x-pack/test/functional/page_objects/upgrade_assistant_page.ts b/x-pack/test/functional/page_objects/upgrade_assistant_page.ts index f59cf660139b9..933880dac739e 100644 --- a/x-pack/test/functional/page_objects/upgrade_assistant_page.ts +++ b/x-pack/test/functional/page_objects/upgrade_assistant_page.ts @@ -31,9 +31,9 @@ export class UpgradeAssistantPageObject extends FtrService { async navigateToEsDeprecationLogs() { return await this.retry.try(async () => { - await this.common.navigateToApp('settings'); - await this.testSubjects.click('upgrade_assistant'); - await this.testSubjects.click('viewElasticsearchDeprecationLogs'); + await this.common.navigateToUrl('management', 'stack/upgrade_assistant/es_deprecation_logs', { + shouldUseHashForSubUrl: false, + }); await this.retry.waitFor( 'url to contain /upgrade_assistant/es_deprecation_logs', async () => {