From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <shanreich@lana.proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 7ECD59B59C
 for <pve-devel@lists.proxmox.com>; Mon, 20 Nov 2023 17:28:39 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 622A11CD35
 for <pve-devel@lists.proxmox.com>; Mon, 20 Nov 2023 17:28:39 +0100 (CET)
Received: from lana.proxmox.com (unknown [94.136.29.99])
 by firstgate.proxmox.com (Proxmox) with ESMTP
 for <pve-devel@lists.proxmox.com>; Mon, 20 Nov 2023 17:28:38 +0100 (CET)
Received: by lana.proxmox.com (Postfix, from userid 10043)
 id 2EF3A2C2B3A; Mon, 20 Nov 2023 17:28:38 +0100 (CET)
From: Stefan Hanreich <s.hanreich@proxmox.com>
To: pve-devel@lists.proxmox.com
Date: Mon, 20 Nov 2023 17:28:32 +0100
Message-Id: <20231120162833.431139-2-s.hanreich@proxmox.com>
X-Mailer: git-send-email 2.39.2
In-Reply-To: <20231120162833.431139-1-s.hanreich@proxmox.com>
References: <20231120162833.431139-1-s.hanreich@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL -0.614 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
 KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery
 methods POISEN_SPAM_PILL          0.1 Meta: its spam
 POISEN_SPAM_PILL_1        0.1 random spam to be learned in bayes
 POISEN_SPAM_PILL_3        0.1 random spam to be learned in bayes
 RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_NONE                0.001 SPF: sender does not publish an SPF Record
 T_SCC_BODY_TEXT_LINE    -0.01 -
Subject: [pve-devel] [PATCH pve-network 1/2] api: refactor URL structure for
 Ipam
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>
X-List-Received-Date: Mon, 20 Nov 2023 16:28:39 -0000

The initial URL structure was less than optimal due to Ipam as well as
Ipams being endpoints in the API, which are too similar and might be
confusing to users.

Move the listing of PVE IPAM to /ipams/pve/status
Move the create / update / delete endpoints to /vnets/{vnetid}/ips

Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com>
---
 src/PVE/API2/Network/SDN.pm                  |  6 --
 src/PVE/API2/Network/SDN/Ipams.pm            | 83 +++++++++++++++++
 src/PVE/API2/Network/SDN/{Ipam.pm => Ips.pm} | 97 ++------------------
 src/PVE/API2/Network/SDN/Makefile            |  2 +-
 src/PVE/API2/Network/SDN/Vnets.pm            |  6 ++
 5 files changed, 100 insertions(+), 94 deletions(-)
 rename src/PVE/API2/Network/SDN/{Ipam.pm => Ips.pm} (58%)

diff --git a/src/PVE/API2/Network/SDN.pm b/src/PVE/API2/Network/SDN.pm
index 551afcf..d216e48 100644
--- a/src/PVE/API2/Network/SDN.pm
+++ b/src/PVE/API2/Network/SDN.pm
@@ -15,7 +15,6 @@ use PVE::Network::SDN;
 use PVE::API2::Network::SDN::Controllers;
 use PVE::API2::Network::SDN::Vnets;
 use PVE::API2::Network::SDN::Zones;
-use PVE::API2::Network::SDN::Ipam;
 use PVE::API2::Network::SDN::Ipams;
 use PVE::API2::Network::SDN::Dns;
 
@@ -36,11 +35,6 @@ __PACKAGE__->register_method ({
     path => 'controllers',
 });
 
-__PACKAGE__->register_method ({
-    subclass => "PVE::API2::Network::SDN::Ipam",
-    path => 'ipam',
-});
-
 __PACKAGE__->register_method ({
     subclass => "PVE::API2::Network::SDN::Ipams",
     path => 'ipams',
diff --git a/src/PVE/API2/Network/SDN/Ipams.pm b/src/PVE/API2/Network/SDN/Ipams.pm
index 6410e8e..d6e0bc8 100644
--- a/src/PVE/API2/Network/SDN/Ipams.pm
+++ b/src/PVE/API2/Network/SDN/Ipams.pm
@@ -12,6 +12,9 @@ use PVE::Network::SDN::Ipams::Plugin;
 use PVE::Network::SDN::Ipams::PVEPlugin;
 use PVE::Network::SDN::Ipams::PhpIpamPlugin;
 use PVE::Network::SDN::Ipams::NetboxPlugin;
+use PVE::Network::SDN::Dhcp;
+use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Zones;
 
 use Storable qw(dclone);
 use PVE::JSONSchema qw(get_standard_option);
@@ -245,4 +248,84 @@ __PACKAGE__->register_method ({
 	return undef;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'ipamindex',
+    path => '{ipam}/status',
+    method => 'GET',
+    description => 'List PVE IPAM Entries',
+    protected => 1,
+    permissions => {
+	description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/zones/<zone>/<vnet>'",
+	user => 'all',
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    ipam => get_standard_option('pve-sdn-ipam-id', {
+                completion => \&PVE::Network::SDN::Ipams::complete_sdn_ipams,
+            }),
+	},
+    },
+    returns => {
+	type => 'array',
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $id = extract_param($param, 'ipam');
+	die "Currently only PVE IPAM is supported!" if $id ne 'pve';
+
+	my $rpcenv = PVE::RPCEnvironment::get();
+	my $authuser = $rpcenv->get_user();
+	my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
+
+	my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve');
+	my $ipam_db = $ipam_plugin->read_db();
+
+	my $result = [];
+
+	for my $zone_id (keys %{$ipam_db->{zones}}) {
+	    my $zone_config = PVE::Network::SDN::Zones::get_zone($zone_id, 1);
+            next if !$zone_config || $zone_config->{ipam} ne 'pve' || !$zone_config->{dhcp};
+
+	    my $zone = $ipam_db->{zones}->{$zone_id};
+
+	    my $vnets = PVE::Network::SDN::Zones::get_vnets($zone_id, 1);
+
+	    for my $subnet_cidr (keys %{$zone->{subnets}}) {
+		my $subnet = $zone->{subnets}->{$subnet_cidr};
+		my $ip = new NetAddr::IP($subnet_cidr) or die 'Found invalid CIDR in IPAM';
+
+		my $vnet = undef;
+		for my $vnet_id (keys %$vnets) {
+		    eval {
+			my ($zone, $subnetid, $subnet_cfg, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip(
+			    $vnet_id,
+			    $ip->addr,
+			);
+
+			$vnet = $subnet_cfg->{vnet};
+		    };
+
+		    last if $vnet;
+		}
+
+		next if !$vnet || !$rpcenv->check_any($authuser, "/sdn/zones/$zone_id/$vnet", $privs, 1);
+
+		for my $ip (keys %{$subnet->{ips}}) {
+		    my $entry = $subnet->{ips}->{$ip};
+		    $entry->{zone} = $zone_id;
+		    $entry->{subnet} = $subnet_cidr;
+		    $entry->{ip} = $ip;
+		    $entry->{vnet} = $vnet;
+
+		    push @$result, $entry;
+		}
+	    }
+	}
+
+	return $result;
+    },
+});
+
 1;
diff --git a/src/PVE/API2/Network/SDN/Ipam.pm b/src/PVE/API2/Network/SDN/Ips.pm
similarity index 58%
rename from src/PVE/API2/Network/SDN/Ipam.pm
rename to src/PVE/API2/Network/SDN/Ips.pm
index e71ca7d..31dec04 100644
--- a/src/PVE/API2/Network/SDN/Ipam.pm
+++ b/src/PVE/API2/Network/SDN/Ips.pm
@@ -1,100 +1,23 @@
-package PVE::API2::Network::SDN::Ipam;
+package PVE::API2::Network::SDN::Ips;
 
 use strict;
 use warnings;
 
 use PVE::Tools qw(extract_param);
-use PVE::Cluster qw(cfs_read_file cfs_write_file);
 
-use PVE::Network::SDN;
-use PVE::Network::SDN::Dhcp;
 use PVE::Network::SDN::Vnets;
-use PVE::Network::SDN::Ipams::Plugin;
+use PVE::Network::SDN::Dhcp;
 
 use PVE::JSONSchema qw(get_standard_option);
-use PVE::RPCEnvironment;
-
 use PVE::RESTHandler;
 
 use base qw(PVE::RESTHandler);
 
 __PACKAGE__->register_method ({
-    name => 'ipamindex',
+    name => 'ipdelete',
     path => '',
-    method => 'GET',
-    description => 'List PVE IPAM Entries',
-    protected => 1,
-    permissions => {
-	description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/zones/<zone>/<vnet>'",
-	user => 'all',
-    },
-    parameters => {
-	additionalProperties => 0,
-    },
-    returns => {
-	type => 'array',
-    },
-    code => sub {
-	my ($param) = @_;
-
-	my $rpcenv = PVE::RPCEnvironment::get();
-	my $authuser = $rpcenv->get_user();
-	my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
-
-	my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve');
-	my $ipam_db = $ipam_plugin->read_db();
-
-	my $result = [];
-
-	for my $zone_id (keys %{$ipam_db->{zones}}) {
-	    my $zone_config = PVE::Network::SDN::Zones::get_zone($zone_id, 1);
-            next if !$zone_config || $zone_config->{ipam} ne 'pve' || !$zone_config->{dhcp};
-
-	    my $zone = $ipam_db->{zones}->{$zone_id};
-
-	    my $vnets = PVE::Network::SDN::Zones::get_vnets($zone_id, 1);
-
-	    for my $subnet_cidr (keys %{$zone->{subnets}}) {
-		my $subnet = $zone->{subnets}->{$subnet_cidr};
-		my $ip = new NetAddr::IP($subnet_cidr) or die 'Found invalid CIDR in IPAM';
-
-		my $vnet = undef;
-		for my $vnet_id (keys %$vnets) {
-		    eval {
-			my ($zone, $subnetid, $subnet_cfg, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip(
-			    $vnet_id,
-			    $ip->addr,
-			);
-
-			$vnet = $subnet_cfg->{vnet};
-		    };
-
-		    last if $vnet;
-		}
-
-		next if !$vnet || !$rpcenv->check_any($authuser, "/sdn/zones/$zone_id/$vnet", $privs, 1);
-
-		for my $ip (keys %{$subnet->{ips}}) {
-		    my $entry = $subnet->{ips}->{$ip};
-		    $entry->{zone} = $zone_id;
-		    $entry->{subnet} = $subnet_cidr;
-		    $entry->{ip} = $ip;
-		    $entry->{vnet} = $vnet;
-
-		    push @$result, $entry;
-		}
-	    }
-	}
-
-	return $result;
-    },
-});
-
-__PACKAGE__->register_method ({
-    name => 'dhcpdelete',
-    path => '{zone}/{vnet}/{mac}',
     method => 'DELETE',
-    description => 'Delete DHCP Mappings in a VNet for a MAC address',
+    description => 'Delete IP Mappings in a VNet',
     protected => 1,
     permissions => {
 	check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
@@ -129,10 +52,10 @@ __PACKAGE__->register_method ({
 });
 
 __PACKAGE__->register_method ({
-    name => 'dhcpcreate',
-    path => '{zone}/{vnet}/{mac}',
+    name => 'ipcreate',
+    path => '',
     method => 'POST',
-    description => 'Create DHCP Mapping',
+    description => 'Create IP Mapping in a VNet',
     protected => 1,
     permissions => {
 	check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
@@ -165,10 +88,10 @@ __PACKAGE__->register_method ({
     },
 });
 __PACKAGE__->register_method ({
-    name => 'dhcpupdate',
-    path => '{zone}/{vnet}/{mac}',
+    name => 'ipupdate',
+    path => '',
     method => 'PUT',
-    description => 'Update DHCP Mapping',
+    description => 'Update IP Mapping in a VNet',
     protected => 1,
     permissions => {
 	check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
diff --git a/src/PVE/API2/Network/SDN/Makefile b/src/PVE/API2/Network/SDN/Makefile
index 2480c09..abd1bfa 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 Ipam.pm Dns.pm
+SOURCES=Vnets.pm Zones.pm Controllers.pm Subnets.pm Ipams.pm Dns.pm Ips.pm
 
 
 PERL5DIR=${DESTDIR}/usr/share/perl5
diff --git a/src/PVE/API2/Network/SDN/Vnets.pm b/src/PVE/API2/Network/SDN/Vnets.pm
index 864dc4a..a32df8c 100644
--- a/src/PVE/API2/Network/SDN/Vnets.pm
+++ b/src/PVE/API2/Network/SDN/Vnets.pm
@@ -13,6 +13,7 @@ use PVE::Network::SDN::Vnets;
 use PVE::Network::SDN::VnetPlugin;
 use PVE::Network::SDN::Subnets;
 use PVE::API2::Network::SDN::Subnets;
+use PVE::API2::Network::SDN::Ips;
 
 use Storable qw(dclone);
 use PVE::JSONSchema qw(get_standard_option);
@@ -28,6 +29,11 @@ __PACKAGE__->register_method ({
     path => '{vnet}/subnets',
 });
 
+__PACKAGE__->register_method ({
+    subclass => "PVE::API2::Network::SDN::Ips",
+    path => '{vnet}/ips',
+});
+
 my $api_sdn_vnets_config = sub {
     my ($cfg, $id) = @_;
 
-- 
2.39.2