]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Sim/Env.pm
Sim/Hardware: check if testdir exists
[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;
9e5ea8f7
DM
13use PVE::HA::Resources;
14use PVE::HA::Sim::Resources::VirtVM;
15use PVE::HA::Sim::Resources::VirtCT;
ec368d74 16use PVE::HA::Sim::Resources::VirtFail;
9e5ea8f7
DM
17
18PVE::HA::Sim::Resources::VirtVM->register();
19PVE::HA::Sim::Resources::VirtCT->register();
ec368d74 20PVE::HA::Sim::Resources::VirtFail->register();
9e5ea8f7
DM
21
22PVE::HA::Resources->init();
87b82b15
DM
23
24sub new {
25 my ($this, $nodename, $hardware, $log_id) = @_;
26
27 die "missing nodename" if !$nodename;
28 die "missing log_id" if !$log_id;
f5c29173 29
87b82b15
DM
30 my $class = ref($this) || $this;
31
32 my $self = bless {}, $class;
33
34 $self->{statusdir} = $hardware->statusdir();
35 $self->{nodename} = $nodename;
36
37 $self->{hardware} = $hardware;
38 $self->{lock_timeout} = 120;
39
40 $self->{log_id} = $log_id;
41
42 return $self;
43}
44
45sub nodename {
46 my ($self) = @_;
47
48 return $self->{nodename};
49}
50
dd9c0c9d
TL
51sub hardware {
52 my ($self) = @_;
53
54 return $self->{hardware};
55}
56
87b82b15
DM
57sub sim_get_lock {
58 my ($self, $lock_name, $unlock) = @_;
59
60 return 0 if !$self->quorate();
61
62 my $filename = "$self->{statusdir}/cluster_locks";
63
64 my $code = sub {
65
f5c29173 66 my $data = PVE::HA::Tools::read_json_from_file($filename, {});
87b82b15
DM
67
68 my $res;
69
70 my $nodename = $self->nodename();
71 my $ctime = $self->get_time();
72
73 if ($unlock) {
74
75 if (my $d = $data->{$lock_name}) {
76 my $tdiff = $ctime - $d->{time};
f5c29173 77
87b82b15
DM
78 if ($tdiff > $self->{lock_timeout}) {
79 $res = 1;
80 } elsif (($tdiff <= $self->{lock_timeout}) && ($d->{node} eq $nodename)) {
81 delete $data->{$lock_name};
82 $res = 1;
83 } else {
84 $res = 0;
85 }
86 }
87
88 } else {
89
90 if (my $d = $data->{$lock_name}) {
f5c29173 91
87b82b15 92 my $tdiff = $ctime - $d->{time};
f5c29173 93
87b82b15
DM
94 if ($tdiff <= $self->{lock_timeout}) {
95 if ($d->{node} eq $nodename) {
96 $d->{time} = $ctime;
97 $res = 1;
98 } else {
99 $res = 0;
100 }
101 } else {
102 $self->log('info', "got lock '$lock_name'");
103 $d->{node} = $nodename;
a371ef65 104 $d->{time} = $ctime;
87b82b15
DM
105 $res = 1;
106 }
107
108 } else {
109 $data->{$lock_name} = {
110 time => $ctime,
111 node => $nodename,
112 };
113 $self->log('info', "got lock '$lock_name'");
114 $res = 1;
115 }
116 }
117
f5c29173 118 PVE::HA::Tools::write_json_to_file($filename, $data);
87b82b15
DM
119
120 return $res;
121 };
122
123 return $self->{hardware}->global_lock($code);
124}
125
126sub read_manager_status {
127 my ($self) = @_;
f5c29173 128
87b82b15
DM
129 my $filename = "$self->{statusdir}/manager_status";
130
f5c29173 131 return PVE::HA::Tools::read_json_from_file($filename, {});
87b82b15
DM
132}
133
134sub write_manager_status {
135 my ($self, $status_obj) = @_;
136
137 my $filename = "$self->{statusdir}/manager_status";
138
f5c29173 139 PVE::HA::Tools::write_json_to_file($filename, $status_obj);
87b82b15
DM
140}
141
c4a221bc
DM
142sub read_lrm_status {
143 my ($self, $node) = @_;
144
145 $node = $self->{nodename} if !defined($node);
146
147 return $self->{hardware}->read_lrm_status($node);
148}
149
150sub write_lrm_status {
151 my ($self, $status_obj) = @_;
152
153 my $node = $self->{nodename};
154
155 return $self->{hardware}->write_lrm_status($node, $status_obj);
156}
157
cde77779 158sub is_node_shutdown {
d42219a3
TL
159 my ($self) = @_;
160
161 return 0; # default to freezing services if not overwritten by subclass
162}
b83b4ae8 163
87b82b15
DM
164sub read_service_config {
165 my ($self) = @_;
166
95360669 167 return $self->{hardware}->read_service_config();
87b82b15
DM
168}
169
c982dfee
TL
170sub read_fence_config {
171 my ($self) = @_;
172
173 return $self->{hardware}->read_fence_config();
174}
175
176# the test/sim framework has hardware enabled fencing if
177# it has devices configured
178sub fencing_mode {
179 my ($self) = @_;
180
181 my $cfg = $self->read_fence_config();
182
183 return (defined($cfg) && keys %{$cfg}) ? 'hardware' : 'watchdog';
184}
185
186sub exec_fence_agent {
187 my ($self, $agent, $node, @param) = @_;
188
189 return $self->{hardware}->exec_fence_agent($agent, $node, @param);
190}
191
abc920b4
DM
192sub read_group_config {
193 my ($self) = @_;
194
195 return $self->{hardware}->read_group_config();
196}
197
9da84a0d
TL
198# this is normally only allowed by the master to recover a _fenced_ service
199sub steal_service {
6da27e23 200 my ($self, $sid, $current_node, $new_node) = @_;
8456bde2 201
6da27e23 202 return $self->{hardware}->change_service_location($sid, $current_node, $new_node);
8456bde2
DM
203}
204
3b996922
DM
205sub queue_crm_commands {
206 my ($self, $cmd) = @_;
207
208 return $self->{hardware}->queue_crm_commands($cmd);
209}
210
211sub read_crm_commands {
212 my ($self) = @_;
213
214 return $self->{hardware}->read_crm_commands();
215}
216
87b82b15
DM
217sub log {
218 my ($self, $level, $msg) = @_;
219
220 chomp $msg;
221
222 my $time = $self->get_time();
223
224 printf("%-5s %5d %12s: $msg\n", $level, $time, "$self->{nodename}/$self->{log_id}");
225}
226
227sub get_time {
228 my ($self) = @_;
229
230 die "implement in subclass";
231}
232
233sub sleep {
234 my ($self, $delay) = @_;
235
236 die "implement in subclass";
237}
238
239sub sleep_until {
240 my ($self, $end_time) = @_;
241
242 die "implement in subclass";
243}
244
245sub get_ha_manager_lock {
246 my ($self) = @_;
247
248 return $self->sim_get_lock('ha_manager_lock');
249}
250
de002253
TL
251# release the cluster wide manager lock.
252# when released another CRM may step up and get the lock, thus this should only
253# get called when shutting down/deactivating the current master
254sub release_ha_manager_lock {
255 my ($self) = @_;
256
257 return $self->sim_get_lock('ha_manager_lock', 1);
258}
259
87b82b15
DM
260sub get_ha_agent_lock_name {
261 my ($self, $node) = @_;
262
263 $node = $self->nodename() if !$node;
264
265 return "ha_agent_${node}_lock";
266}
267
268sub get_ha_agent_lock {
87b82b15
DM
269 my ($self, $node) = @_;
270
271 my $lck = $self->get_ha_agent_lock_name($node);
f5c29173 272 return $self->sim_get_lock($lck);
87b82b15
DM
273}
274
ff165cd8
TL
275
276# release the respective node agent lock.
277# this should only get called if the nodes LRM gracefully shuts down with
278# all services already cleanly stopped!
279sub release_ha_agent_lock {
280 my ($self) = @_;
281
282 my $node = $self->nodename();
283
284 my $lock = $self->get_ha_agent_lock_name($node);
285 return $self->sim_get_lock($lock, 1);
286}
287
87b82b15
DM
288# return true when cluster is quorate
289sub quorate {
290 my ($self) = @_;
291
292 my ($node_info, $quorate) = $self->{hardware}->get_node_info();
293 my $node = $self->nodename();
294 return 0 if !$node_info->{$node}->{online};
295 return $quorate;
296}
297
298sub get_node_info {
299 my ($self) = @_;
300
301 return $self->{hardware}->get_node_info();
302}
303
304sub loop_start_hook {
305 my ($self, $starttime) = @_;
306
307 # do nothing, overwrite in subclass
308}
309
310sub loop_end_hook {
311 my ($self) = @_;
312
313 # do nothing, overwrite in subclass
314}
315
316sub watchdog_open {
317 my ($self) = @_;
318
319 my $node = $self->nodename();
320
321 return $self->{hardware}->watchdog_open($node);
322}
323
324sub watchdog_update {
325 my ($self, $wfh) = @_;
326
327 return $self->{hardware}->watchdog_update($wfh);
328}
329
330sub watchdog_close {
331 my ($self, $wfh) = @_;
332
333 return $self->{hardware}->watchdog_close($wfh);
334}
335
a28fa330 336sub after_fork {
1b3ee441
DM
337 my ($self) = @_;
338
a28fa330 339 # nothing to clean up in the simulation environment
1b3ee441
DM
340}
341
a28fa330
TL
342
343sub get_max_workers {
a2aae08a
TL
344 my ($self) = @_;
345
a28fa330 346 return 4;
a2aae08a
TL
347}
348
87b82b15 3491;