1 package PVE
::HA
::Config
;
9 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
10 use PVE
::HA
::Resources
;
12 PVE
::HA
::Groups-
>register();
14 PVE
::HA
::Groups-
>init();
16 my $manager_status_filename = "ha/manager_status";
17 my $ha_groups_config = "ha/groups.cfg";
18 my $ha_resources_config = "ha/resources.cfg";
19 my $crm_commands_filename = "ha/crm_commands";
20 my $ha_fence_config = "ha/fence.cfg";
22 cfs_register_file
($crm_commands_filename,
23 sub { my ($fn, $raw) = @_; return defined($raw) ?
$raw : ''; },
24 sub { my ($fn, $raw) = @_; return $raw; });
25 cfs_register_file
($ha_groups_config,
26 sub { PVE
::HA
::Groups-
>parse_config(@_); },
27 sub { PVE
::HA
::Groups-
>write_config(@_); });
28 cfs_register_file
($ha_resources_config,
29 sub { PVE
::HA
::Resources-
>parse_config(@_); },
30 sub { PVE
::HA
::Resources-
>write_config(@_); });
31 cfs_register_file
($manager_status_filename,
34 cfs_register_file
($ha_fence_config,
35 \
&PVE
::HA
::FenceConfig
::parse_config
,
36 \
&PVE
::HA
::FenceConfig
::write_config
);
39 my ($filename, $data) = @_;
41 return defined($data) && length($data) > 0 ? decode_json
($data) : {};
45 my ($filename, $data) = @_;
47 return encode_json
($data);
53 die "undefined node" if !defined($node);
55 my $filename = "/etc/pve/nodes/$node/lrm_status";
57 return PVE
::HA
::Tools
::read_json_from_file
($filename, {});
60 sub write_lrm_status
{
61 my ($node, $status_obj) = @_;
63 die "undefined node" if !defined($node);
65 my $filename = "/etc/pve/nodes/$node/lrm_status";
67 PVE
::HA
::Tools
::write_json_to_file
($filename, $status_obj);
70 sub parse_groups_config
{
71 my ($filename, $raw) = @_;
73 return PVE
::HA
::Groups-
>parse_config($filename, $raw);
76 sub parse_resources_config
{
77 my ($filename, $raw) = @_;
79 return PVE
::HA
::Resources-
>parse_config($filename, $raw);
82 sub read_resources_config
{
84 return eval { cfs_read_file
($ha_resources_config) };
87 # checks if resource exists and sets defaults for unset values
88 sub read_and_check_resources_config
{
90 my $res = eval { cfs_read_file
($ha_resources_config) };
92 my $vmlist = PVE
::Cluster
::get_vmlist
();
95 foreach my $sid (keys %{$res->{ids
}}) {
96 my $d = $res->{ids
}->{$sid};
97 my (undef, undef, $name) = PVE
::HA
::Tools
::parse_sid
($sid);
98 $d->{state} = 'started' if !defined($d->{state});
99 $d->{state} = 'started' if $d->{state} eq 'enabled'; # backward compatibility
100 $d->{max_restart
} = 1 if !defined($d->{max_restart
});
101 $d->{max_relocate
} = 1 if !defined($d->{max_relocate
});
102 if (PVE
::HA
::Resources-
>lookup($d->{type
})) {
103 if (my $vmd = $vmlist->{ids
}->{$name}) {
105 warn "no such VM '$name'\n";
107 $d->{node
} = $vmd->{node
};
111 if (defined($d->{node
})) {
114 warn "service '$sid' without node\n";
123 sub read_group_config
{
125 return eval { cfs_read_file
($ha_groups_config) };
128 sub write_group_config
{
131 cfs_write_file
($ha_groups_config, $cfg);
134 sub write_resources_config
{
137 cfs_write_file
($ha_resources_config, $cfg);
140 sub read_manager_status
{
143 return eval { cfs_read_file
($manager_status_filename) };
146 sub write_manager_status
{
147 my ($status_obj) = @_;
149 cfs_write_file
($manager_status_filename, $status_obj);
152 sub read_fence_config
{
155 return eval { cfs_read_file
($ha_fence_config) };
158 sub write_fence_config
{
161 cfs_write_file
($ha_fence_config, $cfg);
165 my ($code, $errmsg) = @_;
167 my $res = PVE
::Cluster
::cfs_lock_domain
("ha", undef, $code);
170 $errmsg ?
die "$errmsg: $err" : die $err;
175 sub queue_crm_commands
{
181 my $data = cfs_read_file
($crm_commands_filename);
183 cfs_write_file
($crm_commands_filename, $data);
186 return lock_ha_domain
($code);
189 sub read_crm_commands
{
192 my $data = eval { cfs_read_file
($crm_commands_filename) };
193 return undef if !$data;
194 cfs_write_file
($crm_commands_filename, '');
198 return lock_ha_domain
($code);
201 my $service_check_ha_state = sub {
202 my ($conf, $sid, $has_state) = @_;
204 if (my $d = $conf->{ids
}->{$sid}) {
205 if (!defined($has_state)) {
206 # ignored service behave as if they were not managed by HA
207 return 0 if defined($d->{state}) && $d->{state} eq 'ignored';
211 # backward compatibility
212 $has_state = 'started' if $has_state eq 'enabled';
214 $d->{state} = 'started' if !defined($d->{state}) ||
215 ($d->{state} eq 'enabled');
217 return 1 if $d->{state} eq $has_state;
223 sub vm_is_ha_managed
{
224 my ($vmid, $has_state) = @_;
226 my $conf = cfs_read_file
($ha_resources_config);
228 my $types = PVE
::HA
::Resources-
>lookup_types();
229 foreach my $type ('vm', 'ct') {
230 return 1 if &$service_check_ha_state($conf, "$type:$vmid", $has_state);
236 sub service_is_ha_managed
{
237 my ($sid, $has_state, $noerr) = @_;
239 my $conf = cfs_read_file
($ha_resources_config);
241 return 1 if &$service_check_ha_state($conf, $sid, $has_state);
243 die "resource '$sid' is not HA managed\n" if !$noerr;
248 sub get_service_status
{
251 my $status = { managed
=> 0 };
253 my $conf = cfs_read_file
($ha_resources_config);
255 if (&$service_check_ha_state($conf, $sid)) {
256 my $manager_status = cfs_read_file
($manager_status_filename);
258 $status->{managed
} = 1;
259 $status->{group
} = $conf->{ids
}->{$sid}->{group
};
260 $status->{state} = $manager_status->{service_status
}->{$sid}->{state};