Auto API-key configuration #7
Merged
rozetko
merged 6 commits from auto-api-key-configuration
into master
2 years ago
13 changed files with 154 additions and 53 deletions
@ -1,5 +1,6 @@ |
|||||||
node_modules/ |
node_modules/ |
||||||
dist/ |
dist/ |
||||||
exported/ |
data/ |
||||||
config.json |
config.json |
||||||
package-lock.json |
package-lock.json |
||||||
|
api-keys.json |
||||||
|
@ -1,6 +1,3 @@ |
|||||||
{ |
{ |
||||||
"apiKeys" : { |
|
||||||
"http://localhost:3000": "eyJrIjoiTjlUcmtLSFRNcTdqeXBaQjB5REk2TFkyUDBDM0Z1bWciLCJuIjoiZXhwb3J0LW1hbmFnZXIiLCJpZCI6MX0=" |
|
||||||
}, |
|
||||||
"port": "8000" |
"port": "8000" |
||||||
} |
} |
||||||
|
@ -0,0 +1,13 @@ |
|||||||
|
version: '2' |
||||||
|
|
||||||
|
services: |
||||||
|
exporter: |
||||||
|
image: corpglory/grafana-data-exporter:latest |
||||||
|
restart: always |
||||||
|
ports: |
||||||
|
- 8000: 8000 |
||||||
|
volumes: |
||||||
|
- data:/var/www/data |
||||||
|
|
||||||
|
volumes: |
||||||
|
data |
@ -0,0 +1,53 @@ |
|||||||
|
import { upsertApiKey, validateGrafanaUrl } from '../services/api_keys'; |
||||||
|
|
||||||
|
import * as express from 'express' |
||||||
|
|
||||||
|
import * as _ from 'lodash'; |
||||||
|
|
||||||
|
|
||||||
|
async function checkConnection(req, res) { |
||||||
|
const query = req.query; |
||||||
|
|
||||||
|
const clientUrl = query.url; |
||||||
|
if (_.isEmpty(clientUrl)) { |
||||||
|
res.status(400).send('"url" field is required'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
validateGrafanaUrl(clientUrl); |
||||||
|
} catch (e) { |
||||||
|
res.status(500).send(e.message); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
res.status(200).send({ version: process.env.npm_package_version }); |
||||||
|
} |
||||||
|
|
||||||
|
async function connectPlugin(req, res) { |
||||||
|
const body = req.body; |
||||||
|
|
||||||
|
const clientUrl = body.url; |
||||||
|
if (_.isEmpty(clientUrl)) { |
||||||
|
res.status(400).send('"url" field is required'); |
||||||
|
return; |
||||||
|
} |
||||||
|
const apiToken = body.apiToken; |
||||||
|
if (_.isEmpty(apiToken)) { |
||||||
|
res.status(400).send('"apiToken" field is required'); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const grafanaUrl = new URL(clientUrl).origin; |
||||||
|
|
||||||
|
upsertApiKey(grafanaUrl, apiToken); |
||||||
|
|
||||||
|
console.log(`Grafana at ${grafanaUrl} is connected`); |
||||||
|
|
||||||
|
res.status(200).send({ version: process.env.npm_package_version }); |
||||||
|
} |
||||||
|
|
||||||
|
export const router = express.Router(); |
||||||
|
|
||||||
|
router.get('/', checkConnection); |
||||||
|
router.post('/', connectPlugin); |
@ -1,10 +1,10 @@ |
|||||||
import * as express from 'express' |
import * as express from 'express' |
||||||
|
|
||||||
|
|
||||||
async function deleteTask(req, res) { |
async function getStatus(req, res) { |
||||||
res.status(200).send({ version: 123 }); |
res.status(200).send({ version: process.env.npm_package_version }); |
||||||
} |
} |
||||||
|
|
||||||
export const router = express.Router(); |
export const router = express.Router(); |
||||||
|
|
||||||
router.get('/', deleteTask); |
router.get('/', getStatus); |
||||||
|
@ -0,0 +1,41 @@ |
|||||||
|
import { DATA_PATH } from '../config'; |
||||||
|
|
||||||
|
import * as path from 'path'; |
||||||
|
import * as fs from 'fs'; |
||||||
|
import * as _ from 'lodash'; |
||||||
|
|
||||||
|
|
||||||
|
const API_KEYS_FILE = path.join(DATA_PATH, 'api-keys.json'); |
||||||
|
if(!fs.existsSync(API_KEYS_FILE)) { |
||||||
|
console.log(`${API_KEYS_FILE} doesn't exist, creating`); |
||||||
|
fs.writeFileSync(API_KEYS_FILE, JSON.stringify({}), 'utf8'); |
||||||
|
} |
||||||
|
|
||||||
|
export function getApiKey(grafanaUrl: string): string | null { |
||||||
|
const data = fs.readFileSync(API_KEYS_FILE, 'utf8'); |
||||||
|
const apiKey = JSON.parse(data)[grafanaUrl]; |
||||||
|
if(_.isNil(apiKey)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return apiKey; |
||||||
|
} |
||||||
|
|
||||||
|
export function upsertApiKey(grafanaUrl: string, apiKey: string): void { |
||||||
|
const data = fs.readFileSync(API_KEYS_FILE, 'utf8'); |
||||||
|
const apiKeys = JSON.parse(data); |
||||||
|
|
||||||
|
apiKeys[grafanaUrl] = apiKey; |
||||||
|
|
||||||
|
fs.writeFileSync(API_KEYS_FILE, JSON.stringify(apiKeys), 'utf8'); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: query Grafana API if a key exists && remove the key if it doesn't work for specified grafanaUrl
|
||||||
|
export function validateGrafanaUrl(grafanaUrl: string) { |
||||||
|
const host = new URL(grafanaUrl).origin; |
||||||
|
const apiKey = getApiKey(host); |
||||||
|
|
||||||
|
if (_.isNil(apiKey) || apiKey === '') { |
||||||
|
throw new Error(`Please configure API key for ${host}`); |
||||||
|
} |
||||||
|
} |
@ -1,17 +1,5 @@ |
|||||||
import * as moment from 'moment-timezone'; |
import * as moment from 'moment-timezone'; |
||||||
|
|
||||||
export async function promisify(method: (...params: any[]) => Promise<any> | void, ...params: any[]) { |
|
||||||
return new Promise((resolve, reject) => { |
|
||||||
method(...params, (err, result) => { |
|
||||||
if(err) { |
|
||||||
reject(err); |
|
||||||
} else { |
|
||||||
resolve(result); |
|
||||||
} |
|
||||||
}) |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
export function toIsoString(msTimestamp: number, timeZone: string): string { |
export function toIsoString(msTimestamp: number, timeZone: string): string { |
||||||
return moment.tz(msTimestamp, timeZone).format('YYYY-MM-DD HH:mm:ssZ').replace(/:00$/, ''); |
return moment.tz(msTimestamp, timeZone).format('YYYY-MM-DD HH:mm:ssZ').replace(/:00$/, ''); |
||||||
} |
} |
||||||
|
Loading…
Reference in new issue