Skip to content

Commit

Permalink
[7.0] Add button for adding index.query.default_field setting to me…
Browse files Browse the repository at this point in the history
…tricbeat indices #32829 (#33057)

* Add button for adding `index.query.default_field` setting to metricbeat indices (#32829)

* Add button for adding `index.query.default_field` setting to metricbeat indices

* Add button to 'group by index' view

* Refactor to more generic API

* Remove comment

* Update functional tests

* Use typeless API in 7.0
  • Loading branch information
joshdover authored Mar 12, 2019
1 parent c5b6da5 commit 803d563
Show file tree
Hide file tree
Showing 16 changed files with 11,238 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ import {
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { FixDefaultFieldsButton } from './default_fields/button';
import { ReindexButton } from './reindex';

interface DeprecationCellProps {
items?: Array<{ title?: string; body: string }>;
reindexIndexName?: string;
indexName?: string;
reindex?: boolean;
needsDefaultFields?: boolean;
docUrl?: string;
headline?: string;
healthColor?: string;
Expand All @@ -33,7 +36,9 @@ interface DeprecationCellProps {
export const DeprecationCell: StatelessComponent<DeprecationCellProps> = ({
headline,
healthColor,
reindexIndexName,
indexName,
reindex,
needsDefaultFields,
docUrl,
items = [],
children,
Expand Down Expand Up @@ -75,9 +80,15 @@ export const DeprecationCell: StatelessComponent<DeprecationCellProps> = ({
))}
</EuiFlexItem>

{reindexIndexName && (
{reindex && (
<EuiFlexItem grow={false}>
<ReindexButton indexName={reindexIndexName} />
<ReindexButton indexName={indexName!} />
</EuiFlexItem>
)}

{needsDefaultFields && (
<EuiFlexItem grow={false}>
<FixDefaultFieldsButton indexName={indexName!} />
</EuiFlexItem>
)}
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* 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, { ReactNode } from 'react';

import { EuiButton } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { kfetch } from 'ui/kfetch';
import { LoadingState } from '../../../../types';

/**
* Field types used by Metricbeat to generate the default_field setting.
* Matches Beats code here:
* https://github.com/elastic/beats/blob/eee127cb59b56f2ed7c7e317398c3f79c4158216/libbeat/template/processor.go#L104
*/
const METRICBEAT_DEFAULT_FIELD_TYPES: ReadonlySet<string> = new Set(['keyword', 'text', 'ip']);
const METRICBEAT_OTHER_DEFAULT_FIELDS: ReadonlySet<string> = new Set(['fields.*']);

interface FixDefaultFieldsButtonProps {
indexName: string;
}

interface FixDefaultFieldsButtonState {
fixLoadingState?: LoadingState;
}

/**
* Renders a button if given index is a valid Metricbeat index to add a default_field setting.
*/
export class FixDefaultFieldsButton extends React.Component<
FixDefaultFieldsButtonProps,
FixDefaultFieldsButtonState
> {
constructor(props: FixDefaultFieldsButtonProps) {
super(props);
this.state = {};
}

public render() {
const { fixLoadingState } = this.state;

if (!this.isMetricbeatIndex()) {
return null;
}

const buttonProps: any = { size: 's', onClick: this.fixMetricbeatIndex };
let buttonContent: ReactNode;

switch (fixLoadingState) {
case LoadingState.Loading:
buttonProps.disabled = true;
buttonProps.isLoading = true;
buttonContent = (
<FormattedMessage
id="xpack.upgradeAssistant.checkupTab.fixMetricbeatIndexButton.fixingLabel"
defaultMessage="Fixing…"
/>
);
break;
case LoadingState.Success:
buttonProps.iconSide = 'left';
buttonProps.iconType = 'check';
buttonProps.disabled = true;
buttonContent = (
<FormattedMessage
id="xpack.upgradeAssistant.checkupTab.fixMetricbeatIndexButton.fixedLabel"
defaultMessage="Fixed"
/>
);
break;
case LoadingState.Error:
buttonProps.color = 'danger';
buttonProps.iconSide = 'left';
buttonProps.iconType = 'cross';
buttonContent = (
<FormattedMessage
id="xpack.upgradeAssistant.checkupTab.fixMetricbeatIndexButton.failedLabel"
defaultMessage="Failed"
/>
);
break;
default:
buttonContent = (
<FormattedMessage
id="xpack.upgradeAssistant.checkupTab.fixMetricbeatIndexButton.reindexLabel"
defaultMessage="Fix"
/>
);
}

return <EuiButton {...buttonProps}>{buttonContent}</EuiButton>;
}

private isMetricbeatIndex = () => {
return this.props.indexName.startsWith('metricbeat-');
};

private fixMetricbeatIndex = async () => {
if (!this.isMetricbeatIndex()) {
return;
}

this.setState({
fixLoadingState: LoadingState.Loading,
});

try {
await kfetch({
pathname: `/api/upgrade_assistant/add_query_default_field/${this.props.indexName}`,
method: 'POST',
body: JSON.stringify({
fieldTypes: [...METRICBEAT_DEFAULT_FIELD_TYPES],
otherFields: [...METRICBEAT_OTHER_DEFAULT_FIELDS],
}),
});

this.setState({
fixLoadingState: LoadingState.Success,
});
} catch (e) {
this.setState({
fixLoadingState: LoadingState.Error,
});
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import React from 'react';

import { EuiBasicTable } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
import { FixDefaultFieldsButton } from './default_fields/button';
import { ReindexButton } from './reindex';

const PAGE_SIZES = [10, 25, 50, 100, 250, 500, 1000];

export interface IndexDeprecationDetails {
index: string;
reindex: boolean;
needsDefaultFields: boolean;
details?: string;
}

Expand Down Expand Up @@ -135,15 +137,21 @@ export class IndexDeprecationTableUI extends React.Component<
// NOTE: this naive implementation assumes all indices in the table are
// should show the reindex button. This should work for known usecases.
const { indices } = this.props;
if (!indices.find(i => i.reindex === true)) {
const showReindexButton = indices.find(i => i.reindex === true);
const showNeedsDefaultFieldsButton = indices.find(i => i.needsDefaultFields === true);
if (!showReindexButton && !showNeedsDefaultFieldsButton) {
return null;
}

return {
actions: [
{
render(indexDep: IndexDeprecationDetails) {
return <ReindexButton indexName={indexDep.index!} />;
if (showReindexButton) {
return <ReindexButton indexName={indexDep.index!} />;
} else {
return <FixDefaultFieldsButton indexName={indexDep.index!} />;
}
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,13 @@ describe('DeprecationList', () => {
Object {
"details": undefined,
"index": "0",
"needsDefaultFields": false,
"reindex": false,
},
Object {
"details": undefined,
"index": "1",
"needsDefaultFields": false,
"reindex": false,
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ const MessageDeprecation: StatelessComponent<{ deprecation: EnrichedDeprecationI
<DeprecationCell
headline={deprecation.message}
healthColor={COLOR_MAP[deprecation.level]}
reindexIndexName={deprecation.reindex ? deprecation.index! : undefined}
indexName={deprecation.index}
reindex={deprecation.reindex}
needsDefaultFields={deprecation.needsDefaultFields}
docUrl={deprecation.url}
items={items}
/>
Expand Down Expand Up @@ -89,6 +91,7 @@ export const DeprecationList: StatelessComponent<{
index: dep.index!,
details: dep.details,
reindex: dep.reindex === true,
needsDefaultFields: dep.needsDefaultFields === true,
}));
return <IndexDeprecation indices={indices} deprecation={deprecations[0]} />;
} else if (currentGroupBy === GroupByOption.index) {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/upgrade_assistant/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import { credentialStoreFactory } from './lib/reindexing/credential_store';
import { makeUpgradeAssistantUsageCollector } from './lib/telemetry';
import { registerClusterCheckupRoutes } from './routes/cluster_checkup';
import { registerDeprecationLoggingRoutes } from './routes/deprecation_logging';
import { registerQueryDefaultFieldRoutes } from './routes/query_default_field';
import { registerReindexIndicesRoutes, registerReindexWorker } from './routes/reindex_indices';
import { registerTelemetryRoutes } from './routes/telemetry';

export function initServer(server: Legacy.Server) {
registerClusterCheckupRoutes(server);
registerDeprecationLoggingRoutes(server);
registerQueryDefaultFieldRoutes(server);

// The ReindexWorker uses a map of request headers that contain the authentication credentials
// for a given reindex. We cannot currently store these in an the .kibana index b/c we do not
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Object {
"index": "twitter",
"level": "warning",
"message": "Coercion of boolean fields",
"needsDefaultFields": false,
"reindex": false,
"url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields",
},
Expand All @@ -42,6 +43,7 @@ Object {
"index": "twitter2",
"level": "warning",
"message": "Coercion of boolean fields",
"needsDefaultFields": false,
"reindex": false,
"url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields",
},
Expand Down
12 changes: 6 additions & 6 deletions x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface EnrichedDeprecationInfo extends DeprecationInfo {
index?: string;
node?: string;
reindex?: boolean;
needsDefaultFields?: boolean;
}

export interface UpgradeAssistantStatus {
Expand Down Expand Up @@ -65,18 +66,17 @@ const getCombinedIndexInfos = (
Object.keys(deprecations.index_settings)
.reduce(
(indexDeprecations, indexName) => {
// prevent APM indices from showing up for general re-indexing
if (apmIndices.has(indexName)) {
return indexDeprecations;
}

return indexDeprecations.concat(
deprecations.index_settings[indexName].map(
d =>
({
...d,
index: indexName,
reindex: /Index created before/.test(d.message),
// prevent APM indices from showing up for general re-indexing
reindex: /Index created before/.test(d.message) && !apmIndices.has(indexName),
needsDefaultFields: /Number of fields exceeds automatic field expansion limit/.test(
d.message
),
} as EnrichedDeprecationInfo)
)
);
Expand Down
Loading

0 comments on commit 803d563

Please sign in to comment.