From 49cfa6851dc494af94557669e5586936e297f8fc Mon Sep 17 00:00:00 2001 From: "Kees C. Bakker" Date: Wed, 24 Apr 2024 19:22:04 +0200 Subject: [PATCH] Add getUidBySlug for the Grafana Service. --- src/service/GrafanaService.js | 47 +++++++++++++-- test/grafana-service-test.js | 109 ++++++++++++++++++++-------------- test/grafana-v8-test.js | 3 +- 3 files changed, 106 insertions(+), 53 deletions(-) diff --git a/src/service/GrafanaService.js b/src/service/GrafanaService.js index 05daf91..8eb2235 100644 --- a/src/service/GrafanaService.js +++ b/src/service/GrafanaService.js @@ -216,6 +216,44 @@ class GrafanaService { return responses; } + /** + * Retrieves the UID of a dashboard by its slug. + * + * @param {string} slug - The slug of the dashboard. + * @returns {Promise} The UID of the dashboard, or undefined if not found. + */ + async getUidBySlug(slug) { + let client = this.client; + + const pageSize = 5000; + let page = 1; + + while (true) { + const url = `search?limit=${pageSize}&page=${encodeURIComponent(slug)}`; + + try { + const items = await client.get(url); + const dashboard = items + .map((i) => ({ + uid: i.uid, + slug: i.url.replace(`/d/${i.uid}/`, ''), + })) + .find((x) => x.slug == slug); + + if (dashboard && dashboard.uid) { + return dashboard.uid; + } + + if (items.length != pageSize) break; + page++; + } catch (err) { + this.logger.error(err, `Error while getting dashboard on URL: ${url}`); + } + } + + return null; + } + /** * Retrieves a dashboard from Grafana based on the provided UID. * @param {string} uid - The UID of the dashboard to retrieve. @@ -237,12 +275,9 @@ class GrafanaService { // check if we can improve the error message if (dashboard && dashboard.message === 'Dashboard not found') { - const dashboards = await this.client.get('search?type=dash-db'); - for (const item of Array.from(dashboards)) { - if (item.url.match(new RegExp(`\/d\/[a-z0-9\-]+\/${uid}$`, 'i'))) { - dashboard.message = `Try your query again with \`${item.uid}\` instead of \`${uid}\``; - break; - } + let realUid = await this.getUidBySlug(uid); + if (realUid) { + dashboard.message = `Try your query again with \`${realUid}\` instead of \`${uid}\``; } } diff --git a/test/grafana-service-test.js b/test/grafana-service-test.js index 301bbbb..17ac002 100644 --- a/test/grafana-service-test.js +++ b/test/grafana-service-test.js @@ -2,53 +2,72 @@ const { expect } = require('chai'); const { createTestBot, TestBotContext } = require('./common/TestBot'); describe('grafana service', () => { - describe('process', function () { - /** @type {TestBotContext} */ - let ctx; + /** @type {TestBotContext} */ + let ctx; - beforeEach(async () => { - ctx = await createTestBot(); + beforeEach(async () => { + ctx = await createTestBot(); + ctx + .nock('https://play.grafana.org') + .get('/api/dashboards/uid/AAy9r_bmk') + .replyWithFile(200, `${__dirname}/fixtures/v8/dashboard-monitoring-default.json`); + + ctx + .nock('https://play.grafana.org') + .get(/\/api\/search/) + .replyWithFile(200, `${__dirname}/fixtures/v8/search-tag.json`); + + [3, 7, 8].map((i) => ctx .nock('https://play.grafana.org') - .get('/api/dashboards/uid/AAy9r_bmk') - .replyWithFile(200, `${__dirname}/fixtures/v8/dashboard-monitoring-default.json`); - - [3, 7, 8].map((i) => - ctx - .nock('https://play.grafana.org') - .defaultReplyHeaders({ 'Content-Type': 'image/png' }) - .get('/render/d-solo/AAy9r_bmk/') - .query({ - panelId: i, - width: 1000, - height: 500, - from: 'now-6h', - to: 'now', - 'var-server': 'ww3.example.com', - }) - .replyWithFile(200, `${__dirname}/fixtures/v8/dashboard-monitoring-default.png`) - ); - }); - - afterEach(function () { - ctx?.shutdown(); - }); - - it('should process response', async () => { - const service = ctx.bot.createService({ robot: ctx.robot }); - const result = await service.process('AAy9r_bmk:cpu server=ww3.example.com now-6h', 2); - - expect(result).to.be.not.null; - expect(result).to.be.of.length(2); - - expect(result[0].grafanaChartLink).to.eql('https://play.grafana.org/d/AAy9r_bmk/?panelId=3&fullscreen&from=now-6h&to=now&var-server=ww3.example.com'); - expect(result[0].imageUrl).to.eql('https://play.grafana.org/render/d-solo/AAy9r_bmk/?panelId=3&width=1000&height=500&from=now-6h&to=now&var-server=ww3.example.com'); - expect(result[0].title).to.eql('CPU'); - - expect(result[1].grafanaChartLink).to.eql('https://play.grafana.org/d/AAy9r_bmk/?panelId=7&fullscreen&from=now-6h&to=now&var-server=ww3.example.com'); - expect(result[1].imageUrl).to.eql('https://play.grafana.org/render/d-solo/AAy9r_bmk/?panelId=7&width=1000&height=500&from=now-6h&to=now&var-server=ww3.example.com'); - expect(result[1].title).to.eql('CPU'); - - }); + .defaultReplyHeaders({ 'Content-Type': 'image/png' }) + .get('/render/d-solo/AAy9r_bmk/') + .query({ + panelId: i, + width: 1000, + height: 500, + from: 'now-6h', + to: 'now', + 'var-server': 'ww3.example.com', + }) + .replyWithFile(200, `${__dirname}/fixtures/v8/dashboard-monitoring-default.png`) + ); + }); + + afterEach(function () { + ctx?.shutdown(); }); + + it('should process response', async () => { + const service = ctx.bot.createService({ robot: ctx.robot }); + const result = await service.process('AAy9r_bmk:cpu server=ww3.example.com now-6h', 2); + + expect(result).to.be.not.null; + expect(result).to.be.of.length(2); + + expect(result[0].grafanaChartLink).to.eql( + 'https://play.grafana.org/d/AAy9r_bmk/?panelId=3&fullscreen&from=now-6h&to=now&var-server=ww3.example.com' + ); + expect(result[0].imageUrl).to.eql( + 'https://play.grafana.org/render/d-solo/AAy9r_bmk/?panelId=3&width=1000&height=500&from=now-6h&to=now&var-server=ww3.example.com' + ); + expect(result[0].title).to.eql('CPU'); + + expect(result[1].grafanaChartLink).to.eql( + 'https://play.grafana.org/d/AAy9r_bmk/?panelId=7&fullscreen&from=now-6h&to=now&var-server=ww3.example.com' + ); + expect(result[1].imageUrl).to.eql( + 'https://play.grafana.org/render/d-solo/AAy9r_bmk/?panelId=7&width=1000&height=500&from=now-6h&to=now&var-server=ww3.example.com' + ); + expect(result[1].title).to.eql('CPU'); + }); + + it('should resolve UID by slug', async () => { + const service = ctx.bot.createService({ robot: ctx.robot }); + const result = await service.getUidBySlug("the-four-golden-signals"); + expect(result).to.eql('000000109'); + }); + + + }); diff --git a/test/grafana-v8-test.js b/test/grafana-v8-test.js index 7a84f4a..625f54c 100644 --- a/test/grafana-v8-test.js +++ b/test/grafana-v8-test.js @@ -109,8 +109,7 @@ describe('grafana v8', () => { .reply(404, { message: 'Dashboard not found' }); ctx .nock('https://play.grafana.org') - .get('/api/search') - .query({ type: 'dash-db' }) + .get(/\/api\/search/) .replyWithFile(200, `${__dirname}/fixtures/v8/search.json`); ctx .nock('https://play.grafana.org')