From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 909301FF15C for <inbox@lore.proxmox.com>; Fri, 4 Apr 2025 18:31:41 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BEF6C37C90; Fri, 4 Apr 2025 18:29:52 +0200 (CEST) From: Gabriel Goller <g.goller@proxmox.com> To: pve-devel@lists.proxmox.com Date: Fri, 4 Apr 2025 18:28:53 +0200 Message-Id: <20250404162908.563060-43-g.goller@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250404162908.563060-1-g.goller@proxmox.com> References: <20250404162908.563060-1-g.goller@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.023 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 SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH pve-network v2 17/19] api: fabrics: add module / subfolder X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> From: Stefan Hanreich <s.hanreich@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.hanreich@proxmox.com> Co-authored-by: Gabriel Goller <g.goller@proxmox.com> Signed-off-by: Gabriel Goller <g.goller@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