From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 310801FF165 for ; Thu, 22 May 2025 18:20:28 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id E9B0AA7A3; Thu, 22 May 2025 18:18:11 +0200 (CEST) From: Stefan Hanreich To: pve-devel@lists.proxmox.com Date: Thu, 22 May 2025 18:17:06 +0200 Message-Id: <20250522161731.537011-51-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250522161731.537011-1-s.hanreich@proxmox.com> References: <20250522161731.537011-1-s.hanreich@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.222 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pve-devel] [PATCH pve-network v3 17/21] api: fabrics: add fabricnode submodule X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" Provides CRUD functionality for editing nodes inside a fabric, as well as an endpoint for listing all the nodes. The URL structure is modeled after the fact that a node can only be uniquely identified by its ID as well as the ID of the fabric that contains the node. Since fabrics can be used to edit the network configuration, we require addtional Sys.Modify permissions on the node itself, since that is the permission that is currently required by other endpoints that allow modifiying the network configuration. Co-authored-by: Gabriel Goller Signed-off-by: Stefan Hanreich --- .../API2/Network/SDN/Fabrics/FabricNode.pm | 242 ++++++++++++++++++ src/PVE/API2/Network/SDN/Fabrics/Makefile | 2 +- src/PVE/API2/Network/SDN/Fabrics/Node.pm | 6 + 3 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 src/PVE/API2/Network/SDN/Fabrics/FabricNode.pm diff --git a/src/PVE/API2/Network/SDN/Fabrics/FabricNode.pm b/src/PVE/API2/Network/SDN/Fabrics/FabricNode.pm new file mode 100644 index 0000000..1374197 --- /dev/null +++ b/src/PVE/API2/Network/SDN/Fabrics/FabricNode.pm @@ -0,0 +1,242 @@ +package PVE::API2::Network::SDN::Fabrics::FabricNode; + +use strict; +use warnings; + +use PVE::JSONSchema qw(get_standard_option); +use PVE::Tools qw(extract_param); + +use PVE::Network::SDN; +use PVE::Network::SDN::Fabrics; + +use PVE::RESTHandler; +use base qw(PVE::RESTHandler); + +__PACKAGE__->register_method ({ + name => 'list_nodes_fabric', + path => '', + method => 'GET', + permissions => { + description => "Only returns nodes where you have 'Sys.Audit' or 'Sys.Modify' permissions.", + check => ['perm', '/sdn/fabrics/{fabric_id}', [ 'SDN.Audit' ]], + }, + description => "SDN Fabrics Index", + parameters => { + properties => { + running => { + type => 'boolean', + optional => 1, + description => "Display running config.", + }, + pending => { + type => 'boolean', + optional => 1, + description => "Display pending config.", + }, + fabric_id => get_standard_option('pve-sdn-fabric-id'), + }, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => PVE::Network::SDN::Fabrics::node_properties(0), + }, + links => [ { rel => 'child', href => "{node_id}" } ], + }, + code => sub { + my ($param) = @_; + + my $fabric_id = extract_param($param, 'fabric_id'); + my $pending = extract_param($param, 'pending'); + my $running = extract_param($param, 'running'); + + my $digest; + my $nodes; + + if ($pending) { + my $current_config = PVE::Network::SDN::Fabrics::config(); + my $running_config = PVE::Network::SDN::Fabrics::config(1); + + my $running_nodes = $running_config + ->list_nodes_fabric($fabric_id); + + my $current_nodes = $current_config + ->list_nodes_fabric($fabric_id); + + my $pending_nodes = PVE::Network::SDN::pending_config( + { nodes => { ids => $running_nodes }}, + { ids => $current_nodes }, + 'nodes' + ); + + $digest = $current_config->digest(); + $nodes = $pending_nodes->{ids}; + } elsif ($running) { + $nodes = PVE::Network::SDN::Fabrics::config(1) + ->list_nodes_fabric($fabric_id); + } else { + my $current_config = PVE::Network::SDN::Fabrics::config(); + + $digest = $current_config->digest(); + $nodes = $current_config->list_nodes_fabric($fabric_id); + } + + my $rpcenv = PVE::RPCEnvironment::get(); + my $authuser = $rpcenv->get_user(); + my $node_privs = ['Sys.Audit', 'Sys.Modify']; + + my @res; + for my $node_id (sort keys %$nodes) { + next if !$rpcenv->check_any($authuser, "/nodes/$node_id", $node_privs, 1); + $nodes->{$node_id}->{digest} = $digest if $digest; + push @res, $nodes->{$node_id}; + } + + return \@res; + }}); + +__PACKAGE__->register_method({ + name => 'get_node', + path => '{node_id}', + method => 'GET', + description => 'Get a node', + permissions => { + check => ['and', + ['perm', '/sdn/fabrics/{fabric_id}', [ 'SDN.Audit', 'SDN.Allocate' ], any => 1], + ['perm', '/nodes/{node_id}', [ 'Sys.Audit', 'Sys.Modify' ], any => 1], + ], + }, + parameters => { + properties => { + fabric_id => get_standard_option('pve-sdn-fabric-id'), + node_id => get_standard_option('pve-sdn-fabric-node-id'), + } + }, + returns => { + properties => PVE::Network::SDN::Fabrics::node_properties(0), + }, + code => sub { + my ($param) = @_; + + my $fabric_id = extract_param($param, 'fabric_id'); + my $node_id = extract_param($param, 'node_id'); + + my $config = PVE::Network::SDN::Fabrics::config(); + + my $node = $config->get_node($fabric_id, $node_id); + $node->{digest} = $config->digest(); + + return $node; + }, +}); + +__PACKAGE__->register_method({ + name => 'add_node', + path => '', + method => 'POST', + description => 'Add a node', + protected => 1, + permissions => { + check => ['and', + ['perm', '/sdn/fabrics/{fabric_id}', [ 'SDN.Allocate' ]], + ['perm', '/nodes/{node_id}', [ 'Sys.Modify' ]], + ], + }, + parameters => { + properties => PVE::Network::SDN::Fabrics::node_properties(0), + }, + returns => { + type => 'null', + }, + code => sub { + my ($param) = @_; + + PVE::Network::SDN::lock_sdn_config(sub { + my $config = PVE::Network::SDN::Fabrics::config(); + + my $digest = extract_param($param, 'digest'); + PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest; + + $config->add_node($param); + PVE::Network::SDN::Fabrics::write_config($config); + }, "adding node failed"); + }, +}); + +__PACKAGE__->register_method({ + name => 'update_node', + path => '{node_id}', + method => 'PUT', + description => 'Update a node', + protected => 1, + permissions => { + check => ['and', + ['perm', '/sdn/fabrics/{fabric_id}', [ 'SDN.Allocate' ]], + ['perm', '/nodes/{node_id}', [ 'Sys.Modify' ]], + ], + }, + parameters => { + properties => PVE::Network::SDN::Fabrics::node_properties(1), + }, + returns => { + type => 'null', + }, + code => sub { + my ($param) = @_; + + PVE::Network::SDN::lock_sdn_config(sub { + my $fabric_id = extract_param($param, 'fabric_id'); + my $node_id = extract_param($param, 'node_id'); + + my $config = PVE::Network::SDN::Fabrics::config(); + + my $digest = extract_param($param, 'digest'); + PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest; + + $config->update_node($fabric_id, $node_id, $param); + PVE::Network::SDN::Fabrics::write_config($config); + }, "updating node failed"); + }, +}); + +__PACKAGE__->register_method({ + name => 'delete_node', + path => '{node_id}', + method => 'DELETE', + description => 'Add a node', + protected => 1, + permissions => { + check => ['and', + ['perm', '/sdn/fabrics/{fabric_id}', [ 'SDN.Allocate' ]], + ['perm', '/nodes/{node_id}', [ 'Sys.Modify' ]], + ], + }, + parameters => { + properties => { + fabric_id => get_standard_option('pve-sdn-fabric-id'), + node_id => get_standard_option('pve-sdn-fabric-node-id'), + } + }, + returns => { + type => 'null', + }, + code => sub { + my ($param) = @_; + + PVE::Network::SDN::lock_sdn_config(sub { + my $fabric_id = extract_param($param, 'fabric_id'); + my $node_id = extract_param($param, 'node_id'); + + my $config = PVE::Network::SDN::Fabrics::config(); + + my $digest = extract_param($param, 'digest'); + PVE::Tools::assert_if_modified($config->digest(), $digest) if $digest; + + $config->delete_node($fabric_id, $node_id); + PVE::Network::SDN::Fabrics::write_config($config); + }, "deleting node failed"); + }, +}); + +1; diff --git a/src/PVE/API2/Network/SDN/Fabrics/Makefile b/src/PVE/API2/Network/SDN/Fabrics/Makefile index 169ebbe..9c4bda8 100644 --- a/src/PVE/API2/Network/SDN/Fabrics/Makefile +++ b/src/PVE/API2/Network/SDN/Fabrics/Makefile @@ -1,4 +1,4 @@ -SOURCES=Fabric.pm Node.pm +SOURCES=Fabric.pm FabricNode.pm Node.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git a/src/PVE/API2/Network/SDN/Fabrics/Node.pm b/src/PVE/API2/Network/SDN/Fabrics/Node.pm index 958d387..fafaadb 100644 --- a/src/PVE/API2/Network/SDN/Fabrics/Node.pm +++ b/src/PVE/API2/Network/SDN/Fabrics/Node.pm @@ -7,12 +7,18 @@ use PVE::Tools qw(extract_param); use PVE::Network::SDN; use PVE::Network::SDN::Fabrics; +use PVE::API2::Network::SDN::Fabrics::FabricNode; use PVE::JSONSchema qw(get_standard_option); use PVE::RESTHandler; use base qw(PVE::RESTHandler); +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Network::SDN::Fabrics::FabricNode", + path => '{fabric_id}', +}); + __PACKAGE__->register_method ({ name => 'list_nodes', path => '', -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel