mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 17:26:10 -06:00
Misc cleanup
This commit is contained in:
parent
8f3590fdd5
commit
bee08050b6
@ -5,8 +5,8 @@ NetBox is ideal for managing your network's transit and peering providers and ci
|
||||
```mermaid
|
||||
flowchart TD
|
||||
ASN --> Provider
|
||||
Provider --> ProviderAccount --> Circuit
|
||||
Provider --> ProviderNetwork & Circuit
|
||||
Provider --> ProviderNetwork & ProviderAccount & Circuit
|
||||
ProviderAccount --> Circuit
|
||||
CircuitType --> Circuit
|
||||
|
||||
click ASN "../../models/circuits/asn/"
|
||||
@ -27,7 +27,7 @@ Sometimes you'll need to model provider networks into which you don't have full
|
||||
|
||||
A circuit is a physical connection between two points, which is installed and maintained by an external provider. For example, an Internet connection delivered as a fiber optic cable would be modeled as a circuit in NetBox.
|
||||
|
||||
Each circuit is associated with a provider account and assigned a circuit ID, which must be unique to that provider. A circuit is also assigned a user-defined type, operational status, and various other operating characteristics.
|
||||
Each circuit is associated with a provider and assigned a circuit ID, which must be unique to that provider. A circuit is also assigned a user-defined type, operational status, and various other operating characteristics. Provider accounts can also be employed to further categorize circuits belonging to a common provider: These may represent different business units or technologies.
|
||||
|
||||
Each circuit may have up to two terminations (A and Z) defined. Each termination can be associated with a particular site or provider network. In the case of the former, a cable can be connected between the circuit termination and a device component to map its physical connectivity.
|
||||
|
||||
|
@ -56,7 +56,7 @@ Below is the (rough) recommended order in which NetBox objects should be created
|
||||
4. Manufacturers, device types, and module types
|
||||
5. Platforms and device roles
|
||||
6. Devices and modules
|
||||
7. Providers, provider accounts and provider networks
|
||||
7. Providers, provider accounts, and provider networks
|
||||
8. Circuit types and circuits
|
||||
9. Wireless LAN groups and wireless LANs
|
||||
10. Route targets and VRFs
|
||||
|
@ -4,9 +4,13 @@ A circuit represents a physical point-to-point data connection, typically used t
|
||||
|
||||
## Fields
|
||||
|
||||
### Provider
|
||||
|
||||
The [provider](./provider.md) to which this circuit belongs.
|
||||
|
||||
### Provider Account
|
||||
|
||||
The [provider account](./provideraccount.md) to which this circuit belongs.
|
||||
Circuits may optionally be assigned to a specific [provider account](./provideraccount.md).
|
||||
|
||||
### Circuit ID
|
||||
|
||||
|
@ -7,15 +7,13 @@ router.APIRootView = views.CircuitsRootView
|
||||
|
||||
# Providers
|
||||
router.register('providers', views.ProviderViewSet)
|
||||
router.register('provider-accounts', views.ProviderAccountViewSet)
|
||||
router.register('provider-networks', views.ProviderNetworkViewSet)
|
||||
|
||||
# Circuits
|
||||
router.register('circuit-types', views.CircuitTypeViewSet)
|
||||
router.register('circuits', views.CircuitViewSet)
|
||||
router.register('circuit-terminations', views.CircuitTerminationViewSet)
|
||||
|
||||
# Provider networks
|
||||
router.register('provider-accounts', views.ProviderAccountViewSet)
|
||||
router.register('provider-networks', views.ProviderNetworkViewSet)
|
||||
|
||||
app_name = 'circuits-api'
|
||||
urlpatterns = router.urls
|
||||
|
@ -22,7 +22,7 @@ class CircuitsRootView(APIRootView):
|
||||
|
||||
class ProviderViewSet(NetBoxModelViewSet):
|
||||
queryset = Provider.objects.prefetch_related('asns', 'tags').annotate(
|
||||
circuit_count=count_related(Circuit, 'provider_account__provider')
|
||||
circuit_count=count_related(Circuit, 'provider')
|
||||
)
|
||||
serializer_class = serializers.ProviderSerializer
|
||||
filterset_class = filtersets.ProviderFilterSet
|
||||
@ -46,7 +46,7 @@ class CircuitTypeViewSet(NetBoxModelViewSet):
|
||||
|
||||
class CircuitViewSet(NetBoxModelViewSet):
|
||||
queryset = Circuit.objects.prefetch_related(
|
||||
'type', 'tenant', 'provider_account', 'provider_account__provider', 'termination_a', 'termination_z'
|
||||
'type', 'tenant', 'provider', 'provider_account', 'termination_a', 'termination_z'
|
||||
).prefetch_related('tags')
|
||||
serializer_class = serializers.CircuitSerializer
|
||||
filterset_class = filtersets.CircuitFilterSet
|
||||
@ -66,11 +66,11 @@ class CircuitTerminationViewSet(PassThroughPortMixin, NetBoxModelViewSet):
|
||||
|
||||
|
||||
#
|
||||
# Provider networks
|
||||
# Provider accounts
|
||||
#
|
||||
|
||||
class ProviderAccountViewSet(NetBoxModelViewSet):
|
||||
queryset = ProviderAccount.objects.prefetch_related('tags')
|
||||
queryset = ProviderAccount.objects.prefetch_related('provider', 'tags')
|
||||
serializer_class = serializers.ProviderAccountSerializer
|
||||
filterset_class = filtersets.ProviderAccountFilterSet
|
||||
|
||||
|
@ -24,37 +24,37 @@ __all__ = (
|
||||
class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
||||
region_id = TreeNodeMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
field_name='accounts__circuits__terminations__site__region',
|
||||
field_name='circuits__terminations__site__region',
|
||||
lookup_expr='in',
|
||||
label=_('Region (ID)'),
|
||||
)
|
||||
region = TreeNodeMultipleChoiceFilter(
|
||||
queryset=Region.objects.all(),
|
||||
field_name='accounts__circuits__terminations__site__region',
|
||||
field_name='circuits__terminations__site__region',
|
||||
lookup_expr='in',
|
||||
to_field_name='slug',
|
||||
label=_('Region (slug)'),
|
||||
)
|
||||
site_group_id = TreeNodeMultipleChoiceFilter(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
field_name='accounts__circuits__terminations__site__group',
|
||||
field_name='circuits__terminations__site__group',
|
||||
lookup_expr='in',
|
||||
label=_('Site group (ID)'),
|
||||
)
|
||||
site_group = TreeNodeMultipleChoiceFilter(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
field_name='accounts__circuits__terminations__site__group',
|
||||
field_name='circuits__terminations__site__group',
|
||||
lookup_expr='in',
|
||||
to_field_name='slug',
|
||||
label=_('Site group (slug)'),
|
||||
)
|
||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='accounts__circuits__terminations__site',
|
||||
field_name='circuits__terminations__site',
|
||||
queryset=Site.objects.all(),
|
||||
label=_('Site'),
|
||||
)
|
||||
site = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='accounts__circuits__terminations__site__slug',
|
||||
field_name='circuits__terminations__site__slug',
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
label=_('Site (slug)'),
|
||||
@ -67,7 +67,7 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
||||
|
||||
class Meta:
|
||||
model = Provider
|
||||
fields = ['id', 'name', 'slug', ]
|
||||
fields = ['id', 'name', 'slug']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
|
@ -35,7 +35,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
|
||||
|
||||
model = Provider
|
||||
fieldsets = (
|
||||
(None, ('asns', )),
|
||||
(None, ('asns', 'description')),
|
||||
)
|
||||
nullable_fields = (
|
||||
'asns', 'description', 'comments',
|
||||
@ -60,8 +60,7 @@ class ProviderAccountBulkEditForm(NetBoxModelBulkEditForm):
|
||||
(None, ('provider', 'description')),
|
||||
)
|
||||
nullable_fields = (
|
||||
'description',
|
||||
'comments',
|
||||
'description', 'comments',
|
||||
)
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ class ProviderAccountImportForm(NetBoxModelImportForm):
|
||||
class Meta:
|
||||
model = ProviderAccount
|
||||
fields = (
|
||||
'provider', 'name', 'account', 'comments', 'tags',
|
||||
'provider', 'name', 'account', 'description', 'comments', 'tags',
|
||||
)
|
||||
|
||||
|
||||
|
@ -69,7 +69,6 @@ class ProviderAccountFilterForm(NetBoxModelFilterSetForm):
|
||||
label=_('Provider')
|
||||
)
|
||||
account = forms.CharField(
|
||||
max_length=100,
|
||||
required=False
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
@ -41,8 +41,7 @@ class ProviderForm(NetBoxModelForm):
|
||||
|
||||
class ProviderAccountForm(NetBoxModelForm):
|
||||
provider = DynamicModelChoiceField(
|
||||
queryset=Provider.objects.all(),
|
||||
selector=True
|
||||
queryset=Provider.objects.all()
|
||||
)
|
||||
comments = CommentField()
|
||||
|
||||
@ -93,14 +92,10 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
|
||||
)
|
||||
provider_account = DynamicModelChoiceField(
|
||||
queryset=ProviderAccount.objects.all(),
|
||||
initial_params={
|
||||
'circuits': '$circuit'
|
||||
},
|
||||
required=False,
|
||||
query_params={
|
||||
'provider_id': '$provider',
|
||||
},
|
||||
selector=True,
|
||||
required=False
|
||||
}
|
||||
)
|
||||
type = DynamicModelChoiceField(
|
||||
queryset=CircuitType.objects.all()
|
||||
@ -129,9 +124,6 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
|
||||
class CircuitTerminationForm(NetBoxModelForm):
|
||||
circuit = DynamicModelChoiceField(
|
||||
queryset=Circuit.objects.all(),
|
||||
query_params={
|
||||
'provider_id': '$provider',
|
||||
},
|
||||
selector=True
|
||||
)
|
||||
site = DynamicModelChoiceField(
|
||||
|
@ -1,35 +1,34 @@
|
||||
# Generated by Django 4.1.4 on 2023-03-14 16:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
import utilities.json
|
||||
|
||||
|
||||
#
|
||||
# Migrate Account in Provider model to separate account model
|
||||
#
|
||||
def create_provideraccounts_from_providers(apps, schema_editor):
|
||||
"""
|
||||
Migrate Account in Provider model to separate account model
|
||||
"""
|
||||
Provider = apps.get_model('circuits', 'Provider')
|
||||
ProviderAccount = apps.get_model('circuits', 'ProviderAccount')
|
||||
|
||||
provider_accounts = []
|
||||
for provider in Provider.objects.all():
|
||||
if provider.account:
|
||||
provideraccount = ProviderAccount.objects.create(
|
||||
name=f'{provider.name} {provider.account}',
|
||||
account=provider.account,
|
||||
provider_accounts.append(ProviderAccount(
|
||||
provider=provider,
|
||||
)
|
||||
account=provider.account
|
||||
))
|
||||
ProviderAccount.objects.bulk_create(provider_accounts, batch_size=100)
|
||||
|
||||
|
||||
#
|
||||
# Unmigrate ProviderAccount to Provider model
|
||||
#
|
||||
def revert_provideraccounts_from_providers(apps, schema_editor):
|
||||
def restore_providers_from_provideraccounts(apps, schema_editor):
|
||||
"""
|
||||
Restore Provider account values from auto-generated ProviderAccounts
|
||||
"""
|
||||
ProviderAccount = apps.get_model('circuits', 'ProviderAccount')
|
||||
provideraccounts = ProviderAccount.objects.all().order_by('pk')
|
||||
for provideraccount in provideraccounts:
|
||||
if provideraccounts.filter(provider=provideraccount.provider)[0] == provideraccount:
|
||||
provider_accounts = ProviderAccount.objects.order_by('pk')
|
||||
for provideraccount in provider_accounts:
|
||||
if provider_accounts.filter(provider=provideraccount.provider)[0] == provideraccount:
|
||||
provideraccount.provider.account = provideraccount.account
|
||||
provideraccount.provider.save()
|
||||
|
||||
@ -51,7 +50,7 @@ class Migration(migrations.Migration):
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('account', models.CharField(max_length=30)),
|
||||
('account', models.CharField(max_length=100)),
|
||||
('name', models.CharField(blank=True, max_length=100)),
|
||||
('provider', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='accounts', to='circuits.provider')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
@ -62,14 +61,14 @@ class Migration(migrations.Migration):
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='provideraccount',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('account', ''), _negated=True), fields=('provider', 'name'), name='circuits_provideraccount_unique_provider_name'),
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('name', ''), _negated=True), fields=('provider', 'name'), name='circuits_provideraccount_unique_provider_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='provideraccount',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'account'), name='circuits_provideraccount_unique_provider_account'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
create_provideraccounts_from_providers, revert_provideraccounts_from_providers
|
||||
create_provideraccounts_from_providers, restore_providers_from_provideraccounts
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
|
@ -28,9 +28,9 @@ class CircuitType(OrganizationalModel):
|
||||
|
||||
class Circuit(PrimaryModel):
|
||||
"""
|
||||
A communications circuit connects two points. Each Circuit belongs to a Provider Account; ProviderAccounts may have
|
||||
multiple circuits. Each circuit is also assigned a CircuitType and a Site. Circuit port speed and commit rate are
|
||||
measured in Kbps.
|
||||
A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple
|
||||
circuits. Each circuit is also assigned a CircuitType and a Site, and may optionally be assigned to a particular
|
||||
ProviderAccount. Circuit port speed and commit rate are measured in Kbps.
|
||||
"""
|
||||
cid = models.CharField(
|
||||
max_length=100,
|
||||
@ -116,7 +116,6 @@ class Circuit(PrimaryModel):
|
||||
prerequisite_models = (
|
||||
'circuits.CircuitType',
|
||||
'circuits.Provider',
|
||||
'circuits.ProviderAccount',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@ -143,8 +142,9 @@ class Circuit(PrimaryModel):
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
if self.provider_account and self.provider != self.provider_account.provider:
|
||||
raise ValidationError("Provider must match ProviderAccount's provider")
|
||||
raise ValidationError({'provider_account': "The assigned account must belong to the assigned provider."})
|
||||
|
||||
|
||||
class CircuitTermination(
|
||||
|
@ -15,8 +15,8 @@ __all__ = (
|
||||
|
||||
class Provider(PrimaryModel):
|
||||
"""
|
||||
This is usually a telecommunications company or similar organization. This model stores information pertinent to
|
||||
the user's relationship with the Provider.
|
||||
Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
|
||||
stores information pertinent to the user's relationship with the Provider.
|
||||
"""
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
@ -54,19 +54,19 @@ class ProviderAccount(PrimaryModel):
|
||||
"""
|
||||
This is a discrete account within a provider. Each Circuit belongs to a Provider Account.
|
||||
"""
|
||||
account = models.CharField(
|
||||
max_length=30,
|
||||
verbose_name='Account number'
|
||||
)
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
blank=True
|
||||
)
|
||||
provider = models.ForeignKey(
|
||||
to='circuits.Provider',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='accounts'
|
||||
)
|
||||
account = models.CharField(
|
||||
max_length=100,
|
||||
verbose_name='Account ID'
|
||||
)
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
blank=True
|
||||
)
|
||||
|
||||
# Generic relations
|
||||
contacts = GenericRelation(
|
||||
@ -85,7 +85,7 @@ class ProviderAccount(PrimaryModel):
|
||||
models.UniqueConstraint(
|
||||
fields=('provider', 'name'),
|
||||
name='%(app_label)s_%(class)s_unique_provider_name',
|
||||
condition=~Q(account="")
|
||||
condition=~Q(name="")
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import django_tables2 as tables
|
||||
from django_tables2.utils import Accessor
|
||||
|
||||
from circuits.models import *
|
||||
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
||||
@ -53,7 +52,8 @@ class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||
linkify=True
|
||||
)
|
||||
provider_account = tables.Column(
|
||||
linkify=True
|
||||
linkify=True,
|
||||
verbose_name='Account'
|
||||
)
|
||||
status = columns.ChoiceFieldColumn()
|
||||
termination_a = tables.TemplateColumn(
|
||||
|
@ -50,8 +50,8 @@ class ProviderTable(ContactsColumnMixin, NetBoxTable):
|
||||
class Meta(NetBoxTable.Meta):
|
||||
model = Provider
|
||||
fields = (
|
||||
'pk', 'id', 'name', 'accounts', 'account_count', 'asns', 'asn_count', 'circuit_count', 'description', 'comments', 'contacts',
|
||||
'tags', 'created', 'last_updated',
|
||||
'pk', 'id', 'name', 'accounts', 'account_count', 'asns', 'asn_count', 'circuit_count', 'description',
|
||||
'comments', 'contacts', 'tags', 'created', 'last_updated',
|
||||
)
|
||||
default_columns = ('pk', 'name', 'account_count', 'circuit_count')
|
||||
|
||||
@ -64,6 +64,12 @@ class ProviderAccountTable(ContactsColumnMixin, NetBoxTable):
|
||||
provider = tables.Column(
|
||||
linkify=True
|
||||
)
|
||||
circuit_count = columns.LinkedCountColumn(
|
||||
accessor=Accessor('count_circuits'),
|
||||
viewname='circuits:circuit_list',
|
||||
url_params={'provider_account_id': 'pk'},
|
||||
verbose_name='Circuits'
|
||||
)
|
||||
comments = columns.MarkdownColumn()
|
||||
tags = columns.TagColumn(
|
||||
url_name='circuits:provideraccount_list'
|
||||
@ -72,7 +78,8 @@ class ProviderAccountTable(ContactsColumnMixin, NetBoxTable):
|
||||
class Meta(NetBoxTable.Meta):
|
||||
model = ProviderAccount
|
||||
fields = (
|
||||
'pk', 'id', 'account', 'name', 'provider', 'circuit_count', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
||||
'pk', 'id', 'account', 'name', 'provider', 'circuit_count', 'comments', 'contacts', 'tags', 'created',
|
||||
'last_updated',
|
||||
)
|
||||
default_columns = ('pk', 'account', 'name', 'provider', 'circuit_count')
|
||||
|
||||
|
@ -158,11 +158,6 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
|
||||
|
||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||
circuit_type = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
||||
provider_account = ProviderAccount.objects.create(
|
||||
name='Provider Account 2',
|
||||
provider=provider,
|
||||
account='2345'
|
||||
)
|
||||
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1'),
|
||||
@ -177,9 +172,9 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
|
||||
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||
|
||||
circuits = (
|
||||
Circuit(cid='Circuit 1', provider=provider, provider_account=provider_account, type=circuit_type),
|
||||
Circuit(cid='Circuit 2', provider=provider, provider_account=provider_account, type=circuit_type),
|
||||
Circuit(cid='Circuit 3', provider=provider, provider_account=provider_account, type=circuit_type),
|
||||
Circuit(cid='Circuit 1', provider=provider, type=circuit_type),
|
||||
Circuit(cid='Circuit 2', provider=provider, type=circuit_type),
|
||||
Circuit(cid='Circuit 3', provider=provider, type=circuit_type),
|
||||
)
|
||||
Circuit.objects.bulk_create(circuits)
|
||||
|
||||
|
@ -36,15 +36,6 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
providers[1].asns.set([asns[1]])
|
||||
providers[2].asns.set([asns[2]])
|
||||
|
||||
provider_accounts = (
|
||||
ProviderAccount(name='Account A', account='AAAA', provider=providers[0]),
|
||||
ProviderAccount(name='Account B', account='BBBB', provider=providers[1]),
|
||||
ProviderAccount(name='Account C', account='CCCC', provider=providers[2]),
|
||||
ProviderAccount(name='Account D', account='DDDD', provider=providers[3]),
|
||||
ProviderAccount(name='Account E', account='EEEE', provider=providers[4]),
|
||||
)
|
||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||
|
||||
regions = (
|
||||
Region(name='Test Region 1', slug='test-region-1'),
|
||||
Region(name='Test Region 2', slug='test-region-2'),
|
||||
@ -73,8 +64,8 @@ class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
CircuitType.objects.bulk_create(circuit_types)
|
||||
|
||||
circuits = (
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Test Circuit 1'),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], type=circuit_types[1], cid='Test Circuit 1'),
|
||||
Circuit(provider=providers[0], type=circuit_types[0], cid='Circuit 1'),
|
||||
Circuit(provider=providers[1], type=circuit_types[1], cid='Circuit 2'),
|
||||
)
|
||||
Circuit.objects.bulk_create(circuits)
|
||||
|
||||
@ -202,8 +193,9 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
Provider.objects.bulk_create(providers)
|
||||
|
||||
provider_accounts = (
|
||||
ProviderAccount(name='Provider Account 1', provider=providers[0], account='1234'),
|
||||
ProviderAccount(name='Provider Account 2', provider=providers[1], account='2345'),
|
||||
ProviderAccount(name='Provider Account 1', provider=providers[0], account='A'),
|
||||
ProviderAccount(name='Provider Account 2', provider=providers[1], account='B'),
|
||||
ProviderAccount(name='Provider Account 3', provider=providers[2], account='C'),
|
||||
)
|
||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||
|
||||
@ -217,10 +209,10 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
circuits = (
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 1', install_date='2020-01-01', termination_date='2021-01-01', commit_rate=1000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar1'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 2', install_date='2020-01-02', termination_date='2021-01-02', commit_rate=2000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar2'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], tenant=tenants[1], type=circuit_types[0], cid='Test Circuit 3', install_date='2020-01-03', termination_date='2021-01-03', commit_rate=3000, status=CircuitStatusChoices.STATUS_PLANNED),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[1], tenant=tenants[1], type=circuit_types[0], cid='Test Circuit 3', install_date='2020-01-03', termination_date='2021-01-03', commit_rate=3000, status=CircuitStatusChoices.STATUS_PLANNED),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], tenant=tenants[1], type=circuit_types[1], cid='Test Circuit 4', install_date='2020-01-04', termination_date='2021-01-04', commit_rate=4000, status=CircuitStatusChoices.STATUS_PLANNED),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 5', install_date='2020-01-05', termination_date='2021-01-05', commit_rate=5000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 6', install_date='2020-01-06', termination_date='2021-01-06', commit_rate=6000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[2], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 5', install_date='2020-01-05', termination_date='2021-01-05', commit_rate=5000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[2], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 6', install_date='2020-01-06', termination_date='2021-01-06', commit_rate=6000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
||||
)
|
||||
Circuit.objects.bulk_create(circuits)
|
||||
|
||||
@ -258,9 +250,9 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
|
||||
def test_provider_account(self):
|
||||
provider_account = ProviderAccount.objects.first()
|
||||
params = {'provider_account_id': [provider_account.pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
provider_accounts = ProviderAccount.objects.all()[:2]
|
||||
params = {'provider_account_id': [provider_accounts[0].pk, provider_accounts[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||
|
||||
def test_provider_network(self):
|
||||
provider_networks = ProviderNetwork.objects.all()[:2]
|
||||
@ -342,11 +334,6 @@ class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
)
|
||||
Provider.objects.bulk_create(providers)
|
||||
|
||||
provider_accounts = (
|
||||
ProviderAccount(name='Provider Account 1', provider=providers[0], account='1234'),
|
||||
)
|
||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||
|
||||
provider_networks = (
|
||||
ProviderNetwork(name='Provider Network 1', provider=providers[0]),
|
||||
ProviderNetwork(name='Provider Network 2', provider=providers[0]),
|
||||
@ -355,13 +342,13 @@ class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||
|
||||
circuits = (
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 1'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 2'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 3'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 4'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 5'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 6'),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], type=circuit_types[0], cid='Circuit 7'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 1'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 2'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 3'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 4'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 5'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 6'),
|
||||
Circuit(provider=providers[0], circuitstype=circuit_types[0], cid='Circuit 7'),
|
||||
)
|
||||
Circuit.objects.bulk_create(circuits)
|
||||
|
||||
|
@ -202,7 +202,6 @@ class ProviderAccountTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
ProviderAccount(name='Provider Account 2', provider=providers[0], account='2345'),
|
||||
ProviderAccount(name='Provider Account 3', provider=providers[0], account='3456'),
|
||||
)
|
||||
|
||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||
|
||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||
@ -305,12 +304,11 @@ class CircuitTerminationTestCase(
|
||||
Site.objects.bulk_create(sites)
|
||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||
circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
||||
account = ProviderAccount.objects.create(name='Provider Account 1', provider=provider, account='1234')
|
||||
|
||||
circuits = (
|
||||
Circuit(cid='Circuit 1', provider=provider, provider_account=account, type=circuittype),
|
||||
Circuit(cid='Circuit 2', provider=provider, provider_account=account, type=circuittype),
|
||||
Circuit(cid='Circuit 3', provider=provider, provider_account=account, type=circuittype),
|
||||
Circuit(cid='Circuit 1', provider=provider, type=circuittype),
|
||||
Circuit(cid='Circuit 2', provider=provider, type=circuittype),
|
||||
Circuit(cid='Circuit 3', provider=provider, type=circuittype),
|
||||
)
|
||||
Circuit.objects.bulk_create(circuits)
|
||||
|
||||
|
@ -14,7 +14,7 @@ urlpatterns = [
|
||||
path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
|
||||
path('providers/<int:pk>/', include(get_model_urls('circuits', 'provider'))),
|
||||
|
||||
# Provider networks
|
||||
# Provider accounts
|
||||
path('provider-accounts/', views.ProviderAccountListView.as_view(), name='provideraccount_list'),
|
||||
path('provider-accounts/add/', views.ProviderAccountEditView.as_view(), name='provideraccount_add'),
|
||||
path('provider-accounts/import/', views.ProviderAccountBulkImportView.as_view(), name='provideraccount_import'),
|
||||
|
@ -30,9 +30,8 @@ class CablePathTestCase(TestCase):
|
||||
cls.powerpanel = PowerPanel.objects.create(site=cls.site, name='Power Panel')
|
||||
|
||||
provider = Provider.objects.create(name='Provider', slug='provider')
|
||||
provider_account = ProviderAccount.objects.create(name='Account', account='AAAA1111', provider=provider)
|
||||
circuit_type = CircuitType.objects.create(name='Circuit Type', slug='circuit-type')
|
||||
cls.circuit = Circuit.objects.create(provider=provider, provider_account=provider_account, type=circuit_type, cid='Circuit 1')
|
||||
cls.circuit = Circuit.objects.create(provider=provider, type=circuit_type, cid='Circuit 1')
|
||||
|
||||
def assertPathExists(self, nodes, **kwargs):
|
||||
"""
|
||||
@ -1309,7 +1308,7 @@ class CablePathTestCase(TestCase):
|
||||
[IF1] --C1-- [CT1] [CT2] --> [PN1]
|
||||
"""
|
||||
interface1 = Interface.objects.create(device=self.device, name='Interface 1')
|
||||
providernetwork = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.circuit.provider_account.provider)
|
||||
providernetwork = ProviderNetwork.objects.create(name='Provider Network 1', provider=self.circuit.provider)
|
||||
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, site=self.site, term_side='A')
|
||||
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, provider_network=providernetwork, term_side='Z')
|
||||
|
||||
@ -1437,7 +1436,7 @@ 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, provider_account=self.circuit.provider_account, type=self.circuit.type, cid='Circuit 2')
|
||||
circuit2 = Circuit.objects.create(provider=self.circuit.provider, type=self.circuit.type, cid='Circuit 2')
|
||||
circuittermination1 = CircuitTermination.objects.create(circuit=self.circuit, site=self.site, term_side='A')
|
||||
circuittermination2 = CircuitTermination.objects.create(circuit=self.circuit, site=self.site, term_side='Z')
|
||||
circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, site=self.site, term_side='A')
|
||||
|
@ -504,11 +504,10 @@ class CableTestCase(TestCase):
|
||||
device=patch_pannel, name='FP4', type='8p8c', rear_port=rear_port4, rear_port_position=1
|
||||
)
|
||||
provider = Provider.objects.create(name='Provider 1', slug='provider-1')
|
||||
provider_account = ProviderAccount.objects.create(name='Provider Account 1', account='A1', provider=provider)
|
||||
provider_network = ProviderNetwork.objects.create(name='Provider Network 1', provider=provider)
|
||||
circuittype = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
||||
circuit1 = Circuit.objects.create(provider=provider, provider_account=provider_account, type=circuittype, cid='1')
|
||||
circuit2 = Circuit.objects.create(provider=provider, provider_account=provider_account, type=circuittype, cid='2')
|
||||
circuit1 = Circuit.objects.create(provider=provider, type=circuittype, cid='1')
|
||||
circuit2 = Circuit.objects.create(provider=provider, type=circuittype, cid='2')
|
||||
circuittermination1 = CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='A')
|
||||
circuittermination2 = CircuitTermination.objects.create(circuit=circuit1, site=site, term_side='Z')
|
||||
circuittermination3 = CircuitTermination.objects.create(circuit=circuit2, provider_network=provider_network, term_side='A')
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.test import TransactionTestCase
|
||||
|
||||
from circuits.models import Provider, Circuit, CircuitType, ProviderAccount
|
||||
from circuits.models import Provider, Circuit, CircuitType
|
||||
from extras.choices import ChangeActionChoices
|
||||
from extras.models import Branch, StagedChange, Tag
|
||||
from ipam.models import ASN, RIR
|
||||
@ -28,25 +28,18 @@ class StagingTestCase(TransactionTestCase):
|
||||
)
|
||||
Provider.objects.bulk_create(providers)
|
||||
|
||||
provider_accounts = (
|
||||
ProviderAccount(name='Account A', provider=providers[0], account='AAAA'),
|
||||
ProviderAccount(name='Account B', provider=providers[1], account='BBBB'),
|
||||
ProviderAccount(name='Account C', provider=providers[2], account='CCCC'),
|
||||
)
|
||||
ProviderAccount.objects.bulk_create(provider_accounts)
|
||||
|
||||
circuit_type = CircuitType.objects.create(name='Circuit Type 1', slug='circuit-type-1')
|
||||
|
||||
Circuit.objects.bulk_create((
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], cid='Circuit A1', type=circuit_type),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], cid='Circuit A2', type=circuit_type),
|
||||
Circuit(provider=providers[0], provider_account=provider_accounts[0], cid='Circuit A3', type=circuit_type),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], cid='Circuit B1', type=circuit_type),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], cid='Circuit B2', type=circuit_type),
|
||||
Circuit(provider=providers[1], provider_account=provider_accounts[1], cid='Circuit B3', type=circuit_type),
|
||||
Circuit(provider=providers[2], provider_account=provider_accounts[2], cid='Circuit C1', type=circuit_type),
|
||||
Circuit(provider=providers[2], provider_account=provider_accounts[2], cid='Circuit C2', type=circuit_type),
|
||||
Circuit(provider=providers[2], provider_account=provider_accounts[2], cid='Circuit C3', type=circuit_type),
|
||||
Circuit(provider=providers[0], cid='Circuit A1', type=circuit_type),
|
||||
Circuit(provider=providers[0], cid='Circuit A2', type=circuit_type),
|
||||
Circuit(provider=providers[0], cid='Circuit A3', type=circuit_type),
|
||||
Circuit(provider=providers[1], cid='Circuit B1', type=circuit_type),
|
||||
Circuit(provider=providers[1], cid='Circuit B2', type=circuit_type),
|
||||
Circuit(provider=providers[1], cid='Circuit B3', type=circuit_type),
|
||||
Circuit(provider=providers[2], cid='Circuit C1', type=circuit_type),
|
||||
Circuit(provider=providers[2], cid='Circuit C2', type=circuit_type),
|
||||
Circuit(provider=providers[2], cid='Circuit C3', type=circuit_type),
|
||||
))
|
||||
|
||||
def test_object_creation(self):
|
||||
@ -57,8 +50,7 @@ class StagingTestCase(TransactionTestCase):
|
||||
with checkout(branch):
|
||||
provider = Provider.objects.create(name='Provider D', slug='provider-d')
|
||||
provider.asns.set(asns)
|
||||
provider_account = ProviderAccount.objects.create(name='Account D', provider=provider, account='DDDD')
|
||||
circuit = Circuit.objects.create(provider=provider, provider_account=provider_account, cid='Circuit D1', type=CircuitType.objects.first())
|
||||
circuit = Circuit.objects.create(provider=provider, cid='Circuit D1', type=CircuitType.objects.first())
|
||||
circuit.tags.set(tags)
|
||||
|
||||
# Sanity-checking
|
||||
@ -70,7 +62,7 @@ class StagingTestCase(TransactionTestCase):
|
||||
# Verify that changes have been rolled back after exiting the context
|
||||
self.assertEqual(Provider.objects.count(), 3)
|
||||
self.assertEqual(Circuit.objects.count(), 9)
|
||||
self.assertEqual(StagedChange.objects.count(), 6)
|
||||
self.assertEqual(StagedChange.objects.count(), 5)
|
||||
|
||||
# Verify that changes are replayed upon entering the context
|
||||
with checkout(branch):
|
||||
@ -153,31 +145,25 @@ class StagingTestCase(TransactionTestCase):
|
||||
|
||||
with checkout(branch):
|
||||
provider = Provider.objects.get(name='Provider A')
|
||||
Circuit.objects.filter(provider_account__provider=provider).delete()
|
||||
provider.accounts.all().delete()
|
||||
provider.delete()
|
||||
|
||||
# Sanity-checking
|
||||
self.assertEqual(Provider.objects.count(), 2)
|
||||
self.assertEqual(ProviderAccount.objects.count(), 2)
|
||||
self.assertEqual(Circuit.objects.count(), 6)
|
||||
|
||||
# Verify that changes have been rolled back after exiting the context
|
||||
self.assertEqual(Provider.objects.count(), 3)
|
||||
self.assertEqual(ProviderAccount.objects.count(), 3)
|
||||
self.assertEqual(Circuit.objects.count(), 9)
|
||||
self.assertEqual(StagedChange.objects.count(), 5)
|
||||
self.assertEqual(StagedChange.objects.count(), 4)
|
||||
|
||||
# Verify that changes are replayed upon entering the context
|
||||
with checkout(branch):
|
||||
self.assertEqual(Provider.objects.count(), 2)
|
||||
self.assertEqual(ProviderAccount.objects.count(), 2)
|
||||
self.assertEqual(Circuit.objects.count(), 6)
|
||||
|
||||
# Verify that changes are applied and deleted upon branch merge
|
||||
branch.merge()
|
||||
self.assertEqual(Provider.objects.count(), 2)
|
||||
self.assertEqual(ProviderAccount.objects.count(), 2)
|
||||
self.assertEqual(Circuit.objects.count(), 6)
|
||||
self.assertEqual(StagedChange.objects.count(), 0)
|
||||
|
||||
|
@ -19,8 +19,8 @@
|
||||
<td>{{ object.provider|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Provider Account</th>
|
||||
<td>{{ object.provider_account|linkify }}</td>
|
||||
<th scope="row">Account</th>
|
||||
<td>{{ object.provider_account|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Circuit ID</th>
|
||||
|
@ -10,12 +10,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Provider Account
|
||||
</h5>
|
||||
<h5 class="card-header">Provider Account</h5>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
@ -23,12 +21,12 @@
|
||||
<td>{{ object.provider|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Name</th>
|
||||
<td>{{ object.name }}</td>
|
||||
<th scope="row">Account</th>
|
||||
<td>{{ object.account }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Account</th>
|
||||
<td>{{ object.account|placeholder }}</td>
|
||||
<th scope="row">Name</th>
|
||||
<td>{{ object.name|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@ -43,16 +41,15 @@
|
||||
{% include 'inc/panels/contacts.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Circuits</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'circuits:circuit_list' %}?provider_id={{ object.pk }}"
|
||||
hx-get="{% url 'circuits:circuit_list' %}?provider_account_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user