From: Markus Frank <m.frank@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH manager v10 07/11] api: add resource map api endpoints for directories
Date: Tue, 14 May 2024 12:54:38 +0200 [thread overview]
Message-ID: <20240514105442.1187746-8-m.frank@proxmox.com> (raw)
In-Reply-To: <20240514105442.1187746-1-m.frank@proxmox.com>
Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
PVE/API2/Cluster/Mapping.pm | 7 +
PVE/API2/Cluster/Mapping/Dir.pm | 317 ++++++++++++++++++++++++++++++
PVE/API2/Cluster/Mapping/Makefile | 1 +
3 files changed, 325 insertions(+)
create mode 100644 PVE/API2/Cluster/Mapping/Dir.pm
diff --git a/PVE/API2/Cluster/Mapping.pm b/PVE/API2/Cluster/Mapping.pm
index 40386579..9f0dcd2b 100644
--- a/PVE/API2/Cluster/Mapping.pm
+++ b/PVE/API2/Cluster/Mapping.pm
@@ -3,11 +3,17 @@ package PVE::API2::Cluster::Mapping;
use strict;
use warnings;
+use PVE::API2::Cluster::Mapping::Dir;
use PVE::API2::Cluster::Mapping::PCI;
use PVE::API2::Cluster::Mapping::USB;
use base qw(PVE::RESTHandler);
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Cluster::Mapping::Dir",
+ path => 'dir',
+});
+
__PACKAGE__->register_method ({
subclass => "PVE::API2::Cluster::Mapping::PCI",
path => 'pci',
@@ -41,6 +47,7 @@ __PACKAGE__->register_method ({
my ($param) = @_;
my $result = [
+ { name => 'dir' },
{ name => 'pci' },
{ name => 'usb' },
];
diff --git a/PVE/API2/Cluster/Mapping/Dir.pm b/PVE/API2/Cluster/Mapping/Dir.pm
new file mode 100644
index 00000000..ddb6977d
--- /dev/null
+++ b/PVE/API2/Cluster/Mapping/Dir.pm
@@ -0,0 +1,317 @@
+package PVE::API2::Cluster::Mapping::Dir;
+
+use strict;
+use warnings;
+
+use Storable qw(dclone);
+
+use PVE::INotify;
+use PVE::JSONSchema qw(get_standard_option parse_property_string);
+use PVE::Mapping::Dir ();
+use PVE::RPCEnvironment;
+use PVE::Tools qw(extract_param);
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ # only proxy if we give the 'check-node' parameter
+ proxyto_callback => sub {
+ my ($rpcenv, $proxyto, $param) = @_;
+ return $param->{'check-node'} // 'localhost';
+ },
+ description => "List directory mapping",
+ permissions => {
+ description => "Only lists entries where you have 'Mapping.Modify', 'Mapping.Use' or".
+ " 'Mapping.Audit' permissions on '/mapping/dir/<id>'.",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ 'check-node' => get_standard_option('pve-node', {
+ description => "If given, checks the configurations on the given node for ".
+ "correctness, and adds relevant diagnostics for the directory to the response.",
+ optional => 1,
+ }),
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => {
+ id => {
+ type => 'string',
+ description => "The logical ID of the mapping."
+ },
+ map => {
+ type => 'array',
+ description => "The entries of the mapping.",
+ items => {
+ type => 'string',
+ description => "A mapping for a node.",
+ },
+ },
+ description => {
+ type => 'string',
+ description => "A description of the logical mapping.",
+ },
+ xattr => {
+ type => 'boolean',
+ description => "Enable support for extended attributes.",
+ optional => 1,
+ },
+ acl => {
+ type => 'boolean',
+ description => "Enable support for posix ACLs (implies --xattr).",
+ optional => 1,
+ },
+ checks => {
+ type => "array",
+ optional => 1,
+ description => "A list of checks, only present if 'check-node' is set.",
+ items => {
+ type => 'object',
+ properties => {
+ severity => {
+ type => "string",
+ enum => ['warning', 'error'],
+ description => "The severity of the error",
+ },
+ message => {
+ type => "string",
+ description => "The message of the error",
+ },
+ },
+ }
+ },
+ },
+ },
+ links => [ { rel => 'child', href => "{id}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+ my $check_node = $param->{'check-node'};
+ my $local_node = PVE::INotify::nodename();
+
+ die "wrong node to check - $check_node != $local_node\n"
+ if defined($check_node) && $check_node ne 'localhost' && $check_node ne $local_node;
+
+ my $cfg = PVE::Mapping::Dir::config();
+
+ my $can_see_mapping_privs = ['Mapping.Modify', 'Mapping.Use', 'Mapping.Audit'];
+
+ my $res = [];
+ for my $id (keys $cfg->{ids}->%*) {
+ next if !$rpcenv->check_any($authuser, "/mapping/dir/$id", $can_see_mapping_privs, 1);
+ next if !$cfg->{ids}->{$id};
+
+ my $entry = dclone($cfg->{ids}->{$id});
+ $entry->{id} = $id;
+ $entry->{digest} = $cfg->{digest};
+
+ if (defined($check_node)) {
+ $entry->{checks} = [];
+ if (my $mappings = PVE::Mapping::Dir::get_node_mapping($cfg, $id, $check_node)) {
+ if (!scalar($mappings->@*)) {
+ push $entry->{checks}->@*, {
+ severity => 'warning',
+ message => "No mapping for node $check_node.",
+ };
+ }
+ for my $mapping ($mappings->@*) {
+ eval { PVE::Mapping::Dir::assert_valid($mapping) };
+ if (my $err = $@) {
+ push $entry->{checks}->@*, {
+ severity => 'error',
+ message => "Invalid configuration: $err",
+ };
+ }
+ }
+ }
+ }
+
+ push @$res, $entry;
+ }
+
+ return $res;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'get',
+ protected => 1,
+ path => '{id}',
+ method => 'GET',
+ description => "Get directory mapping.",
+ permissions => {
+ check =>['or',
+ ['perm', '/mapping/dir/{id}', ['Mapping.Use']],
+ ['perm', '/mapping/dir/{id}', ['Mapping.Modify']],
+ ['perm', '/mapping/dir/{id}', ['Mapping.Audit']],
+ ],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ id => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ }
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::Mapping::Dir::config();
+ my $id = $param->{id};
+
+ my $entry = $cfg->{ids}->{$id};
+ die "mapping '$param->{id}' not found\n" if !defined($entry);
+
+ my $data = dclone($entry);
+
+ $data->{digest} = $cfg->{digest};
+
+ return $data;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ path => '',
+ method => 'POST',
+ description => "Create a new directory mapping.",
+ permissions => {
+ check => ['perm', '/mapping/dir', ['Mapping.Modify']],
+ },
+ parameters => PVE::Mapping::Dir->createSchema(1),
+ returns => {
+ type => 'null',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = extract_param($param, 'id');
+
+ my $plugin = PVE::Mapping::Dir->lookup('dir');
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ my $map_list = $opts->{map};
+ PVE::Mapping::Dir::check_duplicate($map_list);
+
+ PVE::Mapping::Dir::lock_dir_config(sub {
+ my $cfg = PVE::Mapping::Dir::config();
+
+ die "dir ID '$id' already defined\n" if defined($cfg->{ids}->{$id});
+
+ $cfg->{ids}->{$id} = $opts;
+
+ PVE::Mapping::Dir::write_dir_config($cfg);
+
+ }, "create directory mapping failed");
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ path => '{id}',
+ method => 'PUT',
+ description => "Update a directory mapping.",
+ permissions => {
+ check => ['perm', '/mapping/dir/{id}', ['Mapping.Modify']],
+ },
+ parameters => PVE::Mapping::Dir->updateSchema(),
+ returns => {
+ type => 'null',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $digest = extract_param($param, 'digest');
+ my $delete = extract_param($param, 'delete');
+ my $id = extract_param($param, 'id');
+
+ if ($delete) {
+ $delete = [ PVE::Tools::split_list($delete) ];
+ }
+
+ PVE::Mapping::Dir::lock_dir_config(sub {
+ my $cfg = PVE::Mapping::Dir::config();
+
+ PVE::Tools::assert_if_modified($cfg->{digest}, $digest) if defined($digest);
+
+ die "dir ID '$id' does not exist\n" if !defined($cfg->{ids}->{$id});
+
+ my $plugin = PVE::Mapping::Dir->lookup('dir');
+ my $opts = $plugin->check_config($id, $param, 1, 1);
+
+ my $map_list = $opts->{map};
+ PVE::Mapping::Dir::check_duplicate($map_list);
+
+ my $data = $cfg->{ids}->{$id};
+
+ my $options = $plugin->private()->{options}->{dir};
+ PVE::SectionConfig::delete_from_config($data, $options, $opts, $delete);
+
+ $data->{$_} = $opts->{$_} for keys $opts->%*;
+
+ PVE::Mapping::Dir::write_dir_config($cfg);
+
+ }, "update directory mapping failed");
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{id}',
+ method => 'DELETE',
+ description => "Remove directory mapping.",
+ permissions => {
+ check => [ 'perm', '/mapping/dir', ['Mapping.Modify']],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ id => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ }
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ my $id = $param->{id};
+
+ PVE::Mapping::Dir::lock_dir_config(sub {
+ my $cfg = PVE::Mapping::Dir::config();
+
+ if ($cfg->{ids}->{$id}) {
+ delete $cfg->{ids}->{$id};
+ }
+
+ PVE::Mapping::Dir::write_dir_config($cfg);
+
+ }, "delete dir mapping failed");
+
+ return;
+ }
+});
+
+1;
diff --git a/PVE/API2/Cluster/Mapping/Makefile b/PVE/API2/Cluster/Mapping/Makefile
index e7345ab4..5dbb3f5c 100644
--- a/PVE/API2/Cluster/Mapping/Makefile
+++ b/PVE/API2/Cluster/Mapping/Makefile
@@ -3,6 +3,7 @@ include ../../../../defines.mk
# for node independent, cluster-wide applicable, API endpoints
# ensure we do not conflict with files shipped by pve-cluster!!
PERLSOURCE= \
+ Dir.pm \
PCI.pm \
USB.pm
--
2.39.2
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2024-05-14 10:55 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-14 10:54 [pve-devel] [PATCH cluster/guest-common/docs/qemu-server/manager v10 0/11] virtiofs Markus Frank
2024-05-14 10:54 ` [pve-devel] [PATCH cluster v10 1/11] add mapping/dir.cfg for resource mapping Markus Frank
2024-05-14 10:54 ` [pve-devel] [PATCH guest-common v10 2/11] add dir mapping section config Markus Frank
2024-06-12 11:50 ` Fiona Ebner
2024-05-14 10:54 ` [pve-devel] [PATCH docs v10 3/11] add doc section for the shared filesystem virtio-fs Markus Frank
2024-06-12 11:50 ` Fiona Ebner
2024-05-14 10:54 ` [pve-devel] [PATCH qemu-server v10 4/11] add virtiofsd as runtime dependency for qemu-server Markus Frank
2024-06-12 11:50 ` Fiona Ebner
2024-05-14 10:54 ` [pve-devel] [PATCH qemu-server v10 5/11] fix #1027: virtio-fs support Markus Frank
2024-06-12 11:50 ` Fiona Ebner
2024-05-14 10:54 ` [pve-devel] [PATCH qemu-server v10 6/11] migration: check_local_resources for virtiofs Markus Frank
2024-05-14 10:54 ` Markus Frank [this message]
2024-05-14 10:54 ` [pve-devel] [PATCH manager v10 08/11] ui: add edit window for dir mappings Markus Frank
2024-05-14 10:54 ` [pve-devel] [PATCH manager v10 09/11] ui: ResourceMapTree for DIR Markus Frank
2024-05-14 10:54 ` [pve-devel] [PATCH manager v10 10/11] ui: form: add DIRMapSelector Markus Frank
2024-05-14 10:54 ` [pve-devel] [PATCH manager v10 11/11] ui: add options to add virtio-fs to qemu config Markus Frank
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240514105442.1187746-8-m.frank@proxmox.com \
--to=m.frank@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal