This commit is contained in:
akvlad
2021-12-09 16:24:12 +02:00
parent dddfb8855c
commit e24f44e858
9 changed files with 154 additions and 35 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
node_modules
/docker-env/
/docker-env/

View File

@ -51,7 +51,8 @@ this.scanClickhouse = DATABASE.scanClickhouse;
/* Fastify Helper */
const fastify = require('fastify')({
logger: false,
logger: true,
bodyLimit: parseInt(process.env.FASTIFY_BODYLIMIT) || 5242880,
requestTimeout: parseInt(process.env.FASTIFY_REQUESTTIMEOUT) || 0,
maxRequestsPerSocket: parseInt(process.env.FASTIFY_MAXREQUESTS) || 0
@ -202,8 +203,8 @@ fastify.post('/config/v1/alerts', {
}
}
})
fastify.get('/config/v1/alerts', require('./lib/handlers/alerts/get_rules').bind(this))
fastify.get('/config/v1/alerts/:name', require('./lib/handlers/alerts/get_rule').bind(this))
fastify.get('/api/prom/rules', require('./lib/handlers/alerts/get_rules').bind(this))
fastify.get('/api/prom/rules/:ns/:rule', require('./lib/handlers/alerts/get_rule').bind(this))
fastify.put('/config/v1/alerts/:name', {
handler: require('./lib/handlers/alerts/put_rule').putAlert.bind(this),
schema: {

View File

@ -564,8 +564,6 @@
enabled = true
host = smtp.gmail.com:465
user = akvlad90@gmail.com
# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
password = ciprydyxoxdyuuow
;cert_file =
;key_file =
;skip_verify = false

View File

@ -2,22 +2,96 @@ const transpiler = require('../../parser/transpiler')
const { dropAlertViews, createAlertViews, incAlertMark, dropOutdatedParts, getLastAlert, getAlertRules } = require('./clickhouse')
const { samplesTableName } = require('../utils')
module.exports.addAlert = async (name, request, labels) => {
const watcher = new AlertWatcher(name, request, labels)
await watcher.run()
alerts[name] = watcher
module.exports.setGroup = async (namespace, group) => {
const rulesToAdd = alerts[namespace] && alerts[namespace][group.name]
? group.rules.filter(r => !alerts[namespace][group.name][r.alert])
: group.rules
const rulesToDelete = alerts[namespace] && alerts[namespace][group.name]
? Object.keys(alerts[namespace][group.name])
.filter(k => !group.alerts.some(r => r.alert === k))
.map(k => alerts[namespace][group.name][k])
: []
const rulesToUpdate = alerts[namespace] && alerts[namespace][group.name]
? group.rules
.filter(r => alerts[namespace][group.name][r.alert])
.map(r => [alerts[namespace][group.name][r.alert], r])
: []
for (const rul of rulesToAdd) {
const w = new AlertWatcher(rul)
await w.run()
rul._watcher = w
}
for (const rul of rulesToDelete) {
const w = rul._watcher
await w.drop()
}
for (const [_old, _new] of rulesToUpdate) {
const w = _old._watcher
await w.edit(_new)
_new._watcher = w
}
alerts[namespace] = alerts[namespace] || {}
alerts[namespace][group.name] = group
}
module.exports.editAlert = async (name, request, labels) => {
if (!alerts[name]) {
await module.exports.addAlert(name, request, labels)
/**
*
* @param ns {string}
* @returns {Object<string, Object<string, {name: string, interval: string, rules: Object}>> } namespace
*/
module.exports.getAll = () => {
return alerts
}
/**
*
* @param ns {string}
* @returns {Object<string, {name: string, interval: string, rules: Object}>} namespace
*/
module.exports.getNs = (ns) => {
return alerts[ns]
}
/**
*
* @param ns {string}
* @param grp {string}
* @returns {{name: string, interval: string, rules: Object} | undefined} group
*/
module.exports.getGroup = (ns, grp) => {
return alerts[ns] && alerts[ns][grp] ? alerts[ns][grp] : undefined
}
/**
*
* @param ns {string}
* @param grp {string}
* @returns {Promise<void>}
*/
module.exports.dropGroup = async (ns, grp) => {
if (!alerts[ns] || !alerts[ns][grp]) {
return
}
await alerts[name].edit(request, labels)
for (const rul of Object.values(alerts[ns][grp].rules)) {
const w = rul._watcher
await w.drop()
}
delete alerts[ns][grp]
}
module.exports.dropAlert = async (name) => {
alerts[name] && await alerts[name].drop()
/**
*
* @param ns {string}
* @returns {Promise<void>}
*/
module.exports.dropNs = async (ns) => {
if (!alerts[ns]) {
return
}
for (const grp of Object.keys(alerts[ns])) {
await module.exports.dropGroup(ns, grp)
}
delete alerts[ns]
}
module.exports.stop = () => {
@ -35,7 +109,7 @@ module.exports.startAlerting = async () => {
/**
*
* @type {Object<string, AlertWatcher>}
* @type {Object<string, Object<string, {name: string, interval: string, rules: Object}>>}
*/
let alerts = {}
@ -62,6 +136,10 @@ class AlertWatcher {
this.labels = labels
}
async update() {
}
async drop () {
this.stop()
await this._dropViews()

View File

@ -1006,10 +1006,12 @@ module.exports.deleteAlertRule = async (name) => {
*/
module.exports.dropAlertViews = async (name) => {
const fp = UTILS.fingerPrint('alert_rule' + name)
console.log(`DROP VIEW IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}`)
console.log(`DROP TABLE IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark`)
await axios.post(getClickhouseUrl(),
`DROP VIEW IF EXISTS _alert_view_${fp}`)
`DROP VIEW IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}`)
await axios.post(getClickhouseUrl(),
`DROP TABLE IF EXISTS _alert_view_${fp}_mark`)
`DROP TABLE IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark`)
}
/**
@ -1026,7 +1028,9 @@ module.exports.createAlertViews = async (name, request) => {
'mark'
]
)
request.withs.str_sel.inline = true
const strRequest = request.toString()
console.log(strRequest)
await axios.post(getClickhouseUrl(),
`CREATE TABLE IF NOT EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark (id UInt8 default 0,mark UInt64) ` +
'ENGINE ReplacingMergeTree(mark) ORDER BY id')

View File

@ -1,11 +1,32 @@
const { CLokiNotFound } = require('../errors')
const clickhouse = require('../../db/clickhouse')
const yaml = require('yaml')
module.exports = async (req, res) => {
const name = req.params.name
/*const name = req.params.name
const rule = await clickhouse.getAlertRule(name)
if (!rule) {
throw new CLokiNotFound(`Rule with name '${name}' not found`)
}
res.send(rule)
res.send(rule)*/
const result = {
fake: [
{
name: 'fake',
interval: '1m',
rules: [{
alert: 'fake',
expr: 'rate({test_id="_TEST_"}[1m])',
for: '1m',
annotations:
{
a1: 'fake'
},
labels: { l1: 'fake' }
}]
}
]
}
console.log(yaml.stringify(result.fake[0]))
res.header('Content-Type', 'yaml').send(yaml.stringify(result.fake[0]))
}

View File

@ -1,19 +1,28 @@
const { CLokiBadRequest } = require('../errors')
const clickhouse = require('../../db/clickhouse')
const yaml = require('yaml')
module.exports = async (req, res) => {
const limit = req.query.limit ? parseInt(req.query.limit) : 100
const offset = req.query.limit ? parseInt(req.query.offset) : 0
if (isNaN(limit)) {
throw new CLokiBadRequest('limit is not a number')
const result = {
fake: [
{
name: 'fake',
interval: '1m',
rules: [{
alert: 'fake',
expr: 'rate({test_id="_TEST_"}[1m])',
for: '1m',
annotations:
{
a1: 'fake'
},
labels: { l1: 'fake' }
}]
}
]
}
if (isNaN(offset)) {
throw new CLokiBadRequest('offset is not a number')
}
const result = await clickhouse.getAlertRules(limit, offset)
const count = await clickhouse.getAlertRulesCount()
res.send({
alerts: result,
count: count
})
//const result = await clickhouse.getAlertRules(limit, offset)
//const count = await clickhouse.getAlertRulesCount()
console.log(yaml.stringify(result))
res.header('Content-Type', 'yaml').send(yaml.stringify(result))
}

7
package-lock.json generated
View File

@ -2054,7 +2054,7 @@
}
},
"clickhouse-sql": {
"version": "git+https://github.com/metrico/node-clickhouse-sql.git#f88f606ca40dbaa5195809289eab9fa33e43c6c5",
"version": "git+https://github.com/metrico/node-clickhouse-sql.git#f81ce8a5e5885e010dbecbfb64866024661ef03b",
"from": "git+https://github.com/metrico/node-clickhouse-sql.git"
},
"cliui": {
@ -9088,6 +9088,11 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
},
"yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",

View File

@ -50,7 +50,8 @@
"scramjet": "^4.36.1",
"short-hash": "^1.0.0",
"snappyjs": "^0.6.1",
"ws": "^8.3.0"
"ws": "^8.3.0",
"yaml": "^1.10.2"
},
"devDependencies": {
"casual": "^1.6.2",