Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ingest pipelines] Cleanup #64794

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions x-pack/plugins/ingest_pipelines/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
# ingest_pipelines
# Ingest Node Pipelines UI

> Ingest node pipelines UI
## Summary
The `ingest_pipelines` plugin provides Kibana support for [Elasticsearch's ingest nodes](https://www.elastic.co/guide/en/elasticsearch/reference/master/ingest.html). Please refer to the Elasticsearch documentation for more details.

This plugin allows Kibana to create, edit, clone and delete ingest node pipelines. It also provides support to simulate a pipeline.

It requires a Basic license and the following cluster privileges: `manage_pipeline` and `cluster:monitor/nodes/info`.

---

## Development

See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment.
A new app called Ingest Node Pipelines is registered in the Management section and follows a typical CRUD UI pattern. The client-side portion of this app lives in [public/application](public/application) and uses endpoints registered in [server/routes/api](server/routes/api).

See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions on setting up your development environment.

### Test coverage
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! This would be really useful to maintain for all of our apps.


The app has the following test coverage:

- Complete API integration tests
- Smoke-level functional test
- Client-integration tests
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@
*/

export { PipelineForm } from './pipeline_form';

export { PipelineRequestFlyoutProvider as PipelineRequestFlyout } from './pipeline_request_flyout_provider';
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from
import { useForm, Form, FormConfig } from '../../../shared_imports';
import { Pipeline } from '../../../../common/types';

import { PipelineRequestFlyout } from '../';
import { PipelineRequestFlyout } from './pipeline_request_flyout';
import { PipelineTestFlyout } from './pipeline_test_flyout';
import { PipelineFormFields } from './pipeline_form_fields';
import { PipelineFormError } from './pipeline_form_error';
Expand Down Expand Up @@ -85,8 +85,6 @@ export const PipelineForm: React.FunctionComponent<PipelineFormProps> = ({
isInvalid={form.isSubmitted && !form.isValid}
error={form.getErrors()}
>
<EuiSpacer size="l" />

{/* Request error */}
{saveError && <PipelineFormError errorMessage={saveError.message} />}

Expand All @@ -101,9 +99,9 @@ export const PipelineForm: React.FunctionComponent<PipelineFormProps> = ({

{/* Form submission */}
<EuiFlexGroup justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiFlexItem>
<EuiFlexGroup>
<EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
fill
color="secondary"
Expand All @@ -116,7 +114,7 @@ export const PipelineForm: React.FunctionComponent<PipelineFormProps> = ({
{saveButtonLabel}
</EuiButton>
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonEmpty color="primary" onClick={onCancel}>
<FormattedMessage
id="xpack.ingestPipelines.form.cancelButtonLabel"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* 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.
*/

export { PipelineRequestFlyoutProvider as PipelineRequestFlyout } from './pipeline_request_flyout_provider';
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
EuiTitle,
} from '@elastic/eui';

import { Pipeline } from '../../../common/types';
import { Pipeline } from '../../../../../common/types';

interface Props {
pipeline: Pipeline;
Expand All @@ -40,7 +40,7 @@ export const PipelineRequestFlyout: React.FunctionComponent<Props> = ({
uuid.current++;

return (
<EuiFlyout maxWidth={480} onClose={closeFlyout}>
<EuiFlyout maxWidth={550} onClose={closeFlyout}>
<EuiFlyoutHeader>
<EuiTitle>
<h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import React, { useState, useEffect } from 'react';

import { Pipeline } from '../../../common/types';
import { useFormContext } from '../../shared_imports';
import { Pipeline } from '../../../../../common/types';
import { useFormContext } from '../../../../shared_imports';
import { PipelineRequestFlyout } from './pipeline_request_flyout';

export const PipelineRequestFlyoutProvider = ({ closeFlyout }: { closeFlyout: () => void }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const PipelineTestFlyout: React.FunctionComponent<PipelineTestFlyoutProps
}

return (
<EuiFlyout maxWidth={480} onClose={closeFlyout}>
<EuiFlyout maxWidth={550} onClose={closeFlyout}>
<EuiFlyoutHeader>
<EuiTitle>
<h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
* 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 from 'react';

import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { EuiCode } from '@elastic/eui';

import { FormSchema, fieldValidators, ValidationFuncArg } from '../../../../../shared_imports';
import { parseJson, stringifyJson } from '../../../../lib';
Expand All @@ -18,6 +22,27 @@ export const documentsSchema: FormSchema = {
defaultMessage: 'Documents',
}
),
helpText: (
<FormattedMessage
id="xpack.ingestPipelines.form.onFailureFieldHelpText"
defaultMessage="Use JSON format: {code}"
values={{
code: (
<EuiCode>
{JSON.stringify([
{
_index: 'index',
_id: 'id',
_source: {
foo: 'bar',
},
},
])}
</EuiCode>
),
}}
/>
),
serializer: parseJson,
deserializer: stringifyJson,
validations: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';

import { EuiSpacer, EuiText, EuiButton, EuiHorizontalRule } from '@elastic/eui';
import { EuiSpacer, EuiText, EuiButton, EuiHorizontalRule, EuiLink } from '@elastic/eui';

import {
getUseField,
Expand All @@ -17,6 +17,7 @@ import {
Form,
useForm,
FormConfig,
useKibana,
} from '../../../../../shared_imports';

import { documentsSchema } from './schema';
Expand All @@ -35,6 +36,8 @@ export const DocumentsTab: React.FunctionComponent<Props> = ({
handleExecute,
isExecuting,
}) => {
const { services } = useKibana();

const { setCurrentTestConfig, testConfig } = useTestConfigContext();
const { verbose: cachedVerbose, documents: cachedDocuments } = testConfig;

Expand Down Expand Up @@ -69,7 +72,19 @@ export const DocumentsTab: React.FunctionComponent<Props> = ({
<p>
<FormattedMessage
id="xpack.ingestPipelines.testPipelineFlyout.documentsTab.tabDescriptionText"
defaultMessage="Provide an array of documents to be ingested by the pipeline."
defaultMessage="Provide an array of documents to be ingested by the pipeline. {learnMoreLink}"
values={{
learnMoreLink: (
<EuiLink href={services.documentation.getSimulatePipelineApiUrl()} target="_blank">
{i18n.translate(
'xpack.ingestPipelines.testPipelineFlyout.documentsTab.simulateDocumentionLink',
{
defaultMessage: 'Learn more.',
}
)}
</EuiLink>
),
}}
/>
</p>
</EuiText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
* 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 from 'react';

import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiCode } from '@elastic/eui';

import { FormSchema, FIELD_TYPES, fieldValidators, fieldFormatters } from '../../../shared_imports';
import { parseJson, stringifyJson } from '../../lib';
Expand Down Expand Up @@ -47,6 +50,26 @@ export const pipelineFormSchema: FormSchema = {
label: i18n.translate('xpack.ingestPipelines.form.processorsFieldLabel', {
defaultMessage: 'Processors',
}),
helpText: (
<FormattedMessage
id="xpack.ingestPipelines.form.processorsFieldHelpText"
defaultMessage="Use JSON format: {code}"
values={{
code: (
<EuiCode>
{JSON.stringify([
{
set: {
field: 'foo',
value: 'bar',
},
},
])}
</EuiCode>
),
}}
/>
),
serializer: parseJson,
deserializer: stringifyJson,
validations: [
Expand All @@ -70,6 +93,26 @@ export const pipelineFormSchema: FormSchema = {
label: i18n.translate('xpack.ingestPipelines.form.onFailureFieldLabel', {
defaultMessage: 'On-failure processors (optional)',
}),
helpText: (
<FormattedMessage
id="xpack.ingestPipelines.form.onFailureFieldHelpText"
defaultMessage="Use JSON format: {code}"
values={{
code: (
<EuiCode>
{JSON.stringify([
{
set: {
field: '_index',
value: 'failed-{{ _index }}',
},
},
])}
</EuiCode>
),
}}
/>
),
serializer: value => {
const result = parseJson(value);
// If an empty array was passed, strip out this value entirely.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiButtonEmpty,
EuiSpacer,
} from '@elastic/eui';

import { BASE_PATH } from '../../../../common/constants';
Expand Down Expand Up @@ -93,6 +94,8 @@ export const PipelinesCreate: React.FunctionComponent<RouteComponentProps & Prop
</EuiFlexGroup>
</EuiTitle>

<EuiSpacer size="l" />

<PipelineForm
defaultValue={sourcePipeline}
onSave={onSave}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export class DocumentationService {
public getPutPipelineApiUrl() {
return `${this.esDocBasePath}/put-pipeline-api.html`;
}

public getSimulatePipelineApiUrl() {
return `${this.esDocBasePath}/simulate-pipeline-api.html`;
}
}

export const documentationService = new DocumentationService();
Empty file.
2 changes: 0 additions & 2 deletions x-pack/plugins/ingest_pipelines/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/

import './index.scss';

import { IngestPipelinesPlugin } from './plugin';

export function plugin() {
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/ingest_pipelines/server/routes/api/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export const registerGetRoutes = ({
return res.ok({ body: deserializePipelines(pipelines) });
} catch (error) {
if (isEsError(error)) {
// ES returns 404 when there are no pipelines
// Instead, we return an empty array and 200 status back to the client
if (error.status === 404) {
return res.ok({ body: [] });
}

return res.customError({
statusCode: error.statusCode,
body: error,
Expand Down