summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Hanreich <s.hanreich@proxmox.com>2025-07-16 15:08:09 +0200
committerThomas Lamprecht <t.lamprecht@proxmox.com>2025-07-17 00:10:43 +0200
commit21d2ad3f7b6d37a8974127aabc07459ba5166b1f (patch)
tree55e11efab76c40284830ba222468f3fccea7ef6e /src
parent4b7a87353497457ee8f8d4093259bad5703916c9 (diff)
api: fabrics: add root-level module
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@proxmox.com> Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com> Link: https://lore.proxmox.com/20250716130837.585796-49-g.goller@proxmox.com
Diffstat (limited to 'src')
-rw-r--r--src/PVE/API2/Network/SDN.pm7
-rw-r--r--src/PVE/API2/Network/SDN/Fabrics.pm165
-rw-r--r--src/PVE/API2/Network/SDN/Makefile3
-rw-r--r--src/PVE/Network/SDN.pm2
4 files changed, 175 insertions, 2 deletions
diff --git a/src/PVE/API2/Network/SDN.pm b/src/PVE/API2/Network/SDN.pm
index 0824410..6645f28 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);
@@ -46,6 +47,11 @@ __PACKAGE__->register_method({
});
__PACKAGE__->register_method({
+ subclass => "PVE::API2::Network::SDN::Fabrics",
+ path => 'fabrics',
+});
+
+__PACKAGE__->register_method({
name => 'index',
path => '',
method => 'GET',
@@ -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 0000000..a4a972d
--- /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 abd1bfa..08bec75 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 8c584f6..66665a4 100644
--- a/src/PVE/Network/SDN.pm
+++ b/src/PVE/Network/SDN.pm
@@ -376,7 +376,7 @@ sub generate_dhcp_config {
sub encode_value {
my ($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));
} elsif (ref($value) eq 'ARRAY') {