Merge branch 'feature' into 5284-vlangroup-scope

This commit is contained in:
Jeremy Stretch 2021-03-10 14:51:11 -05:00
commit f4e49495e2
24 changed files with 62 additions and 96 deletions

View File

@ -1,12 +1,11 @@
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.fields import ASNField
from dcim.models import CableTermination, PathEndpoint
from extras.models import ObjectChange, TaggedItem
from extras.models import ObjectChange
from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin, OrganizationalModel, PrimaryModel
from netbox.models import BigIDModel, ChangeLoggedModel, OrganizationalModel, PrimaryModel
from utilities.querysets import RestrictedQuerySet
from .choices import *
from .querysets import CircuitQuerySet
@ -60,7 +59,6 @@ class Provider(PrimaryModel):
comments = models.TextField(
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -184,7 +182,6 @@ class Circuit(PrimaryModel):
)
objects = CircuitQuerySet.as_manager()
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
@ -234,7 +231,8 @@ class Circuit(PrimaryModel):
return self._get_termination('Z')
class CircuitTermination(ChangeLoggingMixin, BigIDModel, PathEndpoint, CableTermination):
@extras_features('webhooks')
class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
circuit = models.ForeignKey(
to='circuits.Circuit',
on_delete=models.CASCADE,

View File

@ -6,13 +6,11 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.db.models import Sum
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from dcim.fields import PathField
from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import BigIDModel, PrimaryModel
from utilities.fields import ColorField
@ -108,7 +106,6 @@ class Cable(PrimaryModel):
blank=True,
null=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -5,7 +5,7 @@ from django.db import models
from dcim.choices import *
from dcim.constants import *
from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin
from netbox.models import ChangeLoggedModel
from utilities.fields import NaturalOrderingField
from utilities.querysets import RestrictedQuerySet
from utilities.ordering import naturalize_interface
@ -26,7 +26,7 @@ __all__ = (
)
class ComponentTemplateModel(ChangeLoggingMixin, BigIDModel):
class ComponentTemplateModel(ChangeLoggedModel):
device_type = models.ForeignKey(
to='dcim.DeviceType',
on_delete=models.CASCADE,
@ -76,7 +76,7 @@ class ComponentTemplateModel(ChangeLoggingMixin, BigIDModel):
return super().to_objectchange(action, related_object=device_type)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class ConsolePortTemplate(ComponentTemplateModel):
"""
A template for a ConsolePort to be created for a new Device.
@ -100,7 +100,7 @@ class ConsolePortTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class ConsoleServerPortTemplate(ComponentTemplateModel):
"""
A template for a ConsoleServerPort to be created for a new Device.
@ -124,7 +124,7 @@ class ConsoleServerPortTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class PowerPortTemplate(ComponentTemplateModel):
"""
A template for a PowerPort to be created for a new Device.
@ -171,7 +171,7 @@ class PowerPortTemplate(ComponentTemplateModel):
})
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class PowerOutletTemplate(ComponentTemplateModel):
"""
A template for a PowerOutlet to be created for a new Device.
@ -223,7 +223,7 @@ class PowerOutletTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class InterfaceTemplate(ComponentTemplateModel):
"""
A template for a physical data interface on a new Device.
@ -258,7 +258,7 @@ class InterfaceTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class FrontPortTemplate(ComponentTemplateModel):
"""
Template for a pass-through port on the front of a new Device.
@ -319,7 +319,7 @@ class FrontPortTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class RearPortTemplate(ComponentTemplateModel):
"""
Template for a pass-through port on the rear of a new Device.
@ -350,7 +350,7 @@ class RearPortTemplate(ComponentTemplateModel):
)
@extras_features('custom_fields', 'export_templates', 'webhooks')
@extras_features('webhooks')
class DeviceBayTemplate(ComponentTemplateModel):
"""
A template for a DeviceBay to be created for a new parent Device.

View File

@ -6,12 +6,10 @@ from django.db import models
from django.db.models import Sum
from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from dcim.fields import MACAddressField
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import PrimaryModel
from utilities.fields import NaturalOrderingField
@ -227,7 +225,6 @@ class ConsolePort(ComponentModel, CableTermination, PathEndpoint):
null=True,
help_text='Port speed in bits per second'
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description']
@ -271,7 +268,6 @@ class ConsoleServerPort(ComponentModel, CableTermination, PathEndpoint):
null=True,
help_text='Port speed in bits per second'
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description']
@ -321,7 +317,6 @@ class PowerPort(ComponentModel, CableTermination, PathEndpoint):
validators=[MinValueValidator(1)],
help_text="Allocated power draw (watts)"
)
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description',
@ -434,7 +429,6 @@ class PowerOutlet(ComponentModel, CableTermination, PathEndpoint):
blank=True,
help_text="Phase (for three-phase feeds)"
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description']
@ -568,7 +562,6 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint):
object_id_field='assigned_object_id',
related_query_name='interface'
)
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'device', 'name', 'label', 'parent', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'mtu',
@ -705,7 +698,6 @@ class FrontPort(ComponentModel, CableTermination):
MaxValueValidator(REARPORT_POSITIONS_MAX)
]
)
tags = TaggableManager(through=TaggedItem)
csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description',
@ -766,7 +758,6 @@ class RearPort(ComponentModel, CableTermination):
MaxValueValidator(REARPORT_POSITIONS_MAX)
]
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description']
@ -816,7 +807,6 @@ class DeviceBay(ComponentModel):
blank=True,
null=True
)
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'installed_device', 'description']
@ -909,8 +899,6 @@ class InventoryItem(MPTTModel, ComponentModel):
help_text='This item was automatically discovered'
)
tags = TaggableManager(through=TaggedItem)
objects = TreeManager()
csv_headers = [

View File

@ -9,11 +9,10 @@ from django.db import models
from django.db.models import F, ProtectedError
from django.urls import reverse
from django.utils.safestring import mark_safe
from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from extras.models import ConfigContextModel, TaggedItem
from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features
from netbox.models import OrganizationalModel, PrimaryModel
@ -136,7 +135,6 @@ class DeviceType(PrimaryModel):
comments = models.TextField(
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -601,7 +599,6 @@ class Device(PrimaryModel, ConfigContextModel):
object_id_field='assigned_object_id',
related_query_name='device'
)
tags = TaggableManager(through=TaggedItem)
objects = ConfigContextModelQuerySet.as_manager()
@ -916,7 +913,6 @@ class VirtualChassis(PrimaryModel):
max_length=30,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -2,11 +2,9 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import PrimaryModel
from utilities.querysets import RestrictedQuerySet
@ -41,7 +39,6 @@ class PowerPanel(PrimaryModel):
name = models.CharField(
max_length=100
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -133,7 +130,6 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
comments = models.TextField(
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -11,12 +11,10 @@ from django.db import models
from django.db.models import Count, Sum
from django.urls import reverse
from mptt.models import TreeForeignKey
from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from dcim.elevations import RackElevationSVG
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices
@ -251,7 +249,6 @@ class Rack(PrimaryModel):
images = GenericRelation(
to='extras.ImageAttachment'
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -558,7 +555,6 @@ class RackReservation(PrimaryModel):
description = models.CharField(
max_length=200
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -2,13 +2,11 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from django.urls import reverse
from mptt.models import TreeForeignKey
from taggit.managers import TaggableManager
from timezone_field import TimeZoneField
from dcim.choices import *
from dcim.constants import *
from dcim.fields import ASNField
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import NestedGroupModel, PrimaryModel
from utilities.fields import NaturalOrderingField
@ -232,7 +230,6 @@ class Site(PrimaryModel):
images = GenericRelation(
to='extras.ImageAttachment'
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -16,7 +16,7 @@ from extras.choices import *
from extras.constants import *
from extras.querysets import ConfigContextQuerySet
from extras.utils import extras_features, FeatureQuery, image_upload
from netbox.models import BigIDModel, ChangeLoggingMixin
from netbox.models import BigIDModel, ChangeLoggedModel
from utilities.querysets import RestrictedQuerySet
from utilities.utils import deepmerge, render_jinja2
@ -379,7 +379,8 @@ class ImageAttachment(BigIDModel):
# Config contexts
#
class ConfigContext(ChangeLoggingMixin, BigIDModel):
@extras_features('webhooks')
class ConfigContext(ChangeLoggedModel):
"""
A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned
qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B

View File

@ -2,7 +2,8 @@ from django.db import models
from django.utils.text import slugify
from taggit.models import TagBase, GenericTaggedItemBase
from netbox.models import BigIDModel, ChangeLoggingMixin
from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggedModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField
from utilities.querysets import RestrictedQuerySet
@ -12,7 +13,8 @@ from utilities.querysets import RestrictedQuerySet
# Tags
#
class Tag(ChangeLoggingMixin, BigIDModel, TagBase):
@extras_features('webhooks')
class Tag(ChangeLoggedModel, TagBase):
color = ColorField(
default=ColorChoices.COLOR_GREY
)

View File

@ -6,10 +6,8 @@ from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import F
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Device
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import OrganizationalModel, PrimaryModel
from ipam.choices import *
@ -107,7 +105,6 @@ class Aggregate(PrimaryModel):
max_length=200,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -292,7 +289,6 @@ class Prefix(PrimaryModel):
max_length=200,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = PrefixQuerySet.as_manager()
@ -564,7 +560,6 @@ class IPAddress(PrimaryModel):
max_length=200,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = IPAddressManager()

View File

@ -3,9 +3,7 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features
from ipam.choices import *
from ipam.constants import *
@ -66,7 +64,6 @@ class Service(PrimaryModel):
max_length=200,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -4,10 +4,8 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Interface
from extras.models import TaggedItem
from extras.utils import extras_features
from ipam.choices import *
from ipam.constants import *
@ -149,7 +147,6 @@ class VLAN(PrimaryModel):
max_length=200,
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -1,8 +1,6 @@
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features
from ipam.constants import *
from netbox.models import PrimaryModel
@ -59,7 +57,6 @@ class VRF(PrimaryModel):
related_name='exporting_vrfs',
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -116,7 +113,6 @@ class RouteTarget(PrimaryModel):
blank=True,
null=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -5,6 +5,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.core.validators import ValidationError
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from extras.choices import ObjectChangeActionChoices
from utilities.mptt import TreeManager
@ -12,8 +13,7 @@ from utilities.utils import serialize_object
__all__ = (
'BigIDModel',
'ChangeLoggingMixin',
'CustomFieldsMixin',
'ChangeLoggedModel',
'NestedGroupModel',
'OrganizationalModel',
'PrimaryModel',
@ -137,12 +137,19 @@ class BigIDModel(models.Model):
abstract = True
class ChangeLoggedModel(ChangeLoggingMixin, BigIDModel):
"""
Base model for all objects which support change logging.
"""
class Meta:
abstract = True
class PrimaryModel(ChangeLoggingMixin, CustomFieldsMixin, BigIDModel):
"""
Primary models represent real objects within the infrastructure being modeled.
"""
# TODO
# tags = TaggableManager(through=TaggedItem)
tags = TaggableManager(through='extras.TaggedItem')
class Meta:
abstract = True

View File

@ -12,9 +12,7 @@ from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.encoding import force_bytes
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import BigIDModel, OrganizationalModel, PrimaryModel
from utilities.querysets import RestrictedQuerySet
@ -312,7 +310,6 @@ class Secret(PrimaryModel):
max_length=128,
editable=False
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -57,9 +57,10 @@
</tr>
</table>
</div>
{% plugin_left_page object %}
{% plugin_left_page object %}
</div>
<div class="col-md-6">
{% include 'inc/custom_fields_panel.html' %}
{% include 'extras/inc/tags_panel.html' with tags=object.tags.all %}
{% plugin_right_page object %}
</div>

View File

@ -31,6 +31,14 @@
{% render_field form.tagged_vlans %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
{% endblock %}
{% block buttons %}

View File

@ -1,12 +1,9 @@
from django.db import models
from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import NestedGroupModel, PrimaryModel
from utilities.mptt import TreeManager
from utilities.querysets import RestrictedQuerySet
@ -42,8 +39,6 @@ class TenantGroup(NestedGroupModel):
blank=True
)
objects = TreeManager()
csv_headers = ['name', 'slug', 'parent', 'description']
class Meta:
@ -89,7 +84,6 @@ class Tenant(PrimaryModel):
comments = models.TextField(
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()

View File

@ -103,7 +103,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
# VM interfaces
#
class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
class VMInterfaceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
virtual_machine = NestedVirtualMachineSerializer()
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
@ -119,7 +119,7 @@ class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
model = VMInterface
fields = [
'id', 'url', 'virtual_machine', 'name', 'enabled', 'mtu', 'mac_address', 'description', 'mode',
'untagged_vlan', 'tagged_vlans', 'tags',
'untagged_vlan', 'tagged_vlans', 'tags', 'custom_fields', 'created', 'last_updated',
]
def validate(self, data):

View File

@ -237,7 +237,7 @@ class VirtualMachineFilterSet(
return queryset.exclude(params)
class VMInterfaceFilterSet(BaseFilterSet):
class VMInterfaceFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',

View File

@ -576,7 +576,7 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
# VM interfaces
#
class VMInterfaceForm(BootstrapMixin, InterfaceCommonForm, forms.ModelForm):
class VMInterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(),
required=False,

View File

@ -1,4 +1,5 @@
import django.core.serializers.json
import taggit.managers
from django.db import migrations, models
@ -54,4 +55,14 @@ class Migration(migrations.Migration):
name='last_updated',
field=models.DateTimeField(auto_now=True, null=True),
),
migrations.AddField(
model_name='vminterface',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
migrations.AlterField(
model_name='vminterface',
name='tags',
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
),
]

View File

@ -3,13 +3,12 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel, TaggedItem
from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin, OrganizationalModel, PrimaryModel
from netbox.models import OrganizationalModel, PrimaryModel
from utilities.fields import NaturalOrderingField
from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar
@ -154,7 +153,6 @@ class Cluster(PrimaryModel):
comments = models.TextField(
blank=True
)
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager()
@ -281,7 +279,6 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
object_id_field='assigned_object_id',
related_query_name='virtual_machine'
)
tags = TaggableManager(through=TaggedItem)
objects = ConfigContextModelQuerySet.as_manager()
@ -372,9 +369,8 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
# Interfaces
#
# TODO: Inherit from PrimaryModel
@extras_features('export_templates', 'webhooks')
class VMInterface(ChangeLoggingMixin, BigIDModel, BaseInterface):
@extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
class VMInterface(PrimaryModel, BaseInterface):
virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine',
on_delete=models.CASCADE,
@ -413,10 +409,6 @@ class VMInterface(ChangeLoggingMixin, BigIDModel, BaseInterface):
object_id_field='assigned_object_id',
related_query_name='vminterface'
)
tags = TaggableManager(
through=TaggedItem,
related_name='vminterface'
)
objects = RestrictedQuerySet.as_manager()