From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 129B31FF17A for ; Fri, 4 Jul 2025 16:31:51 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 81DEF3A51E; Fri, 4 Jul 2025 16:32:31 +0200 (CEST) Message-ID: <0f718572-4cbd-4f5e-b4db-b948e4c90859@proxmox.com> Date: Fri, 4 Jul 2025 16:32:27 +0200 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Gabriel Goller , pve-devel@lists.proxmox.com References: <20250702145101.894299-1-g.goller@proxmox.com> <20250702145101.894299-50-g.goller@proxmox.com> Content-Language: en-US From: Stefan Hanreich In-Reply-To: <20250702145101.894299-50-g.goller@proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL 0.527 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 POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] [PATCH pve-network v4 14/21] api: fabrics: add root-level module 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" On 7/2/25 16:50, Gabriel Goller wrote: > From: Stefan Hanreich > > There is one endpoint (/all) at the top-level that fetches both types > of fabric entities (fabrics & nodes) and lists them separately. This > is used for the main view, in order to avoid having to do two API > calls. It works analogous to the existing root-level SDN API calls > with the running / pending parameters. > > Also, since the interfaces key is used in the node sections, we need > to add it to the function encoding the values so they are compared and > returned from the API properly, when the pending parameter is set. > > Co-authored-by: Gabriel Goller > Signed-off-by: Stefan Hanreich > --- > src/PVE/API2/Network/SDN.pm | 7 ++ > src/PVE/API2/Network/SDN/Fabrics.pm | 165 ++++++++++++++++++++++++++++ > src/PVE/API2/Network/SDN/Makefile | 3 +- > src/PVE/Network/SDN.pm | 10 +- > 4 files changed, 177 insertions(+), 8 deletions(-) > create mode 100644 src/PVE/API2/Network/SDN/Fabrics.pm > > diff --git a/src/PVE/API2/Network/SDN.pm b/src/PVE/API2/Network/SDN.pm > index 0824410f43cb..6645f28b5de1 100644 > --- a/src/PVE/API2/Network/SDN.pm > +++ b/src/PVE/API2/Network/SDN.pm > @@ -17,6 +17,7 @@ use PVE::API2::Network::SDN::Vnets; > use PVE::API2::Network::SDN::Zones; > use PVE::API2::Network::SDN::Ipams; > use PVE::API2::Network::SDN::Dns; > +use PVE::API2::Network::SDN::Fabrics; > > use base qw(PVE::RESTHandler); > > @@ -45,6 +46,11 @@ __PACKAGE__->register_method({ > path => 'dns', > }); > > +__PACKAGE__->register_method({ > + subclass => "PVE::API2::Network::SDN::Fabrics", > + path => 'fabrics', > +}); > + > __PACKAGE__->register_method({ > name => 'index', > path => '', > @@ -76,6 +82,7 @@ __PACKAGE__->register_method({ > { id => 'controllers' }, > { id => 'ipams' }, > { id => 'dns' }, > + { id => 'fabrics' }, > ]; > > return $res; > diff --git a/src/PVE/API2/Network/SDN/Fabrics.pm b/src/PVE/API2/Network/SDN/Fabrics.pm > new file mode 100644 > index 000000000000..a4a972d65cc2 > --- /dev/null > +++ b/src/PVE/API2/Network/SDN/Fabrics.pm > @@ -0,0 +1,165 @@ > +package PVE::API2::Network::SDN::Fabrics; > + > +use strict; > +use warnings; > + > +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 => 'index', > + path => '', > + method => 'GET', > + permissions => { > + check => ['perm', '/sdn/fabrics', ['SDN.Audit']], > + }, > + description => "SDN Fabrics Index", > + parameters => { > + properties => {}, > + }, > + returns => { > + type => 'array', > + items => { > + type => "object", > + properties => { > + subdir => { type => 'string' }, > + }, > + }, > + links => [{ rel => 'child', href => "{subdir}" }], > + }, > + code => sub { > + my ($param) = @_; > + > + my $res = [ > + { subdir => 'all' }, > + ]; > + > + return $res; > + }, > +}); > + > +__PACKAGE__->register_method({ > + name => 'list_all', > + path => 'all', > + method => 'GET', > + permissions => { > + description => > + "Only list fabrics where you have 'SDN.Audit' or 'SDN.Allocate' permissions on\n" > + . "'/sdn/fabrics/', only list nodes where you have 'Sys.Audit' or 'Sys.Modify' on /nodes/", > + user => 'all', > + }, > + description => "SDN Fabrics Index", > + parameters => { > + properties => { > + running => { > + type => 'boolean', > + optional => 1, > + description => "Display running config.", > + }, > + pending => { > + type => 'boolean', > + optional => 1, > + description => "Display pending config.", > + }, > + }, > + }, > + returns => { > + type => 'object', > + properties => { > + fabrics => { > + type => 'array', > + items => { > + type => "object", > + properties => PVE::Network::SDN::Fabrics::fabric_properties(0), > + }, > + }, > + nodes => { > + type => 'array', > + items => { > + type => "object", > + properties => PVE::Network::SDN::Fabrics::node_properties(0), > + }, > + }, > + }, > + }, > + code => sub { > + my ($param) = @_; > + > + my $pending = extract_param($param, 'pending'); > + my $running = extract_param($param, 'running'); > + > + my $digest; > + my $fabrics; > + my $nodes; > + > + if ($pending) { > + my $current_config = PVE::Network::SDN::Fabrics::config(); > + my $running_config = PVE::Network::SDN::Fabrics::config(1); > + > + my ($running_fabrics, $running_nodes) = $running_config->list_all(); > + > + my ($current_fabrics, $current_nodes) = $current_config->list_all(); > + > + my $pending_fabrics = PVE::Network::SDN::pending_config( > + { fabrics => { ids => $running_fabrics } }, > + { ids => $current_fabrics }, > + 'fabrics', > + ); > + > + my $pending_nodes = PVE::Network::SDN::pending_config( > + { nodes => { ids => $running_nodes } }, > + { ids => $current_nodes }, > + 'nodes', > + ); > + > + $digest = $current_config->digest(); > + $fabrics = $pending_fabrics->{ids}; > + $nodes = $pending_nodes->{ids}; > + } elsif ($running) { > + ($fabrics, $nodes) = PVE::Network::SDN::Fabrics::config(1)->list_all(); > + } else { > + my $current_config = PVE::Network::SDN::Fabrics::config(); > + > + ($fabrics, $nodes) = $current_config->list_all(); > + $digest = $current_config->digest(); > + } > + > + my $rpcenv = PVE::RPCEnvironment::get(); > + my $authuser = $rpcenv->get_user(); > + my $fabric_privs = ['SDN.Audit', 'SDN.Allocate']; > + my $node_privs = ['Sys.Audit', 'Sys.Modify']; > + > + my @res_fabrics; > + for my $id (keys %$fabrics) { > + next if !$rpcenv->check_any($authuser, "/sdn/fabrics/$id", $fabric_privs, 1); > + > + $fabrics->{$id}->{digest} = $digest if $digest; > + push @res_fabrics, $fabrics->{$id}; > + } > + > + my @res_nodes; > + for my $node_id (keys %$nodes) { > + my $node = $nodes->{$node_id}; > + my $fabric_id = $node->{fabric_id} // $node->{pending}->{fabric_id}; > + > + next if !$rpcenv->check_any($authuser, "/sdn/fabrics/$fabric_id", $fabric_privs, 1); > + next if !$rpcenv->check_any($authuser, "/nodes/$node_id", $node_privs, 1); > + > + $node->{digest} = $digest if $digest; > + > + push @res_nodes, $node; > + } > + > + return { > + fabrics => \@res_fabrics, > + nodes => \@res_nodes, > + }; > + }, > +}); > + > +1; > diff --git a/src/PVE/API2/Network/SDN/Makefile b/src/PVE/API2/Network/SDN/Makefile > index abd1bfae020e..08bec7535530 100644 > --- a/src/PVE/API2/Network/SDN/Makefile > +++ b/src/PVE/API2/Network/SDN/Makefile > @@ -1,4 +1,4 @@ > -SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm Dns.pm Ips.pm > +SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm Dns.pm Ips.pm Fabrics.pm > > > PERL5DIR=${DESTDIR}/usr/share/perl5 > @@ -7,4 +7,5 @@ PERL5DIR=${DESTDIR}/usr/share/perl5 > install: > for i in ${SOURCES}; do install -D -m 0644 $$i ${PERL5DIR}/PVE/API2/Network/SDN/$$i; done > make -C Zones install > + make -C Fabrics install > > diff --git a/src/PVE/Network/SDN.pm b/src/PVE/Network/SDN.pm > index 1a0bc769a252..c6324f1ac5d2 100644 > --- a/src/PVE/Network/SDN.pm > +++ b/src/PVE/Network/SDN.pm > @@ -414,15 +414,11 @@ sub encode_value { > $type, $key, $value, > ) = @_; > > - if ($key eq 'nodes' || $key eq 'exitnodes' || $key eq 'dhcp-range') { > + if ($key eq 'nodes' || $key eq 'exitnodes' || $key eq 'dhcp-range' || $key eq 'interfaces') { > if (ref($value) eq 'HASH') { > - return join( > - ',', sort keys(%$value), > - ); > + return join(',', sort keys(%$value)); > } elsif (ref($value) eq 'ARRAY') { > - return join( > - ',', sort @$value, > - ); > + return join(',', sort @$value); some additional formatting changes here as well? > } else { > return $value; > } _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel