]> git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN/Ipams/PVEPlugin.pm
ipam: add hostname/description to ipam db
[pve-network.git] / PVE / Network / SDN / Ipams / PVEPlugin.pm
1 package PVE::Network::SDN::Ipams::PVEPlugin;
2
3 use strict;
4 use warnings;
5 use PVE::INotify;
6 use PVE::Cluster qw(cfs_read_file cfs_write_file cfs_register_file cfs_lock_file);
7 use PVE::Tools;
8 use JSON;
9 use NetAddr::IP;
10 use Net::IP;
11 use Digest::SHA;
12
13 use base('PVE::Network::SDN::Ipams::Plugin');
14
15
16 my $ipamdb_file = "priv/ipam.db";
17
18 PVE::Cluster::cfs_register_file($ipamdb_file,
19 sub { PVE::Network::SDN::Ipams::PVEPlugin->parse_config(@_); },
20 sub { PVE::Network::SDN::Ipams::PVEPlugin->write_config(@_); });
21
22 sub type {
23 return 'pve';
24 }
25
26 sub properties {
27 }
28
29 sub options {
30 }
31
32 # Plugin implementation
33
34 sub add_subnet {
35 my ($class, $plugin_config, $subnetid, $subnet) = @_;
36
37 my $cidr = $subnet->{cidr};
38 my $zone = $subnet->{zone};
39 my $gateway = $subnet->{gateway};
40
41
42 cfs_lock_file($ipamdb_file, undef, sub {
43 my $db = {};
44 $db = read_db();
45
46 $db->{zones}->{$zone} = {} if !$db->{zones}->{$zone};
47 my $zonedb = $db->{zones}->{$zone};
48
49 if(!$zonedb->{subnets}->{$cidr}) {
50 #create subnet
51 $zonedb->{subnets}->{$cidr}->{ips} = {};
52 write_db($db);
53 }
54 });
55 die "$@" if $@;
56 }
57
58 sub del_subnet {
59 my ($class, $plugin_config, $subnetid, $subnet) = @_;
60
61 my $cidr = $subnet->{cidr};
62 my $zone = $subnet->{zone};
63
64 cfs_lock_file($ipamdb_file, undef, sub {
65
66 my $db = read_db();
67
68 my $dbzone = $db->{zones}->{$zone};
69 die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
70 my $dbsubnet = $dbzone->{subnets}->{$cidr};
71 die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet;
72
73 die "cannot delete subnet '$cidr', not empty\n" if keys %{$dbsubnet->{ips}} > 0;
74
75 delete $dbzone->{subnets}->{$cidr};
76
77 write_db($db);
78 });
79 die "$@" if $@;
80
81 }
82
83 sub add_ip {
84 my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $description, $is_gateway) = @_;
85
86 my $cidr = $subnet->{cidr};
87 my $zone = $subnet->{zone};
88
89 cfs_lock_file($ipamdb_file, undef, sub {
90
91 my $db = read_db();
92
93 my $dbzone = $db->{zones}->{$zone};
94 die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
95 my $dbsubnet = $dbzone->{subnets}->{$cidr};
96 die "subnet '$cidr' doesn't exist in IPAM DB\n" if !$dbsubnet;
97
98 die "IP '$ip' already exist\n" if defined($dbsubnet->{ips}->{$ip});
99
100 $dbsubnet->{ips}->{$ip} = {
101 hostname => $hostname,
102 description => $description,
103 };
104
105 write_db($db);
106 });
107 die "$@" if $@;
108 }
109
110 sub add_next_freeip {
111 my ($class, $plugin_config, $subnetid, $subnet, $hostname, $description) = @_;
112
113 my $cidr = $subnet->{cidr};
114 my $network = $subnet->{network};
115 my $zone = $subnet->{zone};
116 my $mask = $subnet->{mask};
117 my $freeip = undef;
118
119 cfs_lock_file($ipamdb_file, undef, sub {
120
121 my $db = read_db();
122 my $dbzone = $db->{zones}->{$zone};
123 die "zone '$zone' doesn't exist in IPAM DB\n" if !$dbzone;
124 my $dbsubnet = $dbzone->{subnets}->{$cidr};
125 die "subnet '$cidr' doesn't exist in IPAM DB" if !$dbsubnet;
126
127 if (Net::IP::ip_is_ipv4($network) && $mask == 32) {
128 die "cannot find free IP in subnet '$cidr'\n" if defined($dbsubnet->{ips}->{$network});
129 $freeip = $network;
130 } else {
131 my $iplist = new NetAddr::IP($cidr);
132 my $broadcast = $iplist->broadcast();
133
134 while(1) {
135 $iplist++;
136 last if $iplist eq $broadcast;
137 my $ip = $iplist->addr();
138 next if defined($dbsubnet->{ips}->{$ip});
139 $freeip = $ip;
140 last;
141 }
142 }
143
144 die "can't find free ip in subnet '$cidr'\n" if !$freeip;
145
146 $dbsubnet->{ips}->{$freeip} = {
147 hostname => $hostname,
148 description => $description,
149 };
150
151 write_db($db);
152 });
153 die "$@" if $@;
154
155 return "$freeip/$mask";
156 }
157
158 sub del_ip {
159 my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_;
160
161 my $cidr = $subnet->{cidr};
162 my $zone = $subnet->{zone};
163
164 cfs_lock_file($ipamdb_file, undef, sub {
165
166 my $db = read_db();
167 die "zone $zone don't exist in ipam db" if !$db->{zones}->{$zone};
168 my $dbzone = $db->{zones}->{$zone};
169 die "subnet $cidr don't exist in ipam db" if !$dbzone->{subnets}->{$cidr};
170 my $dbsubnet = $dbzone->{subnets}->{$cidr};
171
172 die "IP '$ip' does not exist in IPAM DB\n" if !defined($dbsubnet->{ips}->{$ip});
173 delete $dbsubnet->{ips}->{$ip};
174
175 write_db($db);
176 });
177 die "$@" if $@;
178 }
179
180 #helpers
181
182 sub read_db {
183 my $db = cfs_read_file($ipamdb_file);
184 return $db;
185 }
186
187 sub write_db {
188 my ($cfg) = @_;
189
190 my $json = to_json($cfg);
191 cfs_write_file($ipamdb_file, $json);
192 }
193
194 sub write_config {
195 my ($class, $filename, $cfg) = @_;
196
197 return $cfg;
198 }
199
200 sub parse_config {
201 my ($class, $filename, $raw) = @_;
202
203 $raw = '{}' if !defined($raw) ||$raw eq '';
204 my $cfg = from_json($raw);
205
206 return $cfg;
207 }
208
209 1;