]> git.proxmox.com Git - pve-ha-manager.git/blobdiff - src/PVE/API2/HA/Status.pm
api/status: extra handling of maintenance mode
[pve-ha-manager.git] / src / PVE / API2 / HA / Status.pm
index a7bdea8b56c83e9c84def9b21d06fcd05164655a..6fd525bc299c89ab4693d20fdf71c05a69f5ab0a 100644 (file)
@@ -9,7 +9,6 @@ use PVE::Cluster;
 use PVE::HA::Config;
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::RPCEnvironment;
-use PVE::HA::Env::PVE2;
 
 use PVE::RESTHandler;
 
@@ -31,8 +30,8 @@ my $timestamp_to_status = sub {
 };
 
 __PACKAGE__->register_method ({
-    name => 'index', 
-    path => '', 
+    name => 'index',
+    path => '',
     method => 'GET',
     permissions => { user => 'all' },
     description => "Directory index.",
@@ -50,7 +49,7 @@ __PACKAGE__->register_method ({
     },
     code => sub {
        my ($param) = @_;
-    
+
        my $result = [
            { name => 'current' },
            { name => 'manager_status' },
@@ -60,7 +59,7 @@ __PACKAGE__->register_method ({
     }});
 
 __PACKAGE__->register_method ({
-    name => 'status', 
+    name => 'status',
     path => 'current',
     method => 'GET',
     description => "Get HA manger status.",
@@ -76,56 +75,126 @@ __PACKAGE__->register_method ({
        my ($param) = @_;
 
        my $res = [];
-       
-       if (PVE::Cluster::check_cfs_quorum(1)) {
-           push @$res, { id => 'quorum', type => 'quorum', 
+
+       my $quorate = PVE::Cluster::check_cfs_quorum(1);
+       if ($quorate) {
+           push @$res, { id => 'quorum', type => 'quorum',
                          node => $nodename, status => "OK", quorate => 1 };
        } else {
-           push @$res, { id => 'quorum', type => 'quorum', node => $nodename, 
+           push @$res, { id => 'quorum', type => 'quorum', node => $nodename,
                          status => "No quorum on node '$nodename'!", quorate => 0 };
        }
-       
-       my $haenv = PVE::HA::Env::PVE2->new($nodename);
-       
-       my $status = $haenv->read_manager_status();
 
-       my $ctime = $haenv->get_time();
+       my $status = PVE::HA::Config::read_manager_status();
+
+       my $service_config = PVE::HA::Config::read_and_check_resources_config();
+
+       my $ctime = time();
 
        if (defined($status->{master_node}) && defined($status->{timestamp})) {
            my $master = $status->{master_node};
            my $status_str = &$timestamp_to_status($ctime, $status->{timestamp});
+           # mark crm idle if it has no service configured and is not active
+           if ($quorate && $status_str ne 'active' && !keys %{$service_config}) {
+               $status_str = 'idle';
+           }
            my $time_str = localtime($status->{timestamp});
            my $status_text = "$master ($status_str, $time_str)";
-           push @$res, { id => 'master', type => 'master', node => $master, 
+           push @$res, { id => 'master', type => 'master', node => $master,
                          status => $status_text, timestamp => $status->{timestamp} };
-       } 
-       
+       }
+
+       # compute active services for all nodes
+       my $active_count = {};
+       foreach my $sid (sort keys %{$status->{service_status}}) {
+           my $sd = $status->{service_status}->{$sid};
+           next if !$sd->{node};
+           $active_count->{$sd->{node}} = 0 if !defined($active_count->{$sd->{node}});
+           my $req_state = $sd->{state};
+           next if !defined($req_state);
+           next if $req_state eq 'stopped';
+           next if $req_state eq 'freeze';
+           $active_count->{$sd->{node}}++;
+       }
+
        foreach my $node (sort keys %{$status->{node_status}}) {
-           my $lrm_status = $haenv->read_lrm_status($node);
+           my $lrm_status = PVE::HA::Config::read_lrm_status($node);
            my $id = "lrm:$node";
            if (!$lrm_status->{timestamp}) {
-               push @$res, { id => $id, type => 'lrm',  node => $node, 
-                             status => "$node (unable to read lrm status)"}; 
+               push @$res, { id => $id, type => 'lrm',  node => $node,
+                             status => "$node (unable to read lrm status)"};
            } else {
                my $status_str = &$timestamp_to_status($ctime, $lrm_status->{timestamp});
+               my $lrm_mode = $lrm_status->{mode};
+
+               if ($status_str eq 'active') {
+                   $lrm_mode ||= 'active';
+                   my $lrm_state = $lrm_status->{state} || 'unknown';
+                   if ($lrm_mode ne 'active') {
+                       $status_str = "$lrm_mode mode";
+                   } else {
+                       if ($lrm_state eq 'wait_for_agent_lock' && !$active_count->{$node}) {
+                           $status_str = 'idle';
+                       } else {
+                           $status_str = $lrm_state;
+                       }
+                   }
+               } elsif ($lrm_mode && $lrm_mode eq 'maintenance') {
+                   $status_str = "$lrm_mode mode";
+               }
+
                my $time_str = localtime($lrm_status->{timestamp});
                my $status_text = "$node ($status_str, $time_str)";
-               push @$res, { id => $id, type => 'lrm',  node => $node, 
-                             status => $status_text, timestamp => $lrm_status->{timestamp} }; 
+               push @$res, { id => $id, type => 'lrm',  node => $node,
+                             status => $status_text, timestamp => $lrm_status->{timestamp} };
            }
        }
 
+       my $add_service = sub {
+           my ($sid, $sc, $ss) = @_;
+
+           my $data = { id => "service:$sid", type => 'service', sid => $sid };
+
+           if ($ss) {
+               $data->{node} = $ss->{node};
+               $data->{crm_state} = $ss->{state};
+           } elsif ($sc) {
+               $data->{node} = $sc->{node};
+           }
+           my $node = $data->{node} // '---'; # to be save against manual tinkering
+
+           $data->{state} = PVE::HA::Tools::get_verbose_service_state($ss, $sc);
+           $data->{status} = "$sid ($node, $data->{state})"; # backward compat. and CLI
+
+           # also return common resource attributes
+           if (defined($sc)) {
+               $data->{request_state} = $sc->{state};
+               foreach my $key (qw(group max_restart max_relocate comment)) {
+                   $data->{$key} = $sc->{$key} if defined($sc->{$key});
+               }
+           }
+
+           push @$res, $data;
+       };
+
        foreach my $sid (sort keys %{$status->{service_status}}) {
-           my $d = $status->{service_status}->{$sid};
-           push @$res, { id => "service:$sid", type => 'service', sid => $sid, 
-                         node => $d->{node}, status => "$sid ($d->{node}, $d->{state})" };
+           my $sc = $service_config->{$sid};
+           my $ss = $status->{service_status}->{$sid};
+           $add_service->($sid, $sc, $ss);
+       }
+
+       # show also service which aren't yet processed by the CRM
+       foreach my $sid (sort keys %$service_config) {
+           next if $status->{service_status}->{$sid};
+           my $sc = $service_config->{$sid};
+           $add_service->($sid, $sc);
        }
-               
+
        return $res;
     }});
 
 __PACKAGE__->register_method ({
-    name => 'manager_status', 
+    name => 'manager_status',
     path => 'manager_status',
     method => 'GET',
     description => "Get full HA manger status, including LRM status.",
@@ -140,19 +209,17 @@ __PACKAGE__->register_method ({
     code => sub {
        my ($param) = @_;
 
-       my $haenv = PVE::HA::Env::PVE2->new($nodename);
+       my $status = PVE::HA::Config::read_manager_status();
 
-       my $status = $haenv->read_manager_status();
-       
        my $data = { manager_status => $status };
 
        $data->{quorum} = {
            node => $nodename,
            quorate => PVE::Cluster::check_cfs_quorum(1),
        };
-       
+
        foreach my $node (sort keys %{$status->{node_status}}) {
-           my $lrm_status = $haenv->read_lrm_status($node);
+           my $lrm_status = PVE::HA::Config::read_lrm_status($node);
            $data->{lrm_status}->{$node} = $lrm_status;
        }