Files
Django-Proxmox-Mikrotik/manager/admin.py

263 lines
8.3 KiB
Python
Raw Normal View History

2025-08-27 09:55:55 +02:00
import logging
from django import forms
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.db.models import Q
from lib.decorators import readonly
from manager.models import CloneContainer, DevContainer
from mikrotik.models import DNSStatic
from proxmox.models import Lxc
@readonly
def resync_all(*args, **kwargs):
from proxmox.models import Lxc
from lib.proxmox import Proxmox
from mikrotik.models import DNSStatic, IPDHCPLease
from manager.models import DevContainer
from mikrotik.admin import sync_ipaddress_from_mikrotik, sync_ipdhcplease_from_mikrotik, sync_dns_static_from_mikrotik
from proxmox.admin import sync_all_lxc_templates_from_proxmox, sync_all_lxc_from_proxmox
fulls = []
pm = Proxmox()
lxcs = {}
leases = {}
dnse = {}
sync_all_lxc_templates_from_proxmox()
sync_all_lxc_from_proxmox()
sync_ipaddress_from_mikrotik()
sync_ipdhcplease_from_mikrotik()
sync_dns_static_from_mikrotik()
for lxc in Lxc.objects.all():
lxcs[lxc.hwaddr.upper()] = lxc
for lease in IPDHCPLease.objects.all():
leases[lease.mac_address.upper()] = lease
for dns in DNSStatic.objects.all():
dnse[dns.address.upper()] = dns
container = {c.hwaddr.upper():c for c in DevContainer.objects.all()}
for hwaddr, lxc in lxcs.items():
if hwaddr not in leases:
logging.warning(f'LXC {lxc} has no DHCP lease')
continue
lease = leases[hwaddr]
if lease.address not in dnse:
logging.warning(f'DHCP lease {lease} for {lxc} has no DNS entry')
continue
dns = dnse[lease.address]
if hwaddr in container:
container[hwaddr].dns = dns
container[hwaddr].lease = lease
container[hwaddr].save()
elif lxc:
DevContainer.objects.create(
dns=dns,
lease=lease,
lxc=lxc,
)
# Now remove the non lxc devcontainers
DevContainer.objects.filter(lxc__isnull=True).delete()
def shell_baseimport():
from proxmox.models import Lxc
from lib.proxmox import Proxmox
from mikrotik.models import DNSStatic, IPDHCPLease, IPAddress
from manager.models import DevContainer
from lib.mikrotik import MikrotikModelMixin
fulls = []
for empt in (DevContainer, Lxc, IPAddress, IPDHCPLease, DNSStatic):
if empt.objects.count() != 0:
fulls.append(empt)
if fulls:
msg = []
queries = []
for f in fulls:
logging.error(f'{f.__name__} is not empty.')
queries.append(f'DELETE FROM {f._meta.db_table};')
msg.append(
f"\n\nPlease delete all objects and try again.\n"
f"\nThis can only be done with a raw query\n"
)
msg.append('\n'.join(queries))
logging.error('\n'.join(msg) + '\n\n')
raise ValidationError("Some tables not empty - see above output")
pm = Proxmox()
lxcs = {}
for lxc in pm.get_all_lxc(as_dict=False):
lxc.save()
lxcs[lxc.hwaddr.upper()] = lxc
addresses = IPAddress.get_all_as_object()
for a in addresses:
a.save()
leases = {}
for lease in IPDHCPLease.get_all_as_object():
if isinstance(lease, MikrotikModelMixin):
lease.save()
if lease.mac_address in lxcs:
leases[lease.address.upper()] = lease
else:
logging.warning(f'IPDHCPLease {lease} is not a MikrotikModelMixin')
dnse = {}
for dns in DNSStatic.get_all_as_object():
if isinstance(dns, MikrotikModelMixin):
dns.save()
if dns.address in leases:
dnse[dns.address.upper()] = dns
else:
logging.warning(f'DNSStatic {dns} is not a MikrotikModelMixin')
for _a, dns in dnse.items():
lease = leases[_a]
lxc = lxcs[lease.mac_address.upper()]
DevContainer.objects.get_or_create(
lxc=lxc,
dns=dns,
lease=lease,
)
class DevContainerAdminForm(forms.ModelForm):
disksize = forms.IntegerField(
required=False,
min_value=1,
max_value=100,
help_text="Disk Size of rootfs - can not be shrinked"
)
cores = forms.IntegerField(
required=False,
min_value=1,
help_text="Number of Cores"
)
memory = forms.CharField(
required=False,
help_text="Memory in MB"
)
class Meta:
model = DevContainer
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = kwargs.get('instance')
if instance and hasattr(instance, 'lxc') and instance.lxc:
self.fields['disksize'].initial = instance.lxc.disksize
self.fields['disksize'].min_value = instance.lxc.disksize
self.fields['cores'].initial = instance.lxc.cores
self.fields['memory'].initial = instance.lxc.memory
def save(self, commit=True):
instance = super().save(commit=False)
if hasattr(instance, 'lxc') and instance.lxc:
lxc = instance.lxc
if 'disksize' in self.cleaned_data and self.cleaned_data['disksize']:
lxc.disksize = self.cleaned_data['disksize']
if 'cores' in self.cleaned_data and self.cleaned_data['cores']:
lxc.cores = self.cleaned_data['cores']
if 'memory' in self.cleaned_data and self.cleaned_data['memory']:
lxc.memory = self.cleaned_data['memory']
lxc.save()
if commit:
instance.save()
return instance
def clone_selected_containers(modeladmin, request, queryset):
for container in queryset:
container.execute()
class CloneContainerAdminForm(forms.ModelForm):
class Meta:
model = CloneContainer
fields = '__all__'
def clean_name(self):
name = self.cleaned_data.get('name')
if not name:
return name
dns_domain = Q(name=name) | Q(name__endswith=name) | Q(name__endswith=name.replace('.', r'\.'))
if DNSStatic.objects.filter(dns_domain).exists():
raise ValidationError(f"Ein DNS-Eintrag mit dem Namen '{name}' existiert bereits.")
if Lxc.objects.filter(hostname=name).exists():
raise ValidationError(f"A LXC with name or regex '{name}' exists.")
# Prüfe, ob der Name bereits als CloneContainer-Name existiert
# Ausschluss der aktuellen Instanz bei Updates
existing_clone_query = CloneContainer.objects.filter(name=name)
if self.instance.pk:
existing_clone_query = existing_clone_query.exclude(pk=self.instance.pk)
if existing_clone_query.exists():
raise ValidationError(f"A CloneContainer with name '{name}' exists.")
return name
def clean(self):
cleaned_data = super().clean()
if not cleaned_data.get('template') and not cleaned_data.get('vm'):
raise ValidationError("Please select a template or a VM.")
return cleaned_data
@admin.register(CloneContainer)
class CloneContainerAdmin(admin.ModelAdmin):
autocomplete_fields = ['vm', 'network']
list_display = ('hostname', 'cloned_from', 'network', 'memory', 'cores', 'disksize', 'status',)
search_fields = ('hostname', 'vm__name', 'vm__vmid',)
actions = [clone_selected_containers]
form = CloneContainerAdminForm
def cloned_from(self, obj):
return obj.vm
cloned_from.short_description = 'Cloned from'
cloned_from.admin_order_field = 'vm__name'
@admin.register(DevContainer)
class DevContainerAdmin(admin.ModelAdmin):
form = DevContainerAdminForm
autocomplete_fields = ['dns', 'lxc', 'lease']
# list_display = ('name', 'address', 'hostname_or_regexp', 'lxc__disksize', 'hwaddr', 'status',)
list_filter = (
'lxc__status',
'lease__status',
('lxc', admin.EmptyFieldListFilter),
('lease', admin.EmptyFieldListFilter),
('dns', admin.EmptyFieldListFilter),
)
search_fields = ('dns__name', 'dns__address', 'lease__address', 'dns__regexp')
actions = [resync_all]
def hostname_or_regexp(self, obj):
return obj.hostname
hostname_or_regexp.short_description = 'Hostname or Regexp'
hostname_or_regexp.admin_order_field = 'dns__name'