]> git.proxmox.com Git - pve-network.git/blob - src/PVE/API2/Network/SDN/Ipam.pm
e71ca7da151d72a332e9fc98c2d697857658c986
[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 PVE::Network::SDN::Dhcp::remove_mapping($vnet, $mac);
118
119 eval {
120 PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac);
121 };
122 my $error = $@;
123
124 PVE::Network::SDN::Vnets::add_dhcp_mapping($vnet, $mac) if $error;
125 die "$error\n" if $error;
126
127 return undef;
128 },
129 });
130
131 __PACKAGE__->register_method ({
132 name => 'dhcpcreate',
133 path => '{zone}/{vnet}/{mac}',
134 method => 'POST',
135 description => 'Create DHCP Mapping',
136 protected => 1,
137 permissions => {
138 check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
139 },
140 parameters => {
141 additionalProperties => 0,
142 properties => {
143 zone => get_standard_option('pve-sdn-zone-id'),
144 vnet => get_standard_option('pve-sdn-vnet-id'),
145 mac => get_standard_option('mac-addr'),
146 ip => {
147 type => 'string',
148 format => 'ip',
149 description => 'The IP address to associate with the given MAC address',
150 },
151 },
152 },
153 returns => { type => 'null' },
154 code => sub {
155 my ($param) = @_;
156
157 my $vnet = extract_param($param, 'vnet');
158 my $mac = extract_param($param, 'mac');
159 my $ip = extract_param($param, 'ip');
160
161 PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, undef);
162 PVE::Network::SDN::Vnets::add_dhcp_mapping($vnet, $mac);
163
164 return undef;
165 },
166 });
167 __PACKAGE__->register_method ({
168 name => 'dhcpupdate',
169 path => '{zone}/{vnet}/{mac}',
170 method => 'PUT',
171 description => 'Update DHCP Mapping',
172 protected => 1,
173 permissions => {
174 check => ['perm', '/sdn/zones/{zone}/{vnet}', [ 'SDN.Allocate' ]],
175 },
176 parameters => {
177 additionalProperties => 0,
178 properties => {
179 zone => get_standard_option('pve-sdn-zone-id'),
180 vnet => get_standard_option('pve-sdn-vnet-id'),
181 vmid => get_standard_option('pve-vmid', {
182 optional => 1,
183 }),
184 mac => get_standard_option('mac-addr'),
185 ip => {
186 type => 'string',
187 format => 'ip',
188 description => 'The IP address to associate with the given MAC address',
189 },
190 },
191 },
192 returns => { type => 'null' },
193 code => sub {
194 my ($param) = @_;
195
196 my $vnet = extract_param($param, 'vnet');
197 my $mac = extract_param($param, 'mac');
198 my $vmid = extract_param($param, 'vmid');
199 my $ip = extract_param($param, 'ip');
200
201 PVE::Network::SDN::Dhcp::remove_mapping($vnet, $mac);
202 my ($old_ip4, $old_ip6) = PVE::Network::SDN::Vnets::del_ips_from_mac($vnet, $mac, '');
203
204 eval {
205 PVE::Network::SDN::Vnets::add_ip($vnet, $ip, '', $mac, $vmid);
206 };
207 my $error = $@;
208
209 if ($error) {
210 PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip4, '', $mac, $vmid) if $old_ip4;
211 PVE::Network::SDN::Vnets::add_ip($vnet, $old_ip6, '', $mac, $vmid) if $old_ip6;
212 }
213
214 PVE::Network::SDN::Vnets::add_dhcp_mapping($vnet, $mac);
215
216 die "$error\n" if $error;
217 return undef;
218 },
219 });
220
221 1;