]> git.proxmox.com Git - pve-network.git/commitdiff
api: refactor URL structure for Ipam
authorStefan Hanreich <s.hanreich@proxmox.com>
Mon, 20 Nov 2023 16:28:32 +0000 (17:28 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 20 Nov 2023 16:40:36 +0000 (17:40 +0100)
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
src/PVE/API2/Network/SDN/Ipam.pm [deleted file]
src/PVE/API2/Network/SDN/Ipams.pm
src/PVE/API2/Network/SDN/Ips.pm [new file with mode: 0644]
src/PVE/API2/Network/SDN/Makefile
src/PVE/API2/Network/SDN/Vnets.pm

index 551afcf49b1c50ccd94953dcc53c305860a67c53..d216e4878b611b338e3ed6ec3a092148e3f6713d 100644 (file)
@@ -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/Ipam.pm b/src/PVE/API2/Network/SDN/Ipam.pm
deleted file mode 100644 (file)
index 722baa4..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-package PVE::API2::Network::SDN::Ipam;
-
-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::JSONSchema qw(get_standard_option);
-use PVE::RPCEnvironment;
-
-use PVE::RESTHandler;
-
-use base qw(PVE::RESTHandler);
-
-__PACKAGE__->register_method ({
-    name => 'ipamindex',
-    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',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           zone => get_standard_option('pve-sdn-zone-id'),
-           vnet => get_standard_option('pve-sdn-vnet-id'),
-           mac => get_standard_option('mac-addr'),
-       },
-    },
-    returns => { type => 'null' },
-    code => sub {
-       my ($param) = @_;
-
-       my $vnet = extract_param($param, 'vnet');
-       my $mac = extract_param($param, 'mac');
-
-       eval {
-           PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac);
-       };
-       my $error = $@;
-
-       die "$error\n" if $error;
-
-       return undef;
-    },
-});
-
-__PACKAGE__->register_method ({
-    name => 'dhcpcreate',
-    path => '{zone}/{vnet}/{mac}',
-    method => 'POST',
-    description => 'Create DHCP Mapping',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           zone => get_standard_option('pve-sdn-zone-id'),
-           vnet => get_standard_option('pve-sdn-vnet-id'),
-           mac => get_standard_option('mac-addr'),
-           ip => {
-               type => 'string',
-               format => 'ip',
-               description => 'The IP address to associate with the given MAC address',
-           },
-       },
-    },
-    returns => { type => 'null' },
-    code => sub {
-       my ($param) = @_;
-
-       my $vnet = extract_param($param, 'vnet');
-       my $mac = extract_param($param, 'mac');
-       my $ip = extract_param($param, 'ip');
-
-       PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, undef);
-
-       return undef;
-    },
-});
-__PACKAGE__->register_method ({
-    name => 'dhcpupdate',
-    path => '{zone}/{vnet}/{mac}',
-    method => 'PUT',
-    description => 'Update DHCP Mapping',
-    protected => 1,
-    permissions => {
-       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
-    },
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           zone => get_standard_option('pve-sdn-zone-id'),
-           vnet => get_standard_option('pve-sdn-vnet-id'),
-           vmid => get_standard_option('pve-vmid', {
-               optional => 1,
-           }),
-           mac => get_standard_option('mac-addr'),
-           ip => {
-               type => 'string',
-               format => 'ip',
-               description => 'The IP address to associate with the given MAC address',
-           },
-       },
-    },
-    returns => { type => 'null' },
-    code => sub {
-       my ($param) = @_;
-
-       my $vnet = extract_param($param, 'vnet');
-       my $mac = extract_param($param, 'mac');
-       my $vmid = extract_param($param, 'vmid');
-       my $ip = extract_param($param, 'ip');
-
-       my ($old_ip4, $old_ip6) = PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac, '');
-
-       eval {
-           PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, $vmid);
-       };
-       my $error = $@;
-
-       if ($error) {
-           PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip4, '', $mac, $vmid) if $old_ip4;
-           PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip6, '', $mac, $vmid) if $old_ip6;
-       }
-
-       die "$error\n" if $error;
-       return undef;
-    },
-});
-
-1;
index 6410e8e272dbcf583fd1897e10f9fc73d5f47e7b..d6e0bc8c99c68eb88f31e2533c2c1443ff7ec533 100644 (file)
@@ -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/Ips.pm b/src/PVE/API2/Network/SDN/Ips.pm
new file mode 100644 (file)
index 0000000..6989b9b
--- /dev/null
@@ -0,0 +1,137 @@
+package PVE::API2::Network::SDN::Ips;
+
+use strict;
+use warnings;
+
+use PVE::Tools qw(extract_param);
+
+use PVE::Network::SDN::Vnets;
+use PVE::Network::SDN::Dhcp;
+
+use PVE::JSONSchema qw(get_standard_option);
+use PVE::RESTHandler;
+
+use base qw(PVE::RESTHandler);
+
+__PACKAGE__->register_method ({
+    name => 'ipdelete',
+    path => '',
+    method => 'DELETE',
+    description => 'Delete IP Mappings in a VNet',
+    protected => 1,
+    permissions => {
+       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           zone => get_standard_option('pve-sdn-zone-id'),
+           vnet => get_standard_option('pve-sdn-vnet-id'),
+           mac => get_standard_option('mac-addr'),
+       },
+    },
+    returns => { type => 'null' },
+    code => sub {
+       my ($param) = @_;
+
+       my $vnet = extract_param($param, 'vnet');
+       my $mac = extract_param($param, 'mac');
+
+       eval {
+           PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac);
+       };
+       my $error = $@;
+
+       die "$error\n" if $error;
+
+       return undef;
+    },
+});
+
+__PACKAGE__->register_method ({
+    name => 'ipcreate',
+    path => '',
+    method => 'POST',
+    description => 'Create IP Mapping in a VNet',
+    protected => 1,
+    permissions => {
+       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           zone => get_standard_option('pve-sdn-zone-id'),
+           vnet => get_standard_option('pve-sdn-vnet-id'),
+           mac => get_standard_option('mac-addr'),
+           ip => {
+               type => 'string',
+               format => 'ip',
+               description => 'The IP address to associate with the given MAC address',
+           },
+       },
+    },
+    returns => { type => 'null' },
+    code => sub {
+       my ($param) = @_;
+
+       my $vnet = extract_param($param, 'vnet');
+       my $mac = extract_param($param, 'mac');
+       my $ip = extract_param($param, 'ip');
+
+       PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, undef);
+
+       return undef;
+    },
+});
+__PACKAGE__->register_method ({
+    name => 'ipupdate',
+    path => '',
+    method => 'PUT',
+    description => 'Update IP Mapping in a VNet',
+    protected => 1,
+    permissions => {
+       check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           zone => get_standard_option('pve-sdn-zone-id'),
+           vnet => get_standard_option('pve-sdn-vnet-id'),
+           vmid => get_standard_option('pve-vmid', {
+               optional => 1,
+           }),
+           mac => get_standard_option('mac-addr'),
+           ip => {
+               type => 'string',
+               format => 'ip',
+               description => 'The IP address to associate with the given MAC address',
+           },
+       },
+    },
+    returns => { type => 'null' },
+    code => sub {
+       my ($param) = @_;
+
+       my $vnet = extract_param($param, 'vnet');
+       my $mac = extract_param($param, 'mac');
+       my $vmid = extract_param($param, 'vmid');
+       my $ip = extract_param($param, 'ip');
+
+       my ($old_ip4, $old_ip6) = PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac, '');
+
+       eval {
+           PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, $vmid);
+       };
+       my $error = $@;
+
+       if ($error) {
+           PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip4, '', $mac, $vmid) if $old_ip4;
+           PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip6, '', $mac, $vmid) if $old_ip6;
+       }
+
+       die "$error\n" if $error;
+       return undef;
+    },
+});
+
+1;
index 2480c09ef8c096b8e47a5c6b04095c91517eb3d3..abd1bfae020e0e9b40a7a3e4272de7e2b26eda68 100644 (file)
@@ -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
index 864dc4ac7932067b8dd88f718032743a5ccf54e2..a32df8c63fd9aa716db8a73617421d329fb5c906 100644 (file)
@@ -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) = @_;