Skip to content

Commit

Permalink
Add getUidBySlug for the Grafana Service.
Browse files Browse the repository at this point in the history
  • Loading branch information
KeesCBakker committed Apr 24, 2024
1 parent 46fc436 commit 49cfa68
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 53 deletions.
47 changes: 41 additions & 6 deletions src/service/GrafanaService.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<string|null>} 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.
Expand All @@ -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}\``;
}
}

Expand Down
109 changes: 64 additions & 45 deletions test/grafana-service-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
});



});
3 changes: 1 addition & 2 deletions test/grafana-v8-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down

0 comments on commit 49cfa68

Please sign in to comment.