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

Add support for GeoIP processor databases in Ingest Pipelines #190830

Merged
merged 53 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
dd2473e
[Ingest Pipelines] Add Manage processors page with geo ip databases t…
yuliacech Aug 19, 2024
c317077
[Ingest Pipelines] Add modal for adding a database
yuliacech Aug 22, 2024
383ee51
[Ingest Pipelines] Add a check for existing databases
yuliacech Aug 22, 2024
98c0b8f
[Ingest Pipelines] Add an empty prompt
yuliacech Aug 23, 2024
ca1a98e
[Ingest Pipelines] Add serverless config
yuliacech Aug 23, 2024
75d633c
[Ingest Pipelines] Add type column
yuliacech Aug 26, 2024
ed74711
[Ingest Pipelines] Update the js client for geo ip requests
yuliacech Aug 26, 2024
a87724d
[CI] Auto-commit changed files from 'node scripts/yarn_deduplicate'
kibanamachine Aug 26, 2024
7432c81
[Ingest Pipelines] Add api integration tests
yuliacech Aug 27, 2024
b58180d
[Ingest Pipelines] Add functional tests
yuliacech Aug 27, 2024
d771217
[Ingest Pipelines] Fix i18n errors
yuliacech Aug 27, 2024
a6a38ca
[Ingest Pipelines] Fix tests
yuliacech Aug 28, 2024
d770110
[Ingest Pipelines] Client integration tests
yuliacech Aug 29, 2024
0a087f6
[Ingest Pipelines] Hide the button on serverless
yuliacech Aug 30, 2024
539bed5
Fix missing config mock
yuliacech Aug 30, 2024
d9112fd
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Sep 2, 2024
0d09b45
[Ingest Pipelines] Add ipinfo to add database modal
yuliacech Sep 10, 2024
aa2a2e6
[Ingest Pipelines] Add permissions check for manage processors button
yuliacech Sep 11, 2024
cf2f88f
Merge branch 'main' into geoip/add_table
yuliacech Sep 12, 2024
bfe0572
[Ingest Pipelines] Add ipinfo database type
yuliacech Sep 13, 2024
9a68d51
Merge branch 'main' into geoip/add_table
yuliacech Sep 19, 2024
3da841b
Merge branch 'main' into geoip/add_table
elasticmachine Sep 27, 2024
feb3701
Add web and local types
sabarasaba Sep 30, 2024
b8c94c1
Add combobox for selecting databases
sabarasaba Sep 30, 2024
6378ba9
Merge branch 'main' into geoip/add_table
elasticmachine Sep 30, 2024
92b3934
web and local databases cannot be deleted
sabarasaba Oct 4, 2024
775d613
Add missing translation
sabarasaba Oct 4, 2024
3c86a4a
Remove mocks
sabarasaba Oct 4, 2024
b38183a
Add IP location processor
sabarasaba Oct 7, 2024
d099144
Merge branch 'main' into geoip/add_table
elasticmachine Oct 9, 2024
2c8885c
Replace ipinfo database names
sabarasaba Oct 11, 2024
a915dad
Replace api calls to use new es endpoint
sabarasaba Oct 11, 2024
0c4eec1
Add IP info specific callout warning when creating
sabarasaba Oct 11, 2024
f7b70de
Fix copy
sabarasaba Oct 11, 2024
a8c78be
Fix capitalization
sabarasaba Oct 11, 2024
3baf565
Replace transport layer in routes with JS client
ElenaStoeva Oct 14, 2024
23206c6
Fix jest tests and add ones for ipinfo database
ElenaStoeva Oct 14, 2024
6c1cf7b
Replace ip location processor doc link with geoip processor doc link
ElenaStoeva Oct 14, 2024
93d7882
Fix i18n errors, remove Learn more links from add modal
ElenaStoeva Oct 14, 2024
5ca090e
Merge branch 'main' into geoip/add_table
ElenaStoeva Oct 14, 2024
1b0b3db
Fix functional tests and add one for ipinfo database
ElenaStoeva Oct 14, 2024
549a645
Merge branch 'geoip/add_table' of https://github.com/yuliacech/kibana…
ElenaStoeva Oct 14, 2024
558b099
Unskip tests
ElenaStoeva Oct 14, 2024
4d377a5
Update ingest_pipelines_page.ts
mattkime Oct 14, 2024
c43f71c
Update add_database_modal.tsx
mattkime Oct 14, 2024
c69902e
Update manage_processors.helpers.ts
mattkime Oct 14, 2024
7228df7
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Oct 14, 2024
f0a65df
Fix failing functional tests
ElenaStoeva Oct 15, 2024
ccc25bc
Merge branch 'main' into geoip/add_table
ElenaStoeva Oct 15, 2024
d108302
One more fix in functional tests
ElenaStoeva Oct 15, 2024
157c755
Increase sleep time in functional tests
ElenaStoeva Oct 15, 2024
372bbf1
Merge branch 'main' into geoip/add_table
ElenaStoeva Oct 15, 2024
69ee530
Temporarily skip flaky test
ElenaStoeva Oct 15, 2024
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
3 changes: 3 additions & 0 deletions config/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ xpack.index_management.enableMappingsSourceFieldSection: false
# Disable toggle for enabling data retention in DSL form from Index Management UI
xpack.index_management.enableTogglingDataRetention: false

# Disable Manage Processors UI in Ingest Pipelines
xpack.ingest_pipelines.enableManageProcessors: false

# Keep deeplinks visible so that they are shown in the sidenav
dev_tools.deeplinks.navLinkStatus: visible
management.deeplinks.navLinkStatus: visible
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'xpack.ml.nlp.enabled (boolean)',
'xpack.osquery.actionEnabled (boolean?)',
'xpack.remote_clusters.ui.enabled (boolean?)',
'xpack.ingest_pipelines.enableManageProcessors (boolean?|never)',
/**
* NOTE: The Reporting plugin is currently disabled in functional tests (see test/functional/config.base.js).
* It will be re-enabled once #102552 is completed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,27 @@ const registerHttpRequestMockHelpers = (
const setParseCsvResponse = (response?: object, error?: ResponseError) =>
mockResponse('POST', `${API_BASE_PATH}/parse_csv`, response, error);

const setLoadGeoipDatabasesResponse = (response?: object[], error?: ResponseError) =>
mockResponse('GET', `${API_BASE_PATH}/geoip_database`, response, error);

const setDeleteGeoipDatabaseResponse = (
databaseName: string,
response?: object,
error?: ResponseError
) => mockResponse('DELETE', `${API_BASE_PATH}/geoip_database/${databaseName}`, response, error);

const setCreateGeoipDatabaseResponse = (response?: object, error?: ResponseError) =>
mockResponse('POST', `${API_BASE_PATH}/geoip_database`, response, error);

return {
setLoadPipelinesResponse,
setLoadPipelineResponse,
setDeletePipelineResponse,
setCreatePipelineResponse,
setParseCsvResponse,
setLoadGeoipDatabasesResponse,
setDeleteGeoipDatabaseResponse,
setCreateGeoipDatabaseResponse,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { setup as pipelinesCreateSetup } from './pipelines_create.helpers';
import { setup as pipelinesCloneSetup } from './pipelines_clone.helpers';
import { setup as pipelinesEditSetup } from './pipelines_edit.helpers';
import { setup as pipelinesCreateFromCsvSetup } from './pipelines_create_from_csv.helpers';
import { setup as manageProcessorsSetup } from './manage_processors.helpers';

export { nextTick, getRandomString, findTestSubject } from '@kbn/test-jest-helpers';
export { getRandomString, findTestSubject } from '@kbn/test-jest-helpers';

export { setupEnvironment } from './setup_environment';

Expand All @@ -21,4 +22,5 @@ export const pageHelpers = {
pipelinesClone: { setup: pipelinesCloneSetup },
pipelinesEdit: { setup: pipelinesEditSetup },
pipelinesCreateFromCsv: { setup: pipelinesCreateFromCsvSetup },
manageProcessors: { setup: manageProcessorsSetup },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* 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 { act } from 'react-dom/test-utils';
import { HttpSetup } from '@kbn/core/public';

import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers';
import { ManageProcessors } from '../../../public/application/sections';
import { WithAppDependencies } from './setup_environment';
import { getManageProcessorsPath, ROUTES } from '../../../public/application/services/navigation';

const testBedConfig: AsyncTestBedConfig = {
memoryRouter: {
initialEntries: [getManageProcessorsPath()],
componentRoutePath: ROUTES.manageProcessors,
},
doMountAsync: true,
};

export type ManageProcessorsTestBed = TestBed<ManageProcessorsTestSubjects> & {
actions: ReturnType<typeof createActions>;
};

const createActions = (testBed: TestBed) => {
const { component, find, form } = testBed;

const clickDeleteDatabaseButton = async (index: number) => {
const allDeleteButtons = find('deleteGeoipDatabaseButton');
const deleteButton = allDeleteButtons.at(index);
await act(async () => {
deleteButton.simulate('click');
});

component.update();
};

const confirmDeletingDatabase = async () => {
await act(async () => {
form.setInputValue('geoipDatabaseConfirmation', 'delete');
});

component.update();

const confirmButton: HTMLButtonElement | null = document.body.querySelector(
'[data-test-subj="deleteGeoipDatabaseSubmit"]'
);

expect(confirmButton).not.toBe(null);
expect(confirmButton!.disabled).toBe(false);
expect(confirmButton!.textContent).toContain('Delete');

await act(async () => {
confirmButton!.click();
});

component.update();
};

const clickAddDatabaseButton = async () => {
const button = find('addGeoipDatabaseButton');
await act(async () => {
button.simulate('click');
});

component.update();
};

const fillOutDatabaseValues = async (maxmind: string, databaseName: string) => {
await act(async () => {
form.setInputValue('addDatabaseMaxmind', maxmind);
ElenaStoeva marked this conversation as resolved.
Show resolved Hide resolved
});
await act(async () => {
form.setInputValue('addDatabaseName', databaseName);
});
};

const confirmAddingDatabase = async () => {
const button: HTMLButtonElement | null = document.body.querySelector(
'[data-test-subj="addGeoipDatabaseSubmit"]'
);
await act(async () => {
button!.click();
});

component.update();
};

return {
clickDeleteDatabaseButton,
confirmDeletingDatabase,
clickAddDatabaseButton,
fillOutDatabaseValues,
confirmAddingDatabase,
};
};

export const setup = async (httpSetup: HttpSetup): Promise<ManageProcessorsTestBed> => {
const initTestBed = registerTestBed(
WithAppDependencies(ManageProcessors, httpSetup),
testBedConfig
);
const testBed = await initTestBed();

return {
...testBed,
actions: createActions(testBed),
};
};

export type ManageProcessorsTestSubjects =
| 'manageProcessorsTitle'
| 'addGeoipDatabaseButton'
| 'geoipDatabaseList'
| 'deleteGeoipDatabaseButton'
| 'geoipDatabaseConfirmation'
| 'geoipEmptyListPrompt'
| 'geoipListLoadingError';
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ const appServices = {
},
overlays: overlayServiceMock.createStartContract(),
http: httpServiceMock.createStartContract({ basePath: '/mock' }),
config: {
enableManageProcessors: true,
},
};

export const setupEnvironment = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* 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 { act } from 'react-dom/test-utils';

import { ManageProcessorsTestBed } from './helpers/manage_processors.helpers';

import { setupEnvironment, pageHelpers } from './helpers';
import type { GeoipDatabase } from '../../common/types';
import { API_BASE_PATH } from '../../common/constants';

const { setup } = pageHelpers.manageProcessors;

describe('<ManageProcessors />', () => {
const { httpSetup, httpRequestsMockHelpers } = setupEnvironment();
let testBed: ManageProcessorsTestBed;

describe('With databases', () => {
beforeEach(async () => {
await act(async () => {
testBed = await setup(httpSetup);
});

testBed.component.update();
});

const database1: GeoipDatabase = {
name: 'GeoIP2-Anonymous-IP',
id: 'geoip2-anonymous-ip',
type: 'maxmind',
};

const database2: GeoipDatabase = {
name: 'GeoIP2-City',
id: 'geoip2-city',
type: 'maxmind',
};

const database3 = {
name: 'GeoIP2-Country',
id: 'geoip2-country',
type: 'maxmind',
};

const databases = [database1, database2, database3];

httpRequestsMockHelpers.setLoadGeoipDatabasesResponse(databases);

test('renders the list of databases', async () => {
const { exists, find, table } = testBed;

// Page title
expect(exists('manageProcessorsTitle')).toBe(true);
expect(find('manageProcessorsTitle').text()).toEqual('Manage Processors');

// Add database button
expect(exists('addGeoipDatabaseButton')).toBe(true);

// Table has columns for database name and type
const { tableCellsValues } = table.getMetaData('geoipDatabaseList');
tableCellsValues.forEach((row, i) => {
const database = databases[i];

expect(row).toEqual([database.name, 'MaxMind', 'Delete']);
});
});

test('deletes a database', async () => {
const { actions } = testBed;
const { name: databaseName } = database1;
httpRequestsMockHelpers.setDeleteGeoipDatabaseResponse(databaseName, {});

await actions.clickDeleteDatabaseButton(0);

await actions.confirmDeletingDatabase();

expect(httpSetup.delete).toHaveBeenLastCalledWith(
`${API_BASE_PATH}/geoip_database/${databaseName.toLowerCase()}`,
expect.anything()
);
});
});

describe('Creates a database', () => {
it('creates a database when none with the same name exists', async () => {
const { actions } = testBed;
const databaseName = 'GeoIP2-ISP';
const maxmind = '123456';
httpRequestsMockHelpers.setCreateGeoipDatabaseResponse({
name: databaseName,
id: databaseName.toLowerCase(),
});

await actions.clickAddDatabaseButton();

await actions.fillOutDatabaseValues(maxmind, databaseName);

await actions.confirmAddingDatabase();

expect(httpSetup.post).toHaveBeenLastCalledWith(`${API_BASE_PATH}/geoip_database`, {
asSystemRequest: undefined,
body: '{"maxmind":"123456","databaseName":"GeoIP2-ISP"}',
query: undefined,
version: undefined,
});
});
});

describe('No databases', () => {
test('displays an empty prompt', async () => {
httpRequestsMockHelpers.setLoadGeoipDatabasesResponse([]);

await act(async () => {
testBed = await setup(httpSetup);
});
const { exists, component } = testBed;
component.update();

expect(exists('geoipEmptyListPrompt')).toBe(true);
});
});

describe('Error handling', () => {
beforeEach(async () => {
const error = {
statusCode: 500,
error: 'Internal server error',
message: 'Internal server error',
};

httpRequestsMockHelpers.setLoadGeoipDatabasesResponse(undefined, error);

await act(async () => {
testBed = await setup(httpSetup);
});

testBed.component.update();
});

test('displays an error callout', async () => {
const { exists } = testBed;

expect(exists('geoipListLoadingError')).toBe(true);
});
});
});
17 changes: 8 additions & 9 deletions x-pack/plugins/ingest_pipelines/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@ export interface Pipeline {
deprecated?: boolean;
}

export interface PipelinesByName {
[key: string]: {
description: string;
version?: number;
processors: Processor[];
on_failure?: Processor[];
};
}

export enum FieldCopyAction {
Copy = 'copy',
Rename = 'rename',
}

export type DatabaseType = 'maxmind' | 'ipinfo' | 'web' | 'local' | 'unknown';

export interface GeoipDatabase {
name: string;
id: string;
type: DatabaseType;
}
Loading