From 7557e240219340f7d4e0a8648a6fc050d2a9dceb Mon Sep 17 00:00:00 2001 From: Sonia Sanz Vivas Date: Mon, 9 Dec 2024 09:57:41 +0100 Subject: [PATCH] Snapshots: show slm and status (#199622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes [#148241](https://github.com/elastic/kibana/issues/148241) ## Summary This PR introduces a few changes in the snapshot and restore plugin. #### Snapshots tab * The state column has been aded to the table * In the detail flyout, it has been changed the way in which the status is displayed (icon and text). * No new test needed since this info was already there. The related tests have been updated.
Screenshot 2024-11-27 at 15 17 03 Screenshot 2024-11-27 at 15 54 32
#### Policies tab * The copy of the callout for warning that two or more policies have the same schedule has been changed. For testing that, you need to have two or more policies that have the same time por execution. No test added for this, is only a copy change [[code](https://github.com/elastic/kibana/pull/199622/files#diff-e8e12f0dfdc97e4e064f8a07965312c8c91ca66578bdcaf5ee807e879cebcb6eR207)] Screenshot 2024-11-27 at 15 17 25 * A new callout has been added to warn that the SLM status is different from “running”. SLM status is "running" by default, but it could happen that the user stop it for any reason and then does not restart it. This causes policies not to run when they are scheduled. To known the SLM status a new api call has been introduced (`GET _slm/status`). * I've created a new doc link to https://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-start.html * I've added new tests for the new api call. Screenshot 2024-11-27 at 15 59 56 ## Testing You will need to have at least one policy to test this. For that, you can run Elastic using the following: ``` yarn es snapshot --license=trial -E path.repo=/tmp/es-backups ``` From the console, you can add a repository (you can also do it from the UI): ``` PUT /_snapshot/my_backup { "type": "fs", "settings": { "location": "/tmp/es-backups", "chunk_size": "10mb" } } ```` And for creating a policy you can run this: ``` PUT _slm/policy/nightly-snapshots { "schedule": "0 30 1 * * ?", "name": "", "repository": "my_backup1", "retention": { "expire_after": "30d", "min_count": 5, "max_count": 50 } } ``` SLM status should be started by default (unless you have stopped it). For starting it you can use `POST /_slm/start` and for stop it `POST /_slm/stop` ## Demo https://github.com/user-attachments/assets/b83cd3ba-4821-4295-87f2-ecf427ec46e0 --------- Co-authored-by: shainaraskas <58563081+shainaraskas@users.noreply.github.com> --- .../shared/kbn-doc-links/src/get_doc_links.ts | 1 + x-pack/plugins/snapshot_restore/README.md | 10 +++- .../__jest__/client_integration/home.test.ts | 11 ++-- .../public/application/constants/index.ts | 7 ++- .../application/lib/snapshot_list_params.ts | 3 +- .../sections/home/policy_list/policy_list.tsx | 53 +++++++++++++++-- .../components/snapshot_table.tsx | 10 ++++ .../snapshot_details/tabs/snapshot_state.tsx | 58 +++++++------------ .../snapshot_details/tabs/tab_summary.tsx | 2 +- .../services/http/policy_requests.ts | 7 +++ .../server/routes/api/policy.test.ts | 23 ++++++++ .../server/routes/api/policy.ts | 16 +++++ .../translations/translations/fr-FR.json | 2 - .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - .../snapshot_restore/lib/elasticsearch.ts | 5 ++ .../management/snapshot_restore/policies.ts | 26 ++++++++- 17 files changed, 179 insertions(+), 59 deletions(-) diff --git a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts index d82caffce0343..271d34d800471 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts @@ -793,6 +793,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D restoreSnapshot: `${ELASTICSEARCH_DOCS}snapshots-restore-snapshot.html`, restoreSnapshotApi: `${ELASTICSEARCH_DOCS}restore-snapshot-api.html#restore-snapshot-api-request-body`, searchableSnapshotSharedCache: `${ELASTICSEARCH_DOCS}searchable-snapshots.html#searchable-snapshots-shared-cache`, + slmStart: `${ELASTICSEARCH_DOCS}slm-api-start.html`, }, ingest: { append: `${ELASTICSEARCH_DOCS}append-processor.html`, diff --git a/x-pack/plugins/snapshot_restore/README.md b/x-pack/plugins/snapshot_restore/README.md index b6b75631b07d9..48cd9d51f29a8 100644 --- a/x-pack/plugins/snapshot_restore/README.md +++ b/x-pack/plugins/snapshot_restore/README.md @@ -74,4 +74,12 @@ To run ES with plugins: 1. Run `yarn es snapshot` from the Kibana directory like normal, then exit out of process. 2. `cd .es/8.0.0` 3. `bin/elasticsearch-plugin install https://snapshots.elastic.co/downloads/elasticsearch-plugins/repository-hdfs/repository-hdfs-8.0.0-SNAPSHOT.zip` -4. Run `bin/elasticsearch` from the `.es/8.0.0` directory. Otherwise, starting ES with `yarn es snapshot` would overwrite the plugins you just installed. \ No newline at end of file +4. Run `bin/elasticsearch` from the `.es/8.0.0` directory. Otherwise, starting ES with `yarn es snapshot` would overwrite the plugins you just installed. + + +### SLM status +Snapshot lifecycle management (SLM) status is "RUNNING" by default, but it can be stoped manually (for mantenaince purpouses, for instance). When this happens, no schedule snapshots will be taken. Docs: https://www.elastic.co/guide/en/elasticsearch/reference/master/snapshot-lifecycle-management-api.html + +* To check the SLM status you can run `GET _slm/status` +* To start SLM `POST /_slm/start` +* To stop SLM `POST /_slm/stop` diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts index 222cc4e89c26e..a25dcf2a61341 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts @@ -512,6 +512,7 @@ describe('', () => { expect(row).toEqual([ '', // Checkbox snapshot.snapshot, // Snapshot + 'Complete', // The displayed message when stats is success REPOSITORY_NAME, // Repository snapshot.indices.length.toString(), // Indices snapshot.shards.total.toString(), // Shards @@ -738,7 +739,7 @@ describe('', () => { expect(find('snapshotDetail.version.value').text()).toBe(version); expect(find('snapshotDetail.uuid.value').text()).toBe(uuid); - expect(find('snapshotDetail.state.value').text()).toBe('Snapshot complete'); + expect(find('snapshotDetail.state.value').text()).toBe('Complete'); expect(find('snapshotDetail.includeGlobalState.value').text()).toEqual('Yes'); expect( find('snapshotDetail.snapshotFeatureStatesSummary.featureStatesList').text() @@ -788,10 +789,10 @@ describe('', () => { }; const mapStateToMessage = { - [SNAPSHOT_STATE.IN_PROGRESS]: 'Taking snapshot…', - [SNAPSHOT_STATE.FAILED]: 'Snapshot failed', - [SNAPSHOT_STATE.PARTIAL]: 'Partial failure ', - [SNAPSHOT_STATE.INCOMPATIBLE]: 'Incompatible version ', + [SNAPSHOT_STATE.IN_PROGRESS]: 'In progress', + [SNAPSHOT_STATE.FAILED]: 'Failed', + [SNAPSHOT_STATE.PARTIAL]: 'Partial', + [SNAPSHOT_STATE.SUCCESS]: 'Complete', }; // Call sequentially each state and verify that the message is ok diff --git a/x-pack/plugins/snapshot_restore/public/application/constants/index.ts b/x-pack/plugins/snapshot_restore/public/application/constants/index.ts index f319f1c995d0d..7ca0e3181aea0 100644 --- a/x-pack/plugins/snapshot_restore/public/application/constants/index.ts +++ b/x-pack/plugins/snapshot_restore/public/application/constants/index.ts @@ -17,7 +17,12 @@ export enum SNAPSHOT_STATE { SUCCESS = 'SUCCESS', FAILED = 'FAILED', PARTIAL = 'PARTIAL', - INCOMPATIBLE = 'INCOMPATIBLE', +} + +export enum SLM_STATE { + RUNNING = 'RUNNING', + STOPPING = 'STOPPING', + STOPPED = 'STOPPED', } const INDEX_SETTING_SUGGESTIONS: string[] = [ diff --git a/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts b/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts index 352eb658dd023..8c29a910c2d0c 100644 --- a/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts +++ b/x-pack/plugins/snapshot_restore/public/application/lib/snapshot_list_params.ts @@ -15,7 +15,8 @@ export type SortField = | 'startTimeInMillis' | 'durationInMillis' | 'shards.total' - | 'shards.failed'; + | 'shards.failed' + | 'state'; export type SortDirection = Direction; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx index aa7a35bb2c0b2..6a74b92c4ac57 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx @@ -8,10 +8,11 @@ import React, { Fragment, useEffect } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { RouteComponentProps } from 'react-router-dom'; -import { EuiButton, EuiCallOut, EuiSpacer, EuiPageTemplate } from '@elastic/eui'; +import { EuiButton, EuiCallOut, EuiSpacer, EuiPageTemplate, EuiLink } from '@elastic/eui'; import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; +import { i18n } from '@kbn/i18n'; import { PageLoading, PageError, @@ -23,11 +24,15 @@ import { import { SlmPolicy } from '../../../../../common/types'; import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common'; -import { BASE_PATH, UIM_POLICY_LIST_LOAD } from '../../../constants'; +import { BASE_PATH, SLM_STATE, UIM_POLICY_LIST_LOAD } from '../../../constants'; import { useDecodedParams } from '../../../lib'; -import { useLoadPolicies, useLoadRetentionSettings } from '../../../services/http'; +import { + useLoadPolicies, + useLoadRetentionSettings, + useLoadSlmStatus, +} from '../../../services/http'; import { linkToAddPolicy, linkToPolicy } from '../../../services/navigation'; -import { useAppContext, useServices } from '../../../app_context'; +import { useAppContext, useCore, useServices } from '../../../app_context'; import { PolicyDetails } from './policy_details'; import { PolicyTable } from './policy_table'; @@ -52,6 +57,7 @@ export const PolicyList: React.FunctionComponent { return linkToPolicy(newPolicyName); }; @@ -157,9 +165,44 @@ export const PolicyList: React.FunctionComponent policy.schedule); const hasDuplicateSchedules = policySchedules.length > new Set(policySchedules).size; const hasRetention = Boolean(policies.find((policy: SlmPolicy) => policy.retention)); + const isSlmRunning = slmStatus?.operation_mode === SLM_STATE.RUNNING; content = (
+ {!isSlmRunning ? ( + + + } + color="warning" + iconType="warning" + > + + {i18n.translate('xpack.snapshotRestore.slmDocLink', { + defaultMessage: 'using the API.', + })} + + ), + }} + /> + + + + ) : null} + {hasDuplicateSchedules ? ( diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_table.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_table.tsx index 69f9d1b2f9ffb..e4907709f7e1e 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_table.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/components/snapshot_table.tsx @@ -29,6 +29,7 @@ import { import { SnapshotListParams, SortDirection, SortField } from '../../../../lib'; import { DataPlaceholder, FormattedDateTime, SnapshotDeleteProvider } from '../../../../components'; import { SnapshotSearchBar } from './snapshot_search_bar'; +import { SnapshotState } from '../snapshot_details/tabs/snapshot_state'; const getLastSuccessfulManagedSnapshot = ( snapshots: SnapshotDetails[] @@ -93,6 +94,15 @@ export const SnapshotTable: React.FunctionComponent = (props: Props) => { ), }, + { + field: 'state', + name: i18n.translate('xpack.snapshotRestore.snapshotList.table.stateColumnTitle', { + defaultMessage: 'State', + }), + truncateText: false, + sortable: false, + render: (state: string) => , + }, { field: 'repository', name: i18n.translate('xpack.snapshotRestore.snapshotList.table.repositoryColumnTitle', { diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/snapshot_state.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/snapshot_state.tsx index e4629f1160f38..4b3a0215d7ec6 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/snapshot_state.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/snapshot_state.tsx @@ -5,57 +5,49 @@ * 2.0. */ -import React, { Fragment } from 'react'; +import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiIconTip, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiFlexGroup, EuiHealth, EuiIcon, EuiToolTip } from '@elastic/eui'; import { SNAPSHOT_STATE } from '../../../../../constants'; import { useServices } from '../../../../../app_context'; interface Props { state: any; + displayTooltipIcon: boolean; } -export const SnapshotState: React.FC = ({ state }) => { +export const SnapshotState: React.FC = ({ state, displayTooltipIcon }) => { const { i18n } = useServices(); const stateMap: any = { [SNAPSHOT_STATE.IN_PROGRESS]: { - icon: , + color: 'primary', label: i18n.translate('xpack.snapshotRestore.snapshotState.inProgressLabel', { - defaultMessage: 'Taking snapshot…', + defaultMessage: 'In progress', }), }, [SNAPSHOT_STATE.SUCCESS]: { - icon: , + color: 'success', label: i18n.translate('xpack.snapshotRestore.snapshotState.completeLabel', { - defaultMessage: 'Snapshot complete', + defaultMessage: 'Complete', }), }, [SNAPSHOT_STATE.FAILED]: { - icon: , + color: 'danger', label: i18n.translate('xpack.snapshotRestore.snapshotState.failedLabel', { - defaultMessage: 'Snapshot failed', + defaultMessage: 'Failed', }), }, [SNAPSHOT_STATE.PARTIAL]: { - icon: , + color: 'warning', label: i18n.translate('xpack.snapshotRestore.snapshotState.partialLabel', { - defaultMessage: 'Partial failure', + defaultMessage: 'Partial', }), tip: i18n.translate('xpack.snapshotRestore.snapshotState.partialTipDescription', { defaultMessage: `Global cluster state was stored, but at least one shard wasn't stored successfully. See the 'Failed indices' tab.`, }), }, - [SNAPSHOT_STATE.INCOMPATIBLE]: { - icon: , - label: i18n.translate('xpack.snapshotRestore.snapshotState.incompatibleLabel', { - defaultMessage: 'Incompatible version', - }), - tip: i18n.translate('xpack.snapshotRestore.snapshotState.incompatibleTipDescription', { - defaultMessage: `Snapshot was created with a version of Elasticsearch incompatible with the cluster's version.`, - }), - }, }; if (!stateMap[state]) { @@ -63,26 +55,16 @@ export const SnapshotState: React.FC = ({ state }) => { return state; } - const { icon, label, tip } = stateMap[state]; + const { color, label, tip } = stateMap[state]; - const iconTip = tip && ( - - {' '} - - - ); + const iconTip = displayTooltipIcon && tip && ; return ( - - {icon} - - - {/* Escape flex layout created by EuiFlexItem. */} -
- {label} - {iconTip} -
-
-
+ + + {label} + {iconTip} + + ); }; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/tab_summary.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/tab_summary.tsx index 00ea3fa27109b..cf1f9fd83a3d8 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/tab_summary.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_details/tabs/tab_summary.tsx @@ -94,7 +94,7 @@ export const TabSummary: React.FC = ({ snapshotDetails }) => { - + diff --git a/x-pack/plugins/snapshot_restore/public/application/services/http/policy_requests.ts b/x-pack/plugins/snapshot_restore/public/application/services/http/policy_requests.ts index f4e8abc34e993..945ceff724aef 100644 --- a/x-pack/plugins/snapshot_restore/public/application/services/http/policy_requests.ts +++ b/x-pack/plugins/snapshot_restore/public/application/services/http/policy_requests.ts @@ -131,3 +131,10 @@ export const executeRetention = async () => { uiMetricService.trackUiMetric(UIM_RETENTION_EXECUTE); return result; }; + +export const useLoadSlmStatus = () => { + return useRequest({ + path: `${API_BASE_PATH}policies/slm_status`, + method: 'get', + }); +}; diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/policy.test.ts b/x-pack/plugins/snapshot_restore/server/routes/api/policy.test.ts index 3d4f0f5505b30..873d270a206ca 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/policy.test.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/policy.test.ts @@ -9,6 +9,7 @@ import { addBasePath } from '../helpers'; import { registerPolicyRoutes } from './policy'; import { RouterMock, routeDependencies, RequestMock } from '../../test/helpers'; import { ResolveIndexResponseFromES } from '../../types'; +import { SlmGetStatusResponse } from '@elastic/elasticsearch/lib/api/types'; describe('[Snapshot and Restore API Routes] Policy', () => { const mockEsPolicy = { @@ -56,6 +57,7 @@ describe('[Snapshot and Restore API Routes] Policy', () => { const executeLifecycleFn = router.getMockApiFn('slm.executeLifecycle'); const deleteLifecycleFn = router.getMockApiFn('slm.deleteLifecycle'); const resolveIndicesFn = router.getMockApiFn('indices.resolveIndex'); + const getStatusFn = router.getMockApiFn('slm.getStatus'); beforeAll(() => { registerPolicyRoutes({ @@ -437,4 +439,25 @@ describe('[Snapshot and Restore API Routes] Policy', () => { await expect(router.runRequest(mockRequest)).rejects.toThrowError(); }); }); + + describe('getSlmStatusHandler', () => { + const mockRequest: RequestMock = { + method: 'get', + path: addBasePath('policies/slm_status'), + }; + + it('should return successful ES response', async () => { + const mockEsResponse: SlmGetStatusResponse = { operation_mode: 'RUNNING' }; + getStatusFn.mockResolvedValue(mockEsResponse); + + const expectedResponse = { ...mockEsResponse }; + await expect(router.runRequest(mockRequest)).resolves.toEqual({ body: expectedResponse }); + }); + + it('should throw if ES error', async () => { + getStatusFn.mockRejectedValue(new Error()); + + await expect(router.runRequest(mockRequest)).rejects.toThrowError(); + }); + }); }); diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/policy.ts b/x-pack/plugins/snapshot_restore/server/routes/api/policy.ts index 51bdf96361a24..9f948d0d2524a 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/policy.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/policy.ts @@ -304,4 +304,20 @@ export function registerPolicyRoutes({ return res.ok({ body: response }); }) ); + + // Get snapshot lifecycle management status + router.get( + { path: addBasePath('policies/slm_status'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const { client: clusterClient } = (await ctx.core).elasticsearch; + + try { + const response = await clusterClient.asCurrentUser.slm.getStatus(); + + return res.ok({ body: response }); + } catch (e) { + return handleEsError({ error: e, response: res }); + } + }) + ); } diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 9883c1b53fde6..397c73a512c10 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -44408,8 +44408,6 @@ "xpack.snapshotRestore.snapshots.breadcrumbTitle": "Snapshots", "xpack.snapshotRestore.snapshotState.completeLabel": "Snapshot terminé", "xpack.snapshotRestore.snapshotState.failedLabel": "Snapshot échoué", - "xpack.snapshotRestore.snapshotState.incompatibleLabel": "Version incompatible", - "xpack.snapshotRestore.snapshotState.incompatibleTipDescription": "Le snapshot a été créé avec une version d'Elasticsearch incompatible avec la version du cluster.", "xpack.snapshotRestore.snapshotState.inProgressLabel": "Prise de snapshot…", "xpack.snapshotRestore.snapshotState.partialLabel": "Échec partiel", "xpack.snapshotRestore.snapshotState.partialTipDescription": "L'état du cluster global a été stocké, mais au moins une partition n'a pas été stockée correctement. Consultez l'onglet \"Index échoués\".", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e0214b2fa0834..37f24051c6001 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -44258,8 +44258,6 @@ "xpack.snapshotRestore.snapshots.breadcrumbTitle": "スナップショット", "xpack.snapshotRestore.snapshotState.completeLabel": "スナップショット完了", "xpack.snapshotRestore.snapshotState.failedLabel": "スナップショット失敗", - "xpack.snapshotRestore.snapshotState.incompatibleLabel": "互換性のないバージョン", - "xpack.snapshotRestore.snapshotState.incompatibleTipDescription": "このスナップショットはクラスターのバージョンと互換性のないバージョンの Elasticsearch で作成されました。", "xpack.snapshotRestore.snapshotState.inProgressLabel": "スナップショットを撮影中…", "xpack.snapshotRestore.snapshotState.partialLabel": "一部失敗", "xpack.snapshotRestore.snapshotState.partialTipDescription": "グローバルクラスターステータスが保存されましたが、1 つまたは複数のシャードの保存に失敗しました。「失敗したインシデント」タブをご覧ください。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 19868ab9d392e..67f0cee7591ff 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -43615,8 +43615,6 @@ "xpack.snapshotRestore.snapshots.breadcrumbTitle": "快照", "xpack.snapshotRestore.snapshotState.completeLabel": "快照完成", "xpack.snapshotRestore.snapshotState.failedLabel": "快照失败", - "xpack.snapshotRestore.snapshotState.incompatibleLabel": "不兼容版本", - "xpack.snapshotRestore.snapshotState.incompatibleTipDescription": "创建快照所用的 Elasticsearch 版本与集群的版本不兼容。", "xpack.snapshotRestore.snapshotState.inProgressLabel": "正在拍取快照……", "xpack.snapshotRestore.snapshotState.partialLabel": "部分失败", "xpack.snapshotRestore.snapshotState.partialTipDescription": "全局集群状态已存储,但至少一个分片未成功存储。请参阅'失败的索引'选项卡。", diff --git a/x-pack/test/api_integration/apis/management/snapshot_restore/lib/elasticsearch.ts b/x-pack/test/api_integration/apis/management/snapshot_restore/lib/elasticsearch.ts index b5b0bc053f3de..f1fa340f9ae2e 100644 --- a/x-pack/test/api_integration/apis/management/snapshot_restore/lib/elasticsearch.ts +++ b/x-pack/test/api_integration/apis/management/snapshot_restore/lib/elasticsearch.ts @@ -101,6 +101,10 @@ export const registerEsHelpers = (getService: FtrProviderContext['getService']) }); }; + const startSlm = () => { + return es.slm.start(); + }; + return { createRepository, createPolicy, @@ -110,5 +114,6 @@ export const registerEsHelpers = (getService: FtrProviderContext['getService']) executePolicy, createSnapshot, deleteSnapshots, + startSlm, }; }; diff --git a/x-pack/test/api_integration/apis/management/snapshot_restore/policies.ts b/x-pack/test/api_integration/apis/management/snapshot_restore/policies.ts index e0734680887d2..2e771616f9d1b 100644 --- a/x-pack/test/api_integration/apis/management/snapshot_restore/policies.ts +++ b/x-pack/test/api_integration/apis/management/snapshot_restore/policies.ts @@ -16,7 +16,7 @@ const REPO_NAME = 'test_repo'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const { createRepository, createPolicy, deletePolicy, cleanupPolicies, getPolicy } = + const { createRepository, createPolicy, deletePolicy, cleanupPolicies, getPolicy, startSlm } = registerEsHelpers(getService); describe('SLM policies', function () { @@ -229,5 +229,29 @@ export default function ({ getService }: FtrProviderContext) { }); }); }); + + describe('Show info', () => { + before(async () => { + // Make sure SLM is running + try { + await startSlm(); + } catch (err) { + // eslint-disable-next-line no-console + console.log('[Setup error] Error starting Slm'); + throw err; + } + }); + + it('should get slm status', async () => { + const { body } = await supertest + .get(`${API_BASE_PATH}/policies/slm_status`) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(body).to.eql({ + operation_mode: 'RUNNING', + }); + }); + }); }); }