|
Packit Service |
dfccb1 |
/*
|
|
Packit Service |
dfccb1 |
* Soft: Keepalived is a failover program for the LVS project
|
|
Packit Service |
dfccb1 |
* <www.linuxvirtualserver.org>. It monitor & manipulate
|
|
Packit Service |
dfccb1 |
* a loadbalanced server pool using multi-layer checks.
|
|
Packit Service |
dfccb1 |
*
|
|
Packit Service |
dfccb1 |
* Part: FILE CHECK. Monitor contents if a file
|
|
Packit Service |
dfccb1 |
*
|
|
Packit Service |
dfccb1 |
* Authors: Quentin Armitage, <quentin@armitage.org.uk>
|
|
Packit Service |
dfccb1 |
*
|
|
Packit Service |
dfccb1 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
dfccb1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
dfccb1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit Service |
dfccb1 |
* See the GNU General Public License for more details.
|
|
Packit Service |
dfccb1 |
*
|
|
Packit Service |
dfccb1 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
dfccb1 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
dfccb1 |
* as published by the Free Software Foundation; either version
|
|
Packit Service |
dfccb1 |
* 2 of the License, or (at your option) any later version.
|
|
Packit Service |
dfccb1 |
*
|
|
Packit Service |
dfccb1 |
* Copyright (C) 2020-2020 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit Service |
dfccb1 |
*/
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#include "config.h"
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#include <stdio.h>
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#include "check_file.h"
|
|
Packit Service |
dfccb1 |
#include "check_data.h"
|
|
Packit Service |
dfccb1 |
#include "track_file.h"
|
|
Packit Service |
dfccb1 |
#include "parser.h"
|
|
Packit Service |
dfccb1 |
#include "logger.h"
|
|
Packit Service |
dfccb1 |
#include "check_data.h"
|
|
Packit Service |
dfccb1 |
#include "logger.h"
|
|
Packit Service |
dfccb1 |
#include "main.h"
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
free_file_check(checker_t *checker)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
FREE(checker);
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
dump_file_check(FILE *fp, const checker_t *checker)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
tracked_file_t *tfp = checker->data;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
conf_write(fp, " Keepalive method = FILE_CHECK");
|
|
Packit Service |
dfccb1 |
conf_write(fp, " Tracked file = %s", tfp->fname);
|
|
Packit Service |
dfccb1 |
conf_write(fp, " Reloaded = %s", tfp->reloaded ? "Yes" : "No");
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static bool
|
|
Packit Service |
dfccb1 |
file_check_compare(const checker_t *old_c, checker_t *new_c)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
const tracked_file_t *old = old_c->data;
|
|
Packit Service |
dfccb1 |
tracked_file_t *new = new_c->data;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (strcmp(old->file_path, new->file_path))
|
|
Packit Service |
dfccb1 |
return false;
|
|
Packit Service |
dfccb1 |
if (old->weight != new->weight)
|
|
Packit Service |
dfccb1 |
return false;
|
|
Packit Service |
dfccb1 |
if (old->weight_reverse != new->weight_reverse)
|
|
Packit Service |
dfccb1 |
return false;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
new->reloaded = true;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
return true;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
track_file_handler(const vector_t *strvec)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
|
|
Packit Service |
dfccb1 |
real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
|
|
Packit Service |
dfccb1 |
tracked_file_monitor_t *tfile;
|
|
Packit Service |
dfccb1 |
tracked_file_t *vsf;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
vsf = find_tracked_file_by_name(strvec_slot(strvec, 1), &check_data->track_files);
|
|
Packit Service |
dfccb1 |
if (!vsf) {
|
|
Packit Service |
dfccb1 |
report_config_error(CONFIG_GENERAL_ERROR, "track_file %s not found", strvec_slot(strvec, 1));
|
|
Packit Service |
dfccb1 |
return;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
tfile->file = vsf;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
file_check_handler(__attribute__((unused)) const vector_t *strvec)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
|
|
Packit Service |
dfccb1 |
real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
|
|
Packit Service |
dfccb1 |
tracked_file_monitor_t *tfile;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
PMALLOC(tfile);
|
|
Packit Service |
dfccb1 |
INIT_LIST_HEAD(&tfile->e_list);
|
|
Packit Service |
dfccb1 |
list_add_tail(&tfile->e_list, &rs->track_files);
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
track_file_weight_handler(const vector_t *strvec)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
|
|
Packit Service |
dfccb1 |
real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
|
|
Packit Service |
dfccb1 |
tracked_file_monitor_t *tfile;
|
|
Packit Service |
dfccb1 |
int weight;
|
|
Packit Service |
dfccb1 |
bool reverse = false;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (vector_size(strvec) < 2) {
|
|
Packit Service |
dfccb1 |
report_config_error(CONFIG_GENERAL_ERROR, "track file weight missing");
|
|
Packit Service |
dfccb1 |
return;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (!read_int_strvec(strvec, 1, &weight, -IPVS_WEIGHT_MAX, IPVS_WEIGHT_MAX, true)) {
|
|
Packit Service |
dfccb1 |
report_config_error(CONFIG_GENERAL_ERROR, "weight for track file must be in "
|
|
Packit Service |
dfccb1 |
"[-IPVS_WEIGHT_MAX..IPVS_WEIGHT_MAX] inclusive. Ignoring...");
|
|
Packit Service |
dfccb1 |
return;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (vector_size(strvec) >= 3) {
|
|
Packit Service |
dfccb1 |
if (!strcmp(strvec_slot(strvec, 2), "reverse"))
|
|
Packit Service |
dfccb1 |
reverse = true;
|
|
Packit Service |
dfccb1 |
else if (!strcmp(strvec_slot(strvec, 2), "noreverse"))
|
|
Packit Service |
dfccb1 |
reverse = false;
|
|
Packit Service |
dfccb1 |
else {
|
|
Packit Service |
dfccb1 |
report_config_error(CONFIG_GENERAL_ERROR, "unknown track file weight option %s - ignoring",
|
|
Packit Service |
dfccb1 |
strvec_slot(strvec, 2));
|
|
Packit Service |
dfccb1 |
return;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
tfile->weight = weight;
|
|
Packit Service |
dfccb1 |
tfile->weight_reverse = reverse;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
static void
|
|
Packit Service |
dfccb1 |
file_end_handler(void)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
virtual_server_t *vs = list_last_entry(&check_data->vs, virtual_server_t, e_list);
|
|
Packit Service |
dfccb1 |
real_server_t *rs = list_last_entry(&vs->rs, real_server_t, e_list);
|
|
Packit Service |
dfccb1 |
tracked_file_monitor_t *tfile;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
tfile = list_last_entry(&rs->track_files, tracked_file_monitor_t, e_list);
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (!tfile->file) {
|
|
Packit Service |
dfccb1 |
report_config_error(CONFIG_GENERAL_ERROR, "FILE_CHECK has no track_file specified - ignoring");
|
|
Packit Service |
dfccb1 |
free_track_file_monitor(tfile);
|
|
Packit Service |
dfccb1 |
return;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (!tfile->weight) {
|
|
Packit Service |
dfccb1 |
tfile->weight = tfile->file->weight;
|
|
Packit Service |
dfccb1 |
tfile->weight_reverse = tfile->file->weight_reverse;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
void
|
|
Packit Service |
dfccb1 |
install_file_check_keyword(void)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
install_keyword("FILE_CHECK", &file_check_handler);
|
|
Packit Service |
dfccb1 |
install_sublevel();
|
|
Packit Service |
dfccb1 |
install_keyword("track_file", &track_file_handler);
|
|
Packit Service |
dfccb1 |
install_keyword("weight", &track_file_weight_handler);
|
|
Packit Service |
dfccb1 |
install_sublevel_end_handler(&file_end_handler);
|
|
Packit Service |
dfccb1 |
install_sublevel_end();
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
void
|
|
Packit Service |
dfccb1 |
add_rs_to_track_files(void)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
virtual_server_t *vs;
|
|
Packit Service |
dfccb1 |
real_server_t *rs;
|
|
Packit Service |
dfccb1 |
tracked_file_monitor_t *tfl;
|
|
Packit Service |
dfccb1 |
checker_t *new_checker;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
list_for_each_entry(vs, &check_data->vs, e_list) {
|
|
Packit Service |
dfccb1 |
list_for_each_entry(rs, &vs->rs, e_list) {
|
|
Packit Service |
dfccb1 |
list_for_each_entry(tfl, &rs->track_files, e_list) {
|
|
Packit Service |
dfccb1 |
/* queue new checker */
|
|
Packit Service |
dfccb1 |
new_checker = queue_checker(free_file_check, dump_file_check, NULL, file_check_compare, tfl->file, NULL, false);
|
|
Packit Service |
dfccb1 |
new_checker->vs = vs;
|
|
Packit Service |
dfccb1 |
new_checker->rs = rs;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
/* There is no concept of the checker running, but we will have
|
|
Packit Service |
dfccb1 |
* checked the file, so mark it as run. */
|
|
Packit Service |
dfccb1 |
new_checker->has_run = true;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
add_obj_to_track_file(new_checker, tfl, FMT_RS(rs, vs), dump_tracking_rs);
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
void
|
|
Packit Service |
dfccb1 |
set_track_file_checkers_down(void)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
tracked_file_t *tfl;
|
|
Packit Service |
dfccb1 |
tracking_obj_t *top;
|
|
Packit Service |
dfccb1 |
int status;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
list_for_each_entry(tfl, &check_data->track_files, e_list) {
|
|
Packit Service |
dfccb1 |
if (tfl->last_status) {
|
|
Packit Service |
dfccb1 |
list_for_each_entry(top, &tfl->tracking_obj, e_list) {
|
|
Packit Service |
dfccb1 |
checker_t *checker = top->obj.checker;
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
if (!top->weight) {
|
|
Packit Service |
dfccb1 |
if (reload && !tfl->reloaded) {
|
|
Packit Service |
dfccb1 |
/* This is pretty horrible. At some stage this should
|
|
Packit Service |
dfccb1 |
* be tidied up so that it works without having to
|
|
Packit Service |
dfccb1 |
* fudge the values to make update_track_file_status()
|
|
Packit Service |
dfccb1 |
* work for us. */
|
|
Packit Service |
dfccb1 |
status = tfl->last_status;
|
|
Packit Service |
dfccb1 |
tfl->last_status = 0;
|
|
Packit Service |
dfccb1 |
process_update_checker_track_file_status(tfl, !!status == (top->weight_multiplier == 1) ? INT_MIN : 0, top);
|
|
Packit Service |
dfccb1 |
tfl->last_status = status;
|
|
Packit Service |
dfccb1 |
} else
|
|
Packit Service |
dfccb1 |
checker->is_up = false;
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
|
|
Packit Service |
dfccb1 |
#ifdef THREAD_DUMP
|
|
Packit Service |
dfccb1 |
void
|
|
Packit Service |
dfccb1 |
register_check_file_addresses(void)
|
|
Packit Service |
dfccb1 |
{
|
|
Packit Service |
dfccb1 |
register_track_file_inotify_addresses();
|
|
Packit Service |
dfccb1 |
}
|
|
Packit Service |
dfccb1 |
#endif
|