]>
Commit | Line | Data |
---|---|---|
70b03506 AD |
1 | package PVE::Network::SDN::Ipams::NetboxPlugin; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use PVE::INotify; | |
6 | use PVE::Cluster; | |
7 | use PVE::Tools; | |
8 | ||
9 | use base('PVE::Network::SDN::Ipams::Plugin'); | |
10 | ||
11 | sub type { | |
12 | return 'netbox'; | |
13 | } | |
14 | ||
15 | sub properties { | |
16 | return { | |
17 | }; | |
18 | } | |
19 | ||
20 | sub options { | |
21 | ||
22 | return { | |
23 | url => { optional => 0}, | |
24 | token => { optional => 0 }, | |
25 | }; | |
26 | } | |
27 | ||
28 | # Plugin implementation | |
29 | ||
30 | sub add_subnet { | |
04f6db9a | 31 | my ($class, $plugin_config, $subnetid, $subnet, $noerr) = @_; |
70b03506 | 32 | |
e8736dac | 33 | my $cidr = $subnet->{cidr}; |
70b03506 AD |
34 | my $gateway = $subnet->{gateway}; |
35 | my $url = $plugin_config->{url}; | |
36 | my $token = $plugin_config->{token}; | |
37 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
38 | ||
39 | my $internalid = get_prefix_id($url, $cidr, $headers); | |
40 | ||
41 | #create subnet | |
42 | if (!$internalid) { | |
70b03506 AD |
43 | |
44 | my $params = { prefix => $cidr }; | |
45 | ||
46 | eval { | |
167dc03f | 47 | my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/prefixes/", $headers, $params); |
70b03506 AD |
48 | }; |
49 | if ($@) { | |
04f6db9a | 50 | die "error add subnet to ipam: $@" if !$noerr; |
70b03506 AD |
51 | } |
52 | } | |
53 | ||
54 | } | |
55 | ||
56 | sub del_subnet { | |
04f6db9a | 57 | my ($class, $plugin_config, $subnetid, $subnet, $noerr) = @_; |
70b03506 | 58 | |
e8736dac | 59 | my $cidr = $subnet->{cidr}; |
70b03506 AD |
60 | my $url = $plugin_config->{url}; |
61 | my $token = $plugin_config->{token}; | |
62 | my $gateway = $subnet->{gateway}; | |
63 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
64 | ||
65 | my $internalid = get_prefix_id($url, $cidr, $headers); | |
66 | return if !$internalid; | |
70b03506 | 67 | |
e8736dac | 68 | return; #fixme: check that prefix is empty exluding gateway, before delete |
70b03506 AD |
69 | |
70 | eval { | |
167dc03f | 71 | PVE::Network::SDN::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers); |
70b03506 AD |
72 | }; |
73 | if ($@) { | |
04f6db9a | 74 | die "error deleting subnet from ipam: $@" if !$noerr; |
70b03506 AD |
75 | } |
76 | ||
77 | } | |
78 | ||
79 | sub add_ip { | |
04f6db9a | 80 | my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, $noerr) = @_; |
70b03506 | 81 | |
e8736dac | 82 | my $mask = $subnet->{mask}; |
70b03506 AD |
83 | my $url = $plugin_config->{url}; |
84 | my $token = $plugin_config->{token}; | |
85 | my $section = $plugin_config->{section}; | |
86 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
e9365ab0 | 87 | $description .= " mac:$mac" if $mac && $description; |
70b03506 | 88 | |
ceb972a9 | 89 | my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description }; |
70b03506 AD |
90 | |
91 | eval { | |
167dc03f | 92 | PVE::Network::SDN::api_request("POST", "$url/ipam/ip-addresses/", $headers, $params); |
70b03506 AD |
93 | }; |
94 | ||
95 | if ($@) { | |
34c4c6d7 AD |
96 | if($is_gateway) { |
97 | die "error add subnet ip to ipam: ip $ip already exist: $@" if !is_ip_gateway($url, $ip, $headers) && !$noerr; | |
98 | } else { | |
99 | die "error add subnet ip to ipam: ip already exist: $@" if !$noerr; | |
100 | } | |
70b03506 AD |
101 | } |
102 | } | |
103 | ||
dd54b5a3 | 104 | sub update_ip { |
04f6db9a | 105 | my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway, $noerr) = @_; |
dd54b5a3 AD |
106 | |
107 | my $mask = $subnet->{mask}; | |
108 | my $url = $plugin_config->{url}; | |
109 | my $token = $plugin_config->{token}; | |
110 | my $section = $plugin_config->{section}; | |
111 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
112 | $description .= " mac:$mac" if $mac && $description; | |
113 | ||
114 | my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description }; | |
115 | ||
116 | my $ip_id = get_ip_id($url, $ip, $headers); | |
117 | die "can't find ip $ip in ipam" if !$ip_id; | |
118 | ||
119 | eval { | |
167dc03f | 120 | PVE::Network::SDN::api_request("PATCH", "$url/ipam/ip-addresses/$ip_id/", $headers, $params); |
dd54b5a3 AD |
121 | }; |
122 | if ($@) { | |
04f6db9a | 123 | die "error update ip $ip : $@" if !$noerr; |
dd54b5a3 AD |
124 | } |
125 | } | |
126 | ||
70b03506 | 127 | sub add_next_freeip { |
04f6db9a | 128 | my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description, $noerr) = @_; |
70b03506 | 129 | |
e8736dac AD |
130 | my $cidr = $subnet->{cidr}; |
131 | ||
70b03506 AD |
132 | my $url = $plugin_config->{url}; |
133 | my $token = $plugin_config->{token}; | |
134 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
135 | ||
136 | my $internalid = get_prefix_id($url, $cidr, $headers); | |
e9365ab0 | 137 | $description .= " mac:$mac" if $mac && $description; |
70b03506 | 138 | |
ceb972a9 | 139 | my $params = { dns_name => $hostname, description => $description }; |
70b03506 AD |
140 | |
141 | my $ip = undef; | |
142 | eval { | |
167dc03f | 143 | my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/prefixes/$internalid/available-ips/", $headers, $params); |
70b03506 AD |
144 | $ip = $result->{address}; |
145 | }; | |
146 | ||
147 | if ($@) { | |
04f6db9a | 148 | die "can't find free ip in subnet $cidr: $@" if !$noerr; |
70b03506 AD |
149 | } |
150 | ||
151 | return $ip; | |
152 | } | |
153 | ||
154 | sub del_ip { | |
04f6db9a | 155 | my ($class, $plugin_config, $subnetid, $subnet, $ip, $noerr) = @_; |
70b03506 AD |
156 | |
157 | return if !$ip; | |
158 | ||
159 | my $url = $plugin_config->{url}; | |
160 | my $token = $plugin_config->{token}; | |
161 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
162 | ||
163 | my $ip_id = get_ip_id($url, $ip, $headers); | |
164 | die "can't find ip $ip in ipam" if !$ip_id; | |
165 | ||
166 | eval { | |
167dc03f | 167 | PVE::Network::SDN::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers); |
70b03506 AD |
168 | }; |
169 | if ($@) { | |
04f6db9a | 170 | die "error delete ip $ip : $@" if !$noerr; |
70b03506 AD |
171 | } |
172 | } | |
173 | ||
174 | sub verify_api { | |
175 | my ($class, $plugin_config) = @_; | |
176 | ||
177 | my $url = $plugin_config->{url}; | |
178 | my $token = $plugin_config->{token}; | |
179 | my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; | |
180 | ||
181 | ||
182 | eval { | |
167dc03f | 183 | PVE::Network::SDN::api_request("GET", "$url/ipam/aggregates/", $headers); |
70b03506 AD |
184 | }; |
185 | if ($@) { | |
186 | die "Can't connect to netbox api: $@"; | |
187 | } | |
188 | } | |
189 | ||
190 | sub on_update_hook { | |
191 | my ($class, $plugin_config) = @_; | |
192 | ||
193 | PVE::Network::SDN::Ipams::NetboxPlugin::verify_api($class, $plugin_config); | |
194 | } | |
195 | ||
196 | #helpers | |
197 | ||
198 | sub get_prefix_id { | |
199 | my ($url, $cidr, $headers) = @_; | |
200 | ||
167dc03f | 201 | my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/prefixes/?q=$cidr", $headers); |
70b03506 AD |
202 | my $data = @{$result->{results}}[0]; |
203 | my $internalid = $data->{id}; | |
204 | return $internalid; | |
205 | } | |
206 | ||
207 | sub get_ip_id { | |
208 | my ($url, $ip, $headers) = @_; | |
167dc03f | 209 | my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers); |
70b03506 AD |
210 | my $data = @{$result->{results}}[0]; |
211 | my $ip_id = $data->{id}; | |
212 | return $ip_id; | |
213 | } | |
214 | ||
34c4c6d7 AD |
215 | sub is_ip_gateway { |
216 | my ($url, $ip, $headers) = @_; | |
217 | my $result = PVE::Network::SDN::api_request("GET", "$url/addresses/search/$ip", $headers); | |
218 | my $data = @{$result->{data}}[0]; | |
219 | my $description = $data->{description}; | |
220 | my $is_gateway = 1 if $description eq 'gateway'; | |
221 | return $is_gateway; | |
222 | } | |
70b03506 AD |
223 | |
224 | 1; | |
225 | ||
226 |