[Maps] Add drawing index data endpoint (#94728)

This commit is contained in:
Aaron Caldwell 2021-03-26 14:29:16 -04:00 committed by GitHub
parent 68722313f2
commit d89ede9834
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 265 additions and 53 deletions

View file

@ -298,3 +298,5 @@ export type RawValue = string | number | boolean | undefined | null;
export type FieldFormatter = (value: RawValue) => string | number;
export const INDEX_META_DATA_CREATED_BY = 'maps-drawing-data-ingest';
export const MAX_DRAWING_SIZE_BYTES = 10485760; // 10MB

View file

@ -22,3 +22,9 @@ export interface IndexSourceMappings {
export interface BodySettings {
[key: string]: any;
}
export interface WriteSettings {
index: string;
body: object;
[key: string]: any;
}

View file

@ -11,8 +11,8 @@ import {
CreateDocSourceResp,
IndexSourceMappings,
BodySettings,
} from '../common';
import { IndexPatternsService } from '../../../../src/plugins/data/common';
} from '../../common';
import { IndexPatternsCommonService } from '../../../../../src/plugins/data/server';
const DEFAULT_SETTINGS = { number_of_shards: 1 };
const DEFAULT_MAPPINGS = {
@ -25,16 +25,11 @@ export async function createDocSource(
index: string,
mappings: IndexSourceMappings,
{ asCurrentUser }: IScopedClusterClient,
indexPatternsService: IndexPatternsService
indexPatternsService: IndexPatternsCommonService
): Promise<CreateDocSourceResp> {
try {
await createIndex(index, mappings, asCurrentUser);
await indexPatternsService.createAndSave(
{
title: index,
},
true
);
await indexPatternsService.createAndSave({ title: index }, true);
return {
success: true,

View file

@ -0,0 +1,45 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { ElasticsearchClient } from 'kibana/server';
import { WriteSettings } from '../../common';
export async function writeDataToIndex(
index: string,
data: object,
asCurrentUser: ElasticsearchClient
) {
try {
const { body: indexExists } = await asCurrentUser.indices.exists({ index });
if (!indexExists) {
throw new Error(
i18n.translate('xpack.maps.indexData.indexExists', {
defaultMessage: `Index: '{index}' not found. A valid index must be provided`,
values: {
index,
},
})
);
}
const settings: WriteSettings = { index, body: data };
const { body: resp } = await asCurrentUser.index(settings);
if (resp.result === 'Error') {
throw resp;
} else {
return {
success: true,
data,
};
}
} catch (error) {
return {
success: false,
error,
};
}
}

View file

@ -0,0 +1,104 @@
/*
* 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 { schema } from '@kbn/config-schema';
import { Logger } from 'src/core/server';
import { IRouter } from 'src/core/server';
import type { DataRequestHandlerContext } from 'src/plugins/data/server';
import {
INDEX_SOURCE_API_PATH,
GIS_API_PATH,
MAX_DRAWING_SIZE_BYTES,
} from '../../common/constants';
import { createDocSource } from './create_doc_source';
import { writeDataToIndex } from './index_data';
import { PluginStart as DataPluginStart } from '../../../../../src/plugins/data/server';
export function initIndexingRoutes({
router,
logger,
dataPlugin,
}: {
router: IRouter<DataRequestHandlerContext>;
logger: Logger;
dataPlugin: DataPluginStart;
}) {
router.post(
{
path: `/${INDEX_SOURCE_API_PATH}`,
validate: {
body: schema.object({
index: schema.string(),
mappings: schema.any(),
}),
},
options: {
body: {
accepts: ['application/json'],
},
},
},
async (context, request, response) => {
const { index, mappings } = request.body;
const indexPatternsService = await dataPlugin.indexPatterns.indexPatternsServiceFactory(
context.core.savedObjects.client,
context.core.elasticsearch.client.asCurrentUser
);
const result = await createDocSource(
index,
mappings,
context.core.elasticsearch.client,
indexPatternsService
);
if (result.success) {
return response.ok({ body: result });
} else {
if (result.error) {
logger.error(result.error);
}
return response.custom({
body: result?.error?.message,
statusCode: 500,
});
}
}
);
router.post(
{
path: `/${GIS_API_PATH}/feature`,
validate: {
body: schema.object({
index: schema.string(),
data: schema.any(),
}),
},
options: {
body: {
accepts: ['application/json'],
maxBytes: MAX_DRAWING_SIZE_BYTES,
},
},
},
async (context, request, response) => {
const result = await writeDataToIndex(
request.body.index,
request.body.data,
context.core.elasticsearch.client.asCurrentUser
);
if (result.success) {
return response.ok({ body: result });
} else {
logger.error(result.error);
return response.custom({
body: result.error.message,
statusCode: 500,
});
}
}
);
}

View file

@ -24,8 +24,7 @@ import {
INDEX_SETTINGS_API_PATH,
FONTS_API_PATH,
API_ROOT_PATH,
INDEX_SOURCE_API_PATH,
} from '../common/constants';
} from '../common';
import { EMSClient } from '@elastic/ems-client';
import fetch from 'node-fetch';
import { i18n } from '@kbn/i18n';
@ -34,7 +33,7 @@ import { schema } from '@kbn/config-schema';
import fs from 'fs';
import path from 'path';
import { initMVTRoutes } from './mvt/mvt_routes';
import { createDocSource } from './create_doc_source';
import { initIndexingRoutes } from './data_indexing/indexing_routes';
const EMPTY_EMS_CLIENT = {
async getFileLayers() {
@ -594,47 +593,6 @@ export async function initRoutes(
}
);
if (drawingFeatureEnabled) {
router.post(
{
path: `/${INDEX_SOURCE_API_PATH}`,
validate: {
body: schema.object({
index: schema.string(),
mappings: schema.any(),
}),
},
options: {
body: {
accepts: ['application/json'],
},
},
},
async (context, request, response) => {
const { index, mappings } = request.body;
const indexPatternsService = await dataPlugin.indexPatterns.indexPatternsServiceFactory(
context.core.savedObjects.client,
context.core.elasticsearch.client.asCurrentUser
);
const result = await createDocSource(
index,
mappings,
context.core.elasticsearch.client,
indexPatternsService
);
if (result.success) {
return response.ok({ body: result });
} else {
logger.error(result.error);
return response.custom({
body: result.error.message,
statusCode: 500,
});
}
}
);
}
function checkEMSProxyEnabled() {
const proxyEMSInMaps = emsSettings.isProxyElasticMapsServiceInMaps();
if (!proxyEMSInMaps) {
@ -666,4 +624,7 @@ export async function initRoutes(
}
initMVTRoutes({ router, logger });
if (drawingFeatureEnabled) {
initIndexingRoutes({ router, logger, dataPlugin });
}
}

View file

@ -16,6 +16,7 @@ export default function ({ loadTestFile, getService }) {
describe('', () => {
loadTestFile(require.resolve('./create_doc_source'));
loadTestFile(require.resolve('./index_data'));
loadTestFile(require.resolve('./fonts_api'));
loadTestFile(require.resolve('./index_settings'));
loadTestFile(require.resolve('./migrations'));

View file

@ -0,0 +1,98 @@
/*
* 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';
export default function ({ getService }) {
const supertest = getService('supertest');
describe('index feature data', () => {
it('should add point data to an existing index', async () => {
await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-point-feature-index',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
});
const resp = await supertest
.post(`/api/maps/feature`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-point-feature-index',
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },
})
.expect(200);
expect(resp.body.success).to.be(true);
});
it('should add shape data to an existing index', async () => {
await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-shape-feature-index',
mappings: { properties: { coordinates: { type: 'geo_shape' } } },
});
const resp = await supertest
.post(`/api/maps/feature`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-shape-feature-index',
data: {
coordinates: {
type: 'Polygon',
coordinates: [
[
[-20.91796875, 25.64152637306577],
[-13.0517578125, 25.64152637306577],
[-13.0517578125, 31.203404950917395],
[-20.91796875, 31.203404950917395],
[-20.91796875, 25.64152637306577],
],
],
},
},
})
.expect(200);
expect(resp.body.success).to.be(true);
});
it('should fail if data is invalid', async () => {
await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-feature-index2',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
});
await supertest
.post(`/api/maps/feature`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'new-feature-index2',
data: { coordinates: [600, 800], name: 'Never Gonna Happen Islands' },
})
.expect(500);
});
it('should fail if index does not exist', async () => {
await supertest
.post(`/api/maps/feature`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'not-an-index',
data: { coordinates: [125.6, 10.1], name: 'Dinagat Islands' },
})
.expect(500);
});
});
}