[Maps] Add endpoint to server for creating empty index & index pattern (#94028)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Aaron Caldwell 2021-03-17 21:40:51 -04:00 committed by GitHub
parent 6df27f322f
commit ad18739de7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 208 additions and 4 deletions

View file

@ -40,6 +40,7 @@ export const MAP_PATH = 'map';
export const GIS_API_PATH = `api/${APP_ID}`;
export const INDEX_SETTINGS_API_PATH = `${GIS_API_PATH}/indexSettings`;
export const FONTS_API_PATH = `${GIS_API_PATH}/fonts`;
export const INDEX_SOURCE_API_PATH = `${GIS_API_PATH}/docSource`;
export const API_ROOT_PATH = `/${GIS_API_PATH}`;
export const MVT_GETTILE_API_PATH = 'mvt/getTile';
@ -295,3 +296,5 @@ export const DEFAULT_PERCENTILES = [50, 75, 90, 95, 99];
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';

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export * from './constants';
export * from './types';

View file

@ -0,0 +1,24 @@
/*
* 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.
*/
export interface CreateDocSourceResp {
success: boolean;
error?: Error;
}
export interface IndexSourceMappings {
_meta?: {
created_by: string;
};
properties: {
[key: string]: any;
};
}
export interface BodySettings {
[key: string]: any;
}

View file

@ -10,6 +10,7 @@ import { schema, TypeOf } from '@kbn/config-schema';
export interface MapsConfigType {
enabled: boolean;
showMapVisualizationTypes: boolean;
enableDrawingFeature: boolean;
showMapsInspectorAdapter: boolean;
preserveDrawingBuffer: boolean;
}
@ -17,6 +18,7 @@ export interface MapsConfigType {
export const configSchema = schema.object({
enabled: schema.boolean({ defaultValue: true }),
showMapVisualizationTypes: schema.boolean({ defaultValue: false }),
enableDrawingFeature: schema.boolean({ defaultValue: false }),
// flag used in functional testing
showMapsInspectorAdapter: schema.boolean({ defaultValue: false }),
// flag used in functional testing

View file

@ -0,0 +1,64 @@
/*
* 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 { ElasticsearchClient, IScopedClusterClient } from 'kibana/server';
import {
INDEX_META_DATA_CREATED_BY,
CreateDocSourceResp,
IndexSourceMappings,
BodySettings,
} from '../common';
import { IndexPatternsService } from '../../../../src/plugins/data/common';
const DEFAULT_SETTINGS = { number_of_shards: 1 };
const DEFAULT_MAPPINGS = {
_meta: {
created_by: INDEX_META_DATA_CREATED_BY,
},
};
export async function createDocSource(
index: string,
mappings: IndexSourceMappings,
{ asCurrentUser }: IScopedClusterClient,
indexPatternsService: IndexPatternsService
): Promise<CreateDocSourceResp> {
try {
await createIndex(index, mappings, asCurrentUser);
await indexPatternsService.createAndSave(
{
title: index,
},
true
);
return {
success: true,
};
} catch (error) {
return {
success: false,
error,
};
}
}
async function createIndex(
indexName: string,
mappings: IndexSourceMappings,
asCurrentUser: ElasticsearchClient
) {
const body: { mappings: IndexSourceMappings; settings: BodySettings } = {
mappings: {
...DEFAULT_MAPPINGS,
...mappings,
},
settings: DEFAULT_SETTINGS,
};
await asCurrentUser.indices.create({ index: indexName, body });
}

View file

@ -168,11 +168,12 @@ export class MapsPlugin implements Plugin {
});
initRoutes(
core.http.createRouter(),
core,
() => lastLicenseId,
emsSettings,
this.kibanaVersion,
this._logger
this._logger,
currentConfig.enableDrawingFeature
);
this._initHomeData(home, core.http.basePath.prepend, emsSettings);

View file

@ -24,6 +24,7 @@ import {
INDEX_SETTINGS_API_PATH,
FONTS_API_PATH,
API_ROOT_PATH,
INDEX_SOURCE_API_PATH,
} from '../common/constants';
import { EMSClient } from '@elastic/ems-client';
import fetch from 'node-fetch';
@ -33,6 +34,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';
const EMPTY_EMS_CLIENT = {
async getFileLayers() {
@ -53,9 +55,18 @@ const EMPTY_EMS_CLIENT = {
addQueryParams() {},
};
export function initRoutes(router, getLicenseId, emsSettings, kbnVersion, logger) {
export async function initRoutes(
core,
getLicenseId,
emsSettings,
kbnVersion,
logger,
drawingFeatureEnabled
) {
let emsClient;
let lastLicenseId;
const router = core.http.createRouter();
const [, { data: dataPlugin }] = await core.getStartServices();
function getEMSClient() {
const currentLicenseId = getLicenseId();
@ -555,7 +566,6 @@ export function initRoutes(router, getLicenseId, emsSettings, kbnVersion, logger
},
async (context, request, response) => {
const { query } = request;
if (!query.indexPatternTitle) {
logger.warn(`Required query parameter 'indexPatternTitle' not provided.`);
return response.custom({
@ -587,6 +597,47 @@ export function initRoutes(router, getLicenseId, emsSettings, kbnVersion, logger
}
);
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) {

View file

@ -0,0 +1,48 @@
/*
* 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('doc source creation', () => {
it('should create a new index and pattern but not clobber an existing one', async () => {
const resp = await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'testing123',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
})
.expect(200);
expect(resp.body.success).to.be(true);
// Repeated index fails. We don't want the user clobbering indexes
await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: 'testing123',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
})
.expect(500);
});
it('should fail to create index and pattern with invalid index', async () => {
await supertest
.post(`/api/maps/docSource`)
.set('kbn-xsrf', 'kibana')
.send({
index: '_testing456',
mappings: { properties: { coordinates: { type: 'geo_point' } } },
})
.expect(500);
});
});
}

View file

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

View file

@ -83,6 +83,7 @@ export default async function ({ readConfigFile }) {
'--server.uuid=5b2de169-2785-441b-ae8c-186a1936b17d',
'--xpack.maps.showMapsInspectorAdapter=true',
'--xpack.maps.preserveDrawingBuffer=true',
'--xpack.maps.enableDrawingFeature=true',
'--xpack.reporting.queue.pollInterval=3000', // make it explicitly the default
'--xpack.reporting.csv.maxSizeBytes=2850', // small-ish limit for cutting off a 1999 byte report
'--stats.maximumWaitTimeForAllCollectorsInS=1',