263 lines
8.3 KiB
Python
263 lines
8.3 KiB
Python
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'
|