Make it easier setting multiple hosts as pxe installable, ++
This commit is contained in:
1 parent
a07edd160b
commit
2a959c47af
4 files changed
+60
-19
No files matched your search
+25
-2
@@ -1,5 +1,8 @@
|
||||
from mdb.models import *
|
||||
from django.contrib import admin
|
||||
from django.contrib import admin, messages
|
||||
|
||||
from mdb.models import Ip6Address, Interface, Ip4Address, DhcpOption, DhcpCustomField, DomainSrvRecord, DomainTxtRecord, \
|
||||
DomainCnameRecord, DomainARecord, Domain, Host, Ip4Subnet, Ip6Subnet, Nameserver, MailExchange, OperatingSystem, \
|
||||
HostType, DhcpConfig
|
||||
|
||||
|
||||
class Ip6AddressInline(admin.TabularInline):
|
||||
@@ -40,6 +43,26 @@ class HostAdmin(admin.ModelAdmin):
|
||||
# ('kerberos_principal_name', 'kerberos_principal_created_date'))
|
||||
# }),
|
||||
)
|
||||
actions = ['set_installable']
|
||||
|
||||
def _get_host_warning_message(self, host, ifs):
|
||||
ifs_str = ', '.join([_if.name for _if in ifs])
|
||||
return 'Host {} might not be installable since interface(s) {} has no IP set.'.format(host, ifs_str)
|
||||
|
||||
def set_installable(self, request, queryset):
|
||||
invalid_ifs_per_host = []
|
||||
|
||||
for obj in queryset:
|
||||
invalid_ifs = obj.interface_set.filter(ip4address__isnull=True)
|
||||
if invalid_ifs.exists():
|
||||
invalid_ifs_per_host.append(self._get_host_warning_message(obj, invalid_ifs))
|
||||
obj.pxe_installable = True
|
||||
obj.save() # triggers post save signal
|
||||
|
||||
if invalid_ifs_per_host:
|
||||
self.message_user(request, message='\n'.join(invalid_ifs_per_host), level=messages.WARNING)
|
||||
|
||||
set_installable.short_description = "Mark selected hosts as PXE installable"
|
||||
|
||||
def get_queryset(self, request):
|
||||
return super(HostAdmin, self).get_queryset(request).select_related()
|
||||
|
||||
+7
-7
@@ -53,12 +53,12 @@ class Domain(models.Model):
|
||||
def num_records(self):
|
||||
host_a_records = Host.objects.filter(interface__domain=self).count()
|
||||
size = {
|
||||
"cname": self.domaincnamerecord_set.count(),
|
||||
"srv": self.domainsrvrecord_set.count(),
|
||||
"txt": self.domaintxtrecord_set.count(),
|
||||
"a": self.domainarecord_set.count() + host_a_records
|
||||
"CNAME": self.domaincnamerecord_set.count(),
|
||||
"SRV": self.domainsrvrecord_set.count(),
|
||||
"TXT": self.domaintxtrecord_set.count(),
|
||||
"A": self.domainarecord_set.count() + host_a_records
|
||||
}
|
||||
return size
|
||||
return ', '.join(['{}: {}'.format(k, v) for k, v in size.items()])
|
||||
|
||||
num_records.short_description = "Num Records"
|
||||
|
||||
@@ -526,11 +526,11 @@ class Host(models.Model):
|
||||
|
||||
def mac_addresses(self):
|
||||
addresses = self.interface_set.filter(macaddr__isnull=False).values_list('macaddr', flat=True)
|
||||
return ",".join(addresses)
|
||||
return ", ".join(addresses)
|
||||
|
||||
def ip_addresses(self):
|
||||
addresses = self.interface_set.filter(ip4address__isnull=False).values_list('ip4address__address', flat=True)
|
||||
return ",".join(addresses)
|
||||
return ", ".join(addresses)
|
||||
|
||||
def as_pxe_files(self):
|
||||
return host_as_pxe_files(self)
|
||||
|
||||
+26
-7
@@ -87,21 +87,40 @@ def update_domain_serial_when_change_to_host(sender, instance, created, **kwargs
|
||||
|
||||
@receiver(post_save, sender=Host)
|
||||
def create_pxe_key_and_write_pxe_files_when_host_changes(sender, instance, created, **kwargs):
|
||||
if not instance.pxe_key:
|
||||
host = instance
|
||||
|
||||
if not host.pxe_key:
|
||||
# generate key (prevent infinite recursion by using update)
|
||||
pxe_key = uuid.uuid4().hex
|
||||
Host.objects.filter(pk=instance.pk).update(pxe_key=pxe_key)
|
||||
instance.pxe_key = pxe_key
|
||||
Host.objects.filter(pk=host.pk).update(pxe_key=pxe_key)
|
||||
host.pxe_key = pxe_key
|
||||
|
||||
for pxe_file_name, pxe_file in instance.as_pxe_files():
|
||||
for pxe_file_name, pxe_file in host.as_pxe_files():
|
||||
path = os.path.join(settings.MDB_PXE_TFTP_ROOT, pxe_file_name)
|
||||
if instance.pxe_installable:
|
||||
if host.pxe_installable:
|
||||
with open(path, 'w+') as f:
|
||||
f.write(pxe_file)
|
||||
logger.info("Created or updated {}".format(path))
|
||||
|
||||
# Also set necessary fields for pxe installation
|
||||
interfaces = host.interface_set.exclude(ip4address__isnull=True)
|
||||
|
||||
for _if in interfaces:
|
||||
changed = False
|
||||
if not _if.pxe_filename:
|
||||
_if.pxe_filename = 'pxelinux.0' # don't overwrite
|
||||
changed = True
|
||||
if not _if.dhcp_client:
|
||||
_if.dhcp_client = True
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
_if.save()
|
||||
|
||||
else:
|
||||
os.unlink(path)
|
||||
logger.info("deleted {}".format(path))
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
logger.info("deleted {}".format(path))
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=Interface)
|
||||
|
||||
+2
-3
@@ -68,13 +68,12 @@ def get_pxe_filename(interface, filename_format='mac_addr'):
|
||||
|
||||
|
||||
def host_as_pxe_files(host):
|
||||
""" Returns a list of filename,content for each host """
|
||||
""" Returns a list of filename,content for each host interface with an IPv4 address """
|
||||
from mdb.models import Host
|
||||
assert isinstance(host, Host)
|
||||
|
||||
pxe_files = []
|
||||
ifs = host.interface_set.filter(dhcp_client=True)
|
||||
for _if in ifs:
|
||||
for _if in host.interface_set.exclude(ip4address__isnull=True):
|
||||
filename = get_pxe_filename(_if)
|
||||
content = render_pxelinux_cfg(_if, host)
|
||||
pxe_files.append((filename, content))
|
||||
|
||||
Reference in new issue
Block a user