1 package PVE
::Storage
::DRBDPlugin
;
9 use PVE
::Tools
qw(run_command trim);
11 use PVE
::Storage
::Plugin
;
12 use PVE
::JSONSchema
qw(get_standard_option);
14 use base
qw(PVE::Storage::Plugin);
18 my $default_redundancy = 2;
26 content
=> [ {images
=> 1}, { images
=> 1 }],
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.",
37 default => $default_redundancy,
44 redundancy
=> { optional
=> 1 },
45 nodes
=> { optional
=> 1 },
46 disable
=> { optional
=> 1 },
55 return $scfg->{redundancy
} || $default_redundancy;
58 sub connect_drbdmanage_service
{
60 my $bus = Net
::DBus-
>system;
62 my $service = $bus->get_service("org.drbd.drbdmanaged");
64 my $hdl = $service->get_object("/interface", "org.drbd.drbdmanaged");
72 die "got undefined drbd result\n" if !$rc;
74 foreach my $res (@$rc) {
75 my ($code, $msg, $details) = @$res;
77 return undef if $code == 0;
79 $msg = "drbd error: got error code $code" if !$msg;
82 # fixme: add error details?
83 #print Dumper($details);
85 die "drbd error: $msg\n";
91 sub drbd_list_volumes
{
94 $hdl = connect_drbdmanage_service
() if !$hdl;
96 my ($rc, $res) = $hdl->list_volumes([], 0, {}, []);
101 foreach my $entry (@$res) {
102 my ($volname, $properties, $vol_list) = @$entry;
104 next if $volname !~ m/^vm-(\d+)-/;
107 # fixme: we always use volid 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;
116 $volumes->{$volname} = { format
=> 'raw', size
=> $size,
123 # Storage implementation
126 my ($class, $volname) = @_;
128 if ($volname =~ m/^(vm-(\d+)-[a-z][a-z0-9\-\_\.]*[a-z0-9]+)$/) {
129 return ('images', $1, $2);
132 die "unable to parse lvm volume name '$volname'\n";
135 sub filesystem_path
{
136 my ($class, $scfg, $volname) = @_;
138 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
140 # fixme: always use volid 0?
141 my $path = "/dev/drbd/by-res/$volname/0";
143 return wantarray ?
($path, $vmid, $vtype) : $path;
147 my ($class, $storeid, $scfg, $volname) = @_;
149 die "can't create base images in drbd storage\n";
153 my ($class, $scfg, $storeid, $volname, $vmid, $snap) = @_;
155 die "can't clone images in drbd storage\n";
159 my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
161 die "unsupported format '$fmt'" if $fmt ne 'raw';
163 die "illegal name '$name' - should be 'vm-$vmid-*'\n"
164 if defined($name) && $name !~ m/^vm-$vmid-/;
166 my $hdl = connect_drbdmanage_service
();
167 my $volumes = drbd_list_volumes
($hdl);
169 die "volume '$name' already exists\n" if defined($name) && $volumes->{$name};
171 if (!defined($name)) {
172 for (my $i = 1; $i < 100; $i++) {
173 my $tn = "vm-$vmid-disk-$i";
174 if (!defined ($volumes->{$tn})) {
181 die "unable to allocate an image name for VM $vmid in storage '$storeid'\n"
184 my ($rc, $res) = $hdl->create_resource($name, {});
187 ($rc, $res) = $hdl->create_volume($name, $size, {});
190 ($rc, $res) = $hdl->set_drbdsetup_props(
192 target
=> "resource",
195 'allow-two-primaries' => 'yes',
199 my $redundancy = get_redundancy
($scfg);;
201 ($rc, $res) = $hdl->auto_deploy($name, $redundancy, 0, 0);
208 my ($class, $storeid, $scfg, $volname, $isBase) = @_;
210 my $hdl = connect_drbdmanage_service
();
211 my ($rc, $res) = $hdl->remove_resource($volname, 0);
218 my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
220 my $vgname = $scfg->{vgname
};
222 $cache->{drbd_volumes
} = drbd_list_volumes
() if !$cache->{drbd_volumes
};
226 my $dat = $cache->{drbd_volumes
};
228 foreach my $volname (keys %$dat) {
230 my $owner = $dat->{$volname}->{vmid
};
232 my $volid = "$storeid:$volname";
235 my $found = grep { $_ eq $volid } @$vollist;
238 next if defined ($vmid) && ($owner ne $vmid);
241 my $info = $dat->{$volname};
242 $info->{volid
} = $volid;
251 my ($class, $storeid, $scfg, $cache) = @_;
253 my ($total, $avail, $used);
256 my $hdl = connect_drbdmanage_service
();
257 my $redundancy = get_redundancy
($scfg);;
258 my ($rc, $res) = $hdl->cluster_free_query($redundancy);
263 $total = $used + $avail;
268 # assume storage if offline
273 return ($total, $avail, $used, 1);
276 sub activate_storage
{
277 my ($class, $storeid, $scfg, $cache) = @_;
282 sub deactivate_storage
{
283 my ($class, $storeid, $scfg, $cache) = @_;
288 sub activate_volume
{
289 my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
291 my $path = $class->path($scfg, $volname);
293 my $hdl = connect_drbdmanage_service
();
294 my $nodename = PVE
::INotify
::nodename
();
295 my ($rc, $res) = $hdl->list_assignments([$nodename], [], 0, {}, []);
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
305 # create diskless assignment
306 ($rc, $res) = $hdl->assign($nodename, $volname, { diskless
=> 'true' });
309 # wait until device is acessitble
310 my $print_warning = 1;
311 my $max_wait_time = 20;
312 for (my $i = 0;; $i++) {
315 last if system("dd if=$path of=/dev/null bs=512 count=1 >/dev/null 2>&1") == 0;
317 # correct, but does not work?
318 ($rc, $res) = $hdl->list_assignments([$nodename], [$volname], 0, { "cstate:deploy" => "true" }, []);
320 my $len = scalar(@$res);
323 die "aborting wait - device '$path' still not readable\n" if $i > $max_wait_time;
324 print "waiting for device '$path' to become ready...\n" if $print_warning;
332 sub deactivate_volume
{
333 my ($class, $storeid, $scfg, $volname, $cache) = @_;
335 # fixme: remove diskless assdignments
341 my ($class, $scfg, $storeid, $volname, $size, $running) = @_;
343 $size = ($size/1024/1024) . "M";
345 my $path = $class->path($scfg, $volname);
347 # fixme: howto implement this
348 die "drbd volume_resize is not implemented";
350 #my $cmd = ['/sbin/lvextend', '-L', $size, $path];
351 #run_command($cmd, errmsg => "error resizing volume '$path'");
356 sub volume_snapshot
{
357 my ($class, $scfg, $storeid, $volname, $snap, $running) = @_;
359 die "drbd snapshot is not implemented";
362 sub volume_snapshot_rollback
{
363 my ($class, $scfg, $storeid, $volname, $snap) = @_;
365 die "drbd snapshot rollback is not implemented";
368 sub volume_snapshot_delete
{
369 my ($class, $scfg, $storeid, $volname, $snap) = @_;
371 die "drbd snapshot delete is not implemented";
374 sub volume_has_feature
{
375 my ($class, $scfg, $feature, $storeid, $volname, $snapname, $running) = @_;
378 copy
=> { base
=> 1, current
=> 1},
381 my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) =
382 $class->parse_volname($volname);
388 $key = $isBase ?
'base' : 'current';
390 return 1 if $features->{$feature}->{$key};