X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FStorage%2FDirPlugin.pm;h=39760a89c15f50a91d0c4784dcbd73a2fe782c76;hb=c2fc9fbe1d6eaa6e190e4c80248d3434cb2f4f87;hp=bc3c61f71cc38524bfce60b7b8f65ea9b362e3a9;hpb=35533c68fbcc6b57f1f3e2436360722f2382ca79;p=pve-storage.git diff --git a/PVE/Storage/DirPlugin.pm b/PVE/Storage/DirPlugin.pm index bc3c61f..39760a8 100644 --- a/PVE/Storage/DirPlugin.pm +++ b/PVE/Storage/DirPlugin.pm @@ -2,6 +2,7 @@ package PVE::Storage::DirPlugin; use strict; use warnings; +use Cwd; use File::Path; use PVE::Storage::Plugin; use PVE::JSONSchema qw(get_standard_option); @@ -16,11 +17,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 { @@ -28,6 +29,20 @@ sub properties { description => "File system path.", type => 'string', format => 'pve-storage-path', }, + mkdir => { + description => "Create the directory if it doesn't exist.", + type => 'boolean', + default => 'yes', + }, + is_mountpoint => { + description => + "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'), }; } @@ -40,19 +55,76 @@ sub options { maxfiles => { optional => 1 }, content => { optional => 1 }, format => { optional => 1 }, + mkdir => { optional => 1 }, + is_mountpoint => { optional => 1 }, + bwlimit => { optional => 1 }, }; } # Storage implementation +# + +# NOTE: should ProcFSTools::is_mounted accept an optional cache like this? +sub path_is_mounted { + my ($mountpoint, $mountdata) = @_; + + $mountpoint = Cwd::realpath($mountpoint); # symlinks + return 0 if !defined($mountpoint); # path does not exist + + $mountdata = PVE::ProcFSTools::parse_proc_mounts() if !$mountdata; + return 1 if grep { $_->[1] eq $mountpoint } @$mountdata; + 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 +} + +sub status { + my ($class, $storeid, $scfg, $cache) = @_; + + if (defined(my $mp = parse_is_mountpoint($scfg))) { + $cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts() + if !$cache->{mountdata}; + + return undef if !path_is_mounted($mp, $cache->{mountdata}); + } + + return $class->SUPER::status($storeid, $scfg, $cache); +} + sub activate_storage { my ($class, $storeid, $scfg, $cache) = @_; my $path = $scfg->{path}; - mkpath $path; + if (!defined($scfg->{mkdir}) || $scfg->{mkdir}) { + mkpath $path; + } - $class->SUPER::activate_storage($storeid, $scfg, $cache); + 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: '$mp'\n"; + } + + $class->SUPER::activate_storage($storeid, $scfg, $cache); } +sub check_config { + my ($self, $sectionId, $config, $create, $skipSchemaCheck) = @_; + my $opts = PVE::SectionConfig::check_config($self, $sectionId, $config, $create, $skipSchemaCheck); + return $opts if !$create; + if ($opts->{path} !~ m@^/[-/a-zA-Z0-9_.]+$@) { + die "illegal path for directory storage: $opts->{path}\n"; + } + return $opts; +} 1;