]>
git.proxmox.com Git - pve-ha-manager.git/blob - src/PVE/HA/Env/PVE2.pm
1 package PVE
::HA
::Env
::PVE2
;
5 use POSIX
qw(:errno_h :fcntl_h);
11 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
13 use PVE
::RPCEnvironment
;
15 use PVE
::HA
::Tools
':exit_codes';
20 my $lockdir = "/etc/pve/priv/lock";
23 my ($this, $nodename) = @_;
25 die "missing nodename" if !$nodename;
27 my $class = ref($this) || $this;
29 my $self = bless {}, $class;
31 $self->{nodename
} = $nodename;
39 return $self->{nodename
};
42 sub read_manager_status
{
45 return PVE
::HA
::Config
::read_manager_status
();
48 sub write_manager_status
{
49 my ($self, $status_obj) = @_;
51 PVE
::HA
::Config
::write_manager_status
($status_obj);
55 my ($self, $node) = @_;
57 $node = $self->{nodename
} if !defined($node);
59 return PVE
::HA
::Config
::read_lrm_status
($node);
62 sub write_lrm_status
{
63 my ($self, $status_obj) = @_;
65 my $node = $self->{nodename
};
67 PVE
::HA
::Config
::write_lrm_status
($node, $status_obj);
70 sub is_node_shutdown
{
78 $shutdown = 1 if ($line =~ m/shutdown\.target/);
81 my $cmd = ['/bin/systemctl', 'list-jobs'];
82 eval { PVE
::Tools
::run_command
($cmd, outfunc
=> $code, noerr
=> 1); };
87 sub queue_crm_commands
{
88 my ($self, $cmd) = @_;
90 return PVE
::HA
::Config
::queue_crm_commands
($cmd);
93 sub read_crm_commands
{
96 return PVE
::HA
::Config
::read_crm_commands
();
99 sub service_config_exists
{
102 return PVE
::HA
::Config
::resources_config_exists
();
105 sub read_service_config
{
108 my $res = PVE
::HA
::Config
::read_resources_config
();
110 my $vmlist = PVE
::Cluster
::get_vmlist
();
113 foreach my $sid (keys %{$res->{ids
}}) {
114 my $d = $res->{ids
}->{$sid};
115 my (undef, undef, $name) = PVE
::HA
::Tools
::parse_sid
($sid);
116 $d->{state} = 'enabled' if !defined($d->{state});
117 $d->{max_restart
} = 1 if !defined($d->{max_restart
});
118 $d->{max_relocate
} = 1 if !defined($d->{max_relocate
});
119 if (PVE
::HA
::Resources-
>lookup($d->{type
})) {
120 if (my $vmd = $vmlist->{ids
}->{$name}) {
122 warn "no such VM '$name'\n";
124 $d->{node
} = $vmd->{node
};
128 if (defined($d->{node
})) {
131 warn "service '$sid' without node\n";
140 sub change_service_location
{
141 my ($self, $sid, $current_node, $new_node) = @_;
143 my (undef, $type, $name) = PVE
::HA
::Tools
::parse_sid
($sid);
145 if(my $plugin = PVE
::HA
::Resources-
>lookup($type)) {
146 my $old = $plugin->config_file($name, $current_node);
147 my $new = $plugin->config_file($name, $new_node);
148 rename($old, $new) ||
149 die "rename '$old' to '$new' failed - $!\n";
155 sub read_group_config
{
158 return PVE
::HA
::Config
::read_group_config
();
161 # this should return a hash containing info
162 # what nodes are members and online.
166 my ($node_info, $quorate) = ({}, 0);
168 my $nodename = $self->{nodename
};
170 $quorate = PVE
::Cluster
::check_cfs_quorum
(1) || 0;
172 my $members = PVE
::Cluster
::get_members
();
174 foreach my $node (keys %$members) {
175 my $d = $members->{$node};
176 $node_info->{$node}->{online
} = $d->{online
};
179 $node_info->{$nodename}->{online
} = 1; # local node is always up
181 return ($node_info, $quorate);
185 my ($self, $level, $msg) = @_;
189 syslog
($level, $msg);
192 my $last_lock_status = {};
195 my ($self, $lockid) = @_;
199 my $filename = "$lockdir/$lockid";
201 my $last = $last_lock_status->{$lockid} || 0;
206 my $retry_timeout = 100; # fixme: what timeout
212 # pve cluster filesystem not online
213 die "can't create '$lockdir' (pmxcfs not mounted?)\n" if ! -d
$lockdir;
215 if ($last && (($ctime - $last) < $retry_timeout)) {
216 # send cfs lock update request (utime)
217 if (!utime(0, $ctime, $filename)) {
219 die "cfs lock update failed - $!\n";
223 # fixme: wait some time?
224 if (!(mkdir $filename)) {
225 utime 0, 0, $filename; # cfs unlock request
226 die "can't get cfs lock\n";
236 # $self->log('err', $err) if $err; # for debugging
240 $last_lock_status->{$lockid} = $got_lock ?
$ctime : 0;
242 if (!!$got_lock != !!$last) {
244 $self->log('info', "successfully acquired lock '$lockid'");
246 my $msg = "lost lock '$lockid";
247 $msg .= " - $err" if $err;
248 $self->log('err', $msg);
251 # $self->log('err', $err) if $err; # for debugging
257 sub get_ha_manager_lock
{
260 return $self->get_pve_lock("ha_manager_lock");
263 sub get_ha_agent_lock
{
264 my ($self, $node) = @_;
266 $node = $self->nodename() if !defined($node);
268 return $self->get_pve_lock("ha_agent_${node}_lock");
276 $quorate = PVE
::Cluster
::check_cfs_quorum
();
289 my ($self, $delay) = @_;
295 my ($self, $end_time) = @_;
298 my $cur_time = time();
300 last if $cur_time >= $end_time;
306 sub loop_start_hook
{
309 PVE
::Cluster
::cfs_update
();
311 $self->{loop_start
} = $self->get_time();
317 my $delay = $self->get_time() - $self->{loop_start
};
319 warn "loop take too long ($delay seconds)\n" if $delay > 30;
327 die "watchdog already open\n" if defined($watchdog_fh);
329 $watchdog_fh = IO
::Socket
::UNIX-
>new(
330 Type
=> SOCK_STREAM
(),
331 Peer
=> "/run/watchdog-mux.sock") ||
332 die "unable to open watchdog socket - $!\n";
334 $self->log('info', "watchdog active");
337 sub watchdog_update
{
338 my ($self, $wfh) = @_;
340 my $res = $watchdog_fh->syswrite("\0", 1);
341 if (!defined($res)) {
342 $self->log('err', "watchdog update failed - $!\n");
346 $self->log('err', "watchdog update failed - write $res bytes\n");
354 my ($self, $wfh) = @_;
356 $watchdog_fh->syswrite("V", 1); # magic watchdog close
357 if (!$watchdog_fh->close()) {
358 $self->log('err', "watchdog close failed - $!");
360 $watchdog_fh = undef;
361 $self->log('info', "watchdog closed (disabled)");
366 my ($self, $upid) = @_;
368 my $task = PVE
::Tools
::upid_decode
($upid);
371 while (PVE
::ProcFSTools
::check_process_running
($task->{pid
}, $task->{pstart
})) {
372 $self->log('debug', "Task still active, waiting");
383 sub exec_resource_agent
{
384 my ($self, $sid, $service_config, $cmd, @params) = @_;
386 # setup execution environment
388 $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin';
390 PVE
::INotify
::inotify_close
();
392 PVE
::INotify
::inotify_init
();
394 PVE
::Cluster
::cfs_update
();
396 my $nodename = $self->{nodename
};
398 my (undef, $service_type, $service_name) = PVE
::HA
::Tools
::parse_sid
($sid);
400 my $plugin = PVE
::HA
::Resources-
>lookup($service_type);
402 $self->log('err', "service type '$service_type' not implemented");
403 return EUNKNOWN_SERVICE_TYPE
;
406 if ($service_config->{node
} ne $nodename) {
407 $self->log('err', "service '$sid' not on this node");
411 my $vmid = $service_name;
413 my $running = $plugin->check_running($vmid);
415 if ($cmd eq 'started') {
417 return SUCCESS
if $running;
419 $self->log("info", "starting service $sid");
421 $plugin->start($self, $vmid);
423 $running = $plugin->check_running($vmid);
426 $self->log("info", "service status $sid started");
429 $self->log("warning", "unable to start service $sid");
433 } elsif ($cmd eq 'request_stop' || $cmd eq 'stopped') {
435 return SUCCESS
if !$running;
437 $self->log("info", "stopping service $sid");
439 $plugin->shutdown($self, $vmid);
441 $running = $plugin->check_running($vmid);
444 $self->log("info", "service status $sid stopped");
447 $self->log("info", "unable to stop stop service $sid (still running)");
451 } elsif ($cmd eq 'migrate' || $cmd eq 'relocate') {
453 my $target = $params[0];
454 if (!defined($target)) {
455 die "$cmd '$sid' failed - missing target\n" if !defined($target);
456 return EINVALID_PARAMETER
;
459 if ($service_config->{node
} eq $target) {
464 my $online = ($cmd eq 'migrate') ?
1 : 0;
466 my $oldconfig = $plugin->config_file($vmid, $nodename);
468 $plugin->migrate($self, $vmid, $target, $online);
470 # something went wrong if old config file is still there
472 $self->log("err", "service $sid not moved (migration error)");
478 } elsif ($cmd eq 'error') {
481 $self->log("err", "service $sid is in an error state while running");
483 $self->log("warning", "service $sid is not running and in an error state");
485 return SUCCESS
; # error always succeeds
489 $self->log("err", "implement me (cmd '$cmd')");
490 return EUNKNOWN_COMMAND
;