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