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