]> git.proxmox.com Git - pve-network.git/blob - src/PVE/API2/Network/SDN/Ipam.pm
722baa46a96f786c081cad211b3070916c60fc59
[pve-network.git] / src / PVE / API2 / Network / SDN / Ipam.pm
1 package PVE::API2::Network::SDN::Ipam;
2
3 use strict;
4 use warnings;
5
6 use PVE::Tools qw(extract_param);
7 use PVE::Cluster qw(cfs_read_file cfs_write_file);
8
9 use PVE::Network::SDN;
10 use PVE::Network::SDN::Dhcp;
11 use PVE::Network::SDN::Vnets;
12 use PVE::Network::SDN::Ipams::Plugin;
13
14 use PVE::JSONSchema qw(get_standard_option);
15 use PVE::RPCEnvironment;
16
17 use PVE::RESTHandler;
18
19 use base qw(PVE::RESTHandler);
20
21 __PACKAGE__->register_method ({
22 name => 'ipamindex',
23 path => '',
24 method => 'GET',
25 description => 'List PVE IPAM Entries',
26 protected => 1,
27 permissions => {
28 description => "Only list entries where you have 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/zones/<zone>/<vnet>'",
29 user => 'all',
30 },
31 parameters => {
32 additionalProperties => 0,
33 },
34 returns => {
35 type => 'array',
36 },
37 code => sub {
38 my ($param) = @_;
39
40 my $rpcenv = PVE::RPCEnvironment::get();
41 my $authuser = $rpcenv->get_user();
42 my $privs = [ 'SDN.Audit', 'SDN.Allocate' ];
43
44 my $ipam_plugin = PVE::Network::SDN::Ipams::Plugin->lookup('pve');
45 my $ipam_db = $ipam_plugin->read_db();
46
47 my $result = [];
48
49 for my $zone_id (keys %{$ipam_db->{zones}}) {
50 my $zone_config = PVE::Network::SDN::Zones::get_zone($zone_id, 1);
51 next if !$zone_config || $zone_config->{ipam} ne 'pve' || !$zone_config->{dhcp};
52
53 my $zone = $ipam_db->{zones}->{$zone_id};
54
55 my $vnets = PVE::Network::SDN::Zones::get_vnets($zone_id, 1);
56
57 for my $subnet_cidr (keys %{$zone->{subnets}}) {
58 my $subnet = $zone->{subnets}->{$subnet_cidr};
59 my $ip = new NetAddr::IP($subnet_cidr) or die 'Found invalid CIDR in IPAM';
60
61 my $vnet = undef;
62 for my $vnet_id (keys %$vnets) {
63 eval {
64 my ($zone, $subnetid, $subnet_cfg, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_ip(
65 $vnet_id,
66 $ip->addr,
67 );
68
69 $vnet = $subnet_cfg->{vnet};
70 };
71
72 last if $vnet;
73 }
74
75 next if !$vnet || !$rpcenv->check_any($authuser, "/sdn/zones/$zone_id/$vnet", $privs, 1);
76
77 for my $ip (keys %{$subnet->{ips}}) {
78 my $entry = $subnet->{ips}->{$ip};
79 $entry->{zone} = $zone_id;
80 $entry->{subnet} = $subnet_cidr;
81 $entry->{ip} = $ip;
82 $entry->{vnet} = $vnet;
83
84 push @$result, $entry;
85 }
86 }
87 }
88
89 return $result;
90 },
91 });
92
93 __PACKAGE__->register_method ({
94 name => 'dhcpdelete',
95 path => '{zone}/{vnet}/{mac}',
96 method => 'DELETE',
97 description => 'Delete DHCP Mappings in a VNet for a MAC address',
98 protected => 1,
99 permissions => {
100 check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
101 },
102 parameters => {
103 additionalProperties => 0,
104 properties => {
105 zone => get_standard_option('pve-sdn-zone-id'),
106 vnet => get_standard_option('pve-sdn-vnet-id'),
107 mac => get_standard_option('mac-addr'),
108 },
109 },
110 returns => { type => 'null' },
111 code => sub {
112 my ($param) = @_;
113
114 my $vnet = extract_param($param, 'vnet');
115 my $mac = extract_param($param, 'mac');
116
117 eval {
118 PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac);
119 };
120 my $error = $@;
121
122 die "$error\n" if $error;
123
124 return undef;
125 },
126 });
127
128 __PACKAGE__->register_method ({
129 name => 'dhcpcreate',
130 path => '{zone}/{vnet}/{mac}',
131 method => 'POST',
132 description => 'Create DHCP Mapping',
133 protected => 1,
134 permissions => {
135 check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
136 },
137 parameters => {
138 additionalProperties => 0,
139 properties => {
140 zone => get_standard_option('pve-sdn-zone-id'),
141 vnet => get_standard_option('pve-sdn-vnet-id'),
142 mac => get_standard_option('mac-addr'),
143 ip => {
144 type => 'string',
145 format => 'ip',
146 description => 'The IP address to associate with the given MAC address',
147 },
148 },
149 },
150 returns => { type => 'null' },
151 code => sub {
152 my ($param) = @_;
153
154 my $vnet = extract_param($param, 'vnet');
155 my $mac = extract_param($param, 'mac');
156 my $ip = extract_param($param, 'ip');
157
158 PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, undef);
159
160 return undef;
161 },
162 });
163 __PACKAGE__->register_method ({
164 name => 'dhcpupdate',
165 path => '{zone}/{vnet}/{mac}',
166 method => 'PUT',
167 description => 'Update DHCP Mapping',
168 protected => 1,
169 permissions => {
170 check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
171 },
172 parameters => {
173 additionalProperties => 0,
174 properties => {
175 zone => get_standard_option('pve-sdn-zone-id'),
176 vnet => get_standard_option('pve-sdn-vnet-id'),
177 vmid => get_standard_option('pve-vmid', {
178 optional => 1,
179 }),
180 mac => get_standard_option('mac-addr'),
181 ip => {
182 type => 'string',
183 format => 'ip',
184 description => 'The IP address to associate with the given MAC address',
185 },
186 },
187 },
188 returns => { type => 'null' },
189 code => sub {
190 my ($param) = @_;
191
192 my $vnet = extract_param($param, 'vnet');
193 my $mac = extract_param($param, 'mac');
194 my $vmid = extract_param($param, 'vmid');
195 my $ip = extract_param($param, 'ip');
196
197 my ($old_ip4, $old_ip6) = PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac, '');
198
199 eval {
200 PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, $vmid);
201 };
202 my $error = $@;
203
204 if ($error) {
205 PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip4, '', $mac, $vmid) if $old_ip4;
206 PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip6, '', $mac, $vmid) if $old_ip6;
207 }
208
209 die "$error\n" if $error;
210 return undef;
211 },
212 });
213
214 1;