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 [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 480081FF164 for <inbox@lore.proxmox.com>; Fri, 9 May 2025 12:08:06 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0721B3A2C0; Fri, 9 May 2025 12:08:22 +0200 (CEST) To: <h.duerr@proxmox.com>, <pve-devel@lists.proxmox.com> Date: Fri, 9 May 2025 09:34:56 +0000 References: <20250506090041.53080-1-h.duerr@proxmox.com> <FR2PPF45D006270C594040B87F6E418E7548588A@FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM> <93bc24cc-2465-4ed2-b62f-d12305d5add3@proxmox.com> In-Reply-To: <93bc24cc-2465-4ed2-b62f-d12305d5add3@proxmox.com> MIME-Version: 1.0 Message-ID: <mailman.270.1746785301.394.pve-devel@lists.proxmox.com> List-Id: Proxmox VE development discussion <pve-devel.lists.proxmox.com> List-Post: <mailto:pve-devel@lists.proxmox.com> From: Lou Lecrivain via pve-devel <pve-devel@lists.proxmox.com> Precedence: list Cc: Lou.Lecrivain@wdz.de, jonatan.crystall@gwdg.de X-Mailman-Version: 2.1.29 X-BeenThere: pve-devel@lists.proxmox.com List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel>, <mailto:pve-devel-request@lists.proxmox.com?subject=subscribe> 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/> Reply-To: Proxmox VE development discussion <pve-devel@lists.proxmox.com> List-Help: <mailto:pve-devel-request@lists.proxmox.com?subject=help> Subject: Re: [pve-devel] [!!ACHTUNG extern!!] - Re: SPAM: [PATCH pve-network v4 1/2] ipam: add Nautobot plugin - range workaround questions Content-Type: multipart/mixed; boundary="===============3993655324738362196==" Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" <pve-devel-bounces@lists.proxmox.com> --===============3993655324738362196== Content-Type: message/rfc822 Content-Disposition: inline Return-Path: <Lou.Lecrivain@wdz.de> X-Original-To: pve-devel@lists.proxmox.com Delivered-To: pve-devel@lists.proxmox.com Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 7462ECCF0A for <pve-devel@lists.proxmox.com>; Fri, 9 May 2025 12:08:21 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 4D3773A292 for <pve-devel@lists.proxmox.com>; Fri, 9 May 2025 12:07:51 +0200 (CEST) Received: from FR6P281CU001.outbound.protection.outlook.com (mail-germanywestcentralazlp170100001.outbound.protection.outlook.com [IPv6:2a01:111:f403:c20c::1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (secp384r1) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for <pve-devel@lists.proxmox.com>; Fri, 9 May 2025 12:07:49 +0200 (CEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=c/w6Gi7WCS2g4WEQPW6NNgrkNMablbQ106NO02aMbX/jnh6jOZnJPIbYwJ5tNcVdatZpfEzJas4xxsXl3E8Nc0yPMyvf75X6WWGJE/LvOPxqVuMZVCe3+nGq8p2/PikQpR1mwFVD0ZloZ0jZhhtd1oE2K9Kk6V5/aO5DueCeqgOBrmYrnDNwEogLwYkQBxGaFlxGJQM67D7i408hgxby0N4GIbdqg2aBptLu9yEbbGmbFCHeEG71rmZBnlmx1U3lanwnbpJWmFm/QIZH+IP6liUx/FtDZpdh+0Be80QPA1BIXIumriM3XyIkd0FJ/TjXMrA41Whj5u1H8TVvoL/jVQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CMnUicBAv+gPsbLXe+X4Laa+enjBpr1uPlofW0hGX10=; b=bUoJUsNUTUQ1NgGEVH/exe9W9tStEHM487xV/KTbOlZnvp0KTL05xC51B4Ct3INo9YMNK/t6FJJj+i+9tfsGrdSOJNy4I9lctIMfJHHiSKlRRf7KetSOmp+tJOHQBClIp19yYB50rTcZw9xuQYHKbZ60huge9V5mwnKMp1WDpPbkOz+Y3fPM2QNPixJ1KbOwroOHKkDWYQv8DSL0eWjYgCbPky1Odbr8PJcKp8v4uo7AYgF0ftqr5SjvyGOzy3ajFjIcNtny3qfNCX4013kf8Ov5Wc5DlyQ63yYqDj1K/W1rs1quHc+y+S75zaAPT4j3wJ3v8q07ZvShYrBD/zA+7Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=wdz.de; dmarc=pass action=none header.from=wdz.de; dkim=pass header.d=wdz.de; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lswnetz.onmicrosoft.com; s=selector1-lswnetz-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CMnUicBAv+gPsbLXe+X4Laa+enjBpr1uPlofW0hGX10=; b=I09nsinBqdaIx7QhhQNRpwE1Gdz4segZfb+nktrwJ7eYBugrh7X1n748ccnryGVKEJYoF+qlnniIEoTxslZFRdMvZohMZPt9bOyH7e22VGN7XotLDXChsjAQuSwmiyUlNt5y1i+QTaU/Ju+8+t0HF+OQVgEJMCIJQzu/149PtwI= Received: from FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d18:2::2e) by FR6P281MB4223.DEUP281.PROD.OUTLOOK.COM (2603:10a6:d10:12b::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8722.25; Fri, 9 May 2025 09:34:57 +0000 Received: from FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM ([fe80::61d6:5538:7b39:dea1]) by FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM ([fe80::61d6:5538:7b39:dea1%5]) with mapi id 15.20.8699.026; Fri, 9 May 2025 09:34:56 +0000 From: <Lou.Lecrivain@wdz.de> To: <h.duerr@proxmox.com>, <pve-devel@lists.proxmox.com> CC: <jonatan.crystall@gwdg.de> Subject: RE: [!!ACHTUNG extern!!] - Re: SPAM: [PATCH pve-network v4 1/2] ipam: add Nautobot plugin - range workaround questions Thread-Topic: [!!ACHTUNG extern!!] - Re: SPAM: [PATCH pve-network v4 1/2] ipam: add Nautobot plugin - range workaround questions Thread-Index: AQHbvzDX9DivMuFErk+F8/u1jerq8LPJ/zQAgAAMAos= Date: Fri, 9 May 2025 09:34:56 +0000 Message-ID: <FR2PPF45D0062706987369A6C23E8E8DF74858AA@FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM> References: <20250506090041.53080-1-h.duerr@proxmox.com> <FR2PPF45D006270C594040B87F6E418E7548588A@FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM> <93bc24cc-2465-4ed2-b62f-d12305d5add3@proxmox.com> In-Reply-To: <93bc24cc-2465-4ed2-b62f-d12305d5add3@proxmox.com> Accept-Language: fr-FR, en-US Content-Language: fr-FR X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=wdz.de; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: FR2PPF45D006270:EE_|FR6P281MB4223:EE_ x-ms-office365-filtering-correlation-id: 34e3df92-8fcb-458c-9e07-08dd8edcc2bb x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0;ARA:13230040|376014|366016|1800799024|10070799003|38070700018; x-microsoft-antispam-message-info: =?iso-8859-1?Q?pEJN1TgD7nO4T7DsZcwONDkDOYVuZnmhRvmmeIZeBYU6np5n5l1gooaGOK?= =?iso-8859-1?Q?Pr9SmCvfnA4o/m7Ivu6XdloaxolM/OMcCUxLZq+ZXznFPEjRFqN8BeyN32?= =?iso-8859-1?Q?ib79YaERX+W3rKVnOy00cQ0dcBPMQaaOPIoikPJ4amrZeNi0dzdwwsqf77?= =?iso-8859-1?Q?dpTz/EENVyT+JY7lnrBMTOe6801ddyF/ACU2Hed9/GwB0mnkIqpB6dhce9?= =?iso-8859-1?Q?yYdSR/psMp450F/mKcDQPO4gxfNpjIjEfREqEijm1/n2iQkjm48tpvl4cy?= =?iso-8859-1?Q?/v4KU/97cY3DC35vY6z83AwGF6DQdZtuAsTk5e+2Oj177Qn2KfZTagnQ8E?= =?iso-8859-1?Q?w1hnacTXuYy4hwgsdezxeHUoqG9gAx9n6qzzz6JjnexQpo6aW98RV0hDRQ?= =?iso-8859-1?Q?SMOpR7P9uSw2eRFiqU/q++Dk2fvL6D9jXkhP2l4Y2NwNfSyRcMNNeHyrCK?= =?iso-8859-1?Q?w8QntgQRr15lv/mJRi9Z56vZZelTgKu/XOHlH8sQktgFueKeBx8N4f7eKf?= =?iso-8859-1?Q?QI5NX2LSMKMZ/aO1pW8BOkiiFEiMvnR0ixcWn6+fmbfcXfNB/zZNZnwFYu?= =?iso-8859-1?Q?KWzxxugzLWfsSj33PCEEhx4KGQoEzEccpzVnLdd986TMv/bAfN0WIfWBo9?= =?iso-8859-1?Q?7rePb4UciPv/le6H1UUTHHX7yFqWzWHYSjQVSQyC7ZBeQAY2VVXCvmSBKY?= =?iso-8859-1?Q?KWtkdz4wxIlne1RSq4UgxUW68fCJKpACAggITO2Db9bWKSq1fT3QvtbRAL?= =?iso-8859-1?Q?C6hHYfwyrh90OBtM+cxmdCyBtu7TgxBpVcfWEPR+V/N68J3CUH0j5nGttO?= =?iso-8859-1?Q?Qfy+Ozba37UKYnv/sSo9PmZD7h6qfGP9zufPuNxkxss1zHfHhx95WBAJy3?= =?iso-8859-1?Q?sKq2Pyah35EWFXd8+bhYhi/uALi4vVbo6P5dT3m9qXM8RWz0sTorkMmRi2?= =?iso-8859-1?Q?qwa03FoqwifiwJbAYZUY9SxcwQfD4MbhRlA/nTZU/jHxDMl3ZCYe50W15B?= =?iso-8859-1?Q?foK80HZuU8CN25//vbHOJWJhHJCgBc0HmpHW6bR2t3BLjWdn9ewrYcRpuR?= =?iso-8859-1?Q?ullwRfuxbzWSzMBaFbrdPl3dlY3L5NJNx1PScxFh9YYibZO9S/y3n8eeYp?= =?iso-8859-1?Q?dM35UdiT/gxemrxIx3cnGp+cvb3le5yywDkaHJ6dkAUyaOKCF4PKgygkPz?= =?iso-8859-1?Q?B5zW3WgpmO6YUFYC5Kd0R26lDGoyZRkFJ20w77IqYx6/5Ts/UiqasK0DxA?= =?iso-8859-1?Q?0tjvG8+r/TufhkGrIlaRDQHmlv3mmgLYI8fSUqZnNxtYzykrzsh0BYlLrI?= =?iso-8859-1?Q?l1ONm+Bdl8ajul9b2/tRsBqdiuXSrJcieDCGVGCU6glqfdjysGrdugahlO?= =?iso-8859-1?Q?KImQT9FmLDX24N9SdkM3g+hoftzSiUDnmlXzj3fOWBtEYNxZ9nFALmXEwt?= =?iso-8859-1?Q?eqdRPzIZA/MMZh43QqxoVsuv2O5J3iOn1K2hPjqUM29RjeDhnIJUKjdt3S?= =?iso-8859-1?Q?E=3D?= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024)(10070799003)(38070700018);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?iso-8859-1?Q?xMBzNP6cwYwCrJy8Tvx3Rzm5jDH5ytPS25GU3vHnj7Yy3BFCUHzGymzH+d?= =?iso-8859-1?Q?YZ3QbElhYn3UHWgjhPIJ4o4/fp7iOwpxcQy+FSPTMNok1qspmzc0U8xTzo?= =?iso-8859-1?Q?XNNbLZFiWZ2QleQKCSfYqrJOsL5BJwm0hddSBiLGByd7p0YybnISUJBDo8?= =?iso-8859-1?Q?HUP38pvaNluIycz/HOucghInKtHFwLDoJlGyMYKoKP6x9XqimpfTXMAwkr?= =?iso-8859-1?Q?2243dG6MFBtX1/ETkuJNdJ6KWUN8T2yq1LBc6pm0z/wCAVm8htNU4Kt0nS?= =?iso-8859-1?Q?dWRvn1p5lUXQj5fHf37uLFviddJLMeGmAfL4SG3K8MAnEQ2eDV32HvEXcM?= =?iso-8859-1?Q?meQn2ffjfpamhFp0jflXpFuSsG0e9hv2DKf2/aK1AnZxQvk2apKbw6cp5D?= =?iso-8859-1?Q?aG2e4HeDYntU0cjKUNBBGVDESiEazDiYiIT/RtjPYQIg8tRFUPWgStXvWB?= =?iso-8859-1?Q?972cfyK3cZWOJTFQx22d2/F+xkWnqM6GKKUQrmOTkOZfGtBsyt/GwfNbRx?= =?iso-8859-1?Q?a07SY2uH5wJxtNGnFvU+cBzXo293CaJuKOLAC49Ky75WGyqHz06lrpo+Hc?= =?iso-8859-1?Q?B2gDEkmGHGB1q9SUtc/zQWDnrPI1AmizsUKXVDPczgzR+JrswyC9Yplouo?= =?iso-8859-1?Q?Kbk+GaXkclA1B+3xoj1suGSHDA2xZuzNARFRarwrneGwbOFYNfA/j+knXA?= =?iso-8859-1?Q?dlfsX96opA+FuNkN2UnALHwEtoTwGJdd5IBAdq3BuLiRHgX3wu54VrbKmk?= =?iso-8859-1?Q?SZo/eKspAAp8miWmXR5DdPQFklojCzzTsRZI7wigGKOLdhXbFLM8vB1KU3?= =?iso-8859-1?Q?qNcIBgfxEmzW+T7PyUGJEAPbSrh6yYgWESX8Qtu+ZGRz6YYQTzRD4a7n8n?= =?iso-8859-1?Q?qsO07AzxUVXPAH7YgRMw+ai2TbVFzbIITpnY7he5xppObGBITpS/ObGJn2?= =?iso-8859-1?Q?/ausqDwkuxmR7s6uptMehF6R6EeqFNEeACFjDZqNIIfwyECiKWtDAi0sGD?= =?iso-8859-1?Q?tGMFX3CrTq9mGzces71c4yyIZHRleatv0/SldR4GnNFYLBTanhToq8Qs1A?= =?iso-8859-1?Q?4Yph2geyvo01J6soavPFjzgUn/B5maDU1ctO3EFmIzHqur8zUMJ1yiqnEf?= =?iso-8859-1?Q?xK1A1aLUSGEInWTzwk/YC5ZPNwsd2VKUYX4ndGDBS0yII/oULOhnCcPvN2?= =?iso-8859-1?Q?rzkGj6hItJNW5ycHzUcIrCSsPN6yhY9aGE0ee+mlDn3nnZqRdG2TKrg07o?= =?iso-8859-1?Q?1KFt1eFYGgs3rc6vzLri5D4yV/V/3020hUzpxXtF44QQO3kA75HKYk0wmB?= =?iso-8859-1?Q?qqgH4AEKE4kfD0jKXlwy243ilWKOKZi8Ia3zs0GC1Swyk4KMxXkQzJ4HJ+?= =?iso-8859-1?Q?5IxrpoMlT211rnecZ06eDCCAhSdPe3n4QqfnG9H/sVnAJsfmULXpj0D8Fe?= =?iso-8859-1?Q?EvRmubFOOhQ07RmntGZMsxT/r+LsamTIc+N7tQ1Ii9Tmv2+ZcnOU/BbF0s?= =?iso-8859-1?Q?4eCWfZAhkL3EYhFvuetp//48p/P+EvDAXHGKpDkfi0jJSPsPEbhs6Daq2H?= =?iso-8859-1?Q?O563Cwkr2a1ccHvSbnMzfPSFtsjgUqJ8LUryo/uBEQkJaisffJMYnGuTNp?= =?iso-8859-1?Q?io7qut+2VCc+qjDZclaJiA1N572LGpVRVT?= Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: wdz.de X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: FR2PPF45D006270.DEUP281.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-Network-Message-Id: 34e3df92-8fcb-458c-9e07-08dd8edcc2bb X-MS-Exchange-CrossTenant-originalarrivaltime: 09 May 2025 09:34:56.7040 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: d1b757c4-c391-4d47-b0de-c8365891bd6b X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: kaGgZ4rHl/1gTSK4a+/ZirS5YUBcjU9Y798HIA+plUHg0M3ZtRD2PwAcdYZhLQRsa6NVQi7VTzAGJvgTKk8tvQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: FR6P281MB4223 X-SPAM-LEVEL: Spam detection results: 1 ARC_SIGNED 0.001 Message has a ARC signature ARC_VALID 0.001 Message has a valid ARC signature AWL -0.550 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DMARC_PASS -0.1 DMARC pass policy FORGED_SPF_HELO 1 - KAM_ASCII_DIVIDERS 0.8 Email that uses ascii formatting dividers and possible spam tricks KAM_MAILER 2 Automated Mailer Tag Left in Email SPF_HELO_PASS -0.001 SPF: HELO matches SPF record T_SPF_PERMERROR 0.01 SPF: test of record failed (permerror) URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [phpipamplugin.pm,netboxplugin.pm,pveplugin.pm,lswnetz.onmicrosoft.com,plugin.pm,ipams.pm,nautobotplugin.pm,networktocode.com] Re,=0A= =0A= Ok, thanks for clarifying. Indeed the offset parameter is ineffective (I ha= ve looked at the Nautobot code this morning). Tbqh I don't really like havi= ng to create then delete an object in Nautobot for this, but I guess there'= s no other way, given the limitations we're faced with.=0A= =0A= Alternatively as a middle ground (and I think this would be much quicker th= an implementing IP ranges in Nautobot), we could implement the offset param= eter in Nautobot and change the original workaround code to fit this, and t= hen require a minimal Nautobot version (for ranges or the whole plugin). Bu= t IMO this doesn't mean we can't merge this. We could change it afterwards.= =0A= =0A= I have no other remarks. Thanks again for your work.=0A= =0A= BR=0A= Lou=0A= ________________________________________=0A= De :=A0Hannes Duerr <h.duerr@proxmox.com>=0A= Envoy=E9 :=A0vendredi 9 mai 2025 10:46=0A= =C0 :=A0Lecrivain, Lou (WDZ) <Lou.Lecrivain@wdz.de>; pve-devel@lists.proxmo= x.com <pve-devel@lists.proxmox.com>=0A= Objet :=A0[!!ACHTUNG extern!!] - Re: SPAM: [PATCH pve-network v4 1/2] ipam:= add Nautobot plugin - range workaround questions=0A= =A0=0A= =0A= On 5/7/25 11:17, Lou.Lecrivain@wdz.de=A0wrote:=0A= Hannes,=0A= =0A= Thank you for helping with getting the Netbox plugin in good shape, it's ap= preciated, really :)=0A= =0A= I just have two questions regarding the lack of range support in Nautobot:= =0A= - Was there an issue with the original workaround code? I find this one way= more complex,=0A= =A0 but also I guess I could've missed some corner case(s).=0A= Yes, there was the problem that the old version would possibly output=0A= invalid free IP addresses if the IP range did not start directly at=0A= the beginning of the prefix. Assuming you have 192.168.0.0/16 as=0A= prefix, all IP addresses are still free and you want free ip addresses=0A= in the range 192.168.6.1/16 - 192.168.7.255/16 then the old=0A= implementation would still have received the addresses=0A= 192.168.0.[0-50]/24 from the API. This could have been remedied by an=0A= offset parameter, but this is not implemented for the API endpoint.=0A= Increasing the `limit` is also not an option, as there is a maximum=0A= limit of 1000 and you can still run into problems.=0A= I have therefore opted for the current implementation.=0A= =0A= =0A= - What happens if we use a prefix with a CIDR greater than /24 in IPv4 or /= 120 in IPv6?=0A= =A0 Does not being able to slice it means that ranges with small prefixes = such as these=0A= =A0 would be forbidden/not working?=0A= No, all prefixes should work. For smaller prefixes such as /26, we=0A= still create a /24 pool and search it for free ips, but then check=0A= again whether the ip is actually in the desired range in /26.=0A= =0A= BR=0A= Lou=0A= ________________________________________=0A= De :=A0Hannes Duerr <h.duerr@proxmox.com>=0A= Envoy=E9 :=A0mardi 6 mai 2025 11:00=0A= =C0 :=A0pve-devel@lists.proxmox.com <pve-devel@lists.proxmox.com>=0A= Cc=A0:=A0Hannes Duerr <h.duerr@proxmox.com>; Lecrivain, Lou (WDZ) <Lou.Lecr= ivain@wdz.de>=0A= Objet :=A0[!!ACHTUNG extern!!] - [PATCH pve-network v4 1/2] ipam: add Nauto= bot plugin=0A= =A0=0A= Nautobot is a network source of truth [0] and as such this plugin offers=0A= the possibility to automatically enter IP addresses and subnets=0A= (prefixes in Nautobot jargon) into Nautobot as soon as they are created=0A= in Proxmox VE.=0A= =0A= Limitations:=0A= * The IPAM plugin currently does not recognize whether VMs/CTs are=0A= =A0 active/online and initially sets the status to Active but when the=0A= =A0 VMs/CTs are switched off the status is not deactivated.=0A= * Nautobot does not support ranges that can be searched for free ip=0A= =A0 addresses, so we map as many pool prefixes that we search until we=0A= =A0 have searched the entire range for free ip addresses=0A= * Nautobot has the possibility to map DNS names to IP addresses.=0A= =A0 However, since we have no standardized way to set the DNS names in=0A= =A0 Proxmox VE (for containers the container name in Proxmox VE is set as= =0A= =A0 the host name in the container, but this is not possible for VMs) we=0A= =A0 refrain from setting a DNS name at the moment.=0A= * Nautobot does not have a field in IP address objects for a MAC address=0A= =A0 or to mark them as gateway, so we write this in the comment.=0A= =0A= [0] https://networktocode.com/nautobot/=0A= =0A= Co-authored-by: lou lecrivain <lou.lecrivain@wdz.de>=0A= Signed-off-by: Hannes Duerr <h.duerr@proxmox.com>=0A= ---=0A= =0A= Notes:=0A= =A0=A0=A0 Changes from v3 -> v4:=0A= =A0=A0=A0 * Merge the check for empty prefixes/subnets into this commit=0A= =A0=A0=A0 * Create nautobot_api_request to unify API calls=0A= =A0=A0=A0 * add update_subnet function=0A= =A0=A0=A0 * fix add_range_next_freeip=0A= =A0=A0=A0 * fix and unify error handling=0A= =A0=A0=A0 * Fix perl style=0A= =0A= =A0src/PVE/API2/Network/SDN/Ipams.pm=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0=A0 = 1 +=0A= =A0src/PVE/Network/SDN/Ipams.pm=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0 |=A0=A0 3 +=0A= =A0src/PVE/Network/SDN/Ipams/Makefile=A0=A0=A0=A0=A0=A0=A0=A0=A0 |=A0=A0 2 = +-=0A= =A0src/PVE/Network/SDN/Ipams/NautobotPlugin.pm | 513 ++++++++++++++++++++= =0A= =A04 files changed, 518 insertions(+), 1 deletion(-)=0A= =A0create mode 100644 src/PVE/Network/SDN/Ipams/NautobotPlugin.pm=0A= =0A= diff --git a/src/PVE/API2/Network/SDN/Ipams.pm b/src/PVE/API2/Network/SDN/I= pams.pm=0A= index 27ead02..8074512 100644=0A= --- a/src/PVE/API2/Network/SDN/Ipams.pm=0A= +++ b/src/PVE/API2/Network/SDN/Ipams.pm=0A= @@ -12,6 +12,7 @@ use PVE::Network::SDN::Ipams::Plugin;=0A= =A0use PVE::Network::SDN::Ipams::PVEPlugin;=0A= =A0use PVE::Network::SDN::Ipams::PhpIpamPlugin;=0A= =A0use PVE::Network::SDN::Ipams::NetboxPlugin;=0A= +use PVE::Network::SDN::Ipams::NautobotPlugin;=0A= =A0use PVE::Network::SDN::Dhcp;=0A= =A0use PVE::Network::SDN::Vnets;=0A= =A0use PVE::Network::SDN::Zones;=0A= diff --git a/src/PVE/Network/SDN/Ipams.pm b/src/PVE/Network/SDN/Ipams.pm=0A= index c689b8f..2ecb75e 100644=0A= --- a/src/PVE/Network/SDN/Ipams.pm=0A= +++ b/src/PVE/Network/SDN/Ipams.pm=0A= @@ -12,11 +12,14 @@ use PVE::Network;=0A= =A0=0A= =A0use PVE::Network::SDN::Ipams::PVEPlugin;=0A= =A0use PVE::Network::SDN::Ipams::NetboxPlugin;=0A= +use PVE::Network::SDN::Ipams::NautobotPlugin;=0A= =A0use PVE::Network::SDN::Ipams::PhpIpamPlugin;=0A= =A0use PVE::Network::SDN::Ipams::Plugin;=0A= =A0=0A= +=0A= =A0PVE::Network::SDN::Ipams::PVEPlugin->register();=0A= =A0PVE::Network::SDN::Ipams::NetboxPlugin->register();=0A= +PVE::Network::SDN::Ipams::NautobotPlugin->register();=0A= =A0PVE::Network::SDN::Ipams::PhpIpamPlugin->register();=0A= =A0PVE::Network::SDN::Ipams::Plugin->init();=0A= =A0=0A= diff --git a/src/PVE/Network/SDN/Ipams/Makefile b/src/PVE/Network/SDN/Ipams= /Makefile=0A= index 4e7d65f..75e5b9a 100644=0A= --- a/src/PVE/Network/SDN/Ipams/Makefile=0A= +++ b/src/PVE/Network/SDN/Ipams/Makefile=0A= @@ -1,4 +1,4 @@=0A= -SOURCES=3DPlugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm=0A= +SOURCES=3DPlugin.pm PhpIpamPlugin.pm NetboxPlugin.pm PVEPlugin.pm Nautobot= Plugin.pm=0A= =A0=0A= =A0=0A= =A0PERL5DIR=3D${DESTDIR}/usr/share/perl5=0A= diff --git a/src/PVE/Network/SDN/Ipams/NautobotPlugin.pm b/src/PVE/Network/= SDN/Ipams/NautobotPlugin.pm=0A= new file mode 100644=0A= index 0000000..2897025=0A= --- /dev/null=0A= +++ b/src/PVE/Network/SDN/Ipams/NautobotPlugin.pm=0A= @@ -0,0 +1,513 @@=0A= +package PVE::Network::SDN::Ipams::NautobotPlugin;=0A= +=0A= +use strict;=0A= +use warnings;=0A= +use PVE::INotify;=0A= +use PVE::Cluster;=0A= +use PVE::Tools;=0A= +use NetAddr::IP;=0A= +use Net::Subnet qw(subnet_matcher);=0A= +=0A= +use base('PVE::Network::SDN::Ipams::Plugin');=0A= +=0A= +sub type {=0A= +=A0=A0=A0 return 'nautobot';=0A= +}=0A= +=0A= +sub properties {=0A= +=A0=A0=A0 return {=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 type =3D> 'string',=0A= +=A0=A0=A0=A0=A0=A0 },=0A= +=A0=A0=A0 };=0A= +}=0A= +=0A= +sub options {=0A= +=A0=A0=A0 return {=0A= +=A0=A0=A0=A0=A0=A0 url =3D> { optional =3D> 0 },=0A= +=A0=A0=A0=A0=A0=A0 token =3D> { optional =3D> 0 },=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> { optional =3D> 0 },=0A= +=A0=A0=A0=A0=A0=A0 fingerprint =3D> { optional =3D> 1 },=0A= +=A0=A0=A0 };=0A= +}=0A= +=0A= +sub default_ip_status {=0A= +=A0=A0=A0 return 'Active';=0A= +}=0A= +=0A= +sub nautobot_api_request {=0A= +=A0=A0=A0 my ($config, $method, $path, $params) =3D @_;=0A= +=0A= +=A0=A0=A0 return PVE::Network::SDN::api_request(=0A= +=A0=A0=A0=A0=A0=A0 $method,=0A= +=A0=A0=A0=A0=A0=A0 "$config->{url}${path}",=0A= +=A0=A0=A0=A0=A0=A0 [=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 'Content-Type' =3D> 'application/json; char= set=3DUTF-8',=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 'Authorization' =3D> "token $config->{token= }",=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 'Accept' =3D> "application/json"=0A= +=A0=A0=A0=A0=A0=A0 ],=0A= +=A0=A0=A0=A0=A0=A0 $params,=0A= +=A0=A0=A0=A0=A0=A0 $config->{fingerprint},=0A= +=A0=A0=A0 );=0A= +}=0A= +=0A= +sub add_subnet {=0A= +=A0=A0=A0 my ($class, $config, undef, $subnet, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $cidr =3D $subnet->{cidr};=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $internalid =3D get_prefix_id($config, $cidr, $noerr);=0A= +=A0=A0=A0 if ($internalid) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not add the subnet $subnet because it alread= y exists in nautobot\n"=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $params =3D {=0A= +=A0=A0=A0=A0=A0=A0 prefix =3D> $cidr,=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> $namespace,=0A= +=A0=A0=A0=A0=A0=A0 status =3D> default_ip_status()=0A= +=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "POST", "/ipam/prefixes/"= , $params);=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error adding the subnet $subnet to nautobot $@\n";= =0A= +=A0=A0=A0 }=0A= +}=0A= +=0A= +sub update_subnet {=0A= +=A0=A0=A0 my ($class, $plugin_config, $subnetid, $subnet, $old_subnet, $no= err) =3D @_;=0A= +=A0=A0=A0 # dhcp ranges are not supported in nautobot so we don't have to = update them=0A= +}=0A= +=0A= +sub del_subnet {=0A= +=A0=A0=A0 my ($class, $config, $subnetid, $subnet, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $cidr =3D $subnet->{cidr};=0A= +=0A= +=A0=A0=A0 my $internalid =3D get_prefix_id($config, $cidr, $noerr);=0A= +=A0=A0=A0 if (!$internalid) {=0A= +=A0=A0=A0=A0=A0=A0 warn("could not find delete the subnet $cidr because it= does not exist in nautobot\n");=0A= +=A0=A0=A0=A0=A0=A0 return;=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 if (!subnet_is_deletable($config, $subnetid, $subnet, $internali= d, $noerr)) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not delete the subnet $cidr, it still contai= ns ip addresses!\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 # delete associated gateway IP addresses=0A= +=A0=A0=A0 $class->empty_subnet( $config, $subnetid, $subnet, $internalid, = $noerr);=0A= +=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "DELETE", "/ipam/prefixes= /$internalid/");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error deleting subnet from nautobot: $@\n";=0A= +=A0=A0=A0 }=0A= +=A0=A0=A0 return 1;=0A= +}=0A= +=0A= +sub add_ip {=0A= +=A0=A0=A0 my ($class, $config, undef, $subnet, $ip, $hostname, $mac, undef= ,=0A= +=A0=A0=A0=A0=A0=A0 $is_gateway, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $mask =3D $subnet->{mask};=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $description =3D undef;=0A= +=A0=A0=A0 if ($is_gateway) {=0A= +=A0=A0=A0=A0=A0=A0 $description =3D 'gateway';=0A= +=A0=A0=A0 } elsif ($mac) {=0A= +=A0=A0=A0=A0=A0=A0 $description =3D "mac:$mac";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $params =3D {=0A= +=A0=A0=A0=A0=A0=A0 address =3D> "$ip/$mask",=0A= +=A0=A0=A0=A0=A0=A0 type =3D> "dhcp",=0A= +=A0=A0=A0=A0=A0=A0 description =3D> $description,=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> $namespace,=0A= +=A0=A0=A0=A0=A0=A0 status =3D> default_ip_status()=0A= +=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "POST", "/ipam/ip-address= es/", $params);=0A= +=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 if ($is_gateway) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 die "error add subnet ip to ipam: ip $ip al= ready exist: $@"=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if !is_ip_gateway($config, $ip,= $noerr);=0A= +=A0=A0=A0=A0=A0=A0 } elsif (!$noerr) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 die "error add subnet ip to ipam: ip alread= y exist: $@";=0A= +=A0=A0=A0=A0=A0=A0 }=0A= +=A0=A0=A0 }=0A= +}=0A= +=0A= +sub add_next_freeip {=0A= +=A0=A0=A0 my ($class, $config, undef, $subnet, $hostname, $mac, undef, $no= err) =3D @_;=0A= +=0A= +=A0=A0=A0 my $cidr =3D $subnet->{cidr};=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $internalid =3D get_prefix_id($config, $cidr, $noerr);=0A= +=A0=A0=A0 if (!defined($internalid)) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not find prefix $cidr in nautobot\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $description =3D undef;=0A= +=A0=A0=A0 $description =3D "mac:$mac" if $mac;=0A= +=0A= +=A0=A0=A0 my $params =3D {=0A= +=A0=A0=A0=A0=A0=A0 type =3D> "dhcp",=0A= +=A0=A0=A0=A0=A0=A0 description =3D> $description,=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> $namespace,=0A= +=A0=A0=A0=A0=A0=A0 status =3D> default_ip_status()=0A= +=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0 my $response =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request(=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $config,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "POST",=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "/ipam/prefixes/$internalid/available-ips/"= ,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $params=0A= +=A0=A0=A0=A0=A0=A0 );=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@ || !$response) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not allocate ip in subnet $cidr: $@\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $ip =3D NetAddr::IP->new($response->{address});=0A= +=0A= +=A0=A0=A0 return $ip->addr;=0A= +}=0A= +=0A= +sub add_range_next_freeip {=0A= +=A0=A0=A0 my ($class, $config, $subnet, $range, $data, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $cidr =3D NetAddr::IP->new($subnet->{cidr});=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 # Nautobot does not support IP ranges only prefixes.=0A= +=A0=A0=A0 # We therefore divide the range into smaller pool-prefixes,=0A= +=A0=A0=A0 # each containing 256 addresses, and search for available IPs in= them=0A= +=A0=A0=A0 my $prefix_size =3D $cidr->version =3D=3D 4 ? 24 : 120;=0A= +=A0=A0=A0 my $increment =3D 256;=0A= +=A0=A0=A0 my $found_ip =3D undef;=0A= +=0A= +=A0=A0=A0 my $start_range =3D NetAddr::IP->new($range->{'start-address'}, = $prefix_size);=0A= +=A0=A0=A0 my $end_range =3D NetAddr::IP->new($range->{'end-address'}, $pre= fix_size);=0A= +=A0=A0=A0 my $matcher =3D subnet_matcher($end_range->cidr);=0A= +=A0=A0=A0 my $current_ip =3D $start_range;=0A= +=0A= +=A0=A0=A0 while (1) {=0A= +=A0=A0=A0=A0=A0=A0 my $current_cidr =3D $current_ip->addr . "/$prefix_size= ";=0A= +=0A= +=A0=A0=A0=A0=A0=A0 my $params =3D {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 prefix =3D> $current_cidr,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 namespace =3D> $namespace,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 status =3D> default_ip_status(),=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 type =3D> "pool"=0A= +=A0=A0=A0=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # create temporary pool prefix=0A= +=A0=A0=A0=A0=A0=A0 my $temp_prefix =3D eval {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "POST"= , "/ipam/prefixes/", $params);=0A= +=A0=A0=A0=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # skip if it is not possible to create it=0A= +=A0=A0=A0=A0=A0=A0 next if $@;=0A= +=0A= +=A0=A0=A0=A0=A0=A0 my $temp_prefix_id =3D $temp_prefix->{id};=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # Fetch available IPs from the temporary pool and find = a matching IP=0A= +=A0=A0=A0=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return nautobot_api_request(=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $config,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "GET",=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "/ipam/prefixes/$temp_prefix_id= /available-ips/?limit=3D$increment"=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 );=0A= +=A0=A0=A0=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # search list for IPs in actual range=0A= +=A0=A0=A0=A0=A0=A0 if (!$@) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 foreach my $entry (@$result) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 my $ip =3D NetAddr::IP->new($en= try->{address});=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # comparison is only possible b= ecause they are in the same subnet=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 if ($start_range <=3D $ip && $i= p <=3D $end_range) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $found_ip =3D $ip->= addr;=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 last;=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 }=0A= +=A0=A0=A0=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # Delete temporary prefix pool=0A= +=A0=A0=A0=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "DELETE", "/i= pam/prefixes/$temp_prefix_id/");=0A= +=A0=A0=A0=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0=A0=A0=A0 last if $found_ip;=0A= +=0A= +=A0=A0=A0=A0=A0=A0 # we searched the last pool prefix=0A= +=A0=A0=A0=A0=A0=A0 last if $matcher->($current_ip->addr);=0A= +=0A= +=A0=A0=A0=A0=A0=A0 $current_ip =3D $current_ip->plus($increment);=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 if (!$found_ip) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not allocate ip in the range " . $start_rang= e->addr . " - "=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 . $end_range->addr . ": $@\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 $class->add_ip($config, undef, $subnet, $found_ip, $data->{hostn= ame}, $data->{mac}, undef, 0, $noerr);=0A= +=0A= +=A0=A0=A0 return $found_ip;=0A= +}=0A= +=0A= +sub update_ip {=0A= +=A0=A0=A0 my ($class, $config, $subnetid, $subnet, $ip, $hostname, $mac,= =0A= +=A0=A0=A0=A0=A0=A0 undef, $is_gateway, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $mask =3D $subnet->{mask};=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $description =3D undef;=0A= +=A0=A0=A0 if ($is_gateway) {=0A= +=A0=A0=A0=A0=A0=A0 $description =3D 'gateway'=0A= +=A0=A0=A0 } elsif ($mac) {=0A= +=A0=A0=A0=A0=A0=A0 $description =3D "mac:$mac";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $params =3D {=0A= +=A0=A0=A0=A0=A0=A0 address =3D> "$ip/$mask",=0A= +=A0=A0=A0=A0=A0=A0 type =3D> "dhcp",=0A= +=A0=A0=A0=A0=A0=A0 description =3D> $description,=0A= +=A0=A0=A0=A0=A0=A0 namespace =3D> $namespace,=0A= +=A0=A0=A0=A0=A0=A0 status =3D> default_ip_status()=0A= +=A0=A0=A0 };=0A= +=0A= +=A0=A0=A0 my $ip_id =3D get_ip_id($config, $ip, $noerr);=0A= +=A0=A0=A0 if (!defined($ip_id)) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not find the ip $ip in nautobot\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "PATCH", "/ipam/ip-addres= ses/$ip_id/", $params);=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error updating ip $ip: $@";=0A= +=A0=A0=A0 }=0A= +}=0A= +=0A= +=0A= +sub del_ip {=0A= +=A0=A0=A0 my ($class, $config, undef, undef, $ip, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 return if !$ip;=0A= +=0A= +=A0=A0=A0 my $ip_id =3D get_ip_id($config, $ip, $noerr);=0A= +=A0=A0=A0 if (!defined($ip_id)) {=0A= +=A0=A0=A0=A0=A0=A0 warn("could not find the ip $ip in nautobot\n");=0A= +=A0=A0=A0=A0=A0=A0 return;=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "DELETE", "/ipam/ip-addre= sses/$ip_id/");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error deleting ip $ip : $@\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 return 1;=0A= +}=0A= +=0A= +sub empty_subnet {=0A= +=A0=A0=A0 my ($class, $config, $subnetid, $subnet, $subnetuuid, $noerr) = =3D @_;=0A= +=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $response =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request(=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $config,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "GET",=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "/ipam/ip-addresses/?namespace=3D$namespace= &parent=3D$subnetuuid"=0A= +=A0=A0=A0=A0=A0=A0 );=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "could not find the subnet $subnet in nautobot: $@\= n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 for my $ip (@{$response->{results}}) {=0A= +=A0=A0=A0=A0=A0=A0 del_ip($class, $config, undef, undef, $ip->{host}, $noe= rr);=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 return 1;=0A= +}=0A= +=0A= +sub subnet_is_deletable {=0A= +=A0=A0=A0 my ($config, $subnetid, $subnet, $subnetuuid, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 my $response =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request(=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 $config,=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "GET",=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 "/ipam/ip-addresses/?namespace=3D$namespace= &parent=3D$subnetuuid"=0A= +=A0=A0=A0=A0=A0=A0 );=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error querying prefix $subnet: $@\n";=0A= +=A0=A0=A0 }=0A= +=A0=A0=A0 my $n_ips =3D scalar $response->{results}->@*;=0A= +=0A= +=A0=A0=A0 # least costly check operation 1st=0A= +=A0=A0=A0 return 1 if ($n_ips =3D=3D 0);=0A= +=0A= +=A0=A0=A0 for my $ip (values $response->{results}->@*) {=0A= +=A0=A0=A0=A0=A0=A0 if (!is_ip_gateway($config, $ip->{host}, $noerr)) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 # some remaining IP is not a gateway so we = can't delete the subnet=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 return 0;=0A= +=A0=A0=A0=A0=A0=A0 }=0A= +=A0=A0=A0 }=0A= +=A0=A0=A0 #all remaining IPs are gateways=0A= +=A0=A0=A0 return 1;=0A= +}=0A= +=0A= +sub verify_api {=0A= +=A0=A0=A0 my ($class, $config) =3D @_;=0A= +=0A= +=A0=A0=A0 my $namespace =3D $config->{namespace};=0A= +=0A= +=A0=A0=A0 # check if the namespace and the status "Active" exist=0A= +=A0=A0=A0 eval {=0A= +=A0=A0=A0=A0=A0=A0 get_namespace_id($config, $namespace)=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 // die "namespace $namespace does not exist= ";=0A= +=A0=A0=A0=A0=A0=A0 get_status_id($config, default_ip_status())=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 // die "the status " . default_ip_status() = . " does not exist";=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 die "could not use nautobot api: $@\n";=0A= +=A0=A0=A0 }=0A= +}=0A= +=0A= +sub get_ips_from_mac {=0A= +=A0=A0=A0 my ($class, $config, $mac, $zone) =3D @_;=0A= +=0A= +=A0=A0=A0 my $ip4 =3D undef;=0A= +=A0=A0=A0 my $ip6 =3D undef;=0A= +=0A= +=A0=A0=A0 my $data =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 nautobot_api_request($config, "GET", "/ipam/ip-addresse= s/?q=3D$mac");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 die "could not query ip address entry for mac $mac: $@"= ;=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 for my $ip (@{$data->{results}}) {=0A= +=A0=A0=A0=A0=A0=A0 if ($ip->{ip_version} =3D=3D 4 && !$ip4) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ($ip4, undef) =3D split(/\//, $ip->{address= });=0A= +=A0=A0=A0=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0=A0=A0=A0 if ($ip->{ip_version} =3D=3D 6 && !$ip6) {=0A= +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ($ip6, undef) =3D split(/\//, $ip->{address= });=0A= +=A0=A0=A0=A0=A0=A0 }=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 return ($ip4, $ip6);=0A= +}=0A= +=0A= +sub on_update_hook {=0A= +=A0=A0=A0 my ($class, $config) =3D @_;=0A= +=0A= +=A0=A0=A0 PVE::Network::SDN::Ipams::NautobotPlugin::verify_api($class, $co= nfig);=0A= +}=0A= +=0A= +sub get_ip_id {=0A= +=A0=A0=A0 my ($config, $ip, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "GET", "/ipam/ip-a= ddresses/?address=3D$ip");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error while querying for ip $ip id: $@\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $data =3D @{$result->{results}}[0];=0A= +=A0=A0=A0 return $data->{id};=0A= +}=0A= +=0A= +sub get_prefix_id {=0A= +=A0=A0=A0 my ($config, $cidr, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "GET", "/ipam/pref= ixes/?prefix=3D$cidr");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error while querying for cidr $cidr prefix id: $@\= n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $data =3D @{$result->{results}}[0];=0A= +=A0=A0=A0 return $data->{id};=0A= +}=0A= +=0A= +sub get_namespace_id {=0A= +=A0=A0=A0 my ($config, $namespace, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "GET", "/ipam/n= amespaces/?name=3D$namespace");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error while querying for namespace $namespace id: = $@\n";=0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $data =3D @{$result->{results}}[0];=0A= +=A0=A0=A0 return $data->{id};=0A= +}=0A= +=0A= +sub get_status_id {=0A= +=A0=A0=A0 my ($config, $status, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "GET", "/extras/st= atuses/?name=3D$status");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error while querying for status $status id: $@\n";= =0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $data =3D @{$result->{results}}[0];=0A= +=A0=A0=A0 return $data->{id};=0A= +}=0A= +=0A= +sub is_ip_gateway {=0A= +=A0=A0=A0 my ($config, $ip, $noerr) =3D @_;=0A= +=0A= +=A0=A0=A0 my $result =3D eval {=0A= +=A0=A0=A0=A0=A0=A0=A0 return nautobot_api_request($config, "GET", "/ipam/i= p-addresses/?address=3D$ip");=0A= +=A0=A0=A0 };=0A= +=A0=A0=A0 if ($@) {=0A= +=A0=A0=A0=A0=A0=A0 return if $noerr;=0A= +=A0=A0=A0=A0=A0=A0 die "error while checking if $ip is a gateway: $@\n";= =0A= +=A0=A0=A0 }=0A= +=0A= +=A0=A0=A0 my $data =3D @{$result->{results}}[0];=0A= +=A0=A0=A0 return $data->{description} eq 'gateway';=0A= +}=0A= +=0A= +1;=0A= --=0A= 2.39.5=0A= =0A= =0A= --===============3993655324738362196== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel --===============3993655324738362196==--