]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Sim/Env.pm
TestHardware: add 'reboot' and 'shutdown' command
[pve-ha-manager.git] / src / PVE / HA / Sim / Env.pm
CommitLineData
87b82b15
DM
1package PVE::HA::Sim::Env;
2
3use strict;
4use warnings;
5use POSIX qw(strftime EINTR);
6use Data::Dumper;
f5c29173 7use JSON;
87b82b15
DM
8use IO::File;
9use Fcntl qw(:DEFAULT :flock);
10
11use PVE::HA::Tools;
12use PVE::HA::Env;
13
14sub new {
15 my ($this, $nodename, $hardware, $log_id) = @_;
16
17 die "missing nodename" if !$nodename;
18 die "missing log_id" if !$log_id;
f5c29173 19
87b82b15
DM
20 my $class = ref($this) || $this;
21
22 my $self = bless {}, $class;
23
24 $self->{statusdir} = $hardware->statusdir();
25 $self->{nodename} = $nodename;
26
27 $self->{hardware} = $hardware;
28 $self->{lock_timeout} = 120;
29
30 $self->{log_id} = $log_id;
31
32 return $self;
33}
34
35sub nodename {
36 my ($self) = @_;
37
38 return $self->{nodename};
39}
40
41sub sim_get_lock {
42 my ($self, $lock_name, $unlock) = @_;
43
44 return 0 if !$self->quorate();
45
46 my $filename = "$self->{statusdir}/cluster_locks";
47
48 my $code = sub {
49
f5c29173 50 my $data = PVE::HA::Tools::read_json_from_file($filename, {});
87b82b15
DM
51
52 my $res;
53
54 my $nodename = $self->nodename();
55 my $ctime = $self->get_time();
56
57 if ($unlock) {
58
59 if (my $d = $data->{$lock_name}) {
60 my $tdiff = $ctime - $d->{time};
f5c29173 61
87b82b15
DM
62 if ($tdiff > $self->{lock_timeout}) {
63 $res = 1;
64 } elsif (($tdiff <= $self->{lock_timeout}) && ($d->{node} eq $nodename)) {
65 delete $data->{$lock_name};
66 $res = 1;
67 } else {
68 $res = 0;
69 }
70 }
71
72 } else {
73
74 if (my $d = $data->{$lock_name}) {
f5c29173 75
87b82b15 76 my $tdiff = $ctime - $d->{time};
f5c29173 77
87b82b15
DM
78 if ($tdiff <= $self->{lock_timeout}) {
79 if ($d->{node} eq $nodename) {
80 $d->{time} = $ctime;
81 $res = 1;
82 } else {
83 $res = 0;
84 }
85 } else {
86 $self->log('info', "got lock '$lock_name'");
87 $d->{node} = $nodename;
a371ef65 88 $d->{time} = $ctime;
87b82b15
DM
89 $res = 1;
90 }
91
92 } else {
93 $data->{$lock_name} = {
94 time => $ctime,
95 node => $nodename,
96 };
97 $self->log('info', "got lock '$lock_name'");
98 $res = 1;
99 }
100 }
101
f5c29173 102 PVE::HA::Tools::write_json_to_file($filename, $data);
87b82b15
DM
103
104 return $res;
105 };
106
107 return $self->{hardware}->global_lock($code);
108}
109
110sub read_manager_status {
111 my ($self) = @_;
f5c29173 112
87b82b15
DM
113 my $filename = "$self->{statusdir}/manager_status";
114
f5c29173 115 return PVE::HA::Tools::read_json_from_file($filename, {});
87b82b15
DM
116}
117
118sub write_manager_status {
119 my ($self, $status_obj) = @_;
120
121 my $filename = "$self->{statusdir}/manager_status";
122
f5c29173 123 PVE::HA::Tools::write_json_to_file($filename, $status_obj);
87b82b15
DM
124}
125
c4a221bc
DM
126sub read_lrm_status {
127 my ($self, $node) = @_;
128
129 $node = $self->{nodename} if !defined($node);
130
131 return $self->{hardware}->read_lrm_status($node);
132}
133
134sub write_lrm_status {
135 my ($self, $status_obj) = @_;
136
137 my $node = $self->{nodename};
138
139 return $self->{hardware}->write_lrm_status($node, $status_obj);
140}
141
b83b4ae8
DM
142
143sub service_config_exists {
144 my ($self) = @_;
145
146 return 1;
147}
148
87b82b15
DM
149sub read_service_config {
150 my ($self) = @_;
151
95360669 152 return $self->{hardware}->read_service_config();
87b82b15
DM
153}
154
abc920b4
DM
155sub read_group_config {
156 my ($self) = @_;
157
158 return $self->{hardware}->read_group_config();
159}
160
8456bde2 161sub change_service_location {
6da27e23 162 my ($self, $sid, $current_node, $new_node) = @_;
8456bde2 163
6da27e23 164 return $self->{hardware}->change_service_location($sid, $current_node, $new_node);
8456bde2
DM
165}
166
3b996922
DM
167sub queue_crm_commands {
168 my ($self, $cmd) = @_;
169
170 return $self->{hardware}->queue_crm_commands($cmd);
171}
172
173sub read_crm_commands {
174 my ($self) = @_;
175
176 return $self->{hardware}->read_crm_commands();
177}
178
87b82b15
DM
179sub log {
180 my ($self, $level, $msg) = @_;
181
182 chomp $msg;
183
184 my $time = $self->get_time();
185
186 printf("%-5s %5d %12s: $msg\n", $level, $time, "$self->{nodename}/$self->{log_id}");
187}
188
189sub get_time {
190 my ($self) = @_;
191
192 die "implement in subclass";
193}
194
195sub sleep {
196 my ($self, $delay) = @_;
197
198 die "implement in subclass";
199}
200
201sub sleep_until {
202 my ($self, $end_time) = @_;
203
204 die "implement in subclass";
205}
206
207sub get_ha_manager_lock {
208 my ($self) = @_;
209
210 return $self->sim_get_lock('ha_manager_lock');
211}
212
213sub get_ha_agent_lock_name {
214 my ($self, $node) = @_;
215
216 $node = $self->nodename() if !$node;
217
218 return "ha_agent_${node}_lock";
219}
220
221sub get_ha_agent_lock {
87b82b15
DM
222 my ($self, $node) = @_;
223
224 my $lck = $self->get_ha_agent_lock_name($node);
f5c29173 225 return $self->sim_get_lock($lck);
87b82b15
DM
226}
227
228# return true when cluster is quorate
229sub quorate {
230 my ($self) = @_;
231
232 my ($node_info, $quorate) = $self->{hardware}->get_node_info();
233 my $node = $self->nodename();
234 return 0 if !$node_info->{$node}->{online};
235 return $quorate;
236}
237
238sub get_node_info {
239 my ($self) = @_;
240
241 return $self->{hardware}->get_node_info();
242}
243
244sub loop_start_hook {
245 my ($self, $starttime) = @_;
246
247 # do nothing, overwrite in subclass
248}
249
250sub loop_end_hook {
251 my ($self) = @_;
252
253 # do nothing, overwrite in subclass
254}
255
256sub watchdog_open {
257 my ($self) = @_;
258
259 my $node = $self->nodename();
260
261 return $self->{hardware}->watchdog_open($node);
262}
263
264sub watchdog_update {
265 my ($self, $wfh) = @_;
266
267 return $self->{hardware}->watchdog_update($wfh);
268}
269
270sub watchdog_close {
271 my ($self, $wfh) = @_;
272
273 return $self->{hardware}->watchdog_close($wfh);
274}
275
1b3ee441
DM
276sub can_fork {
277 my ($self) = @_;
278
279 return 1;
280}
281
c4a221bc 282sub exec_resource_agent {
1b3ee441
DM
283 my ($self, $sid, $cd, $cmd, @params) = @_;
284
285 my $hardware = $self->{hardware};
286
287 my $nodename = $self->{nodename};
288
289 # fixme: return valid_exit code (instead of using die)
290
291 my $ss = $hardware->read_service_status($nodename);
292
293 if ($cmd eq 'started') {
294
295 # fixme: return valid_exit code
296 die "service '$sid' not on this node" if $cd->{node} ne $nodename;
297
298 if ($ss->{$sid}) {
299 return 0;
300 }
301 $self->log("info", "starting service $sid");
302
303 $self->sleep(2);
304
305 $ss->{$sid} = 1;
306 $hardware->write_service_status($nodename, $ss);
307
308 $self->log("info", "service status $sid started");
309
310 return 0;
311
312 } elsif ($cmd eq 'request_stop' || $cmd eq 'stopped') {
313
314 # fixme: return valid_exit code
315 die "service '$sid' not on this node" if $cd->{node} ne $nodename;
316
317 if (!$ss->{$sid}) {
318 return 0;
319 }
320 $self->log("info", "stopping service $sid");
321
322 $self->sleep(2);
323
324 $ss->{$sid} = 0;
325 $hardware->write_service_status($nodename, $ss);
326
327 $self->log("info", "service status $sid stopped");
328
329 return 0;
330
331 } elsif ($cmd eq 'migrate' || $cmd eq 'relocate') {
332
333 my $target = $params[0];
334 die "$cmd '$sid' failed - missing target\n" if !defined($target);
335
336 if ($cd->{node} eq $target) {
337 # already migrate
338 return 0;
339 } elsif ($cd->{node} eq $nodename) {
340
341 $self->log("info", "service $sid - start $cmd to node '$target'");
342
343 if ($cmd eq 'relocate' && $ss->{$sid}) {
344 $self->log("info", "stopping service $sid (relocate)");
345 $self->sleep(1);
346 $ss->{$sid} = 0;
347 $hardware->write_service_status($nodename, $ss);
348 $self->log("info", "service status $sid stopped");
349 }
350
351 $self->sleep(2);
620d803d 352 $self->change_service_location($sid, $nodename, $target);
1b3ee441
DM
353 $self->log("info", "service $sid - end $cmd to node '$target'");
354
355 return 0;
356
357 } else {
358 die "migrate '$sid' failed - service is not on this node\n";
359 }
360
361
362 }
c4a221bc 363
1b3ee441 364 die "implement me (cmd '$cmd')";
c4a221bc
DM
365}
366
87b82b15 3671;