]> git.proxmox.com Git - pve-manager.git/blame - bin/test/ReplicationTestEnv.pm
pvesr prepare-local-job: new helper
[pve-manager.git] / bin / test / ReplicationTestEnv.pm
CommitLineData
d0920c29
DM
1package ReplicationTestEnv;
2
3use strict;
4use warnings;
5use JSON;
c5014e65
DM
6use Clone 'clone';
7use File::Basename;
d0920c29
DM
8
9use lib ('.', '../..');
10
11use Data::Dumper;
12
13use PVE::INotify;
14use PVE::Cluster;
15use PVE::Storage;
16use PVE::Replication;
17use PVE::QemuConfig;
18use PVE::LXC::Config;
19
20use Test::MockModule;
21
22our $mocked_nodename = 'node1';
23
24our $mocked_replication_jobs = {};
25
26my $pve_replicationconfig = Test::MockModule->new('PVE::ReplicationConfig');
27
28our $mocked_vm_configs = {};
29
30our $mocked_ct_configs = {};
31
32my $mocked_vmlist = sub {
33 my $res = {};
34
35 foreach my $id (keys %$mocked_ct_configs) {
36 my $d = $mocked_ct_configs->{$id};
37 $res->{$id} = { 'type' => 'lxc', 'node' => $d->{node}, 'version' => 1 };
38 }
39 foreach my $id (keys %$mocked_vm_configs) {
40 my $d = $mocked_vm_configs->{$id};
41 $res->{$id} = { 'type' => 'qemu', 'node' => $d->{node}, 'version' => 1 };
42 }
43
44 return { 'ids' => $res };
45};
46
47
48my $statefile = ".mocked_repl_state";
49
50unlink $statefile;
51$PVE::Replication::state_path = $statefile;
52
53my $mocked_write_state = sub {
54 my ($state) = @_;
55
56 PVE::Tools::file_set_contents($statefile, encode_json($state));
57};
58
59my $mocked_read_state = sub {
60
61 return {} if ! -e $statefile;
62
63 my $raw = PVE::Tools::file_get_contents($statefile);
64
65 return {} if $raw eq '';
66
67 return decode_json($raw);
68};
69
70
71my $pve_cluster_module = Test::MockModule->new('PVE::Cluster');
72
73my $pve_inotify_module = Test::MockModule->new('PVE::INotify');
74
75my $mocked_qemu_load_conf = sub {
76 my ($class, $vmid, $node) = @_;
77
78 $node = $mocked_nodename if !$node;
79
80 my $conf = $mocked_vm_configs->{$vmid};
81
82 die "no such vm '$vmid'" if !defined($conf);
83 die "vm '$vmid' on wrong node" if $conf->{node} ne $node;
84
85 return $conf;
86};
87
88my $pve_qemuserver_module = Test::MockModule->new('PVE::QemuServer');
89
90my $pve_qemuconfig_module = Test::MockModule->new('PVE::QemuConfig');
91
92my $mocked_lxc_load_conf = sub {
93 my ($class, $vmid, $node) = @_;
94
95 $node = $mocked_nodename if !$node;
96
97 my $conf = $mocked_ct_configs->{$vmid};
98
99 die "no such ct '$vmid'" if !defined($conf);
100 die "ct '$vmid' on wrong node" if $conf->{node} ne $node;
101
102 return $conf;
103};
104
105my $pve_lxc_config_module = Test::MockModule->new('PVE::LXC::Config');
106
107my $mocked_replication_config = sub {
108
c5014e65
DM
109 my $res = clone($mocked_replication_jobs);
110
d0920c29
DM
111 return bless { ids => $res }, 'PVE::ReplicationConfig';
112};
113
114my $mocked_storage_config = {
115 ids => {
116 local => {
117 type => 'dir',
118 shared => 0,
119 content => {
120 'iso' => 1,
121 'backup' => 1,
122 },
123 path => "/var/lib/vz",
124 },
125 'local-zfs' => {
126 type => 'zfspool',
127 pool => 'nonexistent-testpool',
128 shared => 0,
129 content => {
130 'images' => 1,
131 'rootdir' => 1
132 },
133 },
134 },
135};
136
137my $pve_storage_module = Test::MockModule->new('PVE::Storage');
c5014e65 138
d0920c29
DM
139sub setup {
140 $pve_storage_module->mock(config => sub { return $mocked_storage_config; });
141
c5014e65 142 $pve_replicationconfig->mock(new => $mocked_replication_config);
d0920c29
DM
143 $pve_qemuserver_module->mock(check_running => sub { return 0; });
144 $pve_qemuconfig_module->mock(load_config => $mocked_qemu_load_conf);
145
146 $pve_lxc_config_module->mock(load_config => $mocked_lxc_load_conf);
147
148
149 $pve_cluster_module->mock(get_vmlist => sub { return $mocked_vmlist->(); });
150 $pve_inotify_module->mock('nodename' => sub { return $mocked_nodename; });
151};
152
c5014e65
DM
153# code to generate/conpare test logs
154
155my $logname;
156my $logfh;
157
158sub openlog {
159 my ($filename) = @_;
160
161 if (!$filename) {
162 # compute from $0
163 $filename = basename($0);
164 if ($filename =~ m/^(\S+)\.pl$/) {
165 $filename = "$1.log";
166 } else {
167 die "unable to compute log name for $0";
168 }
169 }
170
171 die "log already open" if defined($logname);
172
173 open (my $fh, ">", "$filename.tmp") ||
174 die "unable to open log - $!";
175
176 $logname = $filename;
177 $logfh = $fh;
178}
179
180sub logmsg {
181 my ($ctime, $msg) = @_;
182
183 print "$ctime $msg\n";
184 print $logfh "$ctime $msg\n";
185}
186
187sub commit_log {
188
189 close($logfh);
190
191 if (-f $logname) {
192 my $diff = `diff -u '$logname' '$logname.tmp'`;
193 if ($diff) {
194 warn "got unexpeted output\n";
195 print "# diff -u '$logname' '$logname.tmp'\n";
196 print $diff;
197 exit(-1);
198 }
199 } else {
200 rename("$logname.tmp", $logname) || die "rename log failed - $!";
201 }
202}
203
204my $status;
205
206# helper to track job status
207sub track_jobs {
208 my ($ctime) = @_;
209
210 if (!$status) {
211 $status = PVE::Replication::job_status();
212 foreach my $jobid (sort keys %$status) {
213 my $jobcfg = $status->{$jobid};
214 logmsg($ctime, "$jobid: new job next_sync => $jobcfg->{next_sync}");
215 }
216 }
217
f70997ea 218 PVE::Replication::run_jobs($ctime, \&logmsg);
c5014e65
DM
219
220 my $new = PVE::Replication::job_status();
221
222 # detect removed jobs
223 foreach my $jobid (sort keys %$status) {
224 if (!$new->{$jobid}) {
225 logmsg($ctime, "$jobid: vanished job");
226 }
227 }
228
229 foreach my $jobid (sort keys %$new) {
230 my $jobcfg = $new->{$jobid};
231 my $oldcfg = $status->{$jobid};
232 if (!$oldcfg) {
233 logmsg($ctime, "$jobid: new job next_sync => $jobcfg->{next_sync}");
234 next; # no old state to compare
235 } else {
236 foreach my $k (qw(target guest vmtype next_sync)) {
237 my $changes = '';
238 if ($oldcfg->{$k} ne $jobcfg->{$k}) {
239 $changes .= ', ' if $changes;
240 $changes .= "$k => $jobcfg->{$k}";
241 }
242 logmsg($ctime, "$jobid: changed config $changes") if $changes;
243 }
244 }
245
246 my $oldstate = $oldcfg->{state};
247 my $state = $jobcfg->{state};
248
249 my $changes = '';
250 foreach my $k (qw(last_try last_sync fail_count error)) {
251 if (($oldstate->{$k} // '') ne ($state->{$k} // '')) {
252 my $value = $state->{$k};
253 chomp $value;
254 $changes .= ', ' if $changes;
255 $changes .= "$k => $value";
256 }
257 }
258 logmsg($ctime, "$jobid: changed state $changes") if $changes;
259
260 }
261 $status = $new;
262}
d0920c29
DM
263
264
2651;