From dd54b5a3d44f1a7f2f27e2cda1df625f2807bba2 Mon Sep 17 00:00:00 2001 From: Alexandre Derumier Date: Tue, 5 Jan 2021 10:35:24 +0100 Subject: [PATCH] ipam: add update_ip used to update ip address options like hostname, mac,... don't allow to change ip address, as some ipam don't support it. Signed-off-by: Alexandre Derumier --- PVE/Network/SDN/Ipams/NetboxPlugin.pm | 23 ++++++++++++++ PVE/Network/SDN/Ipams/PVEPlugin.pm | 5 +++ PVE/Network/SDN/Ipams/PhpIpamPlugin.pm | 28 +++++++++++++++++ PVE/Network/SDN/Ipams/Plugin.pm | 17 ++++++++++ PVE/Network/SDN/Subnets.pm | 39 +++++++++++++++++++++++ PVE/Network/SDN/Vnets.pm | 43 ++++++++++++++++---------- 6 files changed, 138 insertions(+), 17 deletions(-) diff --git a/PVE/Network/SDN/Ipams/NetboxPlugin.pm b/PVE/Network/SDN/Ipams/NetboxPlugin.pm index 3c99218..f699daa 100644 --- a/PVE/Network/SDN/Ipams/NetboxPlugin.pm +++ b/PVE/Network/SDN/Ipams/NetboxPlugin.pm @@ -97,6 +97,29 @@ sub add_ip { } } +sub update_ip { + my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_; + + my $mask = $subnet->{mask}; + my $url = $plugin_config->{url}; + my $token = $plugin_config->{token}; + my $section = $plugin_config->{section}; + my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Authorization' => "token $token"]; + $description .= " mac:$mac" if $mac && $description; + + my $params = { address => "$ip/$mask", dns_name => $hostname, description => $description }; + + my $ip_id = get_ip_id($url, $ip, $headers); + die "can't find ip $ip in ipam" if !$ip_id; + + eval { + PVE::Network::SDN::Ipams::Plugin::api_request("PATCH", "$url/ipam/ip-addresses/$ip_id/", $headers, $params); + }; + if ($@) { + die "error update ip $ip : $@"; + } +} + sub add_next_freeip { my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description) = @_; diff --git a/PVE/Network/SDN/Ipams/PVEPlugin.pm b/PVE/Network/SDN/Ipams/PVEPlugin.pm index c02b6db..2527850 100644 --- a/PVE/Network/SDN/Ipams/PVEPlugin.pm +++ b/PVE/Network/SDN/Ipams/PVEPlugin.pm @@ -105,6 +105,11 @@ sub add_ip { die "$@" if $@; } +sub update_ip { + my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_; + return; +} + sub add_next_freeip { my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description) = @_; diff --git a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm index ab06f7b..b5ff38c 100644 --- a/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm +++ b/PVE/Network/SDN/Ipams/PhpIpamPlugin.pm @@ -122,6 +122,34 @@ sub add_ip { } } +sub update_ip { + my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_; + + my $cidr = $subnet->{cidr}; + my $url = $plugin_config->{url}; + my $token = $plugin_config->{token}; + my $section = $plugin_config->{section}; + my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'Token' => $token]; + + my $ip_id = get_ip_id($url, $ip, $headers); + die "can't find ip addresse in ipam" if !$ip_id; + + my $params = { + is_gateway => $is_gateway, + hostname => $hostname, + description => $description, + }; + $params->{mac} = $mac if $mac; + + eval { + PVE::Network::SDN::Ipams::Plugin::api_request("PATCH", "$url/addresses/$ip_id", $headers, $params); + }; + + if ($@) { + die "ipam: error update subnet ip $ip: $@"; + } +} + sub add_next_freeip { my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description) = @_; diff --git a/PVE/Network/SDN/Ipams/Plugin.pm b/PVE/Network/SDN/Ipams/Plugin.pm index 10e5212..39675f2 100644 --- a/PVE/Network/SDN/Ipams/Plugin.pm +++ b/PVE/Network/SDN/Ipams/Plugin.pm @@ -68,23 +68,40 @@ sub parse_section_header { sub add_subnet { my ($class, $plugin_config, $subnetid, $subnet) = @_; + + die "please implement inside plugin"; } sub del_subnet { my ($class, $plugin_config, $subnetid, $subnet) = @_; + + die "please implement inside plugin"; } sub add_ip { my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_; + die "please implement inside plugin"; +} + +sub update_ip { + my ($class, $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description, $is_gateway) = @_; + # only update ip attributes (mac,hostname,..). Don't change the ip addresses itself, as some ipam + # don't allow ip address change without del/add + + die "please implement inside plugin"; } sub add_next_freeip { my ($class, $plugin_config, $subnetid, $subnet, $hostname, $mac, $description) = @_; + + die "please implement inside plugin"; } sub del_ip { my ($class, $plugin_config, $subnetid, $subnet, $ip) = @_; + + die "please implement inside plugin"; } sub on_update_hook { diff --git a/PVE/Network/SDN/Subnets.pm b/PVE/Network/SDN/Subnets.pm index b752e2c..808c1bf 100644 --- a/PVE/Network/SDN/Subnets.pm +++ b/PVE/Network/SDN/Subnets.pm @@ -256,6 +256,45 @@ sub add_ip { } } +sub update_ip { + my ($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description) = @_; + + return if !$subnet || !$ip; + + my $ipaddr = new NetAddr::IP($ip); + $ip = $ipaddr->canon(); + + my $ipamid = $zone->{ipam}; + my $dns = $zone->{dns}; + my $dnszone = $zone->{dnszone}; + my $reversedns = $zone->{reversedns}; + my $reversednszone = &$get_reversedns_zone($subnetid, $subnet, $reversedns, $ip); + my $dnszoneprefix = $subnet->{dnszoneprefix}; + + $hostname .= ".$dnszoneprefix" if $dnszoneprefix; + + #verify dns zones before ipam + &$verify_dns_zone($dnszone, $dns); + &$verify_dns_zone($reversednszone, $reversedns); + + if ($ipamid) { + my $ipam_cfg = PVE::Network::SDN::Ipams::config(); + my $plugin_config = $ipam_cfg->{ids}->{$ipamid}; + my $plugin = PVE::Network::SDN::Ipams::Plugin->lookup($plugin_config->{type}); + eval { + $plugin->update_ip($plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $description); + }; + die $@ if $@; + } + + eval { + #add dns + &$add_dns_record($dnszone, $dns, $hostname, $ip); + #add reverse dns + &$add_dns_ptr_record($reversednszone, $dnszone, $reversedns, $hostname, $ip); + }; +} + sub del_ip { my ($zone, $subnetid, $subnet, $ip, $hostname) = @_; diff --git a/PVE/Network/SDN/Vnets.pm b/PVE/Network/SDN/Vnets.pm index d68ffab..7421adf 100644 --- a/PVE/Network/SDN/Vnets.pm +++ b/PVE/Network/SDN/Vnets.pm @@ -79,6 +79,22 @@ sub get_subnets { } +sub get_subnet_from_vnet_cidr { + my ($vnetid, $cidr) = @_; + + my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1); + my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid); + my $zoneid = $vnet->{zone}; + my $zone = PVE::Network::SDN::Zones::get_zone($zoneid); + + my ($ip, $mask) = split(/\//, $cidr); + die "ip address is not in cidr format" if !$mask; + + my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets); + + return ($zone, $subnetid, $subnet, $ip); +} + sub get_next_free_cidr { my ($vnetid, $hostname, $mac, $description, $ipversion) = @_; @@ -113,31 +129,24 @@ sub get_next_free_cidr { sub add_cidr { my ($vnetid, $cidr, $hostname, $mac, $description) = @_; - my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1); - my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid); - my $zoneid = $vnet->{zone}; - my $zone = PVE::Network::SDN::Zones::get_zone($zoneid); + my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr); + PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description); +} - my ($ip, $mask) = split(/\//, $cidr); - die "ip address is not in cidr format" if !$mask; - my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets); +sub update_cidr { + my ($vnetid, $cidr, $hostname, $mac, $description) = @_; - PVE::Network::SDN::Subnets::add_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description); + my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr); + PVE::Network::SDN::Subnets::update_ip($zone, $subnetid, $subnet, $ip, $hostname, $mac, $description); } sub del_cidr { my ($vnetid, $cidr, $hostname) = @_; - my $subnets = PVE::Network::SDN::Vnets::get_subnets($vnetid, 1); - my $vnet = PVE::Network::SDN::Vnets::get_vnet($vnetid); - my $zoneid = $vnet->{zone}; - my $zone = PVE::Network::SDN::Zones::get_zone($zoneid); - - my ($ip, $mask) = split(/\//, $cidr); - die "ip address is not in cidr format" if !$mask; - my ($subnetid, $subnet) = PVE::Network::SDN::Subnets::find_ip_subnet($ip, $mask, $subnets); - + my ($zone, $subnetid, $subnet, $ip) = PVE::Network::SDN::Vnets::get_subnet_from_vnet_cidr($vnetid, $cidr); PVE::Network::SDN::Subnets::del_ip($zone, $subnetid, $subnet, $ip, $hostname); } + + 1; -- 2.39.5