use strict;
use warnings;
-use PVE::INotify;
-use PVE::Cluster;
-use PVE::Tools;
+
use JSON;
use Net::IP;
use NetAddr::IP qw(:lower);
+
+use PVE::Cluster;
+use PVE::INotify;
+use PVE::Tools;
+
use base('PVE::Network::SDN::Dns::Plugin');
sub type {
key => {
type => 'string',
},
- reversemaskv6 => {
- type => 'integer'
- },
+ reversemaskv6 => {
+ type => 'integer'
+ },
};
}
sub options {
-
return {
- url => { optional => 0},
- key => { optional => 0 },
- ttl => { optional => 1 },
- reversemaskv6 => { optional => 1, description => "force a different netmask for the ipv6 reverse zone name." },
-
+ url => { optional => 0},
+ key => { optional => 0 },
+ ttl => { optional => 1 },
+ reversemaskv6 => {
+ optional => 1,
+ description => "force a different netmask for the ipv6 reverse zone name.",
+ },
};
}
my $existing_rrset = get_zone_rrset($zonecontent, $fqdn);
my $final_records = [];
- my $foundrecord = undef;
- foreach my $record (@{$existing_rrset->{records}}) {
- if($record->{content} eq $ip) {
- $foundrecord = 1;
- next;
+ for my $record (@{$existing_rrset->{records}}) {
+ if ($record->{content} eq $ip) {
+ return; # the record already exist so return early
}
push @$final_records, $record;
}
- return if $foundrecord;
-
- my $record = { content => $ip,
- disabled => JSON::false,
- name => $fqdn,
- type => $type };
+ my $record = {
+ content => $ip,
+ disabled => JSON::false,
+ name => $fqdn,
+ type => $type,
+ };
push @$final_records, $record;
- my $rrset = { name => $fqdn,
- type => $type,
- ttl => $ttl,
- changetype => "REPLACE",
- records => $final_records };
-
-
- my $params = { rrsets => [ $rrset ] };
-
- eval {
- PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ my $params = {
+ rrsets => [{
+ name => $fqdn,
+ type => $type,
+ ttl => $ttl,
+ changetype => "REPLACE",
+ records => $final_records,
+ }],
};
- if ($@) {
- die "error add $fqdn to zone $zone: $@" if !$noerr;
- }
+ eval { PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params) };
+ die "error add $fqdn to zone $zone: $@" if $@ && !$noerr;
}
sub add_ptr_record {
my $type = "PTR";
- my $record = { content => $hostname,
- disabled => JSON::false,
- name => $reverseip,
- type => $type };
-
- my $rrset = { name => $reverseip,
- type => $type,
- ttl => $ttl,
- changetype => "REPLACE",
- records => [ $record ] };
-
-
- my $params = { rrsets => [ $rrset ] };
+ my $record = {
+ content => $hostname,
+ disabled => JSON::false,
+ name => $reverseip,
+ type => $type,
+ };
- eval {
- PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ my $params = {
+ rrsets => [{
+ name => $reverseip,
+ type => $type,
+ ttl => $ttl,
+ changetype => "REPLACE",
+ records => [ $record ],
+ }],
};
- if ($@) {
- die "error add $reverseip to zone $zone: $@" if !$noerr;
- }
+ eval { PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params) };
+ die "error add $reverseip to zone $zone: $@" if $@ && !$noerr;
}
sub del_a_record {
my $zonecontent = get_zone_content($plugin_config, $zone);
my $existing_rrset = get_zone_rrset($zonecontent, $fqdn);
- my $final_records = [];
- my $foundrecord = undef;
- foreach my $record (@{$existing_rrset->{records}}) {
- if ($record->{content} eq $ip) {
- $foundrecord = 1;
- next;
- }
- push @$final_records, $record;
- }
- return if !$foundrecord;
-
- my $rrset = {};
-
- if (scalar (@{$final_records}) > 0) {
- #if we still have other records, we rewrite them without removed ip
- $rrset = { name => $fqdn,
- type => $type,
- ttl => $existing_rrset->{ttl},
- changetype => "REPLACE",
- records => $final_records };
+ my $final_records = [ grep { $_->{content} ne $ip } $existing_rrset->{records}->@* ];
+ my $final_records_size = scalar($final_records->@*);
+ # early return if we didn't find our record (i.e., un/filtered record sets have the same size)
+ return if scalar($existing_rrset->{content}->@*) == $final_records_size;
- } else {
+ my $rrset = {
+ name => $fqdn,
+ type => $type,
+ };
- $rrset = { name => $fqdn,
- type => $type,
- changetype => "DELETE",
- records => [] };
+ if ($final_records_size > 0) {
+ # if we still have other records, we rewrite them with the $ip removed
+ $rrset->{ttl} = $existing_rrset->{ttl};
+ $rrset->{changetype} = "REPLACE";
+ $rrset->{records} = $final_records;
+ } else {
+ $rrset->{changetype} = "DELETE";
+ $rrset->{records} = [];
}
my $params = { rrsets => [ $rrset ] };
- eval {
- PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params);
- };
-
- if ($@) {
- die "error delete $fqdn from zone $zone: $@" if !$noerr;
- }
+ eval { PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params) };
+ die "error delete $fqdn from zone $zone: $@" if $@ && !$noerr;
}
sub del_ptr_record {
my $type = "PTR";
- my $rrset = { name => $reverseip,
- type => $type,
- changetype => "DELETE",
- records => [] };
-
- my $params = { rrsets => [ $rrset ] };
-
- eval {
- PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params);
+ my $params = {
+ rrsets => [{
+ name => $reverseip,
+ type => $type,
+ changetype => "DELETE",
+ records => [],
+ }],
};
- if ($@) {
- die "error delete $reverseip from zone $zone: $@" if !$noerr;
- }
+ eval { PVE::Network::SDN::api_request("PATCH", "$url/zones/$zone", $headers, $params) };
+ die "error delete $reverseip from zone $zone: $@" if $@ && !$noerr;
}
sub verify_zone {
my ($class, $plugin_config, $zone, $noerr) = @_;
- #verify that api is working
+ #verify that api is working
my $url = $plugin_config->{url};
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
- eval {
- PVE::Network::SDN::api_request("GET", "$url/zones/$zone?rrsets=false", $headers);
- };
-
- if ($@) {
- die "can't read zone $zone: $@" if !$noerr;
- }
+ eval { PVE::Network::SDN::api_request("GET", "$url/zones/$zone?rrsets=false", $headers) };
+ die "can't read zone $zone: $@" if $@ && !$noerr;
}
sub get_reversedns_zone {
} elsif ($ipblock1 == 10) {
$zone = "10.in-addr.arpa.";
}
-
+
} else {
- #public ipv4 : RIPE,ARIN,AFRNIC
- #. Delegations can be managed in IPv4 on bit boundaries (/8, /16 or /24s), and IPv6 networks can be managed on nibble boundaries (every 4 bits of the IPv6 address)
- #One or more /24 type zones need to be created if your address space has a prefix length between /17 and /24.
- # If your prefix length is between /16 and /9 you will have to request one or more delegations for /16 type zones.
+ # public ipv4 : RIPE,ARIN,AFRNIC
+ # Delegations can be managed in IPv4 on bit boundaries (/8, /16 or /24s), and IPv6
+ # networks can be managed on nibble boundaries (every 4 bits of the IPv6 address)
+ # One or more /24 type zones need to be created if your address space has a prefix
+ # length between /17 and /24.
+ # If your prefix length is between /16 and /9 you will have to request one or more
+ # delegations for /16 type zones.
if ($mask <= 24) {
$zone = "$ipblock3.$ipblock2.$ipblock1.in-addr.arpa.";
sub on_update_hook {
my ($class, $plugin_config) = @_;
- #verify that api is working
+ # verify that api is working
my $url = $plugin_config->{url};
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
- eval {
- PVE::Network::SDN::api_request("GET", "$url", $headers);
- };
-
- if ($@) {
- die "dns api error: $@";
- }
+ eval { PVE::Network::SDN::api_request("GET", "$url", $headers) };
+ die "dns api error: $@" if $@;
}
sub get_zone_content {
my ($plugin_config, $zone) = @_;
- #verify that api is working
+ # verify that api is working
my $url = $plugin_config->{url};
my $key = $plugin_config->{key};
my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
- my $result = undef;
- eval {
- $result = PVE::Network::SDN::api_request("GET", "$url/zones/$zone", $headers);
- };
+ my $result = eval { PVE::Network::SDN::api_request("GET", "$url/zones/$zone", $headers) };
+ die "can't read zone $zone: $@" if $@;
- if ($@) {
- die "can't read zone $zone: $@";
- }
return $result;
}
sub get_zone_rrset {
my ($zonecontent, $name) = @_;
- my $rrsetresult = undef;
- foreach my $rrset (@{$zonecontent->{rrsets}}) {
- next if $rrset->{name} ne $name;
- $rrsetresult = $rrset;
- last;
+ for my $rrset (@{$zonecontent->{rrsets}}) {
+ return $rrset if $rrset->{name} eq $name;
}
- return $rrsetresult;
+ return; # not found
}
1;