]> git.proxmox.com Git - pve-ha-manager.git/blobdiff - src/PVE/HA/Manager.pm
manager: set new request_start state for services freshly added to HA
[pve-ha-manager.git] / src / PVE / HA / Manager.pm
index 56f9efbf2ff719f98a066aac321712dd76529032..494134edd3f26d4856887479ddb76a8028475dc2 100644 (file)
@@ -40,7 +40,7 @@ sub new {
 
     my $class = ref($this) || $this;
 
-    my $self = bless { haenv => $haenv }, $class;
+    my $self = bless { haenv => $haenv, crs => {} }, $class;
 
     my $old_ms = $haenv->read_manager_status();
 
@@ -53,14 +53,33 @@ sub new {
 
     $self->{ms} = { master_node => $haenv->nodename() };
 
-    my $dc_cfg = $haenv->get_datacenter_settings();
-    $self->{'scheduler-mode'} = $dc_cfg->{crs}->{ha} ? $dc_cfg->{crs}->{ha} : 'basic';
-    $haenv->log('info', "using scheduler mode '$self->{'scheduler-mode'}'")
-       if $self->{'scheduler-mode'} ne 'basic';
+    $self->update_crs_scheduler_mode(); # initial set, we update it once every loop
 
     return $self;
 }
 
+sub update_crs_scheduler_mode {
+    my ($self) = @_;
+
+    my $haenv = $self->{haenv};
+    my $dc_cfg = $haenv->get_datacenter_settings();
+
+    my $old_mode = $self->{crs}->{scheduler};
+    my $new_mode = $dc_cfg->{crs}->{ha} || 'basic';
+
+    if (!defined($old_mode)) {
+       $haenv->log('info', "using scheduler mode '$new_mode'") if $new_mode ne 'basic';
+    } elsif ($new_mode eq $old_mode) {
+       return; # nothing to do
+    } else {
+       $haenv->log('info', "switching scheduler mode from '$old_mode' to '$new_mode'");
+    }
+
+    $self->{crs}->{scheduler} = $new_mode;
+
+    return;
+}
+
 sub cleanup {
     my ($self) = @_;
 
@@ -190,6 +209,7 @@ sub compute_new_uuid {
 my $valid_service_states = {
     stopped => 1,
     request_stop => 1,
+    request_start => 1,
     started => 1,
     fence => 1,
     recovery => 1,
@@ -210,14 +230,14 @@ sub recompute_online_node_usage {
 
     my $online_node_usage;
 
-    if (my $mode = $self->{'scheduler-mode'}) {
+    if (my $mode = $self->{crs}->{scheduler}) {
        if ($mode eq 'static') {
            $online_node_usage = eval {
                my $scheduler = PVE::HA::Usage::Static->new($haenv);
                $scheduler->add_node($_) for $online_nodes->@*;
                return $scheduler;
            };
-           $haenv->log('warning', "using 'basic' scheduler mode, init for 'static' failed - $@")
+           $haenv->log('warning', "fallback to 'basic' scheduler mode, init for 'static' failed - $@")
                if $@;
        } elsif ($mode eq 'basic') {
            # handled below in the general fall-back case
@@ -232,14 +252,14 @@ sub recompute_online_node_usage {
        $online_node_usage->add_node($_) for $online_nodes->@*;
     }
 
-    foreach my $sid (keys %{$self->{ss}}) {
+    foreach my $sid (sort keys %{$self->{ss}}) {
        my $sd = $self->{ss}->{$sid};
        my $state = $sd->{state};
        my $target = $sd->{target}; # optional
        if ($online_node_usage->contains_node($sd->{node})) {
            if (
-               $state eq 'started' || $state eq 'request_stop' || $state eq 'fence' ||
-               $state eq 'freeze' || $state eq 'error' || $state eq 'recovery'
+               $state eq 'started' || $state eq 'request_stop' || $state eq 'fence'
+               || $state eq 'freeze' || $state eq 'error' || $state eq 'recovery'
            ) {
                $online_node_usage->add_service_usage_to_node($sd->{node}, $sid, $sd->{node});
            } elsif (($state eq 'migrate') || ($state eq 'relocate')) {
@@ -247,7 +267,7 @@ sub recompute_online_node_usage {
                # count it for both, source and target as load is put on both
                $online_node_usage->add_service_usage_to_node($source, $sid, $source, $target);
                $online_node_usage->add_service_usage_to_node($target, $sid, $source, $target);
-           } elsif ($state eq 'stopped') {
+           } elsif ($state eq 'stopped' || $state eq 'request_start') {
                # do nothing
            } else {
                die "should not be reached (sid = '$sid', state = '$state')";
@@ -415,6 +435,8 @@ sub manage {
        return;
     }
 
+    $self->update_crs_scheduler_mode();
+
     my $sc = $haenv->read_service_config();
 
     $self->{groups} = $haenv->read_group_config(); # update
@@ -429,9 +451,10 @@ sub manage {
 
        $haenv->log('info', "adding new service '$sid' on node '$cd->{node}'");
        # assume we are running to avoid relocate running service at add
-       my $state = ($cd->{state} eq 'started') ? 'started' : 'request_stop';
-       $ss->{$sid} = { state => $state, node => $cd->{node},
-                       uid => compute_new_uuid('started') };
+       my $state = ($cd->{state} eq 'started') ? 'request_start' : 'request_stop';
+       $ss->{$sid} = {
+           state => $state, node => $cd->{node}, uid => compute_new_uuid('started'),
+       };
     }
 
     # remove stale or ignored services from manager state
@@ -468,6 +491,10 @@ sub manage {
 
                $self->next_state_started($sid, $cd, $sd, $lrm_res);
 
+           } elsif ($last_state eq 'request_start') {
+
+               $self->next_state_request_start($sid, $cd, $sd, $lrm_res);
+
            } elsif ($last_state eq 'migrate' || $last_state eq 'relocate') {
 
                $self->next_state_migrate_relocate($sid, $cd, $sd, $lrm_res);
@@ -487,10 +514,10 @@ sub manage {
            } elsif ($last_state eq 'freeze') {
 
                my $lrm_mode = $sd->{node} ? $lrm_modes->{$sd->{node}} : undef;
-               # unfreeze
-               my $state = ($cd->{state} eq 'started') ? 'started' : 'request_stop';
-               &$change_service_state($self, $sid, $state)
-                   if $lrm_mode && $lrm_mode eq 'active';
+               if ($lrm_mode && $lrm_mode eq 'active') { # unfreeze if active again
+                   my $state = ($cd->{state} eq 'started') ? 'started' : 'request_stop';
+                   $change_service_state->($self, $sid, $state);
+               }
 
            } elsif ($last_state eq 'error') {
 
@@ -503,9 +530,9 @@ sub manage {
 
            my $lrm_mode = $sd->{node} ? $lrm_modes->{$sd->{node}} : undef;
            if ($lrm_mode && $lrm_mode eq 'restart') {
-               if (($sd->{state} eq 'started' || $sd->{state} eq 'stopped' ||
-                    $sd->{state} eq 'request_stop')) {
-                   &$change_service_state($self, $sid, 'freeze');
+               my $state = $sd->{state};
+               if ($state eq 'started' || $state eq 'stopped'|| $state eq 'request_stop') {
+                   $change_service_state->($self, $sid, 'freeze');
                }
            }
 
@@ -629,8 +656,7 @@ sub next_state_stopped {
            } elsif ($sd->{node} eq $target) {
                $haenv->log('info', "ignore service '$sid' $cmd request - service already on node '$target'");
            } else {
-               &$change_service_state($self, $sid, $cmd, node => $sd->{node},
-                                      target => $target);
+               &$change_service_state($self, $sid, $cmd, node => $sd->{node}, target => $target);
                return;
            }
        } elsif ($cmd eq 'stop') {
@@ -659,15 +685,20 @@ sub next_state_stopped {
     }
 
     if ($cd->{state} eq 'started') {
-       # simply mark it started, if it's on the wrong node
-       # next_state_started will fix that for us
-       &$change_service_state($self, $sid, 'started', node => $sd->{node});
+       # simply mark it started, if it's on the wrong node next_state_started will fix that for us
+       $change_service_state->($self, $sid, 'request_start', node => $sd->{node});
        return;
     }
 
     $haenv->log('err', "service '$sid' - unknown state '$cd->{state}' in service configuration");
 }
 
+sub next_state_request_start {
+    my ($self, $sid, $cd, $sd, $lrm_res) = @_;
+
+    $change_service_state->($self, $sid, 'started', node => $sd->{node});
+}
+
 sub record_service_failed_on_node {
     my ($self, $sid, $node) = @_;
 
@@ -752,7 +783,7 @@ sub next_state_started {
                    # store flag to indicate successful start - only valid while state == 'started'
                    $sd->{running} = 1;
 
-               } elsif ($ec == ERROR) {
+               } elsif ($ec == ERROR || $ec == EWRONG_NODE) {
 
                    delete $sd->{running};