initial
This commit is contained in:
262
manager/admin.py
Normal file
262
manager/admin.py
Normal file
@@ -0,0 +1,262 @@
|
||||
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'
|
||||
Reference in New Issue
Block a user