Skip to content

Commit

Permalink
[8.x] Snapshots: show slm and status (elastic#199622) (elastic#203372)
Browse files Browse the repository at this point in the history
# Backport

This will backport the following commits from `main` to `8.x`:
- [Snapshots: show slm and status
(elastic#199622)](elastic#199622)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Sonia Sanz
Vivas","email":"sonia.sanzvivas@elastic.co"},"sourceCommit":{"committedDate":"2024-12-09T08:57:41Z","message":"Snapshots:
show slm and status (elastic#199622)\n\nCloses
[elastic#148241](https://github.com/elastic/kibana/issues/148241)\r\n\r\n##
Summary\r\n\r\nThis PR introduces a few changes in the snapshot and
restore plugin.\r\n\r\n#### Snapshots tab\r\n* The state column has been
aded to the table\r\n* In the detail flyout, it has been changed the way
in which the status\r\nis displayed (icon and text).\r\n* No new test
needed since this info was already there. The related\r\ntests have been
updated.\r\n\r\n<table>\r\n <tr>\r\n <td style=\"padding-right:
10px;\">\r\n\r\n\r\n<img alt=\"Screenshot 2024-11-27 at 15 17
03\"\r\nsrc=\"https://github.com/user-attachments/assets/92b5c5cf-d90b-454c-9cf7-2eb101562c5f\">\r\n\r\n\r\n
</td>\r\n <td>\r\n<img alt=\"Screenshot 2024-11-27 at 15 54
32\"\r\nsrc=\"https://github.com/user-attachments/assets/62395bad-4c70-44bb-84b3-c8a30ae9278a\">\r\n\r\n
\r\n\r\n </td>\r\n </tr>\r\n</table>\r\n\r\n\r\n#### Policies tab\r\n*
The copy of the callout for warning that two or more policies have
the\r\nsame schedule has been changed. For testing that, you need to
have two\r\nor more policies that have the same time por execution. No
test added\r\nfor this, is only a copy
change\r\n[[code](https://github.com/elastic/kibana/pull/199622/files#diff-e8e12f0dfdc97e4e064f8a07965312c8c91ca66578bdcaf5ee807e879cebcb6eR207)]\r\n<img
width=\"1249\" alt=\"Screenshot 2024-11-27 at 15 17
25\"\r\nsrc=\"https://github.com/user-attachments/assets/5417910f-573a-4c22-a5e2-44ec2ce256b3\">\r\n\r\n\r\n*
A new callout has been added to warn that the SLM status is
different\r\nfrom “running”. SLM status is \"running\" by default, but
it could happen\r\nthat the user stop it for any reason and then does
not restart it. This\r\ncauses policies not to run when they are
scheduled. To known the SLM\r\nstatus a new api call has been introduced
(`GET _slm/status`).\r\n* I've created a new doc link
to\r\nhttps://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-start.html\r\n
* I've added new tests for the new api call.\r\n \r\n<img width=\"1246\"
alt=\"Screenshot 2024-11-27 at 15 59
56\"\r\nsrc=\"https://github.com/user-attachments/assets/cd5ae491-16a4-4a68-a223-f44ce398ac2f\">\r\n\r\n\r\n
\r\n\r\n## Testing\r\nYou will need to have at least one policy to test
this. For that, you\r\ncan run Elastic using the
following:\r\n```\r\nyarn es snapshot --license=trial -E
path.repo=/tmp/es-backups\r\n```\r\n\r\nFrom the console, you can add a
repository (you can also do it from the\r\nUI):\r\n```\r\nPUT
/_snapshot/my_backup\r\n{\r\n \"type\": \"fs\",\r\n \"settings\": {\r\n
\"location\": \"/tmp/es-backups\",\r\n \"chunk_size\": \"10mb\"\r\n
}\r\n}\r\n````\r\n\r\nAnd for creating a policy you can run
this:\r\n```\r\nPUT _slm/policy/nightly-snapshots\r\n{\r\n \"schedule\":
\"0 30 1 * * ?\", \r\n \"name\": \"<nightly-snap-{now/d}>\", \r\n
\"repository\": \"my_backup1\",\r\n \"retention\": { \r\n
\"expire_after\": \"30d\",\r\n \"min_count\": 5,\r\n \"max_count\":
50\r\n }\r\n}\r\n```\r\n\r\nSLM status should be started by default
(unless you have stopped it).\r\nFor starting it you can use `POST
/_slm/start` and for stop it `POST\r\n/_slm/stop`\r\n\r\n##
Demo\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/b83cd3ba-4821-4295-87f2-ecf427ec46e0\r\n\r\n---------\r\n\r\nCo-authored-by:
shainaraskas
<58563081+shainaraskas@users.noreply.github.com>","sha":"6d3b5c264b771a0fec3eb29112286f032496cf5d","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Kibana
Management","release_note:skip","Feature:Snapshot and
Restore","v9.0.0","backport:prev-minor"],"title":"Snapshots: show slm
and
status","number":199622,"url":"https://github.com/elastic/kibana/pull/199622","mergeCommit":{"message":"Snapshots:
show slm and status (elastic#199622)\n\nCloses
[elastic#148241](https://github.com/elastic/kibana/issues/148241)\r\n\r\n##
Summary\r\n\r\nThis PR introduces a few changes in the snapshot and
restore plugin.\r\n\r\n#### Snapshots tab\r\n* The state column has been
aded to the table\r\n* In the detail flyout, it has been changed the way
in which the status\r\nis displayed (icon and text).\r\n* No new test
needed since this info was already there. The related\r\ntests have been
updated.\r\n\r\n<table>\r\n <tr>\r\n <td style=\"padding-right:
10px;\">\r\n\r\n\r\n<img alt=\"Screenshot 2024-11-27 at 15 17
03\"\r\nsrc=\"https://github.com/user-attachments/assets/92b5c5cf-d90b-454c-9cf7-2eb101562c5f\">\r\n\r\n\r\n
</td>\r\n <td>\r\n<img alt=\"Screenshot 2024-11-27 at 15 54
32\"\r\nsrc=\"https://github.com/user-attachments/assets/62395bad-4c70-44bb-84b3-c8a30ae9278a\">\r\n\r\n
\r\n\r\n </td>\r\n </tr>\r\n</table>\r\n\r\n\r\n#### Policies tab\r\n*
The copy of the callout for warning that two or more policies have
the\r\nsame schedule has been changed. For testing that, you need to
have two\r\nor more policies that have the same time por execution. No
test added\r\nfor this, is only a copy
change\r\n[[code](https://github.com/elastic/kibana/pull/199622/files#diff-e8e12f0dfdc97e4e064f8a07965312c8c91ca66578bdcaf5ee807e879cebcb6eR207)]\r\n<img
width=\"1249\" alt=\"Screenshot 2024-11-27 at 15 17
25\"\r\nsrc=\"https://github.com/user-attachments/assets/5417910f-573a-4c22-a5e2-44ec2ce256b3\">\r\n\r\n\r\n*
A new callout has been added to warn that the SLM status is
different\r\nfrom “running”. SLM status is \"running\" by default, but
it could happen\r\nthat the user stop it for any reason and then does
not restart it. This\r\ncauses policies not to run when they are
scheduled. To known the SLM\r\nstatus a new api call has been introduced
(`GET _slm/status`).\r\n* I've created a new doc link
to\r\nhttps://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-start.html\r\n
* I've added new tests for the new api call.\r\n \r\n<img width=\"1246\"
alt=\"Screenshot 2024-11-27 at 15 59
56\"\r\nsrc=\"https://github.com/user-attachments/assets/cd5ae491-16a4-4a68-a223-f44ce398ac2f\">\r\n\r\n\r\n
\r\n\r\n## Testing\r\nYou will need to have at least one policy to test
this. For that, you\r\ncan run Elastic using the
following:\r\n```\r\nyarn es snapshot --license=trial -E
path.repo=/tmp/es-backups\r\n```\r\n\r\nFrom the console, you can add a
repository (you can also do it from the\r\nUI):\r\n```\r\nPUT
/_snapshot/my_backup\r\n{\r\n \"type\": \"fs\",\r\n \"settings\": {\r\n
\"location\": \"/tmp/es-backups\",\r\n \"chunk_size\": \"10mb\"\r\n
}\r\n}\r\n````\r\n\r\nAnd for creating a policy you can run
this:\r\n```\r\nPUT _slm/policy/nightly-snapshots\r\n{\r\n \"schedule\":
\"0 30 1 * * ?\", \r\n \"name\": \"<nightly-snap-{now/d}>\", \r\n
\"repository\": \"my_backup1\",\r\n \"retention\": { \r\n
\"expire_after\": \"30d\",\r\n \"min_count\": 5,\r\n \"max_count\":
50\r\n }\r\n}\r\n```\r\n\r\nSLM status should be started by default
(unless you have stopped it).\r\nFor starting it you can use `POST
/_slm/start` and for stop it `POST\r\n/_slm/stop`\r\n\r\n##
Demo\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/b83cd3ba-4821-4295-87f2-ecf427ec46e0\r\n\r\n---------\r\n\r\nCo-authored-by:
shainaraskas
<58563081+shainaraskas@users.noreply.github.com>","sha":"6d3b5c264b771a0fec3eb29112286f032496cf5d"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/199622","number":199622,"mergeCommit":{"message":"Snapshots:
show slm and status (elastic#199622)\n\nCloses
[elastic#148241](https://github.com/elastic/kibana/issues/148241)\r\n\r\n##
Summary\r\n\r\nThis PR introduces a few changes in the snapshot and
restore plugin.\r\n\r\n#### Snapshots tab\r\n* The state column has been
aded to the table\r\n* In the detail flyout, it has been changed the way
in which the status\r\nis displayed (icon and text).\r\n* No new test
needed since this info was already there. The related\r\ntests have been
updated.\r\n\r\n<table>\r\n <tr>\r\n <td style=\"padding-right:
10px;\">\r\n\r\n\r\n<img alt=\"Screenshot 2024-11-27 at 15 17
03\"\r\nsrc=\"https://github.com/user-attachments/assets/92b5c5cf-d90b-454c-9cf7-2eb101562c5f\">\r\n\r\n\r\n
</td>\r\n <td>\r\n<img alt=\"Screenshot 2024-11-27 at 15 54
32\"\r\nsrc=\"https://github.com/user-attachments/assets/62395bad-4c70-44bb-84b3-c8a30ae9278a\">\r\n\r\n
\r\n\r\n </td>\r\n </tr>\r\n</table>\r\n\r\n\r\n#### Policies tab\r\n*
The copy of the callout for warning that two or more policies have
the\r\nsame schedule has been changed. For testing that, you need to
have two\r\nor more policies that have the same time por execution. No
test added\r\nfor this, is only a copy
change\r\n[[code](https://github.com/elastic/kibana/pull/199622/files#diff-e8e12f0dfdc97e4e064f8a07965312c8c91ca66578bdcaf5ee807e879cebcb6eR207)]\r\n<img
width=\"1249\" alt=\"Screenshot 2024-11-27 at 15 17
25\"\r\nsrc=\"https://github.com/user-attachments/assets/5417910f-573a-4c22-a5e2-44ec2ce256b3\">\r\n\r\n\r\n*
A new callout has been added to warn that the SLM status is
different\r\nfrom “running”. SLM status is \"running\" by default, but
it could happen\r\nthat the user stop it for any reason and then does
not restart it. This\r\ncauses policies not to run when they are
scheduled. To known the SLM\r\nstatus a new api call has been introduced
(`GET _slm/status`).\r\n* I've created a new doc link
to\r\nhttps://www.elastic.co/guide/en/elasticsearch/reference/current/slm-api-start.html\r\n
* I've added new tests for the new api call.\r\n \r\n<img width=\"1246\"
alt=\"Screenshot 2024-11-27 at 15 59
56\"\r\nsrc=\"https://github.com/user-attachments/assets/cd5ae491-16a4-4a68-a223-f44ce398ac2f\">\r\n\r\n\r\n
\r\n\r\n## Testing\r\nYou will need to have at least one policy to test
this. For that, you\r\ncan run Elastic using the
following:\r\n```\r\nyarn es snapshot --license=trial -E
path.repo=/tmp/es-backups\r\n```\r\n\r\nFrom the console, you can add a
repository (you can also do it from the\r\nUI):\r\n```\r\nPUT
/_snapshot/my_backup\r\n{\r\n \"type\": \"fs\",\r\n \"settings\": {\r\n
\"location\": \"/tmp/es-backups\",\r\n \"chunk_size\": \"10mb\"\r\n
}\r\n}\r\n````\r\n\r\nAnd for creating a policy you can run
this:\r\n```\r\nPUT _slm/policy/nightly-snapshots\r\n{\r\n \"schedule\":
\"0 30 1 * * ?\", \r\n \"name\": \"<nightly-snap-{now/d}>\", \r\n
\"repository\": \"my_backup1\",\r\n \"retention\": { \r\n
\"expire_after\": \"30d\",\r\n \"min_count\": 5,\r\n \"max_count\":
50\r\n }\r\n}\r\n```\r\n\r\nSLM status should be started by default
(unless you have stopped it).\r\nFor starting it you can use `POST
/_slm/start` and for stop it `POST\r\n/_slm/stop`\r\n\r\n##
Demo\r\n\r\n\r\n\r\nhttps://github.com/user-attachments/assets/b83cd3ba-4821-4295-87f2-ecf427ec46e0\r\n\r\n---------\r\n\r\nCo-authored-by:
shainaraskas
<58563081+shainaraskas@users.noreply.github.com>","sha":"6d3b5c264b771a0fec3eb29112286f032496cf5d"}}]}]
BACKPORT-->

Co-authored-by: Sonia Sanz Vivas <sonia.sanzvivas@elastic.co>
  • Loading branch information
kibanamachine and SoniaSanzV authored Dec 9, 2024
1 parent d3229a8 commit 4d8e8d9
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 59 deletions.
1 change: 1 addition & 0 deletions packages/kbn-doc-links/src/get_doc_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,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`,
Expand Down
10 changes: 9 additions & 1 deletion x-pack/plugins/snapshot_restore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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`
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ describe('<SnapshotRestoreHome />', () => {
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
Expand Down Expand Up @@ -738,7 +739,7 @@ describe('<SnapshotRestoreHome />', () => {

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()
Expand Down Expand Up @@ -788,10 +789,10 @@ describe('<SnapshotRestoreHome />', () => {
};

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export type SortField =
| 'startTimeInMillis'
| 'durationInMillis'
| 'shards.total'
| 'shards.failed';
| 'shards.failed'
| 'state';

export type SortDirection = Direction;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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';
Expand All @@ -52,6 +57,7 @@ export const PolicyList: React.FunctionComponent<RouteComponentProps<MatchParams

const { uiMetricService } = useServices();
const { core } = useAppContext();
const { docLinks } = useCore();

// Load retention cluster settings
const {
Expand All @@ -61,6 +67,8 @@ export const PolicyList: React.FunctionComponent<RouteComponentProps<MatchParams
resendRequest: reloadRetentionSettings,
} = useLoadRetentionSettings();

const { data: slmStatus } = useLoadSlmStatus();

const openPolicyDetailsUrl = (newPolicyName: SlmPolicy['name']): string => {
return linkToPolicy(newPolicyName);
};
Expand Down Expand Up @@ -157,9 +165,44 @@ export const PolicyList: React.FunctionComponent<RouteComponentProps<MatchParams
const policySchedules = policies.map((policy: SlmPolicy) => 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 = (
<section data-test-subj="policyList">
{!isSlmRunning ? (
<Fragment>
<EuiCallOut
title={
<FormattedMessage
id="xpack.snapshotRestore.slmWarningTitle"
defaultMessage="Snapshot lifecycle management (SLM) is not running"
/>
}
color="warning"
iconType="warning"
>
<FormattedMessage
id="xpack.snapshotRestore.slmWarningDescription"
defaultMessage="Policies are not being executed. You must restart SLM {slmDocLink}"
values={{
slmDocLink: (
<EuiLink
href={docLinks.links.snapshotRestore.slmStart}
external={true}
target="_blank"
>
{i18n.translate('xpack.snapshotRestore.slmDocLink', {
defaultMessage: 'using the API.',
})}
</EuiLink>
),
}}
/>
</EuiCallOut>
<EuiSpacer />
</Fragment>
) : null}

{hasDuplicateSchedules ? (
<Fragment>
<EuiCallOut
Expand All @@ -174,7 +217,7 @@ export const PolicyList: React.FunctionComponent<RouteComponentProps<MatchParams
>
<FormattedMessage
id="xpack.snapshotRestore.policyScheduleWarningDescription"
defaultMessage="Only one snapshot can be taken at a time. To avoid snapshot failures, edit or delete the policies."
defaultMessage="Only one snapshot can be taken at a time. To avoid snapshot failures, edit the policies to run on different schedules, or delete redundant policies."
/>
</EuiCallOut>
<EuiSpacer />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down Expand Up @@ -93,6 +94,15 @@ export const SnapshotTable: React.FunctionComponent<Props> = (props: Props) => {
</EuiLink>
),
},
{
field: 'state',
name: i18n.translate('xpack.snapshotRestore.snapshotList.table.stateColumnTitle', {
defaultMessage: 'State',
}),
truncateText: false,
sortable: false,
render: (state: string) => <SnapshotState state={state} displayTooltipIcon={false} />,
},
{
field: 'repository',
name: i18n.translate('xpack.snapshotRestore.snapshotList.table.repositoryColumnTitle', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,84 +5,66 @@
* 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<Props> = ({ state }) => {
export const SnapshotState: React.FC<Props> = ({ state, displayTooltipIcon }) => {
const { i18n } = useServices();

const stateMap: any = {
[SNAPSHOT_STATE.IN_PROGRESS]: {
icon: <EuiLoadingSpinner size="m" />,
color: 'primary',
label: i18n.translate('xpack.snapshotRestore.snapshotState.inProgressLabel', {
defaultMessage: 'Taking snapshot…',
defaultMessage: 'In progress',
}),
},
[SNAPSHOT_STATE.SUCCESS]: {
icon: <EuiIcon color="success" type="check" />,
color: 'success',
label: i18n.translate('xpack.snapshotRestore.snapshotState.completeLabel', {
defaultMessage: 'Snapshot complete',
defaultMessage: 'Complete',
}),
},
[SNAPSHOT_STATE.FAILED]: {
icon: <EuiIcon color="danger" type="cross" />,
color: 'danger',
label: i18n.translate('xpack.snapshotRestore.snapshotState.failedLabel', {
defaultMessage: 'Snapshot failed',
defaultMessage: 'Failed',
}),
},
[SNAPSHOT_STATE.PARTIAL]: {
icon: <EuiIcon color="warning" type="warning" />,
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: <EuiIcon color="warning" type="warning" />,
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]) {
// Help debug unexpected state.
return state;
}

const { icon, label, tip } = stateMap[state];
const { color, label, tip } = stateMap[state];

const iconTip = tip && (
<Fragment>
{' '}
<EuiIconTip content={tip} />
</Fragment>
);
const iconTip = displayTooltipIcon && tip && <EuiIcon type="questionInCircle" />;

return (
<EuiFlexGroup gutterSize="xs" alignItems="center" responsive={false}>
<EuiFlexItem grow={false}>{icon}</EuiFlexItem>

<EuiFlexItem grow={false}>
{/* Escape flex layout created by EuiFlexItem. */}
<div>
{label}
{iconTip}
</div>
</EuiFlexItem>
</EuiFlexGroup>
<EuiToolTip position="top" content={tip}>
<EuiFlexGroup gutterSize="xs" alignItems="center" responsive={false}>
<EuiHealth color={color}>{label}</EuiHealth>
{iconTip}
</EuiFlexGroup>
</EuiToolTip>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const TabSummary: React.FC<Props> = ({ snapshotDetails }) => {
</EuiDescriptionListTitle>

<EuiDescriptionListDescription className="eui-textBreakWord" data-test-subj="value">
<SnapshotState state={state} />
<SnapshotState state={state} displayTooltipIcon={true} />
</EuiDescriptionListDescription>
</EuiFlexItem>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
});
};
23 changes: 23 additions & 0 deletions x-pack/plugins/snapshot_restore/server/routes/api/policy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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();
});
});
});
16 changes: 16 additions & 0 deletions x-pack/plugins/snapshot_restore/server/routes/api/policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}
})
);
}
Loading

0 comments on commit 4d8e8d9

Please sign in to comment.