[Monitoring/React] Render ES Indices Listing with Base Controller / React (#18595) (#18970)

* [Monitoring/React] Render ES Indices Listing with Base Controller

Refactors the ES Indices Listing to use Base Controller and a React component instead of an Angular directive

* fix functional tests

* fix another test

* better default for summary status component

* nicer code for whitespace after label

* apiFn => apiUrlFn

* Deleted / Closed
This commit is contained in:
Tim Sullivan 2018-05-10 09:18:36 -07:00 committed by GitHub
parent 9e3a2a4a15
commit 50906670e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 635 additions and 462 deletions

View file

@ -4,8 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { SummaryStatus } from '../../';
import React, { Fragment } from 'react';
import { SummaryStatus } from '../../summary_status';
import { ElasticsearchStatusIcon } from '../status_icon';
import { formatMetric } from '../../../lib/format_number';
export function ClusterStatus({ stats }) {
@ -59,10 +60,17 @@ export function ClusterStatus({ stats }) {
}
];
const IconComponent = ({ status }) => (
<Fragment>
Health: <ElasticsearchStatusIcon status={status} />
</Fragment>
);
return (
<SummaryStatus
children={children}
status={status}
IconComponent={IconComponent}
data-test-subj="elasticsearchSummaryStatus"
/>
);

View file

@ -6,3 +6,4 @@
export { ElasticsearchOverview } from './overview';
export { ElasticsearchNodes } from './nodes';
export { ElasticsearchIndices } from './indices';

View file

@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { ShowSytemIndicesCheckbox } from './show_system_indices_checkbox';
export { ElasticsearchIndices } from './indices';

View file

@ -0,0 +1,117 @@
/*
* 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 { capitalize, get } from 'lodash';
import { SORT_ASCENDING, SORT_DESCENDING } from '../../../../common/constants';
import { LARGE_FLOAT, LARGE_BYTES, LARGE_ABBREVIATED } from '../../../../common/formatting';
import { formatMetric } from '../../../lib/format_number';
import { ElasticsearchStatusIcon } from '../status_icon';
import { ClusterStatus } from '../cluster_status';
import { MonitoringTable } from '../../';
import { EuiLink } from '@elastic/eui';
import { KuiTableRowCell, KuiTableRow } from '@kbn/ui-framework/components';
import { SytemIndicesCheckbox } from './system_indices_checkbox';
const filterFields = ['name', 'status'];
const columns = [
{ title: 'Name', sortKey: 'name', secondarySortOrder: SORT_ASCENDING },
{ title: 'Status', sortKey: 'status_sort', sortOrder: SORT_DESCENDING }, // default sort: red, then yellow, then green
{ title: 'Document Count', sortKey: 'doc_count' },
{ title: 'Data', sortKey: 'data_size' },
{ title: 'Index Rate', sortKey: 'index_rate' },
{ title: 'Search Rate', sortKey: 'search_rate' },
{ title: 'Unassigned Shards', sortKey: 'unassigned_shards' }
];
const IndexRow = ({ status, ...props }) => (
<KuiTableRow>
<KuiTableRowCell data-test-subj="name">
<EuiLink
href={`#/elasticsearch/indices/${props.name}`}
data-test-subj={`indexLink-${props.name}`}
>
{props.name}
</EuiLink>
</KuiTableRowCell>
<KuiTableRowCell>
<div title={`Index status: ${status}`}>
<ElasticsearchStatusIcon status={status} />&nbsp;
{capitalize(status)}
</div>
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="documentCount">
{formatMetric(get(props, 'doc_count'), LARGE_ABBREVIATED)}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="dataSize">
{formatMetric(get(props, 'data_size'), LARGE_BYTES)}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="indexRate">
{formatMetric(get(props, 'index_rate'), LARGE_FLOAT, '/s')}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="searchRate">
{formatMetric(get(props, 'search_rate'), LARGE_FLOAT, '/s')}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="unassignedShards">
{formatMetric(get(props, 'unassigned_shards'), '0')}
</KuiTableRowCell>
</KuiTableRow>
);
const getNoDataMessage = filterText => {
if (filterText) {
return (
<div>
<p>
There are no indices that match your selection with the filter [{filterText.trim()}].
Try changing the filter or the time range selection.
</p>
<p>
If you are looking for system indices (e.g., .kibana), try checking &lsquo;Show system indices&rsquo;.
</p>
</div>
);
}
return (
<div>
<p>There are no indices that match your selections. Try changing the time range selection.</p>
<p>If you are looking for system indices (e.g., .kibana), try checking &lsquo;Show system indices&rsquo;.</p>
</div>
);
};
const renderToolBarSection = ({ showSystemIndices, toggleShowSystemIndices, ...props }) => (
<SytemIndicesCheckbox
showSystemIndices={showSystemIndices}
toggleShowSystemIndices={toggleShowSystemIndices}
{...props}
/>
);
export function ElasticsearchIndices({ clusterStatus, indices, ...props }) {
return (
<Fragment>
<ClusterStatus stats={clusterStatus} />
<MonitoringTable
className="elasticsearchIndicesTable"
rows={indices}
pageIndex={props.pageIndex}
filterText={props.filterText}
sortKey={props.sortKey}
sortOrder={props.sortOrder}
onNewState={props.onNewState}
placeholder="Filter Indices..."
filterFields={filterFields}
renderToolBarSections={renderToolBarSection}
columns={columns}
rowComponent={IndexRow}
getNoDataMessage={getNoDataMessage}
showSystemIndices={props.showSystemIndices}
toggleShowSystemIndices={props.toggleShowSystemIndices}
/>
</Fragment>
);
}

View file

@ -14,7 +14,7 @@ import {
} from '@elastic/eui';
import { TABLE_ACTION_RESET_PAGING } from '../../../../common/constants';
export class ShowSytemIndicesCheckbox extends React.Component {
export class SytemIndicesCheckbox extends React.Component {
constructor(props) {
super(props);
this.state = { showSystemIndices: props.showSystemIndices };

View file

@ -5,7 +5,7 @@
*/
import React from 'react';
import { StatusIcon } from 'plugins/monitoring/components/status_icon';
import { StatusIcon } from '../status_icon';
export function ElasticsearchStatusIcon({ status }) {
const type = (() => {

View file

@ -10,6 +10,10 @@ export { Tooltip } from './tooltip';
export { NoData } from './no_data';
export { License } from './license';
export { StatusIcon } from './status_icon';
export { SummaryStatus } from './summary_status';
export { SummaryStatus } from './summary_status'; // TODO this line can be removed, component is only used by other components
export { PageLoading } from './page_loading';
export { ElasticsearchOverview, ElasticsearchNodes } from './elasticsearch';
export {
ElasticsearchOverview,
ElasticsearchNodes,
ElasticsearchIndices
} from './elasticsearch';

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import React, { Fragment } from 'react';
import { isEmpty, capitalize } from 'lodash';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { StatusIcon } from '../';
@ -19,20 +19,28 @@ const wrapChild = ({ label, value, dataTestSubj }, index) => (
</EuiFlexItem>
);
const StatusIndicator = ({ status }) => {
const DefaultIconComponent = ({ status }) => (
<Fragment>
Status: {(
<StatusIcon type={status.toUpperCase()} label={`Status: ${status}`} />
)}
</Fragment>
);
const StatusIndicator = ({ status, IconComponent }) => {
if (isEmpty(status)) {
return null;
}
return (
<div className="monitoring-summary-status__status-indicator">
Health: <StatusIcon type={status.toUpperCase()} label={`Status: ${status}`} />{' '}
<IconComponent status={status} />{' '}
{capitalize(status)}
</div>
);
};
export function SummaryStatus({ children, status, ...props }) {
export function SummaryStatus({ children, status, IconComponent = DefaultIconComponent, ...props }) {
return (
<div className="monitoring-summary-status" role="status">
<div className="monitoring-summary-status__content" {...props}>
@ -43,7 +51,7 @@ export function SummaryStatus({ children, status, ...props }) {
grow={true}
className="monitoring-summary-status__eui-content"
>
<StatusIndicator status={status} />
<StatusIndicator status={status} IconComponent={IconComponent} />
</EuiFlexItem>
</EuiFlexGroup>
</div>

View file

@ -12,7 +12,6 @@ import './status_icon';
import './cluster/overview';
import './cluster/listing';
import './elasticsearch/cluster_status';
import './elasticsearch/index_listing';
import './elasticsearch/index_summary';
import './elasticsearch/node_summary';
import './elasticsearch/ml_job_listing';

View file

@ -1,158 +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 { capitalize, get } from 'lodash';
import React from 'react';
import { render } from 'react-dom';
import { SORT_ASCENDING, SORT_DESCENDING } from '../../../../common/constants';
import { LARGE_FLOAT, LARGE_BYTES, LARGE_ABBREVIATED } from '../../../../common/formatting';
import { uiModules } from 'ui/modules';
import {
KuiTableRowCell,
KuiTableRow,
} from '@kbn/ui-framework/components';
import { MonitoringTable } from 'plugins/monitoring/components/table';
import { ShowSytemIndicesCheckbox } from 'plugins/monitoring/components/elasticsearch/index_listing';
import { ElasticsearchStatusIcon } from 'plugins/monitoring/components/elasticsearch/status_icon';
import { formatMetric } from '../../../lib/format_number';
import {
EuiLink,
} from '@elastic/eui';
const filterFields = ['name', 'status'];
const cols = [
{ title: 'Name', sortKey: 'name', secondarySortOrder: SORT_ASCENDING },
{ title: 'Status', sortKey: 'statusSort', sortOrder: SORT_DESCENDING }, // default sort: red, then yellow, then green
{ title: 'Document Count', sortKey: 'doc_count' },
{ title: 'Data', sortKey: 'data_size' },
{ title: 'Index Rate', sortKey: 'index_rate' },
{ title: 'Search Rate', sortKey: 'search_rate' },
{ title: 'Unassigned Shards', sortKey: 'unassigned_shards' }
];
const indexRowFactory = (scope, kbnUrl) => {
return class IndexRow extends React.Component { // eslint-disable-line react/no-multi-comp
constructor(props) {
super(props);
this.changePath = this.changePath.bind(this);
}
changePath() {
scope.$evalAsync(() => {
kbnUrl.changePath(`/elasticsearch/indices/${this.props.name}`);
});
}
render() {
const status = this.props.status;
return (
<KuiTableRow>
<KuiTableRowCell data-test-subj="name">
<EuiLink
onClick={this.changePath}
data-test-subj={`indexLink-${this.props.name}`}
>
{this.props.name}
</EuiLink>
</KuiTableRowCell>
<KuiTableRowCell>
<div title={`Index status: ${status}`}>
<ElasticsearchStatusIcon status={status} />&nbsp;
{capitalize(status)}
</div>
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="documentCount">
{formatMetric(get(this.props, 'doc_count'), LARGE_ABBREVIATED)}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="dataSize">
{formatMetric(get(this.props, 'data_size'), LARGE_BYTES)}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="indexRate">
{formatMetric(get(this.props, 'index_rate'), LARGE_FLOAT, '/s')}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="searchRate">
{formatMetric(get(this.props, 'search_rate'), LARGE_FLOAT, '/s')}
</KuiTableRowCell>
<KuiTableRowCell data-test-subj="unassignedShards">
{formatMetric(get(this.props, 'unassigned_shards'), '0')}
</KuiTableRowCell>
</KuiTableRow>
);
}
};
};
const getNoDataMessage = filterText => {
if (filterText) {
return (
<div>
<p>
There are no indices that match your selection with the filter [{filterText.trim()}].
Try changing the filter or the time range selection.
</p>
<p>
If you are looking for system indices (e.g., .kibana), try checking &lsquo;Show system indices&rsquo;.
</p>
</div>
);
}
return (
<div>
<p>There are no indices that match your selections. Try changing the time range selection.</p>
<p>If you are looking for system indices (e.g., .kibana), try checking &lsquo;Show system indices&rsquo;.</p>
</div>
);
};
const uiModule = uiModules.get('monitoring/directives', []);
uiModule.directive('monitoringIndexListing', kbnUrl => {
return {
restrict: 'E',
scope: {
indices: '=',
pageIndex: '=',
filterText: '=',
sortKey: '=',
sortOrder: '=',
onNewState: '=',
showSystemIndices: '=',
toggleShowSystemIndices: '='
},
link(scope, $el) {
const toggleShowSystemIndices = isChecked => {
scope.$evalAsync(() => {
scope.toggleShowSystemIndices(isChecked);
});
};
const renderToolBarSection = props => (
<ShowSytemIndicesCheckbox
showSystemIndices={scope.showSystemIndices}
toggleShowSystemIndices={toggleShowSystemIndices}
{...props}
/>
);
scope.$watch('indices', (indices = []) => {
const instancesTable = (
<MonitoringTable
className="indicesTable"
rows={indices}
pageIndex={scope.pageIndex}
filterText={scope.filterText}
sortKey={scope.sortKey}
sortOrder={scope.sortOrder}
onNewState={scope.onNewState}
placeholder="Filter Indices..."
filterFields={filterFields}
renderToolBarSections={renderToolBarSection}
columns={cols}
rowComponent={indexRowFactory(scope, kbnUrl)}
getNoDataMessage={getNoDataMessage}
/>
);
render(instancesTable, $el[0]);
});
}
};
});

View file

@ -40,19 +40,27 @@ export class MonitoringViewBaseController {
/**
* Create a view controller
* @param {String} title - Title of the page
* @param {String} api - Back-end API endpoint to poll for getting the page data using POST and time range data in the body.
* Whenever possible, use this method for data polling rather than supply the getPageData param.
* @param {Function} getPageData - (Optional) Function to fetch page data, if simply passing the API string isn't workable.
* @param {String} api - Back-end API endpoint to poll for getting the page
* data using POST and time range data in the body. Whenever possible, use
* this method for data polling rather than supply the getPageData param.
* @param {Function} apiUrlFn - Function that returns a string for the back-end
* API endpoint, in case the string has dynamic query parameters (e.g.
* show_system_indices) rather than supply the getPageData param.
* @param {Function} getPageData - (Optional) Function to fetch page data, if
* simply passing the API string isn't workable.
* @param {Object} defaultData - Initial model data to populate
* @param {String} reactNodeId - DOM element ID of the element for mounting the view's main React component
* @param {String} reactNodeId - DOM element ID of the element for mounting
* the view's main React component
* @param {Service} $injector - Angular dependency injection service
* @param {Service} $scope - Angular view data binding service
* @param {Boolean} options.enableTimeFilter - Whether to show the time filter
* @param {Boolean} options.enableAutoRefresh - Whether to show the auto refresh control
* @param {Boolean} options.enableAutoRefresh - Whether to show the auto
* refresh control
*/
constructor({
title = '',
api = '',
apiUrlFn,
getPageData: _getPageData = getPageData,
defaultData,
reactNodeId = null, // WIP: https://github.com/elastic/x-pack-kibana/issues/5198
@ -88,7 +96,8 @@ export class MonitoringViewBaseController {
}
this.updateData = () => {
return _getPageData($injector, api)
const _api = apiUrlFn ? apiUrlFn() : api;
return _getPageData($injector, _api)
.then(pageData => {
this._isDataInitialized = true; // render will replace loading screen with the react component
this.data = pageData; // update the view's data with the fetch result

View file

@ -1,56 +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 { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler';
export function getPageData($injector) {
const globalState = $injector.get('globalState');
const timefilter = $injector.get('timefilter');
const $http = $injector.get('$http');
const features = $injector.get('features');
const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/indices`;
const showSystemIndices = features.isEnabled('showSystemIndices', false);
const timeBounds = timefilter.getBounds();
/* TODO: get `pageIndex`, `filterText`, `sortKey`, `sortOrder` through `getLocalStorageData`
* and send params through API */
return $http.post(url, {
showSystemIndices,
ccs: globalState.ccs,
timeRange: {
min: timeBounds.min.toISOString(),
max: timeBounds.max.toISOString()
}
})
.then(response => response.data)
.then(data => {
data.rows.forEach(row => {
// calculate a numerical field to help sorting by status
// this allows default sort to show red, then yellow, then green
switch (row.status) {
case 'Deleted':
row.statusSort = 0;
break;
case 'green':
row.statusSort = 1;
break;
case 'yellow':
row.statusSort = 2;
break;
default:
row.statusSort = 3;
}
});
return data;
})
.catch((err) => {
const Private = $injector.get('Private');
const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider);
return ajaxErrorHandlers(err);
});
}

View file

@ -3,18 +3,5 @@
name="indices"
data-test-subj="elasticsearchIndicesListingPage"
>
<monitoring-cluster-status-elasticsearch status="esIndices.data.clusterStatus"></monitoring-cluster-status-elasticsearch>
<div class="page-row">
<h3 class="kuiScreenReaderOnly">Indices</h3>
<monitoring-index-listing
page-index="esIndices.pageIndex"
filter-text="esIndices.filterText"
sort-key="esIndices.sortKey"
sort-order="esIndices.sortOrder"
on-new-state="esIndices.onNewState"
indices="esIndices.data.rows"
show-system-indices="esIndices.showSystemIndices"
toggle-show-system-indices="esIndices.toggleShowSystemIndices"
></monitoring-index-listing>
</div>
<div id="elasticsearchIndicesReact"></div>
</monitoring-main>

View file

@ -4,53 +4,70 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { find } from 'lodash';
import uiRoutes from 'ui/routes';
import { routeInitProvider } from 'plugins/monitoring/lib/route_init';
import { MonitoringViewBaseTableController } from '../../';
import { getPageData } from './get_page_data';
import { ElasticsearchIndices } from '../../../components';
import template from './index.html';
uiRoutes.when('/elasticsearch/indices', {
template,
resolve: {
clusters: function (Private) {
clusters(Private) {
const routeInit = Private(routeInitProvider);
return routeInit();
},
pageData: getPageData
}
},
controllerAs: 'esIndices',
controller: class EsIndicesList extends MonitoringViewBaseTableController {
controllerAs: 'elasticsearchIndices',
controller: class ElasticsearchIndicesController extends MonitoringViewBaseTableController {
constructor($injector, $scope) {
const $route = $injector.get('$route');
const globalState = $injector.get('globalState');
const features = $injector.get('features');
const { cluster_uuid: clusterUuid } = globalState;
$scope.cluster = find($route.current.locals.clusters, { cluster_uuid: clusterUuid });
let showSystemIndices = features.isEnabled('showSystemIndices', false);
super({
title: 'Elasticsearch - Indices',
storageKey: 'elasticsearch.indices',
getPageData,
apiUrlFn: () => `../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/indices?show_system_indices=${showSystemIndices}`,
reactNodeId: 'elasticsearchIndicesReact',
defaultData: {},
$scope,
$injector,
$scope,
$injector
});
const $route = $injector.get('$route');
this.data = $route.current.locals.pageData;
const globalState = $injector.get('globalState');
$scope.cluster = find($route.current.locals.clusters, { cluster_uuid: globalState.cluster_uuid });
// used in table toolbar
const features = $injector.get('features');
this.showSystemIndices = features.isEnabled('showSystemIndices', false);
// for binding
this.toggleShowSystemIndices = isChecked => {
const toggleShowSystemIndices = isChecked => {
// flip the boolean
this.showSystemIndices = isChecked;
showSystemIndices = isChecked;
// preserve setting in localStorage
features.update('showSystemIndices', isChecked);
// update the page (resets pagination and sorting)
this.updateData();
};
}
$scope.$watch(() => this.data, data => {
this.renderReact(data);
});
this.renderReact = ({ clusterStatus, indices }) => {
super.renderReact(
<ElasticsearchIndices
clusterStatus={clusterStatus}
indices={indices}
showSystemIndices={showSystemIndices}
toggleShowSystemIndices={toggleShowSystemIndices}
/>
);
};
}
}
});

View file

@ -13,7 +13,7 @@ describe('Get Elasticsearch Indices', () => {
expect(result).to.eql([]);
});
it('handle a simple response', () => {
it('should handle a simple response', () => {
const resp = {
hits: {
hits: [{
@ -30,12 +30,15 @@ describe('Get Elasticsearch Indices', () => {
doc_count: undefined,
data_size: undefined,
index_rate: null,
search_rate: null
search_rate: null,
status: 'Deleted / Closed',
status_sort: 0,
unassigned_shards: undefined
}
]);
});
it('handle a typical multi-hit response', () => {
it('should handle a multi-hit response with deleted/closed indices', () => {
const resp = {
'hits': {
'hits': [ {
@ -97,14 +100,126 @@ describe('Get Elasticsearch Indices', () => {
doc_count: 381,
data_size: 3199059,
index_rate: 0,
search_rate: 0
search_rate: 0,
status: 'Deleted / Closed',
status_sort: 0,
unassigned_shards: undefined
},
{
name: 'cat-tweets-2017.08.08',
doc_count: 31375,
data_size: 239591867,
index_rate: 13.30026455026455,
search_rate: 28.902116402116405
search_rate: 28.902116402116405,
status: 'Deleted / Closed',
status_sort: 0,
unassigned_shards: undefined
}
]);
});
it('should handle a multi-hit response with open indices', () => {
const resp = {
hits: {
hits: [
{
_source: {
index_stats: {
index: 'avocado-tweets-2017.08.08',
primaries: {
docs: { count: 381 },
indexing: { index_total: 15 }
},
total: {
search: { query_total: 19345 },
store: { size_in_bytes: 3199059 }
}
},
timestamp: '2017-08-08T19:16:20.104Z'
},
inner_hits: {
earliest: {
hits: {
hits: [
{
_source: {
index_stats: {
primaries: { indexing: { index_total: 15 } },
total: { search: { query_total: 19345 } }
},
timestamp: '2017-08-08T18:16:28.898Z'
}
}
]
}
}
}
},
{
_source: {
index_stats: {
index: 'cat-tweets-2017.08.08',
primaries: {
docs: { count: 31375 },
indexing: { index_total: 31377 }
},
total: {
search: { query_total: 43155 },
store: { size_in_bytes: 239591867 }
}
},
timestamp: '2017-08-08T19:16:20.104Z'
},
inner_hits: {
earliest: {
hits: {
hits: [
{
_source: {
index_stats: {
primaries: { indexing: { index_total: 23333 } },
total: { search: { query_total: 25675 } }
},
timestamp: '2017-08-08T18:16:28.898Z'
}
}
]
}
}
}
}
]
}
};
const shardStats = {
indices: {
'avocado-tweets-2017.08.08': { status: 'green', primary: 5, replica: 5, unassigned: { primary: 0, replica: 0 } },
'cat-tweets-2017.08.08': { status: 'yellow', primary: 5, replica: 5, unassigned: { primary: 0, replica: 1 } }
}
};
const result = handleResponse(resp, 0, 604800, shardStats);
expect(result).to.eql([
{
name: 'avocado-tweets-2017.08.08',
doc_count: 381,
data_size: 3199059,
index_rate: 0,
search_rate: 0,
status: 'green',
status_sort: 1,
unassigned_shards: 0
},
{
name: 'cat-tweets-2017.08.08',
doc_count: 31375,
data_size: 239591867,
index_rate: 13.30026455026455,
search_rate: 28.902116402116405,
status: 'yellow',
status_sort: 2,
unassigned_shards: 1
}
]);
});

View file

@ -9,8 +9,9 @@ import { checkParam } from '../../error_missing_required';
import { ElasticsearchMetric } from '../../metrics';
import { createQuery } from '../../create_query';
import { calculateRate } from '../../calculate_rate';
import { getUnassignedShards } from '../shards';
export function handleResponse(resp, min, max) {
export function handleResponse(resp, min, max, shardStats) {
// map the hits
const hits = get(resp, 'hits.hits', []);
return hits.map(hit => {
@ -38,17 +39,42 @@ export function handleResponse(resp, min, max) {
...rateOptions
});
const shardStatsForIndex = get(shardStats, ['indices', stats.index]);
let status;
let statusSort;
let unassignedShards;
if (shardStatsForIndex && shardStatsForIndex.status) {
status = shardStatsForIndex.status;
unassignedShards = getUnassignedShards(shardStatsForIndex);
// create a numerical status value for sorting
if (status === 'green') {
statusSort = 1;
} else if (status === 'yellow') {
statusSort = 2;
} else {
statusSort = 3;
}
} else {
status = 'Deleted / Closed';
statusSort = 0;
}
return {
name: stats.index,
status,
doc_count: get(stats, 'primaries.docs.count'),
data_size: get(stats, 'total.store.size_in_bytes'),
index_rate: indexRate,
search_rate: searchRate
search_rate: searchRate,
unassigned_shards: unassignedShards,
status_sort: statusSort
};
});
}
export function getIndices(req, esIndexPattern, showSystemIndices = false) {
export function getIndices(req, esIndexPattern, showSystemIndices = false, shardStats) {
checkParam(esIndexPattern, 'esIndexPattern in elasticsearch/getIndices');
const { min, max } = req.payload.timeRange;
@ -110,5 +136,5 @@ export function getIndices(req, esIndexPattern, showSystemIndices = false) {
const { callWithRequest } = req.server.plugins.elasticsearch.getCluster('monitoring');
return callWithRequest(req, 'search', params)
.then(resp => handleResponse(resp, min, max));
.then(resp => handleResponse(resp, min, max, shardStats));
}

View file

@ -4,12 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { get } from 'lodash';
import Joi from 'joi';
import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats';
import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status';
import { getIndices } from '../../../../lib/elasticsearch/indices';
import { getShardStats, getUnassignedShards } from '../../../../lib/elasticsearch/shards';
import { getShardStats } from '../../../../lib/elasticsearch/shards';
import { handleError } from '../../../../lib/errors/handle_error';
import { prefixIndexPattern } from '../../../../lib/ccs_utils';
@ -22,9 +21,11 @@ export function esIndicesRoute(server) {
params: Joi.object({
clusterUuid: Joi.string().required()
}),
query: Joi.object({
show_system_indices: Joi.boolean()
}),
payload: Joi.object({
ccs: Joi.string().optional(),
showSystemIndices: Joi.boolean().default(false), // show/hide indices in listing
timeRange: Joi.object({
min: Joi.date().required(),
max: Joi.date().required()
@ -34,38 +35,19 @@ export function esIndicesRoute(server) {
},
async handler(req, reply) {
const config = server.config();
const ccs = req.payload.ccs;
const clusterUuid = req.params.clusterUuid;
const showSystemIndices = req.payload.showSystemIndices;
const { clusterUuid } = req.params;
const { show_system_indices: showSystemIndices } = req.query;
const { ccs } = req.payload;
const esIndexPattern = prefixIndexPattern(config, 'xpack.monitoring.elasticsearch.index_pattern', ccs);
try {
const clusterStats = await getClusterStats(req, esIndexPattern, clusterUuid);
const shardStats = await getShardStats(req, esIndexPattern, clusterStats, { includeIndices: true });
const rows = await getIndices(req, esIndexPattern, showSystemIndices);
const mappedRows = rows.map(row => {
const { name } = row;
const shardStatsForIndex = get(shardStats, ['indices', name]);
if (shardStatsForIndex && shardStatsForIndex.status) {
return {
...row,
status: shardStatsForIndex.status,
unassigned_shards: getUnassignedShards(shardStatsForIndex),
};
}
// not in shardStats docs, is a deleted index
return {
name,
status: 'Deleted'
};
});
const indices = await getIndices(req, esIndexPattern, showSystemIndices, shardStats);
reply({
clusterStatus: getClusterStatus(clusterStats, shardStats),
rows: mappedRows
indices
});
} catch(err) {
reply(handleError(err, req));

View file

@ -14,215 +14,261 @@
"unassignedShards": 23,
"totalShards": 46
},
"rows": [
"indices": [
{
"name": "many-0010_dgnlpqtstfvi",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0024_rixhhwzyiczb",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0016_gyvtsyauoqqg",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0006_gkuqbjonkjmg",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 4.0788690476190474,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0022_dqbcjopzejlk",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0020_fqfovcnznbus",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0012_jwomwdgfpisl",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0018_ipugjcmuagih",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0008_amnscruqlsnu",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 4.0788690476190474,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0014_zrukbrvuluby",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "phone-home",
"status": "yellow",
"doc_count": 1,
"data_size": 67798,
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"unassigned_shards": 5
"unassigned_shards": 5,
"status_sort": 2
},
{
"name": "many-0015_vwmrucgzvohb",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0009_reolfgzjjtvh",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0011_xtkcmlwmxcov",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0019_slpgftmneikv",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0017_zpyxggzmytun",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0025_xmvpnfeuqxtp",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0013_smjuwdkhpduv",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0007_milycdknpycp",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0021_xjtlceanhvup",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0.000744047619047619,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0023_hkbvktonytxh",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0005_dnzzblxoumfe",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0004_wzgjkelqclur",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0002_emdkmgdeflno",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0003_jbwrztjwhkjt",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0001_clruksahirti",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
}
]
}

View file

@ -14,287 +14,341 @@
"unassignedShards": 23,
"totalShards": 46
},
"rows": [
"indices": [
{
"name": ".triggered_watches",
"status": "yellow",
"doc_count": 0,
"data_size": 134430,
"index_rate": 0.078125,
"search_rate": 0.001488095238095238,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0010_dgnlpqtstfvi",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0024_rixhhwzyiczb",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": ".watcher-history-7-2017.10.05",
"status": "yellow",
"doc_count": 404,
"data_size": 707598,
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0016_gyvtsyauoqqg",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": ".watcher-history-7-2017.10.06",
"status": "yellow",
"doc_count": 1978,
"data_size": 5256199,
"index_rate": 0.078125,
"search_rate": 0,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0006_gkuqbjonkjmg",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 4.0788690476190474,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": ".monitoring-es-6-2017.10.06",
"status": "yellow",
"doc_count": 2001,
"data_size": 2607666,
"index_rate": 2.2202380952380953,
"search_rate": 2.34375,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0022_dqbcjopzejlk",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0020_fqfovcnznbus",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0012_jwomwdgfpisl",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": ".monitoring-kibana-6-2017.10.06",
"status": "yellow",
"doc_count": 134,
"data_size": 171216,
"index_rate": 0.09672619047619048,
"search_rate": 0.09672619047619048,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0018_ipugjcmuagih",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0008_amnscruqlsnu",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 4.0788690476190474,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": "many-0014_zrukbrvuluby",
"status": "green",
"doc_count": 1,
"data_size": 3821,
"index_rate": 0,
"search_rate": 1.9449404761904763,
"status": "green",
"unassigned_shards": 0
"unassigned_shards": 0,
"status_sort": 1
},
{
"name": ".kibana",
"status": "yellow",
"doc_count": 1,
"data_size": 5406,
"index_rate": 0,
"search_rate": 0.34672619047619047,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": ".monitoring-alerts-6",
"status": "yellow",
"doc_count": 1,
"data_size": 6706,
"index_rate": 0.012648809523809524,
"search_rate": 0.07738095238095238,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "phone-home",
"status": "yellow",
"doc_count": 1,
"data_size": 67798,
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"unassigned_shards": 5
"unassigned_shards": 5,
"status_sort": 2
},
{
"name": ".watches",
"status": "yellow",
"doc_count": 5,
"data_size": 41076,
"index_rate": 0.078125,
"search_rate": 0,
"status": "yellow",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 2
},
{
"name": "many-0015_vwmrucgzvohb",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0009_reolfgzjjtvh",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0011_xtkcmlwmxcov",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0019_slpgftmneikv",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0017_zpyxggzmytun",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0025_xmvpnfeuqxtp",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0013_smjuwdkhpduv",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0007_milycdknpycp",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0021_xjtlceanhvup",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0.000744047619047619,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0023_hkbvktonytxh",
"status": "red",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status": "red",
"unassigned_shards": 1
"unassigned_shards": 1,
"status_sort": 3
},
{
"name": "many-0005_dnzzblxoumfe",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0004_wzgjkelqclur",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0002_emdkmgdeflno",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0003_jbwrztjwhkjt",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
},
{
"name": "many-0001_clruksahirti",
"status": "Deleted"
"status": "Deleted / Closed",
"doc_count": 1,
"data_size": 3728,
"index_rate": 0,
"search_rate": 0,
"status_sort": 0
}
]
}

View file

@ -14,7 +14,7 @@
"unassignedShards": 5,
"totalShards": 80
},
"rows": [
"indices": [
{
"name": "watermelon-tweets-2017.10.05",
"doc_count": 3,
@ -22,6 +22,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
},
{
@ -31,6 +32,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -40,6 +42,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -49,6 +52,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -58,6 +62,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -67,6 +72,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
}
]

View file

@ -14,7 +14,7 @@
"unassignedShards": 5,
"totalShards": 80
},
"rows": [
"indices": [
{
"name": ".triggered_watches",
"doc_count": 0,
@ -22,6 +22,7 @@
"index_rate": 0.08823529411764706,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -31,6 +32,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
},
{
@ -40,6 +42,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -49,6 +52,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -58,6 +62,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -67,6 +72,7 @@
"index_rate": 0.08823529411764706,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -76,6 +82,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -85,6 +92,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -94,6 +102,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -103,6 +112,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -112,6 +122,7 @@
"index_rate": 9.117647058823529,
"search_rate": 1.7352941176470589,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
},
{
@ -121,6 +132,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
},
{
@ -130,6 +142,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -139,6 +152,7 @@
"index_rate": 0,
"search_rate": 0.7058823529411765,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -148,6 +162,7 @@
"index_rate": 0.00980392156862745,
"search_rate": 0.05392156862745098,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -157,6 +172,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -166,6 +182,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -175,6 +192,7 @@
"index_rate": 0.08823529411764706,
"search_rate": 0.00980392156862745,
"status": "green",
"status_sort": 1,
"unassigned_shards": 0
},
{
@ -184,6 +202,7 @@
"index_rate": 0,
"search_rate": 0,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
},
{
@ -193,6 +212,7 @@
"index_rate": 0.08333333333333333,
"search_rate": 0.11764705882352941,
"status": "yellow",
"status_sort": 2,
"unassigned_shards": 1
}
]

View file

@ -32,12 +32,9 @@ export default function ({ getService }) {
it('should summarize the non-system indices with stats', async () => {
const { body } = await supertest
.post('/api/monitoring/v1/clusters/YCxj-RAgSZCP6GuOQ8M1EQ/elasticsearch/indices')
.post('/api/monitoring/v1/clusters/YCxj-RAgSZCP6GuOQ8M1EQ/elasticsearch/indices?show_system_indices=false')
.set('kbn-xsrf', 'xxx')
.send({
timeRange,
showSystemIndices: false
})
.send({ timeRange })
.expect(200);
expect(body).to.eql(relocatingShardsFixture);
@ -45,17 +42,15 @@ export default function ({ getService }) {
it('should summarize all indices with stats', async () => {
const { body } = await supertest
.post('/api/monitoring/v1/clusters/YCxj-RAgSZCP6GuOQ8M1EQ/elasticsearch/indices')
.post('/api/monitoring/v1/clusters/YCxj-RAgSZCP6GuOQ8M1EQ/elasticsearch/indices?show_system_indices=true')
.set('kbn-xsrf', 'xxx')
.send({
timeRange,
showSystemIndices: true
})
.send({ timeRange })
.expect(200);
expect(body).to.eql(relocationShardsAllFixture);
});
});
describe('health-red', () => {
const archive = 'monitoring/singlecluster-red-platinum';
const timeRange = {
@ -73,25 +68,18 @@ export default function ({ getService }) {
it('should summarize the non-system indices with stats', async () => {
const { body } = await supertest
.post('/api/monitoring/v1/clusters/1LYuyvCCQFS3FAO_h65PQw/elasticsearch/indices')
.post('/api/monitoring/v1/clusters/1LYuyvCCQFS3FAO_h65PQw/elasticsearch/indices?show_system_indices=false')
.set('kbn-xsrf', 'xxx')
.send({
timeRange,
showSystemIndices: false
})
.send({ timeRange })
.expect(200);
expect(body).to.eql(indicesRedClusterFixture);
});
it('should summarize all indices with stats', async () => {
const { body } = await supertest
.post('/api/monitoring/v1/clusters/1LYuyvCCQFS3FAO_h65PQw/elasticsearch/indices')
.post('/api/monitoring/v1/clusters/1LYuyvCCQFS3FAO_h65PQw/elasticsearch/indices?show_system_indices=true')
.set('kbn-xsrf', 'xxx')
.send({
timeRange,
showSystemIndices: true
})
.send({ timeRange })
.expect(200);
expect(body).to.eql(indicesRedClusterAllFixture);

View file

@ -94,26 +94,26 @@ export default function ({ getService, getPageObjects }) {
const indicesAll = await indicesList.getIndicesAll();
const tableData = [ /*eslint-disable max-len*/
{ name: 'many-0001_clruksahirti', status: 'Health: Deleted', documentCount: 'N/A', dataSize: 'N/A', indexRate: 'N/A', searchRate: 'N/A', unassignedShards: 'N/A' },
{ name: 'many-0002_emdkmgdeflno', status: 'Health: Deleted', documentCount: 'N/A', dataSize: 'N/A', indexRate: 'N/A', searchRate: 'N/A', unassignedShards: 'N/A' },
{ name: 'many-0003_jbwrztjwhkjt', status: 'Health: Deleted', documentCount: 'N/A', dataSize: 'N/A', indexRate: 'N/A', searchRate: 'N/A', unassignedShards: 'N/A' },
{ name: 'many-0004_wzgjkelqclur', status: 'Health: Deleted', documentCount: 'N/A', dataSize: 'N/A', indexRate: 'N/A', searchRate: 'N/A', unassignedShards: 'N/A' },
{ name: 'many-0005_dnzzblxoumfe', status: 'Health: Deleted', documentCount: 'N/A', dataSize: 'N/A', indexRate: 'N/A', searchRate: 'N/A', unassignedShards: 'N/A' },
{ name: 'many-0006_gkuqbjonkjmg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0' },
{ name: 'many-0008_amnscruqlsnu', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0' },
{ name: 'many-0010_dgnlpqtstfvi', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0012_jwomwdgfpisl', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0014_zrukbrvuluby', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0016_gyvtsyauoqqg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0018_ipugjcmuagih', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0020_fqfovcnznbus', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0022_dqbcjopzejlk', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0024_rixhhwzyiczb', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0' },
{ name: 'many-0007_milycdknpycp', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' },
{ name: 'many-0009_reolfgzjjtvh', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' },
{ name: 'many-0011_xtkcmlwmxcov', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' },
{ name: 'many-0013_smjuwdkhpduv', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' },
{ name: 'many-0015_vwmrucgzvohb', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1' },
{ name: 'many-0006_gkuqbjonkjmg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0', },
{ name: 'many-0008_amnscruqlsnu', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '4.08 /s', unassignedShards: '0', },
{ name: 'many-0010_dgnlpqtstfvi', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0012_jwomwdgfpisl', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0014_zrukbrvuluby', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0016_gyvtsyauoqqg', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0018_ipugjcmuagih', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0020_fqfovcnznbus', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0022_dqbcjopzejlk', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0024_rixhhwzyiczb', status: 'Health: green', documentCount: '1', dataSize: '3.7 KB', indexRate: '0 /s', searchRate: '1.95 /s', unassignedShards: '0', },
{ name: 'many-0001_clruksahirti', status: 'Health: Deleted / Closed', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: 'N/A', },
{ name: 'many-0002_emdkmgdeflno', status: 'Health: Deleted / Closed', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: 'N/A', },
{ name: 'many-0003_jbwrztjwhkjt', status: 'Health: Deleted / Closed', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: 'N/A', },
{ name: 'many-0004_wzgjkelqclur', status: 'Health: Deleted / Closed', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: 'N/A', },
{ name: 'many-0005_dnzzblxoumfe', status: 'Health: Deleted / Closed', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: 'N/A', },
{ name: 'many-0007_milycdknpycp', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1', },
{ name: 'many-0009_reolfgzjjtvh', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1', },
{ name: 'many-0011_xtkcmlwmxcov', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1', },
{ name: 'many-0013_smjuwdkhpduv', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1', },
{ name: 'many-0015_vwmrucgzvohb', status: 'Health: red', documentCount: '1', dataSize: '3.6 KB', indexRate: '0 /s', searchRate: '0 /s', unassignedShards: '1', },
]; /*eslint-enable*/
// check the all data in the table

View file

@ -39,7 +39,7 @@ export default function ({ getService, getPageObjects }) {
unassignedShards: '5',
documentCount: '25,927',
dataSize: '101.6 MB',
health: 'Status: yellow',
health: 'Health: yellow',
});
});

View file

@ -39,7 +39,7 @@ export default function ({ getService, getPageObjects }) {
unassignedShards: '5',
documentCount: '25,927',
dataSize: '101.6 MB',
health: 'Status: yellow',
health: 'Health: yellow',
});
});
});

View file

@ -13,13 +13,13 @@ export function MonitoringElasticsearchIndicesProvider({ getService, getPageObje
const SUBJ_LISTING_PAGE = 'elasticsearchIndicesListingPage';
const SUBJ_TABLE_CONTAINER = 'indicesTableContainer';
const SUBJ_TABLE_CONTAINER = 'elasticsearchIndicesTableContainer';
const SUBJ_TABLE_NO_DATA = `${SUBJ_TABLE_CONTAINER} monitoringTableNoData`;
const SUBJ_SEARCH_BAR = `${SUBJ_TABLE_CONTAINER} monitoringTableToolBar`;
const SUBJ_TABLE_SORT_SEARCH_COL = `${SUBJ_TABLE_CONTAINER} tableHeaderCell-searchRate`;
const SUBJ_TABLE_BODY = 'indicesTableBody';
const SUBJ_TABLE_BODY = 'elasticsearchIndicesTableBody';
const SUBJ_INDICES_NAMES = `${SUBJ_TABLE_BODY} name`;
const SUBJ_INDICES_STATUSES = `${SUBJ_TABLE_BODY} statusIcon`;
const SUBJ_INDICES_DOCUMENT_COUNTS = `${SUBJ_TABLE_BODY} documentCount`;