ipam: netbox integration: add fingerprint option to api requests

Signed-off-by: Hannes Duerr <h.duerr@proxmox.com>
Tested-by: Stefan Hanreich <s.hanreich@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Hannes Duerr 2025-02-10 15:19:29 +01:00 committed by Thomas Lamprecht
parent bafa528fba
commit 3903003f31

View file

@ -18,10 +18,10 @@ sub properties {
} }
sub options { sub options {
return { return {
url => { optional => 0}, url => { optional => 0},
token => { optional => 0 }, token => { optional => 0 },
fingerprint => { optional => 1 },
}; };
} }
@ -34,9 +34,10 @@ sub add_subnet {
my $gateway = $subnet->{gateway}; my $gateway = $subnet->{gateway};
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $fingerprint = $plugin_config->{fingerprint};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $internalid = get_prefix_id($url, $cidr, $headers); my $internalid = get_prefix_id($url, $cidr, $headers, $fingerprint);
#create subnet #create subnet
if (!$internalid) { if (!$internalid) {
@ -44,7 +45,8 @@ sub add_subnet {
my $params = { prefix => $cidr }; my $params = { prefix => $cidr };
eval { eval {
my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/prefixes/", $headers, $params); my $result = PVE::Network::SDN::api_request(
"POST", "$url/ipam/prefixes/", $headers, $params, $fingerprint );
}; };
if ($@) { if ($@) {
die "error add subnet to ipam: $@" if !$noerr; die "error add subnet to ipam: $@" if !$noerr;
@ -60,15 +62,17 @@ sub del_subnet {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $gateway = $subnet->{gateway}; my $gateway = $subnet->{gateway};
my $fingerprint = $plugin_config->{fingerprint};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $internalid = get_prefix_id($url, $cidr, $headers); my $internalid = get_prefix_id($url, $cidr, $headers, $fingerprint);
return if !$internalid; return if !$internalid;
return; #fixme: check that prefix is empty exluding gateway, before delete return; #fixme: check that prefix is empty exluding gateway, before delete
eval { eval {
PVE::Network::SDN::api_request("DELETE", "$url/ipam/prefixes/$internalid/", $headers); PVE::Network::SDN::api_request(
"DELETE", "$url/ipam/prefixes/$internalid/", $headers, undef, $fingerprint);
}; };
if ($@) { if ($@) {
die "error deleting subnet from ipam: $@" if !$noerr; die "error deleting subnet from ipam: $@" if !$noerr;
@ -82,7 +86,7 @@ sub add_ip {
my $mask = $subnet->{mask}; my $mask = $subnet->{mask};
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $section = $plugin_config->{section}; my $fingerprint = $plugin_config->{fingerprint};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $description = undef; my $description = undef;
@ -95,14 +99,17 @@ sub add_ip {
my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description }; my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description };
eval { eval {
PVE::Network::SDN::api_request("POST", "$url/ipam/ip-addresses/", $headers, $params); PVE::Network::SDN::api_request(
"POST", "$url/ipam/ip-addresses/", $headers, $params, $fingerprint);
}; };
if ($@) { if ($@) {
if($is_gateway) { if ($is_gateway) {
die "error add subnet ip to ipam: ip $ip already exist: $@" if !is_ip_gateway($url, $ip, $headers) && !$noerr; if (!is_ip_gateway($url, $ip, $headers, $fingerprint) && !$noerr) {
} else { die "error add subnet ip to ipam: ip $ip already exist: $@";
die "error add subnet ip to ipam: ip already exist: $@" if !$noerr; }
} elsif (!$noerr) {
die "error add subnet ip to ipam: ip already exist: $@";
} }
} }
} }
@ -114,6 +121,7 @@ sub update_ip {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $section = $plugin_config->{section}; my $section = $plugin_config->{section};
my $fingerprint = $plugin_config->{fingerprint};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $description = undef; my $description = undef;
@ -125,11 +133,12 @@ sub update_ip {
my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description }; my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description };
my $ip_id = get_ip_id($url, $ip, $headers); my $ip_id = get_ip_id($url, $ip, $headers, $fingerprint);
die "can't find ip $ip in ipam" if !$ip_id; die "can't find ip $ip in ipam" if !$ip_id;
eval { eval {
PVE::Network::SDN::api_request("PATCH", "$url/ipam/ip-addresses/$ip_id/", $headers, $params); PVE::Network::SDN::api_request(
"PATCH", "$url/ipam/ip-addresses/$ip_id/", $headers, $params, $fingerprint);
}; };
if ($@) { if ($@) {
die "error update ip $ip : $@" if !$noerr; die "error update ip $ip : $@" if !$noerr;
@ -143,16 +152,18 @@ sub add_next_freeip {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $fingerprint = $plugin_config->{fingerprint};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $internalid = get_prefix_id($url, $cidr, $headers); my $internalid = get_prefix_id($url, $cidr, $headers, $fingerprint);
my $description = "mac:$mac" if $mac; my $description = "mac:$mac" if $mac;
my $params = { dns_name => $hostname, description => $description }; my $params = { dns_name => $hostname, description => $description };
eval { eval {
my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/prefixes/$internalid/available-ips/", $headers, $params); my $result = PVE::Network::SDN::api_request(
"POST", "$url/ipam/prefixes/$internalid/available-ips/", $headers, $params, $fingerprint);
my ($ip, undef) = split(/\//, $result->{address}); my ($ip, undef) = split(/\//, $result->{address});
return $ip; return $ip;
}; };
@ -168,14 +179,16 @@ sub add_range_next_freeip {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $fingerprint = $plugin_config->{fingerprint};
my $internalid = get_iprange_id($url, $range, $headers); my $internalid = get_iprange_id($url, $range, $headers, $fingerprint);
my $description = "mac:$data->{mac}" if $data->{mac}; my $description = "mac:$data->{mac}" if $data->{mac};
my $params = { dns_name => $data->{hostname}, description => $description }; my $params = { dns_name => $data->{hostname}, description => $description };
eval { eval {
my $result = PVE::Network::SDN::api_request("POST", "$url/ipam/ip-ranges/$internalid/available-ips/", $headers, $params); my $result = PVE::Network::SDN::api_request(
"POST", "$url/ipam/ip-ranges/$internalid/available-ips/", $headers, $params, $fingerprint);
my ($ip, undef) = split(/\//, $result->{address}); my ($ip, undef) = split(/\//, $result->{address});
print "found ip free $ip in range $range->{'start-address'}-$range->{'end-address'}\n" if $ip; print "found ip free $ip in range $range->{'start-address'}-$range->{'end-address'}\n" if $ip;
return $ip; return $ip;
@ -194,12 +207,13 @@ sub del_ip {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $fingerprint = $plugin_config->{fingerprint};
my $ip_id = get_ip_id($url, $ip, $headers); my $ip_id = get_ip_id($url, $ip, $headers, $fingerprint);
die "can't find ip $ip in ipam" if !$ip_id; die "can't find ip $ip in ipam" if !$ip_id;
eval { eval {
PVE::Network::SDN::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers); PVE::Network::SDN::api_request("DELETE", "$url/ipam/ip-addresses/$ip_id/", $headers, undef, $fingerprint);
}; };
if ($@) { if ($@) {
die "error delete ip $ip : $@" if !$noerr; die "error delete ip $ip : $@" if !$noerr;
@ -212,11 +226,14 @@ sub get_ips_from_mac {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $fingerprint = $plugin_config->{fingerprint};
my $ip4 = undef; my $ip4 = undef;
my $ip6 = undef; my $ip6 = undef;
my $data = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?description__ic=$mac", $headers); my $data = PVE::Network::SDN::api_request(
"GET", "$url/ipam/ip-addresses/?description__ic=$mac", $headers, undef, $fingerprint);
for my $ip (@{$data->{results}}) { for my $ip (@{$data->{results}}) {
if ($ip->{family}->{value} == 4 && !$ip4) { if ($ip->{family}->{value} == 4 && !$ip4) {
($ip4, undef) = split(/\//, $ip->{address}); ($ip4, undef) = split(/\//, $ip->{address});
@ -237,10 +254,10 @@ sub verify_api {
my $url = $plugin_config->{url}; my $url = $plugin_config->{url};
my $token = $plugin_config->{token}; my $token = $plugin_config->{token};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"];
my $fingerprint = $plugin_config->{fingerprint};
eval { eval {
PVE::Network::SDN::api_request("GET", "$url/ipam/aggregates/", $headers); PVE::Network::SDN::api_request("GET", "$url/ipam/aggregates/", $headers, undef, $fingerprint);
}; };
if ($@) { if ($@) {
die "Can't connect to netbox api: $@"; die "Can't connect to netbox api: $@";
@ -256,34 +273,40 @@ sub on_update_hook {
#helpers #helpers
sub get_prefix_id { sub get_prefix_id {
my ($url, $cidr, $headers) = @_; my ($url, $cidr, $headers, $fingerprint) = @_;
my $result = PVE::Network::SDN::api_request(
my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/prefixes/?q=$cidr", $headers); "GET", "$url/ipam/prefixes/?q=$cidr", $headers, undef, $fingerprint);
my $data = @{$result->{results}}[0]; my $data = @{$result->{results}}[0];
my $internalid = $data->{id}; my $internalid = $data->{id};
return $internalid; return $internalid;
} }
sub get_iprange_id { sub get_iprange_id {
my ($url, $range, $headers) = @_; my ($url, $range, $headers, $fingerprint) = @_;
my $result = PVE::Network::SDN::api_request(
my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-ranges/?start_address=$range->{'start-address'}&end_address=$range->{'end-address'}", $headers); "GET",
"$url/ipam/ip-ranges/?start_address=$range->{'start-address'}&end_address=$range->{'end-address'}",
$headers,
undef,
$fingerprint
);
my $data = @{$result->{results}}[0]; my $data = @{$result->{results}}[0];
my $internalid = $data->{id}; my $internalid = $data->{id};
return $internalid; return $internalid;
} }
sub get_ip_id { sub get_ip_id {
my ($url, $ip, $headers) = @_; my ($url, $ip, $headers, $fingerprint) = @_;
my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers); my $result = PVE::Network::SDN::api_request(
"GET", "$url/ipam/ip-addresses/?q=$ip", $headers, undef, $fingerprint);
my $data = @{$result->{results}}[0]; my $data = @{$result->{results}}[0];
my $ip_id = $data->{id}; my $ip_id = $data->{id};
return $ip_id; return $ip_id;
} }
sub is_ip_gateway { sub is_ip_gateway {
my ($url, $ip, $headers) = @_; my ($url, $ip, $headers, $fingerprint) = @_;
my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers); my $result = PVE::Network::SDN::api_request("GET", "$url/ipam/ip-addresses/?q=$ip", $headers, undef, $fingerprint);
my $data = @{$result->{data}}[0]; my $data = @{$result->{data}}[0];
my $description = $data->{description}; my $description = $data->{description};
my $is_gateway = 1 if $description eq 'gateway'; my $is_gateway = 1 if $description eq 'gateway';