# SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2026 Bryan Joshua Pedini """ Provision the custom fields this plugin relies on. A real (data) migration — not a post_migrate hook — because the netbox-docker entrypoint only runs `migrate` when `migrate --check` reports something pending. A pending migration is therefore what guarantees provisioning on first boot. Creates: * virtualization.VirtualMachine -> "vmid" (integer, required, min 100) * virtualization.Cluster -> "endpoint" (text) * virtualization.Cluster -> "token" (text) Each field carries a description, rendered as help text in the UI so the expected format is obvious without reading the source. VMID per-cluster uniqueness is enforced separately in signals.py (post_clean). """ from django.db import migrations FIELD_NAMES = ["vmid", "endpoint", "token"] def create_custom_fields(apps, schema_editor): # Use the real models (not historical): by the time this runs, extras and # virtualization are fully migrated, so CustomField.object_types exists. from django.contrib.contenttypes.models import ContentType from extras.choices import CustomFieldTypeChoices from extras.models import CustomField vm_ct = ContentType.objects.get(app_label="virtualization", model="virtualmachine") cluster_ct = ContentType.objects.get(app_label="virtualization", model="cluster") vmid, _ = CustomField.objects.get_or_create( name="vmid", defaults=dict( type=CustomFieldTypeChoices.TYPE_INTEGER, label="VMID", required=True, validation_minimum=100, # Proxmox VMIDs start at 100 group_name="Proxmox", description=( "Proxmox VM ID (integer, min 100). " "Must be unique within the VM's cluster." ), ), ) vmid.object_types.set([vm_ct]) cluster_fields = [ ( "endpoint", "Proxmox Endpoint", "Proxmox host or URL, e.g. pve.example.com:8006 or " "https://pve.example.com:8006", ), ( "token", "Proxmox API Token", "Proxmox API token as user@realm!tokenid=secret " "(e.g. root@pam!netbox=6f31a4c2-9d1e-4b7a-8c23-1f5e0a9b2d34)", ), ] for name, label, description in cluster_fields: cf, _ = CustomField.objects.get_or_create( name=name, defaults=dict( type=CustomFieldTypeChoices.TYPE_TEXT, label=label, group_name="Proxmox", description=description, ), ) cf.object_types.set([cluster_ct]) def remove_custom_fields(apps, schema_editor): from extras.models import CustomField CustomField.objects.filter(name__in=FIELD_NAMES).delete() class Migration(migrations.Migration): initial = True # Pin to this NetBox version's migration graph so CustomField.object_types is # available. Bump these (and PluginConfig.min_version) when targeting a # different NetBox release. dependencies = [ ("extras", "0134_owner"), ("virtualization", "0052_gfk_indexes"), ] operations = [ migrations.RunPython(create_custom_fields, remove_custom_fields), ]