From 6e5e0bda97b3057c3a10f12c90944bec8e9e2f48 Mon Sep 17 00:00:00 2001 From: Shaunak Kashyap Date: Wed, 16 May 2018 13:40:39 -0700 Subject: [PATCH] [Beats Management] APIs: List beats (#19086) * WIP checkin * Add API integration test * Converting to Jest test * WIP checkin * Fixing API for default case + adding test for it * Fixing copy pasta typos * Fixing variable name * Using a single index * Implementing GET /api/beats/agents API * Updating mapping --- .../plugins/beats/server/routes/api/index.js | 2 + .../routes/api/register_list_beats_route.js | 47 ++++++++++ .../test/api_integration/apis/beats/index.js | 1 + .../api_integration/apis/beats/list_beats.js | 46 ++++++++++ .../es_archives/beats/list/data.json.gz | Bin 0 -> 343 bytes .../es_archives/beats/list/mappings.json | 82 ++++++++++++++++++ 6 files changed, 178 insertions(+) create mode 100644 x-pack/plugins/beats/server/routes/api/register_list_beats_route.js create mode 100644 x-pack/test/api_integration/apis/beats/list_beats.js create mode 100644 x-pack/test/functional/es_archives/beats/list/data.json.gz create mode 100644 x-pack/test/functional/es_archives/beats/list/mappings.json diff --git a/x-pack/plugins/beats/server/routes/api/index.js b/x-pack/plugins/beats/server/routes/api/index.js index 07d923876ee79..76cedde5cdf3d 100644 --- a/x-pack/plugins/beats/server/routes/api/index.js +++ b/x-pack/plugins/beats/server/routes/api/index.js @@ -6,8 +6,10 @@ import { registerCreateEnrollmentTokensRoute } from './register_create_enrollment_tokens_route'; import { registerEnrollBeatRoute } from './register_enroll_beat_route'; +import { registerListBeatsRoute } from './register_list_beats_route'; export function registerApiRoutes(server) { registerCreateEnrollmentTokensRoute(server); registerEnrollBeatRoute(server); + registerListBeatsRoute(server); } diff --git a/x-pack/plugins/beats/server/routes/api/register_list_beats_route.js b/x-pack/plugins/beats/server/routes/api/register_list_beats_route.js new file mode 100644 index 0000000000000..b84210988978f --- /dev/null +++ b/x-pack/plugins/beats/server/routes/api/register_list_beats_route.js @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import { + get, + omit +} from "lodash"; +import { INDEX_NAMES } from "../../../common/constants"; +import { callWithRequestFactory } from '../../lib/client'; +import { wrapEsError } from "../../lib/error_wrappers"; + +async function getBeats(callWithRequest) { + const params = { + index: INDEX_NAMES.BEATS, + type: '_doc', + q: 'type:beat' + }; + + const response = await callWithRequest('search', params); + return get(response, 'hits.hits', []); +} + +// TODO: add license check pre-hook +export function registerListBeatsRoute(server) { + server.route({ + method: 'GET', + path: '/api/beats/agents', + handler: async (request, reply) => { + const callWithRequest = callWithRequestFactory(server, request); + let beats; + + try { + beats = await getBeats(callWithRequest); + } catch (err) { + return reply(wrapEsError(err)); + } + + const response = { + beats: beats.map(beat => omit(beat._source.beat, ['access_token'])) + }; + reply(response); + } + }); +} diff --git a/x-pack/test/api_integration/apis/beats/index.js b/x-pack/test/api_integration/apis/beats/index.js index dc6137f979019..6b3562863a2b7 100644 --- a/x-pack/test/api_integration/apis/beats/index.js +++ b/x-pack/test/api_integration/apis/beats/index.js @@ -19,5 +19,6 @@ export default function ({ getService, loadTestFile }) { loadTestFile(require.resolve('./create_enrollment_tokens')); loadTestFile(require.resolve('./enroll_beat')); + loadTestFile(require.resolve('./list_beats')); }); } diff --git a/x-pack/test/api_integration/apis/beats/list_beats.js b/x-pack/test/api_integration/apis/beats/list_beats.js new file mode 100644 index 0000000000000..dfd0dccf32cc0 --- /dev/null +++ b/x-pack/test/api_integration/apis/beats/list_beats.js @@ -0,0 +1,46 @@ +/* + * 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. + */ + +import expect from 'expect.js'; + +export default function ({ getService }) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + + describe('list_beats', () => { + const archive = 'beats/list'; + + beforeEach('load beats archive', () => esArchiver.load(archive)); + afterEach('unload beats archive', () => esArchiver.unload(archive)); + + it('should return all beats', async () => { + const { body: apiResponse } = await supertest + .get( + '/api/beats/agents' + ) + .expect(200); + + const beatsFromApi = apiResponse.beats; + + expect(beatsFromApi.length).to.be(3); + expect(beatsFromApi.filter(beat => beat.hasOwnProperty('verified_on')).length).to.be(1); + expect(beatsFromApi.find(beat => beat.hasOwnProperty('verified_on')).id).to.be('foo'); + }); + + it('should not return access tokens', async () => { + const { body: apiResponse } = await supertest + .get( + '/api/beats/agents' + ) + .expect(200); + + const beatsFromApi = apiResponse.beats; + + expect(beatsFromApi.length).to.be(3); + expect(beatsFromApi.filter(beat => beat.hasOwnProperty('access_token')).length).to.be(0); + }); + }); +} diff --git a/x-pack/test/functional/es_archives/beats/list/data.json.gz b/x-pack/test/functional/es_archives/beats/list/data.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..c5bcfc6fb14f91eaed3dd09d5fc8ec099ff637a3 GIT binary patch literal 343 zcmV-d0jT~TiwFqyEc;pj17u-zVJ>QOZ*Bm^Qp;|GFc7@+6^L_V*QP zHQ*FTls3x07v~|UN_uIPUM%fAR-^GAqBu^5_YEdRoH%cjhXCwgy$#4=9LBM39qxmG zG|<8`HrNg;gD~_b`D{aZT@hR^AVF5VZTDBS_uI}+yJy~@yr|;KG^u8~s$Sz4?a00O zekkirpczR?M))_jh30Jco*3we_03#!PCErXfnY86eL477Yy+)9TCD+T7VT>oK~%$LJVEhr5();N$N~ZgA*o`$Ns?*m6b~Bm8#NW1`ztPjMHkW=f?( zpb?S+=UkaQl|ov9T3bL_{cF|Z4c)QoUtRPRb@`$*%Yi#bm5|&rr6EVlkyn&UqjNF$ p?y#$?8eQp6)|4`}qGH9wBa=lcicArm@~7pW`2>YU+a_rQ0061trn&$C literal 0 HcmV?d00001 diff --git a/x-pack/test/functional/es_archives/beats/list/mappings.json b/x-pack/test/functional/es_archives/beats/list/mappings.json new file mode 100644 index 0000000000000..92d89fb159733 --- /dev/null +++ b/x-pack/test/functional/es_archives/beats/list/mappings.json @@ -0,0 +1,82 @@ +{ + "type": "index", + "value": { + "index": ".management-beats", + "settings": { + "index": { + "codec": "best_compression", + "number_of_shards": "1", + "auto_expand_replicas": "0-1", + "number_of_replicas": "0" + } + }, + "mappings": { + "_doc": { + "dynamic": "strict", + "properties": { + "type": { + "type": "keyword" + }, + "enrollment_token": { + "properties": { + "token": { + "type": "keyword" + }, + "expires_on": { + "type": "date" + } + } + }, + "configuration_block": { + "properties": { + "tag": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "block_yml": { + "type": "text" + } + } + }, + "beat": { + "properties": { + "id": { + "type": "keyword" + }, + "access_token": { + "type": "keyword" + }, + "verified_on": { + "type": "date" + }, + "type": { + "type": "keyword" + }, + "host_ip": { + "type": "ip" + }, + "host_name": { + "type": "keyword" + }, + "ephemeral_id": { + "type": "keyword" + }, + "local_configuration_yml": { + "type": "text" + }, + "central_configuration_yml": { + "type": "text" + }, + "metadata": { + "dynamic": "true", + "type": "object" + } + } + } + } + } + } + } +}