From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pve-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 8B0371FF15C for <inbox@lore.proxmox.com>; Wed, 19 Feb 2025 17:37:04 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 9A1BE2F754; Wed, 19 Feb 2025 17:37:00 +0100 (CET) Message-ID: <79735d83-c2b3-4932-8ea7-714821f57238@proxmox.com> Date: Wed, 19 Feb 2025 17:36:57 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> References: <20250108121529.5813-1-lou.lecrivain@wdz.de> <mailman.131.1736338546.441.pve-devel@lists.proxmox.com> Content-Language: en-US From: =?UTF-8?Q?Hannes_D=C3=BCrr?= <h.duerr@proxmox.com> In-Reply-To: <mailman.131.1736338546.441.pve-devel@lists.proxmox.com> X-SPAM-LEVEL: Spam detection results: 0 AWL 0.023 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pve-devel] SPAM: [PATCH pve-network v2 1/7] ipam: nautobot support initial commit X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pve-devel/> List-Post: <mailto:pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> On 1/8/25 13:15, Lou Lecrivain via pve-devel wrote: > +use base('PVE::Network::SDN::Ipams::NetboxPlugin'); why do you base the Plugin in NetboxPlugin at the beginning?> +sub get_ips_from_mac { > + my ($class, $plugin_config, $mac, $zoneid) = @_; $zoneid is unused in the function, this looks like a copy paste mistake On 1/8/25 13:15, Lou Lecrivain via pve-devel wrote: > This is the initial Nautobot plugin, based on the Netbox plugin > implementation. Signed-off-by: lou lecrivain <lou.lecrivain@wdz.de>--- > src/PVE/API2/Network/SDN/Ipams.pm | 1 + src/PVE/Network/SDN/Ipams.pm | > 3 + src/PVE/Network/SDN/Ipams/Makefile | 2 +- > src/PVE/Network/SDN/Ipams/NautobotPlugin.pm | 195 ++++++++++++++++++++ > 4 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 > src/PVE/Network/SDN/Ipams/NautobotPlugin.pm diff --git > a/src/PVE/API2/Network/SDN/Ipams.pm > b/src/PVE/API2/Network/SDN/Ipams.pm index 27ead02..8074512 100644 --- > a/src/PVE/API2/Network/SDN/Ipams.pm +++ > b/src/PVE/API2/Network/SDN/Ipams.pm @@ -12,6 +12,7 @@ use > PVE::Network::SDN::Ipams::Plugin; use > PVE::Network::SDN::Ipams::PVEPlugin; use > PVE::Network::SDN::Ipams::PhpIpamPlugin; use > PVE::Network::SDN::Ipams::NetboxPlugin; +use > PVE::Network::SDN::Ipams::NautobotPlugin; use PVE::Network::SDN::Dhcp; > use PVE::Network::SDN::Vnets; use PVE::Network::SDN::Zones; diff --git > a/src/PVE/Network/SDN/Ipams.pm b/src/PVE/Network/SDN/Ipams.pm index > c689b8f..2ecb75e 100644 --- a/src/PVE/Network/SDN/Ipams.pm +++ > b/src/PVE/Network/SDN/Ipams.pm @@ -12,11 +12,14 @@ use PVE::Network; > use PVE::Network::SDN::Ipams::PVEPlugin; use > PVE::Network::SDN::Ipams::NetboxPlugin; +use > PVE::Network::SDN::Ipams::NautobotPlugin; use > PVE::Network::SDN::Ipams::PhpIpamPlugin; use > PVE::Network::SDN::Ipams::Plugin; + > PVE::Network::SDN::Ipams::PVEPlugin->register(); > PVE::Network::SDN::Ipams::NetboxPlugin->register(); > +PVE::Network::SDN::Ipams::NautobotPlugin->register(); > PVE::Network::SDN::Ipams::PhpIpamPlugin->register(); > PVE::Network::SDN::Ipams::Plugin->init(); diff --git > a/src/PVE/Network/SDN/Ipams/Makefile > b/src/PVE/Network/SDN/Ipams/Makefile index 4e7d65f..75e5b9a 100644 --- > a/src/PVE/Network/SDN/Ipams/Makefile +++ > b/src/PVE/Network/SDN/Ipams/Makefile @@ -1,4 +1,4 @@ > -SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm > +SOURCES=Plugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm > NautobotPlugin.pm PERL5DIR=${DESTDIR}/usr/share/perl5 diff --git > a/src/PVE/Network/SDN/Ipams/NautobotPlugin.pm > b/src/PVE/Network/SDN/Ipams/NautobotPlugin.pm new file mode 100644 > index 0000000..69e7897 --- /dev/null +++ > b/src/PVE/Network/SDN/Ipams/NautobotPlugin.pm @@ -0,0 +1,195 @@ > +package PVE::Network::SDN::Ipams::NautobotPlugin; + +use strict; +use > warnings; +use PVE::INotify; +use PVE::Cluster; +use PVE::Tools; + > +use base('PVE::Network::SDN::Ipams::NetboxPlugin'); why do you base the Plugin in NetboxPlugin at the beginning? > + +sub type { + return 'nautobot'; +} + +sub properties { + return { + > namespace => { + type => 'string', + }, + }; +} + +sub options { + > return { + url => { optional => 0 }, + token => { optional => 0 }, + > namespace => { optional => 0 }, + }; +} + +sub default_ip_status { + > return 'Active'; +} + +sub default_headers { + my ($plugin_config) = > @_; + my $token = $plugin_config->{token}; + + return ['Content-Type' > => "application/json", 'Authorization' => "token $token", 'Accept' => > "application/json"]; +} + +# implem + +sub add_subnet { + my ($class, > $plugin_config, $subnetid, $subnet, $noerr) = @_; $subnetid is unused > + + my $cidr = $subnet->{cidr}; + my $gateway = $subnet->{gateway}; + > my $url = $plugin_config->{url}; + my $namespace = > $plugin_config->{namespace}; + my $headers = > default_headers($plugin_config); + + my $internalid = > PVE::Network::SDN::Ipams::NetboxPlugin::get_prefix_id($url, $cidr, > $headers); + + #create subnet + if (!$internalid) { + my $params = { > prefix => $cidr, namespace => $namespace, status => > default_ip_status()}; + + eval { + my $result = > PVE::Network::SDN::api_request("POST", "$url/ipam/prefixes/", > $headers, $params); + }; + if ($@) { + die "error adding subnet to > ipam: $@" if !$noerr; + } + } +} + +sub add_ip { + my ($class, > $plugin_config, $subnetid, $subnet, $ip, $hostname, $mac, $vmid, > $is_gateway, $noerr) = @_; $subnetid and $vmid are unused > + + my $mask = $subnet->{mask}; + my $url = $plugin_config->{url}; + > my $namespace = $plugin_config->{namespace}; + my $headers = > default_headers($plugin_config); + + my $description = undef; + if > ($is_gateway) { + $description = 'gateway' + } elsif ($mac) { + > $description = "mac:$mac"; + } + + my $params = { address => > "$ip/$mask", type => "dhcp", dns_name => $hostname, description => > $description, namespace => $namespace, status => default_ip_status()}; please break the line > + + eval { + PVE::Network::SDN::api_request("POST", > "$url/ipam/ip-addresses/", $headers, $params); + }; + + if ($@) { + > if($is_gateway) { + die "error adding subnet ip to ipam: ip $ip > already exists: $@" if > !PVE::Network::SDN::Ipams::NetboxPlugin::is_ip_gateway($url, $ip, > $headers) && !$noerr; + } else { + die "error adding subnet ip to > ipam: ip $ip already exists: $@" if !$noerr; + } + } +} + + +sub > update_ip { + my ($class, $plugin_config, $subnetid, $subnet, $ip, > $hostname, $mac, $vmid, $is_gateway, $noerr) = @_; $vmid is unused > + + my $mask = $subnet->{mask}; + my $url = $plugin_config->{url}; + > my $namespace = $plugin_config->{namespace}; + my $headers = > default_headers($plugin_config); + + my $description = undef; + if > ($is_gateway) { + $description = 'gateway' + } elsif ($mac) { + > $description = "mac:$mac"; + } + + my $params = { address => > "$ip/$mask", type => "dhcp", dns_name => $hostname, description => > $description, namespace => $namespace, status => default_ip_status()}; > + + my $ip_id = > PVE::Network::SDN::Ipams::NetboxPlugin::get_ip_id($url, $ip, > $headers); + die "can't find ip $ip in ipam" if !$ip_id; + + eval { + > PVE::Network::SDN::api_request("PATCH", > "$url/ipam/ip-addresses/$ip_id/", $headers, $params); + }; + if ($@) { > + die "error updating ip $ip: $@" if !$noerr; + } +} + + +sub > verify_api { + my ($class, $plugin_config) = @_; $class is unused > + + my $url = $plugin_config->{url}; + my $namespace = > $plugin_config->{namespace}; + my $headers = > default_headers($plugin_config); + + # check that the namespace exists > AND that default IP active status + # exists AND that we have indeed > API access + eval { + get_namespace_id($url, $namespace, $headers) // > die "namespace $namespace does not exist"; + get_status_id($url, > default_ip_status(), $headers) // die "default IP status ". > default_ip_status() . " not found"; + }; + if ($@) { + die "Can't use > nautobot api: $@"; + } +} + +sub get_ips_from_mac { + my ($class, > $plugin_config, $mac, $zoneid) = @_; $zoneid is unused in the function, this looks like a copy paste mistake > + + my $url = $plugin_config->{url}; + my $namespace = > $plugin_config->{namespace}; + my $headers = > default_headers($plugin_config); + + my $ip4 = undef; + my $ip6 = > undef; + + my $data = PVE::Network::SDN::api_request("GET", > "$url/ipam/ip-addresses/?q=$mac", $headers); + for my $ip > (@{$data->{results}}) { + if ($ip->{ip_version} == 4 && !$ip4) { + > ($ip4, undef) = split(/\//, $ip->{address}); + } + + if > ($ip->{ip_version} == 6 && !$ip6) { + ($ip6, undef) = split(/\//, > $ip->{address}); + } + } + + return ($ip4, $ip6); +} + +sub > on_update_hook { + my ($class, $plugin_config) = @_; + + > PVE::Network::SDN::Ipams::NautobotPlugin::verify_api($class, > $plugin_config); +} + +# helpers +sub get_namespace_id { + my ($url, > $namespace, $headers) = @_; + + my $result = > PVE::Network::SDN::api_request("GET", > "$url/ipam/namespaces/?q=$namespace", $headers); + my $data = > @{$result->{results}}[0]; + my $internalid = $data->{id}; + return > $internalid; +} + +sub get_status_id { + my ($url, $status, $headers) > = @_; + + my $result = PVE::Network::SDN::api_request("GET", > "$url/extras/statuses/?q=$status", $headers); + my $data = > @{$result->{results}}[0]; + my $internalid = $data->{id}; + return > $internalid; +} + +1; > -- 2.39.5 ______________________________________________ > pve-devel mailing list > pve-devel@lists.proxmox.comhttps://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel