-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathluotsi.js
106 lines (82 loc) · 2.92 KB
/
luotsi.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
const Handlebars = require('handlebars')
const winston = require('winston')
const fs = require('fs')
const A = require('axios')
const Promise = require('bluebird')
const crypto = require('crypto')
const exec = require('child_process').exec
const env = (k, d) => process.env[k] || d
/* CHECKSUM STATE (mutable global) */
let CHECKSUM = ''
/* CONFIG */
const NODE_ENV = env('NODE_ENV', 'PROD')
const VERSION = '0.1.1'
const SETTINGS = {
cert_path: env('CERT_PATH', '/etc/haproxy/cert.pem'),
halti_url: env('HALTI_URL', 'http://localhost:4040') + '/api/v1/loadbalancers/config',
log_level: env('LOG_LEVEL', 'info'),
loop_interval: env('LOOP_INTERVAL', 5000),
maintenance_page: env('MAINTENANCE_PAGE', '/etc/haproxy/maintenance.http'),
stats: {
path: '/haproxy',
user: env('STATS_USER', 'hadmin'),
pass: env('STATS_PASS', 'hadmin'),
},
ssl: env('SSL_ENABLED', 'true'),
template_file: 'haproxy.template',
haproxy: {
user: env('HAPROXY_USER', 'haproxy'),
group: env('HAPROXY_GROUP', 'haproxy'),
config_file: env('HAPROXY_CONF', '/etc/haproxy/haproxy.cfg'),
reload_cmd: env('HAPROXY_RELOAD_CMD', 'service haproxy reload'),
}
}
/* UTILS */
const md5 = data => crypto.createHash('md5').update(data).digest('hex')
const noop = () => {}
const readFile = Promise.promisify(fs.readFile)
const writeFile = Promise.promisify(fs.writeFile)
const logger = new (winston.Logger)({
transports: [new (winston.transports.Console)({'timestamp': true, 'level': SETTINGS.log_level})]
})
/* HELPERS */
const renderConfig = (tmpl, settings, loadbalancers) => Handlebars.compile(tmpl)({loadbalancers, settings})
const reconfig = (config) => (
writeFile(SETTINGS.haproxy.config_file, config)
.then(() => Promise.promisify(exec)(SETTINGS.haproxy.reload_cmd))
)
function luotsiPoll (reconfig) {
Promise.all([
readFile(SETTINGS.template_file, 'utf-8'),
SETTINGS,
A.get(SETTINGS.halti_url).then(res => res.data)]
)
.spread(renderConfig)
.then(config => {
const hash = md5(config)
if (hash != CHECKSUM) {
CHECKSUM = hash // save checksum
logger.info('Update haproxy config, new checksum: %s', CHECKSUM)
reconfig(config)
.then(() => logger.info('HAProxy running with new config.'))
.catch(e => logger.error(`HAProxy reconfig failed!\n${e}`))
} else {
logger.debug(`Received config without any changes (checksum: ${hash}).`)
}
})
.catch(e => logger.error(`issue during polling loop\n ${e}`))
}
/* MAIN */
function main() {
logger.info('Halti - Luotsi loadbalancer v%s', VERSION)
logger.info(`starting polling loop, with loop interval ${SETTINGS.loop_interval}ms`)
setInterval(luotsiPoll.bind(null, reconfig), SETTINGS.loop_interval)
}
/* ENTRYPOINT (with test exports) */
if (NODE_ENV == 'PROD') main()
else if (NODE_ENV == 'DEV') main()
else if (NODE_ENV == 'TEST') {
module.exports = {
md5, renderConfig, readFile, writeFile, SETTINGS, luotsiPoll
}
}