mirror of
https://git.proxmox.com/git/pve-guest-common
synced 2025-04-28 16:42:06 +00:00
add dir mapping section config
Adds a config file for directories by using a 'map' property string for each node mapping. example config: ``` some-dir-id map node=node1,path=/path/to/share/ map node=node2,path=/different/location/ ``` Signed-off-by: Markus Frank <m.frank@proxmox.com> [TL: adapt config path to directory.cfg like in pve-cluster] Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
5186eefdf3
commit
728afcdf6c
@ -15,6 +15,7 @@ install: PVE
|
|||||||
install -m 0644 PVE/StorageTunnel.pm ${PERL5DIR}/PVE/
|
install -m 0644 PVE/StorageTunnel.pm ${PERL5DIR}/PVE/
|
||||||
install -m 0644 PVE/Tunnel.pm ${PERL5DIR}/PVE/
|
install -m 0644 PVE/Tunnel.pm ${PERL5DIR}/PVE/
|
||||||
install -d ${PERL5DIR}/PVE/Mapping
|
install -d ${PERL5DIR}/PVE/Mapping
|
||||||
|
install -m 0644 PVE/Mapping/Dir.pm ${PERL5DIR}/PVE/Mapping/
|
||||||
install -m 0644 PVE/Mapping/PCI.pm ${PERL5DIR}/PVE/Mapping/
|
install -m 0644 PVE/Mapping/PCI.pm ${PERL5DIR}/PVE/Mapping/
|
||||||
install -m 0644 PVE/Mapping/USB.pm ${PERL5DIR}/PVE/Mapping/
|
install -m 0644 PVE/Mapping/USB.pm ${PERL5DIR}/PVE/Mapping/
|
||||||
install -d ${PERL5DIR}/PVE/VZDump
|
install -d ${PERL5DIR}/PVE/VZDump
|
||||||
|
198
src/PVE/Mapping/Dir.pm
Normal file
198
src/PVE/Mapping/Dir.pm
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
package PVE::Mapping::Dir;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_lock_file cfs_write_file);
|
||||||
|
use PVE::INotify;
|
||||||
|
use PVE::JSONSchema qw(get_standard_option parse_property_string);
|
||||||
|
use PVE::SectionConfig;
|
||||||
|
|
||||||
|
use base qw(PVE::SectionConfig);
|
||||||
|
|
||||||
|
my $FILENAME = 'mapping/directory.cfg';
|
||||||
|
|
||||||
|
cfs_register_file($FILENAME,
|
||||||
|
sub { __PACKAGE__->parse_config(@_); },
|
||||||
|
sub { __PACKAGE__->write_config(@_); });
|
||||||
|
|
||||||
|
|
||||||
|
# so we don't have to repeat the type every time
|
||||||
|
sub parse_section_header {
|
||||||
|
my ($class, $line) = @_;
|
||||||
|
|
||||||
|
if ($line =~ m/^(\S+)\s*$/) {
|
||||||
|
my $id = $1;
|
||||||
|
my $errmsg = undef; # set if you want to skip whole section
|
||||||
|
eval { PVE::JSONSchema::pve_verify_configid($id) };
|
||||||
|
$errmsg = $@ if $@;
|
||||||
|
my $config = {}; # to return additional attributes
|
||||||
|
return ('dir', $id, $errmsg, $config);
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub format_section_header {
|
||||||
|
my ($class, $type, $sectionId, $scfg, $done_hash) = @_;
|
||||||
|
|
||||||
|
return "$sectionId\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub type {
|
||||||
|
return 'dir';
|
||||||
|
}
|
||||||
|
|
||||||
|
# temporary path format that also disallows commas and equal signs
|
||||||
|
# TODO: Remove this when property_string supports quotation of properties
|
||||||
|
PVE::JSONSchema::register_format('pve-storage-path-in-property-string', \&pve_verify_path);
|
||||||
|
sub pve_verify_path {
|
||||||
|
my ($path, $noerr) = @_;
|
||||||
|
|
||||||
|
if ($path !~ m|^/[^;,=\(\)]+|) {
|
||||||
|
return undef if $noerr;
|
||||||
|
die "Value does not look like a valid absolute path."
|
||||||
|
." These symbols are currently not allowed in path: ;,=()\n";
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $map_fmt = {
|
||||||
|
node => get_standard_option('pve-node'),
|
||||||
|
path => {
|
||||||
|
description => "Absolute directory path that should be shared with the guest.",
|
||||||
|
type => 'string',
|
||||||
|
format => 'pve-storage-path-in-property-string',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
my $defaultData = {
|
||||||
|
propertyList => {
|
||||||
|
id => {
|
||||||
|
type => 'string',
|
||||||
|
description => "The ID of the directory mapping",
|
||||||
|
format => 'pve-configid',
|
||||||
|
},
|
||||||
|
description => {
|
||||||
|
type => 'string',
|
||||||
|
description => "Description of the directory mapping",
|
||||||
|
optional => 1,
|
||||||
|
maxLength => 4096,
|
||||||
|
},
|
||||||
|
map => {
|
||||||
|
type => 'array',
|
||||||
|
description => 'A list of maps for the cluster nodes.',
|
||||||
|
optional => 1,
|
||||||
|
items => {
|
||||||
|
type => 'string',
|
||||||
|
format => $map_fmt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
sub private {
|
||||||
|
return $defaultData;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub options {
|
||||||
|
return {
|
||||||
|
description => { optional => 1 },
|
||||||
|
map => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub assert_valid {
|
||||||
|
my ($dir_cfg) = @_;
|
||||||
|
|
||||||
|
my $path = $dir_cfg->{path};
|
||||||
|
|
||||||
|
pve_verify_path($path);
|
||||||
|
|
||||||
|
if (! -e $path) {
|
||||||
|
die "Path $path does not exist\n";
|
||||||
|
} elsif (! -d $path) {
|
||||||
|
die "Path $path exists, but is not a directory\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
sub assert_valid_map_list {
|
||||||
|
my ($map_list) = @_;
|
||||||
|
|
||||||
|
my $nodename = PVE::INotify::nodename();
|
||||||
|
|
||||||
|
my %count;
|
||||||
|
for my $map (@$map_list) {
|
||||||
|
my $entry = parse_property_string($map_fmt, $map);
|
||||||
|
if ($entry->{node} eq $nodename) {
|
||||||
|
assert_valid($entry);
|
||||||
|
}
|
||||||
|
$count{$entry->{node}}++;
|
||||||
|
}
|
||||||
|
for my $node (keys %count) {
|
||||||
|
if ($count{$node} > 1) {
|
||||||
|
die "Node '$node' is specified $count{$node} times.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub config {
|
||||||
|
return cfs_read_file($FILENAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub lock_dir_config {
|
||||||
|
my ($code, $errmsg) = @_;
|
||||||
|
|
||||||
|
cfs_lock_file($FILENAME, undef, $code);
|
||||||
|
if (my $err = $@) {
|
||||||
|
$errmsg ? die "$errmsg: $err" : die $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub write_dir_config {
|
||||||
|
my ($cfg) = @_;
|
||||||
|
|
||||||
|
cfs_write_file($FILENAME, $cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub find_on_current_node {
|
||||||
|
my ($id) = @_;
|
||||||
|
|
||||||
|
my $cfg = config();
|
||||||
|
my $node = PVE::INotify::nodename();
|
||||||
|
|
||||||
|
my $node_mapping = get_node_mapping($cfg, $id, $node);
|
||||||
|
if (!$node_mapping) {
|
||||||
|
die "Directory ID $id does not exist.\n";
|
||||||
|
}
|
||||||
|
if (@{$node_mapping} > 1) {
|
||||||
|
die "More than than one directory mapping for node $node.\n";
|
||||||
|
} elsif (@{$node_mapping} == 0) {
|
||||||
|
die "No directory mapping for node $node.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $node_mapping->[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_node_mapping {
|
||||||
|
my ($cfg, $id, $nodename) = @_;
|
||||||
|
|
||||||
|
return undef if !defined($cfg->{ids}->{$id});
|
||||||
|
|
||||||
|
my $res = [];
|
||||||
|
my $mapping_list = $cfg->{ids}->{$id}->{map};
|
||||||
|
for my $map (@{$mapping_list}) {
|
||||||
|
my $entry = eval { parse_property_string($map_fmt, $map) };
|
||||||
|
warn $@ if $@;
|
||||||
|
if ($entry && $entry->{node} eq $nodename) {
|
||||||
|
push $res->@*, $entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
PVE::Mapping::Dir->register();
|
||||||
|
PVE::Mapping::Dir->init();
|
||||||
|
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user