9604 scope->termination

This commit is contained in:
Arthur Hanson 2024-10-30 09:10:57 -07:00
parent 5b7fda6075
commit d6adebbe6b
19 changed files with 176 additions and 176 deletions

View File

@ -21,7 +21,7 @@ Designates the termination as forming either the A or Z end of the circuit.
If selected, the circuit termination will be considered "connected" even if no cable has been connected to it in NetBox.
### Scope
### Termination
The [region](../dcim/region.md), [site group](../dcim/sitegroup.md), [site](../dcim/site.md) or [location](../dcim/location.md) with which this circuit termination is associated. Once created, a cable can be connected between the circuit termination and a device interface (or similar component).

View File

@ -3,7 +3,7 @@ from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers
from circuits.choices import CircuitPriorityChoices, CircuitStatusChoices
from circuits.constants import CIRCUIT_TERMINATION_SCOPE_TYPES
from circuits.constants import CIRCUIT_TERMINATION_TERMINATION_TYPES
from circuits.models import Circuit, CircuitGroup, CircuitGroupAssignment, CircuitTermination, CircuitType
from dcim.api.serializers_.cables import CabledObjectSerializer
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
@ -38,32 +38,32 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
scope_type = ContentTypeField(
termination_type = ContentTypeField(
queryset=ContentType.objects.filter(
model__in=CIRCUIT_TERMINATION_SCOPE_TYPES
model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES
),
allow_null=True,
required=False,
default=None
)
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
scope = serializers.SerializerMethodField(read_only=True)
termination_id = serializers.IntegerField(allow_null=True, required=False, default=None)
termination = serializers.SerializerMethodField(read_only=True)
provider_network = ProviderNetworkSerializer(nested=True, allow_null=True)
class Meta:
model = CircuitTermination
fields = [
'id', 'url', 'display_url', 'display', 'scope_type', 'scope_id', 'scope', 'provider_network', 'port_speed', 'upstream_speed',
'id', 'url', 'display_url', 'display', 'termination_type', 'termination_id', 'termination', 'provider_network', 'port_speed', 'upstream_speed',
'xconnect_id', 'description',
]
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_scope(self, obj):
if obj.scope_id is None:
def get_termination(self, obj):
if obj.termination_id is None:
return None
serializer = get_serializer_for_model(obj.scope)
serializer = get_serializer_for_model(obj.termination)
context = {'request': self.context['request']}
return serializer(obj.scope, nested=True, context=context).data
return serializer(obj.termination, nested=True, context=context).data
class CircuitGroupSerializer(NetBoxModelSerializer):
@ -117,34 +117,34 @@ class CircuitSerializer(NetBoxModelSerializer):
class CircuitTerminationSerializer(NetBoxModelSerializer, CabledObjectSerializer):
circuit = CircuitSerializer(nested=True)
scope_type = ContentTypeField(
termination_type = ContentTypeField(
queryset=ContentType.objects.filter(
model__in=CIRCUIT_TERMINATION_SCOPE_TYPES
model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES
),
allow_null=True,
required=False,
default=None
)
scope_id = serializers.IntegerField(allow_null=True, required=False, default=None)
scope = serializers.SerializerMethodField(read_only=True)
termination_id = serializers.IntegerField(allow_null=True, required=False, default=None)
termination = serializers.SerializerMethodField(read_only=True)
provider_network = ProviderNetworkSerializer(nested=True, required=False, allow_null=True)
class Meta:
model = CircuitTermination
fields = [
'id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'scope_type', 'scope_id', 'scope', 'provider_network', 'port_speed',
'id', 'url', 'display_url', 'display', 'circuit', 'term_side', 'termination_type', 'termination_id', 'termination', 'provider_network', 'port_speed',
'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'cable_end',
'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
]
brief_fields = ('id', 'url', 'display', 'circuit', 'term_side', 'description', 'cable', '_occupied')
@extend_schema_field(serializers.JSONField(allow_null=True))
def get_scope(self, obj):
if obj.scope_id is None:
def get_termination(self, obj):
if obj.termination_id is None:
return None
serializer = get_serializer_for_model(obj.scope)
serializer = get_serializer_for_model(obj.termination)
context = {'request': self.context['request']}
return serializer(obj.scope, nested=True, context=context).data
return serializer(obj.termination, nested=True, context=context).data
class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_):

View File

@ -1,4 +1,4 @@
# models values for ContentTypes which may be CircuitTermination scope types
CIRCUIT_TERMINATION_SCOPE_TYPES = (
# models values for ContentTypes which may be CircuitTermination termination types
CIRCUIT_TERMINATION_TERMINATION_TYPES = (
'region', 'sitegroup', 'site', 'location', 'providernetwork',
)

View File

@ -263,7 +263,7 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
queryset=Circuit.objects.all(),
label=_('Circuit'),
)
scope_type = ContentTypeFilter()
termination_type = ContentTypeFilter()
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='_region',
@ -334,7 +334,7 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
class Meta:
model = CircuitTermination
fields = (
'id', 'scope_id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', 'mark_connected',
'id', 'termination_id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', 'mark_connected',
'pp_info', 'cable_end',
)

View File

@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _
from circuits.choices import CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices
from circuits.constants import CIRCUIT_TERMINATION_SCOPE_TYPES
from circuits.constants import CIRCUIT_TERMINATION_TERMINATION_TYPES
from circuits.models import *
from dcim.models import Site
from ipam.models import ASN
@ -199,14 +199,14 @@ class CircuitTerminationBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
scope_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_SCOPE_TYPES),
termination_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES),
widget=HTMXSelect(method='post', attrs={'hx-select': '#form_fields'}),
required=False,
label=_('Scope type')
label=_('Termination type')
)
scope = DynamicModelChoiceField(
label=_('Scope'),
termination = DynamicModelChoiceField(
label=_('Termination'),
queryset=Site.objects.none(), # Initial queryset
required=False,
disabled=True,
@ -230,24 +230,24 @@ class CircuitTerminationBulkEditForm(NetBoxModelBulkEditForm):
fieldsets = (
FieldSet(
'description',
'scope_type', 'scope',
'termination_type', 'termination',
'mark_connected', name=_('Circuit Termination')
),
FieldSet('port_speed', 'upstream_speed', name=_('Termination Details')),
)
nullable_fields = ('description', 'scope')
nullable_fields = ('description', 'termination')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if scope_type_id := get_field_value(self, 'scope_type'):
if termination_type_id := get_field_value(self, 'termination_type'):
try:
scope_type = ContentType.objects.get(pk=scope_type_id)
model = scope_type.model_class()
self.fields['scope'].queryset = model.objects.all()
self.fields['scope'].widget.attrs['selector'] = model._meta.label_lower
self.fields['scope'].disabled = False
self.fields['scope'].label = _(bettertitle(model._meta.verbose_name))
termination_type = ContentType.objects.get(pk=termination_type_id)
model = termination_type.model_class()
self.fields['termination'].queryset = model.objects.all()
self.fields['termination'].widget.attrs['selector'] = model._meta.label_lower
self.fields['termination'].disabled = False
self.fields['termination'].label = _(bettertitle(model._meta.verbose_name))
except ObjectDoesNotExist:
pass

View File

@ -128,10 +128,10 @@ class BaseCircuitTerminationImportForm(forms.ModelForm):
label=_('Termination'),
choices=CircuitTerminationSideChoices,
)
scope_type = CSVContentTypeField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_SCOPE_TYPES),
termination_type = CSVContentTypeField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES),
required=False,
label=_('Scope type (app & model)')
label=_('Termination type (app & model)')
)
@ -139,11 +139,11 @@ class CircuitTerminationImportRelatedForm(BaseCircuitTerminationImportForm):
class Meta:
model = CircuitTermination
fields = [
'circuit', 'term_side', 'scope_type', 'scope_id', 'port_speed', 'upstream_speed', 'xconnect_id',
'circuit', 'term_side', 'termination_type', 'termination_id', 'port_speed', 'upstream_speed', 'xconnect_id',
'pp_info', 'description'
]
labels = {
'scope_id': 'Scope ID',
'termination_id': 'Termination ID',
}
@ -152,11 +152,11 @@ class CircuitTerminationImportForm(NetBoxModelImportForm, BaseCircuitTermination
class Meta:
model = CircuitTermination
fields = [
'circuit', 'term_side', 'scope_type', 'scope_id', 'port_speed', 'upstream_speed', 'xconnect_id',
'circuit', 'term_side', 'termination_type', 'termination_id', 'port_speed', 'upstream_speed', 'xconnect_id',
'pp_info', 'description', 'tags'
]
labels = {
'scope_id': 'Scope ID',
'termination_id': 'Termination ID',
}

View File

@ -208,7 +208,7 @@ class CircuitTerminationFilterForm(NetBoxModelFilterSetForm):
FieldSet('q', 'filter_id', 'tag'),
FieldSet('circuit_id', 'term_side', name=_('Circuit')),
FieldSet('provider_id', name=_('Provider')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Termination')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),

View File

@ -149,14 +149,14 @@ class CircuitTerminationForm(NetBoxModelForm):
queryset=Circuit.objects.all(),
selector=True
)
scope_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_SCOPE_TYPES),
termination_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES),
widget=HTMXSelect(),
required=False,
label=_('Scope type')
label=_('Termination type')
)
scope = DynamicModelChoiceField(
label=_('Scope'),
termination = DynamicModelChoiceField(
label=_('Termination'),
queryset=Site.objects.none(), # Initial queryset
required=False,
disabled=True,
@ -166,7 +166,7 @@ class CircuitTerminationForm(NetBoxModelForm):
fieldsets = (
FieldSet(
'circuit', 'term_side', 'description', 'tags',
'scope_type', 'scope',
'termination_type', 'termination',
'mark_connected', name=_('Circuit Termination')
),
FieldSet('port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', name=_('Termination Details')),
@ -175,7 +175,7 @@ class CircuitTerminationForm(NetBoxModelForm):
class Meta:
model = CircuitTermination
fields = [
'circuit', 'term_side', 'scope_type', 'mark_connected', 'port_speed', 'upstream_speed',
'circuit', 'term_side', 'termination_type', 'mark_connected', 'port_speed', 'upstream_speed',
'xconnect_id', 'pp_info', 'description', 'tags',
]
widgets = {
@ -191,31 +191,31 @@ class CircuitTerminationForm(NetBoxModelForm):
instance = kwargs.get('instance')
initial = kwargs.get('initial', {})
if instance is not None and instance.scope:
initial['scope'] = instance.scope
if instance is not None and instance.termination:
initial['termination'] = instance.termination
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
if scope_type_id := get_field_value(self, 'scope_type'):
if termination_type_id := get_field_value(self, 'termination_type'):
try:
scope_type = ContentType.objects.get(pk=scope_type_id)
model = scope_type.model_class()
self.fields['scope'].queryset = model.objects.all()
self.fields['scope'].widget.attrs['selector'] = model._meta.label_lower
self.fields['scope'].disabled = False
self.fields['scope'].label = _(bettertitle(model._meta.verbose_name))
termination_type = ContentType.objects.get(pk=termination_type_id)
model = termination_type.model_class()
self.fields['termination'].queryset = model.objects.all()
self.fields['termination'].widget.attrs['selector'] = model._meta.label_lower
self.fields['termination'].disabled = False
self.fields['termination'].label = _(bettertitle(model._meta.verbose_name))
except ObjectDoesNotExist:
pass
if self.instance and scope_type_id != self.instance.scope_type_id:
self.initial['scope'] = None
if self.instance and termination_type_id != self.instance.termination_type_id:
self.initial['termination'] = None
def clean(self):
super().clean()
# Assign the selected scope (if any)
self.instance.scope = self.cleaned_data.get('scope')
# Assign the selected termination (if any)
self.instance.termination = self.cleaned_data.get('termination')
class CircuitGroupForm(TenancyForm, NetBoxModelForm):

View File

@ -59,21 +59,21 @@ class ProviderNetworkType(NetBoxObjectType):
@strawberry_django.type(
models.CircuitTermination,
exclude=('scope_type', 'scope_id', '_location', '_region', '_site', '_sitegroup', '_provider_network'),
exclude=('termination_type', 'termination_id', '_location', '_region', '_site', '_sitegroup', '_provider_network'),
filters=CircuitTerminationFilter
)
class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, ObjectType):
circuit: Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]
@strawberry_django.field
def scope(self) -> Annotated[Union[
def termination(self) -> Annotated[Union[
Annotated["LocationType", strawberry.lazy('dcim.graphql.types')],
Annotated["RegionType", strawberry.lazy('dcim.graphql.types')],
Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')],
Annotated["SiteType", strawberry.lazy('dcim.graphql.types')],
Annotated["ProviderNetworkType", strawberry.lazy('circuits.graphql.types')],
], strawberry.union("CircuitTerminationScopeType")] | None:
return self.scope
], strawberry.union("CircuitTerminationTerminationType")] | None:
return self.termination
@strawberry_django.type(

View File

@ -4,21 +4,21 @@ from django.db import migrations, models
def copy_site_assignments(apps, schema_editor):
"""
Copy site ForeignKey values to the scope GFK.
Copy site ForeignKey values to the Termination GFK.
"""
ContentType = apps.get_model('contenttypes', 'ContentType')
CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
Site = apps.get_model('dcim', 'Site')
CircuitTermination.objects.filter(site__isnull=False).update(
scope_type=ContentType.objects.get_for_model(Site),
scope_id=models.F('site_id')
termination_type=ContentType.objects.get_for_model(Site),
termination_id=models.F('site_id')
)
ProviderNetwork = apps.get_model('circuits', 'ProviderNetwork')
CircuitTermination.objects.filter(provider_network__isnull=False).update(
scope_type=ContentType.objects.get_for_model(ProviderNetwork),
scope_id=models.F('provider_network_id')
termination_type=ContentType.objects.get_for_model(ProviderNetwork),
termination_id=models.F('provider_network_id')
)
class Migration(migrations.Migration):
@ -32,12 +32,12 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
model_name='circuittermination',
name='scope_id',
name='termination_id',
field=models.PositiveBigIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='circuittermination',
name='scope_type',
name='termination_type',
field=models.ForeignKey(
blank=True,
limit_choices_to=models.Q(('model__in', ('region', 'sitegroup', 'site', 'location', 'providernetwork'))),

View File

@ -5,7 +5,7 @@ from django.db import migrations, models
def populate_denormalized_fields(apps, schema_editor):
"""
Copy site ForeignKey values to the scope GFK.
Copy site ForeignKey values to the Termination GFK.
"""
CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
@ -22,7 +22,7 @@ def populate_denormalized_fields(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('circuits', '0047_circuittermination__scope'),
('circuits', '0047_circuittermination__termination'),
]
operations = [
@ -33,7 +33,7 @@ class Migration(migrations.Migration):
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
to='dcim.location',
),
),
@ -44,7 +44,7 @@ class Migration(migrations.Migration):
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
to='dcim.region',
),
),
@ -55,7 +55,7 @@ class Migration(migrations.Migration):
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
to='dcim.site',
),
),
@ -66,7 +66,7 @@ class Migration(migrations.Migration):
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
to='dcim.sitegroup',
),
),

View File

@ -236,21 +236,21 @@ class CircuitTermination(
choices=CircuitTerminationSideChoices,
verbose_name=_('termination')
)
scope_type = models.ForeignKey(
termination_type = models.ForeignKey(
to='contenttypes.ContentType',
on_delete=models.PROTECT,
limit_choices_to=Q(model__in=CIRCUIT_TERMINATION_SCOPE_TYPES),
limit_choices_to=Q(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES),
related_name='+',
blank=True,
null=True
)
scope_id = models.PositiveBigIntegerField(
termination_id = models.PositiveBigIntegerField(
blank=True,
null=True
)
scope = GenericForeignKey(
ct_field='scope_type',
fk_field='scope_id'
termination = GenericForeignKey(
ct_field='termination_type',
fk_field='termination_id'
)
port_speed = models.PositiveIntegerField(
verbose_name=_('port speed (Kbps)'),
@ -293,28 +293,28 @@ class CircuitTermination(
_location = models.ForeignKey(
to='dcim.Location',
on_delete=models.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
blank=True,
null=True
)
_site = models.ForeignKey(
to='dcim.Site',
on_delete=models.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
blank=True,
null=True
)
_region = models.ForeignKey(
to='dcim.Region',
on_delete=models.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
blank=True,
null=True
)
_sitegroup = models.ForeignKey(
to='dcim.SiteGroup',
on_delete=models.CASCADE,
related_name='_circuit_terminations',
related_name='circuit_terminations',
blank=True,
null=True
)
@ -340,8 +340,8 @@ class CircuitTermination(
super().clean()
# Must define either site *or* provider network
if self.scope is None:
raise ValidationError(_("A circuit termination must attach to either a scope or a provider network."))
if self.termination is None:
raise ValidationError(_("A circuit termination must attach to termination."))
def save(self, *args, **kwargs):
# Cache objects associated with the terminating object (for filtering)
@ -351,23 +351,23 @@ class CircuitTermination(
def cache_related_objects(self):
self._provider_network = self._region = self._sitegroup = self._site = self._location = None
if self.scope_type:
scope_type = self.scope_type.model_class()
if scope_type == apps.get_model('dcim', 'region'):
self._region = self.scope
elif scope_type == apps.get_model('dcim', 'sitegroup'):
self._sitegroup = self.scope
elif scope_type == apps.get_model('dcim', 'site'):
self._region = self.scope.region
self._sitegroup = self.scope.group
self._site = self.scope
elif scope_type == apps.get_model('dcim', 'location'):
self._region = self.scope.site.region
self._sitegroup = self.scope.site.group
self._site = self.scope.site
self._location = self.scope
elif scope_type == apps.get_model('circuits', 'providernetwork'):
self._provider_network = self.scope
if self.termination_type:
termination_type = self.termination_type.model_class()
if termination_type == apps.get_model('dcim', 'region'):
self._region = self.termination
elif termination_type == apps.get_model('dcim', 'sitegroup'):
self._sitegroup = self.termination
elif termination_type == apps.get_model('dcim', 'site'):
self._region = self.termination.region
self._sitegroup = self.termination.group
self._site = self.termination
elif termination_type == apps.get_model('dcim', 'location'):
self._region = self.termination.site.region
self._sitegroup = self.termination.site.group
self._site = self.termination.site
self._location = self.termination
elif termination_type == apps.get_model('circuits', 'providernetwork'):
self._provider_network = self.termination
cache_related_objects.alters_data = True
def to_objectchange(self, action):
@ -382,7 +382,7 @@ class CircuitTermination(
def get_peer_termination(self):
peer_side = 'Z' if self.term_side == 'A' else 'A'
try:
return CircuitTermination.objects.prefetch_related('scope').get(
return CircuitTermination.objects.prefetch_related('termination').get(
circuit=self.circuit,
term_side=peer_side
)

View File

@ -181,10 +181,10 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
Circuit.objects.bulk_create(circuits)
circuit_terminations = (
CircuitTermination(circuit=circuits[0], term_side=SIDE_A, scope=sites[0]),
CircuitTermination(circuit=circuits[0], term_side=SIDE_Z, scope=provider_networks[0]),
CircuitTermination(circuit=circuits[1], term_side=SIDE_A, scope=sites[1]),
CircuitTermination(circuit=circuits[1], term_side=SIDE_Z, scope=provider_networks[1]),
CircuitTermination(circuit=circuits[0], term_side=SIDE_A, termination=sites[0]),
CircuitTermination(circuit=circuits[0], term_side=SIDE_Z, termination=provider_networks[0]),
CircuitTermination(circuit=circuits[1], term_side=SIDE_A, termination=sites[1]),
CircuitTermination(circuit=circuits[1], term_side=SIDE_Z, termination=provider_networks[1]),
)
CircuitTermination.objects.bulk_create(circuit_terminations)
@ -192,15 +192,15 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
{
'circuit': circuits[2].pk,
'term_side': SIDE_A,
'scope_type': 'dcim.site',
'scope_id': sites[0].pk,
'termination_type': 'dcim.site',
'termination_id': sites[0].pk,
'port_speed': 200000,
},
{
'circuit': circuits[2].pk,
'term_side': SIDE_Z,
'scope_type': 'circuits.providernetwork',
'scope_id': provider_networks[0].pk,
'termination_type': 'circuits.providernetwork',
'termination_id': provider_networks[0].pk,
'port_speed': 200000,
},
]

View File

@ -71,8 +71,8 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
Circuit.objects.bulk_create(circuits)
circuit_terminations = (
CircuitTermination(circuit=circuits[0], scope=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[1], scope=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[0], termination=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[1], termination=sites[0], term_side='A'),
)
for ct in circuit_terminations:
ct.save()
@ -235,12 +235,12 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
Circuit.objects.bulk_create(circuits)
circuit_terminations = ((
CircuitTermination(circuit=circuits[0], scope=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[1], scope=sites[1], term_side='A'),
CircuitTermination(circuit=circuits[2], scope=sites[2], term_side='A'),
CircuitTermination(circuit=circuits[3], scope=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], scope=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], scope=provider_networks[2], term_side='A'),
CircuitTermination(circuit=circuits[0], termination=sites[0], term_side='A'),
CircuitTermination(circuit=circuits[1], termination=sites[1], term_side='A'),
CircuitTermination(circuit=circuits[2], termination=sites[2], term_side='A'),
CircuitTermination(circuit=circuits[3], termination=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], termination=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], termination=provider_networks[2], term_side='A'),
))
for ct in circuit_terminations:
ct.save()
@ -387,16 +387,16 @@ class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
Circuit.objects.bulk_create(circuits)
circuit_terminations = ((
CircuitTermination(circuit=circuits[0], scope=sites[0], term_side='A', port_speed=1000, upstream_speed=1000, xconnect_id='ABC', description='foobar1'),
CircuitTermination(circuit=circuits[0], scope=sites[1], term_side='Z', port_speed=1000, upstream_speed=1000, xconnect_id='DEF', description='foobar2'),
CircuitTermination(circuit=circuits[1], scope=sites[1], term_side='A', port_speed=2000, upstream_speed=2000, xconnect_id='GHI'),
CircuitTermination(circuit=circuits[1], scope=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'),
CircuitTermination(circuit=circuits[2], scope=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'),
CircuitTermination(circuit=circuits[2], scope=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'),
CircuitTermination(circuit=circuits[3], scope=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], scope=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], scope=provider_networks[2], term_side='A'),
CircuitTermination(circuit=circuits[6], scope=provider_networks[0], term_side='A', mark_connected=True),
CircuitTermination(circuit=circuits[0], termination=sites[0], term_side='A', port_speed=1000, upstream_speed=1000, xconnect_id='ABC', description='foobar1'),
CircuitTermination(circuit=circuits[0], termination=sites[1], term_side='Z', port_speed=1000, upstream_speed=1000, xconnect_id='DEF', description='foobar2'),
CircuitTermination(circuit=circuits[1], termination=sites[1], term_side='A', port_speed=2000, upstream_speed=2000, xconnect_id='GHI'),
CircuitTermination(circuit=circuits[1], termination=sites[2], term_side='Z', port_speed=2000, upstream_speed=2000, xconnect_id='JKL'),
CircuitTermination(circuit=circuits[2], termination=sites[2], term_side='A', port_speed=3000, upstream_speed=3000, xconnect_id='MNO'),
CircuitTermination(circuit=circuits[2], termination=sites[0], term_side='Z', port_speed=3000, upstream_speed=3000, xconnect_id='PQR'),
CircuitTermination(circuit=circuits[3], termination=provider_networks[0], term_side='A'),
CircuitTermination(circuit=circuits[4], termination=provider_networks[1], term_side='A'),
CircuitTermination(circuit=circuits[5], termination=provider_networks[2], term_side='A'),
CircuitTermination(circuit=circuits[6], termination=provider_networks[0], term_side='A', mark_connected=True),
))
for ct in circuit_terminations:
ct.save()

View File

@ -203,23 +203,23 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
"terminations": [
{
"term_side": "A",
"scope_type": "dcim.site",
"scope_id": "1"
"termination_type": "dcim.site",
"termination_id": "1"
},
{
"term_side": "Z",
"scope_type": "dcim.site",
"scope_id": "1"
"termination_type": "dcim.site",
"termination_id": "1"
}
]
}
]
"""
# Fix up the scope site id
# Fix up the termination site id
site = Site.objects.first()
data = json.loads(json_data)
data[0]["terminations"][0]["scope_id"] = data[0]["terminations"][1]["scope_id"] = site.id
data[0]["terminations"][0]["termination_id"] = data[0]["terminations"][1]["termination_id"] = site.id
json_data = json.dumps(data)
initial_count = self._get_queryset().count()
@ -370,10 +370,10 @@ class TestCase(ViewTestCases.PrimaryObjectViewTestCase):
Circuit.objects.bulk_create(circuits)
circuit_terminations = (
CircuitTermination(circuit=circuits[0], term_side='A', scope=sites[0]),
CircuitTermination(circuit=circuits[0], term_side='Z', scope=sites[1]),
CircuitTermination(circuit=circuits[1], term_side='A', scope=sites[0]),
CircuitTermination(circuit=circuits[1], term_side='Z', scope=sites[1]),
CircuitTermination(circuit=circuits[0], term_side='A', termination=sites[0]),
CircuitTermination(circuit=circuits[0], term_side='Z', termination=sites[1]),
CircuitTermination(circuit=circuits[1], term_side='A', termination=sites[0]),
CircuitTermination(circuit=circuits[1], term_side='Z', termination=sites[1]),
)
for ct in circuit_terminations:
ct.save()
@ -381,14 +381,14 @@ class TestCase(ViewTestCases.PrimaryObjectViewTestCase):
cls.form_data = {
'circuit': circuits[2].pk,
'term_side': 'A',
'scope_type': ContentType.objects.get_for_model(Site).pk,
'scope': sites[2].pk,
'termination_type': ContentType.objects.get_for_model(Site).pk,
'termination': sites[2].pk,
'description': 'New description',
}
site = sites[0].pk
cls.csv_data = (
"circuit,term_side,scope_type,scope_id,description",
"circuit,term_side,termination_type,termination_id,description",
f"Circuit 3,A,dcim.site,{site},Foo",
f"Circuit 3,Z,dcim.site,{site},Bar",
)

View File

@ -1167,7 +1167,7 @@ class CablePathTestCase(TestCase):
[IF1] --C1-- [CT1]
"""
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
# Create cable 1
cable1 = Cable(
@ -1198,7 +1198,7 @@ class CablePathTestCase(TestCase):
"""
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
interface2 = Interface.objects.create(device=self.device, name='Interface 2')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
# Create cable 1
cable1 = Cable(
@ -1214,7 +1214,7 @@ class CablePathTestCase(TestCase):
)
# Create CT2
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='Z')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z')
# Check for partial path to site
self.assertPathExists(
@ -1266,7 +1266,7 @@ class CablePathTestCase(TestCase):
interface2 = Interface.objects.create(device=self.device, name='Interface 2')
interface3 = Interface.objects.create(device=self.device, name='Interface 3')
interface4 = Interface.objects.create(device=self.device, name='Interface 4')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
# Create cable 1
cable1 = Cable(
@ -1282,7 +1282,7 @@ class CablePathTestCase(TestCase):
)
# Create CT2
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='Z')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z')
# Check for partial path to site
self.assertPathExists(
@ -1335,8 +1335,8 @@ class CablePathTestCase(TestCase):
"""
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
site2 = Site.objects.create(name='Site 2', slug='site-2')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=site2, term_side='Z')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=site2, term_side='Z')
# Create cable 1
cable1 = Cable(
@ -1365,8 +1365,8 @@ class CablePathTestCase(TestCase):
"""
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
providernetwork = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.circuit.provider)
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=providernetwork, term_side='Z')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=providernetwork, term_side='Z')
# Create cable 1
cable1 = Cable(
@ -1413,8 +1413,8 @@ class CablePathTestCase(TestCase):
frontport2_2 = FrontPort.objects.create(
device=self.device, name='Front Port 2:2', rear_port=rearport2, rear_port_position=2
)
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='Z')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z')
# Create cables
cable1 = Cable(
@ -1499,10 +1499,10 @@ class CablePathTestCase(TestCase):
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
interface2 = Interface.objects.create(device=self.device, name='Interface 2')
circuit2 = Circuit.objects.create(provider=self.circuit.provider, type=self.circuit.type, cid='Circuit 2')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, scope=self.site, term_side='Z')
circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, scope=self.site, term_side='A')
circuittermination4 = CircuitTermination.objects.create(circuit=circuit2, scope=self.site, term_side='Z')
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='A')
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, termination=self.site, term_side='Z')
circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, termination=self.site, term_side='A')
circuittermination4 = CircuitTermination.objects.create(circuit=circuit2, termination=self.site, term_side='Z')
# Create cables
cable1 = Cable(

View File

@ -5117,7 +5117,7 @@ class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
circuit_type = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
circuit = Circuit.objects.create(cid='Circuit 1', provider=provider, type=circuit_type)
circuit_termination = CircuitTermination.objects.create(circuit=circuit, term_side='A', scope=sites[0])
circuit_termination = CircuitTermination.objects.create(circuit=circuit, term_side='A', termination=sites[0])
# Cables
cables = (

View File

@ -762,9 +762,9 @@ class CableTestCase(TestCase):
circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
circuit1 = Circuit.objects.create(provider=provider, type=circuittype, cid='1')
circuit2 = Circuit.objects.create(provider=provider, type=circuittype, cid='2')
CircuitTermination.objects.create(circuit=circuit1, scope=site, term_side='A')
CircuitTermination.objects.create(circuit=circuit1, scope=site, term_side='Z')
CircuitTermination.objects.create(circuit=circuit2, scope=provider_network, term_side='A')
CircuitTermination.objects.create(circuit=circuit1, termination=site, term_side='A')
CircuitTermination.objects.create(circuit=circuit1, termination=site, term_side='Z')
CircuitTermination.objects.create(circuit=circuit2, termination=provider_network, term_side='A')
def test_cable_creation(self):
"""

View File

@ -1,11 +1,11 @@
{% load helpers %}
{% load i18n %}
{% if termination.scope %}
{% if termination.termination %}
<tr>
<th scope="row">{% trans "Scope" %}</th>
{% if termination.scope %}
<td>{{ termination.scope|linkify }} ({% trans termination.scope_type.name %})</td>
<th scope="row">{% trans "Termination" %}</th>
{% if termination.termination %}
<td>{{ termination.termination|linkify }} ({% trans termination.termination_type.name %})</td>
{% else %}
<td>{{ ''|placeholder }}</td>
{% endif %}