assign available netbox IP to a netbox VM

Signed-off-by: Kiara Grouwstra <kiara@procolix.eu>
This commit is contained in:
Kiara Grouwstra 2025-11-14 10:36:36 +01:00
parent b6e1b5cba7
commit cd5d1400bf
Signed by: kiara
SSH key fingerprint: SHA256:COspvLoLJ5WC5rFb9ZDe5urVCkK4LJZOsjfF4duRJFU
10 changed files with 370 additions and 3 deletions

View file

@ -14,9 +14,20 @@ let
(pkgs.callPackage ../../run { (pkgs.callPackage ../../run {
inherit sources; inherit sources;
}) })
tf-netbox-cluster-type
tf-netbox-cluster
tf-netbox-store-ips tf-netbox-store-ips
tf-netbox-get-ip tf-netbox-get-ip
; ;
netbox-cluster-type = evalOption tf-netbox-cluster-type {
httpBackend = tfBackend "proxmox-test/cluster-type";
name = "test-type";
};
netbox-cluster = evalOption tf-netbox-cluster {
httpBackend = tfBackend "proxmox-test/cluster";
cluster_type_name = "test-type";
name = "cluster";
};
netbox-store-ips = evalOption tf-netbox-store-ips { netbox-store-ips = evalOption tf-netbox-store-ips {
httpBackend = tfBackend "proxmox-test/store-ips"; httpBackend = tfBackend "proxmox-test/store-ips";
startAddress = "192.168.10.236/24"; startAddress = "192.168.10.236/24";
@ -24,6 +35,9 @@ let
}; };
netbox-get-ip = evalOption tf-netbox-get-ip { netbox-get-ip = evalOption tf-netbox-get-ip {
httpBackend = tfBackend "proxmox-test/get-ip"; httpBackend = tfBackend "proxmox-test/get-ip";
cluster_name = "cluster";
vm_name = "vm";
interface_name = "eth";
}; };
netboxUser = "netbox"; netboxUser = "netbox";
netboxPassword = "netbox"; netboxPassword = "netbox";
@ -47,6 +61,8 @@ in
environment.systemPackages = [ environment.systemPackages = [
pkgs.jq pkgs.jq
(pkgs.callPackage ../../run/tf-netbox-cluster-type/tf.nix { })
(pkgs.callPackage ../../run/tf-netbox-cluster/tf.nix { })
(pkgs.callPackage ../../run/tf-netbox-store-ips/tf.nix { }) (pkgs.callPackage ../../run/tf-netbox-store-ips/tf.nix { })
(pkgs.callPackage ../../run/tf-netbox-get-ip/tf.nix { }) (pkgs.callPackage ../../run/tf-netbox-get-ip/tf.nix { })
]; ];
@ -76,14 +92,24 @@ in
netbox_token = deployer.succeed(""" netbox_token = deployer.succeed("""
curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" http://localhost:8001/api/users/tokens/provision/ --data '{"username":"${netboxUser}","password":"${netboxPassword}"}' | jq -r .key curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" http://localhost:8001/api/users/tokens/provision/ --data '{"username":"${netboxUser}","password":"${netboxPassword}"}' | jq -r .key
""").strip() """).strip()
ip_range_id = deployer.succeed(f""" netbox_vars = f"""
export NETBOX_SERVER_URL="localhost:8001" export NETBOX_SERVER_URL="localhost:8001"
export NETBOX_API_TOKEN="{netbox_token}" export NETBOX_API_TOKEN="{netbox_token}"
"""
deployer.succeed(f"""
{netbox_vars}
${lib.getExe netbox-cluster-type.run}
""")
cluster_id = deployer.succeed(f"""
{netbox_vars}
${lib.getExe netbox-cluster.run} | jq -r '.id.value'
""").strip()
ip_range_id = deployer.succeed(f"""
{netbox_vars}
${lib.getExe netbox-store-ips.run} | jq -r '.id.value' ${lib.getExe netbox-store-ips.run} | jq -r '.id.value'
""").strip() """).strip()
ipv4 = deployer.succeed(f""" ipv4 = deployer.succeed(f"""
export NETBOX_SERVER_URL="localhost:8001" {netbox_vars}
export NETBOX_API_TOKEN="{netbox_token}"
export TF_VAR_ip_range_id={ip_range_id} export TF_VAR_ip_range_id={ip_range_id}
${lib.getExe netbox-get-ip.run} | jq -r '.ipv4.value' ${lib.getExe netbox-get-ip.run} | jq -r '.ipv4.value'
""").strip() """).strip()

View file

@ -588,6 +588,127 @@ in
} }
); );
}; };
tf-netbox-cluster-type = mkOption {
description = "A cluster type represents a technology or mechanism by which a cluster is formed. For example, you might create a cluster type named 'VMware vSphere' for a locally hosted cluster or 'DigitalOcean NYC3' for one hosted by a cloud provider.";
type = submodule (
{ config, ... }:
{
options = {
inherit httpBackend;
name = mkOption {
description = "";
type = str;
};
slug = mkOption {
description = "";
type = nullOr str;
default = null;
};
run = mkOption {
type = types.package;
readOnly = true;
default = tfApply {
inherit (config) httpBackend;
directory = "tf-netbox-cluster-type";
environment = {
inherit (config)
name
slug
;
};
};
};
};
}
);
};
tf-netbox-cluster = mkOption {
description = "A cluster is a logical grouping of physical resources within which virtual machines run. Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside.";
type = submodule (
{ config, ... }:
{
options = {
inherit httpBackend;
cluster_type_name = mkOption {
description = "";
type = str;
};
name = mkOption {
description = "";
type = str;
};
cluster_group_id = mkOption {
description = "";
type = nullOr int;
default = null;
};
comments = mkOption {
description = "";
type = str;
default = "";
};
description = mkOption {
description = "";
type = str;
default = "";
};
location_id = mkOption {
description = "Conflicts with site_id, site_group_id and region_id.";
type = nullOr int;
default = null;
};
region_id = mkOption {
description = "Conflicts with location_id, site_id and site_group_id.";
type = nullOr int;
default = null;
};
site_group_id = mkOption {
description = "Conflicts with location_id, site_id and region_id.";
type = nullOr int;
default = null;
};
site_id = mkOption {
description = "Conflicts with location_id, site_group_id and region_id.";
type = nullOr int;
default = null;
};
tags = mkOption {
description = "";
type = types.listOf str;
default = [ ];
};
tenant_id = mkOption {
description = "";
type = nullOr int;
default = null;
};
run = mkOption {
type = types.package;
readOnly = true;
default = tfApply {
inherit (config) httpBackend;
directory = "tf-netbox-cluster";
environment = {
inherit (config)
cluster_type_name
name
cluster_group_id
comments
description
location_id
region_id
site_group_id
site_id
tags
tenant_id
;
};
};
};
};
}
);
};
tf-netbox-store-ips = mkOption { tf-netbox-store-ips = mkOption {
description = "Store a range of IPs in a Netbox instance."; description = "Store a range of IPs in a Netbox instance.";
type = submodule ( type = submodule (
@ -636,6 +757,18 @@ in
{ {
options = { options = {
inherit httpBackend; inherit httpBackend;
cluster_name = mkOption {
description = "";
type = str;
};
vm_name = mkOption {
description = "";
type = str;
};
interface_name = mkOption {
description = "";
type = str;
};
run = mkOption { run = mkOption {
type = types.package; type = types.package;
readOnly = true; readOnly = true;
@ -643,6 +776,11 @@ in
inherit (config) httpBackend; inherit (config) httpBackend;
directory = "tf-netbox-get-ip"; directory = "tf-netbox-get-ip";
environment = { environment = {
inherit (config)
cluster_name
vm_name
interface_name
;
}; };
}; };
}; };

View file

@ -0,0 +1,19 @@
terraform {
required_providers {
netbox = {
source = "e-breuninger/netbox"
version = "= 5.0.0"
}
}
backend "http" {
}
}
resource "netbox_cluster_type" "type" {
name = var.name
slug = var.slug
}
output "id" {
value = netbox_cluster_type.type.id
}

View file

@ -0,0 +1,24 @@
{
pkgs,
}:
let
sources = import ../../../npins;
mkProvider =
args:
pkgs.terraform-providers.mkProvider (
{ mkProviderFetcher = { repo, ... }: sources.${repo}; } // args
);
in
(pkgs.callPackage ../../tf.nix { }).withPlugins (_: [
(mkProvider {
owner = "e-breuninger";
repo = "terraform-provider-netbox";
rev = "v5.0.0";
spdx = "MPL-2.0";
# hash = "sha256-iCaCt8ZbkxCk43QEyj3PeHYuKPCPVU2oQ78aumH/l6k=";
hash = null;
vendorHash = "sha256-Q3H/6mpkWn1Gw0NRMtKtkBRGHjPJZGBFdGwfalyQ4Z0=";
homepage = "https://registry.terraform.io/providers/e-breuninger/netbox";
provider-source-address = "registry.opentofu.org/e-breuninger/netbox";
})
])

View file

@ -0,0 +1,10 @@
variable "name" {
description = ""
type = string
}
variable "slug" {
description = ""
type = string
default = null
}

View file

@ -0,0 +1,32 @@
terraform {
required_providers {
netbox = {
source = "e-breuninger/netbox"
version = "= 5.0.0"
}
}
backend "http" {
}
}
data "netbox_cluster_type" "type" {
name = var.cluster_type_name
}
resource "netbox_cluster" "cluster" {
cluster_type_id = data.netbox_cluster_type.type.id
name = var.name
cluster_group_id = var.cluster_group_id
comments = var.comments
description = var.description
location_id = var.location_id
region_id = var.region_id
site_group_id = var.site_group_id
site_id = var.site_id
tags = var.tags
tenant_id = var.tenant_id
}
output "id" {
value = netbox_cluster.cluster.id
}

View file

@ -0,0 +1,24 @@
{
pkgs,
}:
let
sources = import ../../../npins;
mkProvider =
args:
pkgs.terraform-providers.mkProvider (
{ mkProviderFetcher = { repo, ... }: sources.${repo}; } // args
);
in
(pkgs.callPackage ../../tf.nix { }).withPlugins (_: [
(mkProvider {
owner = "e-breuninger";
repo = "terraform-provider-netbox";
rev = "v5.0.0";
spdx = "MPL-2.0";
# hash = "sha256-iCaCt8ZbkxCk43QEyj3PeHYuKPCPVU2oQ78aumH/l6k=";
hash = null;
vendorHash = "sha256-Q3H/6mpkWn1Gw0NRMtKtkBRGHjPJZGBFdGwfalyQ4Z0=";
homepage = "https://registry.terraform.io/providers/e-breuninger/netbox";
provider-source-address = "registry.opentofu.org/e-breuninger/netbox";
})
])

View file

@ -0,0 +1,63 @@
variable "cluster_type_name" {
description = ""
type = string
}
variable "name" {
description = ""
type = string
}
variable "cluster_group_id" {
description = ""
type = number
default = null
}
variable "comments" {
description = ""
type = string
default = ""
}
variable "description" {
description = ""
type = string
default = ""
}
variable "location_id" {
description = "Conflicts with site_id, site_group_id and region_id."
type = number
default = null
}
variable "region_id" {
description = "Conflicts with location_id, site_id and site_group_id."
type = number
default = null
}
variable "site_group_id" {
description = "Conflicts with location_id, site_id and region_id."
type = number
default = null
}
variable "site_id" {
description = "Conflicts with location_id, site_group_id and region_id."
type = number
default = null
}
variable "tags" {
description = ""
type = set(string)
default = []
}
variable "tenant_id" {
description = ""
type = number
default = null
}

View file

@ -9,7 +9,23 @@ terraform {
} }
} }
data "netbox_cluster" "cluster" {
name = var.cluster_name
}
resource "netbox_virtual_machine" "vm" {
cluster_id = data.netbox_cluster.cluster.id
name = var.vm_name
}
resource "netbox_interface" "interface" {
virtual_machine_id = netbox_virtual_machine.vm.id
name = var.interface_name
}
resource "netbox_available_ip_address" "get_ip" { resource "netbox_available_ip_address" "get_ip" {
object_type = "virtualization.vminterface"
interface_id = netbox_interface.interface.id
prefix_id = var.prefix_id prefix_id = var.prefix_id
ip_range_id = var.ip_range_id ip_range_id = var.ip_range_id
} }

View file

@ -9,3 +9,18 @@ variable "ip_range_id" {
type = number type = number
default = null default = null
} }
variable "cluster_name" {
description = ""
type = string
}
variable "vm_name" {
description = ""
type = string
}
variable "interface_name" {
description = ""
type = string
}