]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Env/PVE2.pm
add systemd service for pve-ha-crm
[pve-ha-manager.git] / src / PVE / HA / Env / PVE2.pm
CommitLineData
714a4016
DM
1package PVE::HA::Env::PVE2;
2
3use strict;
4use warnings;
76737af5
DM
5use POSIX qw(:errno_h :fcntl_h);
6use IO::File;
714a4016
DM
7
8use PVE::SafeSyslog;
9use PVE::Tools;
abc920b4 10use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_lock_file);
714a4016
DM
11
12use PVE::HA::Tools;
13use PVE::HA::Env;
abc920b4 14use PVE::HA::Groups;
714a4016 15
007fcc8b
DM
16my $lockdir = "/etc/pve/priv/lock";
17
714a4016 18my $manager_status_filename = "/etc/pve/manager_status";
abc920b4
DM
19my $ha_groups_config = "ha/groups.cfg";
20
6cbcb5f7
DM
21#cfs_register_file($ha_groups_config,
22# sub { PVE::HA::Groups->parse_config(@_); },
23# sub { PVE::HA::Groups->write_config(@_); });
714a4016
DM
24
25sub new {
26 my ($this, $nodename) = @_;
27
28 die "missing nodename" if !$nodename;
29
30 my $class = ref($this) || $this;
31
32 my $self = bless {}, $class;
33
34 $self->{nodename} = $nodename;
35
36 return $self;
37}
38
39sub nodename {
40 my ($self) = @_;
41
42 return $self->{nodename};
43}
44
45sub read_manager_status {
46 my ($self) = @_;
47
48 my $filename = $manager_status_filename;
49
50 return PVE::HA::Tools::read_json_from_file($filename, {});
51}
52
53sub write_manager_status {
54 my ($self, $status_obj) = @_;
55
56 my $filename = $manager_status_filename;
57
58 PVE::HA::Tools::write_json_to_file($filename, $status_obj);
59}
60
c4a221bc
DM
61sub read_lrm_status {
62 my ($self, $node) = @_;
63
64 $node = $self->{nodename} if !defined($node);
65
66 my $filename = "/etc/pve/nodes/$node/lrm_status";
67
68 return PVE::HA::Tools::read_json_from_file($filename, {});
69}
70
71sub write_lrm_status {
72 my ($self, $status_obj) = @_;
73
6cbcb5f7 74 my $node = $self->{nodename};
c4a221bc
DM
75
76 my $filename = "/etc/pve/nodes/$node/lrm_status";
77
78 PVE::HA::Tools::write_json_to_file($filename, $status_obj);
79}
80
714a4016
DM
81sub manager_status_exists {
82 my ($self) = @_;
83
84 return -f $manager_status_filename ? 1 : 0;
85}
86
87sub read_service_config {
88 my ($self) = @_;
89
90 die "implement me";
91}
92
8456bde2
DM
93sub change_service_location {
94 my ($self, $sid, $node) = @_;
95
96 die "implement me";
97}
98
abc920b4
DM
99sub read_group_config {
100 my ($self) = @_;
101
102 return cfs_read_file($ha_groups_config);
103}
104
3b996922
DM
105sub queue_crm_commands {
106 my ($self, $cmd) = @_;
107
108 die "implement me";
109}
110
111sub read_crm_commands {
112 my ($self) = @_;
113
114 die "implement me";
115}
116
714a4016
DM
117# this should return a hash containing info
118# what nodes are members and online.
119sub get_node_info {
120 my ($self) = @_;
121
122 die "implement me";
123}
124
125sub log {
126 my ($self, $level, $msg) = @_;
127
128 chomp $msg;
129
130 syslog($level, $msg);
131}
132
007fcc8b
DM
133my $last_lock_status = {};
134
135sub get_pve_lock {
136 my ($self, $lockid) = @_;
714a4016 137
007fcc8b 138 my $got_lock = 0;
4d24e7db 139
4d24e7db
DM
140 my $filename = "$lockdir/$lockid";
141
007fcc8b
DM
142 my $last = $last_lock_status->{$lockid} || 0;
143
144 my $ctime = time();
4d24e7db
DM
145
146 eval {
147
148 mkdir $lockdir;
149
007fcc8b
DM
150 # pve cluster filesystem not online
151 die "can't create '$lockdir' (pmxcfs not mounted?)\n" if ! -d $lockdir;
152
153 if ($last && (($ctime - $last) < 100)) { # fixme: what timeout
154 utime(0, $ctime, $filename) || # cfs lock update request
155 die "cfs lock update failed - $!\n";
156 } else {
157
158 # fixme: wait some time?
159 if (!(mkdir $filename)) {
160 utime 0, 0, $filename; # cfs unlock request
161 die "can't get cfs lock\n";
162 }
163 }
4d24e7db 164
007fcc8b 165 $got_lock = 1;
4d24e7db
DM
166 };
167
007fcc8b
DM
168 my $err = $@;
169
170 $last_lock_status->{$lockid} = $got_lock ? $ctime : 0;
171
172 if ($got_lock != $last) {
173 if ($got_lock) {
174 $self->log('info', "successfully aquired lock '$lockid'");
175 } else {
176 my $msg = "lost lock '$lockid";
177 $msg .= " - $err" if $err;
178 $self->log('err', $msg);
179 }
180 }
181
182 return $got_lock;
183}
184
185sub get_ha_manager_lock {
186 my ($self) = @_;
187
188 my $lockid = "ha_manager_lock";
189
190 my $filename = "$lockdir/$lockid";
191
192 return $self->get_pve_lock("ha_manager_lock");
714a4016
DM
193}
194
195sub get_ha_agent_lock {
196 my ($self) = @_;
007fcc8b
DM
197
198 my $node = $self->nodename();
714a4016 199
007fcc8b 200 return $self->get_pve_lock("ha_agent_${node}_lock");
714a4016
DM
201}
202
203sub test_ha_agent_lock {
204 my ($self, $node) = @_;
007fcc8b
DM
205
206 my $lockid = "ha_agent_${node}_lock";
207 my $filename = "$lockdir/$lockid";
208 my $res = $self->get_pve_lock($lockid);
209 rmdir $filename if $res; # cfs unlock
714a4016 210
007fcc8b 211 return $res;
714a4016
DM
212}
213
214sub quorate {
215 my ($self) = @_;
216
4d24e7db
DM
217 my $quorate = 0;
218 eval {
219 $quorate = PVE::Cluster::check_cfs_quorum();
220 };
221
222 return $quorate;
714a4016
DM
223}
224
225sub get_time {
226 my ($self) = @_;
227
228 return time();
229}
230
231sub sleep {
232 my ($self, $delay) = @_;
233
234 CORE::sleep($delay);
235}
236
237sub sleep_until {
238 my ($self, $end_time) = @_;
239
240 for (;;) {
241 my $cur_time = time();
242
243 last if $cur_time >= $end_time;
244
245 $self->sleep(1);
246 }
247}
248
249sub loop_start_hook {
250 my ($self) = @_;
251
4d24e7db
DM
252 PVE::Cluster::cfs_update();
253
714a4016
DM
254 $self->{loop_start} = $self->get_time();
255}
256
257sub loop_end_hook {
258 my ($self) = @_;
259
260 my $delay = $self->get_time() - $self->{loop_start};
261
262 warn "loop take too long ($delay seconds)\n" if $delay > 30;
263}
264
76737af5
DM
265my $watchdog_fh;
266
267my $WDIOC_GETSUPPORT = 0x80285700;
268my $WDIOC_KEEPALIVE = 0x80045705;
269my $WDIOC_SETTIMEOUT = 0xc0045706;
270my $WDIOC_GETTIMEOUT = 0x80045707;
271
714a4016
DM
272sub watchdog_open {
273 my ($self) = @_;
274
76737af5 275 system("modprobe -q softdog soft_noboot=1") if ! -e "/dev/watchdog";
007fcc8b 276
76737af5
DM
277 die "watchdog already open\n" if defined($watchdog_fh);
278
279 $watchdog_fh = IO::File->new(">/dev/watchdog") ||
280 die "unable to open watchdog device - $!\n";
281
282 eval {
283 my $timeoutbuf = pack('I', 100);
284 my $res = ioctl($watchdog_fh, $WDIOC_SETTIMEOUT, $timeoutbuf) ||
285 die "unable to set watchdog timeout - $!\n";
286 my $timeout = unpack("I", $timeoutbuf);
287 die "got wrong watchdog timeout '$timeout'\n" if $timeout != 100;
714a4016 288
76737af5
DM
289 my $wdinfo = "\x00" x 40;
290 $res = ioctl($watchdog_fh, $WDIOC_GETSUPPORT, $wdinfo) ||
291 die "unable to get watchdog info - $!\n";
007fcc8b 292
76737af5
DM
293 my ($options, $firmware_version, $indentity) = unpack("lla32", $wdinfo);
294 die "watchdog does not support magic close\n" if !($options & 0x0100);
007fcc8b 295
76737af5
DM
296 };
297 if (my $err = $@) {
298 $self->watchdog_close();
299 die $err;
300 }
301
302 # fixme: use ioctl to setup watchdog timeout (requires C interface)
303
304 $self->log('info', "watchdog active");
714a4016
DM
305}
306
307sub watchdog_update {
308 my ($self, $wfh) = @_;
309
76737af5
DM
310 my $res = $watchdog_fh->syswrite("\0", 1);
311 if (!defined($res)) {
312 $self->log('err', "watchdog update failed - $!\n");
313 return 0;
314 }
315 if ($res != 1) {
316 $self->log('err', "watchdog update failed - write $res bytes\n");
317 return 0;
318 }
319
320 return 1;
714a4016
DM
321}
322
323sub watchdog_close {
324 my ($self, $wfh) = @_;
325
76737af5
DM
326 $watchdog_fh->syswrite("V", 1); # magic watchdog close
327 if (!$watchdog_fh->close()) {
328 $self->log('err', "watchdog close failed - $!");
329 } else {
330 $watchdog_fh = undef;
331 $self->log('info', "watchdog closed (disabled)");
332 }
714a4016
DM
333}
334
c4a221bc
DM
335sub exec_resource_agent {
336 my ($self, $sid, $cmd, @params) = @_;
337
338 die "implement me";
339}
340
714a4016 3411;