]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/DirPlugin.pm
fix #3803: ZFSPoolPlugin: zfs_request: increase minimum timeout in worker
[pve-storage.git] / PVE / Storage / DirPlugin.pm
index 39f3b30e103c6e23cdc1fa4bc58d135d02c81692..1baad63aa8550032d738f6300ef4f5b8b5d2e150 100644 (file)
@@ -2,8 +2,12 @@ package PVE::Storage::DirPlugin;
 
 use strict;
 use warnings;
+
 use Cwd;
 use File::Path;
+use IO::File;
+use POSIX;
+
 use PVE::Storage::Plugin;
 use PVE::JSONSchema qw(get_standard_option);
 
@@ -17,11 +21,11 @@ sub type {
 
 sub plugindata {
     return {
-       content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, none => 1 },
+       content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1, snippets => 1, none => 1 },
                     { images => 1,  rootdir => 1 }],
        format => [ { raw => 1, qcow2 => 1, vmdk => 1, subvol => 1 } , 'raw' ],
     };
-}   
+}
 
 sub properties {
     return {
@@ -36,25 +40,31 @@ sub properties {
        },
        is_mountpoint => {
            description =>
-               "Assume the directory is an externally managed mountpoint. " .
-               "If nothing is mounted the storage will be considered offline.",
-           type => 'boolean',
+               "Assume the given path is an externally managed mountpoint " .
+               "and consider the storage offline if it is not mounted. ".
+               "Using a boolean (yes/no) value serves as a shortcut to using the target path in this field.",
+           type => 'string',
            default => 'no',
        },
+       bwlimit => get_standard_option('bwlimit'),
     };
 }
 
 sub options {
     return {
        path => { fixed => 1 },
-        nodes => { optional => 1 },
+       nodes => { optional => 1 },
        shared => { optional => 1 },
        disable => { optional => 1 },
-        maxfiles => { optional => 1 },
+       maxfiles => { optional => 1 },
+       'prune-backups' => { optional => 1 },
+       'max-protected-backups' => { optional => 1 },
        content => { optional => 1 },
        format => { optional => 1 },
        mkdir => { optional => 1 },
        is_mountpoint => { optional => 1 },
+       bwlimit => { optional => 1 },
+       preallocation => { optional => 1 },
    };
 }
 
@@ -73,15 +83,109 @@ sub path_is_mounted {
     return undef;
 }
 
+sub parse_is_mountpoint {
+    my ($scfg) = @_;
+    my $is_mp = $scfg->{is_mountpoint};
+    return undef if !defined $is_mp;
+    if (defined(my $bool = PVE::JSONSchema::parse_boolean($is_mp))) {
+       return $bool ? $scfg->{path} : undef;
+    }
+    return $is_mp; # contains a path
+}
+
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use get_volume_attribute instead.
+sub get_volume_notes {
+    my ($class, $scfg, $storeid, $volname, $timeout) = @_;
+
+    my ($vtype) = $class->parse_volname($volname);
+    return if $vtype ne 'backup';
+
+    my $path = $class->filesystem_path($scfg, $volname);
+    $path .= $class->SUPER::NOTES_EXT;
+
+    return PVE::Tools::file_get_contents($path) if -f $path;
+
+    return '';
+}
+
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use update_volume_attribute instead.
+sub update_volume_notes {
+    my ($class, $scfg, $storeid, $volname, $notes, $timeout) = @_;
+
+    my ($vtype) = $class->parse_volname($volname);
+    die "only backups can have notes\n" if $vtype ne 'backup';
+
+    my $path = $class->filesystem_path($scfg, $volname);
+    $path .= $class->SUPER::NOTES_EXT;
+
+    if (defined($notes) && $notes ne '') {
+       PVE::Tools::file_set_contents($path, $notes);
+    } else {
+       unlink $path or $! == ENOENT or die "could not delete notes - $!\n";
+    }
+    return;
+}
+
+sub get_volume_attribute {
+    my ($class, $scfg, $storeid, $volname, $attribute) = @_;
+
+    if ($attribute eq 'notes') {
+       return $class->get_volume_notes($scfg, $storeid, $volname);
+    }
+
+    my ($vtype) = $class->parse_volname($volname);
+    return if $vtype ne 'backup';
+
+    if ($attribute eq 'protected') {
+       my $path = $class->filesystem_path($scfg, $volname);
+       return -e PVE::Storage::protection_file_path($path) ? 1 : 0;
+    }
+
+    return;
+}
+
+sub update_volume_attribute {
+    my ($class, $scfg, $storeid, $volname, $attribute, $value) = @_;
+
+    if ($attribute eq 'notes') {
+       return $class->update_volume_notes($scfg, $storeid, $volname, $value);
+    }
+
+    my ($vtype) = $class->parse_volname($volname);
+    die "only backups support attribute '$attribute'\n" if $vtype ne 'backup';
+
+    if ($attribute eq 'protected') {
+       my $path = $class->filesystem_path($scfg, $volname);
+       my $protection_path = PVE::Storage::protection_file_path($path);
+
+       return if !((-e $protection_path) xor $value); # protection status already correct
+
+       if ($value) {
+           my $fh = IO::File->new($protection_path, O_CREAT, 0644)
+               or die "unable to create protection file '$protection_path' - $!\n";
+           close($fh);
+       } else {
+           unlink $protection_path or $! == ENOENT
+               or die "could not delete protection file '$protection_path' - $!\n";
+       }
+
+       return;
+    }
+
+    die "attribute '$attribute' is not supported for storage type '$scfg->{type}'\n";
+}
+
 sub status {
     my ($class, $storeid, $scfg, $cache) = @_;
 
-    $cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts()
-       if !$cache->{mountdata};
+    if (defined(my $mp = parse_is_mountpoint($scfg))) {
+       $cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts()
+           if !$cache->{mountdata};
 
-    my $path = $scfg->{path};
-
-    return undef if !path_is_mounted($path, $cache->{mountdata});
+       return undef if !path_is_mounted($mp, $cache->{mountdata});
+    }
 
     return $class->SUPER::status($storeid, $scfg, $cache);
 }
@@ -95,12 +199,13 @@ sub activate_storage {
        mkpath $path;
     }
 
-    if ($scfg->{is_mountpoint} && !path_is_mounted($path, $cache->{mountdata})) {
+    my $mp = parse_is_mountpoint($scfg);
+    if (defined($mp) && !path_is_mounted($mp, $cache->{mountdata})) {
        die "unable to activate storage '$storeid' - " .
-           "directory is expected to be a mount point but is not mounted: '$path'\n";
+           "directory is expected to be a mount point but is not mounted: '$mp'\n";
     }
 
-    $class->SUPER::activate_storage($storeid, $scfg, $cache);    
+    $class->SUPER::activate_storage($storeid, $scfg, $cache);
 }
 
 sub check_config {