mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-13 16:47:34 -06:00
* Closes #18153: Introduce virtual circuit types * Fix TagTestCase * Fix GraphQL API test
This commit is contained in:
parent
89d7487197
commit
83d62315cc
@ -18,6 +18,10 @@ The [provider account](./provideraccount.md) with which the virtual circuit is a
|
|||||||
|
|
||||||
The unique identifier assigned to the virtual circuit by its [provider](./provider.md).
|
The unique identifier assigned to the virtual circuit by its [provider](./provider.md).
|
||||||
|
|
||||||
|
### Type
|
||||||
|
|
||||||
|
The assigned [virtual circuit type](./virtualcircuittype.md).
|
||||||
|
|
||||||
### Status
|
### Status
|
||||||
|
|
||||||
The operational status of the virtual circuit. By default, the following statuses are available:
|
The operational status of the virtual circuit. By default, the following statuses are available:
|
||||||
|
13
docs/models/circuits/virtualcircuittype.md
Normal file
13
docs/models/circuits/virtualcircuittype.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Virtual Circuit Types
|
||||||
|
|
||||||
|
Like physical [circuits](./circuit.md), [virtual circuits](./virtualcircuit.md) are classified by functional type. These types are completely customizable, and can help categorize circuits by function or technology.
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
### Name
|
||||||
|
|
||||||
|
A unique human-friendly name.
|
||||||
|
|
||||||
|
### Slug
|
||||||
|
|
||||||
|
A unique URL-friendly identifier. (This value can be used for filtering.)
|
@ -6,7 +6,7 @@ from circuits.choices import CircuitPriorityChoices, CircuitStatusChoices, Virtu
|
|||||||
from circuits.constants import CIRCUIT_GROUP_ASSIGNMENT_MEMBER_MODELS, CIRCUIT_TERMINATION_TERMINATION_TYPES
|
from circuits.constants import CIRCUIT_GROUP_ASSIGNMENT_MEMBER_MODELS, CIRCUIT_TERMINATION_TERMINATION_TYPES
|
||||||
from circuits.models import (
|
from circuits.models import (
|
||||||
Circuit, CircuitGroup, CircuitGroupAssignment, CircuitTermination, CircuitType, VirtualCircuit,
|
Circuit, CircuitGroup, CircuitGroupAssignment, CircuitTermination, CircuitType, VirtualCircuit,
|
||||||
VirtualCircuitTermination,
|
VirtualCircuitTermination, VirtualCircuitType,
|
||||||
)
|
)
|
||||||
from dcim.api.serializers_.device_components import InterfaceSerializer
|
from dcim.api.serializers_.device_components import InterfaceSerializer
|
||||||
from dcim.api.serializers_.cables import CabledObjectSerializer
|
from dcim.api.serializers_.cables import CabledObjectSerializer
|
||||||
@ -25,6 +25,7 @@ __all__ = (
|
|||||||
'CircuitTypeSerializer',
|
'CircuitTypeSerializer',
|
||||||
'VirtualCircuitSerializer',
|
'VirtualCircuitSerializer',
|
||||||
'VirtualCircuitTerminationSerializer',
|
'VirtualCircuitTerminationSerializer',
|
||||||
|
'VirtualCircuitTypeSerializer',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -175,17 +176,32 @@ class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_):
|
|||||||
return serializer(obj.member, nested=True, context=context).data
|
return serializer(obj.member, nested=True, context=context).data
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeSerializer(NetBoxModelSerializer):
|
||||||
|
|
||||||
|
# Related object counts
|
||||||
|
virtual_circuit_count = RelatedObjectCountField('virtual_circuits')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fields = [
|
||||||
|
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields',
|
||||||
|
'created', 'last_updated', 'virtual_circuit_count',
|
||||||
|
]
|
||||||
|
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'virtual_circuit_count')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitSerializer(NetBoxModelSerializer):
|
class VirtualCircuitSerializer(NetBoxModelSerializer):
|
||||||
provider_network = ProviderNetworkSerializer(nested=True)
|
provider_network = ProviderNetworkSerializer(nested=True)
|
||||||
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
|
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
|
||||||
|
type = VirtualCircuitTypeSerializer(nested=True)
|
||||||
status = ChoiceField(choices=CircuitStatusChoices, required=False)
|
status = ChoiceField(choices=CircuitStatusChoices, required=False)
|
||||||
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
tenant = TenantSerializer(nested=True, required=False, allow_null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display_url', 'display', 'cid', 'provider_network', 'provider_account', 'status', 'tenant',
|
'id', 'url', 'display_url', 'display', 'cid', 'provider_network', 'provider_account', 'type', 'status',
|
||||||
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
brief_fields = ('id', 'url', 'display', 'provider_network', 'cid', 'description')
|
brief_fields = ('id', 'url', 'display', 'provider_network', 'cid', 'description')
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ router.register('circuit-group-assignments', views.CircuitGroupAssignmentViewSet
|
|||||||
|
|
||||||
# Virtual circuits
|
# Virtual circuits
|
||||||
router.register('virtual-circuits', views.VirtualCircuitViewSet)
|
router.register('virtual-circuits', views.VirtualCircuitViewSet)
|
||||||
|
router.register('virtual-circuit-types', views.VirtualCircuitTypeViewSet)
|
||||||
router.register('virtual-circuit-terminations', views.VirtualCircuitTerminationViewSet)
|
router.register('virtual-circuit-terminations', views.VirtualCircuitTerminationViewSet)
|
||||||
|
|
||||||
app_name = 'circuits-api'
|
app_name = 'circuits-api'
|
||||||
|
@ -95,6 +95,16 @@ class ProviderNetworkViewSet(NetBoxModelViewSet):
|
|||||||
filterset_class = filtersets.ProviderNetworkFilterSet
|
filterset_class = filtersets.ProviderNetworkFilterSet
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Virtual circuit types
|
||||||
|
#
|
||||||
|
|
||||||
|
class VirtualCircuitTypeViewSet(NetBoxModelViewSet):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
serializer_class = serializers.VirtualCircuitTypeSerializer
|
||||||
|
filterset_class = filtersets.VirtualCircuitTypeFilterSet
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Virtual circuits
|
# Virtual circuits
|
||||||
#
|
#
|
||||||
|
@ -25,6 +25,7 @@ __all__ = (
|
|||||||
'ProviderFilterSet',
|
'ProviderFilterSet',
|
||||||
'VirtualCircuitFilterSet',
|
'VirtualCircuitFilterSet',
|
||||||
'VirtualCircuitTerminationFilterSet',
|
'VirtualCircuitTerminationFilterSet',
|
||||||
|
'VirtualCircuitTypeFilterSet',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -462,6 +463,13 @@ class CircuitGroupAssignmentFilterSet(NetBoxModelFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeFilterSet(OrganizationalModelFilterSet):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fields = ('id', 'name', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class VirtualCircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
provider_id = django_filters.ModelMultipleChoiceFilter(
|
provider_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='provider_network__provider',
|
field_name='provider_network__provider',
|
||||||
@ -489,6 +497,16 @@ class VirtualCircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
queryset=ProviderNetwork.objects.all(),
|
queryset=ProviderNetwork.objects.all(),
|
||||||
label=_('Provider network (ID)'),
|
label=_('Provider network (ID)'),
|
||||||
)
|
)
|
||||||
|
type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
label=_('Virtual circuit type (ID)'),
|
||||||
|
)
|
||||||
|
type = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='type__slug',
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
label=_('Virtual circuit type (slug)'),
|
||||||
|
)
|
||||||
status = django_filters.MultipleChoiceFilter(
|
status = django_filters.MultipleChoiceFilter(
|
||||||
choices=CircuitStatusChoices,
|
choices=CircuitStatusChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
|
@ -32,6 +32,7 @@ __all__ = (
|
|||||||
'ProviderNetworkBulkEditForm',
|
'ProviderNetworkBulkEditForm',
|
||||||
'VirtualCircuitBulkEditForm',
|
'VirtualCircuitBulkEditForm',
|
||||||
'VirtualCircuitTerminationBulkEditForm',
|
'VirtualCircuitTerminationBulkEditForm',
|
||||||
|
'VirtualCircuitTypeBulkEditForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -297,6 +298,24 @@ class CircuitGroupAssignmentBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
nullable_fields = ('priority',)
|
nullable_fields = ('priority',)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
|
color = ColorField(
|
||||||
|
label=_('Color'),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
label=_('Description'),
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fieldsets = (
|
||||||
|
FieldSet('color', 'description'),
|
||||||
|
)
|
||||||
|
nullable_fields = ('color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm):
|
class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
provider_network = DynamicModelChoiceField(
|
provider_network = DynamicModelChoiceField(
|
||||||
label=_('Provider network'),
|
label=_('Provider network'),
|
||||||
@ -308,6 +327,11 @@ class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
queryset=ProviderAccount.objects.all(),
|
queryset=ProviderAccount.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
type = DynamicModelChoiceField(
|
||||||
|
label=_('Type'),
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
label=_('Status'),
|
label=_('Status'),
|
||||||
choices=add_blank_choice(CircuitStatusChoices),
|
choices=add_blank_choice(CircuitStatusChoices),
|
||||||
|
@ -24,6 +24,7 @@ __all__ = (
|
|||||||
'VirtualCircuitImportForm',
|
'VirtualCircuitImportForm',
|
||||||
'VirtualCircuitTerminationImportForm',
|
'VirtualCircuitTerminationImportForm',
|
||||||
'VirtualCircuitTerminationImportRelatedForm',
|
'VirtualCircuitTerminationImportRelatedForm',
|
||||||
|
'VirtualCircuitTypeImportForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -194,6 +195,14 @@ class CircuitGroupAssignmentImportForm(NetBoxModelImportForm):
|
|||||||
fields = ('member_type', 'member_id', 'group', 'priority')
|
fields = ('member_type', 'member_id', 'group', 'priority')
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeImportForm(NetBoxModelImportForm):
|
||||||
|
slug = SlugField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fields = ('name', 'slug', 'color', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitImportForm(NetBoxModelImportForm):
|
class VirtualCircuitImportForm(NetBoxModelImportForm):
|
||||||
provider_network = CSVModelChoiceField(
|
provider_network = CSVModelChoiceField(
|
||||||
label=_('Provider network'),
|
label=_('Provider network'),
|
||||||
@ -208,6 +217,12 @@ class VirtualCircuitImportForm(NetBoxModelImportForm):
|
|||||||
help_text=_('Assigned provider account (if any)'),
|
help_text=_('Assigned provider account (if any)'),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
type = CSVModelChoiceField(
|
||||||
|
label=_('Type'),
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
help_text=_('Type of virtual circuit')
|
||||||
|
)
|
||||||
status = CSVChoiceField(
|
status = CSVChoiceField(
|
||||||
label=_('Status'),
|
label=_('Status'),
|
||||||
choices=CircuitStatusChoices,
|
choices=CircuitStatusChoices,
|
||||||
@ -224,7 +239,8 @@ class VirtualCircuitImportForm(NetBoxModelImportForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
fields = [
|
fields = [
|
||||||
'cid', 'provider_network', 'provider_account', 'status', 'tenant', 'description', 'comments', 'tags',
|
'cid', 'provider_network', 'provider_account', 'type', 'status', 'tenant', 'description', 'comments',
|
||||||
|
'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ __all__ = (
|
|||||||
'ProviderNetworkFilterForm',
|
'ProviderNetworkFilterForm',
|
||||||
'VirtualCircuitFilterForm',
|
'VirtualCircuitFilterForm',
|
||||||
'VirtualCircuitTerminationFilterForm',
|
'VirtualCircuitTerminationFilterForm',
|
||||||
|
'VirtualCircuitTypeFilterForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -302,12 +303,26 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm):
|
|||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeFilterForm(NetBoxModelFilterSetForm):
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fieldsets = (
|
||||||
|
FieldSet('q', 'filter_id', 'tag'),
|
||||||
|
FieldSet('color', name=_('Attributes')),
|
||||||
|
)
|
||||||
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
color = ColorField(
|
||||||
|
label=_('Color'),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet('q', 'filter_id', 'tag'),
|
FieldSet('q', 'filter_id', 'tag'),
|
||||||
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
|
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
|
||||||
FieldSet('status', name=_('Attributes')),
|
FieldSet('type', 'status', name=_('Attributes')),
|
||||||
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
|
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
|
||||||
)
|
)
|
||||||
selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id')
|
selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id')
|
||||||
@ -332,6 +347,11 @@ class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBox
|
|||||||
},
|
},
|
||||||
label=_('Provider network')
|
label=_('Provider network')
|
||||||
)
|
)
|
||||||
|
type_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label=_('Type')
|
||||||
|
)
|
||||||
status = forms.MultipleChoiceField(
|
status = forms.MultipleChoiceField(
|
||||||
label=_('Status'),
|
label=_('Status'),
|
||||||
choices=CircuitStatusChoices,
|
choices=CircuitStatusChoices,
|
||||||
|
@ -31,6 +31,7 @@ __all__ = (
|
|||||||
'ProviderNetworkForm',
|
'ProviderNetworkForm',
|
||||||
'VirtualCircuitForm',
|
'VirtualCircuitForm',
|
||||||
'VirtualCircuitTerminationForm',
|
'VirtualCircuitTerminationForm',
|
||||||
|
'VirtualCircuitTypeForm',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -305,6 +306,20 @@ class CircuitGroupAssignmentForm(NetBoxModelForm):
|
|||||||
self.instance.member = self.cleaned_data.get('member')
|
self.instance.member = self.cleaned_data.get('member')
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeForm(NetBoxModelForm):
|
||||||
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
FieldSet('name', 'slug', 'color', 'description', 'tags'),
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fields = [
|
||||||
|
'name', 'slug', 'color', 'description', 'tags',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
|
class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
|
||||||
provider_network = DynamicModelChoiceField(
|
provider_network = DynamicModelChoiceField(
|
||||||
label=_('Provider network'),
|
label=_('Provider network'),
|
||||||
@ -316,11 +331,16 @@ class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
|
|||||||
queryset=ProviderAccount.objects.all(),
|
queryset=ProviderAccount.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
type = DynamicModelChoiceField(
|
||||||
|
queryset=VirtualCircuitType.objects.all(),
|
||||||
|
quick_add=True
|
||||||
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
FieldSet(
|
FieldSet(
|
||||||
'provider_network', 'provider_account', 'cid', 'status', 'description', 'tags', name=_('Virtual circuit'),
|
'provider_network', 'provider_account', 'cid', 'type', 'status', 'description', 'tags',
|
||||||
|
name=_('Virtual circuit'),
|
||||||
),
|
),
|
||||||
FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
|
FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
|
||||||
)
|
)
|
||||||
@ -328,7 +348,7 @@ class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
fields = [
|
fields = [
|
||||||
'cid', 'provider_network', 'provider_account', 'status', 'description', 'tenant_group', 'tenant',
|
'cid', 'provider_network', 'provider_account', 'type', 'status', 'description', 'tenant_group', 'tenant',
|
||||||
'comments', 'tags',
|
'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ __all__ = (
|
|||||||
'ProviderNetworkFilter',
|
'ProviderNetworkFilter',
|
||||||
'VirtualCircuitFilter',
|
'VirtualCircuitFilter',
|
||||||
'VirtualCircuitTerminationFilter',
|
'VirtualCircuitTerminationFilter',
|
||||||
|
'VirtualCircuitTypeFilter',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +66,12 @@ class ProviderNetworkFilter(BaseFilterMixin):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry_django.filter(models.VirtualCircuitType, lookups=True)
|
||||||
|
@autotype_decorator(filtersets.VirtualCircuitTypeFilterSet)
|
||||||
|
class VirtualCircuitTypeFilter(BaseFilterMixin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@strawberry_django.filter(models.VirtualCircuit, lookups=True)
|
@strawberry_django.filter(models.VirtualCircuit, lookups=True)
|
||||||
@autotype_decorator(filtersets.VirtualCircuitFilterSet)
|
@autotype_decorator(filtersets.VirtualCircuitFilterSet)
|
||||||
class VirtualCircuitFilter(BaseFilterMixin):
|
class VirtualCircuitFilter(BaseFilterMixin):
|
||||||
|
@ -37,3 +37,6 @@ class CircuitsQuery:
|
|||||||
|
|
||||||
virtual_circuit_termination: VirtualCircuitTerminationType = strawberry_django.field()
|
virtual_circuit_termination: VirtualCircuitTerminationType = strawberry_django.field()
|
||||||
virtual_circuit_termination_list: List[VirtualCircuitTerminationType] = strawberry_django.field()
|
virtual_circuit_termination_list: List[VirtualCircuitTerminationType] = strawberry_django.field()
|
||||||
|
|
||||||
|
virtual_circuit_type: VirtualCircuitTypeType = strawberry_django.field()
|
||||||
|
virtual_circuit_type_list: List[VirtualCircuitTypeType] = strawberry_django.field()
|
||||||
|
@ -21,6 +21,7 @@ __all__ = (
|
|||||||
'ProviderNetworkType',
|
'ProviderNetworkType',
|
||||||
'VirtualCircuitTerminationType',
|
'VirtualCircuitTerminationType',
|
||||||
'VirtualCircuitType',
|
'VirtualCircuitType',
|
||||||
|
'VirtualCircuitTypeType',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -130,6 +131,17 @@ class CircuitGroupAssignmentType(TagsMixin, BaseObjectType):
|
|||||||
return self.member
|
return self.member
|
||||||
|
|
||||||
|
|
||||||
|
@strawberry_django.type(
|
||||||
|
models.VirtualCircuitType,
|
||||||
|
fields='__all__',
|
||||||
|
filters=VirtualCircuitTypeFilter
|
||||||
|
)
|
||||||
|
class VirtualCircuitTypeType(OrganizationalObjectType):
|
||||||
|
color: str
|
||||||
|
|
||||||
|
virtual_circuits: List[Annotated["VirtualCircuitType", strawberry.lazy('circuits.graphql.types')]]
|
||||||
|
|
||||||
|
|
||||||
@strawberry_django.type(
|
@strawberry_django.type(
|
||||||
models.VirtualCircuitTermination,
|
models.VirtualCircuitTermination,
|
||||||
fields='__all__',
|
fields='__all__',
|
||||||
@ -154,6 +166,9 @@ class VirtualCircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType):
|
|||||||
class VirtualCircuitType(NetBoxObjectType):
|
class VirtualCircuitType(NetBoxObjectType):
|
||||||
provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"])
|
provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"])
|
||||||
provider_account: ProviderAccountType | None
|
provider_account: ProviderAccountType | None
|
||||||
|
type: Annotated["VirtualCircuitTypeType", strawberry.lazy('circuits.graphql.types')] = strawberry_django.field(
|
||||||
|
select_related=["type"]
|
||||||
|
)
|
||||||
tenant: TenantType | None
|
tenant: TenantType | None
|
||||||
|
|
||||||
terminations: List[VirtualCircuitTerminationType]
|
terminations: List[VirtualCircuitTerminationType]
|
||||||
|
@ -2,6 +2,7 @@ import django.db.models.deletion
|
|||||||
import taggit.managers
|
import taggit.managers
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
import utilities.fields
|
||||||
import utilities.json
|
import utilities.json
|
||||||
|
|
||||||
|
|
||||||
@ -14,6 +15,29 @@ class Migration(migrations.Migration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='VirtualCircuitType',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||||
|
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||||
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
|
('custom_field_data', models.JSONField(
|
||||||
|
blank=True,
|
||||||
|
default=dict,
|
||||||
|
encoder=utilities.json.CustomFieldJSONEncoder
|
||||||
|
)),
|
||||||
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
|
('color', utilities.fields.ColorField(blank=True, max_length=6)),
|
||||||
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'virtual circuit type',
|
||||||
|
'verbose_name_plural': 'virtual circuit types',
|
||||||
|
'ordering': ('name',),
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='VirtualCircuit',
|
name='VirtualCircuit',
|
||||||
fields=[
|
fields=[
|
||||||
@ -47,6 +71,14 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
|
(
|
||||||
|
'type',
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
related_name='virtual_circuits',
|
||||||
|
to='circuits.virtualcircuittype'
|
||||||
|
)
|
||||||
|
),
|
||||||
(
|
(
|
||||||
'tenant',
|
'tenant',
|
||||||
models.ForeignKey(
|
models.ForeignKey(
|
||||||
|
23
netbox/circuits/models/base.py
Normal file
23
netbox/circuits/models/base.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from netbox.models import OrganizationalModel
|
||||||
|
from utilities.fields import ColorField
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'BaseCircuitType',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BaseCircuitType(OrganizationalModel):
|
||||||
|
"""
|
||||||
|
Abstract base model to represent a type of physical or virtual circuit.
|
||||||
|
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
|
||||||
|
"Long Haul," "Metro," or "Out-of-Band".
|
||||||
|
"""
|
||||||
|
color = ColorField(
|
||||||
|
verbose_name=_('color'),
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
@ -13,7 +13,7 @@ from netbox.models.mixins import DistanceMixin
|
|||||||
from netbox.models.features import (
|
from netbox.models.features import (
|
||||||
ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, ImageAttachmentsMixin, TagsMixin,
|
ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, ImageAttachmentsMixin, TagsMixin,
|
||||||
)
|
)
|
||||||
from utilities.fields import ColorField
|
from .base import BaseCircuitType
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Circuit',
|
'Circuit',
|
||||||
@ -24,16 +24,11 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CircuitType(OrganizationalModel):
|
class CircuitType(BaseCircuitType):
|
||||||
"""
|
"""
|
||||||
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
|
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
|
||||||
"Long Haul," "Metro," or "Out-of-Band".
|
"Long Haul," "Metro," or "Out-of-Band".
|
||||||
"""
|
"""
|
||||||
color = ColorField(
|
|
||||||
verbose_name=_('color'),
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('name',)
|
ordering = ('name',)
|
||||||
verbose_name = _('circuit type')
|
verbose_name = _('circuit type')
|
||||||
@ -64,7 +59,7 @@ class Circuit(ContactsMixin, ImageAttachmentsMixin, DistanceMixin, PrimaryModel)
|
|||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
type = models.ForeignKey(
|
type = models.ForeignKey(
|
||||||
to='CircuitType',
|
to='circuits.CircuitType',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
related_name='circuits'
|
related_name='circuits'
|
||||||
)
|
)
|
||||||
|
@ -9,13 +9,26 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from circuits.choices import *
|
from circuits.choices import *
|
||||||
from netbox.models import ChangeLoggedModel, PrimaryModel
|
from netbox.models import ChangeLoggedModel, PrimaryModel
|
||||||
from netbox.models.features import CustomFieldsMixin, CustomLinksMixin, TagsMixin
|
from netbox.models.features import CustomFieldsMixin, CustomLinksMixin, TagsMixin
|
||||||
|
from .base import BaseCircuitType
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'VirtualCircuit',
|
'VirtualCircuit',
|
||||||
'VirtualCircuitTermination',
|
'VirtualCircuitTermination',
|
||||||
|
'VirtualCircuitType',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitType(BaseCircuitType):
|
||||||
|
"""
|
||||||
|
Like physical circuits, virtual circuits can be organized by their functional role. For example, a user might wish
|
||||||
|
to categorize virtual circuits by their technological nature or by product name.
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
ordering = ('name',)
|
||||||
|
verbose_name = _('virtual circuit type')
|
||||||
|
verbose_name_plural = _('virtual circuit types')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuit(PrimaryModel):
|
class VirtualCircuit(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A virtual connection between two or more endpoints, delivered across one or more physical circuits.
|
A virtual connection between two or more endpoints, delivered across one or more physical circuits.
|
||||||
@ -37,6 +50,11 @@ class VirtualCircuit(PrimaryModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
type = models.ForeignKey(
|
||||||
|
to='circuits.VirtualCircuitType',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name='virtual_circuits'
|
||||||
|
)
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
verbose_name=_('status'),
|
verbose_name=_('status'),
|
||||||
max_length=50,
|
max_length=50,
|
||||||
@ -63,6 +81,7 @@ class VirtualCircuit(PrimaryModel):
|
|||||||
)
|
)
|
||||||
prerequisite_models = (
|
prerequisite_models = (
|
||||||
'circuits.ProviderNetwork',
|
'circuits.ProviderNetwork',
|
||||||
|
'circuits.VirtualCircuitType',
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -100,3 +100,14 @@ class VirtualCircuitTerminationIndex(SearchIndex):
|
|||||||
('description', 500),
|
('description', 500),
|
||||||
)
|
)
|
||||||
display_attrs = ('virtual_circuit', 'role', 'description')
|
display_attrs = ('virtual_circuit', 'role', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class VirtualCircuitTypeIndex(SearchIndex):
|
||||||
|
model = models.VirtualCircuitType
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
display_attrs = ('description',)
|
||||||
|
@ -45,7 +45,7 @@ class CircuitTypeTable(NetBoxTable):
|
|||||||
'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated',
|
'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated',
|
||||||
'actions',
|
'actions',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
|
default_columns = ('pk', 'name', 'circuit_count', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
@ -61,6 +61,10 @@ class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
|||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name=_('Account')
|
verbose_name=_('Account')
|
||||||
)
|
)
|
||||||
|
type = tables.Column(
|
||||||
|
verbose_name=_('Type'),
|
||||||
|
linkify=True
|
||||||
|
)
|
||||||
status = columns.ChoiceFieldColumn()
|
status = columns.ChoiceFieldColumn()
|
||||||
termination_a = columns.TemplateColumn(
|
termination_a = columns.TemplateColumn(
|
||||||
template_code=CIRCUITTERMINATION_LINK,
|
template_code=CIRCUITTERMINATION_LINK,
|
||||||
|
@ -8,9 +8,34 @@ from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
|||||||
__all__ = (
|
__all__ = (
|
||||||
'VirtualCircuitTable',
|
'VirtualCircuitTable',
|
||||||
'VirtualCircuitTerminationTable',
|
'VirtualCircuitTerminationTable',
|
||||||
|
'VirtualCircuitTypeTable',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeTable(NetBoxTable):
|
||||||
|
name = tables.Column(
|
||||||
|
linkify=True,
|
||||||
|
verbose_name=_('Name'),
|
||||||
|
)
|
||||||
|
color = columns.ColorColumn()
|
||||||
|
tags = columns.TagColumn(
|
||||||
|
url_name='circuits:virtualcircuittype_list'
|
||||||
|
)
|
||||||
|
virtual_circuit_count = columns.LinkedCountColumn(
|
||||||
|
viewname='circuits:virtualcircuit_list',
|
||||||
|
url_params={'type_id': 'pk'},
|
||||||
|
verbose_name=_('Circuits')
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta(NetBoxTable.Meta):
|
||||||
|
model = VirtualCircuitType
|
||||||
|
fields = (
|
||||||
|
'pk', 'id', 'name', 'virtual_circuit_count', 'color', 'description', 'slug', 'tags', 'created',
|
||||||
|
'last_updated', 'actions',
|
||||||
|
)
|
||||||
|
default_columns = ('pk', 'name', 'virtual_circuit_count', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
cid = tables.Column(
|
cid = tables.Column(
|
||||||
linkify=True,
|
linkify=True,
|
||||||
@ -29,6 +54,10 @@ class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable)
|
|||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name=_('Account')
|
verbose_name=_('Account')
|
||||||
)
|
)
|
||||||
|
type = tables.Column(
|
||||||
|
verbose_name=_('Type'),
|
||||||
|
linkify=True
|
||||||
|
)
|
||||||
status = columns.ChoiceFieldColumn()
|
status = columns.ChoiceFieldColumn()
|
||||||
termination_count = columns.LinkedCountColumn(
|
termination_count = columns.LinkedCountColumn(
|
||||||
viewname='circuits:virtualcircuittermination_list',
|
viewname='circuits:virtualcircuittermination_list',
|
||||||
@ -45,12 +74,12 @@ class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable)
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'cid', 'provider', 'provider_account', 'provider_network', 'status', 'tenant', 'tenant_group',
|
'pk', 'id', 'cid', 'provider', 'provider_account', 'provider_network', 'type', 'status', 'tenant',
|
||||||
'description', 'comments', 'tags', 'created', 'last_updated',
|
'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'cid', 'provider', 'provider_account', 'provider_network', 'status', 'tenant', 'termination_count',
|
'pk', 'cid', 'provider', 'provider_account', 'provider_network', 'type', 'status', 'tenant',
|
||||||
'description',
|
'termination_count', 'description',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -409,6 +409,38 @@ class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeTest(APIViewTestCases.APIViewTestCase):
|
||||||
|
model = VirtualCircuitType
|
||||||
|
brief_fields = ['description', 'display', 'id', 'name', 'slug', 'url', 'virtual_circuit_count']
|
||||||
|
create_data = (
|
||||||
|
{
|
||||||
|
'name': 'Virtual Circuit Type 4',
|
||||||
|
'slug': 'virtual-circuit-type-4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Virtual Circuit Type 5',
|
||||||
|
'slug': 'virtual-circuit-type-5',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'Virtual Circuit Type 6',
|
||||||
|
'slug': 'virtual-circuit-type-6',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
bulk_update_data = {
|
||||||
|
'description': 'New description',
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
virtual_circuit_types = (
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 1', slug='virtual-circuit-type-1'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 2', slug='virtual-circuit-type-2'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 3', slug='virtual-circuit-type-3'),
|
||||||
|
)
|
||||||
|
VirtualCircuitType.objects.bulk_create(virtual_circuit_types)
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitTest(APIViewTestCases.APIViewTestCase):
|
class VirtualCircuitTest(APIViewTestCases.APIViewTestCase):
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
brief_fields = ['cid', 'description', 'display', 'id', 'provider_network', 'url']
|
brief_fields = ['cid', 'description', 'display', 'id', 'provider_network', 'url']
|
||||||
@ -421,21 +453,28 @@ class VirtualCircuitTest(APIViewTestCases.APIViewTestCase):
|
|||||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||||
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
||||||
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
||||||
|
virtual_circuit_type = VirtualCircuitType.objects.create(
|
||||||
|
name='Virtual Circuit Type 1',
|
||||||
|
slug='virtual-circuit-type-1'
|
||||||
|
)
|
||||||
|
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
|
type=virtual_circuit_type,
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1'
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
|
type=virtual_circuit_type,
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2'
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
|
type=virtual_circuit_type,
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3'
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -446,18 +485,21 @@ class VirtualCircuitTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'cid': 'Virtual Circuit 4',
|
'cid': 'Virtual Circuit 4',
|
||||||
'provider_network': provider_network.pk,
|
'provider_network': provider_network.pk,
|
||||||
'provider_account': provider_account.pk,
|
'provider_account': provider_account.pk,
|
||||||
|
'type': virtual_circuit_type.pk,
|
||||||
'status': CircuitStatusChoices.STATUS_PLANNED,
|
'status': CircuitStatusChoices.STATUS_PLANNED,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'cid': 'Virtual Circuit 5',
|
'cid': 'Virtual Circuit 5',
|
||||||
'provider_network': provider_network.pk,
|
'provider_network': provider_network.pk,
|
||||||
'provider_account': provider_account.pk,
|
'provider_account': provider_account.pk,
|
||||||
|
'type': virtual_circuit_type.pk,
|
||||||
'status': CircuitStatusChoices.STATUS_PLANNED,
|
'status': CircuitStatusChoices.STATUS_PLANNED,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'cid': 'Virtual Circuit 6',
|
'cid': 'Virtual Circuit 6',
|
||||||
'provider_network': provider_network.pk,
|
'provider_network': provider_network.pk,
|
||||||
'provider_account': provider_account.pk,
|
'provider_account': provider_account.pk,
|
||||||
|
'type': virtual_circuit_type.pk,
|
||||||
'status': CircuitStatusChoices.STATUS_PLANNED,
|
'status': CircuitStatusChoices.STATUS_PLANNED,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -563,27 +605,35 @@ class VirtualCircuitTerminationTest(APIViewTestCases.APIViewTestCase):
|
|||||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||||
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
||||||
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
||||||
|
virtual_circuit_type = VirtualCircuitType.objects.create(
|
||||||
|
name='Virtual Circuit Type 1',
|
||||||
|
slug='virtual-circuit-type-1'
|
||||||
|
)
|
||||||
|
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 4'
|
cid='Virtual Circuit 4',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
||||||
|
@ -656,12 +656,12 @@ class CircuitGroupAssignmentTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Provider(name='Provider 2', slug='provider-2'),
|
Provider(name='Provider 2', slug='provider-2'),
|
||||||
Provider(name='Provider 3', slug='provider-3'),
|
Provider(name='Provider 3', slug='provider-3'),
|
||||||
))
|
))
|
||||||
circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
circuit_type = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
||||||
|
|
||||||
circuits = (
|
circuits = (
|
||||||
Circuit(cid='Circuit 1', provider=providers[0], type=circuittype),
|
Circuit(cid='Circuit 1', provider=providers[0], type=circuit_type),
|
||||||
Circuit(cid='Circuit 2', provider=providers[1], type=circuittype),
|
Circuit(cid='Circuit 2', provider=providers[1], type=circuit_type),
|
||||||
Circuit(cid='Circuit 3', provider=providers[2], type=circuittype),
|
Circuit(cid='Circuit 3', provider=providers[2], type=circuit_type),
|
||||||
)
|
)
|
||||||
Circuit.objects.bulk_create(circuits)
|
Circuit.objects.bulk_create(circuits)
|
||||||
|
|
||||||
@ -672,18 +672,25 @@ class CircuitGroupAssignmentTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
ProviderNetwork.objects.bulk_create(provider_networks)
|
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||||
|
|
||||||
|
virtual_circuit_type = VirtualCircuitType.objects.create(
|
||||||
|
name='Virtual Circuit Type 1',
|
||||||
|
slug='virtual-circuit-type-1'
|
||||||
|
)
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[1],
|
provider_network=provider_networks[1],
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[2],
|
provider_network=provider_networks[2],
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
||||||
@ -837,6 +844,36 @@ class ProviderAccountTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
filterset = VirtualCircuitTypeFilterSet
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
VirtualCircuitType.objects.bulk_create((
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 1', slug='virtual-circuit-type-1', description='foobar1'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 2', slug='virtual-circuit-type-2', description='foobar2'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 3', slug='virtual-circuit-type-3'),
|
||||||
|
))
|
||||||
|
|
||||||
|
def test_q(self):
|
||||||
|
params = {'q': 'foobar1'}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
def test_name(self):
|
||||||
|
params = {'name': ['Virtual Circuit Type 1']}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
def test_slug(self):
|
||||||
|
params = {'slug': ['virtual-circuit-type-1']}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
def test_description(self):
|
||||||
|
params = {'description': ['foobar1', 'foobar2']}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = VirtualCircuit.objects.all()
|
queryset = VirtualCircuit.objects.all()
|
||||||
filterset = VirtualCircuitFilterSet
|
filterset = VirtualCircuitFilterSet
|
||||||
@ -880,12 +917,20 @@ class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
ProviderNetwork.objects.bulk_create(provider_networks)
|
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||||
|
|
||||||
|
virtual_circuit_types = (
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 1', slug='virtual-circuit-type-1'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 2', slug='virtual-circuit-type-2'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 3', slug='virtual-circuit-type-3'),
|
||||||
|
)
|
||||||
|
VirtualCircuitType.objects.bulk_create(virtual_circuit_types)
|
||||||
|
|
||||||
virutal_circuits = (
|
virutal_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
provider_account=provider_accounts[0],
|
provider_account=provider_accounts[0],
|
||||||
tenant=tenants[0],
|
tenant=tenants[0],
|
||||||
cid='Virtual Circuit 1',
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_types[0],
|
||||||
status=CircuitStatusChoices.STATUS_PLANNED,
|
status=CircuitStatusChoices.STATUS_PLANNED,
|
||||||
description='virtualcircuit1',
|
description='virtualcircuit1',
|
||||||
),
|
),
|
||||||
@ -894,6 +939,7 @@ class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
provider_account=provider_accounts[1],
|
provider_account=provider_accounts[1],
|
||||||
tenant=tenants[1],
|
tenant=tenants[1],
|
||||||
cid='Virtual Circuit 2',
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_types[1],
|
||||||
status=CircuitStatusChoices.STATUS_ACTIVE,
|
status=CircuitStatusChoices.STATUS_ACTIVE,
|
||||||
description='virtualcircuit2',
|
description='virtualcircuit2',
|
||||||
),
|
),
|
||||||
@ -902,6 +948,7 @@ class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
provider_account=provider_accounts[2],
|
provider_account=provider_accounts[2],
|
||||||
tenant=tenants[2],
|
tenant=tenants[2],
|
||||||
cid='Virtual Circuit 3',
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_types[2],
|
||||||
status=CircuitStatusChoices.STATUS_DEPROVISIONING,
|
status=CircuitStatusChoices.STATUS_DEPROVISIONING,
|
||||||
description='virtualcircuit3',
|
description='virtualcircuit3',
|
||||||
),
|
),
|
||||||
@ -933,6 +980,13 @@ class VirtualCircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
|
params = {'provider_network_id': [provider_networks[0].pk, provider_networks[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_type(self):
|
||||||
|
virtual_circuit_types = VirtualCircuitType.objects.all()[:2]
|
||||||
|
params = {'type_id': [virtual_circuit_types[0].pk, virtual_circuit_types[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
params = {'type': [virtual_circuit_types[0].slug, virtual_circuit_types[1].slug]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_status(self):
|
def test_status(self):
|
||||||
params = {'status': [CircuitStatusChoices.STATUS_ACTIVE, CircuitStatusChoices.STATUS_PLANNED]}
|
params = {'status': [CircuitStatusChoices.STATUS_ACTIVE, CircuitStatusChoices.STATUS_PLANNED]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
@ -1029,22 +1083,29 @@ class VirtualCircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
ProviderAccount(provider=providers[2], account='Provider Account 3'),
|
ProviderAccount(provider=providers[2], account='Provider Account 3'),
|
||||||
)
|
)
|
||||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||||
|
virtual_circuit_type = VirtualCircuitType.objects.create(
|
||||||
|
name='Virtual Circuit Type 1',
|
||||||
|
slug='virtual-circuit-type-1'
|
||||||
|
)
|
||||||
|
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
provider_account=provider_accounts[0],
|
provider_account=provider_accounts[0],
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[1],
|
provider_network=provider_networks[1],
|
||||||
provider_account=provider_accounts[1],
|
provider_account=provider_accounts[1],
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[2],
|
provider_network=provider_networks[2],
|
||||||
provider_account=provider_accounts[2],
|
provider_account=provider_accounts[2],
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
||||||
|
@ -543,6 +543,47 @@ class CircuitGroupAssignmentTestCase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualCircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
||||||
|
model = VirtualCircuitType
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
|
||||||
|
virtual_circuit_types = (
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 1', slug='circuit-type-1'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 2', slug='circuit-type-2'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 3', slug='circuit-type-3'),
|
||||||
|
)
|
||||||
|
VirtualCircuitType.objects.bulk_create(virtual_circuit_types)
|
||||||
|
|
||||||
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
|
cls.form_data = {
|
||||||
|
'name': 'Virtual Circuit Type X',
|
||||||
|
'slug': 'virtual-circuit-type-x',
|
||||||
|
'description': 'A new virtual circuit type',
|
||||||
|
'tags': [t.pk for t in tags],
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.csv_data = (
|
||||||
|
"name,slug",
|
||||||
|
"Virtual Circuit Type 4,circuit-type-4",
|
||||||
|
"Virtual Circuit Type 5,circuit-type-5",
|
||||||
|
"Virtual Circuit Type 6,circuit-type-6",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{virtual_circuit_types[0].pk},Virtual Circuit Type 7,New description7",
|
||||||
|
f"{virtual_circuit_types[1].pk},Virtual Circuit Type 8,New description8",
|
||||||
|
f"{virtual_circuit_types[2].pk},Virtual Circuit Type 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
|
cls.bulk_edit_data = {
|
||||||
|
'description': 'Foo',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||||
model = VirtualCircuit
|
model = VirtualCircuit
|
||||||
|
|
||||||
@ -566,22 +607,30 @@ class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
ProviderAccount(provider=provider, account='Provider Account 2'),
|
ProviderAccount(provider=provider, account='Provider Account 2'),
|
||||||
)
|
)
|
||||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||||
|
virtual_circuit_types = (
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 1', slug='virtual-circuit-type-1'),
|
||||||
|
VirtualCircuitType(name='Virtual Circuit Type 2', slug='virtual-circuit-type-2'),
|
||||||
|
)
|
||||||
|
VirtualCircuitType.objects.bulk_create(virtual_circuit_types)
|
||||||
|
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
provider_account=provider_accounts[0],
|
provider_account=provider_accounts[0],
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_types[0]
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
provider_account=provider_accounts[0],
|
provider_account=provider_accounts[0],
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_types[0]
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_networks[0],
|
provider_network=provider_networks[0],
|
||||||
provider_account=provider_accounts[0],
|
provider_account=provider_accounts[0],
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_types[0]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
||||||
@ -600,6 +649,7 @@ class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'cid': 'Virtual Circuit X',
|
'cid': 'Virtual Circuit X',
|
||||||
'provider_network': provider_networks[1].pk,
|
'provider_network': provider_networks[1].pk,
|
||||||
'provider_account': provider_accounts[1].pk,
|
'provider_account': provider_accounts[1].pk,
|
||||||
|
'type': virtual_circuit_types[1].pk,
|
||||||
'status': CircuitStatusChoices.STATUS_PLANNED,
|
'status': CircuitStatusChoices.STATUS_PLANNED,
|
||||||
'description': 'A new virtual circuit',
|
'description': 'A new virtual circuit',
|
||||||
'comments': 'Some comments',
|
'comments': 'Some comments',
|
||||||
@ -607,22 +657,41 @@ class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
cls.csv_data = (
|
cls.csv_data = (
|
||||||
"cid,provider_network,provider_account,status",
|
"cid,provider_network,provider_account,type,status",
|
||||||
f"Virtual Circuit 4,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
|
(
|
||||||
f"Virtual Circuit 5,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
|
f"Virtual Circuit 4,Provider Network 1,Provider Account 1,{virtual_circuit_types[0].name},"
|
||||||
f"Virtual Circuit 6,Provider Network 1,Provider Account 1,{CircuitStatusChoices.STATUS_PLANNED}",
|
f"{CircuitStatusChoices.STATUS_PLANNED}"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Virtual Circuit 5,Provider Network 1,Provider Account 1,{virtual_circuit_types[0].name},"
|
||||||
|
f"{CircuitStatusChoices.STATUS_PLANNED}"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"Virtual Circuit 6,Provider Network 1,Provider Account 1,{virtual_circuit_types[0].name},"
|
||||||
|
f"{CircuitStatusChoices.STATUS_PLANNED}"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.csv_update_data = (
|
cls.csv_update_data = (
|
||||||
"id,cid,description,status",
|
"id,cid,description,type,status",
|
||||||
f"{virtual_circuits[0].pk},Virtual Circuit A,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
(
|
||||||
f"{virtual_circuits[1].pk},Virtual Circuit B,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
f"{virtual_circuits[0].pk},Virtual Circuit A,New description,{virtual_circuit_types[1].name},"
|
||||||
f"{virtual_circuits[2].pk},Virtual Circuit C,New description,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
f"{CircuitStatusChoices.STATUS_DECOMMISSIONED}"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"{virtual_circuits[1].pk},Virtual Circuit B,New description,{virtual_circuit_types[1].name},"
|
||||||
|
f"{CircuitStatusChoices.STATUS_DECOMMISSIONED}"
|
||||||
|
),
|
||||||
|
(
|
||||||
|
f"{virtual_circuits[2].pk},Virtual Circuit C,New description,{virtual_circuit_types[1].name},"
|
||||||
|
f"{CircuitStatusChoices.STATUS_DECOMMISSIONED}"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'provider_network': provider_networks[1].pk,
|
'provider_network': provider_networks[1].pk,
|
||||||
'provider_account': provider_accounts[1].pk,
|
'provider_account': provider_accounts[1].pk,
|
||||||
|
'type': virtual_circuit_types[1].pk,
|
||||||
'status': CircuitStatusChoices.STATUS_DECOMMISSIONED,
|
'status': CircuitStatusChoices.STATUS_DECOMMISSIONED,
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
'comments': 'New comments',
|
'comments': 'New comments',
|
||||||
@ -636,6 +705,7 @@ class VirtualCircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
{{
|
{{
|
||||||
"cid": "Virtual Circuit 7",
|
"cid": "Virtual Circuit 7",
|
||||||
"provider_network": "Provider Network 1",
|
"provider_network": "Provider Network 1",
|
||||||
|
"type": "Virtual Circuit Type 1",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"terminations": [
|
"terminations": [
|
||||||
{{
|
{{
|
||||||
@ -774,27 +844,35 @@ class VirtualCircuitTerminationTestCase(ViewTestCases.PrimaryObjectViewTestCase)
|
|||||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||||
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
provider_network = ProviderNetwork.objects.create(provider=provider, name='Provider Network 1')
|
||||||
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
provider_account = ProviderAccount.objects.create(provider=provider, account='Provider Account 1')
|
||||||
|
virtual_circuit_type = VirtualCircuitType.objects.create(
|
||||||
|
name='Virtual Circuit Type 1',
|
||||||
|
slug='virtual-circuit-type-1'
|
||||||
|
)
|
||||||
|
|
||||||
virtual_circuits = (
|
virtual_circuits = (
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 1'
|
cid='Virtual Circuit 1',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 2'
|
cid='Virtual Circuit 2',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 3'
|
cid='Virtual Circuit 3',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
VirtualCircuit(
|
VirtualCircuit(
|
||||||
provider_network=provider_network,
|
provider_network=provider_network,
|
||||||
provider_account=provider_account,
|
provider_account=provider_account,
|
||||||
cid='Virtual Circuit 4'
|
cid='Virtual Circuit 4',
|
||||||
|
type=virtual_circuit_type
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
VirtualCircuit.objects.bulk_create(virtual_circuits)
|
||||||
|
@ -42,6 +42,9 @@ urlpatterns = [
|
|||||||
path('virtual-circuits/delete/', views.VirtualCircuitBulkDeleteView.as_view(), name='virtualcircuit_bulk_delete'),
|
path('virtual-circuits/delete/', views.VirtualCircuitBulkDeleteView.as_view(), name='virtualcircuit_bulk_delete'),
|
||||||
path('virtual-circuits/<int:pk>/', include(get_model_urls('circuits', 'virtualcircuit'))),
|
path('virtual-circuits/<int:pk>/', include(get_model_urls('circuits', 'virtualcircuit'))),
|
||||||
|
|
||||||
|
path('virtual-circuit-types/', include(get_model_urls('circuits', 'virtualcircuittype', detail=False))),
|
||||||
|
path('virtual-circuit-types/<int:pk>/', include(get_model_urls('circuits', 'virtualcircuittype'))),
|
||||||
|
|
||||||
# Virtual circuit terminations
|
# Virtual circuit terminations
|
||||||
path(
|
path(
|
||||||
'virtual-circuit-terminations/',
|
'virtual-circuit-terminations/',
|
||||||
|
@ -579,6 +579,67 @@ class CircuitGroupAssignmentBulkDeleteView(generic.BulkDeleteView):
|
|||||||
table = tables.CircuitGroupAssignmentTable
|
table = tables.CircuitGroupAssignmentTable
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Virtual circuit Types
|
||||||
|
#
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'list', path='', detail=False)
|
||||||
|
class VirtualCircuitTypeListView(generic.ObjectListView):
|
||||||
|
queryset = VirtualCircuitType.objects.annotate(
|
||||||
|
virtual_circuit_count=count_related(VirtualCircuit, 'type')
|
||||||
|
)
|
||||||
|
filterset = filtersets.VirtualCircuitTypeFilterSet
|
||||||
|
filterset_form = forms.VirtualCircuitTypeFilterForm
|
||||||
|
table = tables.VirtualCircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType)
|
||||||
|
class VirtualCircuitTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
|
||||||
|
def get_extra_context(self, request, instance):
|
||||||
|
return {
|
||||||
|
'related_models': self.get_related_models(request, instance),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'add', detail=False)
|
||||||
|
@register_model_view(VirtualCircuitType, 'edit')
|
||||||
|
class VirtualCircuitTypeEditView(generic.ObjectEditView):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
form = forms.VirtualCircuitTypeForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'delete')
|
||||||
|
class VirtualCircuitTypeDeleteView(generic.ObjectDeleteView):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'bulk_import', detail=False)
|
||||||
|
class VirtualCircuitTypeBulkImportView(generic.BulkImportView):
|
||||||
|
queryset = VirtualCircuitType.objects.all()
|
||||||
|
model_form = forms.VirtualCircuitTypeImportForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'bulk_edit', path='edit', detail=False)
|
||||||
|
class VirtualCircuitTypeBulkEditView(generic.BulkEditView):
|
||||||
|
queryset = VirtualCircuitType.objects.annotate(
|
||||||
|
circuit_count=count_related(Circuit, 'type')
|
||||||
|
)
|
||||||
|
filterset = filtersets.VirtualCircuitTypeFilterSet
|
||||||
|
table = tables.VirtualCircuitTypeTable
|
||||||
|
form = forms.VirtualCircuitTypeBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualCircuitType, 'bulk_delete', path='delete', detail=False)
|
||||||
|
class VirtualCircuitTypeBulkDeleteView(generic.BulkDeleteView):
|
||||||
|
queryset = VirtualCircuitType.objects.annotate(
|
||||||
|
circuit_count=count_related(Circuit, 'type')
|
||||||
|
)
|
||||||
|
filterset = filtersets.VirtualCircuitTypeFilterSet
|
||||||
|
table = tables.VirtualCircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Virtual circuits
|
# Virtual circuits
|
||||||
#
|
#
|
||||||
|
@ -1170,6 +1170,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
'virtualchassis',
|
'virtualchassis',
|
||||||
'virtualcircuit',
|
'virtualcircuit',
|
||||||
'virtualcircuittermination',
|
'virtualcircuittermination',
|
||||||
|
'virtualcircuittype',
|
||||||
'virtualdevicecontext',
|
'virtualdevicecontext',
|
||||||
'virtualdisk',
|
'virtualdisk',
|
||||||
'virtualmachine',
|
'virtualmachine',
|
||||||
|
@ -286,6 +286,7 @@ CIRCUITS_MENU = Menu(
|
|||||||
label=_('Virtual Circuits'),
|
label=_('Virtual Circuits'),
|
||||||
items=(
|
items=(
|
||||||
get_model_item('circuits', 'virtualcircuit', _('Virtual Circuits')),
|
get_model_item('circuits', 'virtualcircuit', _('Virtual Circuits')),
|
||||||
|
get_model_item('circuits', 'virtualcircuittype', _('Virtual Circuit Types')),
|
||||||
get_model_item('circuits', 'virtualcircuittermination', _('Virtual Circuit Terminations')),
|
get_model_item('circuits', 'virtualcircuittermination', _('Virtual Circuit Terminations')),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
<th scope="row">{% trans "Circuit ID" %}</th>
|
<th scope="row">{% trans "Circuit ID" %}</th>
|
||||||
<td>{{ object.cid }}</td>
|
<td>{{ object.cid }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Type" %}</th>
|
||||||
|
<td>{{ object.type|linkify }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Status" %}</th>
|
<th scope="row">{% trans "Status" %}</th>
|
||||||
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
||||||
|
55
netbox/templates/circuits/virtualcircuittype.html
Normal file
55
netbox/templates/circuits/virtualcircuittype.html
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'generic/object.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
{% load plugins %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block extra_controls %}
|
||||||
|
{% if perms.circuits.add_virtualcircuit %}
|
||||||
|
<a href="{% url 'circuits:virtualcircuit_add' %}?type={{ object.pk }}" class="btn btn-primary">
|
||||||
|
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add Virtual Circuit" %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock extra_controls %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<h2 class="card-header">{% trans "Virtual Circuit Type" %}</h2>
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Name" %}</th>
|
||||||
|
<td>{{ object.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Description" %}</th>
|
||||||
|
<td>{{ object.description|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Color" %}</th>
|
||||||
|
<td>
|
||||||
|
{% if object.color %}
|
||||||
|
<span class="badge color-label" style="background-color: #{{ object.color }}"> </span>
|
||||||
|
{% else %}
|
||||||
|
{{ ''|placeholder }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% include 'inc/panels/tags.html' %}
|
||||||
|
{% plugin_left_page object %}
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-6">
|
||||||
|
{% include 'inc/panels/related_objects.html' %}
|
||||||
|
{% include 'inc/panels/custom_fields.html' %}
|
||||||
|
{% plugin_right_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col col-md-12">
|
||||||
|
{% plugin_full_width_page object %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user