mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #7120: Add termination_date field to Circuit
This commit is contained in:
@ -13,7 +13,7 @@ Each circuit is also assigned one of the following operational statuses:
|
|||||||
* Deprovisioning
|
* Deprovisioning
|
||||||
* Decommissioned
|
* Decommissioned
|
||||||
|
|
||||||
Circuits also have optional fields for annotating their installation date and commit rate, and may be assigned to NetBox tenants.
|
Circuits also have optional fields for annotating their installation and termination dates and commit rate, and may be assigned to NetBox tenants.
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
NetBox currently models only physical circuits: those which have exactly two endpoints. It is common to layer virtualized constructs (_virtual circuits_) such as MPLS or EVPN tunnels on top of these, however NetBox does not yet support virtual circuit modeling.
|
NetBox currently models only physical circuits: those which have exactly two endpoints. It is common to layer virtualized constructs (_virtual circuits_) such as MPLS or EVPN tunnels on top of these, however NetBox does not yet support virtual circuit modeling.
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
* [#1202](https://github.com/netbox-community/netbox/issues/1202) - Support overlapping assignment of NAT IP addresses
|
* [#1202](https://github.com/netbox-community/netbox/issues/1202) - Support overlapping assignment of NAT IP addresses
|
||||||
* [#4350](https://github.com/netbox-community/netbox/issues/4350) - Illustrate reservations vertically alongside rack elevations
|
* [#4350](https://github.com/netbox-community/netbox/issues/4350) - Illustrate reservations vertically alongside rack elevations
|
||||||
* [#5303](https://github.com/netbox-community/netbox/issues/5303) - A virtual machine may be assigned to a site and/or cluster
|
* [#5303](https://github.com/netbox-community/netbox/issues/5303) - A virtual machine may be assigned to a site and/or cluster
|
||||||
|
* [#7120](https://github.com/netbox-community/netbox/issues/7120) - Add `termination_date` field to Circuit
|
||||||
* [#7744](https://github.com/netbox-community/netbox/issues/7744) - Add `status` field to Location
|
* [#7744](https://github.com/netbox-community/netbox/issues/7744) - Add `status` field to Location
|
||||||
* [#8222](https://github.com/netbox-community/netbox/issues/8222) - Enable the assignment of a VM to a specific host device within a cluster
|
* [#8222](https://github.com/netbox-community/netbox/issues/8222) - Enable the assignment of a VM to a specific host device within a cluster
|
||||||
* [#8471](https://github.com/netbox-community/netbox/issues/8471) - Add `status` field to Cluster
|
* [#8471](https://github.com/netbox-community/netbox/issues/8471) - Add `status` field to Cluster
|
||||||
@ -32,6 +33,8 @@
|
|||||||
|
|
||||||
### REST API Changes
|
### REST API Changes
|
||||||
|
|
||||||
|
* circuits.Circuit
|
||||||
|
* Added optional `termination_date` field
|
||||||
* dcim.Device
|
* dcim.Device
|
||||||
* The `position` field has been changed from an integer to a decimal
|
* The `position` field has been changed from an integer to a decimal
|
||||||
* dcim.DeviceType
|
* dcim.DeviceType
|
||||||
|
@ -92,9 +92,9 @@ class CircuitSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate',
|
'id', 'url', 'display', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date',
|
||||||
'description', 'termination_a', 'termination_z', 'comments', 'tags', 'custom_fields', 'created',
|
'commit_rate', 'description', 'termination_a', 'termination_z', 'comments', 'tags', 'custom_fields',
|
||||||
'last_updated',
|
'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fields = ['id', 'cid', 'description', 'install_date', 'commit_rate']
|
fields = ['id', 'cid', 'description', 'install_date', 'termination_date', 'commit_rate']
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -7,7 +7,7 @@ from ipam.models import ASN
|
|||||||
from netbox.forms import NetBoxModelBulkEditForm
|
from netbox.forms import NetBoxModelBulkEditForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
add_blank_choice, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SmallTextarea,
|
add_blank_choice, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SmallTextarea,
|
||||||
StaticSelect,
|
StaticSelect,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -122,6 +122,14 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
install_date = forms.DateField(
|
||||||
|
required=False,
|
||||||
|
widget=DatePicker()
|
||||||
|
)
|
||||||
|
termination_date = forms.DateField(
|
||||||
|
required=False,
|
||||||
|
widget=DatePicker()
|
||||||
|
)
|
||||||
commit_rate = forms.IntegerField(
|
commit_rate = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Commit rate (Kbps)'
|
label='Commit rate (Kbps)'
|
||||||
@ -137,7 +145,9 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('type', 'provider', 'status', 'tenant', 'commit_rate', 'description')),
|
('Circuit', ('provider', 'type', 'status', 'description')),
|
||||||
|
('Service Parameters', ('install_date', 'termination_date', 'commit_rate')),
|
||||||
|
('Tenancy', ('tenant',)),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'tenant', 'commit_rate', 'description', 'comments',
|
'tenant', 'commit_rate', 'description', 'comments',
|
||||||
|
@ -72,5 +72,6 @@ class CircuitCSVForm(NetBoxModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fields = [
|
fields = [
|
||||||
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
|
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate',
|
||||||
|
'description', 'comments',
|
||||||
]
|
]
|
||||||
|
@ -7,7 +7,7 @@ from dcim.models import Region, Site, SiteGroup
|
|||||||
from ipam.models import ASN
|
from ipam.models import ASN
|
||||||
from netbox.forms import NetBoxModelFilterSetForm
|
from netbox.forms import NetBoxModelFilterSetForm
|
||||||
from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
|
from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
|
||||||
from utilities.forms import DynamicModelMultipleChoiceField, MultipleChoiceField, TagFilterField
|
from utilities.forms import DatePicker, DynamicModelMultipleChoiceField, MultipleChoiceField, TagFilterField
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'CircuitFilterForm',
|
'CircuitFilterForm',
|
||||||
@ -84,7 +84,7 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi
|
|||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'tag')),
|
||||||
('Provider', ('provider_id', 'provider_network_id')),
|
('Provider', ('provider_id', 'provider_network_id')),
|
||||||
('Attributes', ('type_id', 'status', 'commit_rate')),
|
('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
@ -130,6 +130,14 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi
|
|||||||
},
|
},
|
||||||
label=_('Site')
|
label=_('Site')
|
||||||
)
|
)
|
||||||
|
install_date = forms.DateField(
|
||||||
|
required=False,
|
||||||
|
widget=DatePicker
|
||||||
|
)
|
||||||
|
termination_date = forms.DateField(
|
||||||
|
required=False,
|
||||||
|
widget=DatePicker
|
||||||
|
)
|
||||||
commit_rate = forms.IntegerField(
|
commit_rate = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
min_value=0,
|
min_value=0,
|
||||||
|
@ -93,15 +93,16 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')),
|
('Circuit', ('provider', 'cid', 'type', 'status', 'description', 'tags')),
|
||||||
|
('Service Parameters', ('install_date', 'termination_date', 'commit_rate')),
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fields = [
|
fields = [
|
||||||
'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
|
'cid', 'type', 'provider', 'status', 'install_date', 'termination_date', 'commit_rate', 'description',
|
||||||
'comments', 'tags',
|
'tenant_group', 'tenant', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'cid': "Unique circuit ID",
|
'cid': "Unique circuit ID",
|
||||||
@ -110,6 +111,7 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
|
|||||||
widgets = {
|
widgets = {
|
||||||
'status': StaticSelect(),
|
'status': StaticSelect(),
|
||||||
'install_date': DatePicker(),
|
'install_date': DatePicker(),
|
||||||
|
'termination_date': DatePicker(),
|
||||||
'commit_rate': SelectSpeedWidget(),
|
'commit_rate': SelectSpeedWidget(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
netbox/circuits/migrations/0036_circuit_termination_date.py
Normal file
18
netbox/circuits/migrations/0036_circuit_termination_date.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.0.5 on 2022-06-22 18:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('circuits', '0035_provider_asns'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='circuit',
|
||||||
|
name='termination_date',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -78,7 +78,12 @@ class Circuit(NetBoxModel):
|
|||||||
install_date = models.DateField(
|
install_date = models.DateField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name='Date installed'
|
verbose_name='Installed'
|
||||||
|
)
|
||||||
|
termination_date = models.DateField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
verbose_name='Terminates'
|
||||||
)
|
)
|
||||||
commit_rate = models.PositiveIntegerField(
|
commit_rate = models.PositiveIntegerField(
|
||||||
blank=True,
|
blank=True,
|
||||||
@ -119,7 +124,7 @@ class Circuit(NetBoxModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
clone_fields = [
|
clone_fields = [
|
||||||
'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description',
|
'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate', 'description',
|
||||||
]
|
]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -70,7 +70,7 @@ class CircuitTable(NetBoxTable):
|
|||||||
model = Circuit
|
model = Circuit
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date',
|
'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date',
|
||||||
'commit_rate', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
'termination_date', 'commit_rate', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'description',
|
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'description',
|
||||||
|
@ -208,12 +208,12 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
ProviderNetwork.objects.bulk_create(provider_networks)
|
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||||
|
|
||||||
circuits = (
|
circuits = (
|
||||||
Circuit(provider=providers[0], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 1', install_date='2020-01-01', commit_rate=1000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar1'),
|
Circuit(provider=providers[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], tenant=tenants[0], type=circuit_types[0], cid='Test Circuit 2', install_date='2020-01-02', commit_rate=2000, status=CircuitStatusChoices.STATUS_ACTIVE, description='foobar2'),
|
Circuit(provider=providers[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], tenant=tenants[1], type=circuit_types[0], cid='Test Circuit 3', install_date='2020-01-03', commit_rate=3000, status=CircuitStatusChoices.STATUS_PLANNED),
|
Circuit(provider=providers[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[1], tenant=tenants[1], type=circuit_types[1], cid='Test Circuit 4', install_date='2020-01-04', commit_rate=4000, status=CircuitStatusChoices.STATUS_PLANNED),
|
Circuit(provider=providers[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], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 5', install_date='2020-01-05', commit_rate=5000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
Circuit(provider=providers[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], tenant=tenants[2], type=circuit_types[1], cid='Test Circuit 6', install_date='2020-01-06', commit_rate=6000, status=CircuitStatusChoices.STATUS_OFFLINE),
|
Circuit(provider=providers[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.objects.bulk_create(circuits)
|
Circuit.objects.bulk_create(circuits)
|
||||||
|
|
||||||
@ -235,6 +235,10 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'install_date': ['2020-01-01', '2020-01-02']}
|
params = {'install_date': ['2020-01-01', '2020-01-02']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_termination_date(self):
|
||||||
|
params = {'termination_date': ['2021-01-01', '2021-01-02']}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_commit_rate(self):
|
def test_commit_rate(self):
|
||||||
params = {'commit_rate': ['1000', '2000']}
|
params = {'commit_rate': ['1000', '2000']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
@ -130,6 +130,7 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'status': CircuitStatusChoices.STATUS_DECOMMISSIONED,
|
'status': CircuitStatusChoices.STATUS_DECOMMISSIONED,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'install_date': datetime.date(2020, 1, 1),
|
'install_date': datetime.date(2020, 1, 1),
|
||||||
|
'termination_date': datetime.date(2021, 1, 1),
|
||||||
'commit_rate': 1000,
|
'commit_rate': 1000,
|
||||||
'description': 'A new circuit',
|
'description': 'A new circuit',
|
||||||
'comments': 'Some comments',
|
'comments': 'Some comments',
|
||||||
|
@ -45,6 +45,10 @@
|
|||||||
<th scope="row">Install Date</th>
|
<th scope="row">Install Date</th>
|
||||||
<td>{{ object.install_date|annotated_date|placeholder }}</td>
|
<td>{{ object.install_date|annotated_date|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Termination Date</th>
|
||||||
|
<td>{{ object.termination_date|annotated_date|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Commit Rate</th>
|
<th scope="row">Commit Rate</th>
|
||||||
<td>{{ object.commit_rate|humanize_speed|placeholder }}</td>
|
<td>{{ object.commit_rate|humanize_speed|placeholder }}</td>
|
||||||
|
Reference in New Issue
Block a user