mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 03:01:21 -04:00
[Index Management] Disable index stats on serverless (#163849)
This commit is contained in:
parent
615c450b37
commit
a14f76d96c
29 changed files with 406 additions and 102 deletions
|
@ -37,6 +37,8 @@ xpack.license_management.enabled: false
|
||||||
xpack.index_management.enableIndexActions: false
|
xpack.index_management.enableIndexActions: false
|
||||||
# Disable legacy index templates from Index Management UI
|
# Disable legacy index templates from Index Management UI
|
||||||
xpack.index_management.enableLegacyTemplates: false
|
xpack.index_management.enableLegacyTemplates: false
|
||||||
|
# Disable index stats information from Index Management UI
|
||||||
|
xpack.index_management.enableIndexStats: false
|
||||||
|
|
||||||
# Keep deeplinks visible so that they are shown in the sidenav
|
# Keep deeplinks visible so that they are shown in the sidenav
|
||||||
dev_tools.deeplinks.navLinkStatus: visible
|
dev_tools.deeplinks.navLinkStatus: visible
|
||||||
|
|
|
@ -243,6 +243,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
|
||||||
'xpack.index_management.enableIndexActions (any)',
|
'xpack.index_management.enableIndexActions (any)',
|
||||||
'xpack.index_management.enableLegacyTemplates (any)',
|
'xpack.index_management.enableLegacyTemplates (any)',
|
||||||
'xpack.index_management.dev.enableIndexDetailsPage (boolean)',
|
'xpack.index_management.dev.enableIndexDetailsPage (boolean)',
|
||||||
|
'xpack.index_management.enableIndexStats (any)',
|
||||||
'xpack.infra.sources.default.fields.message (array)',
|
'xpack.infra.sources.default.fields.message (array)',
|
||||||
/**
|
/**
|
||||||
* xpack.infra.logs is conditional and will resolve to an object of properties
|
* xpack.infra.logs is conditional and will resolve to an object of properties
|
||||||
|
|
|
@ -80,7 +80,7 @@ const indexWithLifecyclePolicy: Index = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const indexWithLifecycleError = {
|
const indexWithLifecycleError: Index = {
|
||||||
health: 'yellow',
|
health: 'yellow',
|
||||||
status: 'open',
|
status: 'open',
|
||||||
name: 'testy3',
|
name: 'testy3',
|
||||||
|
|
|
@ -60,6 +60,7 @@ const appDependencies = {
|
||||||
config: {
|
config: {
|
||||||
enableLegacyTemplates: true,
|
enableLegacyTemplates: true,
|
||||||
enableIndexActions: true,
|
enableIndexActions: true,
|
||||||
|
enableIndexStats: true,
|
||||||
},
|
},
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ export type TestSubjects =
|
||||||
| 'deleteSystemTemplateCallOut'
|
| 'deleteSystemTemplateCallOut'
|
||||||
| 'deleteTemplateButton'
|
| 'deleteTemplateButton'
|
||||||
| 'deleteTemplatesConfirmation'
|
| 'deleteTemplatesConfirmation'
|
||||||
|
| 'descriptionTitle'
|
||||||
| 'documentationLink'
|
| 'documentationLink'
|
||||||
| 'emptyPrompt'
|
| 'emptyPrompt'
|
||||||
| 'forcemergeIndexMenuButton'
|
| 'forcemergeIndexMenuButton'
|
||||||
|
|
|
@ -62,14 +62,13 @@ describe('<IndexManagementHome />', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
httpRequestsMockHelpers.setLoadIndicesResponse([]);
|
httpRequestsMockHelpers.setLoadIndicesResponse([]);
|
||||||
|
|
||||||
testBed = await setup(httpSetup);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
const { component } = testBed;
|
testBed = await setup(httpSetup);
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
component.update();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { component } = testBed;
|
||||||
|
|
||||||
|
component.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toggles the include hidden button through URL hash correctly', () => {
|
test('toggles the include hidden button through URL hash correctly', () => {
|
||||||
|
@ -423,4 +422,103 @@ describe('<IndexManagementHome />', () => {
|
||||||
expect(exists('updateIndexSettingsErrorCallout')).toBe(true);
|
expect(exists('updateIndexSettingsErrorCallout')).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Index stats', () => {
|
||||||
|
const indexName = 'test';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
httpRequestsMockHelpers.setLoadIndicesResponse([createNonDataStreamIndex(indexName)]);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
testBed = await setup(httpSetup);
|
||||||
|
});
|
||||||
|
|
||||||
|
const { component } = testBed;
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders the table column with index stats by default', () => {
|
||||||
|
const { table } = testBed;
|
||||||
|
const { tableCellsValues } = table.getMetaData('indexTable');
|
||||||
|
|
||||||
|
expect(tableCellsValues).toEqual([
|
||||||
|
['', 'test', 'green', 'open', '1', '1', '10000', '156kb', ''],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders index stats in details flyout by default', async () => {
|
||||||
|
const { component, find } = testBed;
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
find('indexTableIndexNameLink').at(0).simulate('click');
|
||||||
|
});
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
const descriptions = find('descriptionTitle');
|
||||||
|
|
||||||
|
const descriptionText = descriptions
|
||||||
|
.map((description) => {
|
||||||
|
return description.text();
|
||||||
|
})
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
expect(descriptionText).toEqual([
|
||||||
|
'Aliases',
|
||||||
|
'Docs count',
|
||||||
|
'Docs deleted',
|
||||||
|
'Health',
|
||||||
|
'Primaries',
|
||||||
|
'Primary storage size',
|
||||||
|
'Replicas',
|
||||||
|
'Status',
|
||||||
|
'Storage size',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Disabled', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await act(async () => {
|
||||||
|
testBed = await setup(httpSetup, {
|
||||||
|
config: {
|
||||||
|
enableLegacyTemplates: true,
|
||||||
|
enableIndexActions: true,
|
||||||
|
enableIndexStats: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const { component } = testBed;
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hides index stats information from table', async () => {
|
||||||
|
const { table } = testBed;
|
||||||
|
const { tableCellsValues } = table.getMetaData('indexTable');
|
||||||
|
|
||||||
|
expect(tableCellsValues).toEqual([['', 'test', '1', '1', '']]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('hides index stats information from details panel', async () => {
|
||||||
|
const { component, find } = testBed;
|
||||||
|
await act(async () => {
|
||||||
|
find('indexTableIndexNameLink').at(0).simulate('click');
|
||||||
|
});
|
||||||
|
|
||||||
|
component.update();
|
||||||
|
|
||||||
|
const descriptions = find('descriptionTitle');
|
||||||
|
|
||||||
|
const descriptionText = descriptions
|
||||||
|
.map((description) => {
|
||||||
|
return description.text();
|
||||||
|
})
|
||||||
|
.sort();
|
||||||
|
|
||||||
|
expect(descriptionText).toEqual(['Aliases', 'Primaries', 'Replicas']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -172,6 +172,7 @@ describe('index table', () => {
|
||||||
config: {
|
config: {
|
||||||
enableLegacyTemplates: true,
|
enableLegacyTemplates: true,
|
||||||
enableIndexActions: true,
|
enableIndexActions: true,
|
||||||
|
enableIndexStats: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,12 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
HealthStatus,
|
||||||
|
IndicesStatsIndexMetadataState,
|
||||||
|
Uuid,
|
||||||
|
} from '@elastic/elasticsearch/lib/api/types';
|
||||||
|
|
||||||
interface IndexModule {
|
interface IndexModule {
|
||||||
number_of_shards: number | string;
|
number_of_shards: number | string;
|
||||||
codec: string;
|
codec: string;
|
||||||
|
@ -50,21 +56,21 @@ export interface IndexSettings {
|
||||||
analysis?: AnalysisModule;
|
analysis?: AnalysisModule;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Index {
|
export interface Index {
|
||||||
health?: string;
|
|
||||||
status?: string;
|
|
||||||
name: string;
|
name: string;
|
||||||
uuid?: string;
|
|
||||||
primary?: number | string;
|
primary?: number | string;
|
||||||
replica?: number | string;
|
replica?: number | string;
|
||||||
documents: number;
|
|
||||||
documents_deleted: number;
|
|
||||||
size: string;
|
|
||||||
primary_size: string;
|
|
||||||
isFrozen: boolean;
|
isFrozen: boolean;
|
||||||
hidden: boolean;
|
hidden: boolean;
|
||||||
aliases: string | string[];
|
aliases: string | string[];
|
||||||
data_stream?: string;
|
data_stream?: string;
|
||||||
[key: string]: any;
|
// The types from here below represent information returned from the index stats API;
|
||||||
|
// treated optional as the stats API is not available on serverless
|
||||||
|
health?: HealthStatus;
|
||||||
|
status?: IndicesStatsIndexMetadataState;
|
||||||
|
uuid?: Uuid;
|
||||||
|
documents?: number;
|
||||||
|
size?: string;
|
||||||
|
primary_size?: string;
|
||||||
|
documents_deleted?: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ export interface AppDependencies {
|
||||||
enableIndexActions: boolean;
|
enableIndexActions: boolean;
|
||||||
enableLegacyTemplates: boolean;
|
enableLegacyTemplates: boolean;
|
||||||
enableIndexDetailsPage: boolean;
|
enableIndexDetailsPage: boolean;
|
||||||
|
enableIndexStats: boolean;
|
||||||
};
|
};
|
||||||
history: ScopedHistory;
|
history: ScopedHistory;
|
||||||
setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs'];
|
setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs'];
|
||||||
|
|
|
@ -56,6 +56,7 @@ export async function mountManagementSection({
|
||||||
enableIndexActions = true,
|
enableIndexActions = true,
|
||||||
enableLegacyTemplates = true,
|
enableLegacyTemplates = true,
|
||||||
enableIndexDetailsPage = false,
|
enableIndexDetailsPage = false,
|
||||||
|
enableIndexStats = true,
|
||||||
}: {
|
}: {
|
||||||
coreSetup: CoreSetup<StartDependencies>;
|
coreSetup: CoreSetup<StartDependencies>;
|
||||||
usageCollection: UsageCollectionSetup;
|
usageCollection: UsageCollectionSetup;
|
||||||
|
@ -66,6 +67,7 @@ export async function mountManagementSection({
|
||||||
enableIndexActions?: boolean;
|
enableIndexActions?: boolean;
|
||||||
enableLegacyTemplates?: boolean;
|
enableLegacyTemplates?: boolean;
|
||||||
enableIndexDetailsPage?: boolean;
|
enableIndexDetailsPage?: boolean;
|
||||||
|
enableIndexStats?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const { element, setBreadcrumbs, history, theme$ } = params;
|
const { element, setBreadcrumbs, history, theme$ } = params;
|
||||||
const [core, startDependencies] = await coreSetup.getStartServices();
|
const [core, startDependencies] = await coreSetup.getStartServices();
|
||||||
|
@ -111,6 +113,7 @@ export async function mountManagementSection({
|
||||||
enableIndexActions,
|
enableIndexActions,
|
||||||
enableLegacyTemplates,
|
enableLegacyTemplates,
|
||||||
enableIndexDetailsPage,
|
enableIndexDetailsPage,
|
||||||
|
enableIndexStats,
|
||||||
},
|
},
|
||||||
history,
|
history,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
|
|
|
@ -34,7 +34,7 @@ import { IndexActionsContextMenu } from '../index_actions_context_menu';
|
||||||
import { ShowJson } from './show_json';
|
import { ShowJson } from './show_json';
|
||||||
import { Summary } from './summary';
|
import { Summary } from './summary';
|
||||||
import { EditSettingsJson } from './edit_settings_json';
|
import { EditSettingsJson } from './edit_settings_json';
|
||||||
import { useServices } from '../../../../app_context';
|
import { useServices, useAppContext } from '../../../../app_context';
|
||||||
import { renderDiscoverLink } from '../../../../lib/render_discover_link';
|
import { renderDiscoverLink } from '../../../../lib/render_discover_link';
|
||||||
|
|
||||||
const tabToHumanizedMap = {
|
const tabToHumanizedMap = {
|
||||||
|
@ -58,12 +58,19 @@ const tabToHumanizedMap = {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs = [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_STATS, TAB_EDIT_SETTINGS];
|
const getTabs = (showStats) => {
|
||||||
|
if (showStats) {
|
||||||
|
return [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_STATS, TAB_EDIT_SETTINGS];
|
||||||
|
}
|
||||||
|
return [TAB_SUMMARY, TAB_SETTINGS, TAB_MAPPING, TAB_EDIT_SETTINGS];
|
||||||
|
};
|
||||||
|
|
||||||
export const DetailPanel = ({ panelType, indexName, index, openDetailPanel, closeDetailPanel }) => {
|
export const DetailPanel = ({ panelType, indexName, index, openDetailPanel, closeDetailPanel }) => {
|
||||||
const { extensionsService } = useServices();
|
const { extensionsService } = useServices();
|
||||||
|
const { config } = useAppContext();
|
||||||
|
|
||||||
const renderTabs = () => {
|
const renderTabs = () => {
|
||||||
|
const tabs = getTabs(config.enableIndexStats);
|
||||||
return tabs.map((tab, i) => {
|
return tabs.map((tab, i) => {
|
||||||
const isSelected = tab === panelType;
|
const isSelected = tab === panelType;
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -21,36 +21,43 @@ import {
|
||||||
import { DataHealth } from '../../../../../components';
|
import { DataHealth } from '../../../../../components';
|
||||||
import { AppContextConsumer } from '../../../../../app_context';
|
import { AppContextConsumer } from '../../../../../app_context';
|
||||||
|
|
||||||
const getHeaders = () => {
|
const getHeaders = (showStats) => {
|
||||||
return {
|
const baseHeaders = {
|
||||||
health: i18n.translate('xpack.idxMgmt.summary.headers.healthHeader', {
|
|
||||||
defaultMessage: 'Health',
|
|
||||||
}),
|
|
||||||
status: i18n.translate('xpack.idxMgmt.summary.headers.statusHeader', {
|
|
||||||
defaultMessage: 'Status',
|
|
||||||
}),
|
|
||||||
primary: i18n.translate('xpack.idxMgmt.summary.headers.primaryHeader', {
|
primary: i18n.translate('xpack.idxMgmt.summary.headers.primaryHeader', {
|
||||||
defaultMessage: 'Primaries',
|
defaultMessage: 'Primaries',
|
||||||
}),
|
}),
|
||||||
replica: i18n.translate('xpack.idxMgmt.summary.headers.replicaHeader', {
|
replica: i18n.translate('xpack.idxMgmt.summary.headers.replicaHeader', {
|
||||||
defaultMessage: 'Replicas',
|
defaultMessage: 'Replicas',
|
||||||
}),
|
}),
|
||||||
documents: i18n.translate('xpack.idxMgmt.summary.headers.documentsHeader', {
|
|
||||||
defaultMessage: 'Docs count',
|
|
||||||
}),
|
|
||||||
documents_deleted: i18n.translate('xpack.idxMgmt.summary.headers.deletedDocumentsHeader', {
|
|
||||||
defaultMessage: 'Docs deleted',
|
|
||||||
}),
|
|
||||||
size: i18n.translate('xpack.idxMgmt.summary.headers.storageSizeHeader', {
|
|
||||||
defaultMessage: 'Storage size',
|
|
||||||
}),
|
|
||||||
primary_size: i18n.translate('xpack.idxMgmt.summary.headers.primaryStorageSizeHeader', {
|
|
||||||
defaultMessage: 'Primary storage size',
|
|
||||||
}),
|
|
||||||
aliases: i18n.translate('xpack.idxMgmt.summary.headers.aliases', {
|
aliases: i18n.translate('xpack.idxMgmt.summary.headers.aliases', {
|
||||||
defaultMessage: 'Aliases',
|
defaultMessage: 'Aliases',
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (showStats) {
|
||||||
|
return {
|
||||||
|
...baseHeaders,
|
||||||
|
health: i18n.translate('xpack.idxMgmt.summary.headers.healthHeader', {
|
||||||
|
defaultMessage: 'Health',
|
||||||
|
}),
|
||||||
|
status: i18n.translate('xpack.idxMgmt.summary.headers.statusHeader', {
|
||||||
|
defaultMessage: 'Status',
|
||||||
|
}),
|
||||||
|
documents: i18n.translate('xpack.idxMgmt.summary.headers.documentsHeader', {
|
||||||
|
defaultMessage: 'Docs count',
|
||||||
|
}),
|
||||||
|
documents_deleted: i18n.translate('xpack.idxMgmt.summary.headers.deletedDocumentsHeader', {
|
||||||
|
defaultMessage: 'Docs deleted',
|
||||||
|
}),
|
||||||
|
size: i18n.translate('xpack.idxMgmt.summary.headers.storageSizeHeader', {
|
||||||
|
defaultMessage: 'Storage size',
|
||||||
|
}),
|
||||||
|
primary_size: i18n.translate('xpack.idxMgmt.summary.headers.primaryStorageSizeHeader', {
|
||||||
|
defaultMessage: 'Primary storage size',
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return baseHeaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Summary extends React.PureComponent {
|
export class Summary extends React.PureComponent {
|
||||||
|
@ -67,9 +74,9 @@ export class Summary extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildRows() {
|
buildRows(config) {
|
||||||
const { index } = this.props;
|
const { index } = this.props;
|
||||||
const headers = getHeaders();
|
const headers = getHeaders(config.enableIndexStats);
|
||||||
const rows = {
|
const rows = {
|
||||||
left: [],
|
left: [],
|
||||||
right: [],
|
right: [],
|
||||||
|
@ -84,7 +91,7 @@ export class Summary extends React.PureComponent {
|
||||||
content = content.join(', ');
|
content = content.join(', ');
|
||||||
}
|
}
|
||||||
const cell = [
|
const cell = [
|
||||||
<EuiDescriptionListTitle key={fieldName}>
|
<EuiDescriptionListTitle key={fieldName} data-test-subj="descriptionTitle">
|
||||||
<strong>{headers[fieldName]}</strong>
|
<strong>{headers[fieldName]}</strong>
|
||||||
</EuiDescriptionListTitle>,
|
</EuiDescriptionListTitle>,
|
||||||
<EuiDescriptionListDescription key={fieldName + '_desc'}>
|
<EuiDescriptionListDescription key={fieldName + '_desc'}>
|
||||||
|
@ -103,8 +110,8 @@ export class Summary extends React.PureComponent {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<AppContextConsumer>
|
<AppContextConsumer>
|
||||||
{({ services, core }) => {
|
{({ services, core, config }) => {
|
||||||
const { left, right } = this.buildRows();
|
const { left, right } = this.buildRows(config);
|
||||||
const additionalContent = this.getAdditionalContent(
|
const additionalContent = this.getAdditionalContent(
|
||||||
services.extensionsService,
|
services.extensionsService,
|
||||||
core.getUrlForApp
|
core.getUrlForApp
|
||||||
|
|
|
@ -51,31 +51,46 @@ import { renderBadges } from '../../../../lib/render_badges';
|
||||||
import { NoMatch, DataHealth } from '../../../../components';
|
import { NoMatch, DataHealth } from '../../../../components';
|
||||||
import { IndexActionsContextMenu } from '../index_actions_context_menu';
|
import { IndexActionsContextMenu } from '../index_actions_context_menu';
|
||||||
|
|
||||||
const HEADERS = {
|
const getHeaders = ({ showIndexStats }) => {
|
||||||
name: i18n.translate('xpack.idxMgmt.indexTable.headers.nameHeader', {
|
const headers = {};
|
||||||
|
|
||||||
|
headers.name = i18n.translate('xpack.idxMgmt.indexTable.headers.nameHeader', {
|
||||||
defaultMessage: 'Name',
|
defaultMessage: 'Name',
|
||||||
}),
|
});
|
||||||
health: i18n.translate('xpack.idxMgmt.indexTable.headers.healthHeader', {
|
|
||||||
defaultMessage: 'Health',
|
if (showIndexStats) {
|
||||||
}),
|
headers.health = i18n.translate('xpack.idxMgmt.indexTable.headers.healthHeader', {
|
||||||
status: i18n.translate('xpack.idxMgmt.indexTable.headers.statusHeader', {
|
defaultMessage: 'Health',
|
||||||
defaultMessage: 'Status',
|
});
|
||||||
}),
|
|
||||||
primary: i18n.translate('xpack.idxMgmt.indexTable.headers.primaryHeader', {
|
headers.status = i18n.translate('xpack.idxMgmt.indexTable.headers.statusHeader', {
|
||||||
|
defaultMessage: 'Status',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
headers.primary = i18n.translate('xpack.idxMgmt.indexTable.headers.primaryHeader', {
|
||||||
defaultMessage: 'Primaries',
|
defaultMessage: 'Primaries',
|
||||||
}),
|
});
|
||||||
replica: i18n.translate('xpack.idxMgmt.indexTable.headers.replicaHeader', {
|
|
||||||
|
headers.replica = i18n.translate('xpack.idxMgmt.indexTable.headers.replicaHeader', {
|
||||||
defaultMessage: 'Replicas',
|
defaultMessage: 'Replicas',
|
||||||
}),
|
});
|
||||||
documents: i18n.translate('xpack.idxMgmt.indexTable.headers.documentsHeader', {
|
|
||||||
defaultMessage: 'Docs count',
|
if (showIndexStats) {
|
||||||
}),
|
headers.documents = i18n.translate('xpack.idxMgmt.indexTable.headers.documentsHeader', {
|
||||||
size: i18n.translate('xpack.idxMgmt.indexTable.headers.storageSizeHeader', {
|
defaultMessage: 'Docs count',
|
||||||
defaultMessage: 'Storage size',
|
});
|
||||||
}),
|
|
||||||
data_stream: i18n.translate('xpack.idxMgmt.indexTable.headers.dataStreamHeader', {
|
headers.size = i18n.translate('xpack.idxMgmt.indexTable.headers.storageSizeHeader', {
|
||||||
|
defaultMessage: 'Storage size',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
headers.data_stream = i18n.translate('xpack.idxMgmt.indexTable.headers.dataStreamHeader', {
|
||||||
defaultMessage: 'Data stream',
|
defaultMessage: 'Data stream',
|
||||||
}),
|
});
|
||||||
|
|
||||||
|
return headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class IndexTable extends Component {
|
export class IndexTable extends Component {
|
||||||
|
@ -246,9 +261,10 @@ export class IndexTable extends Component {
|
||||||
return indexOfUnselectedItem === -1;
|
return indexOfUnselectedItem === -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
buildHeader() {
|
buildHeader(config) {
|
||||||
const { sortField, isSortAscending } = this.props;
|
const { sortField, isSortAscending } = this.props;
|
||||||
return Object.entries(HEADERS).map(([fieldName, label]) => {
|
const headers = getHeaders({ showIndexStats: config.enableIndexStats });
|
||||||
|
return Object.entries(headers).map(([fieldName, label]) => {
|
||||||
const isSorted = sortField === fieldName;
|
const isSorted = sortField === fieldName;
|
||||||
return (
|
return (
|
||||||
<EuiTableHeaderCell
|
<EuiTableHeaderCell
|
||||||
|
@ -302,8 +318,9 @@ export class IndexTable extends Component {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildRowCells(index, appServices) {
|
buildRowCells(index, appServices, config) {
|
||||||
return Object.keys(HEADERS).map((fieldName) => {
|
const headers = getHeaders({ showIndexStats: config.enableIndexStats });
|
||||||
|
return Object.keys(headers).map((fieldName) => {
|
||||||
const { name } = index;
|
const { name } = index;
|
||||||
const value = index[fieldName];
|
const value = index[fieldName];
|
||||||
|
|
||||||
|
@ -363,7 +380,7 @@ export class IndexTable extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildRows(appServices) {
|
buildRows(appServices, config) {
|
||||||
const { indices = [], detailPanelIndexName } = this.props;
|
const { indices = [], detailPanelIndexName } = this.props;
|
||||||
return indices.map((index) => {
|
return indices.map((index) => {
|
||||||
const { name } = index;
|
const { name } = index;
|
||||||
|
@ -388,7 +405,7 @@ export class IndexTable extends Component {
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
</EuiTableRowCellCheckbox>
|
</EuiTableRowCellCheckbox>
|
||||||
{this.buildRowCells(index, appServices)}
|
{this.buildRowCells(index, appServices, config)}
|
||||||
</EuiTableRow>
|
</EuiTableRow>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -479,7 +496,7 @@ export class IndexTable extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContextConsumer>
|
<AppContextConsumer>
|
||||||
{({ services }) => {
|
{({ services, config }) => {
|
||||||
const { extensionsService } = services;
|
const { extensionsService } = services;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -639,10 +656,10 @@ export class IndexTable extends Component {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</EuiTableHeaderCellCheckbox>
|
</EuiTableHeaderCellCheckbox>
|
||||||
{this.buildHeader()}
|
{this.buildHeader(config)}
|
||||||
</EuiTableHeader>
|
</EuiTableHeader>
|
||||||
|
|
||||||
<EuiTableBody>{this.buildRows(services)}</EuiTableBody>
|
<EuiTableBody>{this.buildRows(services, config)}</EuiTableBody>
|
||||||
</EuiTable>
|
</EuiTable>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -123,15 +123,19 @@ export const getPageOfIndices = createSelector(
|
||||||
const { firstItemIndex, lastItemIndex } = pager;
|
const { firstItemIndex, lastItemIndex } = pager;
|
||||||
const pagedIndexes = sortedIndexes.slice(firstItemIndex, lastItemIndex + 1);
|
const pagedIndexes = sortedIndexes.slice(firstItemIndex, lastItemIndex + 1);
|
||||||
return pagedIndexes.map((index) => {
|
return pagedIndexes.map((index) => {
|
||||||
const status =
|
if (index.status) {
|
||||||
indexStatusLabels[rowStatuses[index.name]] || // user friendly version of row status
|
const status =
|
||||||
rowStatuses[index.name] || // row status
|
indexStatusLabels[rowStatuses[index.name]] || // user friendly version of row status
|
||||||
indexStatusLabels[index.status] || // user friendly version of index status
|
rowStatuses[index.name] || // row status
|
||||||
index.status; // index status
|
indexStatusLabels[index.status] || // user friendly version of index status
|
||||||
return {
|
index.status; // index status
|
||||||
...index,
|
return {
|
||||||
status,
|
...index,
|
||||||
};
|
status,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -40,6 +40,7 @@ export class IndexMgmtUIPlugin {
|
||||||
ui: { enabled: isIndexManagementUiEnabled },
|
ui: { enabled: isIndexManagementUiEnabled },
|
||||||
enableIndexActions,
|
enableIndexActions,
|
||||||
enableLegacyTemplates,
|
enableLegacyTemplates,
|
||||||
|
enableIndexStats,
|
||||||
dev: { enableIndexDetailsPage },
|
dev: { enableIndexDetailsPage },
|
||||||
} = this.ctx.config.get<ClientConfigType>();
|
} = this.ctx.config.get<ClientConfigType>();
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ export class IndexMgmtUIPlugin {
|
||||||
enableIndexActions,
|
enableIndexActions,
|
||||||
enableLegacyTemplates,
|
enableLegacyTemplates,
|
||||||
enableIndexDetailsPage,
|
enableIndexDetailsPage,
|
||||||
|
enableIndexStats,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -31,6 +31,7 @@ export interface ClientConfigType {
|
||||||
};
|
};
|
||||||
enableIndexActions?: boolean;
|
enableIndexActions?: boolean;
|
||||||
enableLegacyTemplates?: boolean;
|
enableLegacyTemplates?: boolean;
|
||||||
|
enableIndexStats?: boolean;
|
||||||
dev: {
|
dev: {
|
||||||
enableIndexDetailsPage?: boolean;
|
enableIndexDetailsPage?: boolean;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,6 +33,11 @@ const schemaLatest = schema.object(
|
||||||
serverless: schema.boolean({ defaultValue: true }),
|
serverless: schema.boolean({ defaultValue: true }),
|
||||||
}),
|
}),
|
||||||
dev: schema.object({ enableIndexDetailsPage: schema.boolean({ defaultValue: false }) }),
|
dev: schema.object({ enableIndexDetailsPage: schema.boolean({ defaultValue: false }) }),
|
||||||
|
enableIndexStats: offeringBasedSchema({
|
||||||
|
// Index stats information is disabled in serverless; refer to the serverless.yml file as the source of truth
|
||||||
|
// We take this approach in order to have a central place (serverless.yml) for serverless config across Kibana
|
||||||
|
serverless: schema.boolean({ defaultValue: true }),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ defaultValue: undefined }
|
{ defaultValue: undefined }
|
||||||
);
|
);
|
||||||
|
@ -45,6 +50,7 @@ const configLatest: PluginConfigDescriptor<IndexManagementConfig> = {
|
||||||
dev: {
|
dev: {
|
||||||
enableIndexDetailsPage: true,
|
enableIndexDetailsPage: true,
|
||||||
},
|
},
|
||||||
|
enableIndexStats: true,
|
||||||
},
|
},
|
||||||
schema: schemaLatest,
|
schema: schemaLatest,
|
||||||
deprecations: () => [],
|
deprecations: () => [],
|
||||||
|
|
|
@ -9,9 +9,11 @@ import { ByteSizeValue } from '@kbn/config-schema';
|
||||||
import { IScopedClusterClient } from '@kbn/core/server';
|
import { IScopedClusterClient } from '@kbn/core/server';
|
||||||
import { IndexDataEnricher } from '../services';
|
import { IndexDataEnricher } from '../services';
|
||||||
import { Index } from '..';
|
import { Index } from '..';
|
||||||
|
import { RouteDependencies } from '../types';
|
||||||
|
|
||||||
async function fetchIndicesCall(
|
async function fetchIndicesCall(
|
||||||
client: IScopedClusterClient,
|
client: IScopedClusterClient,
|
||||||
|
config: RouteDependencies['config'],
|
||||||
indexNames?: string[]
|
indexNames?: string[]
|
||||||
): Promise<Index[]> {
|
): Promise<Index[]> {
|
||||||
const indexNamesString = indexNames && indexNames.length ? indexNames.join(',') : '*';
|
const indexNamesString = indexNames && indexNames.length ? indexNames.join(',') : '*';
|
||||||
|
@ -38,41 +40,77 @@ async function fetchIndicesCall(
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { indices: indicesStats = {} } = await client.asCurrentUser.indices.stats({
|
const indicesNames = Object.keys(indices);
|
||||||
|
|
||||||
|
// Return response without index stats, if isIndexStatsEnabled === false
|
||||||
|
if (config.isIndexStatsEnabled === false) {
|
||||||
|
return indicesNames.map((indexName: string) => {
|
||||||
|
const indexData = indices[indexName];
|
||||||
|
const aliases = Object.keys(indexData.aliases!);
|
||||||
|
return {
|
||||||
|
name: indexName,
|
||||||
|
primary: indexData.settings?.index?.number_of_shards,
|
||||||
|
replica: indexData.settings?.index?.number_of_replicas,
|
||||||
|
isFrozen: indexData.settings?.index?.frozen === 'true',
|
||||||
|
aliases: aliases.length ? aliases : 'none',
|
||||||
|
hidden: indexData.settings?.index?.hidden === 'true',
|
||||||
|
data_stream: indexData.data_stream,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { indices: indicesStats } = await client.asCurrentUser.indices.stats({
|
||||||
index: indexNamesString,
|
index: indexNamesString,
|
||||||
expand_wildcards: ['hidden', 'all'],
|
expand_wildcards: ['hidden', 'all'],
|
||||||
forbid_closed_indices: false,
|
forbid_closed_indices: false,
|
||||||
metric: ['docs', 'store'],
|
metric: ['docs', 'store'],
|
||||||
});
|
});
|
||||||
const indicesNames = Object.keys(indices);
|
|
||||||
return indicesNames.map((indexName: string) => {
|
return indicesNames.map((indexName: string) => {
|
||||||
const indexData = indices[indexName];
|
const indexData = indices[indexName];
|
||||||
const indexStats = indicesStats[indexName];
|
|
||||||
const aliases = Object.keys(indexData.aliases!);
|
const aliases = Object.keys(indexData.aliases!);
|
||||||
return {
|
const baseResponse = {
|
||||||
health: indexStats?.health,
|
|
||||||
status: indexStats?.status,
|
|
||||||
name: indexName,
|
name: indexName,
|
||||||
uuid: indexStats?.uuid,
|
|
||||||
primary: indexData.settings?.index?.number_of_shards,
|
primary: indexData.settings?.index?.number_of_shards,
|
||||||
replica: indexData.settings?.index?.number_of_replicas,
|
replica: indexData.settings?.index?.number_of_replicas,
|
||||||
documents: indexStats?.primaries?.docs?.count ?? 0,
|
|
||||||
documents_deleted: indexStats?.primaries?.docs?.deleted ?? 0,
|
|
||||||
size: new ByteSizeValue(indexStats?.total?.store?.size_in_bytes ?? 0).toString(),
|
|
||||||
primary_size: new ByteSizeValue(indexStats?.primaries?.store?.size_in_bytes ?? 0).toString(),
|
|
||||||
isFrozen: indexData.settings?.index?.frozen === 'true',
|
isFrozen: indexData.settings?.index?.frozen === 'true',
|
||||||
aliases: aliases.length ? aliases : 'none',
|
aliases: aliases.length ? aliases : 'none',
|
||||||
hidden: indexData.settings?.index?.hidden === 'true',
|
hidden: indexData.settings?.index?.hidden === 'true',
|
||||||
data_stream: indexData.data_stream,
|
data_stream: indexData.data_stream,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (indicesStats) {
|
||||||
|
const indexStats = indicesStats[indexName];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...baseResponse,
|
||||||
|
health: indexStats?.health,
|
||||||
|
status: indexStats?.status,
|
||||||
|
uuid: indexStats?.uuid,
|
||||||
|
documents: indexStats?.primaries?.docs?.count ?? 0,
|
||||||
|
documents_deleted: indexStats?.primaries?.docs?.deleted ?? 0,
|
||||||
|
size: new ByteSizeValue(indexStats?.total?.store?.size_in_bytes ?? 0).toString(),
|
||||||
|
primary_size: new ByteSizeValue(
|
||||||
|
indexStats?.primaries?.store?.size_in_bytes ?? 0
|
||||||
|
).toString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return baseResponse;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchIndices = async (
|
export const fetchIndices = async ({
|
||||||
client: IScopedClusterClient,
|
client,
|
||||||
indexDataEnricher: IndexDataEnricher,
|
indexDataEnricher,
|
||||||
indexNames?: string[]
|
config,
|
||||||
) => {
|
indexNames,
|
||||||
const indices = await fetchIndicesCall(client, indexNames);
|
}: {
|
||||||
|
client: IScopedClusterClient;
|
||||||
|
indexDataEnricher: IndexDataEnricher;
|
||||||
|
config: RouteDependencies['config'];
|
||||||
|
indexNames?: string[];
|
||||||
|
}) => {
|
||||||
|
const indices = await fetchIndicesCall(client, config, indexNames);
|
||||||
return await indexDataEnricher.enrichIndices(indices, client);
|
return await indexDataEnricher.enrichIndices(indices, client);
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,6 +55,7 @@ export class IndexMgmtServerPlugin implements Plugin<IndexManagementPluginSetup,
|
||||||
config: {
|
config: {
|
||||||
isSecurityEnabled: () => security !== undefined && security.license.isEnabled(),
|
isSecurityEnabled: () => security !== undefined && security.license.isEnabled(),
|
||||||
isLegacyTemplatesEnabled: this.config.enableLegacyTemplates,
|
isLegacyTemplatesEnabled: this.config.enableLegacyTemplates,
|
||||||
|
isIndexStatsEnabled: this.config.enableIndexStats,
|
||||||
},
|
},
|
||||||
indexDataEnricher: this.indexDataEnricher,
|
indexDataEnricher: this.indexDataEnricher,
|
||||||
lib: {
|
lib: {
|
||||||
|
|
|
@ -47,6 +47,7 @@ describe('GET privileges', () => {
|
||||||
config: {
|
config: {
|
||||||
isSecurityEnabled: () => true,
|
isSecurityEnabled: () => true,
|
||||||
isLegacyTemplatesEnabled: true,
|
isLegacyTemplatesEnabled: true,
|
||||||
|
isIndexStatsEnabled: true,
|
||||||
},
|
},
|
||||||
indexDataEnricher: mockedIndexDataEnricher,
|
indexDataEnricher: mockedIndexDataEnricher,
|
||||||
lib: {
|
lib: {
|
||||||
|
@ -114,6 +115,7 @@ describe('GET privileges', () => {
|
||||||
config: {
|
config: {
|
||||||
isSecurityEnabled: () => false,
|
isSecurityEnabled: () => false,
|
||||||
isLegacyTemplatesEnabled: true,
|
isLegacyTemplatesEnabled: true,
|
||||||
|
isIndexStatsEnabled: true,
|
||||||
},
|
},
|
||||||
indexDataEnricher: mockedIndexDataEnricher,
|
indexDataEnricher: mockedIndexDataEnricher,
|
||||||
lib: {
|
lib: {
|
||||||
|
|
|
@ -13,13 +13,14 @@ export function registerListRoute({
|
||||||
router,
|
router,
|
||||||
indexDataEnricher,
|
indexDataEnricher,
|
||||||
lib: { handleEsError },
|
lib: { handleEsError },
|
||||||
|
config,
|
||||||
}: RouteDependencies) {
|
}: RouteDependencies) {
|
||||||
router.get(
|
router.get(
|
||||||
{ path: addBasePath('/indices'), validate: false },
|
{ path: addBasePath('/indices'), validate: false },
|
||||||
async (context, request, response) => {
|
async (context, request, response) => {
|
||||||
const { client } = (await context.core).elasticsearch;
|
const { client } = (await context.core).elasticsearch;
|
||||||
try {
|
try {
|
||||||
const indices = await fetchIndices(client, indexDataEnricher);
|
const indices = await fetchIndices({ client, indexDataEnricher, config });
|
||||||
return response.ok({ body: indices });
|
return response.ok({ body: indices });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleEsError({ error, response });
|
return handleEsError({ error, response });
|
||||||
|
|
|
@ -21,6 +21,7 @@ export function registerReloadRoute({
|
||||||
router,
|
router,
|
||||||
indexDataEnricher,
|
indexDataEnricher,
|
||||||
lib: { handleEsError },
|
lib: { handleEsError },
|
||||||
|
config,
|
||||||
}: RouteDependencies) {
|
}: RouteDependencies) {
|
||||||
router.post(
|
router.post(
|
||||||
{ path: addBasePath('/indices/reload'), validate: { body: bodySchema } },
|
{ path: addBasePath('/indices/reload'), validate: { body: bodySchema } },
|
||||||
|
@ -29,7 +30,7 @@ export function registerReloadRoute({
|
||||||
const { indexNames = [] } = (request.body as typeof bodySchema.type) ?? {};
|
const { indexNames = [] } = (request.body as typeof bodySchema.type) ?? {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const indices = await fetchIndices(client, indexDataEnricher, indexNames);
|
const indices = await fetchIndices({ client, indexDataEnricher, config, indexNames });
|
||||||
return response.ok({ body: indices });
|
return response.ok({ body: indices });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return handleEsError({ error, response });
|
return handleEsError({ error, response });
|
||||||
|
|
|
@ -23,11 +23,14 @@ export class ApiRoutes {
|
||||||
registerIndicesRoutes(dependencies);
|
registerIndicesRoutes(dependencies);
|
||||||
registerTemplateRoutes(dependencies);
|
registerTemplateRoutes(dependencies);
|
||||||
registerSettingsRoutes(dependencies);
|
registerSettingsRoutes(dependencies);
|
||||||
registerStatsRoute(dependencies);
|
|
||||||
registerMappingRoute(dependencies);
|
registerMappingRoute(dependencies);
|
||||||
registerComponentTemplateRoutes(dependencies);
|
registerComponentTemplateRoutes(dependencies);
|
||||||
registerNodesRoute(dependencies);
|
registerNodesRoute(dependencies);
|
||||||
registerEnrichPoliciesRoute(dependencies);
|
registerEnrichPoliciesRoute(dependencies);
|
||||||
|
|
||||||
|
if (dependencies.config.isIndexStatsEnabled !== false) {
|
||||||
|
registerStatsRoute(dependencies);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {}
|
start() {}
|
||||||
|
|
|
@ -13,6 +13,7 @@ export const routeDependencies: Omit<RouteDependencies, 'router'> = {
|
||||||
config: {
|
config: {
|
||||||
isSecurityEnabled: jest.fn().mockReturnValue(true),
|
isSecurityEnabled: jest.fn().mockReturnValue(true),
|
||||||
isLegacyTemplatesEnabled: true,
|
isLegacyTemplatesEnabled: true,
|
||||||
|
isIndexStatsEnabled: true,
|
||||||
},
|
},
|
||||||
indexDataEnricher: new IndexDataEnricher(),
|
indexDataEnricher: new IndexDataEnricher(),
|
||||||
lib: {
|
lib: {
|
||||||
|
|
|
@ -24,6 +24,7 @@ export interface RouteDependencies {
|
||||||
config: {
|
config: {
|
||||||
isSecurityEnabled: () => boolean;
|
isSecurityEnabled: () => boolean;
|
||||||
isLegacyTemplatesEnabled: boolean;
|
isLegacyTemplatesEnabled: boolean;
|
||||||
|
isIndexStatsEnabled: boolean;
|
||||||
};
|
};
|
||||||
indexDataEnricher: IndexDataEnricher;
|
indexDataEnricher: IndexDataEnricher;
|
||||||
lib: {
|
lib: {
|
||||||
|
|
|
@ -10,5 +10,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
export default function ({ loadTestFile }: FtrProviderContext) {
|
export default function ({ loadTestFile }: FtrProviderContext) {
|
||||||
describe('Index Management APIs', function () {
|
describe('Index Management APIs', function () {
|
||||||
loadTestFile(require.resolve('./index_templates'));
|
loadTestFile(require.resolve('./index_templates'));
|
||||||
|
loadTestFile(require.resolve('./indices'));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import expect from 'expect';
|
||||||
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
|
||||||
|
const API_BASE_PATH = '/api/index_management';
|
||||||
|
|
||||||
|
export default function ({ getService }: FtrProviderContext) {
|
||||||
|
const supertest = getService('supertest');
|
||||||
|
const es = getService('es');
|
||||||
|
const log = getService('log');
|
||||||
|
|
||||||
|
describe('Indices', function () {
|
||||||
|
const indexName = `index-${Math.random()}`;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
// Create a new index to test against
|
||||||
|
try {
|
||||||
|
await es.indices.create({ index: indexName });
|
||||||
|
} catch (err) {
|
||||||
|
log.debug('[Setup error] Error creating index');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
after(async () => {
|
||||||
|
// Cleanup index created for testing purposes
|
||||||
|
try {
|
||||||
|
await es.indices.delete({
|
||||||
|
index: indexName,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
log.debug('[Cleanup error] Error deleting index');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('get all', () => {
|
||||||
|
it('should list indices with the expected parameters', async () => {
|
||||||
|
const { body: indices } = await supertest
|
||||||
|
.get(`${API_BASE_PATH}/indices`)
|
||||||
|
.set('kbn-xsrf', 'xxx')
|
||||||
|
.set('x-elastic-internal-origin', 'xxx')
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const indexFound = indices.find((index: { name: string }) => index.name === indexName);
|
||||||
|
|
||||||
|
expect(indexFound).toBeTruthy();
|
||||||
|
|
||||||
|
const expectedKeys = ['aliases', 'hidden', 'isFrozen', 'primary', 'replica', 'name'].sort();
|
||||||
|
|
||||||
|
expect(Object.keys(indexFound).sort()).toEqual(expectedKeys);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -10,5 +10,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
export default ({ loadTestFile }: FtrProviderContext) => {
|
export default ({ loadTestFile }: FtrProviderContext) => {
|
||||||
describe('Index Management', function () {
|
describe('Index Management', function () {
|
||||||
loadTestFile(require.resolve('./index_templates'));
|
loadTestFile(require.resolve('./index_templates'));
|
||||||
|
loadTestFile(require.resolve('./indices'));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License
|
||||||
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
|
* 2.0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import expect from '@kbn/expect';
|
||||||
|
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||||
|
|
||||||
|
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||||
|
const testSubjects = getService('testSubjects');
|
||||||
|
const pageObjects = getPageObjects(['common', 'indexManagement', 'header']);
|
||||||
|
const browser = getService('browser');
|
||||||
|
const security = getService('security');
|
||||||
|
const retry = getService('retry');
|
||||||
|
|
||||||
|
describe('Indices', function () {
|
||||||
|
before(async () => {
|
||||||
|
await security.testUser.setRoles(['index_management_user']);
|
||||||
|
await pageObjects.common.navigateToApp('indexManagement');
|
||||||
|
// Navigate to the indices tab
|
||||||
|
await pageObjects.indexManagement.changeTabs('indicesTab');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders the indices tab', async () => {
|
||||||
|
await retry.waitFor('indices list to be visible', async () => {
|
||||||
|
return await testSubjects.exists('indicesList');
|
||||||
|
});
|
||||||
|
|
||||||
|
const url = await browser.getCurrentUrl();
|
||||||
|
expect(url).to.contain(`/indices`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue