[pve-devel] [PATCH manager 1/8] PVE/API2/Hardware: add Mapping.pm
Dominik Csapak
d.csapak at proxmox.com
Mon Jun 21 15:55:27 CEST 2021
adds the basic api calls to list/get/create/update/delete device
mappings
for now these api calls are only per node, so it only affects
the node specific mapping (thought consistency checks are
done for the whole config, e.g if an id exists already on another
node with a different type)
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
PVE/API2/Hardware.pm | 6 +
PVE/API2/Hardware/Makefile | 1 +
PVE/API2/Hardware/Mapping.pm | 292 +++++++++++++++++++++++++++++++++++
3 files changed, 299 insertions(+)
create mode 100644 PVE/API2/Hardware/Mapping.pm
diff --git a/PVE/API2/Hardware.pm b/PVE/API2/Hardware.pm
index f59bfbe0..ab7b5e63 100644
--- a/PVE/API2/Hardware.pm
+++ b/PVE/API2/Hardware.pm
@@ -8,6 +8,7 @@ use PVE::RESTHandler;
use PVE::API2::Hardware::PCI;
use PVE::API2::Hardware::USB;
+use PVE::API2::Hardware::Mapping;
use base qw(PVE::RESTHandler);
@@ -21,6 +22,10 @@ __PACKAGE__->register_method ({
path => 'usb',
});
+__PACKAGE__->register_method ({
+ subclass => "PVE::API2::Hardware::Mapping",
+ path => "mapping",
+});
__PACKAGE__->register_method ({
name => 'index',
@@ -50,6 +55,7 @@ __PACKAGE__->register_method ({
my $res = [
{ type => 'pci' },
{ type => 'usb' },
+ { type => 'mapping' },
];
return $res;
diff --git a/PVE/API2/Hardware/Makefile b/PVE/API2/Hardware/Makefile
index d27d2201..9f5f3231 100644
--- a/PVE/API2/Hardware/Makefile
+++ b/PVE/API2/Hardware/Makefile
@@ -3,6 +3,7 @@ include ../../../defines.mk
PERLSOURCE= \
PCI.pm \
USB.pm \
+ Mapping.pm \
all:
diff --git a/PVE/API2/Hardware/Mapping.pm b/PVE/API2/Hardware/Mapping.pm
new file mode 100644
index 00000000..0a02931f
--- /dev/null
+++ b/PVE/API2/Hardware/Mapping.pm
@@ -0,0 +1,292 @@
+package PVE::API2::Hardware::Mapping;
+
+use strict;
+use warnings;
+
+use Storable qw(dclone);
+
+use PVE::Cluster qw(cfs_lock_file);
+use PVE::HardwareMap;
+use PVE::HardwareMap::Plugin;
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::Tools qw(extract_param);
+
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method ({
+ name => 'index',
+ path => '',
+ method => 'GET',
+ description => "Hardware Mapping",
+ permissions => {
+ description => "Only lists entries where you have 'Hardware.Audit', 'Hardware.Use', 'Hardware.Configure' permissions on '/hardware/<name>'.",
+ user => 'all',
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ type => {
+ enum => PVE::HardwareMap::Plugin->lookup_types(),
+ description => "Show only devices of this type.",
+ optional => 1,
+ },
+ },
+ },
+ returns => {
+ type => 'array',
+ items => {
+ type => "object",
+ properties => { name => { type => 'string'} },
+ },
+ links => [ { rel => 'child', href => "{name}" } ],
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
+
+ my $cfg = PVE::HardwareMap::config();
+
+ my $res = [];
+
+ my $privs = ['Hardware.Audit', 'Hardware.Use', 'Hardware.Configure'];
+
+ for my $id (keys %{$cfg->{ids}}) {
+ my $entry = $cfg->{ids}->{$id};
+ next if $entry->{node} ne $param->{node};
+ next if $param->{type} && $entry->{type} ne $param->{type};
+ next if !$rpcenv->check_hw_perm($authuser, $entry->{name}, $privs, 1);
+
+ my $type = $entry->{type};
+ my $plugin = PVE::HardwareMap::Plugin->lookup($type);
+ eval {
+ $plugin->assert_device_valid($entry);
+ };
+ if (my $err = $@) {
+ $entry->{valid} = 0;
+ $entry->{errmsg} = "$err";
+ } else {
+ $entry->{valid} = 1;
+ }
+
+ push @$res, $entry;
+ }
+
+ return $res;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'get',
+ protected => 1,
+ path => '{name}',
+ method => 'GET',
+ description => "Remove Hardware Mapping.",
+ permissions => {
+ check => [ 'and',
+ ['perm', '/node/{node}', ['Sys.Modify']],
+ ['perm', '/hardware/{name}', ['Hardware.Configure']],
+ ],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ name => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ node => get_standard_option('pve-node'),
+ }
+ },
+ returns => { type => 'object' },
+ code => sub {
+ my ($param) = @_;
+
+ my $cfg = PVE::HardwareMap::config();
+
+ my $id = "$param->{node}:$param->{name}";
+
+ "mapping '$param->{name}' not found on '$param->{node}'\n"
+ if !defined($cfg->{ids}->{$id});
+
+ my $data = dclone($cfg->{ids}->{$id});
+
+ $data->{digest} = $cfg->{digest};
+
+ return $data;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'create',
+ protected => 1,
+ proxyto => 'node',
+ path => '',
+ method => 'POST',
+ description => "Create a new hardware mapping.",
+ permissions => {
+ check => [ 'and',
+ ['perm', '/node/{node}', ['Sys.Modify']],
+ ['perm', '/hardware/{name}', ['Hardware.Configure']],
+ ],
+ },
+ parameters => PVE::HardwareMap::Plugin->createSchema(),
+ returns => {
+ type => 'null',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $type = extract_param($param, 'type');
+ my $name = $param->{name};
+ my $node = $param->{node};
+
+ my $mapid = "$node:$name";
+
+ my $plugin = PVE::HardwareMap::Plugin->lookup($type);
+ my $opts = $plugin->check_config($mapid, $param, 1, 1);
+
+ $plugin->assert_device_valid($opts);
+
+ PVE::HardwareMap::lock_config(sub {
+ my $cfg = PVE::HardwareMap::config();
+
+ if ($cfg->{ids}->{$mapid}) {
+ die "mapping '$mapid' already defined\n";
+ }
+
+ for my $id (keys %{$cfg->{ids}}) {
+ next if $id !~ m/:${name}$/;
+ my $entry = $cfg->{ids}->{$id};
+
+ die "'$name' already defined as type '$entry->{type}'\n"
+ if $entry->{type} ne $type;
+ }
+
+ $cfg->{ids}->{$mapid} = $opts;
+
+ PVE::HardwareMap::write_config($cfg);
+
+ }, "create hardware mapping failed");
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'update',
+ protected => 1,
+ proxyto => 'node',
+ path => '{name}',
+ method => 'PUT',
+ description => "Update a hardware mapping.",
+ permissions => {
+ check => [ 'and',
+ ['perm', '/node/{node}', ['Sys.Modify']],
+ ['perm', '/hardware/{name}', ['Hardware.Configure']],
+ ],
+ },
+ parameters => PVE::HardwareMap::Plugin->updateSchema(),
+ returns => {
+ type => 'null',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $digest = extract_param($param, 'digest');
+ my $delete = extract_param($param, 'delete');
+ my $name = extract_param($param, 'name');
+ my $node = extract_param($param, 'node');
+ if ($delete) {
+ $delete = [ PVE::Tools::split_list($delete) ];
+ }
+
+ my $mapid = "$node:$name";
+
+
+ PVE::HardwareMap::lock_config(sub {
+ my $cfg = PVE::HardwareMap::config();
+
+ PVE::SectionConfig::assert_if_modified($cfg, $digest);
+
+ my $data = $cfg->{ids}->{$mapid};
+ die "no mapping '$mapid'\n" if !$data;
+
+ my $plugin = PVE::HardwareMap::Plugin->lookup($data->{type});
+ my $opts = $plugin->check_config($mapid, $param, 0, 1);
+
+ $plugin->assert_device_valid($opts);
+
+ for my $k (keys %$opts) {
+ $data->{$k} = $opts->{$k};
+ }
+
+ if ($delete) {
+ my $options = $plugin->private()->{options}->{$data->{type}};
+ for my $k (@$delete) {
+ my $d = $options->{$k} || die "no such option '$k'\n";
+ die "unable to delete required option '$k'\n" if !$d->{optional};
+ die "unable to delete fixed option '$k'\n" if $d->{fixed};
+ die "cannot set and delete property '$k' at the same time!\n"
+ if defined($opts->{$k});
+
+ delete $data->{$k};
+ }
+ }
+
+ PVE::HardwareMap::write_config($cfg);
+
+ }, "update hardware mapping failed");
+
+ return;
+ },
+});
+
+__PACKAGE__->register_method ({
+ name => 'delete',
+ protected => 1,
+ path => '{name}',
+ method => 'DELETE',
+ description => "Remove Hardware Mapping.",
+ permissions => {
+ check => [ 'and',
+ ['perm', '/node/{node}', ['Sys.Modify']],
+ ['perm', '/hardware/{name}', ['Hardware.Configure']],
+ ],
+ },
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ name => {
+ type => 'string',
+ format => 'pve-configid',
+ },
+ }
+ },
+ returns => { type => 'null' },
+ code => sub {
+ my ($param) = @_;
+
+ PVE::HardwareMap::lock_config(sub {
+ my $cfg = PVE::HardwareMap::config();
+
+ my $id = "$param->{node}:$param->{name}";
+
+ my $plugin_cfg = $cfg->{ids}->{$id};
+
+ my $plugin = PVE::HardwareMap::Plugin->lookup($plugin_cfg->{type});
+
+ delete $cfg->{ids}->{$id};
+
+ PVE::HardwareMap::write_config($cfg);
+
+ }, "delete hardware mapping failed");
+
+ return;
+ }});
+
+1;
--
2.20.1
More information about the pve-devel
mailing list