]> git.proxmox.com Git - pve-storage.git/blob - PVE/Storage/DRBDPlugin.pm
DRBDPlugin: fix bug in status
[pve-storage.git] / PVE / Storage / DRBDPlugin.pm
1 package PVE::Storage::DRBDPlugin;
2
3 use strict;
4 use warnings;
5 use IO::File;
6 use Net::DBus;
7 use Data::Dumper;
8
9 use PVE::Tools qw(run_command trim);
10 use PVE::Storage::Plugin;
11 use PVE::JSONSchema qw(get_standard_option);
12
13 use base qw(PVE::Storage::Plugin);
14
15 # Configuration
16
17 sub type {
18 return 'drbd';
19 }
20
21 sub plugindata {
22 return {
23 content => [ {images => 1}, { images => 1 }],
24 };
25 }
26
27 sub properties {
28 return {
29 redundancy => {
30 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.",
31 type => 'integer',
32 minimum => 1,
33 maximum => 16,
34 default => 2,
35 },
36 };
37 }
38
39 sub options {
40 return {
41 redundancy => { optional => 1 },
42 nodes => { optional => 1 },
43 disable => { optional => 1 },
44 };
45 }
46
47 # helper
48
49 sub connect_drbdmanage_service {
50
51 my $bus = Net::DBus->system;
52
53 my $service = $bus->get_service("org.drbd.drbdmanaged");
54
55 my $hdl = $service->get_object("/interface", "org.drbd.drbdmanaged");
56
57 return $hdl;
58 }
59
60 sub check_drbd_rc {
61 my ($rc) = @_;
62
63 die "got undefined drbd rc\n" if !$rc;
64
65 my ($code, $msg, $details) = @$rc;
66
67 return undef if $code == 0;
68
69 $msg = "drbd error: got error code $code" if !$msg;
70 chomp $msg;
71
72 # fixme: add error details?
73 #print Dumper($details);
74
75 die "drbd error: $msg\n";
76 }
77
78 sub drbd_list_volumes {
79 my ($hdl) = @_;
80
81 $hdl = connect_drbdmanage_service() if !$hdl;
82
83 my ($rc, $res) = $hdl->list_volumes([], 0, {}, []);
84 check_drbd_rc($rc->[0]);
85
86 my $volumes = {};
87
88 foreach my $entry (@$res) {
89 my ($volname, $properties, $vol_list) = @$entry;
90
91 next if $volname !~ m/^vm-(\d+)-/;
92 my $vmid = $1;
93
94 # fixme: we always use volid 0 ?
95 my $size = 0;
96 foreach my $volentry (@$vol_list) {
97 my ($vol_id, $vol_properties) = @$volentry;
98 next if $vol_id != 0;
99 my $vol_size = $vol_properties->{vol_size} * 1024;
100 $size = $vol_size if $vol_size > $size;
101 }
102
103 $volumes->{$volname} = { format => 'raw', size => $size,
104 vmid => $vmid };
105 }
106
107 return $volumes;
108 }
109
110 # Storage implementation
111
112 sub parse_volname {
113 my ($class, $volname) = @_;
114
115 if ($volname =~ m/^(vm-(\d+)-[a-z][a-z0-9\-\_\.]*[a-z0-9]+)$/) {
116 return ('images', $1, $2);
117 }
118
119 die "unable to parse lvm volume name '$volname'\n";
120 }
121
122 sub filesystem_path {
123 my ($class, $scfg, $volname) = @_;
124
125 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
126
127 # fixme: always use volid 0?
128 my $path = "/dev/drbd/by-res/$volname/0";
129
130 return wantarray ? ($path, $vmid, $vtype) : $path;
131 }
132
133 sub create_base {
134 my ($class, $storeid, $scfg, $volname) = @_;
135
136 die "can't create base images in drbd storage\n";
137 }
138
139 sub clone_image {
140 my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
141
142 die "can't clone images in drbd storage\n";
143 }
144
145 sub alloc_image {
146 my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
147
148 die "unsupported format '$fmt'" if $fmt ne 'raw';
149
150 die "illegal name '$name' - sould be 'vm-$vmid-*'\n"
151 if $name && $name !~ m/^vm-$vmid-/;
152
153 my $hdl = connect_drbdmanage_service();
154 my $volumes = drbd_list_volumes($hdl);
155
156 die "volume '$name' already exists\n" if $volumes->{$name};
157
158 if (!$name) {
159 for (my $i = 1; $i < 100; $i++) {
160 my $tn = "vm-$vmid-disk-$i";
161 if (!defined ($volumes->{$tn})) {
162 $name = $tn;
163 last;
164 }
165 }
166 }
167
168 die "unable to allocate an image name for VM $vmid in storage '$storeid'\n"
169 if !$name;
170
171 my ($rc, $res) = $hdl->create_resource($name, {});
172 check_drbd_rc($rc->[0]);
173
174 ($rc, $res) = $hdl->create_volume($name, $size, {});
175 check_drbd_rc($rc->[0]);
176
177 ($rc, $res) = $hdl->auto_deploy($name, $scfg->{redundancy}, 0, 0);
178 check_drbd_rc($rc->[0]);
179
180 return $name;
181 }
182
183 sub free_image {
184 my ($class, $storeid, $scfg, $volname, $isBase) = @_;
185
186 my $hdl = connect_drbdmanage_service();
187 my ($rc, $res) = $hdl->remove_resource($volname, 0);
188 check_drbd_rc($rc->[0]);
189
190 return undef;
191 }
192
193 sub list_images {
194 my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
195
196 my $vgname = $scfg->{vgname};
197
198 $cache->{drbd_volumes} = drbd_list_volumes() if !$cache->{drbd_volumes};
199
200 my $res = [];
201
202 my $dat = $cache->{drbd_volumes};
203
204 foreach my $volname (keys %$dat) {
205
206 my $owner = $dat->{$volname}->{vmid};
207
208 my $volid = "$storeid:$volname";
209
210 if ($vollist) {
211 my $found = grep { $_ eq $volid } @$vollist;
212 next if !$found;
213 } else {
214 next if defined ($vmid) && ($owner ne $vmid);
215 }
216
217 my $info = $dat->{$volname};
218 $info->{volid} = $volid;
219
220 push @$res, $info;
221 }
222
223 return $res;
224 }
225
226 sub status {
227 my ($class, $storeid, $scfg, $cache) = @_;
228
229 my ($total, $avail, $used);
230
231 eval {
232 my $hdl = connect_drbdmanage_service();
233 my ($rc, $res) = $hdl->cluster_free_query($scfg->{redundancy});
234 check_drbd_rc($rc->[0]);
235
236 $avail = $res;
237 $used = 0; # fixme
238 $total = $used + $avail;
239
240 };
241 if (my $err = $@) {
242 # ignore error,
243 # assume storage if offline
244
245 return undef;
246 }
247
248 return ($total, $avail, $used, 1);
249 }
250
251 sub activate_storage {
252 my ($class, $storeid, $scfg, $cache) = @_;
253
254 return undef;
255 }
256
257 sub deactivate_storage {
258 my ($class, $storeid, $scfg, $cache) = @_;
259
260 return undef;
261 }
262
263 sub activate_volume {
264 my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
265
266 return undef;
267 }
268
269 sub deactivate_volume {
270 my ($class, $storeid, $scfg, $volname, $cache) = @_;
271
272 return undef;
273 }
274
275 sub volume_resize {
276 my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
277
278 $size = ($size/1024/1024) . "M";
279
280 my $path = $class->path($scfg, $volname);
281
282 # fixme: howto implement this
283 die "drbd volume_resize is not implemented";
284
285 #my $cmd = ['/sbin/lvextend', '-L', $size, $path];
286 #run_command($cmd, errmsg => "error resizing volume '$path'");
287
288 return 1;
289 }
290
291 sub volume_snapshot {
292 my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
293
294 die "drbd snapshot is not implemented";
295 }
296
297 sub volume_snapshot_rollback {
298 my ($class, $scfg, $storeid, $volname, $snap) = @_;
299
300 die "drbd snapshot rollback is not implemented";
301 }
302
303 sub volume_snapshot_delete {
304 my ($class, $scfg, $storeid, $volname, $snap) = @_;
305
306 die "drbd snapshot delete is not implemented";
307 }
308
309 sub volume_has_feature {
310 my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
311
312 my $features = {
313 copy => { base => 1, current => 1},
314 };
315
316 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
317 $class->parse_volname($volname);
318
319 my $key = undef;
320 if($snapname){
321 $key = 'snap';
322 }else{
323 $key = $isBase ? 'base' : 'current';
324 }
325 return 1 if $features->{$feature}->{$key};
326
327 return undef;
328 }
329
330 1;