From: Stefan Hanreich <s.hanre...@proxmox.com> Add a new subfolder that hosts all the API methods for the sdn fabrics. We also add a method for listing all fabrics of all types as a GET endpoint, with the respective schemas. It supports the same filtering options as the other SDN GET endpoints (pending / running).
We also need to add a special case in encode_value for the interfaces key of nodes, since they require special handling when encoding because they are arrays. Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com> Co-authored-by: Gabriel Goller <g.gol...@proxmox.com> Signed-off-by: Gabriel Goller <g.gol...@proxmox.com> --- src/PVE/API2/Network/SDN.pm | 7 + src/PVE/API2/Network/SDN/Fabrics.pm | 208 ++++++++++++++++++++++++++++ src/PVE/API2/Network/SDN/Makefile | 3 +- src/PVE/Network/SDN.pm | 2 +- 4 files changed, 218 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 d216e4878b61..ccbf0777e3d4 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..86785ee47cff --- /dev/null +++ b/src/PVE/API2/Network/SDN/Fabrics.pm @@ -0,0 +1,208 @@ +package PVE::API2::Network::SDN::Fabrics; + +use strict; +use warnings; + +use Storable qw(dclone); + +use PVE::JSONSchema qw(get_standard_option); +use PVE::RPCEnvironment; +use PVE::Tools qw(extract_param); + +use PVE::Network::SDN::Fabrics; + +use PVE::API2::Network::SDN::Fabrics::OpenFabric; +use PVE::API2::Network::SDN::Fabrics::OpenFabricNode; +use PVE::API2::Network::SDN::Fabrics::OSPF; +use PVE::API2::Network::SDN::Fabrics::OSPFNode; + +use PVE::RESTHandler; +use base qw(PVE::RESTHandler); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Network::SDN::Fabrics::OpenFabric", + path => 'openfabric', +}); + +__PACKAGE__->register_method ({ + subclass => "PVE::API2::Network::SDN::Fabrics::OSPF", + path => 'ospf', +}); + +__PACKAGE__->register_method ({ + name => 'index', + path => '', + method => 'GET', + permissions => { user => 'all' }, + description => "SDN Fabrics Index", + parameters => { + additionalProperties => 0, + properties => {}, + }, + returns => { + type => 'array', + items => { + type => "object", + properties => {}, + }, + links => [ { rel => 'child', href => "{protocol}" } ], + }, + code => sub { + my ($param) = @_; + + return [ + { protocol => 'openfabric' }, + { protocol => 'ospf' }, + ]; + }}); + +__PACKAGE__->register_method({ + name => 'fabric_index', + path => 'all', + method => 'GET', + description => 'Index of SDN Fabrics', + permissions => { + description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/fabrics/<protocol>/<fabric>'", + user => 'all', + }, + parameters => { + additionalProperties => 0, + properties => { + running => { + type => 'boolean', + optional => 1, + description => "Display running config.", + }, + pending => { + type => 'boolean', + optional => 1, + description => "Display pending config.", + }, + }, + }, + returns => { + type => 'object', + properties => { + openfabric => { + type => 'array', + items => { + type => 'object', + properties => { + 'type' => get_standard_option('pve-sdn-fabric-section-type'), + 'config' => { + type => 'object', + 'type-property' => 'type', + oneOf => [ + { + 'instance-types' => ['fabric'], + type => 'object', + description => 'OpenFabric fabric', + properties => $PVE::API2::Network::SDN::Fabrics::OpenFabric::fabric_properties, + }, + { + 'instance-types' => ['node'], + type => 'object', + description => 'OpenFabric node', + properties => $PVE::API2::Network::SDN::Fabrics::OpenFabricNode::node_properties, + }, + ], + }, + }, + }, + }, + ospf => { + type => 'array', + items => { + type => 'object', + properties => { + 'type' => get_standard_option('pve-sdn-fabric-section-type'), + config => { + type => 'object', + 'type-property' => 'type', + oneOf => [ + { + 'instance-types' => ['fabric'], + type => 'object', + description => 'OSPF fabric', + properties => $PVE::API2::Network::SDN::Fabrics::OSPF::fabric_properties, + }, + { + 'instance-types' => ['node'], + type => 'object', + description => 'OSPF node', + properties => $PVE::API2::Network::SDN::Fabrics::OSPFNode::node_properties, + }, + ] + }, + }, + }, + }, + }, + }, + code => sub { + my ($param) = @_; + + my $rpcenv = PVE::RPCEnvironment::get(); + my $authuser = $rpcenv->get_user(); + my $privs = [ 'SDN.Audit', 'SDN.Allocate' ]; + + my $running = extract_param($param, 'running'); + my $pending = extract_param($param, 'pending'); + + my $extract_fabric_id = sub { + my ($entry) = @_; + + my $data = $entry; + + if ($entry->{state} && $entry->{state} eq 'new') { + $data = $entry->{pending}; + } + + return $data->{fabric_id}; + }; + + my $res = {}; + + my @protocols = PVE::Network::SDN::Fabrics::get_protocols(); + foreach my $protocol (@protocols) { + $res->{$protocol} = []; + + my $config; + + if ($pending) { + my $section_config = PVE::Network::SDN::Fabrics::config_for_protocol($protocol, 0) + ->get_inner(); + my $running_config = PVE::Network::SDN::Fabrics::config_for_protocol($protocol, 1) + ->get_inner(); + + # pending_config expects the configuration to be under the ids + # key, but the Fabrics function doesn't include that key + $config = PVE::Network::SDN::pending_config( + { $protocol => { ids => $running_config } }, + { ids => $section_config }, + $protocol + ); + + $config = $config->{ids}; + } elsif ($running) { + $config = PVE::Network::SDN::Fabrics::config_for_protocol($protocol, 1) + ->get_inner(); + } else { + $config = PVE::Network::SDN::Fabrics::config_for_protocol($protocol, 0) + ->get_inner(); + } + + foreach my $id (sort keys %$config) { + my $entry = $config->{$id}; + + my $fabric_id = $extract_fabric_id->($entry); + next if !$rpcenv->check_any($authuser, "/sdn/fabrics/$protocol/$fabric_id", $privs, 1); + + push @{$res->{$protocol}}, dclone($entry); + } + } + return $res; + }, +}); + +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 af1550b0ab40..6057bca1c6b1 100644 --- a/src/PVE/Network/SDN.pm +++ b/src/PVE/Network/SDN.pm @@ -344,7 +344,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