Adding frozen indices support index management (#28855) (#29096)

* adding frozen badge and refactoring list and reload server routes

* adding freeze and unfreeze actions to index management

* adding badge to detail panel and factoring rendering of badges into lib function

* fixing issue with sorted name field and ellipsis

* modifying button label for freeze confirmation

* copy edit

* correcting i18n label

* fixing duplicate i18n id issue

* fixing another duplicate i18n id

* updating jest snapshots

* adding color to badge specification

* removing icons from index management context menu
This commit is contained in:
Bill McConaghy 2019-01-22 09:49:32 -05:00 committed by GitHub
parent 83690fd182
commit 766d193de7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 425 additions and 155 deletions

View file

@ -102,6 +102,7 @@ Array [
"Refresh indices",
"Clear indices cache",
"Flush indices",
"Freeze indices",
"Delete indices",
]
`;
@ -127,6 +128,7 @@ Array [
"Refresh index",
"Clear index cache",
"Flush index",
"Freeze index",
"Delete index",
]
`;

View file

@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
const summaryExtensions = [];
export const addSummaryExtension = (summaryExtension)=> {
summaryExtensions.push(summaryExtension);
@ -39,7 +39,17 @@ export const addToggleExtension = (toggleExtension)=> {
export const getToggleExtensions = () => {
return toggleExtensions;
};
const badgeExtensions = [];
const badgeExtensions = [
{
matchIndex: (index) => {
return index.isFrozen;
},
label: i18n.translate('xpack.idxMgmt.frozenBadgeLabel', {
defaultMessage: 'Frozen',
}),
color: 'primary'
}
];
export const addBadgeExtension = (badgeExtension)=> {
badgeExtensions.push(badgeExtension);
};

View file

@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React, { Fragment } from 'react';
import { EuiBadge } from '@elastic/eui';
import { getBadgeExtensions } from '../index_management_extensions';
export const renderBadges = (index) => {
const badgeLabels = [];
getBadgeExtensions().forEach(({ matchIndex, label, color }) => {
if (matchIndex(index)) {
badgeLabels.push(
<Fragment key={label}>
{' '}<EuiBadge color={color}>{label}</EuiBadge>
</Fragment>
);
}
});
return (
<Fragment>
{badgeLabels}
</Fragment>
);
};

View file

@ -10,7 +10,7 @@ import { Route } from 'react-router-dom';
import { ShowJson } from './show_json';
import { Summary } from './summary';
import { EditSettingsJson } from './edit_settings_json';
import { renderBadges } from '../../../../lib/render_badges';
import {
EuiCallOut,
EuiFlexGroup,
@ -50,7 +50,6 @@ export class DetailPanel extends Component {
);
});
}
render() {
const { panelType, indexName, index, closeDetailPanel } = this.props;
if (!panelType) {
@ -126,7 +125,7 @@ export class DetailPanel extends Component {
>
<EuiFlyoutHeader>
<EuiTitle size="l" id="indexDetailsFlyoutTitle">
<h2>{indexName}</h2>
<h2>{indexName}{renderBadges(index)}</h2>
</EuiTitle>
{index ? <EuiTabs>{this.renderTabs()}</EuiTabs> : null }
</EuiFlyoutHeader>

View file

@ -17,7 +17,9 @@ import {
refreshIndices,
openDetailPanel,
performExtensionAction,
reloadIndices
reloadIndices,
freezeIndices,
unfreezeIndices,
} from '../../../../store/actions';
import {
@ -57,6 +59,12 @@ const mapDispatchToProps = (dispatch, { indexNames }) => {
refreshIndices: () => {
dispatch(refreshIndices({ indexNames }));
},
freezeIndices: () => {
dispatch(freezeIndices({ indexNames }));
},
unfreezeIndices: () => {
dispatch(unfreezeIndices({ indexNames }));
},
forcemergeIndices: (maxNumSegments) => {
dispatch(forcemergeIndices({ indexNames, maxNumSegments }));
},

View file

@ -14,7 +14,6 @@ import {
EuiFieldText,
EuiForm,
EuiFormRow,
EuiIcon,
EuiPopover,
EuiSpacer,
EuiConfirmModal,
@ -57,11 +56,14 @@ class IndexActionsContextMenuUi extends Component {
performExtensionAction,
indices,
intl,
reloadIndices
reloadIndices,
unfreezeIndices,
} = this.props;
const allOpen = all(indexNames, indexName => {
return indexStatusByName[indexName] === INDEX_OPEN;
});
const allFrozen = all(indices, (index) => index.isFrozen);
const allUnfrozen = all(indices, (index) => !index.isFrozen);
const selectedIndexCount = indexNames.length;
const items = [];
if (!detailPanel && selectedIndexCount === 1) {
@ -70,7 +72,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.showIndexSettingsLabel',
defaultMessage: 'Show {selectedIndexCount, plural, one {index} other {indices} } settings',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexSettings" />,
onClick: () => {
this.closePopoverAndExecute(showSettings);
}
@ -80,7 +81,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.showIndexMappingLabel',
defaultMessage: 'Show {selectedIndexCount, plural, one {index} other {indices} } mapping',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexMapping" />,
onClick: () => {
this.closePopoverAndExecute(showMapping);
}
@ -91,7 +91,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.showIndexStatsLabel',
defaultMessage: 'Show {selectedIndexCount, plural, one {index} other {indices} } stats',
}, { selectedIndexCount }),
icon: <EuiIcon type="stats" />,
onClick: () => {
this.closePopoverAndExecute(showStats);
}
@ -102,7 +101,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.editIndexSettingsLabel',
defaultMessage: 'Edit {selectedIndexCount, plural, one {index} other {indices} } settings',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexEdit" />,
onClick: () => {
this.closePopoverAndExecute(editIndex);
}
@ -114,7 +112,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.closeIndexLabel',
defaultMessage: 'Close {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexClose" />,
onClick: () => {
this.closePopoverAndExecute(closeIndices);
}
@ -124,7 +121,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.forceMergeIndexLabel',
defaultMessage: 'Force merge {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="merge" />,
onClick: () => {
this.closePopover();
this.setState({ renderConfirmModal: this.renderForcemergeSegmentsModal });
@ -135,7 +131,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.refreshIndexLabel',
defaultMessage: 'Refresh {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="refresh" />,
onClick: () => {
this.closePopoverAndExecute(refreshIndices);
}
@ -145,7 +140,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.clearIndexCacheLabel',
defaultMessage: 'Clear {selectedIndexCount, plural, one {index} other {indices} } cache',
}, { selectedIndexCount }),
icon: <EuiIcon type="broom" />,
onClick: () => {
this.closePopoverAndExecute(clearCacheIndices);
}
@ -155,18 +149,38 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.flushIndexLabel',
defaultMessage: 'Flush {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexFlush" />,
onClick: () => {
this.closePopoverAndExecute(flushIndices);
}
});
if (allFrozen) {
items.push({
name: intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.unfreezeIndexLabel',
defaultMessage: 'Unfreeze {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
onClick: () => {
this.closePopoverAndExecute(unfreezeIndices);
}
});
} else if (allUnfrozen) {
items.push({
name: intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.freezeIndexLabel',
defaultMessage: 'Freeze {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
onClick: () => {
this.closePopover();
this.setState({ renderConfirmModal: this.renderConfirmFreezeModal });
}
});
}
} else {
items.push({
name: intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.openIndexLabel',
defaultMessage: 'Open {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="indexOpen" />,
onClick: () => {
this.closePopoverAndExecute(openIndices);
}
@ -177,7 +191,6 @@ class IndexActionsContextMenuUi extends Component {
id: 'xpack.idxMgmt.indexActionsMenu.deleteIndexLabel',
defaultMessage: 'Delete {selectedIndexCount, plural, one {index} other {indices} }',
}, { selectedIndexCount }),
icon: <EuiIcon type="trash" />,
onClick: () => {
this.closePopover();
this.setState({ renderConfirmModal: this.renderConfirmDeleteModal });
@ -186,11 +199,10 @@ class IndexActionsContextMenuUi extends Component {
getActionExtensions().forEach((actionExtension) => {
const actionExtensionDefinition = actionExtension(indices, reloadIndices);
if (actionExtensionDefinition) {
const { buttonLabel, requestMethod, successMessage, icon, renderConfirmModal } = actionExtensionDefinition;
const { buttonLabel, requestMethod, successMessage, renderConfirmModal } = actionExtensionDefinition;
if (requestMethod) {
items.push({
name: buttonLabel,
icon: <EuiIcon type={icon} />,
onClick: () => {
this.closePopoverAndExecute(async () => {
await performExtensionAction(requestMethod, successMessage);
@ -200,7 +212,6 @@ class IndexActionsContextMenuUi extends Component {
} else {
items.push({
name: buttonLabel,
icon: <EuiIcon type={icon} />,
onClick: () => {
this.closePopover();
this.setState({ renderConfirmModal });
@ -416,6 +427,91 @@ class IndexActionsContextMenuUi extends Component {
</EuiOverlayMask>
);
};
renderConfirmFreezeModal = () => {
const oneIndexSelected = this.oneIndexSelected();
const entity = this.getEntity(oneIndexSelected);
const { freezeIndices, indexNames, intl } = this.props;
return (
<EuiOverlayMask>
<EuiConfirmModal
title={
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.modalTitle',
defaultMessage: 'Confirm Freeze {entity}',
}, { entity })
}
onCancel={this.closeConfirmModal}
onConfirm={() => this.closePopoverAndExecute(freezeIndices)}
cancelButtonText={
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.cancelButtonText',
defaultMessage: 'Cancel',
})
}
confirmButtonText={
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.freezeEntity.confirmModal.confirmButtonText',
defaultMessage: 'Freeze {entity}',
}, { entity })
}
>
<div>
<p>
<FormattedMessage
id="xpack.idxMgmt.indexActionsMenu.freezeEntity.freezeDescription"
defaultMessage="You are about to freeze {oneIndexSelected, plural, one {this} other {these}}"
values={{ oneIndexSelected: oneIndexSelected ? 1 : 0 }}
/>
{' '}
{entity}:
</p>
<ul>
{indexNames.map(indexName => (
<li key={indexName}>{indexName}</li>
))}
</ul>
<EuiCallOut
title={
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.freezeEntity.proceedWithCautionCallOutTitle',
defaultMessage: 'Proceed with caution',
})
}
color="warning"
iconType="help"
>
<p>
<FormattedMessage
id="xpack.idxMgmt.indexActionsMenu.freezeEntity.freezeEntityWarningDescription"
defaultMessage="
A frozen index has little overhead on the cluster and is blocked for write operations.
You can search a frozen index, but expect queries to be slower.
"
/>
</p>
</EuiCallOut>
</div>
</EuiConfirmModal>
</EuiOverlayMask>
);
};
oneIndexSelected = () => {
return this.props.indexNames.length === 1;
};
getEntity = oneIndexSelected => {
const { intl } = this.props;
return oneIndexSelected ? (
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.indexMessage',
defaultMessage: 'index'
})
) : (
intl.formatMessage({
id: 'xpack.idxMgmt.indexActionsMenu.indicesMessage',
defaultMessage: 'indices'
})
);
};
render() {
const { indexNames, intl } = this.props;
const selectedIndexCount = indexNames.length;

View file

@ -14,7 +14,6 @@ import '../../../../styles/table.less';
import { REFRESH_RATE_INDEX_LIST } from '../../../../constants';
import {
EuiBadge,
EuiButton,
EuiCallOut,
EuiHealth,
@ -47,8 +46,8 @@ import {
getBannerExtensions,
getFilterExtensions,
getToggleExtensions,
getBadgeExtensions,
} from '../../../../index_management_extensions';
import { renderBadges } from '../../../../lib/render_badges';
const HEADERS = {
name: i18n.translate('xpack.idxMgmt.indexTable.headers.nameHeader', {
@ -216,26 +215,6 @@ export class IndexTableUi extends Component {
});
}
renderBadges(index) {
const badgeLabels = [];
getBadgeExtensions().forEach(({ matchIndex, label }) => {
if (matchIndex(index)) {
badgeLabels.push(label);
}
});
return (
<Fragment>
{badgeLabels.map(badgeLabel => {
return (
<Fragment key={badgeLabel}>
{' '}
<EuiBadge color="primary">{badgeLabel}</EuiBadge>
</Fragment>
);
})}
</Fragment>
);
}
buildRowCell(fieldName, value, index) {
const { openDetailPanel } = this.props;
if (fieldName === 'health') {
@ -249,8 +228,7 @@ export class IndexTableUi extends Component {
openDetailPanel(value);
}}
>
{value}
{this.renderBadges(index)}
{value}{renderBadges(index)}
</EuiLink>
);
}

View file

@ -83,6 +83,20 @@ export async function clearCacheIndices(indices) {
const response = await httpClient.post(`${apiPrefix}/indices/clear_cache`, body);
return response.data;
}
export async function freezeIndices(indices) {
const body = {
indices
};
const response = await httpClient.post(`${apiPrefix}/indices/freeze`, body);
return response.data;
}
export async function unfreezeIndices(indices) {
const body = {
indices
};
const response = await httpClient.post(`${apiPrefix}/indices/unfreeze`, body);
return response.data;
}
export async function loadIndexSettings(indexName) {
const response = await httpClient.get(`${apiPrefix}/settings/${indexName}`);

View file

@ -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 { createAction } from 'redux-actions';
import { i18n } from '@kbn/i18n';
import { freezeIndices as request } from '../../services';
import { clearRowStatus, reloadIndices } from '../actions';
import { toastNotifications } from 'ui/notify';
export const freezeIndicesStart = createAction(
'INDEX_MANAGEMENT_FREEZE_INDICES_START'
);
export const freezeIndices = ({ indexNames }) => async (dispatch) => {
dispatch(freezeIndicesStart({ indexNames }));
try {
await request(indexNames);
} catch (error) {
toastNotifications.addDanger(error.data.message);
return dispatch(clearRowStatus({ indexNames }));
}
dispatch(reloadIndices(indexNames));
toastNotifications.addSuccess(
i18n.translate('xpack.idxMgmt.freezeIndicesAction.successfullyFrozeIndicesMessage', {
defaultMessage: 'Successfully froze: [{indexNames}]',
values: { indexNames: indexNames.join(', ') }
})
);
};

View file

@ -14,6 +14,8 @@ export * from './load_indices';
export * from './load_index_data';
export * from './open_indices';
export * from './refresh_indices';
export * from './freeze_indices';
export * from './unfreeze_indices';
export * from './reload_indices';
export * from './table_state';
export * from './edit_index_settings';

View file

@ -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 { createAction } from 'redux-actions';
import { i18n } from '@kbn/i18n';
import { unfreezeIndices as request } from '../../services';
import { clearRowStatus, reloadIndices } from '../actions';
import { toastNotifications } from 'ui/notify';
export const unfreezeIndicesStart = createAction(
'INDEX_MANAGEMENT_UNFREEZE_INDICES_START'
);
export const unfreezeIndices = ({ indexNames }) => async (dispatch) => {
dispatch(unfreezeIndicesStart({ indexNames }));
try {
await request(indexNames);
} catch (error) {
toastNotifications.addDanger(error.data.message);
return dispatch(clearRowStatus({ indexNames }));
}
dispatch(reloadIndices(indexNames));
toastNotifications.addSuccess(
i18n.translate('xpack.idxMgmt.unfreezeIndicesAction.successfullyUnfrozeIndicesMessage', {
defaultMessage: 'Successfully unfroze: [{indexNames}]',
values: { indexNames: indexNames.join(', ') }
})
);
};

View file

@ -1,21 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { getIndexManagementDataEnrichers } from '../../index_management_data';
export const enrichResponse = async (response, callWithRequest) => {
let enrichedResponse = response;
const dataEnrichers = getIndexManagementDataEnrichers();
for (let i = 0; i < dataEnrichers.length; i++) {
const dataEnricher = dataEnrichers[i];
try {
const dataEnricherResponse = await dataEnricher(enrichedResponse, callWithRequest);
enrichedResponse = dataEnricherResponse;
} catch(e) {
// silently swallow enricher response errors
}
}
return enrichedResponse;
};

View file

@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { wrapEsError, wrapUnknownError } from './error_wrappers';
import { fetchAliases } from './fetch_aliases';
import { getIndexManagementDataEnrichers } from '../../index_management_data';
const enrichResponse = async (response, callWithRequest) => {
let enrichedResponse = response;
const dataEnrichers = getIndexManagementDataEnrichers();
for (let i = 0; i < dataEnrichers.length; i++) {
const dataEnricher = dataEnrichers[i];
try {
const dataEnricherResponse = await dataEnricher(enrichedResponse, callWithRequest);
enrichedResponse = dataEnricherResponse;
} catch(e) {
// silently swallow enricher response errors
}
}
return enrichedResponse;
};
function formatHits(hits, aliases) {
return hits.map(hit => {
return {
health: hit.health,
status: hit.status,
name: hit.index,
uuid: hit.uuid,
primary: hit.pri,
replica: hit.rep,
documents: hit["docs.count"],
size: hit["store.size"],
isFrozen: hit.sth === 'true', // sth value coming back as a string from ES
aliases: aliases.hasOwnProperty(hit.index) ? aliases[hit.index] : 'none',
};
});
}
async function fetchIndicesCall(callWithRequest, indexNames) {
const params = {
format: 'json',
h: 'health,status,index,uuid,pri,rep,docs.count,sth,store.size'
};
if (indexNames) {
params.index = indexNames;
}
return await callWithRequest('cat.indices', params);
}
export const fetchIndices = async (callWithRequest, isEsError, indexNames) => {
try {
const aliases = await fetchAliases(callWithRequest);
const hits = await fetchIndicesCall(callWithRequest, indexNames);
let response = formatHits(hits, aliases);
response = await enrichResponse(response, callWithRequest);
return response;
} catch (err) {
if (isEsError(err)) {
throw wrapEsError(err);
}
throw wrapUnknownError(err);
}
};

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
function getIndexArrayFromPayload(payload) {
return payload.indices || [];
}
async function freezeIndices(callWithRequest, indices) {
const params = {
path: `/${indices.join(',')}/_freeze`,
method: 'POST',
};
return await callWithRequest('transport.request', params);
}
export function registerFreezeRoute(server) {
const isEsError = isEsErrorFactory(server);
const licensePreRouting = licensePreRoutingFactory(server);
server.route({
path: '/api/index_management/indices/freeze',
method: 'POST',
handler: async (request, h) => {
const callWithRequest = callWithRequestFactory(server, request);
const indices = getIndexArrayFromPayload(request.payload);
try {
await freezeIndices(callWithRequest, indices);
return h.response();
} catch (err) {
if (isEsError(err)) {
throw wrapEsError(err);
}
throw wrapUnknownError(err);
}
},
config: {
pre: [ licensePreRouting ]
}
});
}

View file

@ -14,6 +14,8 @@ import { registerRefreshRoute } from './register_refresh_route';
import { registerReloadRoute } from './register_reload_route';
import { registerDeleteRoute } from './register_delete_route';
import { registerShardsRoute } from './register_shards_route';
import { registerFreezeRoute } from './register_freeze_route';
import { registerUnfreezeRoute } from './register_unfreeze_route';
export function registerIndicesRoutes(server) {
registerClearCacheRoute(server);
@ -26,4 +28,6 @@ export function registerIndicesRoutes(server) {
registerReloadRoute(server);
registerDeleteRoute(server);
registerShardsRoute(server);
registerFreezeRoute(server);
registerUnfreezeRoute(server);
}

View file

@ -6,36 +6,8 @@
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
import { fetchAliases } from './fetch_aliases';
import { enrichResponse } from '../../../lib/enrich_response';
function formatHits(hits, aliases) {
return hits.map(hit => {
return {
health: hit.health,
status: hit.status,
name: hit.index,
uuid: hit.uuid,
primary: hit.pri,
replica: hit.rep,
documents: hit["docs.count"],
documents_deleted: hit["docs.deleted"],
size: hit["store.size"],
primary_size: hit["pri.store.size"],
aliases: aliases.hasOwnProperty(hit.index) ? aliases[hit.index] : 'none',
};
});
}
async function fetchIndices(callWithRequest) {
const params = {
format: 'json'
};
return await callWithRequest('cat.indices', params);
}
import { fetchIndices } from '../../../lib/fetch_indices';
export function registerListRoute(server) {
const isEsError = isEsErrorFactory(server);
@ -46,20 +18,7 @@ export function registerListRoute(server) {
method: 'GET',
handler: async (request) => {
const callWithRequest = callWithRequestFactory(server, request);
try {
const aliases = await fetchAliases(callWithRequest);
const hits = await fetchIndices(callWithRequest);
let response = formatHits(hits, aliases);
response = await enrichResponse(response, callWithRequest);
return response;
} catch (err) {
if (isEsError(err)) {
throw wrapEsError(err);
}
throw wrapUnknownError(err);
}
return fetchIndices(callWithRequest, isEsError);
},
config: {
pre: [licensePreRouting]

View file

@ -6,42 +6,12 @@
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
import { enrichResponse } from '../../../lib/enrich_response';
import { fetchAliases } from './fetch_aliases';
import { fetchIndices } from '../../../lib/fetch_indices';
function getIndexNamesFromPayload(payload) {
return payload.indexNames || [];
}
function formatHits(hits, aliases) {
return hits.map(hit => {
return {
health: hit.health,
status: hit.status,
name: hit.index,
uuid: hit.uuid,
primary: hit.pri,
replica: hit.rep,
documents: hit["docs.count"],
documents_deleted: hit["docs.deleted"],
size: hit["store.size"],
primary_size: hit["pri.store.size"],
aliases: aliases.hasOwnProperty(hit.index) ? aliases[hit.index] : 'none',
};
});
}
async function fetchIndices(callWithRequest, indexNames) {
const params = {
format: 'json',
index: indexNames
};
return await callWithRequest('cat.indices', params);
}
export function registerReloadRoute(server) {
const isEsError = isEsErrorFactory(server);
const licensePreRouting = licensePreRoutingFactory(server);
@ -52,20 +22,7 @@ export function registerReloadRoute(server) {
handler: async (request) => {
const callWithRequest = callWithRequestFactory(server, request);
const indexNames = getIndexNamesFromPayload(request.payload);
try {
const indices = await fetchIndices(callWithRequest, indexNames);
const aliases = await fetchAliases(callWithRequest);
let response = formatHits(indices, aliases);
response = await enrichResponse(response, callWithRequest);
return response;
} catch (err) {
if (isEsError(err)) {
throw wrapEsError(err);
}
throw wrapUnknownError(err);
}
return await fetchIndices(callWithRequest, isEsError, indexNames);
},
config: {
pre: [ licensePreRouting ]

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { callWithRequestFactory } from '../../../lib/call_with_request_factory';
import { isEsErrorFactory } from '../../../lib/is_es_error_factory';
import { wrapEsError, wrapUnknownError } from '../../../lib/error_wrappers';
import { licensePreRoutingFactory } from'../../../lib/license_pre_routing_factory';
function getIndexArrayFromPayload(payload) {
return payload.indices || [];
}
async function unfreezeIndices(callWithRequest, indices) {
const params = {
path: `/${indices.join(',')}/_unfreeze`,
method: 'POST',
};
return await callWithRequest('transport.request', params);
}
export function registerUnfreezeRoute(server) {
const isEsError = isEsErrorFactory(server);
const licensePreRouting = licensePreRoutingFactory(server);
server.route({
path: '/api/index_management/indices/unfreeze',
method: 'POST',
handler: async (request, h) => {
const callWithRequest = callWithRequestFactory(server, request);
const indices = getIndexArrayFromPayload(request.payload);
try {
await unfreezeIndices(callWithRequest, indices);
return h.response();
} catch (err) {
if (isEsError(err)) {
throw wrapEsError(err);
}
throw wrapUnknownError(err);
}
},
config: {
pre: [ licensePreRouting ]
}
});
}

View file

@ -27,6 +27,7 @@ export const rollupBadgeExtension = {
label: i18n.translate('xpack.rollupJobs.indexMgmtBadge.rollupLabel', {
defaultMessage: 'Rollup',
}),
color: 'secondary'
};
addBadgeExtension(rollupBadgeExtension);