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.gol...@proxmox.com> Signed-off-by: Stefan Hanreich <s.hanre...@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 | 2 +- 4 files changed, 175 insertions(+), 2 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 910f89a..877d46d 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 0000000..9333700 --- /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 79e19b1..1a340a5 100644 --- a/src/PVE/Network/SDN.pm +++ b/src/PVE/Network/SDN.pm @@ -362,7 +362,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') { -- 2.39.5 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel