]>
Commit | Line | Data |
---|---|---|
50306453 DM |
1 | package PVE::API2::HA::Status; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
475f19fe TL |
6 | use PVE::Cluster qw(cfs_read_file); |
7 | use PVE::DataCenterConfig; | |
d0625985 | 8 | use PVE::INotify; |
50306453 DM |
9 | use PVE::JSONSchema qw(get_standard_option); |
10 | use PVE::RPCEnvironment; | |
d0625985 | 11 | use PVE::SafeSyslog; |
50306453 | 12 | |
d0625985 | 13 | use PVE::HA::Config; |
50306453 | 14 | |
d0625985 | 15 | use PVE::RESTHandler; |
50306453 DM |
16 | use base qw(PVE::RESTHandler); |
17 | ||
18 | my $nodename = PVE::INotify::nodename(); | |
19 | ||
20 | my $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 | |
244 | 1; |