From 95ca65804cf79c9396f7e4fc4845fe3eec304df2 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 29 Nov 2014 11:14:59 +0100 Subject: [PATCH] initial commit --- PVE/HA/Env.pm | 60 ++++++++++++++++++++++++++++ PVE/HA/SimEnv.pm | 65 ++++++++++++++++++++++++++++++ README | 6 +++ pve-ha-manager | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 PVE/HA/Env.pm create mode 100644 PVE/HA/SimEnv.pm create mode 100644 README create mode 100755 pve-ha-manager diff --git a/PVE/HA/Env.pm b/PVE/HA/Env.pm new file mode 100644 index 0000000..6dc9a85 --- /dev/null +++ b/PVE/HA/Env.pm @@ -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; diff --git a/PVE/HA/SimEnv.pm b/PVE/HA/SimEnv.pm new file mode 100644 index 0000000..a706a30 --- /dev/null +++ b/PVE/HA/SimEnv.pm @@ -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; diff --git a/README b/README new file mode 100644 index 0000000..372182d --- /dev/null +++ b/README @@ -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 + diff --git a/pve-ha-manager b/pve-ha-manager new file mode 100755 index 0000000..fa058d8 --- /dev/null +++ b/pve-ha-manager @@ -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); +