]> git.proxmox.com Git - pve-storage.git/blame - PVE/Storage/DRBDPlugin.pm
remove unused Data::Dumper usages
[pve-storage.git] / PVE / Storage / DRBDPlugin.pm
CommitLineData
14770890
DM
1package PVE::Storage::DRBDPlugin;
2
3use strict;
4use warnings;
074b2cb4 5
14770890 6use IO::File;
eab90afd 7use Net::DBus;
eab90afd 8
14770890 9use PVE::Tools qw(run_command trim);
28d58512 10use PVE::INotify;
14770890
DM
11use PVE::Storage::Plugin;
12use PVE::JSONSchema qw(get_standard_option);
13
14use base qw(PVE::Storage::Plugin);
15
16# Configuration
17
fb0e1d93
DM
18my $default_redundancy = 2;
19
14770890
DM
20sub type {
21 return 'drbd';
22}
23
24sub plugindata {
25 return {
3c056934 26 content => [ {images => 1, rootdir => 1}, { images => 1 }],
14770890
DM
27 };
28}
29
30sub properties {
31 return {
32 redundancy => {
33 description => "The redundancy count specifies the number of nodes to which the resource should be deployed. It must be at least 1 and at most the number of nodes in the cluster.",
34 type => 'integer',
35 minimum => 1,
36 maximum => 16,
fb0e1d93 37 default => $default_redundancy,
14770890
DM
38 },
39 };
40}
41
42sub options {
43 return {
44 redundancy => { optional => 1 },
c2c31217 45 content => { optional => 1 },
14770890
DM
46 nodes => { optional => 1 },
47 disable => { optional => 1 },
9edb99a5 48 bwlimit => { optional => 1 },
14770890
DM
49 };
50}
51
eab90afd
DM
52# helper
53
fb0e1d93
DM
54sub get_redundancy {
55 my ($scfg) = @_;
56
57 return $scfg->{redundancy} || $default_redundancy;
58}
59
eab90afd
DM
60sub connect_drbdmanage_service {
61
62 my $bus = Net::DBus->system;
63
64 my $service = $bus->get_service("org.drbd.drbdmanaged");
65
66 my $hdl = $service->get_object("/interface", "org.drbd.drbdmanaged");
67
68 return $hdl;
69}
70
31ba75ff 71sub check_drbd_res {
eab90afd
DM
72 my ($rc) = @_;
73
31ba75ff 74 die "got undefined drbd result\n" if !$rc;
eab90afd 75
9e4632c2 76 # Messages for return codes 1 to 99 are not considered an error.
31ba75ff 77 foreach my $res (@$rc) {
30a1369b 78 my ($code, $format, $details) = @$res;
eab90afd 79
9e4632c2 80 next if $code < 100;
eab90afd 81
30a1369b
DM
82 my $msg;
83 if (defined($format)) {
84 my @args = ();
85 push @args, $details->{$1} // ""
86 while $format =~ s,\%\((\w+)\),%,;
87
88 $msg = sprintf($format, @args);
89
90 } else {
91 $msg = "drbd error: got error code $code";
92 }
93
31ba75ff 94 chomp $msg;
31ba75ff
DM
95 die "drbd error: $msg\n";
96 }
97
98 return undef;
eab90afd
DM
99}
100
101sub drbd_list_volumes {
102 my ($hdl) = @_;
103
104 $hdl = connect_drbdmanage_service() if !$hdl;
105
106 my ($rc, $res) = $hdl->list_volumes([], 0, {}, []);
31ba75ff 107 check_drbd_res($rc);
eab90afd
DM
108
109 my $volumes = {};
110
111 foreach my $entry (@$res) {
112 my ($volname, $properties, $vol_list) = @$entry;
113
114 next if $volname !~ m/^vm-(\d+)-/;
115 my $vmid = $1;
116
117 # fixme: we always use volid 0 ?
118 my $size = 0;
119 foreach my $volentry (@$vol_list) {
120 my ($vol_id, $vol_properties) = @$volentry;
121 next if $vol_id != 0;
122 my $vol_size = $vol_properties->{vol_size} * 1024;
123 $size = $vol_size if $vol_size > $size;
124 }
125
126 $volumes->{$volname} = { format => 'raw', size => $size,
127 vmid => $vmid };
128 }
129
130 return $volumes;
131}
132
14770890
DM
133# Storage implementation
134
135sub parse_volname {
136 my ($class, $volname) = @_;
137
138 if ($volname =~ m/^(vm-(\d+)-[a-z][a-z0-9\-\_\.]*[a-z0-9]+)$/) {
7800e84d 139 return ('images', $1, $2, undef, undef, undef, 'raw');
14770890
DM
140 }
141
142 die "unable to parse lvm volume name '$volname'\n";
143}
144
145sub filesystem_path {
e67069eb
DM
146 my ($class, $scfg, $volname, $snapname) = @_;
147
148 die "drbd snapshot is not implemented\n" if defined($snapname);
14770890
DM
149
150 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
151
eab90afd
DM
152 # fixme: always use volid 0?
153 my $path = "/dev/drbd/by-res/$volname/0";
14770890
DM
154
155 return wantarray ? ($path, $vmid, $vtype) : $path;
156}
157
158sub create_base {
159 my ($class, $storeid, $scfg, $volname) = @_;
160
161 die "can't create base images in drbd storage\n";
162}
163
164sub clone_image {
165 my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
166
167 die "can't clone images in drbd storage\n";
168}
169
170sub alloc_image {
171 my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
172
173 die "unsupported format '$fmt'" if $fmt ne 'raw';
174
47dbb901 175 die "illegal name '$name' - should be 'vm-$vmid-*'\n"
69a093c7 176 if defined($name) && $name !~ m/^vm-$vmid-/;
14770890 177
eab90afd
DM
178 my $hdl = connect_drbdmanage_service();
179 my $volumes = drbd_list_volumes($hdl);
14770890 180
69a093c7 181 die "volume '$name' already exists\n" if defined($name) && $volumes->{$name};
eab90afd 182
69a093c7 183 if (!defined($name)) {
14770890
DM
184 for (my $i = 1; $i < 100; $i++) {
185 my $tn = "vm-$vmid-disk-$i";
eab90afd 186 if (!defined ($volumes->{$tn})) {
14770890
DM
187 $name = $tn;
188 last;
189 }
190 }
191 }
192
193 die "unable to allocate an image name for VM $vmid in storage '$storeid'\n"
69a093c7 194 if !defined($name);
9e4632c2 195
eab90afd 196 my ($rc, $res) = $hdl->create_resource($name, {});
31ba75ff 197 check_drbd_res($rc);
14770890 198
eab90afd 199 ($rc, $res) = $hdl->create_volume($name, $size, {});
31ba75ff 200 check_drbd_res($rc);
14770890 201
98e250aa
DM
202 ($rc, $res) = $hdl->set_drbdsetup_props(
203 {
204 target => "resource",
205 resource => $name,
206 type => 'neto',
207 'allow-two-primaries' => 'yes',
208 });
31ba75ff 209 check_drbd_res($rc);
9e4632c2 210
b0e0ed1a
DM
211 my $redundancy = get_redundancy($scfg);;
212
213 ($rc, $res) = $hdl->auto_deploy($name, $redundancy, 0, 0);
214 check_drbd_res($rc);
215
14770890
DM
216 return $name;
217}
218
219sub free_image {
220 my ($class, $storeid, $scfg, $volname, $isBase) = @_;
221
eab90afd
DM
222 my $hdl = connect_drbdmanage_service();
223 my ($rc, $res) = $hdl->remove_resource($volname, 0);
31ba75ff 224 check_drbd_res($rc);
14770890
DM
225
226 return undef;
227}
228
229sub list_images {
230 my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
231
232 my $vgname = $scfg->{vgname};
233
eab90afd
DM
234 $cache->{drbd_volumes} = drbd_list_volumes() if !$cache->{drbd_volumes};
235
14770890
DM
236 my $res = [];
237
eab90afd
DM
238 my $dat = $cache->{drbd_volumes};
239
240 foreach my $volname (keys %$dat) {
241
242 my $owner = $dat->{$volname}->{vmid};
243
244 my $volid = "$storeid:$volname";
245
246 if ($vollist) {
247 my $found = grep { $_ eq $volid } @$vollist;
248 next if !$found;
249 } else {
250 next if defined ($vmid) && ($owner ne $vmid);
251 }
252
253 my $info = $dat->{$volname};
254 $info->{volid} = $volid;
255
256 push @$res, $info;
257 }
258
14770890
DM
259 return $res;
260}
261
262sub status {
263 my ($class, $storeid, $scfg, $cache) = @_;
264
5d6a88b0
DM
265 my ($total, $avail, $used);
266
eab90afd
DM
267 eval {
268 my $hdl = connect_drbdmanage_service();
fb0e1d93 269 my $redundancy = get_redundancy($scfg);;
2e346fd4 270 my ($rc, $free_space, $total_space) = $hdl->cluster_free_query($redundancy);
31ba75ff 271 check_drbd_res($rc);
eab90afd 272
82548118
DM
273 $avail = $free_space*1024;
274 $total = $total_space*1024;
275 $used = $total - $avail;
eab90afd 276
eab90afd 277 };
5d6a88b0
DM
278 if (my $err = $@) {
279 # ignore error,
280 # assume storage if offline
14770890 281
5d6a88b0
DM
282 return undef;
283 }
284
285 return ($total, $avail, $used, 1);
14770890
DM
286}
287
288sub activate_storage {
289 my ($class, $storeid, $scfg, $cache) = @_;
290
291 return undef;
292}
293
294sub deactivate_storage {
295 my ($class, $storeid, $scfg, $cache) = @_;
296
297 return undef;
298}
299
300sub activate_volume {
02e797b8
WL
301 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
302
303 die "Snapshot not implemented on DRBD\n" if $snapname;
14770890 304
28d58512
DM
305 my $path = $class->path($scfg, $volname);
306
307 my $hdl = connect_drbdmanage_service();
308 my $nodename = PVE::INotify::nodename();
046fd4cb 309 my ($rc, $res) = $hdl->list_assignments([$nodename], [$volname], 0, {}, []);
31ba75ff 310 check_drbd_res($rc);
28d58512 311
046fd4cb
PM
312# assignment already exists?
313 return undef if @$res;
28d58512
DM
314
315 # create diskless assignment
316 ($rc, $res) = $hdl->assign($nodename, $volname, { diskless => 'true' });
31ba75ff 317 check_drbd_res($rc);
466183d6 318
0bdf560c 319 # wait until device is accessible
466183d6
DM
320 my $print_warning = 1;
321 my $max_wait_time = 20;
322 for (my $i = 0;; $i++) {
99136653
DM
323 if (1) {
324 # clumsy, but works
325 last if system("dd if=$path of=/dev/null bs=512 count=1 >/dev/null 2>&1") == 0;
326 } else {
327 # correct, but does not work?
328 ($rc, $res) = $hdl->list_assignments([$nodename], [$volname], 0, { "cstate:deploy" => "true" }, []);
329 check_drbd_res($rc);
330 my $len = scalar(@$res);
331 last if $len > 0;
332 }
466183d6
DM
333 die "aborting wait - device '$path' still not readable\n" if $i > $max_wait_time;
334 print "waiting for device '$path' to become ready...\n" if $print_warning;
335 $print_warning = 0;
336 sleep(1);
337 }
4959ea20 338
14770890
DM
339 return undef;
340}
341
342sub deactivate_volume {
02e797b8
WL
343 my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
344
345 die "Snapshot not implemented on DRBD\n" if $snapname;
14770890 346
ae9e512e
DM
347 return undef; # fixme: should we unassign ?
348
349 # remove above return to enable this code
350 my $hdl = connect_drbdmanage_service();
351 my $nodename = PVE::INotify::nodename();
352 my ($rc, $res) = $hdl->list_assignments([$nodename], [$volname], 0,
353 { "cstate:diskless" => "true" }, []);
354 check_drbd_res($rc);
355 if (scalar(@$res)) {
356 my ($rc, $res) = $hdl->unassign($nodename, $volname,0);
357 check_drbd_res($rc);
358 }
359
14770890
DM
360 return undef;
361}
362
363sub volume_resize {
364 my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
365
366 $size = ($size/1024/1024) . "M";
367
368 my $path = $class->path($scfg, $volname);
369
eab90afd
DM
370 # fixme: howto implement this
371 die "drbd volume_resize is not implemented";
14770890
DM
372
373 #my $cmd = ['/sbin/lvextend', '-L', $size, $path];
374 #run_command($cmd, errmsg => "error resizing volume '$path'");
375
376 return 1;
377}
378
379sub volume_snapshot {
380 my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
381
382 die "drbd snapshot is not implemented";
383}
384
385sub volume_snapshot_rollback {
386 my ($class, $scfg, $storeid, $volname, $snap) = @_;
387
388 die "drbd snapshot rollback is not implemented";
389}
390
391sub volume_snapshot_delete {
392 my ($class, $scfg, $storeid, $volname, $snap) = @_;
393
394 die "drbd snapshot delete is not implemented";
395}
396
397sub volume_has_feature {
398 my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
399
400 my $features = {
401 copy => { base => 1, current => 1},
402 };
403
404 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
405 $class->parse_volname($volname);
406
407 my $key = undef;
408 if($snapname){
409 $key = 'snap';
410 }else{
411 $key = $isBase ? 'base' : 'current';
412 }
413 return 1 if $features->{$feature}->{$key};
414
415 return undef;
416}
417
4181;