Introduce ConfigItem; add rack elevation parameters

This commit is contained in:
jeremystretch 2021-10-26 10:04:56 -04:00
parent 82243732a1
commit 7c0f32e8ee
11 changed files with 58 additions and 50 deletions

View File

@ -13,6 +13,7 @@ from netbox.api import ChoiceField, ContentTypeField, SerializedPKRelatedField
from netbox.api.serializers import (
NestedGroupModelSerializer, PrimaryModelSerializer, ValidatedModelSerializer, WritableNestedSerializer,
)
from netbox.config import ConfigItem
from tenancy.api.nested_serializers import NestedTenantSerializer
from users.api.nested_serializers import NestedUserSerializer
from utilities.api import get_serializer_for_model
@ -229,10 +230,10 @@ class RackElevationDetailFilterSerializer(serializers.Serializer):
default=RackElevationDetailRenderChoices.RENDER_JSON
)
unit_width = serializers.IntegerField(
default=settings.RACK_ELEVATION_DEFAULT_UNIT_WIDTH
default=ConfigItem('RACK_ELEVATION_DEFAULT_UNIT_WIDTH')
)
unit_height = serializers.IntegerField(
default=settings.RACK_ELEVATION_DEFAULT_UNIT_HEIGHT
default=ConfigItem('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT')
)
legend_width = serializers.IntegerField(
default=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT

View File

@ -1,7 +1,6 @@
from collections import OrderedDict
import yaml
from django.conf import settings
from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
@ -15,7 +14,7 @@ from dcim.constants import *
from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features
from netbox.config import ConfigResolver
from netbox.config import ConfigItem
from netbox.models import OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField
@ -816,8 +815,7 @@ class Device(PrimaryModel, ConfigContextModel):
@property
def primary_ip(self):
config = ConfigResolver()
if config.PREFER_IPV4 and self.primary_ip4:
if ConfigItem('PREFER_IPV4')() and self.primary_ip4:
return self.primary_ip4
elif self.primary_ip6:
return self.primary_ip6

View File

@ -1,6 +1,5 @@
from collections import OrderedDict
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
@ -15,6 +14,7 @@ from dcim.choices import *
from dcim.constants import *
from dcim.svg import RackElevationSVG
from extras.utils import extras_features
from netbox.config import Config
from netbox.models import OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField
@ -373,8 +373,8 @@ class Rack(PrimaryModel):
self,
face=DeviceFaceChoices.FACE_FRONT,
user=None,
unit_width=settings.RACK_ELEVATION_DEFAULT_UNIT_WIDTH,
unit_height=settings.RACK_ELEVATION_DEFAULT_UNIT_HEIGHT,
unit_width=None,
unit_height=None,
legend_width=RACK_ELEVATION_LEGEND_WIDTH_DEFAULT,
include_images=True,
base_url=None
@ -393,6 +393,10 @@ class Rack(PrimaryModel):
:param base_url: Base URL for links and images. If none, URLs will be relative.
"""
elevation = RackElevationSVG(self, user=user, include_images=include_images, base_url=base_url)
if unit_width is None or unit_height is None:
config = Config()
unit_width = unit_width or config.RACK_ELEVATION_DEFAULT_UNIT_WIDTH
unit_height = unit_height or config.RACK_ELEVATION_DEFAULT_UNIT_HEIGHT
return elevation.render(face, unit_width, unit_height, legend_width)

View File

@ -10,9 +10,9 @@ class ConfigRevisionAdmin(admin.ModelAdmin):
# ('Authentication', {
# 'fields': ('LOGIN_REQUIRED', 'LOGIN_PERSISTENCE', 'LOGIN_TIMEOUT'),
# }),
# ('Rack Elevations', {
# 'fields': ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH'),
# }),
('Rack Elevations', {
'fields': ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH'),
}),
('IPAM', {
'fields': ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4'),
}),

View File

@ -1,10 +1,9 @@
import netaddr
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import F, Q
from django.db.models import F
from django.urls import reverse
from django.utils.functional import cached_property
@ -17,7 +16,7 @@ from ipam.fields import IPNetworkField, IPAddressField
from ipam.managers import IPAddressManager
from ipam.querysets import PrefixQuerySet
from ipam.validators import DNSValidator
from netbox.config import ConfigResolver
from netbox.config import Config
from utilities.querysets import RestrictedQuerySet
from virtualization.models import VirtualMachine
@ -317,8 +316,7 @@ class Prefix(PrimaryModel):
})
# Enforce unique IP space (if applicable)
config = ConfigResolver()
if (self.vrf is None and config.ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
if (self.vrf is None and Config().ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
duplicate_prefixes = self.get_duplicates()
if duplicate_prefixes:
raise ValidationError({
@ -813,8 +811,7 @@ class IPAddress(PrimaryModel):
})
# Enforce unique IP space (if applicable)
config = ConfigResolver()
if (self.vrf is None and config.ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
if (self.vrf is None and Config().ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
duplicate_ips = self.get_duplicates()
if duplicate_ips and (
self.role not in IPADDRESS_ROLES_NONUNIQUE or

View File

@ -4,18 +4,20 @@ from django.core.cache import cache
from .parameters import PARAMS
__all__ = (
'ConfigResolver',
'Config',
'ConfigItem',
'PARAMS',
)
class ConfigResolver:
class Config:
"""
Active NetBox configuration.
Fetch and store in memory the current NetBox configuration. This class must be instantiated prior to access, and
must be re-instantiated each time it's necessary to check for updates to the cached config.
"""
def __init__(self):
self.config = cache.get('config')
self.version = self.config.get('config_version')
self.version = cache.get('config_version')
self.defaults = {param.name: param.default for param in PARAMS}
def __getattr__(self, item):
@ -33,3 +35,16 @@ class ConfigResolver:
return self.defaults[item]
raise AttributeError(f"Invalid configuration parameter: {item}")
class ConfigItem:
"""
A callable to retrieve a configuration parameter from the cache. This can serve as a placeholder to defer
referencing a configuration parameter.
"""
def __init__(self, item):
self.item = item
def __call__(self):
config = Config()
return getattr(config, self.item)

View File

@ -52,4 +52,20 @@ PARAMS = (
field=OptionalBooleanField
),
# Racks
ConfigParam(
name='RACK_ELEVATION_DEFAULT_UNIT_HEIGHT',
label='Rack Unit Height',
default=22,
description="Default unit height for rendered rack elevations",
field=forms.IntegerField
),
ConfigParam(
name='RACK_ELEVATION_DEFAULT_UNIT_WIDTH',
label='Rack Unit Width',
default=220,
description="Default unit width for rendered rack elevations",
field=forms.IntegerField
),
)

View File

@ -77,14 +77,6 @@ ALLOWED_URL_SCHEMES = (
'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp',
)
# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same
# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP.
BANNER_TOP = ''
BANNER_BOTTOM = ''
# Text to include on the login page above the login form. HTML is allowed.
BANNER_LOGIN = ''
# Base URL path if accessing NetBox within a directory. For example, if installed at https://example.com/netbox/, set:
# BASE_PATH = 'netbox/'
BASE_PATH = ''
@ -134,10 +126,6 @@ EMAIL = {
'FROM_EMAIL': '',
}
# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table
# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True.
ENFORCE_GLOBAL_UNIQUE = False
# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and
# by anonymous users. List models in the form `<app>.<model>`. Add '*' to this list to exempt all models.
EXEMPT_VIEW_PERMISSIONS = [
@ -229,14 +217,6 @@ PLUGINS = []
# }
# }
# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to
# prefer IPv4 instead.
PREFER_IPV4 = False
# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1.
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = 22
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = 220
# Remote authentication support
REMOTE_AUTH_ENABLED = False
REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend'

View File

@ -1,7 +1,7 @@
from django.conf import settings as django_settings
from extras.registry import registry
from netbox.config import ConfigResolver
from netbox.config import Config
def settings_and_registry(request):
@ -10,7 +10,7 @@ def settings_and_registry(request):
"""
return {
'settings': django_settings,
'config': ConfigResolver(),
'config': Config(),
'registry': registry,
'preferences': request.user.config if request.user.is_authenticated else {},
}

View File

@ -140,8 +140,6 @@ NAPALM_PASSWORD = getattr(configuration, 'NAPALM_PASSWORD', '')
NAPALM_TIMEOUT = getattr(configuration, 'NAPALM_TIMEOUT', 30)
NAPALM_USERNAME = getattr(configuration, 'NAPALM_USERNAME', '')
PAGINATE_COUNT = getattr(configuration, 'PAGINATE_COUNT', 50)
RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = getattr(configuration, 'RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 22)
RACK_ELEVATION_DEFAULT_UNIT_WIDTH = getattr(configuration, 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH', 220)
RELEASE_CHECK_URL = getattr(configuration, 'RELEASE_CHECK_URL', None)
# Validate update repo URL and timeout

View File

@ -8,7 +8,7 @@ from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features
from netbox.config import ConfigResolver
from netbox.config import Config
from netbox.models import OrganizationalModel, PrimaryModel
from utilities.fields import NaturalOrderingField
from utilities.ordering import naturalize_interface
@ -340,8 +340,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
@property
def primary_ip(self):
config = ConfigResolver()
if config.PREFER_IPV4 and self.primary_ip4:
if Config().PREFER_IPV4 and self.primary_ip4:
return self.primary_ip4
elif self.primary_ip6:
return self.primary_ip6