admin.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. from django.contrib import admin
  2. from django.shortcuts import get_object_or_404, redirect
  3. from django.template.response import TemplateResponse
  4. from django.urls import path, reverse
  5. from django.utils.html import format_html
  6. from netbox.config import get_config, PARAMS
  7. from .forms import ConfigRevisionForm
  8. from .models import ConfigRevision, JobResult
  9. @admin.register(ConfigRevision)
  10. class ConfigRevisionAdmin(admin.ModelAdmin):
  11. fieldsets = [
  12. ('Rack Elevations', {
  13. 'fields': ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH'),
  14. }),
  15. ('Power', {
  16. 'fields': ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')
  17. }),
  18. ('IPAM', {
  19. 'fields': ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4'),
  20. }),
  21. ('Security', {
  22. 'fields': ('ALLOWED_URL_SCHEMES',),
  23. }),
  24. ('Banners', {
  25. 'fields': ('BANNER_LOGIN', 'BANNER_TOP', 'BANNER_BOTTOM'),
  26. 'classes': ('monospace',),
  27. }),
  28. ('Pagination', {
  29. 'fields': ('PAGINATE_COUNT', 'MAX_PAGE_SIZE'),
  30. }),
  31. ('Validation', {
  32. 'fields': ('CUSTOM_VALIDATORS',),
  33. 'classes': ('monospace',),
  34. }),
  35. ('NAPALM', {
  36. 'fields': ('NAPALM_USERNAME', 'NAPALM_PASSWORD', 'NAPALM_TIMEOUT', 'NAPALM_ARGS'),
  37. 'classes': ('monospace',),
  38. }),
  39. ('User Preferences', {
  40. 'fields': ('DEFAULT_USER_PREFERENCES',),
  41. }),
  42. ('Miscellaneous', {
  43. 'fields': ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOBRESULT_RETENTION', 'MAPS_URL'),
  44. }),
  45. ('Config Revision', {
  46. 'fields': ('comment',),
  47. })
  48. ]
  49. form = ConfigRevisionForm
  50. list_display = ('id', 'is_active', 'created', 'comment', 'restore_link')
  51. ordering = ('-id',)
  52. readonly_fields = ('data',)
  53. def get_changeform_initial_data(self, request):
  54. """
  55. Populate initial form data from the most recent ConfigRevision.
  56. """
  57. latest_revision = ConfigRevision.objects.last()
  58. initial = latest_revision.data if latest_revision else {}
  59. initial.update(super().get_changeform_initial_data(request))
  60. return initial
  61. # Permissions
  62. def has_add_permission(self, request):
  63. # Only superusers may modify the configuration.
  64. return request.user.is_superuser
  65. def has_change_permission(self, request, obj=None):
  66. # ConfigRevisions cannot be modified once created.
  67. return False
  68. def has_delete_permission(self, request, obj=None):
  69. # Only inactive ConfigRevisions may be deleted (must be superuser).
  70. return request.user.is_superuser and (
  71. obj is None or not obj.is_active()
  72. )
  73. # List display methods
  74. def restore_link(self, obj):
  75. if obj.is_active():
  76. return ''
  77. return format_html(
  78. '<a href="{url}" class="button">Restore</a>',
  79. url=reverse('admin:extras_configrevision_restore', args=(obj.pk,))
  80. )
  81. restore_link.short_description = "Actions"
  82. # URLs
  83. def get_urls(self):
  84. urls = [
  85. path('<int:pk>/restore/', self.admin_site.admin_view(self.restore), name='extras_configrevision_restore'),
  86. ]
  87. return urls + super().get_urls()
  88. # Views
  89. def restore(self, request, pk):
  90. # Get the ConfigRevision being restored
  91. candidate_config = get_object_or_404(ConfigRevision, pk=pk)
  92. if request.method == 'POST':
  93. candidate_config.activate()
  94. self.message_user(request, f"Restored configuration revision #{pk}")
  95. return redirect(reverse('admin:extras_configrevision_changelist'))
  96. # Get the current ConfigRevision
  97. config_version = get_config().version
  98. current_config = ConfigRevision.objects.filter(pk=config_version).first()
  99. params = []
  100. for param in PARAMS:
  101. params.append((
  102. param.name,
  103. current_config.data.get(param.name, None),
  104. candidate_config.data.get(param.name, None)
  105. ))
  106. context = self.admin_site.each_context(request)
  107. context.update({
  108. 'object': candidate_config,
  109. 'params': params,
  110. })
  111. return TemplateResponse(request, 'admin/extras/configrevision/restore.html', context)
  112. #
  113. # Reports & scripts
  114. #
  115. @admin.register(JobResult)
  116. class JobResultAdmin(admin.ModelAdmin):
  117. list_display = [
  118. 'obj_type', 'name', 'created', 'completed', 'user', 'status',
  119. ]
  120. fields = [
  121. 'obj_type', 'name', 'created', 'completed', 'user', 'status', 'data', 'job_id'
  122. ]
  123. list_filter = [
  124. 'status',
  125. ]
  126. readonly_fields = fields
  127. def has_add_permission(self, request):
  128. return False