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