]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/API2/HA/Status.pm
api: status: add CRS info to manager if not set to default
[pve-ha-manager.git] / src / PVE / API2 / HA / Status.pm
CommitLineData
50306453
DM
1package PVE::API2::HA::Status;
2
3use strict;
4use warnings;
5
475f19fe
TL
6use PVE::Cluster qw(cfs_read_file);
7use PVE::DataCenterConfig;
d0625985 8use PVE::INotify;
50306453
DM
9use PVE::JSONSchema qw(get_standard_option);
10use PVE::RPCEnvironment;
d0625985 11use PVE::SafeSyslog;
50306453 12
d0625985 13use PVE::HA::Config;
50306453 14
d0625985 15use PVE::RESTHandler;
50306453
DM
16use base qw(PVE::RESTHandler);
17
18my $nodename = PVE::INotify::nodename();
19
20my $timestamp_to_status = sub {
21 my ($ctime, $timestamp) = @_;
22
23 my $tdiff = $ctime - $timestamp;
24 if ($tdiff > 30) {
25 return "old timestamp - dead?";
26 } elsif ($tdiff < -2) {
27 return "detected time drift!";
28 } else {
29 return "active";
30 }
31};
32
5c9d7bc9 33__PACKAGE__->register_method ({
289e4784
TL
34 name => 'index',
35 path => '',
5c9d7bc9
DM
36 method => 'GET',
37 permissions => { user => 'all' },
38 description => "Directory index.",
39 parameters => {
d0625985 40 additionalProperties => 0,
5c9d7bc9
DM
41 properties => {},
42 },
43 returns => {
44 type => 'array',
45 items => {
46 type => "object",
47 properties => {},
48 },
49 links => [ { rel => 'child', href => "{name}" } ],
50 },
51 code => sub {
52 my ($param) = @_;
289e4784 53
5c9d7bc9
DM
54 my $result = [
55 { name => 'current' },
56 { name => 'manager_status' },
d0625985 57 ];
5c9d7bc9
DM
58
59 return $result;
60 }});
61
50306453 62__PACKAGE__->register_method ({
289e4784 63 name => 'status',
5c9d7bc9 64 path => 'current',
50306453
DM
65 method => 'GET',
66 description => "Get HA manger status.",
0fcba7ab
TL
67 permissions => {
68 check => ['perm', '/', [ 'Sys.Audit' ]],
69 },
50306453 70 parameters => {
d0625985 71 additionalProperties => 0,
50306453
DM
72 properties => {},
73 },
74 returns => { type => 'array' },
75 code => sub {
76 my ($param) = @_;
77
78 my $res = [];
322d3550
TL
79
80 my $quorate = PVE::Cluster::check_cfs_quorum(1);
d0625985
TL
81 push @$res, {
82 id => 'quorum', type => 'quorum',
83 node => $nodename,
84 status => $quorate ? 'OK' : "No quorum on node '$nodename'!",
85 quorate => $quorate ? 1 : 0,
86 };
322d3550 87
c12b9a1d 88 my $status = PVE::HA::Config::read_manager_status();
322d3550 89
c12b9a1d 90 my $service_config = PVE::HA::Config::read_and_check_resources_config();
50306453 91
c12b9a1d 92 my $ctime = time();
50306453
DM
93
94 if (defined($status->{master_node}) && defined($status->{timestamp})) {
95 my $master = $status->{master_node};
96 my $status_str = &$timestamp_to_status($ctime, $status->{timestamp});
322d3550
TL
97 # mark crm idle if it has no service configured and is not active
98 if ($quorate && $status_str ne 'active' && !keys %{$service_config}) {
99 $status_str = 'idle';
100 }
475f19fe
TL
101
102 my $extra_status = '';
103
104 my $datacenter_config = eval { cfs_read_file('datacenter.cfg') } // {};
105 if (my $crs = $datacenter_config->{crs}) {
106 $extra_status = " - $crs->{ha} load CRS" if $crs->{ha} && $crs->{ha} ne 'basic';
107 }
50306453 108 my $time_str = localtime($status->{timestamp});
475f19fe 109 my $status_text = "$master ($status_str, $time_str)$extra_status";
d0625985
TL
110 push @$res, {
111 id => 'master', type => 'master',
112 node => $master,
113 status => $status_text,
114 timestamp => $status->{timestamp},
115 };
322d3550 116 }
331a9f00
DM
117
118 # compute active services for all nodes
119 my $active_count = {};
120 foreach my $sid (sort keys %{$status->{service_status}}) {
121 my $sd = $status->{service_status}->{$sid};
122 next if !$sd->{node};
123 $active_count->{$sd->{node}} = 0 if !defined($active_count->{$sd->{node}});
124 my $req_state = $sd->{state};
125 next if !defined($req_state);
126 next if $req_state eq 'stopped';
127 next if $req_state eq 'freeze';
128 $active_count->{$sd->{node}}++;
129 }
289e4784 130
50306453 131 foreach my $node (sort keys %{$status->{node_status}}) {
c12b9a1d 132 my $lrm_status = PVE::HA::Config::read_lrm_status($node);
50306453
DM
133 my $id = "lrm:$node";
134 if (!$lrm_status->{timestamp}) {
289e4784
TL
135 push @$res, { id => $id, type => 'lrm', node => $node,
136 status => "$node (unable to read lrm status)"};
50306453
DM
137 } else {
138 my $status_str = &$timestamp_to_status($ctime, $lrm_status->{timestamp});
77bcb60a
TL
139 my $lrm_mode = $lrm_status->{mode};
140
331a9f00 141 if ($status_str eq 'active') {
77bcb60a 142 $lrm_mode ||= 'active';
331a9f00
DM
143 my $lrm_state = $lrm_status->{state} || 'unknown';
144 if ($lrm_mode ne 'active') {
145 $status_str = "$lrm_mode mode";
146 } else {
147 if ($lrm_state eq 'wait_for_agent_lock' && !$active_count->{$node}) {
148 $status_str = 'idle';
149 } else {
150 $status_str = $lrm_state;
151 }
152 }
77bcb60a
TL
153 } elsif ($lrm_mode && $lrm_mode eq 'maintenance') {
154 $status_str = "$lrm_mode mode";
331a9f00
DM
155 }
156
50306453
DM
157 my $time_str = localtime($lrm_status->{timestamp});
158 my $status_text = "$node ($status_str, $time_str)";
d0625985
TL
159 push @$res, {
160 id => $id, type => 'lrm',
161 node => $node,
162 status => $status_text,
163 timestamp => $lrm_status->{timestamp},
164 };
50306453
DM
165 }
166 }
167
30b36b89
DM
168 my $add_service = sub {
169 my ($sid, $sc, $ss) = @_;
170
98808a5a
DM
171 my $data = { id => "service:$sid", type => 'service', sid => $sid };
172
30b36b89 173 if ($ss) {
98808a5a 174 $data->{node} = $ss->{node};
98808a5a 175 $data->{crm_state} = $ss->{state};
c9b21b5a 176 } elsif ($sc) {
98808a5a 177 $data->{node} = $sc->{node};
98808a5a 178 }
fbda2658 179 my $node = $data->{node} // '---'; # to be save against manual tinkering
30b36b89 180
aa68337a 181 $data->{state} = PVE::HA::Tools::get_verbose_service_state($ss, $sc);
fbda2658 182 $data->{status} = "$sid ($node, $data->{state})"; # backward compat. and CLI
aa68337a 183
98808a5a
DM
184 # also return common resource attributes
185 if (defined($sc)) {
186 $data->{request_state} = $sc->{state};
187 foreach my $key (qw(group max_restart max_relocate comment)) {
188 $data->{$key} = $sc->{$key} if defined($sc->{$key});
189 }
30b36b89 190 }
98808a5a
DM
191
192 push @$res, $data;
30b36b89
DM
193 };
194
50306453 195 foreach my $sid (sort keys %{$status->{service_status}}) {
30b36b89
DM
196 my $sc = $service_config->{$sid};
197 my $ss = $status->{service_status}->{$sid};
198 $add_service->($sid, $sc, $ss);
50306453 199 }
2afff38a
TL
200
201 # show also service which aren't yet processed by the CRM
202 foreach my $sid (sort keys %$service_config) {
203 next if $status->{service_status}->{$sid};
30b36b89
DM
204 my $sc = $service_config->{$sid};
205 $add_service->($sid, $sc);
2afff38a
TL
206 }
207
50306453
DM
208 return $res;
209 }});
210
5c9d7bc9 211__PACKAGE__->register_method ({
289e4784 212 name => 'manager_status',
5c9d7bc9
DM
213 path => 'manager_status',
214 method => 'GET',
215 description => "Get full HA manger status, including LRM status.",
0fcba7ab
TL
216 permissions => {
217 check => ['perm', '/', [ 'Sys.Audit' ]],
218 },
5c9d7bc9 219 parameters => {
d0625985 220 additionalProperties => 0,
5c9d7bc9
DM
221 properties => {},
222 },
223 returns => { type => 'object' },
224 code => sub {
225 my ($param) = @_;
50306453 226
c12b9a1d 227 my $status = PVE::HA::Config::read_manager_status();
289e4784 228
5c9d7bc9
DM
229 my $data = { manager_status => $status };
230
231 $data->{quorum} = {
232 node => $nodename,
233 quorate => PVE::Cluster::check_cfs_quorum(1),
234 };
289e4784 235
5c9d7bc9 236 foreach my $node (sort keys %{$status->{node_status}}) {
c12b9a1d 237 my $lrm_status = PVE::HA::Config::read_lrm_status($node);
5c9d7bc9
DM
238 $data->{lrm_status}->{$node} = $lrm_status;
239 }
240
241 return $data;
242 }});
50306453
DM
243
2441;