mirror of
git://git.proxmox.com/git/pve-ha-manager.git
synced 2024-12-22 17:34:22 +03:00
initial commit
This commit is contained in:
commit
95ca65804c
60
PVE/HA/Env.pm
Normal file
60
PVE/HA/Env.pm
Normal file
@ -0,0 +1,60 @@
|
||||
package PVE::HA::Env;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PVE::SafeSyslog;
|
||||
|
||||
# abstract out the cluster environment
|
||||
|
||||
sub new {
|
||||
my ($this) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
|
||||
my $self = bless {}, $class;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub log {
|
||||
my ($self, $level, $msg) = @_;
|
||||
|
||||
syslog($level, $msg);
|
||||
}
|
||||
|
||||
# aquire a cluster wide lock
|
||||
sub get_ha_manager_lock {
|
||||
my ($self) = @_;
|
||||
|
||||
die "implement me";
|
||||
}
|
||||
|
||||
# return current time
|
||||
# overwrite that if you want to simulate
|
||||
sub get_time {
|
||||
my ($self) = @_;
|
||||
|
||||
return time();
|
||||
}
|
||||
|
||||
sub sleep {
|
||||
my ($self, $delay) = @_;
|
||||
|
||||
sleep($delay);
|
||||
}
|
||||
|
||||
sub loop_start_hook {
|
||||
my ($self) = @_;
|
||||
|
||||
# do nothing
|
||||
}
|
||||
|
||||
sub loop_end_hook {
|
||||
my ($self) = @_;
|
||||
|
||||
# do nothing
|
||||
}
|
||||
|
||||
|
||||
1;
|
65
PVE/HA/SimEnv.pm
Normal file
65
PVE/HA/SimEnv.pm
Normal file
@ -0,0 +1,65 @@
|
||||
package PVE::HA::SimEnv;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
use PVE::HA::Env;
|
||||
|
||||
use base qw(PVE::HA::Env);
|
||||
|
||||
my $max_sim_time = 1000;
|
||||
|
||||
sub log {
|
||||
my ($self, $level, $msg) = @_;
|
||||
|
||||
my $time = $self->get_time();
|
||||
|
||||
my $timestr = strftime("%H:%M:%S", gmtime($time));
|
||||
|
||||
print "$level $timestr: $msg\n";
|
||||
}
|
||||
|
||||
my $cur_time = 0;
|
||||
|
||||
sub get_time {
|
||||
my ($self) = @_;
|
||||
|
||||
return $cur_time;
|
||||
}
|
||||
|
||||
sub sleep {
|
||||
my ($self, $delay) = @_;
|
||||
|
||||
$cur_time += $delay;
|
||||
}
|
||||
|
||||
sub get_ha_manager_lock {
|
||||
my ($self) = @_;
|
||||
|
||||
++$cur_time;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub loop_start_hook {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->{loop_start_time} = $cur_time;
|
||||
|
||||
# do nothing
|
||||
}
|
||||
|
||||
sub loop_end_hook {
|
||||
my ($self) = @_;
|
||||
|
||||
my $delay = $cur_time - $self->{loop_start_time};
|
||||
|
||||
die "loop take too long ($delay seconds)\n" if $delay > 20;
|
||||
|
||||
$cur_time++;
|
||||
|
||||
die "simulation end\n" if $cur_time > $max_sim_time;
|
||||
}
|
||||
|
||||
1;
|
6
README
Normal file
6
README
Normal file
@ -0,0 +1,6 @@
|
||||
= Experimental implementation of a simple HA Manager =
|
||||
|
||||
- should run with any distributed key/value store (consul, ...)
|
||||
|
||||
- only works with simply resources like VMs
|
||||
|
100
pve-ha-manager
Executable file
100
pve-ha-manager
Executable file
@ -0,0 +1,100 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use lib '.';
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PVE::Tools;
|
||||
use PVE::HA::SimEnv;
|
||||
|
||||
my $statusdir = "/var/tmp/pve-ha-manager";
|
||||
|
||||
mkdir $statusdir;
|
||||
|
||||
my $haenv = PVE::HA::SimEnv->new();
|
||||
|
||||
my $status;
|
||||
|
||||
sub get_manager_status {
|
||||
|
||||
my $status = PVE::Tools::file_read_firstline("$statusdir/status");
|
||||
|
||||
$status = 'startup' if !$status;
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
sub set_manager_status {
|
||||
my ($new_status) = @_;
|
||||
|
||||
return if $status eq $new_status;
|
||||
|
||||
$haenv->log('info', "manager status change $status => $new_status");
|
||||
|
||||
$status = $new_status;
|
||||
|
||||
PVE::Tools::file_set_contents("$statusdir/status", $status);
|
||||
}
|
||||
|
||||
sub get_manager_lock {
|
||||
|
||||
my $count = 0;
|
||||
for (;;) {
|
||||
return 1 if $haenv->get_ha_manager_lock();
|
||||
last if ++$count > 5;
|
||||
$haenv->sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
$status = get_manager_status();
|
||||
|
||||
# can happen after crash?
|
||||
if ($status eq 'quorate') {
|
||||
set_manager_status('recover');
|
||||
} else {
|
||||
set_manager_status('startup');
|
||||
|
||||
}
|
||||
|
||||
|
||||
$haenv->log('info', "starting simulation environment (status = $status)");
|
||||
|
||||
eval {
|
||||
|
||||
for (;;) {
|
||||
|
||||
$haenv->loop_start_hook();
|
||||
|
||||
if ($status eq 'recover') {
|
||||
$haenv->log('info', "waiting for 5 seconds");
|
||||
$haenv->sleep(5);
|
||||
set_manager_status('startup');
|
||||
} elsif ($status eq 'startup') {
|
||||
if (get_manager_lock()) {
|
||||
set_manager_status('quorate');
|
||||
}
|
||||
} elsif ($status eq 'quorate') {
|
||||
|
||||
} elsif ($status eq 'lost_quorum') {
|
||||
|
||||
} elsif ($status eq 'halt') {
|
||||
die "halt\n";
|
||||
} else {
|
||||
die "got unexpected status '$status'\n";
|
||||
}
|
||||
|
||||
$haenv->loop_end_hook();
|
||||
}
|
||||
};
|
||||
if (my $err = $@) {
|
||||
$haenv->log('err', "exit now (status = $status) - $err ");
|
||||
} else {
|
||||
$haenv->log('info', "exit simulation environment (status = $status)");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
Loading…
Reference in New Issue
Block a user