Compare commits
No commits in common. "10434a9b2bb6832a9d743b061e4d1c799189c65d" and "df668286fbdc92043b17c6e1da2a116e58bf1bc3" have entirely different histories.
10434a9b2b
...
df668286fb
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
These parameters only apply to Monitors.
|
These parameters only apply to Monitors.
|
||||||
|
|
||||||
- [use_antietcd](#use_antietcd)
|
|
||||||
- [enable_prometheus](#enable_prometheus)
|
- [enable_prometheus](#enable_prometheus)
|
||||||
- [mon_http_port](#mon_http_port)
|
- [mon_http_port](#mon_http_port)
|
||||||
- [mon_http_ip](#mon_http_ip)
|
- [mon_http_ip](#mon_http_ip)
|
||||||
|
@ -25,39 +24,12 @@ These parameters only apply to Monitors.
|
||||||
- [placement_levels](#placement_levels)
|
- [placement_levels](#placement_levels)
|
||||||
- [use_old_pg_combinator](#use_old_pg_combinator)
|
- [use_old_pg_combinator](#use_old_pg_combinator)
|
||||||
|
|
||||||
## use_antietcd
|
|
||||||
|
|
||||||
- Type: boolean
|
|
||||||
- Default: false
|
|
||||||
|
|
||||||
Enable experimental built-in etcd replacement (clustered key-value database):
|
|
||||||
[antietcd](https://git.yourcmc.ru/vitalif/antietcd/).
|
|
||||||
|
|
||||||
When set to true, monitor runs internal antietcd automatically if it finds
|
|
||||||
a network interface with an IP address matching one of addresses in the
|
|
||||||
`etcd_address` configuration option (in `/etc/vitastor/vitastor.conf` or in
|
|
||||||
the monitor command line). If there are multiple matching addresses, it also
|
|
||||||
checks `antietcd_port` and antietcd is started for address with matching port.
|
|
||||||
By default, antietcd accepts connection on the selected IP address, but it
|
|
||||||
can also be overridden manually in the `antietcd_ip` option.
|
|
||||||
|
|
||||||
When antietcd is started, monitor stores cluster metadata itself and exposes
|
|
||||||
a etcd-compatible REST API. On disk, these metadata are stored in
|
|
||||||
`/var/lib/vitastor/mon_2379.json.gz` (can be overridden in antietcd_data_file
|
|
||||||
or antietcd_data_dir options). All other antietcd parameters
|
|
||||||
(see [here](https://git.yourcmc.ru/vitalif/antietcd/)) except node_id,
|
|
||||||
cluster, cluster_key, persist_filter, stale_read can also be set in
|
|
||||||
Vitastor configuration with `antietcd_` prefix.
|
|
||||||
|
|
||||||
## enable_prometheus
|
## enable_prometheus
|
||||||
|
|
||||||
- Type: boolean
|
- Type: boolean
|
||||||
- Default: true
|
- Default: true
|
||||||
|
|
||||||
Enable built-in Prometheus metrics exporter at mon_http_port (8060 by default).
|
Enable built-in Prometheus metrics exporter
|
||||||
|
|
||||||
Note that only the active (master) monitor exposes metrics, others return
|
|
||||||
HTTP 503. So you should add all monitor URLs to your Prometheus job configuration.
|
|
||||||
|
|
||||||
## mon_http_port
|
## mon_http_port
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
Данные параметры используются только мониторами Vitastor.
|
Данные параметры используются только мониторами Vitastor.
|
||||||
|
|
||||||
- [use_antietcd](#use_antietcd)
|
|
||||||
- [enable_prometheus](#enable_prometheus)
|
- [enable_prometheus](#enable_prometheus)
|
||||||
- [mon_http_port](#mon_http_port)
|
- [mon_http_port](#mon_http_port)
|
||||||
- [mon_http_ip](#mon_http_ip)
|
- [mon_http_ip](#mon_http_ip)
|
||||||
|
@ -25,40 +24,12 @@
|
||||||
- [placement_levels](#placement_levels)
|
- [placement_levels](#placement_levels)
|
||||||
- [use_old_pg_combinator](#use_old_pg_combinator)
|
- [use_old_pg_combinator](#use_old_pg_combinator)
|
||||||
|
|
||||||
## use_antietcd
|
|
||||||
|
|
||||||
- Тип: булево (да/нет)
|
|
||||||
- Значение по умолчанию: false
|
|
||||||
|
|
||||||
Включить экспериментальный встроенный заменитель etcd (кластерную БД ключ-значение):
|
|
||||||
[antietcd](https://git.yourcmc.ru/vitalif/antietcd/).
|
|
||||||
|
|
||||||
Если параметр установлен в true, монитор запускает antietcd автоматически,
|
|
||||||
если обнаруживает сетевой интерфейс с одним из адресов, указанных в опции
|
|
||||||
конфигурации `etcd_address` (в `/etc/vitastor/vitastor.conf` или в опциях
|
|
||||||
командной строки монитора). Если таких адресов несколько, также проверяется
|
|
||||||
опция `antietcd_port` и antietcd запускается для адреса с соответствующим
|
|
||||||
портом. По умолчанию antietcd принимает подключения по выбранному совпадающему
|
|
||||||
IP, но его также можно определить вручную опцией `antietcd_ip`.
|
|
||||||
|
|
||||||
При запуске antietcd монитор сам хранит центральные метаданные кластера и
|
|
||||||
выставляет etcd-совместимое REST API. На диске эти метаданные хранятся в файле
|
|
||||||
`/var/lib/vitastor/mon_2379.json.gz` (можно переопределить параметрами
|
|
||||||
antietcd_data_file или antietcd_data_dir). Все остальные параметры antietcd
|
|
||||||
(смотрите [по ссылке](https://git.yourcmc.ru/vitalif/antietcd/)), за исключением
|
|
||||||
node_id, cluster, cluster_key, persist_filter, stale_read также можно задавать
|
|
||||||
в конфигурации Vitastor с префиксом `antietcd_`.
|
|
||||||
|
|
||||||
## enable_prometheus
|
## enable_prometheus
|
||||||
|
|
||||||
- Тип: булево (да/нет)
|
- Тип: булево (да/нет)
|
||||||
- Значение по умолчанию: true
|
- Значение по умолчанию: true
|
||||||
|
|
||||||
Включить встроенный Prometheus-экспортер метрик на порту mon_http_port (по умолчанию 8060).
|
Включить встроенный Prometheus-экспортер метри
|
||||||
|
|
||||||
Обратите внимание, что метрики выставляет только активный (главный) монитор, остальные
|
|
||||||
возвращают статус HTTP 503, поэтому вам следует добавлять адреса всех мониторов
|
|
||||||
в задание по сбору метрик Prometheus.
|
|
||||||
|
|
||||||
## mon_http_port
|
## mon_http_port
|
||||||
|
|
||||||
|
|
|
@ -1,58 +1,8 @@
|
||||||
- name: use_antietcd
|
|
||||||
type: bool
|
|
||||||
default: false
|
|
||||||
info: |
|
|
||||||
Enable experimental built-in etcd replacement (clustered key-value database):
|
|
||||||
[antietcd](https://git.yourcmc.ru/vitalif/antietcd/).
|
|
||||||
|
|
||||||
When set to true, monitor runs internal antietcd automatically if it finds
|
|
||||||
a network interface with an IP address matching one of addresses in the
|
|
||||||
`etcd_address` configuration option (in `/etc/vitastor/vitastor.conf` or in
|
|
||||||
the monitor command line). If there are multiple matching addresses, it also
|
|
||||||
checks `antietcd_port` and antietcd is started for address with matching port.
|
|
||||||
By default, antietcd accepts connection on the selected IP address, but it
|
|
||||||
can also be overridden manually in the `antietcd_ip` option.
|
|
||||||
|
|
||||||
When antietcd is started, monitor stores cluster metadata itself and exposes
|
|
||||||
a etcd-compatible REST API. On disk, these metadata are stored in
|
|
||||||
`/var/lib/vitastor/mon_2379.json.gz` (can be overridden in antietcd_data_file
|
|
||||||
or antietcd_data_dir options). All other antietcd parameters
|
|
||||||
(see [here](https://git.yourcmc.ru/vitalif/antietcd/)) except node_id,
|
|
||||||
cluster, cluster_key, persist_filter, stale_read can also be set in
|
|
||||||
Vitastor configuration with `antietcd_` prefix.
|
|
||||||
info_ru: |
|
|
||||||
Включить экспериментальный встроенный заменитель etcd (кластерную БД ключ-значение):
|
|
||||||
[antietcd](https://git.yourcmc.ru/vitalif/antietcd/).
|
|
||||||
|
|
||||||
Если параметр установлен в true, монитор запускает antietcd автоматически,
|
|
||||||
если обнаруживает сетевой интерфейс с одним из адресов, указанных в опции
|
|
||||||
конфигурации `etcd_address` (в `/etc/vitastor/vitastor.conf` или в опциях
|
|
||||||
командной строки монитора). Если таких адресов несколько, также проверяется
|
|
||||||
опция `antietcd_port` и antietcd запускается для адреса с соответствующим
|
|
||||||
портом. По умолчанию antietcd принимает подключения по выбранному совпадающему
|
|
||||||
IP, но его также можно определить вручную опцией `antietcd_ip`.
|
|
||||||
|
|
||||||
При запуске antietcd монитор сам хранит центральные метаданные кластера и
|
|
||||||
выставляет etcd-совместимое REST API. На диске эти метаданные хранятся в файле
|
|
||||||
`/var/lib/vitastor/mon_2379.json.gz` (можно переопределить параметрами
|
|
||||||
antietcd_data_file или antietcd_data_dir). Все остальные параметры antietcd
|
|
||||||
(смотрите [по ссылке](https://git.yourcmc.ru/vitalif/antietcd/)), за исключением
|
|
||||||
node_id, cluster, cluster_key, persist_filter, stale_read также можно задавать
|
|
||||||
в конфигурации Vitastor с префиксом `antietcd_`.
|
|
||||||
- name: enable_prometheus
|
- name: enable_prometheus
|
||||||
type: bool
|
type: bool
|
||||||
default: true
|
default: true
|
||||||
info: |
|
info: Enable built-in Prometheus metrics exporter
|
||||||
Enable built-in Prometheus metrics exporter at mon_http_port (8060 by default).
|
info_ru: Включить встроенный Prometheus-экспортер метри
|
||||||
|
|
||||||
Note that only the active (master) monitor exposes metrics, others return
|
|
||||||
HTTP 503. So you should add all monitor URLs to your Prometheus job configuration.
|
|
||||||
info_ru: |
|
|
||||||
Включить встроенный Prometheus-экспортер метрик на порту mon_http_port (по умолчанию 8060).
|
|
||||||
|
|
||||||
Обратите внимание, что метрики выставляет только активный (главный) монитор, остальные
|
|
||||||
возвращают статус HTTP 503, поэтому вам следует добавлять адреса всех мониторов
|
|
||||||
в задание по сбору метрик Prometheus.
|
|
||||||
- name: mon_http_port
|
- name: mon_http_port
|
||||||
type: int
|
type: int
|
||||||
default: 8060
|
default: 8060
|
||||||
|
|
|
@ -34,8 +34,6 @@
|
||||||
- [Client write-back cache](../config/client.en.md#client_enable_writeback)
|
- [Client write-back cache](../config/client.en.md#client_enable_writeback)
|
||||||
- [Intelligent recovery auto-tuning](../config/osd.en.md#recovery_tune_interval)
|
- [Intelligent recovery auto-tuning](../config/osd.en.md#recovery_tune_interval)
|
||||||
- [Clustered file system](../usage/nfs.en.md#vitastorfs)
|
- [Clustered file system](../usage/nfs.en.md#vitastorfs)
|
||||||
- [Experimental internal etcd replacement - antietcd](../config/monitor.en.md#use_antietcd)
|
|
||||||
- [Built-in Prometheus metric exporter](../config/monitor.en.md#enable_prometheus)
|
|
||||||
|
|
||||||
## Plugins and tools
|
## Plugins and tools
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
- [Буферизация записи на стороне клиента](../config/client.ru.md#client_enable_writeback)
|
- [Буферизация записи на стороне клиента](../config/client.ru.md#client_enable_writeback)
|
||||||
- [Интеллектуальная автоподстройка скорости восстановления](../config/osd.ru.md#recovery_tune_interval)
|
- [Интеллектуальная автоподстройка скорости восстановления](../config/osd.ru.md#recovery_tune_interval)
|
||||||
- [Кластерная файловая система](../usage/nfs.ru.md#vitastorfs)
|
- [Кластерная файловая система](../usage/nfs.ru.md#vitastorfs)
|
||||||
- [Экспериментальная встроенная замена etcd - antietcd](../config/monitor.ru.md#use_antietcd)
|
|
||||||
- [Встроенный Prometheus-экспортер метрик](../config/monitor.ru.md#enable_prometheus)
|
|
||||||
|
|
||||||
## Драйверы и инструменты
|
## Драйверы и инструменты
|
||||||
|
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
const AntiEtcd = require('antietcd');
|
|
||||||
|
|
||||||
const vitastor_persist_filter = require('./vitastor_persist_filter.js');
|
|
||||||
const { b64, local_ips } = require('./utils.js');
|
|
||||||
|
|
||||||
class AntiEtcdAdapter
|
|
||||||
{
|
|
||||||
static async start_antietcd(config)
|
|
||||||
{
|
|
||||||
let antietcd;
|
|
||||||
if (config.use_antietcd)
|
|
||||||
{
|
|
||||||
let fileConfig = {};
|
|
||||||
if (fs.existsSync(config.config_path||'/etc/vitastor/vitastor.conf'))
|
|
||||||
{
|
|
||||||
fileConfig = JSON.parse(fs.readFileSync(config.config_path||'/etc/vitastor/vitastor.conf', { encoding: 'utf-8' }));
|
|
||||||
}
|
|
||||||
let mergedConfig = { ...fileConfig, ...config };
|
|
||||||
let cluster = mergedConfig.etcd_address;
|
|
||||||
if (!(cluster instanceof Array))
|
|
||||||
cluster = cluster ? (''+(cluster||'')).split(/,+/) : [];
|
|
||||||
cluster = Object.keys(cluster.reduce((a, url) =>
|
|
||||||
{
|
|
||||||
a[url.toLowerCase().replace(/^https?:\/\//, '').replace(/\/.*$/, '')] = true;
|
|
||||||
return a;
|
|
||||||
}, {}));
|
|
||||||
const cfg_port = mergedConfig.antietcd_port;
|
|
||||||
const is_local = local_ips(true).reduce((a, c) => { a[c] = true; return a; }, {});
|
|
||||||
const selected = cluster.map(s => s.split(':', 2)).filter(ip => is_local[ip[0]] && (!cfg_port || ip[1] == cfg_port));
|
|
||||||
if (selected.length > 1)
|
|
||||||
{
|
|
||||||
console.error('More than 1 etcd_address matches local IPs, please specify port');
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
else if (selected.length == 1)
|
|
||||||
{
|
|
||||||
const antietcd_config = {
|
|
||||||
ip: selected[0][0],
|
|
||||||
port: selected[0][1],
|
|
||||||
data: mergedConfig.antietcd_data_file || ((mergedConfig.antietcd_data_dir || '/var/lib/vitastor') + '/mon_'+selected[0][1]+'.json.gz'),
|
|
||||||
persist_filter: vitastor_persist_filter(mergedConfig.etcd_prefix || '/vitastor'),
|
|
||||||
node_id: selected[0][0]+':'+selected[0][1], // node_id = ip:port
|
|
||||||
cluster: (cluster.length == 1 ? null : cluster),
|
|
||||||
cluster_key: (mergedConfig.etcd_prefix || '/vitastor'),
|
|
||||||
stale_read: 1,
|
|
||||||
};
|
|
||||||
for (const key in config)
|
|
||||||
{
|
|
||||||
if (key.substr(0, 9) === 'antietcd_')
|
|
||||||
{
|
|
||||||
const noprefix = key.substr(9);
|
|
||||||
if (!(noprefix in antietcd_config) || noprefix == 'ip' || noprefix == 'cluster_key')
|
|
||||||
{
|
|
||||||
antietcd_config[noprefix] = config[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
antietcd = new AntiEtcd(antietcd_config);
|
|
||||||
await antietcd.start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
console.log('Antietcd is enabled, but etcd_address does not contain local IPs, proceeding without it');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return antietcd;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(mon, antietcd)
|
|
||||||
{
|
|
||||||
this.mon = mon;
|
|
||||||
this.antietcd = antietcd;
|
|
||||||
this.on_leader = [];
|
|
||||||
this.on_change = (st) =>
|
|
||||||
{
|
|
||||||
if (st.state === 'leader')
|
|
||||||
{
|
|
||||||
for (const cb of this.on_leader)
|
|
||||||
{
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
this.on_leader = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.antietcd.on('raftchange', this.on_change);
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_config(/*config*/)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_watcher()
|
|
||||||
{
|
|
||||||
this.antietcd.off('raftchange', this.on_change);
|
|
||||||
const watch_id = this.watch_id;
|
|
||||||
if (watch_id)
|
|
||||||
{
|
|
||||||
this.watch_id = null;
|
|
||||||
this.antietcd.cancel_watch(watch_id).catch(console.error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async start_watcher()
|
|
||||||
{
|
|
||||||
if (this.watch_id)
|
|
||||||
{
|
|
||||||
await this.antietcd.cancel_watch(this.watch_id);
|
|
||||||
this.watch_id = null;
|
|
||||||
}
|
|
||||||
const watch_id = await this.antietcd.create_watch({
|
|
||||||
key: b64(this.mon.config.etcd_prefix+'/'),
|
|
||||||
range_end: b64(this.mon.config.etcd_prefix+'0'),
|
|
||||||
start_revision: ''+this.mon.etcd_watch_revision,
|
|
||||||
watch_id: 1,
|
|
||||||
progress_notify: true,
|
|
||||||
}, (message) =>
|
|
||||||
{
|
|
||||||
setImmediate(() => this.mon.on_message(message.result));
|
|
||||||
});
|
|
||||||
console.log('Successfully subscribed to antietcd revision '+this.antietcd.etctree.mod_revision);
|
|
||||||
this.watch_id = watch_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
async become_master()
|
|
||||||
{
|
|
||||||
if (!this.antietcd.raft)
|
|
||||||
{
|
|
||||||
console.log('Running in non-clustered mode');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
console.log('Waiting to become master');
|
|
||||||
await new Promise(ok => this.on_leader.push(ok));
|
|
||||||
}
|
|
||||||
const state = { ...this.mon.get_mon_state(), id: ''+this.mon.etcd_lease_id };
|
|
||||||
await this.etcd_call('/kv/txn', {
|
|
||||||
success: [ { requestPut: { key: b64(this.mon.config.etcd_prefix+'/mon/master'), value: b64(JSON.stringify(state)), lease: ''+this.mon.etcd_lease_id } } ],
|
|
||||||
}, this.mon.config.etcd_start_timeout, 0);
|
|
||||||
if (this.antietcd.raft)
|
|
||||||
{
|
|
||||||
console.log('Became master');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async etcd_call(path, body, timeout, retries)
|
|
||||||
{
|
|
||||||
let retry = 0;
|
|
||||||
if (retries >= 0 && retries < 1)
|
|
||||||
{
|
|
||||||
retries = 1;
|
|
||||||
}
|
|
||||||
let prev = 0;
|
|
||||||
while (retries < 0 || retry < retries)
|
|
||||||
{
|
|
||||||
retry++;
|
|
||||||
if (this.mon.stopped)
|
|
||||||
{
|
|
||||||
throw new Error('Monitor instance is stopped');
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Date.now()-prev < timeout)
|
|
||||||
{
|
|
||||||
await new Promise(ok => setTimeout(ok, timeout-(Date.now()-prev)));
|
|
||||||
}
|
|
||||||
prev = Date.now();
|
|
||||||
const res = await this.antietcd.api(path.replace(/^\/+/, '').replace(/\/+$/, '').replace(/\/+/g, '_'), body);
|
|
||||||
if (res.error)
|
|
||||||
{
|
|
||||||
console.error('Failed to query antietcd '+path+' (retry '+retry+'/'+retries+'): '+res.error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e)
|
|
||||||
{
|
|
||||||
console.error('Failed to query antietcd '+path+' (retry '+retry+'/'+retries+'): '+e.stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error('Failed to query antietcd ('+retries+' retries)');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = AntiEtcdAdapter;
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const WebSocket = require('ws');
|
const WebSocket = require('ws');
|
||||||
const { b64, local_ips } = require('./utils.js');
|
|
||||||
|
|
||||||
const MON_STOPPED = 'Monitor instance is stopped';
|
const MON_STOPPED = 'Monitor instance is stopped';
|
||||||
|
|
||||||
|
@ -24,7 +23,7 @@ class EtcdAdapter
|
||||||
|
|
||||||
parse_etcd_addresses(addrs)
|
parse_etcd_addresses(addrs)
|
||||||
{
|
{
|
||||||
const is_local_ip = local_ips(true).reduce((a, c) => { a[c] = true; return a; }, {});
|
const is_local_ip = this.mon.local_ips(true).reduce((a, c) => { a[c] = true; return a; }, {});
|
||||||
this.etcd_local = [];
|
this.etcd_local = [];
|
||||||
this.etcd_urls = [];
|
this.etcd_urls = [];
|
||||||
this.selected_etcd_url = null;
|
this.selected_etcd_url = null;
|
||||||
|
@ -349,4 +348,9 @@ function POST(url, body, timeout)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function b64(str)
|
||||||
|
{
|
||||||
|
return Buffer.from(str).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = EtcdAdapter;
|
module.exports = EtcdAdapter;
|
||||||
|
|
|
@ -23,4 +23,4 @@ for (let i = 2; i < process.argv.length; i++)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mon.run_forever(options).catch(console.error);
|
Mon.run_forever(options);
|
||||||
|
|
54
mon/mon.js
54
mon/mon.js
|
@ -5,7 +5,6 @@ const { URL } = require('url');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const AntiEtcdAdapter = require('./antietcd_adapter.js');
|
|
||||||
const EtcdAdapter = require('./etcd_adapter.js');
|
const EtcdAdapter = require('./etcd_adapter.js');
|
||||||
const { create_http_server } = require('./http_server.js');
|
const { create_http_server } = require('./http_server.js');
|
||||||
const { export_prometheus_metrics } = require('./prometheus.js');
|
const { export_prometheus_metrics } = require('./prometheus.js');
|
||||||
|
@ -15,23 +14,17 @@ const { sum_op_stats, sum_object_counts, sum_inode_stats, serialize_bigints } =
|
||||||
const stableStringify = require('./stable-stringify.js');
|
const stableStringify = require('./stable-stringify.js');
|
||||||
const { scale_pg_history } = require('./pg_utils.js');
|
const { scale_pg_history } = require('./pg_utils.js');
|
||||||
const { get_osd_tree } = require('./osd_tree.js');
|
const { get_osd_tree } = require('./osd_tree.js');
|
||||||
const { b64, de64, local_ips } = require('./utils.js');
|
|
||||||
const { recheck_primary, save_new_pgs_txn, generate_pool_pgs } = require('./pg_gen.js');
|
const { recheck_primary, save_new_pgs_txn, generate_pool_pgs } = require('./pg_gen.js');
|
||||||
|
|
||||||
class Mon
|
class Mon
|
||||||
{
|
{
|
||||||
static async run_forever(config)
|
static run_forever(config)
|
||||||
{
|
{
|
||||||
let antietcd = await AntiEtcdAdapter.start_antietcd(config);
|
|
||||||
let mon;
|
let mon;
|
||||||
const run = () =>
|
const run = () =>
|
||||||
{
|
{
|
||||||
console.log('Starting Monitor');
|
console.log('Starting Monitor');
|
||||||
const my_mon = new Mon(config);
|
const my_mon = new Mon(config);
|
||||||
my_mon.etcd = antietcd
|
|
||||||
? new AntiEtcdAdapter(my_mon, antietcd)
|
|
||||||
: new EtcdAdapter(my_mon);
|
|
||||||
my_mon.etcd.parse_config(my_mon.config);
|
|
||||||
mon = my_mon;
|
mon = my_mon;
|
||||||
my_mon.on_die = () =>
|
my_mon.on_die = () =>
|
||||||
{
|
{
|
||||||
|
@ -68,6 +61,8 @@ class Mon
|
||||||
this.state = JSON.parse(JSON.stringify(etcd_tree));
|
this.state = JSON.parse(JSON.stringify(etcd_tree));
|
||||||
this.prev_stats = { osd_stats: {}, osd_diff: {} };
|
this.prev_stats = { osd_stats: {}, osd_diff: {} };
|
||||||
this.recheck_pgs_active = false;
|
this.recheck_pgs_active = false;
|
||||||
|
this.etcd = new EtcdAdapter(this);
|
||||||
|
this.etcd.parse_config(this.config);
|
||||||
this.watcher_active = false;
|
this.watcher_active = false;
|
||||||
if (this.config.enable_prometheus || !('enable_prometheus' in this.config))
|
if (this.config.enable_prometheus || !('enable_prometheus' in this.config))
|
||||||
{
|
{
|
||||||
|
@ -182,8 +177,8 @@ class Mon
|
||||||
this.etcd_watch_revision = BigInt(msg.header.revision)+BigInt(1);
|
this.etcd_watch_revision = BigInt(msg.header.revision)+BigInt(1);
|
||||||
for (const e of msg.events||[])
|
for (const e of msg.events||[])
|
||||||
{
|
{
|
||||||
const kv = this.parse_kv(e.kv);
|
this.parse_kv(e.kv);
|
||||||
const key = kv.key.substr(this.config.etcd_prefix.length);
|
const key = e.kv.key.substr(this.config.etcd_prefix.length);
|
||||||
if (key.substr(0, 11) == '/osd/state/')
|
if (key.substr(0, 11) == '/osd/state/')
|
||||||
{
|
{
|
||||||
stats_changed = true;
|
stats_changed = true;
|
||||||
|
@ -203,7 +198,7 @@ class Mon
|
||||||
}
|
}
|
||||||
if (this.config.verbose)
|
if (this.config.verbose)
|
||||||
{
|
{
|
||||||
console.log(JSON.stringify({ ...e, kv: kv || undefined }));
|
console.log(JSON.stringify(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pg_states_changed)
|
if (pg_states_changed)
|
||||||
|
@ -287,7 +282,7 @@ class Mon
|
||||||
|
|
||||||
get_mon_state()
|
get_mon_state()
|
||||||
{
|
{
|
||||||
return { ip: local_ips(), hostname: os.hostname() };
|
return { ip: this.local_ips(), hostname: os.hostname() };
|
||||||
}
|
}
|
||||||
|
|
||||||
async get_lease()
|
async get_lease()
|
||||||
|
@ -725,16 +720,15 @@ class Mon
|
||||||
{
|
{
|
||||||
if (!kv || !kv.key)
|
if (!kv || !kv.key)
|
||||||
{
|
{
|
||||||
return kv;
|
return;
|
||||||
}
|
}
|
||||||
kv = { ...kv };
|
|
||||||
kv.key = de64(kv.key);
|
kv.key = de64(kv.key);
|
||||||
kv.value = kv.value ? de64(kv.value) : null;
|
kv.value = kv.value ? de64(kv.value) : null;
|
||||||
let key = kv.key.substr(this.config.etcd_prefix.length+1);
|
let key = kv.key.substr(this.config.etcd_prefix.length+1);
|
||||||
if (!etcd_allow.exec(key))
|
if (!etcd_allow.exec(key))
|
||||||
{
|
{
|
||||||
console.log('Bad key in etcd: '+kv.key+' = '+kv.value);
|
console.log('Bad key in etcd: '+kv.key+' = '+kv.value);
|
||||||
return kv;
|
return;
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -743,7 +737,7 @@ class Mon
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
console.log('Bad value in etcd: '+kv.key+' = '+kv.value);
|
console.log('Bad value in etcd: '+kv.key+' = '+kv.value);
|
||||||
return kv;
|
return;
|
||||||
}
|
}
|
||||||
let key_parts = key.split('/');
|
let key_parts = key.split('/');
|
||||||
let cur = this.state;
|
let cur = this.state;
|
||||||
|
@ -793,7 +787,6 @@ class Mon
|
||||||
!this.state.osd.stats[osd_num] ? 0 : this.state.osd.stats[osd_num].time+this.config.osd_out_time
|
!this.state.osd.stats[osd_num] ? 0 : this.state.osd.stats[osd_num].time+this.config.osd_out_time
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return kv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_die(err)
|
_die(err)
|
||||||
|
@ -803,6 +796,33 @@ class Mon
|
||||||
this.on_stop().catch(console.error);
|
this.on_stop().catch(console.error);
|
||||||
this.on_die();
|
this.on_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local_ips(all)
|
||||||
|
{
|
||||||
|
const ips = [];
|
||||||
|
const ifaces = os.networkInterfaces();
|
||||||
|
for (const ifname in ifaces)
|
||||||
|
{
|
||||||
|
for (const iface of ifaces[ifname])
|
||||||
|
{
|
||||||
|
if (iface.family == 'IPv4' && !iface.internal || all)
|
||||||
|
{
|
||||||
|
ips.push(iface.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ips;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function b64(str)
|
||||||
|
{
|
||||||
|
return Buffer.from(str).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
function de64(str)
|
||||||
|
{
|
||||||
|
return Buffer.from(str, 'base64').toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sha1hex(str)
|
function sha1hex(str)
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
"author": "Vitaliy Filippov",
|
"author": "Vitaliy Filippov",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"antietcd": "^1.0.5",
|
|
||||||
"sprintf-js": "^1.1.2",
|
"sprintf-js": "^1.1.2",
|
||||||
"ws": "^7.2.5"
|
"ws": "^7.2.5"
|
||||||
},
|
},
|
||||||
|
|
37
mon/utils.js
37
mon/utils.js
|
@ -1,37 +0,0 @@
|
||||||
// Copyright (c) Vitaliy Filippov, 2019+
|
|
||||||
// License: VNPL-1.1 (see README.md for details)
|
|
||||||
|
|
||||||
const os = require('os');
|
|
||||||
|
|
||||||
function local_ips(all)
|
|
||||||
{
|
|
||||||
const ips = [];
|
|
||||||
const ifaces = os.networkInterfaces();
|
|
||||||
for (const ifname in ifaces)
|
|
||||||
{
|
|
||||||
for (const iface of ifaces[ifname])
|
|
||||||
{
|
|
||||||
if (iface.family == 'IPv4' && !iface.internal || all)
|
|
||||||
{
|
|
||||||
ips.push(iface.address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ips;
|
|
||||||
}
|
|
||||||
|
|
||||||
function b64(str)
|
|
||||||
{
|
|
||||||
return Buffer.from(str).toString('base64');
|
|
||||||
}
|
|
||||||
|
|
||||||
function de64(str)
|
|
||||||
{
|
|
||||||
return Buffer.from(str, 'base64').toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
b64,
|
|
||||||
de64,
|
|
||||||
local_ips,
|
|
||||||
};
|
|
|
@ -1,48 +0,0 @@
|
||||||
// AntiEtcd persistence filter for Vitastor
|
|
||||||
// (c) Vitaliy Filippov, 2024
|
|
||||||
// License: Mozilla Public License 2.0 or Vitastor Network Public License 1.1
|
|
||||||
|
|
||||||
function vitastor_persist_filter(cfg)
|
|
||||||
{
|
|
||||||
const prefix = cfg.vitastor_prefix || '/vitastor';
|
|
||||||
return (key, value) =>
|
|
||||||
{
|
|
||||||
if (key.substr(0, prefix.length+'/osd/stats/'.length) == prefix+'/osd/stats/')
|
|
||||||
{
|
|
||||||
if (value)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value = JSON.parse(value);
|
|
||||||
value = JSON.stringify({
|
|
||||||
bitmap_granularity: value.bitmap_granularity || undefined,
|
|
||||||
data_block_size: value.data_block_size || undefined,
|
|
||||||
host: value.host || undefined,
|
|
||||||
immediate_commit: value.immediate_commit || undefined,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (e)
|
|
||||||
{
|
|
||||||
console.error('invalid JSON in '+key+' = '+value+': '+e);
|
|
||||||
value = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = undefined;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
else if (key.substr(0, prefix.length+'/osd/'.length) == prefix+'/osd/' ||
|
|
||||||
key.substr(0, prefix.length+'/inode/stats/'.length) == prefix+'/inode/stats/' ||
|
|
||||||
key.substr(0, prefix.length+'/pg/stats/'.length) == prefix+'/pg/stats/' ||
|
|
||||||
key.substr(0, prefix.length+'/pool/stats/'.length) == prefix+'/pool/stats/' ||
|
|
||||||
key == prefix+'/stats')
|
|
||||||
{
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = vitastor_persist_filter;
|
|
Loading…
Reference in New Issue