[pve-devel] [PATCH pve-network v4 14/21] api: fabrics: add root-level module
Gabriel Goller
g.goller at proxmox.com
Wed Jul 2 16:50:34 CEST 2025
From: Stefan Hanreich <s.hanreich at proxmox.com>
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 <g.goller at proxmox.com>
Signed-off-by: Stefan Hanreich <s.hanreich at proxmox.com>
---
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/<fabric>', only list nodes where you have 'Sys.Audit' or 'Sys.Modify' on /nodes/<node_id>",
+ 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);
} else {
return $value;
}
--
2.39.5
More information about the pve-devel
mailing list