1 package PVE
::API2
::HA
::Status
;
6 use PVE
::Cluster
qw(cfs_read_file);
7 use PVE
::DataCenterConfig
;
9 use PVE
::JSONSchema
qw(get_standard_option);
10 use PVE
::RPCEnvironment
;
16 use base
qw(PVE::RESTHandler);
18 my $nodename = PVE
::INotify
::nodename
();
20 my $timestamp_to_status = sub {
21 my ($ctime, $timestamp) = @_;
23 my $tdiff = $ctime - $timestamp;
25 return "old timestamp - dead?";
26 } elsif ($tdiff < -2) {
27 return "detected time drift!";
33 __PACKAGE__-
>register_method ({
37 permissions
=> { user
=> 'all' },
38 description
=> "Directory index.",
40 additionalProperties
=> 0,
49 links
=> [ { rel
=> 'child', href
=> "{name}" } ],
55 { name
=> 'current' },
56 { name
=> 'manager_status' },
62 __PACKAGE__-
>register_method ({
66 description
=> "Get HA manger status.",
68 check
=> ['perm', '/', [ 'Sys.Audit' ]],
71 additionalProperties
=> 0,
74 returns
=> { type
=> 'array' },
80 my $quorate = PVE
::Cluster
::check_cfs_quorum
(1);
82 id
=> 'quorum', type
=> 'quorum',
84 status
=> $quorate ?
'OK' : "No quorum on node '$nodename'!",
85 quorate
=> $quorate ?
1 : 0,
88 my $status = PVE
::HA
::Config
::read_manager_status
();
90 my $service_config = PVE
::HA
::Config
::read_and_check_resources_config
();
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
});
97 # mark crm idle if it has no service configured and is not active
98 if ($quorate && $status_str ne 'active' && !keys %{$service_config}) {
102 my $extra_status = '';
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';
108 my $time_str = localtime($status->{timestamp
});
109 my $status_text = "$master ($status_str, $time_str)$extra_status";
111 id
=> 'master', type
=> 'master',
113 status
=> $status_text,
114 timestamp
=> $status->{timestamp
},
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
}}++;
131 foreach my $node (sort keys %{$status->{node_status
}}) {
132 my $lrm_status = PVE
::HA
::Config
::read_lrm_status
($node);
133 my $id = "lrm:$node";
134 if (!$lrm_status->{timestamp
}) {
135 push @$res, { id
=> $id, type
=> 'lrm', node
=> $node,
136 status
=> "$node (unable to read lrm status)"};
138 my $status_str = &$timestamp_to_status($ctime, $lrm_status->{timestamp
});
139 my $lrm_mode = $lrm_status->{mode
};
141 if ($status_str eq 'active') {
142 $lrm_mode ||= 'active';
143 my $lrm_state = $lrm_status->{state} || 'unknown';
144 if ($lrm_mode ne 'active') {
145 $status_str = "$lrm_mode mode";
147 if ($lrm_state eq 'wait_for_agent_lock' && !$active_count->{$node}) {
148 $status_str = 'idle';
150 $status_str = $lrm_state;
153 } elsif ($lrm_mode && $lrm_mode eq 'maintenance') {
154 $status_str = "$lrm_mode mode";
157 my $time_str = localtime($lrm_status->{timestamp
});
158 my $status_text = "$node ($status_str, $time_str)";
160 id
=> $id, type
=> 'lrm',
162 status
=> $status_text,
163 timestamp
=> $lrm_status->{timestamp
},
168 my $add_service = sub {
169 my ($sid, $sc, $ss) = @_;
171 my $data = { id
=> "service:$sid", type
=> 'service', sid
=> $sid };
174 $data->{node
} = $ss->{node
};
175 $data->{crm_state
} = $ss->{state};
177 $data->{node
} = $sc->{node
};
179 my $node = $data->{node
} // '---'; # to be save against manual tinkering
181 $data->{state} = PVE
::HA
::Tools
::get_verbose_service_state
($ss, $sc);
182 $data->{status
} = "$sid ($node, $data->{state})"; # backward compat. and CLI
184 # also return common resource attributes
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});
195 foreach my $sid (sort keys %{$status->{service_status
}}) {
196 my $sc = $service_config->{$sid};
197 my $ss = $status->{service_status
}->{$sid};
198 $add_service->($sid, $sc, $ss);
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};
204 my $sc = $service_config->{$sid};
205 $add_service->($sid, $sc);
211 __PACKAGE__-
>register_method ({
212 name
=> 'manager_status',
213 path
=> 'manager_status',
215 description
=> "Get full HA manger status, including LRM status.",
217 check
=> ['perm', '/', [ 'Sys.Audit' ]],
220 additionalProperties
=> 0,
223 returns
=> { type
=> 'object' },
227 my $status = PVE
::HA
::Config
::read_manager_status
();
229 my $data = { manager_status
=> $status };
233 quorate
=> PVE
::Cluster
::check_cfs_quorum
(1),
236 foreach my $node (sort keys %{$status->{node_status
}}) {
237 my $lrm_status = PVE
::HA
::Config
::read_lrm_status
($node);
238 $data->{lrm_status
}->{$node} = $lrm_status;