Skip to content

Commit

Permalink
[Maps] Add drawing index data endpoint (elastic#94728)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aaron Caldwell authored Mar 26, 2021
1 parent 6872231 commit d89ede9
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 53 deletions.
2 changes: 2 additions & 0 deletions x-pack/plugins/maps/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
6 changes: 6 additions & 0 deletions x-pack/plugins/maps/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ export interface IndexSourceMappings {
export interface BodySettings {
[key: string]: any;
}

export interface WriteSettings {
index: string;
body: object;
[key: string]: any;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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,
Expand Down
45 changes: 45 additions & 0 deletions x-pack/plugins/maps/server/data_indexing/index_data.ts
Original file line number Diff line number Diff line change
@@ -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,
};
}
}
104 changes: 104 additions & 0 deletions x-pack/plugins/maps/server/data_indexing/indexing_routes.ts
Original file line number Diff line number Diff line change
@@ -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,
});
}
}
);
}
49 changes: 5 additions & 44 deletions x-pack/plugins/maps/server/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -666,4 +624,7 @@ export async function initRoutes(
}

initMVTRoutes({ router, logger });
if (drawingFeatureEnabled) {
initIndexingRoutes({ router, logger, dataPlugin });
}
}
1 change: 1 addition & 0 deletions x-pack/test/api_integration/apis/maps/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'));
Expand Down
98 changes: 98 additions & 0 deletions x-pack/test/api_integration/apis/maps/index_data.js
Original file line number Diff line number Diff line change
@@ -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);
});
});
}

0 comments on commit d89ede9

Please sign in to comment.