mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-19 11:52:22 -06:00
9856 merge feature
This commit is contained in:
@@ -2,8 +2,8 @@ import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import login as auth_login, logout as auth_logout
|
||||
from django.contrib.auth import update_session_auth_hash
|
||||
from django.contrib.auth import login as auth_login, logout as auth_logout, update_session_auth_hash
|
||||
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.models import update_last_login
|
||||
from django.contrib.auth.signals import user_logged_in
|
||||
@@ -72,7 +72,7 @@ class LoginView(View):
|
||||
return auth_backends
|
||||
|
||||
def get(self, request):
|
||||
form = forms.LoginForm(request)
|
||||
form = AuthenticationForm(request)
|
||||
|
||||
if request.user.is_authenticated:
|
||||
logger = logging.getLogger('netbox.auth.login')
|
||||
@@ -85,7 +85,7 @@ class LoginView(View):
|
||||
|
||||
def post(self, request):
|
||||
logger = logging.getLogger('netbox.auth.login')
|
||||
form = forms.LoginForm(request, data=request.POST)
|
||||
form = AuthenticationForm(request, data=request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
logger.debug("Login form validation was successful")
|
||||
@@ -220,7 +220,7 @@ class ChangePasswordView(LoginRequiredMixin, View):
|
||||
messages.warning(request, "LDAP-authenticated user credentials cannot be changed within NetBox.")
|
||||
return redirect('account:profile')
|
||||
|
||||
form = forms.PasswordChangeForm(user=request.user)
|
||||
form = PasswordChangeForm(user=request.user)
|
||||
|
||||
return render(request, self.template_name, {
|
||||
'form': form,
|
||||
@@ -228,7 +228,7 @@ class ChangePasswordView(LoginRequiredMixin, View):
|
||||
})
|
||||
|
||||
def post(self, request):
|
||||
form = forms.PasswordChangeForm(user=request.user, data=request.POST)
|
||||
form = PasswordChangeForm(user=request.user, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
update_session_auth_hash(request, form.user)
|
||||
|
||||
@@ -7,7 +7,6 @@ from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from netbox.forms import NetBoxModelImportForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import BootstrapMixin
|
||||
from utilities.forms.fields import CSVChoiceField, CSVModelChoiceField, SlugField
|
||||
|
||||
__all__ = (
|
||||
@@ -112,7 +111,7 @@ class CircuitImportForm(NetBoxModelImportForm):
|
||||
]
|
||||
|
||||
|
||||
class CircuitTerminationImportForm(BootstrapMixin, forms.ModelForm):
|
||||
class CircuitTerminationImportForm(forms.ModelForm):
|
||||
site = CSVModelChoiceField(
|
||||
label=_('Site'),
|
||||
queryset=Site.objects.all(),
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2021-10-21 14:50
|
||||
|
||||
from django.db import migrations
|
||||
import taggit.managers
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0062_clear_secrets_changelog'),
|
||||
('circuits', '0002_squashed_0029'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='circuittype',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
]
|
||||
127
netbox/circuits/migrations/0003_squashed_0037.py
Normal file
127
netbox/circuits/migrations/0003_squashed_0037.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import taggit.managers
|
||||
from django.db import migrations, models
|
||||
|
||||
import utilities.json
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [
|
||||
('circuits', '0003_extend_tag_support'),
|
||||
('circuits', '0004_rename_cable_peer'),
|
||||
('circuits', '0032_provider_service_id'),
|
||||
('circuits', '0033_standardize_id_fields'),
|
||||
('circuits', '0034_created_datetimefield'),
|
||||
('circuits', '0035_provider_asns'),
|
||||
('circuits', '0036_circuit_termination_date_tags_custom_fields'),
|
||||
('circuits', '0037_new_cabling_models')
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0047_squashed_0053'),
|
||||
('extras', '0002_squashed_0059'),
|
||||
('circuits', '0002_squashed_0029'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='circuittype',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='circuittermination',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='circuittermination',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='providernetwork',
|
||||
name='service_id',
|
||||
field=models.CharField(blank=True, max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuit',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittype',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='provider',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='providernetwork',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuit',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittype',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='provider',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='providernetwork',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='provider',
|
||||
name='asns',
|
||||
field=models.ManyToManyField(blank=True, related_name='providers', to='ipam.asn'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuit',
|
||||
name='termination_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='custom_field_data',
|
||||
field=models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0003_extend_tag_support'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='circuittermination',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='circuittermination',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
]
|
||||
@@ -1,17 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0004_rename_cable_peer'),
|
||||
('dcim', '0145_site_remove_deprecated_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='providernetwork',
|
||||
name='service_id',
|
||||
field=models.CharField(blank=True, max_length=100),
|
||||
),
|
||||
]
|
||||
@@ -1,44 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0032_provider_service_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Model IDs
|
||||
migrations.AlterField(
|
||||
model_name='circuit',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittype',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='provider',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='providernetwork',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
|
||||
# GFK IDs
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
# Generated by Django 4.0.2 on 2022-02-08 18:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0033_standardize_id_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='circuit',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittermination',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='circuittype',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='provider',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='providernetwork',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.0.3 on 2022-03-30 20:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0057_created_datetimefield'),
|
||||
('circuits', '0034_created_datetimefield'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='provider',
|
||||
name='asns',
|
||||
field=models.ManyToManyField(blank=True, related_name='providers', to='ipam.asn'),
|
||||
),
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
from utilities.json import CustomFieldJSONEncoder
|
||||
from django.db import migrations, models
|
||||
import taggit.managers
|
||||
|
||||
|
||||
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),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='custom_field_data',
|
||||
field=models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
]
|
||||
@@ -1,16 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0036_circuit_termination_date_tags_custom_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0037_new_cabling_models'),
|
||||
('dcim', '0160_populate_cable_ends'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
]
|
||||
@@ -1,46 +1,83 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
from django.db import migrations, models
|
||||
|
||||
import utilities.json
|
||||
|
||||
|
||||
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:
|
||||
provider_accounts.append(ProviderAccount(
|
||||
provider=provider,
|
||||
account=provider.account
|
||||
))
|
||||
ProviderAccount.objects.bulk_create(provider_accounts, batch_size=100)
|
||||
|
||||
|
||||
def restore_providers_from_provideraccounts(apps, schema_editor):
|
||||
"""
|
||||
Restore Provider account values from auto-generated ProviderAccounts
|
||||
"""
|
||||
ProviderAccount = apps.get_model('circuits', '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()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0084_staging'),
|
||||
replaces = [
|
||||
('circuits', '0038_cabling_cleanup'),
|
||||
('circuits', '0039_unique_constraints'),
|
||||
('circuits', '0040_provider_remove_deprecated_fields'),
|
||||
('circuits', '0041_standardize_description_comments'),
|
||||
('circuits', '0042_provideraccount')
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0037_new_cabling_models'),
|
||||
('dcim', '0160_populate_cable_ends'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='circuittermination',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveConstraint(
|
||||
model_name='providernetwork',
|
||||
name='circuits_providernetwork_provider_name',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='circuit',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='circuittermination',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='providernetwork',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='circuit',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'cid'), name='circuits_circuit_unique_provider_cid'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='circuittermination',
|
||||
constraint=models.UniqueConstraint(fields=('circuit', 'term_side'), name='circuits_circuittermination_unique_circuit_term_side'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='providernetwork',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_unique_provider_name'),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='admin_contact',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='asn',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='noc_contact',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='portal_url',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='provider',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProviderAccount',
|
||||
fields=[
|
||||
@@ -67,9 +104,6 @@ class Migration(migrations.Migration):
|
||||
model_name='provideraccount',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'account'), name='circuits_provideraccount_unique_provider_account'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
create_provideraccounts_from_providers, restore_providers_from_provideraccounts
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='account',
|
||||
@@ -77,7 +111,7 @@ class Migration(migrations.Migration):
|
||||
migrations.AddField(
|
||||
model_name='circuit',
|
||||
name='provider_account',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.provideraccount', null=True, blank=True),
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuits', to='circuits.provideraccount'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
@@ -1,39 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0038_cabling_cleanup'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveConstraint(
|
||||
model_name='providernetwork',
|
||||
name='circuits_providernetwork_provider_name',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='circuit',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='circuittermination',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='providernetwork',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='circuit',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'cid'), name='circuits_circuit_unique_provider_cid'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='circuittermination',
|
||||
constraint=models.UniqueConstraint(fields=('circuit', 'term_side'), name='circuits_circuittermination_unique_circuit_term_side'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='providernetwork',
|
||||
constraint=models.UniqueConstraint(fields=('provider', 'name'), name='circuits_providernetwork_unique_provider_name'),
|
||||
),
|
||||
]
|
||||
@@ -1,59 +0,0 @@
|
||||
import os
|
||||
|
||||
from django.db import migrations
|
||||
from django.db.utils import DataError
|
||||
|
||||
|
||||
def check_legacy_data(apps, schema_editor):
|
||||
"""
|
||||
Abort the migration if any legacy provider fields still contain data.
|
||||
"""
|
||||
Provider = apps.get_model('circuits', 'Provider')
|
||||
|
||||
provider_count = Provider.objects.exclude(asn__isnull=True).count()
|
||||
if provider_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
|
||||
raise DataError(
|
||||
f"Unable to proceed with deleting asn field from Provider model: Found {provider_count} "
|
||||
f"providers with legacy ASN data. Please ensure all legacy provider ASN data has been "
|
||||
f"migrated to ASN objects before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA "
|
||||
f"environment variable to bypass this safeguard and delete all legacy provider ASN data."
|
||||
)
|
||||
|
||||
provider_count = Provider.objects.exclude(admin_contact='', noc_contact='', portal_url='').count()
|
||||
if provider_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
|
||||
raise DataError(
|
||||
f"Unable to proceed with deleting contact fields from Provider model: Found {provider_count} "
|
||||
f"providers with legacy contact data. Please ensure all legacy provider contact data has been "
|
||||
f"migrated to contact objects before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA "
|
||||
f"environment variable to bypass this safeguard and delete all legacy provider contact data."
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0039_unique_constraints'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=check_legacy_data,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='admin_contact',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='asn',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='noc_contact',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='provider',
|
||||
name='portal_url',
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-11-03 18:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0040_provider_remove_deprecated_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='provider',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
]
|
||||
@@ -36,7 +36,7 @@ class DataSourceSerializer(NetBoxModelSerializer):
|
||||
model = DataSource
|
||||
fields = [
|
||||
'id', 'url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', 'comments',
|
||||
'parameters', 'ignore_rules', 'created', 'last_updated', 'file_count',
|
||||
'parameters', 'ignore_rules', 'custom_fields', 'created', 'last_updated', 'file_count',
|
||||
]
|
||||
|
||||
|
||||
|
||||
26
netbox/core/constants.py
Normal file
26
netbox/core/constants.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rq.job import JobStatus
|
||||
|
||||
__all__ = (
|
||||
'RQ_TASK_STATUSES',
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Status:
|
||||
label: str
|
||||
color: str
|
||||
|
||||
|
||||
RQ_TASK_STATUSES = {
|
||||
JobStatus.QUEUED: Status(_('Queued'), 'cyan'),
|
||||
JobStatus.FINISHED: Status(_('Finished'), 'green'),
|
||||
JobStatus.FAILED: Status(_('Failed'), 'red'),
|
||||
JobStatus.STARTED: Status(_('Started'), 'blue'),
|
||||
JobStatus.DEFERRED: Status(_('Deferred'), 'gray'),
|
||||
JobStatus.SCHEDULED: Status(_('Scheduled'), 'purple'),
|
||||
JobStatus.STOPPED: Status(_('Stopped'), 'orange'),
|
||||
JobStatus.CANCELED: Status(_('Cancelled'), 'yellow'),
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class DataSourceBulkEditForm(NetBoxModelBulkEditForm):
|
||||
enabled = forms.NullBooleanField(
|
||||
required=False,
|
||||
widget=BulkEditNullBooleanSelect(),
|
||||
label=_('Enforce unique space')
|
||||
label=_('Enabled')
|
||||
)
|
||||
description = forms.CharField(
|
||||
label=_('Description'),
|
||||
|
||||
@@ -11,7 +11,7 @@ from netbox.config import get_config, PARAMS
|
||||
from netbox.forms import NetBoxModelForm
|
||||
from netbox.registry import registry
|
||||
from netbox.utils import get_data_backend_choices
|
||||
from utilities.forms import BootstrapMixin, get_field_value
|
||||
from utilities.forms import get_field_value
|
||||
from utilities.forms.fields import CommentField
|
||||
from utilities.forms.widgets import HTMXSelect
|
||||
|
||||
@@ -138,7 +138,7 @@ class ConfigFormMetaclass(forms.models.ModelFormMetaclass):
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
|
||||
|
||||
class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMetaclass):
|
||||
class ConfigRevisionForm(forms.ModelForm, metaclass=ConfigFormMetaclass):
|
||||
"""
|
||||
Form for creating a new ConfigRevision.
|
||||
"""
|
||||
|
||||
@@ -9,9 +9,9 @@ class Command(_Command):
|
||||
"""
|
||||
This built-in management command enables the creation of new database schema migration files, which should
|
||||
never be required by and ordinary user. We prevent this command from executing unless the configuration
|
||||
indicates that the user is a developer (i.e. configuration.DEVELOPER == True).
|
||||
indicates that the user is a developer (i.e. configuration.DEVELOPER == True), or it was run with --check.
|
||||
"""
|
||||
if not settings.DEVELOPER:
|
||||
if not kwargs['check_changes'] and not settings.DEVELOPER:
|
||||
raise CommandError(
|
||||
"This command is available for development purposes only. It will\n"
|
||||
"NOT resolve any issues with missing or unapplied migrations. For assistance,\n"
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
# Generated by Django 4.1.5 on 2023-02-02 02:37
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
import utilities.json
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
replaces = [
|
||||
('core', '0001_initial'),
|
||||
('core', '0002_managedfile'),
|
||||
('core', '0003_job'),
|
||||
('core', '0004_replicate_jobresults'),
|
||||
('core', '0005_job_created_auto_now')
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('extras', '0084_staging'),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('extras', '0002_squashed_0059'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@@ -71,13 +79,61 @@ class Migration(migrations.Migration):
|
||||
('datafile', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='core.datafile')),
|
||||
('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='contenttypes.contenttype')),
|
||||
],
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='autosyncrecord',
|
||||
index=models.Index(fields=['object_type', 'object_id'], name='core_autosy_object__c17bac_idx'),
|
||||
options={
|
||||
'indexes': [models.Index(fields=['object_type', 'object_id'], name='core_autosy_object__c17bac_idx')],
|
||||
},
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='autosyncrecord',
|
||||
constraint=models.UniqueConstraint(fields=('object_type', 'object_id'), name='core_autosyncrecord_object'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ManagedFile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('data_path', models.CharField(blank=True, editable=False, max_length=1000)),
|
||||
('data_synced', models.DateTimeField(blank=True, editable=False, null=True)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated', models.DateTimeField(blank=True, editable=False, null=True)),
|
||||
('file_root', models.CharField(max_length=1000)),
|
||||
('file_path', models.FilePathField(editable=False)),
|
||||
('data_file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile')),
|
||||
('data_source', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource')),
|
||||
('auto_sync_enabled', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('file_root', 'file_path'),
|
||||
'indexes': [models.Index(fields=['file_root', 'file_path'], name='core_managedfile_root_path')],
|
||||
},
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='managedfile',
|
||||
constraint=models.UniqueConstraint(fields=('file_root', 'file_path'), name='core_managedfile_unique_root_path'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Job',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('object_id', models.PositiveBigIntegerField(blank=True, null=True)),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('created', models.DateTimeField()),
|
||||
('scheduled', models.DateTimeField(blank=True, null=True)),
|
||||
('interval', models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])),
|
||||
('started', models.DateTimeField(blank=True, null=True)),
|
||||
('completed', models.DateTimeField(blank=True, null=True)),
|
||||
('status', models.CharField(default='pending', max_length=30)),
|
||||
('data', models.JSONField(blank=True, null=True)),
|
||||
('job_id', models.UUIDField(unique=True)),
|
||||
('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='contenttypes.contenttype')),
|
||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created'],
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='job',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
]
|
||||
@@ -1,40 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-23 17:35
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ManagedFile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('data_path', models.CharField(blank=True, editable=False, max_length=1000)),
|
||||
('data_synced', models.DateTimeField(blank=True, editable=False, null=True)),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('last_updated', models.DateTimeField(blank=True, editable=False, null=True)),
|
||||
('file_root', models.CharField(max_length=1000)),
|
||||
('file_path', models.FilePathField(editable=False)),
|
||||
('data_file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.datafile')),
|
||||
('data_source', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='core.datasource')),
|
||||
('auto_sync_enabled', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('file_root', 'file_path'),
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='managedfile',
|
||||
index=models.Index(fields=['file_root', 'file_path'], name='core_managedfile_root_path'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='managedfile',
|
||||
constraint=models.UniqueConstraint(fields=('file_root', 'file_path'), name='core_managedfile_unique_root_path'),
|
||||
),
|
||||
]
|
||||
@@ -1,39 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-27 15:02
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('core', '0002_managedfile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Job',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('object_id', models.PositiveBigIntegerField(blank=True, null=True)),
|
||||
('name', models.CharField(max_length=200)),
|
||||
('created', models.DateTimeField()),
|
||||
('scheduled', models.DateTimeField(blank=True, null=True)),
|
||||
('interval', models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])),
|
||||
('started', models.DateTimeField(blank=True, null=True)),
|
||||
('completed', models.DateTimeField(blank=True, null=True)),
|
||||
('status', models.CharField(default='pending', max_length=30)),
|
||||
('data', models.JSONField(blank=True, null=True)),
|
||||
('job_id', models.UUIDField(unique=True)),
|
||||
('object_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobs', to='contenttypes.contenttype')),
|
||||
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['-created'],
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,46 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def replicate_jobresults(apps, schema_editor):
|
||||
"""
|
||||
Replicate existing JobResults to the new Jobs table before deleting the old JobResults table.
|
||||
"""
|
||||
Job = apps.get_model('core', 'Job')
|
||||
JobResult = apps.get_model('extras', 'JobResult')
|
||||
|
||||
jobs = []
|
||||
for job_result in JobResult.objects.order_by('pk').iterator(chunk_size=100):
|
||||
jobs.append(
|
||||
Job(
|
||||
object_type=job_result.obj_type,
|
||||
name=job_result.name,
|
||||
created=job_result.created,
|
||||
scheduled=job_result.scheduled,
|
||||
interval=job_result.interval,
|
||||
started=job_result.started,
|
||||
completed=job_result.completed,
|
||||
user=job_result.user,
|
||||
status=job_result.status,
|
||||
data=job_result.data,
|
||||
job_id=job_result.job_id,
|
||||
)
|
||||
)
|
||||
if len(jobs) == 100:
|
||||
Job.objects.bulk_create(jobs)
|
||||
jobs = []
|
||||
if jobs:
|
||||
Job.objects.bulk_create(jobs)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0003_job'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=replicate_jobresults,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.7 on 2023-03-27 17:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0004_replicate_jobresults'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='job',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
]
|
||||
@@ -14,6 +14,7 @@ from django.utils import timezone
|
||||
from django.utils.module_loading import import_string
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from netbox.constants import CENSOR_TOKEN, CENSOR_TOKEN_CHANGED
|
||||
from netbox.models import PrimaryModel
|
||||
from netbox.models.features import JobsMixin
|
||||
from netbox.registry import registry
|
||||
@@ -130,6 +131,28 @@ class DataSource(JobsMixin, PrimaryModel):
|
||||
'source_url': f"URLs for local sources must start with file:// (or specify no scheme)"
|
||||
})
|
||||
|
||||
def to_objectchange(self, action):
|
||||
objectchange = super().to_objectchange(action)
|
||||
|
||||
# Censor any backend parameters marked as sensitive in the serialized data
|
||||
pre_change_params = {}
|
||||
post_change_params = {}
|
||||
if objectchange.prechange_data:
|
||||
pre_change_params = objectchange.prechange_data.get('parameters') or {} # parameters may be None
|
||||
if objectchange.postchange_data:
|
||||
post_change_params = objectchange.postchange_data.get('parameters') or {}
|
||||
for param in self.backend_class.sensitive_parameters:
|
||||
if post_change_params.get(param):
|
||||
if post_change_params[param] != pre_change_params.get(param):
|
||||
# Set the "changed" token if the parameter's value has been modified
|
||||
post_change_params[param] = CENSOR_TOKEN_CHANGED
|
||||
else:
|
||||
post_change_params[param] = CENSOR_TOKEN
|
||||
if pre_change_params.get(param):
|
||||
pre_change_params[param] = CENSOR_TOKEN
|
||||
|
||||
return objectchange
|
||||
|
||||
def enqueue_sync_job(self, request):
|
||||
"""
|
||||
Enqueue a background job to synchronize the DataSource by calling sync().
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from .config import *
|
||||
from .data import *
|
||||
from .jobs import *
|
||||
from .tasks import *
|
||||
from .plugins import *
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import django_tables2 as tables
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from core.constants import RQ_TASK_STATUSES
|
||||
from netbox.registry import registry
|
||||
|
||||
__all__ = (
|
||||
'BackendTypeColumn',
|
||||
'RQJobStatusColumn',
|
||||
)
|
||||
|
||||
|
||||
@@ -18,3 +21,16 @@ class BackendTypeColumn(tables.Column):
|
||||
|
||||
def value(self, value):
|
||||
return value
|
||||
|
||||
|
||||
class RQJobStatusColumn(tables.Column):
|
||||
"""
|
||||
Render a colored label for the status of an RQ job.
|
||||
"""
|
||||
def render(self, value):
|
||||
status = RQ_TASK_STATUSES.get(value)
|
||||
return mark_safe(f'<span class="badge text-bg-{status.color}">{status.label}</span>')
|
||||
|
||||
def value(self, value):
|
||||
status = RQ_TASK_STATUSES.get(value)
|
||||
return status.label
|
||||
|
||||
39
netbox/core/tables/plugins.py
Normal file
39
netbox/core/tables/plugins.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import django_tables2 as tables
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from netbox.tables import BaseTable
|
||||
|
||||
__all__ = (
|
||||
'PluginTable',
|
||||
)
|
||||
|
||||
|
||||
class PluginTable(BaseTable):
|
||||
name = tables.Column(
|
||||
accessor=tables.A('verbose_name'),
|
||||
verbose_name=_('Name')
|
||||
)
|
||||
version = tables.Column(
|
||||
verbose_name=_('Version')
|
||||
)
|
||||
package = tables.Column(
|
||||
accessor=tables.A('name'),
|
||||
verbose_name=_('Package')
|
||||
)
|
||||
author = tables.Column(
|
||||
verbose_name=_('Author')
|
||||
)
|
||||
author_email = tables.Column(
|
||||
verbose_name=_('Author Email')
|
||||
)
|
||||
description = tables.Column(
|
||||
verbose_name=_('Description')
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
empty_text = _('No plugins found')
|
||||
fields = (
|
||||
'name', 'version', 'package', 'author', 'author_email', 'description',
|
||||
)
|
||||
default_columns = (
|
||||
'name', 'version', 'package', 'author', 'author_email', 'description',
|
||||
)
|
||||
134
netbox/core/tables/tasks.py
Normal file
134
netbox/core/tables/tasks.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import django_tables2 as tables
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_tables2.utils import A
|
||||
|
||||
from core.tables.columns import RQJobStatusColumn
|
||||
from netbox.tables import BaseTable
|
||||
|
||||
|
||||
class BackgroundQueueTable(BaseTable):
|
||||
name = tables.Column(
|
||||
verbose_name=_("Name")
|
||||
)
|
||||
jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "queued"]),
|
||||
verbose_name=_("Queued")
|
||||
)
|
||||
oldest_job_timestamp = tables.Column(
|
||||
verbose_name=_("Oldest Task")
|
||||
)
|
||||
started_jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "started"]),
|
||||
verbose_name=_("Active")
|
||||
)
|
||||
deferred_jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "deferred"]),
|
||||
verbose_name=_("Deferred")
|
||||
)
|
||||
finished_jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "finished"]),
|
||||
verbose_name=_("Finished")
|
||||
)
|
||||
failed_jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "failed"]),
|
||||
verbose_name=_("Failed")
|
||||
)
|
||||
scheduled_jobs = tables.Column(
|
||||
linkify=("core:background_task_list", [A("index"), "scheduled"]),
|
||||
verbose_name=_("Scheduled")
|
||||
)
|
||||
workers = tables.Column(
|
||||
linkify=("core:worker_list", [A("index")]),
|
||||
verbose_name=_("Workers")
|
||||
)
|
||||
host = tables.Column(
|
||||
accessor="connection_kwargs__host",
|
||||
verbose_name=_("Host")
|
||||
)
|
||||
port = tables.Column(
|
||||
accessor="connection_kwargs__port",
|
||||
verbose_name=_("Port")
|
||||
)
|
||||
db = tables.Column(
|
||||
accessor="connection_kwargs__db",
|
||||
verbose_name=_("DB")
|
||||
)
|
||||
pid = tables.Column(
|
||||
accessor="scheduler__pid",
|
||||
verbose_name=_("Scheduler PID")
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
empty_text = _('No queues found')
|
||||
fields = (
|
||||
'name', 'jobs', 'oldest_job_timestamp', 'started_jobs', 'deferred_jobs', 'finished_jobs', 'failed_jobs',
|
||||
'scheduled_jobs', 'workers', 'host', 'port', 'db', 'pid',
|
||||
)
|
||||
default_columns = (
|
||||
'name', 'jobs', 'started_jobs', 'deferred_jobs', 'finished_jobs', 'failed_jobs', 'scheduled_jobs',
|
||||
'workers',
|
||||
)
|
||||
|
||||
|
||||
class BackgroundTaskTable(BaseTable):
|
||||
id = tables.Column(
|
||||
linkify=("core:background_task", [A("id")]),
|
||||
verbose_name=_("ID")
|
||||
)
|
||||
created_at = tables.DateTimeColumn(
|
||||
verbose_name=_("Created")
|
||||
)
|
||||
enqueued_at = tables.DateTimeColumn(
|
||||
verbose_name=_("Enqueued")
|
||||
)
|
||||
ended_at = tables.DateTimeColumn(
|
||||
verbose_name=_("Ended")
|
||||
)
|
||||
status = RQJobStatusColumn(
|
||||
verbose_name=_("Status"),
|
||||
accessor='get_status'
|
||||
)
|
||||
callable = tables.Column(
|
||||
empty_values=(),
|
||||
verbose_name=_("Callable")
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
empty_text = _('No tasks found')
|
||||
fields = (
|
||||
'id', 'created_at', 'enqueued_at', 'ended_at', 'status', 'callable',
|
||||
)
|
||||
default_columns = (
|
||||
'id', 'created_at', 'enqueued_at', 'ended_at', 'status', 'callable',
|
||||
)
|
||||
|
||||
def render_callable(self, value, record):
|
||||
try:
|
||||
return record.func_name
|
||||
except Exception as e:
|
||||
return repr(e)
|
||||
|
||||
|
||||
class WorkerTable(BaseTable):
|
||||
name = tables.Column(
|
||||
linkify=("core:worker", [A("name")]),
|
||||
verbose_name=_("Name")
|
||||
)
|
||||
state = tables.Column(
|
||||
verbose_name=_("State")
|
||||
)
|
||||
birth_date = tables.DateTimeColumn(
|
||||
verbose_name=_("Birth")
|
||||
)
|
||||
pid = tables.Column(
|
||||
verbose_name=_("PID")
|
||||
)
|
||||
|
||||
class Meta(BaseTable.Meta):
|
||||
empty_text = _('No workers found')
|
||||
fields = (
|
||||
'name', 'state', 'birth_date', 'pid',
|
||||
)
|
||||
default_columns = (
|
||||
'name', 'state', 'birth_date', 'pid',
|
||||
)
|
||||
@@ -1,8 +1,6 @@
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from django.test import TestCase
|
||||
from django.utils import timezone
|
||||
|
||||
from utilities.testing import ChangeLoggedFilterSetTests
|
||||
from ..choices import *
|
||||
from ..filtersets import *
|
||||
|
||||
122
netbox/core/tests/test_models.py
Normal file
122
netbox/core/tests/test_models.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from django.test import TestCase
|
||||
|
||||
from core.models import DataSource
|
||||
from extras.choices import ObjectChangeActionChoices
|
||||
from netbox.constants import CENSOR_TOKEN, CENSOR_TOKEN_CHANGED
|
||||
|
||||
|
||||
class DataSourceChangeLoggingTestCase(TestCase):
|
||||
|
||||
def test_password_added_on_create(self):
|
||||
datasource = DataSource.objects.create(
|
||||
name='Data Source 1',
|
||||
type='git',
|
||||
source_url='http://localhost/',
|
||||
parameters={
|
||||
'username': 'jeff',
|
||||
'password': 'foobar123',
|
||||
}
|
||||
)
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_CREATE)
|
||||
self.assertIsNone(objectchange.prechange_data)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], CENSOR_TOKEN_CHANGED)
|
||||
|
||||
def test_password_added_on_update(self):
|
||||
datasource = DataSource.objects.create(
|
||||
name='Data Source 1',
|
||||
type='git',
|
||||
source_url='http://localhost/'
|
||||
)
|
||||
datasource.snapshot()
|
||||
|
||||
# Add a blank password
|
||||
datasource.parameters = {
|
||||
'username': 'jeff',
|
||||
'password': '',
|
||||
}
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertIsNone(objectchange.prechange_data['parameters'])
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], '')
|
||||
|
||||
# Add a password
|
||||
datasource.parameters = {
|
||||
'username': 'jeff',
|
||||
'password': 'foobar123',
|
||||
}
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], CENSOR_TOKEN_CHANGED)
|
||||
|
||||
def test_password_changed(self):
|
||||
datasource = DataSource.objects.create(
|
||||
name='Data Source 1',
|
||||
type='git',
|
||||
source_url='http://localhost/',
|
||||
parameters={
|
||||
'username': 'jeff',
|
||||
'password': 'password1',
|
||||
}
|
||||
)
|
||||
datasource.snapshot()
|
||||
|
||||
# Change the password
|
||||
datasource.parameters['password'] = 'password2'
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], CENSOR_TOKEN_CHANGED)
|
||||
|
||||
def test_password_removed_on_update(self):
|
||||
datasource = DataSource.objects.create(
|
||||
name='Data Source 1',
|
||||
type='git',
|
||||
source_url='http://localhost/',
|
||||
parameters={
|
||||
'username': 'jeff',
|
||||
'password': 'foobar123',
|
||||
}
|
||||
)
|
||||
datasource.snapshot()
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
|
||||
# Remove the password
|
||||
datasource.parameters['password'] = ''
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'jeff')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], '')
|
||||
|
||||
def test_password_not_modified(self):
|
||||
datasource = DataSource.objects.create(
|
||||
name='Data Source 1',
|
||||
type='git',
|
||||
source_url='http://localhost/',
|
||||
parameters={
|
||||
'username': 'username1',
|
||||
'password': 'foobar123',
|
||||
}
|
||||
)
|
||||
datasource.snapshot()
|
||||
|
||||
# Remove the password
|
||||
datasource.parameters['username'] = 'username2'
|
||||
|
||||
objectchange = datasource.to_objectchange(ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['username'], 'username1')
|
||||
self.assertEqual(objectchange.prechange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['username'], 'username2')
|
||||
self.assertEqual(objectchange.postchange_data['parameters']['password'], CENSOR_TOKEN)
|
||||
@@ -1,6 +1,16 @@
|
||||
from django.utils import timezone
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from utilities.testing import ViewTestCases, create_tags
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django_rq import get_queue
|
||||
from django_rq.settings import QUEUES_MAP
|
||||
from django_rq.workers import get_worker
|
||||
from rq.job import Job as RQ_Job, JobStatus
|
||||
from rq.registry import DeferredJobRegistry, FailedJobRegistry, FinishedJobRegistry, StartedJobRegistry
|
||||
|
||||
from utilities.testing import TestCase, ViewTestCases, create_tags
|
||||
from ..models import *
|
||||
|
||||
|
||||
@@ -87,3 +97,211 @@ class DataFileTestCase(
|
||||
),
|
||||
)
|
||||
DataFile.objects.bulk_create(data_files)
|
||||
|
||||
|
||||
class BackgroundTaskTestCase(TestCase):
|
||||
user_permissions = ()
|
||||
|
||||
# Dummy worker functions
|
||||
@staticmethod
|
||||
def dummy_job_default():
|
||||
return "Job finished"
|
||||
|
||||
@staticmethod
|
||||
def dummy_job_high():
|
||||
return "Job finished"
|
||||
|
||||
@staticmethod
|
||||
def dummy_job_failing():
|
||||
raise Exception("Job failed")
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user.is_staff = True
|
||||
self.user.is_active = True
|
||||
self.user.save()
|
||||
|
||||
# Clear all queues prior to running each test
|
||||
get_queue('default').connection.flushall()
|
||||
get_queue('high').connection.flushall()
|
||||
get_queue('low').connection.flushall()
|
||||
|
||||
def test_background_queue_list(self):
|
||||
url = reverse('core:background_queue_list')
|
||||
|
||||
# Attempt to load view without permission
|
||||
self.user.is_staff = False
|
||||
self.user.save()
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
# Load view with permission
|
||||
self.user.is_staff = True
|
||||
self.user.save()
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('default', str(response.content))
|
||||
self.assertIn('high', str(response.content))
|
||||
self.assertIn('low', str(response.content))
|
||||
|
||||
def test_background_tasks_list_default(self):
|
||||
queue = get_queue('default')
|
||||
queue.enqueue(self.dummy_job_default)
|
||||
queue_index = QUEUES_MAP['default']
|
||||
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'queued']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content))
|
||||
|
||||
def test_background_tasks_list_high(self):
|
||||
queue = get_queue('high')
|
||||
queue.enqueue(self.dummy_job_high)
|
||||
queue_index = QUEUES_MAP['high']
|
||||
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'queued']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_high', str(response.content))
|
||||
|
||||
def test_background_tasks_list_finished(self):
|
||||
queue = get_queue('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
queue_index = QUEUES_MAP['default']
|
||||
|
||||
registry = FinishedJobRegistry(queue.name, queue.connection)
|
||||
registry.add(job, 2)
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'finished']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content))
|
||||
|
||||
def test_background_tasks_list_failed(self):
|
||||
queue = get_queue('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
queue_index = QUEUES_MAP['default']
|
||||
|
||||
registry = FailedJobRegistry(queue.name, queue.connection)
|
||||
registry.add(job, 2)
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'failed']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content))
|
||||
|
||||
def test_background_tasks_scheduled(self):
|
||||
queue = get_queue('default')
|
||||
queue.enqueue_at(datetime.now(), self.dummy_job_default)
|
||||
queue_index = QUEUES_MAP['default']
|
||||
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'scheduled']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content))
|
||||
|
||||
def test_background_tasks_list_deferred(self):
|
||||
queue = get_queue('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
queue_index = QUEUES_MAP['default']
|
||||
|
||||
registry = DeferredJobRegistry(queue.name, queue.connection)
|
||||
registry.add(job, 2)
|
||||
response = self.client.get(reverse('core:background_task_list', args=[queue_index, 'deferred']))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('BackgroundTaskTestCase.dummy_job_default', str(response.content))
|
||||
|
||||
def test_background_task(self):
|
||||
queue = get_queue('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
|
||||
response = self.client.get(reverse('core:background_task', args=[job.id]))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn('Background Tasks', str(response.content))
|
||||
self.assertIn(str(job.id), str(response.content))
|
||||
self.assertIn('Callable', str(response.content))
|
||||
self.assertIn('Meta', str(response.content))
|
||||
self.assertIn('Keyword Arguments', str(response.content))
|
||||
|
||||
def test_background_task_delete(self):
|
||||
queue = get_queue('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
|
||||
response = self.client.post(reverse('core:background_task_delete', args=[job.id]), {'confirm': True})
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertFalse(RQ_Job.exists(job.id, connection=queue.connection))
|
||||
self.assertNotIn(job.id, queue.job_ids)
|
||||
|
||||
def test_background_task_requeue(self):
|
||||
queue = get_queue('default')
|
||||
|
||||
# Enqueue & run a job that will fail
|
||||
job = queue.enqueue(self.dummy_job_failing)
|
||||
worker = get_worker('default')
|
||||
worker.work(burst=True)
|
||||
self.assertTrue(job.is_failed)
|
||||
|
||||
# Re-enqueue the failed job and check that its status has been reset
|
||||
response = self.client.get(reverse('core:background_task_requeue', args=[job.id]))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertFalse(job.is_failed)
|
||||
|
||||
def test_background_task_enqueue(self):
|
||||
queue = get_queue('default')
|
||||
|
||||
# Enqueue some jobs that each depends on its predecessor
|
||||
job = previous_job = None
|
||||
for _ in range(0, 3):
|
||||
job = queue.enqueue(self.dummy_job_default, depends_on=previous_job)
|
||||
previous_job = job
|
||||
|
||||
# Check that the last job to be enqueued has a status of deferred
|
||||
self.assertIsNotNone(job)
|
||||
self.assertEqual(job.get_status(), JobStatus.DEFERRED)
|
||||
self.assertIsNone(job.enqueued_at)
|
||||
|
||||
# Force-enqueue the deferred job
|
||||
response = self.client.get(reverse('core:background_task_enqueue', args=[job.id]))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
# Check that job's status is updated correctly
|
||||
job = queue.fetch_job(job.id)
|
||||
self.assertEqual(job.get_status(), JobStatus.QUEUED)
|
||||
self.assertIsNotNone(job.enqueued_at)
|
||||
|
||||
def test_background_task_stop(self):
|
||||
queue = get_queue('default')
|
||||
|
||||
worker = get_worker('default')
|
||||
job = queue.enqueue(self.dummy_job_default)
|
||||
worker.prepare_job_execution(job)
|
||||
|
||||
self.assertEqual(job.get_status(), JobStatus.STARTED)
|
||||
|
||||
# Stop those jobs using the view
|
||||
started_job_registry = StartedJobRegistry(queue.name, connection=queue.connection)
|
||||
self.assertEqual(len(started_job_registry), 1)
|
||||
response = self.client.get(reverse('core:background_task_stop', args=[job.id]))
|
||||
self.assertEqual(response.status_code, 302)
|
||||
worker.monitor_work_horse(job, queue) # Sets the job as Failed and removes from Started
|
||||
self.assertEqual(len(started_job_registry), 0)
|
||||
|
||||
canceled_job_registry = FailedJobRegistry(queue.name, connection=queue.connection)
|
||||
self.assertEqual(len(canceled_job_registry), 1)
|
||||
self.assertIn(job.id, canceled_job_registry)
|
||||
|
||||
def test_worker_list(self):
|
||||
worker1 = get_worker('default', name=uuid.uuid4().hex)
|
||||
worker1.register_birth()
|
||||
|
||||
worker2 = get_worker('high')
|
||||
worker2.register_birth()
|
||||
|
||||
queue_index = QUEUES_MAP['default']
|
||||
response = self.client.get(reverse('core:worker_list', args=[queue_index]))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(str(worker1.name), str(response.content))
|
||||
self.assertNotIn(str(worker2.name), str(response.content))
|
||||
|
||||
def test_worker(self):
|
||||
worker1 = get_worker('default', name=uuid.uuid4().hex)
|
||||
worker1.register_birth()
|
||||
|
||||
response = self.client.get(reverse('core:worker', args=[worker1.name]))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(str(worker1.name), str(response.content))
|
||||
self.assertIn('Birth', str(response.content))
|
||||
self.assertIn('Total working time', str(response.content))
|
||||
|
||||
@@ -25,6 +25,17 @@ urlpatterns = (
|
||||
path('jobs/<int:pk>/', views.JobView.as_view(), name='job'),
|
||||
path('jobs/<int:pk>/delete/', views.JobDeleteView.as_view(), name='job_delete'),
|
||||
|
||||
# Background Tasks
|
||||
path('background-queues/', views.BackgroundQueueListView.as_view(), name='background_queue_list'),
|
||||
path('background-queues/<int:queue_index>/<str:status>/', views.BackgroundTaskListView.as_view(), name='background_task_list'),
|
||||
path('background-tasks/<str:job_id>/', views.BackgroundTaskView.as_view(), name='background_task'),
|
||||
path('background-tasks/<str:job_id>/delete/', views.BackgroundTaskDeleteView.as_view(), name='background_task_delete'),
|
||||
path('background-tasks/<str:job_id>/requeue/', views.BackgroundTaskRequeueView.as_view(), name='background_task_requeue'),
|
||||
path('background-tasks/<str:job_id>/enqueue/', views.BackgroundTaskEnqueueView.as_view(), name='background_task_enqueue'),
|
||||
path('background-tasks/<str:job_id>/stop/', views.BackgroundTaskStopView.as_view(), name='background_task_stop'),
|
||||
path('background-workers/<int:queue_index>/', views.WorkerListView.as_view(), name='worker_list'),
|
||||
path('background-workers/<str:key>/', views.WorkerView.as_view(), name='worker'),
|
||||
|
||||
# Config revisions
|
||||
path('config-revisions/', views.ConfigRevisionListView.as_view(), name='configrevision_list'),
|
||||
path('config-revisions/add/', views.ConfigRevisionEditView.as_view(), name='configrevision_add'),
|
||||
@@ -35,4 +46,6 @@ urlpatterns = (
|
||||
# Configuration
|
||||
path('config/', views.ConfigView.as_view(), name='config'),
|
||||
|
||||
# Plugins
|
||||
path('plugins/', views.PluginListView.as_view(), name='plugin_list'),
|
||||
)
|
||||
|
||||
@@ -1,12 +1,30 @@
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.http import HttpResponseForbidden, Http404
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import View
|
||||
from django_rq.queues import get_queue_by_index, get_redis_connection
|
||||
from django_rq.settings import QUEUES_MAP, QUEUES_LIST
|
||||
from django_rq.utils import get_jobs, get_statistics, stop_jobs
|
||||
from rq import requeue_job
|
||||
from rq.exceptions import NoSuchJobError
|
||||
from rq.job import Job as RQ_Job, JobStatus as RQJobStatus
|
||||
from rq.registry import (
|
||||
DeferredJobRegistry, FailedJobRegistry, FinishedJobRegistry, ScheduledJobRegistry, StartedJobRegistry,
|
||||
)
|
||||
from rq.worker import Worker
|
||||
from rq.worker_registration import clean_worker_registry
|
||||
|
||||
from netbox.config import get_config, PARAMS
|
||||
from netbox.views import generic
|
||||
from netbox.views.generic.base import BaseObjectView
|
||||
from netbox.views.generic.mixins import TableMixin
|
||||
from utilities.forms import ConfirmationForm
|
||||
from utilities.utils import count_related
|
||||
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
|
||||
from . import filtersets, forms, tables
|
||||
@@ -232,3 +250,297 @@ class ConfigRevisionRestoreView(ContentTypePermissionRequiredMixin, View):
|
||||
messages.success(request, f"Restored configuration revision #{pk}")
|
||||
|
||||
return redirect(candidate_config.get_absolute_url())
|
||||
|
||||
|
||||
#
|
||||
# Background Tasks (RQ)
|
||||
#
|
||||
|
||||
class BaseRQView(UserPassesTestMixin, View):
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_staff
|
||||
|
||||
|
||||
class BackgroundQueueListView(TableMixin, BaseRQView):
|
||||
table = tables.BackgroundQueueTable
|
||||
|
||||
def get(self, request):
|
||||
data = get_statistics(run_maintenance_tasks=True)["queues"]
|
||||
table = self.get_table(data, request, bulk_actions=False)
|
||||
|
||||
return render(request, 'core/rq_queue_list.html', {
|
||||
'table': table,
|
||||
})
|
||||
|
||||
|
||||
class BackgroundTaskListView(TableMixin, BaseRQView):
|
||||
table = tables.BackgroundTaskTable
|
||||
|
||||
def get_table_data(self, request, queue, status):
|
||||
jobs = []
|
||||
|
||||
# Call get_jobs() to returned queued tasks
|
||||
if status == RQJobStatus.QUEUED:
|
||||
return queue.get_jobs()
|
||||
|
||||
# For other statuses, determine the registry to list (or raise a 404 for invalid statuses)
|
||||
try:
|
||||
registry_cls = {
|
||||
RQJobStatus.STARTED: StartedJobRegistry,
|
||||
RQJobStatus.DEFERRED: DeferredJobRegistry,
|
||||
RQJobStatus.FINISHED: FinishedJobRegistry,
|
||||
RQJobStatus.FAILED: FailedJobRegistry,
|
||||
RQJobStatus.SCHEDULED: ScheduledJobRegistry,
|
||||
}[status]
|
||||
except KeyError:
|
||||
raise Http404
|
||||
registry = registry_cls(queue.name, queue.connection)
|
||||
|
||||
job_ids = registry.get_job_ids()
|
||||
if status != RQJobStatus.DEFERRED:
|
||||
jobs = get_jobs(queue, job_ids, registry)
|
||||
else:
|
||||
# Deferred jobs require special handling
|
||||
for job_id in job_ids:
|
||||
try:
|
||||
jobs.append(RQ_Job.fetch(job_id, connection=queue.connection, serializer=queue.serializer))
|
||||
except NoSuchJobError:
|
||||
pass
|
||||
|
||||
if jobs and status == RQJobStatus.SCHEDULED:
|
||||
for job in jobs:
|
||||
job.scheduled_at = registry.get_scheduled_time(job)
|
||||
|
||||
return jobs
|
||||
|
||||
def get(self, request, queue_index, status):
|
||||
queue = get_queue_by_index(queue_index)
|
||||
data = self.get_table_data(request, queue, status)
|
||||
table = self.get_table(data, request, False)
|
||||
|
||||
# If this is an HTMX request, return only the rendered table HTML
|
||||
if request.htmx:
|
||||
return render(request, 'htmx/table.html', {
|
||||
'table': table,
|
||||
})
|
||||
|
||||
return render(request, 'core/rq_task_list.html', {
|
||||
'table': table,
|
||||
'queue': queue,
|
||||
'status': status,
|
||||
})
|
||||
|
||||
|
||||
class BackgroundTaskView(BaseRQView):
|
||||
|
||||
def get(self, request, job_id):
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
try:
|
||||
job = RQ_Job.fetch(job_id, connection=get_redis_connection(config['connection_config']),)
|
||||
except NoSuchJobError:
|
||||
raise Http404(_("Job {job_id} not found").format(job_id=job_id))
|
||||
|
||||
queue_index = QUEUES_MAP[job.origin]
|
||||
queue = get_queue_by_index(queue_index)
|
||||
|
||||
try:
|
||||
exc_info = job._exc_info
|
||||
except AttributeError:
|
||||
exc_info = None
|
||||
|
||||
return render(request, 'core/rq_task.html', {
|
||||
'queue': queue,
|
||||
'job': job,
|
||||
'queue_index': queue_index,
|
||||
'dependency_id': job._dependency_id,
|
||||
'exc_info': exc_info,
|
||||
})
|
||||
|
||||
|
||||
class BackgroundTaskDeleteView(BaseRQView):
|
||||
|
||||
def get(self, request, job_id):
|
||||
if not request.htmx:
|
||||
return redirect(reverse('core:background_queue_list'))
|
||||
|
||||
form = ConfirmationForm(initial=request.GET)
|
||||
|
||||
return render(request, 'htmx/delete_form.html', {
|
||||
'object_type': 'background task',
|
||||
'object': job_id,
|
||||
'form': form,
|
||||
'form_url': reverse('core:background_task_delete', kwargs={'job_id': job_id})
|
||||
})
|
||||
|
||||
def post(self, request, job_id):
|
||||
form = ConfirmationForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
try:
|
||||
job = RQ_Job.fetch(job_id, connection=get_redis_connection(config['connection_config']),)
|
||||
except NoSuchJobError:
|
||||
raise Http404(_("Job {job_id} not found").format(job_id=job_id))
|
||||
|
||||
queue_index = QUEUES_MAP[job.origin]
|
||||
queue = get_queue_by_index(queue_index)
|
||||
|
||||
# Remove job id from queue and delete the actual job
|
||||
queue.connection.lrem(queue.key, 0, job.id)
|
||||
job.delete()
|
||||
messages.success(request, f'Deleted job {job_id}')
|
||||
else:
|
||||
messages.error(request, f'Error deleting job: {form.errors[0]}')
|
||||
|
||||
return redirect(reverse('core:background_queue_list'))
|
||||
|
||||
|
||||
class BackgroundTaskRequeueView(BaseRQView):
|
||||
|
||||
def get(self, request, job_id):
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
try:
|
||||
job = RQ_Job.fetch(job_id, connection=get_redis_connection(config['connection_config']),)
|
||||
except NoSuchJobError:
|
||||
raise Http404(_("Job {job_id} not found").format(job_id=job_id))
|
||||
|
||||
queue_index = QUEUES_MAP[job.origin]
|
||||
queue = get_queue_by_index(queue_index)
|
||||
|
||||
requeue_job(job_id, connection=queue.connection, serializer=queue.serializer)
|
||||
messages.success(request, f'You have successfully requeued: {job_id}')
|
||||
return redirect(reverse('core:background_task', args=[job_id]))
|
||||
|
||||
|
||||
class BackgroundTaskEnqueueView(BaseRQView):
|
||||
|
||||
def get(self, request, job_id):
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
try:
|
||||
job = RQ_Job.fetch(job_id, connection=get_redis_connection(config['connection_config']),)
|
||||
except NoSuchJobError:
|
||||
raise Http404(_("Job {job_id} not found").format(job_id=job_id))
|
||||
|
||||
queue_index = QUEUES_MAP[job.origin]
|
||||
queue = get_queue_by_index(queue_index)
|
||||
|
||||
try:
|
||||
# _enqueue_job is new in RQ 1.14, this is used to enqueue
|
||||
# job regardless of its dependencies
|
||||
queue._enqueue_job(job)
|
||||
except AttributeError:
|
||||
queue.enqueue_job(job)
|
||||
|
||||
# Remove job from correct registry if needed
|
||||
if job.get_status() == RQJobStatus.DEFERRED:
|
||||
registry = DeferredJobRegistry(queue.name, queue.connection)
|
||||
registry.remove(job)
|
||||
elif job.get_status() == RQJobStatus.FINISHED:
|
||||
registry = FinishedJobRegistry(queue.name, queue.connection)
|
||||
registry.remove(job)
|
||||
elif job.get_status() == RQJobStatus.SCHEDULED:
|
||||
registry = ScheduledJobRegistry(queue.name, queue.connection)
|
||||
registry.remove(job)
|
||||
|
||||
messages.success(request, f'You have successfully enqueued: {job_id}')
|
||||
return redirect(reverse('core:background_task', args=[job_id]))
|
||||
|
||||
|
||||
class BackgroundTaskStopView(BaseRQView):
|
||||
|
||||
def get(self, request, job_id):
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
try:
|
||||
job = RQ_Job.fetch(job_id, connection=get_redis_connection(config['connection_config']),)
|
||||
except NoSuchJobError:
|
||||
raise Http404(_("Job {job_id} not found").format(job_id=job_id))
|
||||
|
||||
queue_index = QUEUES_MAP[job.origin]
|
||||
queue = get_queue_by_index(queue_index)
|
||||
|
||||
stopped, _ = stop_jobs(queue, job_id)
|
||||
if len(stopped) == 1:
|
||||
messages.success(request, f'You have successfully stopped {job_id}')
|
||||
else:
|
||||
messages.error(request, f'Failed to stop {job_id}')
|
||||
|
||||
return redirect(reverse('core:background_task', args=[job_id]))
|
||||
|
||||
|
||||
class WorkerListView(TableMixin, BaseRQView):
|
||||
table = tables.WorkerTable
|
||||
|
||||
def get_table_data(self, request, queue):
|
||||
clean_worker_registry(queue)
|
||||
all_workers = Worker.all(queue.connection)
|
||||
workers = [worker for worker in all_workers if queue.name in worker.queue_names()]
|
||||
return workers
|
||||
|
||||
def get(self, request, queue_index):
|
||||
queue = get_queue_by_index(queue_index)
|
||||
data = self.get_table_data(request, queue)
|
||||
|
||||
table = self.get_table(data, request, False)
|
||||
|
||||
# If this is an HTMX request, return only the rendered table HTML
|
||||
if request.htmx:
|
||||
if request.htmx.target != 'object_list':
|
||||
table.embedded = True
|
||||
# Hide selection checkboxes
|
||||
if 'pk' in table.base_columns:
|
||||
table.columns.hide('pk')
|
||||
return render(request, 'htmx/table.html', {
|
||||
'table': table,
|
||||
'queue': queue,
|
||||
})
|
||||
|
||||
return render(request, 'core/rq_worker_list.html', {
|
||||
'table': table,
|
||||
'queue': queue,
|
||||
})
|
||||
|
||||
|
||||
class WorkerView(BaseRQView):
|
||||
|
||||
def get(self, request, key):
|
||||
# all the RQ queues should use the same connection
|
||||
config = QUEUES_LIST[0]
|
||||
worker = Worker.find_by_key('rq:worker:' + key, connection=get_redis_connection(config['connection_config']))
|
||||
# Convert microseconds to milliseconds
|
||||
worker.total_working_time = worker.total_working_time / 1000
|
||||
|
||||
return render(request, 'core/rq_worker.html', {
|
||||
'worker': worker,
|
||||
'job': worker.get_current_job(),
|
||||
'total_working_time': worker.total_working_time * 1000,
|
||||
})
|
||||
|
||||
|
||||
#
|
||||
# Plugins
|
||||
#
|
||||
|
||||
class PluginListView(UserPassesTestMixin, View):
|
||||
|
||||
def test_func(self):
|
||||
return self.request.user.is_staff
|
||||
|
||||
def get(self, request):
|
||||
plugins = [
|
||||
# Look up app config by package name
|
||||
apps.get_app_config(plugin.rsplit('.', 1)[-1]) for plugin in settings.PLUGINS
|
||||
]
|
||||
table = tables.PluginTable(plugins, user=request.user)
|
||||
table.configure(request)
|
||||
|
||||
return render(request, 'core/plugin_list.html', {
|
||||
'plugins': plugins,
|
||||
'active_tab': 'api-tokens',
|
||||
'table': table,
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.utils.translation import gettext_lazy as _
|
||||
from dcim.models import *
|
||||
from extras.models import Tag
|
||||
from netbox.forms.mixins import CustomFieldsMixin
|
||||
from utilities.forms import BootstrapMixin, form_from_model
|
||||
from utilities.forms import form_from_model
|
||||
from utilities.forms.fields import DynamicModelMultipleChoiceField, ExpandableNameField
|
||||
from .object_create import ComponentCreateForm
|
||||
|
||||
@@ -26,7 +26,7 @@ __all__ = (
|
||||
# Device components
|
||||
#
|
||||
|
||||
class DeviceBulkAddComponentForm(BootstrapMixin, CustomFieldsMixin, ComponentCreateForm):
|
||||
class DeviceBulkAddComponentForm(CustomFieldsMixin, ComponentCreateForm):
|
||||
pk = forms.ModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
widget=forms.MultipleHiddenInput()
|
||||
|
||||
@@ -727,7 +727,7 @@ class PowerOutletImportForm(NetBoxModelImportForm):
|
||||
help_text=_('Local power port which feeds this outlet')
|
||||
)
|
||||
feed_leg = CSVChoiceField(
|
||||
label=_('Feed lag'),
|
||||
label=_('Feed leg'),
|
||||
choices=PowerOutletFeedLegChoices,
|
||||
required=False,
|
||||
help_text=_('Electrical phase (for three-phase circuits)')
|
||||
@@ -1359,6 +1359,10 @@ class VirtualDeviceContextImportForm(NetBoxModelImportForm):
|
||||
to_field_name='name',
|
||||
help_text='Assigned tenant'
|
||||
)
|
||||
status = CSVChoiceField(
|
||||
label=_('Status'),
|
||||
choices=VirtualDeviceContextStatusChoices,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = [
|
||||
|
||||
@@ -11,7 +11,7 @@ from extras.models import ConfigTemplate
|
||||
from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF
|
||||
from netbox.forms import NetBoxModelForm
|
||||
from tenancy.forms import TenancyForm
|
||||
from utilities.forms import BootstrapMixin, add_blank_choice
|
||||
from utilities.forms import add_blank_choice
|
||||
from utilities.forms.fields import (
|
||||
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField,
|
||||
NumericArrayField, SlugField,
|
||||
@@ -748,7 +748,7 @@ class DeviceVCMembershipForm(forms.ModelForm):
|
||||
return vc_position
|
||||
|
||||
|
||||
class VCMemberSelectForm(BootstrapMixin, forms.Form):
|
||||
class VCMemberSelectForm(forms.Form):
|
||||
device = DynamicModelChoiceField(
|
||||
label=_('Device'),
|
||||
queryset=Device.objects.all(),
|
||||
@@ -771,7 +771,7 @@ class VCMemberSelectForm(BootstrapMixin, forms.Form):
|
||||
# Device component templates
|
||||
#
|
||||
|
||||
class ComponentTemplateForm(BootstrapMixin, forms.ModelForm):
|
||||
class ComponentTemplateForm(forms.ModelForm):
|
||||
device_type = DynamicModelChoiceField(
|
||||
label=_('Device type'),
|
||||
queryset=DeviceType.objects.all()
|
||||
@@ -1272,7 +1272,7 @@ class DeviceBayForm(DeviceComponentForm):
|
||||
]
|
||||
|
||||
|
||||
class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
|
||||
class PopulateDeviceBayForm(forms.Form):
|
||||
installed_device = forms.ModelChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
label=_('Child Device'),
|
||||
|
||||
@@ -3,7 +3,6 @@ from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices
|
||||
from dcim.models import *
|
||||
from utilities.forms import BootstrapMixin
|
||||
from wireless.choices import WirelessRoleChoices
|
||||
|
||||
__all__ = (
|
||||
@@ -24,11 +23,7 @@ __all__ = (
|
||||
# Component template import forms
|
||||
#
|
||||
|
||||
class ComponentTemplateImportForm(BootstrapMixin, forms.ModelForm):
|
||||
pass
|
||||
|
||||
|
||||
class ConsolePortTemplateImportForm(ComponentTemplateImportForm):
|
||||
class ConsolePortTemplateImportForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ConsolePortTemplate
|
||||
@@ -37,7 +32,7 @@ class ConsolePortTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class ConsoleServerPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
class ConsoleServerPortTemplateImportForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ConsoleServerPortTemplate
|
||||
@@ -46,7 +41,7 @@ class ConsoleServerPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class PowerPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
class PowerPortTemplateImportForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = PowerPortTemplate
|
||||
@@ -55,7 +50,7 @@ class PowerPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class PowerOutletTemplateImportForm(ComponentTemplateImportForm):
|
||||
class PowerOutletTemplateImportForm(forms.ModelForm):
|
||||
power_port = forms.ModelChoiceField(
|
||||
label=_('Power port'),
|
||||
queryset=PowerPortTemplate.objects.all(),
|
||||
@@ -84,7 +79,7 @@ class PowerOutletTemplateImportForm(ComponentTemplateImportForm):
|
||||
return module_type
|
||||
|
||||
|
||||
class InterfaceTemplateImportForm(ComponentTemplateImportForm):
|
||||
class InterfaceTemplateImportForm(forms.ModelForm):
|
||||
type = forms.ChoiceField(
|
||||
label=_('Type'),
|
||||
choices=InterfaceTypeChoices.CHOICES
|
||||
@@ -113,7 +108,7 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class FrontPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
class FrontPortTemplateImportForm(forms.ModelForm):
|
||||
type = forms.ChoiceField(
|
||||
label=_('Type'),
|
||||
choices=PortTypeChoices.CHOICES
|
||||
@@ -145,7 +140,7 @@ class FrontPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class RearPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
class RearPortTemplateImportForm(forms.ModelForm):
|
||||
type = forms.ChoiceField(
|
||||
label=_('Type'),
|
||||
choices=PortTypeChoices.CHOICES
|
||||
@@ -158,7 +153,7 @@ class RearPortTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class ModuleBayTemplateImportForm(ComponentTemplateImportForm):
|
||||
class ModuleBayTemplateImportForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ModuleBayTemplate
|
||||
@@ -167,7 +162,7 @@ class ModuleBayTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class DeviceBayTemplateImportForm(ComponentTemplateImportForm):
|
||||
class DeviceBayTemplateImportForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = DeviceBayTemplate
|
||||
@@ -176,7 +171,7 @@ class DeviceBayTemplateImportForm(ComponentTemplateImportForm):
|
||||
]
|
||||
|
||||
|
||||
class InventoryItemTemplateImportForm(ComponentTemplateImportForm):
|
||||
class InventoryItemTemplateImportForm(forms.ModelForm):
|
||||
parent = forms.ModelChoiceField(
|
||||
label=_('Parent'),
|
||||
queryset=InventoryItemTemplate.objects.all(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import graphene
|
||||
from circuits.graphql.types import CircuitTerminationType
|
||||
from circuits.models import CircuitTermination
|
||||
from circuits.graphql.types import CircuitTerminationType, ProviderNetworkType
|
||||
from circuits.models import CircuitTermination, ProviderNetwork
|
||||
from dcim.graphql.types import (
|
||||
ConsolePortTemplateType,
|
||||
ConsolePortType,
|
||||
@@ -167,3 +167,42 @@ class InventoryItemComponentType(graphene.Union):
|
||||
return PowerPortType
|
||||
if type(instance) is RearPort:
|
||||
return RearPortType
|
||||
|
||||
|
||||
class ConnectedEndpointType(graphene.Union):
|
||||
class Meta:
|
||||
types = (
|
||||
CircuitTerminationType,
|
||||
ConsolePortType,
|
||||
ConsoleServerPortType,
|
||||
FrontPortType,
|
||||
InterfaceType,
|
||||
PowerFeedType,
|
||||
PowerOutletType,
|
||||
PowerPortType,
|
||||
ProviderNetworkType,
|
||||
RearPortType,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def resolve_type(cls, instance, info):
|
||||
if type(instance) is CircuitTermination:
|
||||
return CircuitTerminationType
|
||||
if type(instance) is ConsolePortType:
|
||||
return ConsolePortType
|
||||
if type(instance) is ConsoleServerPort:
|
||||
return ConsoleServerPortType
|
||||
if type(instance) is FrontPort:
|
||||
return FrontPortType
|
||||
if type(instance) is Interface:
|
||||
return InterfaceType
|
||||
if type(instance) is PowerFeed:
|
||||
return PowerFeedType
|
||||
if type(instance) is PowerOutlet:
|
||||
return PowerOutletType
|
||||
if type(instance) is PowerPort:
|
||||
return PowerPortType
|
||||
if type(instance) is ProviderNetwork:
|
||||
return ProviderNetworkType
|
||||
if type(instance) is RearPort:
|
||||
return RearPortType
|
||||
|
||||
@@ -13,7 +13,7 @@ class CabledObjectMixin:
|
||||
|
||||
|
||||
class PathEndpointMixin:
|
||||
connected_endpoints = graphene.List('dcim.graphql.gfk_mixins.LinkPeerType')
|
||||
connected_endpoints = graphene.List('dcim.graphql.gfk_mixins.ConnectedEndpointType')
|
||||
|
||||
def resolve_connected_endpoints(self, info):
|
||||
# Handle empty values
|
||||
|
||||
@@ -34,7 +34,7 @@ class Command(BaseCommand):
|
||||
Draw a simple progress bar 20 increments wide illustrating the specified percentage.
|
||||
"""
|
||||
bar_size = int(percentage / 5)
|
||||
self.stdout.write(f"\r [{'#' * bar_size}{' ' * (20-bar_size)}] {int(percentage)}%", ending='')
|
||||
self.stdout.write(f"\r [{'#' * bar_size}{' ' * (20 - bar_size)}] {int(percentage)}%", ending='')
|
||||
|
||||
def handle(self, *model_names, **options):
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0130_sitegroup'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='consoleport',
|
||||
name='speed',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverport',
|
||||
name='speed',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
1194
netbox/dcim/migrations/0131_squashed_0159.py
Normal file
1194
netbox/dcim/migrations/0131_squashed_0159.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0131_consoleport_speed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='length',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,32 +0,0 @@
|
||||
from django.db import migrations
|
||||
import utilities.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0132_cable_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='frontport',
|
||||
name='color',
|
||||
field=utilities.fields.ColorField(blank=True, max_length=6),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='frontporttemplate',
|
||||
name='color',
|
||||
field=utilities.fields.ColorField(blank=True, max_length=6),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rearport',
|
||||
name='color',
|
||||
field=utilities.fields.ColorField(blank=True, max_length=6),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rearporttemplate',
|
||||
name='color',
|
||||
field=utilities.fields.ColorField(blank=True, max_length=6),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
import dcim.fields
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0133_port_colors'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='wwn',
|
||||
field=dcim.fields.WWNField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='bridge',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bridge_interfaces', to='dcim.interface'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tenancy', '0002_tenant_ordering'),
|
||||
('dcim', '0134_interface_wwn_bridge'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='tenant',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='locations', to='tenancy.tenant'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='tenant',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='cables', to='tenancy.tenant'),
|
||||
),
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0135_tenancy_extensions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='airflow',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='airflow',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
]
|
||||
@@ -1,83 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0136_device_airflow'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='region',
|
||||
name='name',
|
||||
field=models.CharField(max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='region',
|
||||
name='slug',
|
||||
field=models.SlugField(max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sitegroup',
|
||||
name='name',
|
||||
field=models.CharField(max_length=100),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sitegroup',
|
||||
name='slug',
|
||||
field=models.SlugField(max_length=100),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='location',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='location',
|
||||
constraint=models.UniqueConstraint(fields=('site', 'parent', 'name'), name='dcim_location_parent_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='location',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('site', 'name'), name='dcim_location_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='location',
|
||||
constraint=models.UniqueConstraint(fields=('site', 'parent', 'slug'), name='dcim_location_parent_slug'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='location',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('site', 'slug'), name='dcim_location_slug'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='region',
|
||||
constraint=models.UniqueConstraint(fields=('parent', 'name'), name='dcim_region_parent_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='region',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('name',), name='dcim_region_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='region',
|
||||
constraint=models.UniqueConstraint(fields=('parent', 'slug'), name='dcim_region_parent_slug'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='region',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('slug',), name='dcim_region_slug'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='sitegroup',
|
||||
constraint=models.UniqueConstraint(fields=('parent', 'name'), name='dcim_sitegroup_parent_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='sitegroup',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('name',), name='dcim_sitegroup_name'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='sitegroup',
|
||||
constraint=models.UniqueConstraint(fields=('parent', 'slug'), name='dcim_sitegroup_parent_slug'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='sitegroup',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent', None)), fields=('slug',), name='dcim_sitegroup_slug'),
|
||||
),
|
||||
]
|
||||
@@ -1,50 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2021-10-21 14:50
|
||||
|
||||
from django.db import migrations
|
||||
import taggit.managers
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0062_clear_secrets_changelog'),
|
||||
('dcim', '0137_relax_uniqueness_constraints'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='devicerole',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='manufacturer',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rackrole',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='region',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sitegroup',
|
||||
name='tags',
|
||||
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
|
||||
),
|
||||
]
|
||||
@@ -1,91 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0138_extend_tag_support'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='consoleport',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='consoleport',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='consoleserverport',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='consoleserverport',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='frontport',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='frontport',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='interface',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='interface',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='powerfeed',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='powerfeed',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='poweroutlet',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='poweroutlet',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='powerport',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='powerport',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='rearport',
|
||||
old_name='_cable_peer_id',
|
||||
new_name='_link_peer_id',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='rearport',
|
||||
old_name='_cable_peer_type',
|
||||
new_name='_link_peer_type',
|
||||
),
|
||||
]
|
||||
@@ -1,49 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0139_rename_cable_peer'),
|
||||
('wireless', '0001_wireless'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_role',
|
||||
field=models.CharField(blank=True, max_length=30),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_channel',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_channel_frequency',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='rf_channel_width',
|
||||
field=models.DecimalField(blank=True, decimal_places=3, max_digits=7, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='tx_power',
|
||||
field=models.PositiveSmallIntegerField(blank=True, null=True, validators=[django.core.validators.MaxValueValidator(127)]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='wireless_lans',
|
||||
field=models.ManyToManyField(blank=True, related_name='interfaces', to='wireless.WirelessLAN'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='wireless_link',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wireless.wirelesslink'),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 3.2.8 on 2021-11-02 16:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0053_asn_model'),
|
||||
('dcim', '0140_wireless'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='site',
|
||||
name='asns',
|
||||
field=models.ManyToManyField(blank=True, related_name='sites', to='ipam.ASN'),
|
||||
),
|
||||
]
|
||||
@@ -1,29 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
OLD_VALUE = '128gfc-sfp28'
|
||||
NEW_VALUE = '128gfc-qsfp28'
|
||||
|
||||
|
||||
def correct_type(apps, schema_editor):
|
||||
"""
|
||||
Correct TYPE_128GFC_QSFP28 interface type.
|
||||
"""
|
||||
Interface = apps.get_model('dcim', 'Interface')
|
||||
InterfaceTemplate = apps.get_model('dcim', 'InterfaceTemplate')
|
||||
|
||||
for model in (Interface, InterfaceTemplate):
|
||||
model.objects.filter(type=OLD_VALUE).update(type=NEW_VALUE)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0141_asn_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=correct_type,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0053_asn_model'),
|
||||
('dcim', '0142_rename_128gfc_qsfp28'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='primary_ip4',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='primary_ip6',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'),
|
||||
),
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
from utilities.utils import to_meters
|
||||
|
||||
|
||||
def recalculate_abs_length(apps, schema_editor):
|
||||
"""
|
||||
Recalculate absolute lengths for all cables with a length and length unit defined. Fixes
|
||||
incorrectly calculated values as reported under bug #8377.
|
||||
"""
|
||||
Cable = apps.get_model('dcim', 'Cable')
|
||||
|
||||
cables = Cable.objects.filter(length__isnull=False).exclude(length_unit='')
|
||||
for cable in cables:
|
||||
cable._abs_length = to_meters(cable.length, cable.length_unit)
|
||||
|
||||
Cable.objects.bulk_update(cables, ['_abs_length'], batch_size=100)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0143_remove_primary_for_related_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=recalculate_abs_length,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,59 +0,0 @@
|
||||
import os
|
||||
|
||||
from django.db import migrations
|
||||
from django.db.utils import DataError
|
||||
|
||||
|
||||
def check_legacy_data(apps, schema_editor):
|
||||
"""
|
||||
Abort the migration if any legacy site fields still contain data.
|
||||
"""
|
||||
Site = apps.get_model('dcim', 'Site')
|
||||
|
||||
site_count = Site.objects.exclude(asn__isnull=True).count()
|
||||
if site_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
|
||||
raise DataError(
|
||||
f"Unable to proceed with deleting asn field from Site model: Found {site_count} sites with "
|
||||
f"legacy ASN data. Please ensure all legacy site ASN data has been migrated to ASN objects "
|
||||
f"before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA environment variable to bypass "
|
||||
f"this safeguard and delete all legacy site ASN data."
|
||||
)
|
||||
|
||||
site_count = Site.objects.exclude(contact_name='', contact_phone='', contact_email='').count()
|
||||
if site_count and 'NETBOX_DELETE_LEGACY_DATA' not in os.environ:
|
||||
raise DataError(
|
||||
f"Unable to proceed with deleting contact fields from Site model: Found {site_count} sites "
|
||||
f"with legacy contact data. Please ensure all legacy site contact data has been migrated to "
|
||||
f"contact objects before proceeding. Or, set the NETBOX_DELETE_LEGACY_DATA environment "
|
||||
f"variable to bypass this safeguard and delete all legacy site contact data."
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0144_fix_cable_abs_length'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=check_legacy_data,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='asn',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='contact_email',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='contact_name',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='contact_phone',
|
||||
),
|
||||
]
|
||||
@@ -1,279 +0,0 @@
|
||||
from utilities.json import CustomFieldJSONEncoder
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
import utilities.fields
|
||||
import utilities.ordering
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0066_customfield_name_validation'),
|
||||
('dcim', '0145_site_remove_deprecated_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Rename any indexes left over from the old Module model (now InventoryItem) (#8656)
|
||||
migrations.RunSQL(
|
||||
"""
|
||||
DO $$
|
||||
DECLARE
|
||||
idx record;
|
||||
BEGIN
|
||||
FOR idx IN
|
||||
SELECT indexname AS old_name,
|
||||
replace(indexname, 'module', 'inventoryitem') AS new_name
|
||||
FROM pg_indexes
|
||||
WHERE schemaname = 'public' AND
|
||||
tablename = 'dcim_inventoryitem' AND
|
||||
indexname LIKE 'dcim_module_%'
|
||||
LOOP
|
||||
EXECUTE format(
|
||||
'ALTER INDEX %I RENAME TO %I;',
|
||||
idx.old_name,
|
||||
idx.new_name
|
||||
);
|
||||
END LOOP;
|
||||
END$$;
|
||||
"""
|
||||
),
|
||||
|
||||
migrations.AlterModelOptions(
|
||||
name='consoleporttemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='consoleserverporttemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='frontporttemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='interfacetemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='poweroutlettemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='powerporttemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='rearporttemplate',
|
||||
options={'ordering': ('device_type', 'module_type', '_name')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleporttemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverporttemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontporttemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interfacetemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlettemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearporttemplate',
|
||||
name='device_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ModuleType',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('model', models.CharField(max_length=100)),
|
||||
('part_number', models.CharField(blank=True, max_length=50)),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('manufacturer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='module_types', to='dcim.manufacturer')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('manufacturer', 'model'),
|
||||
'unique_together': {('manufacturer', 'model')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ModuleBay',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||
('label', models.CharField(blank=True, max_length=64)),
|
||||
('position', models.CharField(blank=True, max_length=30)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.device')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('device', '_name'),
|
||||
'unique_together': {('device', 'name')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Module',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('local_context_data', models.JSONField(blank=True, null=True)),
|
||||
('serial', models.CharField(blank=True, max_length=50)),
|
||||
('asset_tag', models.CharField(blank=True, max_length=50, null=True, unique=True)),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modules', to='dcim.device')),
|
||||
('module_bay', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='installed_module', to='dcim.modulebay')),
|
||||
('module_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='instances', to='dcim.moduletype')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('module_bay',),
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consoleport',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consoleporttemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consoleserverport',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consoleserverporttemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='frontport',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='frontporttemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='poweroutlet',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='poweroutlettemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerport',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerporttemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rearport',
|
||||
name='module',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.module'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rearporttemplate',
|
||||
name='module_type',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.moduletype'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='consoleporttemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='consoleserverporttemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='frontporttemplate',
|
||||
unique_together={('device_type', 'name'), ('rear_port', 'rear_port_position'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='interfacetemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='poweroutlettemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='powerporttemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='rearporttemplate',
|
||||
unique_together={('device_type', 'name'), ('module_type', 'name')},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ModuleBayTemplate',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||
('label', models.CharField(blank=True, max_length=64)),
|
||||
('position', models.CharField(blank=True, max_length=30)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('device_type', '_name'),
|
||||
'unique_together': {('device_type', 'name')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,38 +0,0 @@
|
||||
from utilities.json import CustomFieldJSONEncoder
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
import utilities.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0068_configcontext_cluster_types'),
|
||||
('dcim', '0146_modules'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='InventoryItemRole',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, unique=True)),
|
||||
('slug', models.SlugField(max_length=100, unique=True)),
|
||||
('color', utilities.fields.ColorField(default='9e9e9e', max_length=6)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('name',),
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventoryitem',
|
||||
name='role',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_items', to='dcim.inventoryitemrole'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('dcim', '0147_inventoryitemrole'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='inventoryitem',
|
||||
name='component_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='inventoryitem',
|
||||
name='component_type',
|
||||
field=models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'poweroutlet', 'powerport', 'rearport'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype'),
|
||||
),
|
||||
]
|
||||
@@ -1,43 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import mptt.fields
|
||||
import utilities.fields
|
||||
import utilities.ordering
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('dcim', '0148_inventoryitem_component'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='InventoryItemTemplate',
|
||||
fields=[
|
||||
('created', models.DateField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||
('label', models.CharField(blank=True, max_length=64)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('component_id', models.PositiveBigIntegerField(blank=True, null=True)),
|
||||
('part_id', models.CharField(blank=True, max_length=50)),
|
||||
('lft', models.PositiveIntegerField(editable=False)),
|
||||
('rght', models.PositiveIntegerField(editable=False)),
|
||||
('tree_id', models.PositiveIntegerField(db_index=True, editable=False)),
|
||||
('level', models.PositiveIntegerField(editable=False)),
|
||||
('component_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(('app_label', 'dcim'), ('model__in', ('consoleporttemplate', 'consoleserverporttemplate', 'frontporttemplate', 'interfacetemplate', 'poweroutlettemplate', 'powerporttemplate', 'rearporttemplate'))), null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')),
|
||||
('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='%(class)ss', to='dcim.devicetype')),
|
||||
('manufacturer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.manufacturer')),
|
||||
('parent', mptt.fields.TreeForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='child_items', to='dcim.inventoryitemtemplate')),
|
||||
('role', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inventory_item_templates', to='dcim.inventoryitemrole')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('device_type__id', 'parent__id', '_name'),
|
||||
'unique_together': {('device_type', 'parent', 'name')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# Generated by Django 3.2.11 on 2022-01-07 18:34
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0054_vlangroup_min_max_vids'),
|
||||
('dcim', '0149_inventoryitem_templates'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='vrf',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interfaces', to='ipam.vrf'),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
# Generated by Django 3.2.10 on 2022-01-08 18:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0150_interface_vrf'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='duplex',
|
||||
field=models.CharField(blank=True, max_length=50, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='speed',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,274 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0151_interface_speed_duplex'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Model IDs
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cablepath',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleport',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleporttemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverport',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverporttemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicebay',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicebaytemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicerole',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicetype',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontport',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontporttemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interfacetemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitem',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitemrole',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitemtemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='manufacturer',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='module',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modulebay',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modulebaytemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='moduletype',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platform',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerfeed',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlet',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlettemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerpanel',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rack',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rackreservation',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rackrole',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearport',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearporttemplate',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='region',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='site',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sitegroup',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='virtualchassis',
|
||||
name='id',
|
||||
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False),
|
||||
),
|
||||
|
||||
# GFK IDs
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='termination_a_id',
|
||||
field=models.PositiveBigIntegerField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='termination_b_id',
|
||||
field=models.PositiveBigIntegerField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cablepath',
|
||||
name='destination_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cablepath',
|
||||
name='origin_id',
|
||||
field=models.PositiveBigIntegerField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleport',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverport',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontport',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerfeed',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlet',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearport',
|
||||
name='_link_peer_id',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,208 +0,0 @@
|
||||
# Generated by Django 4.0.2 on 2022-02-08 18:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0152_standardize_id_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cable',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleport',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleporttemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverport',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='consoleserverporttemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicebay',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicebaytemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicerole',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='devicetype',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontport',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='frontporttemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interfacetemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitem',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitemrole',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventoryitemtemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='location',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='manufacturer',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='module',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modulebay',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='modulebaytemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='moduletype',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='platform',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerfeed',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlet',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='poweroutlettemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerpanel',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rack',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rackreservation',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rackrole',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearport',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='rearporttemplate',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='region',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='site',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sitegroup',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='virtualchassis',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,23 +0,0 @@
|
||||
import django.contrib.postgres.fields
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0153_created_datetimefield'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='devicetype',
|
||||
name='u_height',
|
||||
field=models.DecimalField(decimal_places=1, default=1.0, max_digits=4),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='device',
|
||||
name='position',
|
||||
field=models.DecimalField(blank=True, decimal_places=1, max_digits=4, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(100.5)]),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 4.0.5 on 2022-06-22 00:36
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0154_half_height_rack_units'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='poe_mode',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='poe_type',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='poe_mode',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='poe_type',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.0.5 on 2022-06-22 17:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0155_interface_poe_mode_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='location',
|
||||
name='status',
|
||||
field=models.CharField(default='active', max_length=50),
|
||||
),
|
||||
]
|
||||
@@ -1,95 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('dcim', '0156_location_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
# Create CableTermination model
|
||||
migrations.CreateModel(
|
||||
name='CableTermination',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('cable_end', models.CharField(max_length=1)),
|
||||
('termination_id', models.PositiveBigIntegerField()),
|
||||
('cable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='terminations', to='dcim.cable')),
|
||||
('termination_type', models.ForeignKey(limit_choices_to=models.Q(models.Q(models.Q(('app_label', 'circuits'), ('model__in', ('circuittermination',))), models.Q(('app_label', 'dcim'), ('model__in', ('consoleport', 'consoleserverport', 'frontport', 'interface', 'powerfeed', 'poweroutlet', 'powerport', 'rearport'))), _connector='OR')), on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')),
|
||||
('_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.device')),
|
||||
('_rack', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.rack')),
|
||||
('_location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.location')),
|
||||
('_site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='dcim.site')),
|
||||
],
|
||||
options={
|
||||
'ordering': ('cable', 'cable_end', 'pk'),
|
||||
},
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='cabletermination',
|
||||
constraint=models.UniqueConstraint(fields=('termination_type', 'termination_id'), name='dcim_cable_termination_unique_termination'),
|
||||
),
|
||||
|
||||
# Update CablePath model
|
||||
migrations.RenameField(
|
||||
model_name='cablepath',
|
||||
old_name='path',
|
||||
new_name='_nodes',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cablepath',
|
||||
name='path',
|
||||
field=models.JSONField(default=list),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cablepath',
|
||||
name='is_complete',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
|
||||
# Add cable_end field to cable termination models
|
||||
migrations.AddField(
|
||||
model_name='consoleport',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='consoleserverport',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='frontport',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerfeed',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='poweroutlet',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerport',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rearport',
|
||||
name='cable_end',
|
||||
field=models.CharField(blank=True, max_length=1),
|
||||
),
|
||||
]
|
||||
@@ -1,87 +0,0 @@
|
||||
import sys
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def cache_related_objects(termination):
|
||||
"""
|
||||
Replicate caching logic from CableTermination.cache_related_objects()
|
||||
"""
|
||||
attrs = {}
|
||||
|
||||
# Device components
|
||||
if getattr(termination, 'device', None):
|
||||
attrs['_device'] = termination.device
|
||||
attrs['_rack'] = termination.device.rack
|
||||
attrs['_location'] = termination.device.location
|
||||
attrs['_site'] = termination.device.site
|
||||
|
||||
# Power feeds
|
||||
elif getattr(termination, 'rack', None):
|
||||
attrs['_rack'] = termination.rack
|
||||
attrs['_location'] = termination.rack.location
|
||||
attrs['_site'] = termination.rack.site
|
||||
|
||||
# Circuit terminations
|
||||
elif getattr(termination, 'site', None):
|
||||
attrs['_site'] = termination.site
|
||||
|
||||
return attrs
|
||||
|
||||
|
||||
def populate_cable_terminations(apps, schema_editor):
|
||||
"""
|
||||
Replicate terminations from the Cable model into CableTermination instances.
|
||||
"""
|
||||
ContentType = apps.get_model('contenttypes', 'ContentType')
|
||||
Cable = apps.get_model('dcim', 'Cable')
|
||||
CableTermination = apps.get_model('dcim', 'CableTermination')
|
||||
|
||||
# Retrieve the necessary data from Cable objects
|
||||
cables = Cable.objects.values(
|
||||
'id', 'termination_a_type', 'termination_a_id', 'termination_b_type', 'termination_b_id'
|
||||
)
|
||||
|
||||
# Queue CableTerminations to be created
|
||||
cable_terminations = []
|
||||
cable_count = cables.count()
|
||||
for i, cable in enumerate(cables, start=1):
|
||||
for cable_end in ('a', 'b'):
|
||||
# We must manually instantiate the termination object, because GFK fields are not
|
||||
# supported within migrations.
|
||||
termination_ct = ContentType.objects.get(pk=cable[f'termination_{cable_end}_type'])
|
||||
termination_model = apps.get_model(termination_ct.app_label, termination_ct.model)
|
||||
termination = termination_model.objects.get(pk=cable[f'termination_{cable_end}_id'])
|
||||
|
||||
cable_terminations.append(CableTermination(
|
||||
cable_id=cable['id'],
|
||||
cable_end=cable_end.upper(),
|
||||
termination_type_id=cable[f'termination_{cable_end}_type'],
|
||||
termination_id=cable[f'termination_{cable_end}_id'],
|
||||
**cache_related_objects(termination)
|
||||
))
|
||||
|
||||
# Output progress occasionally
|
||||
if 'test' not in sys.argv and not i % 100:
|
||||
progress = float(i) * 100 / cable_count
|
||||
if i == 100:
|
||||
print('')
|
||||
sys.stdout.write(f"\r Updated {i}/{cable_count} cables ({progress:.2f}%)")
|
||||
sys.stdout.flush()
|
||||
|
||||
# Bulk create the termination objects
|
||||
CableTermination.objects.bulk_create(cable_terminations, batch_size=100)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0157_new_cabling_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=populate_cable_terminations,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,50 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
from dcim.utils import compile_path_node
|
||||
|
||||
|
||||
def populate_cable_paths(apps, schema_editor):
|
||||
"""
|
||||
Replicate terminations from the Cable model into CableTermination instances.
|
||||
"""
|
||||
CablePath = apps.get_model('dcim', 'CablePath')
|
||||
|
||||
# Construct the new two-dimensional path, and add the origin & destination objects to the nodes list
|
||||
cable_paths = []
|
||||
for cablepath in CablePath.objects.all():
|
||||
|
||||
# Origin
|
||||
origin = compile_path_node(cablepath.origin_type_id, cablepath.origin_id)
|
||||
cablepath.path.append([origin])
|
||||
cablepath._nodes.insert(0, origin)
|
||||
|
||||
# Transit nodes
|
||||
cablepath.path.extend([
|
||||
[node] for node in cablepath._nodes[1:]
|
||||
])
|
||||
|
||||
# Destination
|
||||
if cablepath.destination_id:
|
||||
destination = compile_path_node(cablepath.destination_type_id, cablepath.destination_id)
|
||||
cablepath.path.append([destination])
|
||||
cablepath._nodes.append(destination)
|
||||
cablepath.is_complete = True
|
||||
|
||||
cable_paths.append(cablepath)
|
||||
|
||||
# Bulk update all CableTerminations
|
||||
CablePath.objects.bulk_update(cable_paths, fields=('path', '_nodes', 'is_complete'), batch_size=100)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0158_populate_cable_terminations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=populate_cable_paths,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,46 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def populate_cable_terminations(apps, schema_editor):
|
||||
Cable = apps.get_model('dcim', 'Cable')
|
||||
|
||||
cable_termination_models = (
|
||||
apps.get_model('dcim', 'ConsolePort'),
|
||||
apps.get_model('dcim', 'ConsoleServerPort'),
|
||||
apps.get_model('dcim', 'PowerPort'),
|
||||
apps.get_model('dcim', 'PowerOutlet'),
|
||||
apps.get_model('dcim', 'Interface'),
|
||||
apps.get_model('dcim', 'FrontPort'),
|
||||
apps.get_model('dcim', 'RearPort'),
|
||||
apps.get_model('dcim', 'PowerFeed'),
|
||||
apps.get_model('circuits', 'CircuitTermination'),
|
||||
)
|
||||
|
||||
for model in cable_termination_models:
|
||||
model.objects.filter(
|
||||
id__in=Cable.objects.filter(
|
||||
termination_a_type__app_label=model._meta.app_label,
|
||||
termination_a_type__model=model._meta.model_name
|
||||
).values_list('termination_a_id', flat=True)
|
||||
).update(cable_end='A')
|
||||
model.objects.filter(
|
||||
id__in=Cable.objects.filter(
|
||||
termination_b_type__app_label=model._meta.app_label,
|
||||
termination_b_type__model=model._meta.model_name
|
||||
).values_list('termination_b_id', flat=True)
|
||||
).update(cable_end='B')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0037_new_cabling_models'),
|
||||
('dcim', '0159_populate_cable_paths'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=populate_cable_terminations,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,14 +1,146 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.functions.text
|
||||
import taggit.managers
|
||||
from django.db import migrations, models
|
||||
|
||||
import utilities.json
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
replaces = [
|
||||
('dcim', '0160_populate_cable_ends'),
|
||||
('dcim', '0161_cabling_cleanup'),
|
||||
('dcim', '0162_unique_constraints'),
|
||||
('dcim', '0163_weight_fields'),
|
||||
('dcim', '0164_rack_mounting_depth'),
|
||||
('dcim', '0165_standardize_description_comments'),
|
||||
('dcim', '0166_virtualdevicecontext')
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0047_squashed_0053'),
|
||||
('tenancy', '0009_standardize_description_comments'),
|
||||
('circuits', '0037_new_cabling_models'),
|
||||
('dcim', '0159_populate_cable_paths'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='cable',
|
||||
options={'ordering': ('pk',)},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cable',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_a_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_a_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_b_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_b_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='_termination_a_device',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='_termination_b_device',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cablepath',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='destination_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='destination_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='origin_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='origin_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleserverport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleserverport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='frontport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='frontport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='interface',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='interface',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerfeed',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerfeed',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='poweroutlet',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='poweroutlet',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='rearport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='rearport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveConstraint(
|
||||
model_name='cabletermination',
|
||||
name='dcim_cable_termination_unique_termination',
|
||||
@@ -329,4 +461,164 @@ class Migration(migrations.Migration):
|
||||
model_name='sitegroup',
|
||||
constraint=models.UniqueConstraint(condition=models.Q(('parent__isnull', True)), fields=('slug',), name='dcim_sitegroup_slug', violation_error_message='A top-level site group with this slug already exists.'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='max_weight',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='_abs_max_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='mounting_depth',
|
||||
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerfeed',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerpanel',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerpanel',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rackreservation',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VirtualDeviceContext',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('status', models.CharField(max_length=50)),
|
||||
('identifier', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='dcim.device')),
|
||||
('primary_ip4', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')),
|
||||
('primary_ip6', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='tenancy.tenant')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='vdcs',
|
||||
field=models.ManyToManyField(related_name='interfaces', to='dcim.virtualdevicecontext'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='virtualdevicecontext',
|
||||
constraint=models.UniqueConstraint(fields=('device', 'identifier'), name='dcim_virtualdevicecontext_device_identifier'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='virtualdevicecontext',
|
||||
constraint=models.UniqueConstraint(fields=('device', 'name'), name='dcim_virtualdevicecontext_device_name'),
|
||||
),
|
||||
]
|
||||
@@ -1,134 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0160_populate_cable_ends'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
# Remove old fields from Cable
|
||||
migrations.AlterModelOptions(
|
||||
name='cable',
|
||||
options={'ordering': ('pk',)},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cable',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_a_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_a_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_b_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='termination_b_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='_termination_a_device',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cable',
|
||||
name='_termination_b_device',
|
||||
),
|
||||
|
||||
# Remove old fields from CablePath
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cablepath',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='destination_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='destination_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='origin_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cablepath',
|
||||
name='origin_type',
|
||||
),
|
||||
|
||||
# Remove link peer type/ID fields from cable termination models
|
||||
migrations.RemoveField(
|
||||
model_name='consoleport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleserverport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='consoleserverport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='frontport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='frontport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='interface',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='interface',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerfeed',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerfeed',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='poweroutlet',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='poweroutlet',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='powerport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='rearport',
|
||||
name='_link_peer_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='rearport',
|
||||
name='_link_peer_type',
|
||||
),
|
||||
|
||||
]
|
||||
@@ -1,72 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0162_unique_constraints'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
|
||||
# Device types
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
|
||||
# Module types
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
|
||||
# Racks
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='weight',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='max_weight',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='weight_unit',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='_abs_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='_abs_max_weight',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.1 on 2022-10-27 14:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0163_weight_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='mounting_depth',
|
||||
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,78 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-11-03 18:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0164_rack_mounting_depth'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cable',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='moduletype',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerfeed',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerpanel',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerpanel',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rackreservation',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='comments',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
]
|
||||
@@ -1,54 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-11-10 16:56
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import taggit.managers
|
||||
import utilities.json
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('ipam', '0063_standardize_description_comments'),
|
||||
('extras', '0082_savedfilter'),
|
||||
('tenancy', '0009_standardize_description_comments'),
|
||||
('dcim', '0165_standardize_description_comments'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='VirtualDeviceContext',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
|
||||
('created', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
|
||||
('description', models.CharField(blank=True, max_length=200)),
|
||||
('name', models.CharField(max_length=64)),
|
||||
('status', models.CharField(max_length=50)),
|
||||
('identifier', models.PositiveSmallIntegerField(blank=True, null=True)),
|
||||
('comments', models.TextField(blank=True)),
|
||||
('device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='dcim.device')),
|
||||
('primary_ip4', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')),
|
||||
('primary_ip6', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress')),
|
||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||
('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='vdcs', to='tenancy.tenant')),
|
||||
],
|
||||
options={
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interface',
|
||||
name='vdcs',
|
||||
field=models.ManyToManyField(related_name='interfaces', to='dcim.virtualdevicecontext'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='virtualdevicecontext',
|
||||
constraint=models.UniqueConstraint(fields=('device', 'identifier'), name='dcim_virtualdevicecontext_device_identifier'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='virtualdevicecontext',
|
||||
constraint=models.UniqueConstraint(fields=('device', 'name'), name='dcim_virtualdevicecontext_device_name'),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.2 on 2022-12-09 15:09
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0166_virtualdevicecontext'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='status',
|
||||
field=models.CharField(default='active', max_length=50),
|
||||
),
|
||||
]
|
||||
251
netbox/dcim/migrations/0167_squashed_0182.py
Normal file
251
netbox/dcim/migrations/0167_squashed_0182.py
Normal file
@@ -0,0 +1,251 @@
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import utilities.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
replaces = [
|
||||
('dcim', '0167_module_status'),
|
||||
('dcim', '0168_interface_template_enabled'),
|
||||
('dcim', '0169_devicetype_default_platform'),
|
||||
('dcim', '0170_configtemplate'),
|
||||
('dcim', '0171_cabletermination_change_logging'),
|
||||
('dcim', '0172_larger_power_draw_values'),
|
||||
('dcim', '0173_remove_napalm_fields'),
|
||||
('dcim', '0174_device_latitude_device_longitude'),
|
||||
('dcim', '0174_rack_starting_unit'),
|
||||
('dcim', '0175_device_oob_ip'),
|
||||
('dcim', '0176_device_component_counters'),
|
||||
('dcim', '0177_devicetype_component_counters'),
|
||||
('dcim', '0178_virtual_chassis_member_counter'),
|
||||
('dcim', '0179_interfacetemplate_rf_role'),
|
||||
('dcim', '0180_powerfeed_tenant'),
|
||||
('dcim', '0181_rename_device_role_device_role'),
|
||||
('dcim', '0182_zero_length_cable_fix')
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
('extras', '0086_configtemplate'),
|
||||
('tenancy', '0010_tenant_relax_uniqueness'),
|
||||
('ipam', '0047_squashed_0053'),
|
||||
('dcim', '0166_virtualdevicecontext'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='status',
|
||||
field=models.CharField(default='active', max_length=50),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='enabled',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='bridge',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bridge_interfaces', to='dcim.interfacetemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='default_platform',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.platform'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='extras.configtemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicerole',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='device_roles', to='extras.configtemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='platforms', to='extras.configtemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cabletermination',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cabletermination',
|
||||
name='last_updated',
|
||||
field=models.DateTimeField(auto_now=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='allocated_draw',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='maximum_draw',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='allocated_draw',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='maximum_draw',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='napalm_args',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='napalm_driver',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='latitude',
|
||||
field=models.DecimalField(blank=True, decimal_places=6, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='longitude',
|
||||
field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='starting_unit',
|
||||
field=models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='oob_ip',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='ipam.ipaddress'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='console_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ConsolePort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='console_server_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ConsoleServerPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='power_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.PowerPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='power_outlet_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.PowerOutlet'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='interface_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.Interface'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='front_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.FrontPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='rear_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.RearPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='device_bay_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.DeviceBay'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='module_bay_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.ModuleBay'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='inventory_item_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device', to_model='dcim.InventoryItem'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ConsolePortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_server_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ConsoleServerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.PowerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_outlet_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.PowerOutletTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='interface_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.InterfaceTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='front_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.FrontPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='rear_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.RearPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='device_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.DeviceBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='module_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.ModuleBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='inventory_item_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='device_type', to_model='dcim.InventoryItemTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='member_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, editable=False, to_field='virtual_chassis', to_model='dcim.Device'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='rf_role',
|
||||
field=models.CharField(blank=True, max_length=30),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='powerfeed',
|
||||
name='tenant',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='power_feeds', to='tenancy.tenant'),
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='device',
|
||||
old_name='device_role',
|
||||
new_name='role',
|
||||
),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0167_module_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='enabled',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='bridge',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='bridge_interfaces', to='dcim.interfacetemplate'),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
# Generated by Django 4.1.6 on 2023-02-10 18:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0168_interface_template_enabled'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='default_platform',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.platform'),
|
||||
),
|
||||
]
|
||||
@@ -1,28 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('extras', '0086_configtemplate'),
|
||||
('dcim', '0169_devicetype_default_platform'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='extras.configtemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicerole',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='device_roles', to='extras.configtemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='platform',
|
||||
name='config_template',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='platforms', to='extras.configtemplate'),
|
||||
),
|
||||
]
|
||||
@@ -1,21 +0,0 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0170_configtemplate'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='cabletermination',
|
||||
name='created',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cabletermination',
|
||||
name='last_updated',
|
||||
field=models.DateTimeField(auto_now=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,42 +0,0 @@
|
||||
# Generated by Django 4.1.9 on 2023-05-12 18:46
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0171_cabletermination_change_logging'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='allocated_draw',
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerport',
|
||||
name='maximum_draw',
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='allocated_draw',
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powerporttemplate',
|
||||
name='maximum_draw',
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)]
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,19 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0172_larger_power_draw_values'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='napalm_args',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='platform',
|
||||
name='napalm_driver',
|
||||
),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
# Generated by Django 4.1.9 on 2023-05-31 22:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0173_remove_napalm_fields'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='latitude',
|
||||
field=models.DecimalField(blank=True, decimal_places=6, max_digits=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='longitude',
|
||||
field=models.DecimalField(blank=True, decimal_places=6, max_digits=9, null=True),
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.1.9 on 2023-05-31 15:47
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0174_device_latitude_device_longitude'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='rack',
|
||||
name='starting_unit',
|
||||
field=models.PositiveSmallIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)]),
|
||||
),
|
||||
]
|
||||
@@ -1,25 +0,0 @@
|
||||
# Generated by Django 4.1.9 on 2023-07-24 20:29
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('ipam', '0066_iprange_mark_utilized'),
|
||||
('dcim', '0174_rack_starting_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='oob_ip',
|
||||
field=models.OneToOneField(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name='+',
|
||||
to='ipam.ipaddress',
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,83 +0,0 @@
|
||||
from django.db import migrations
|
||||
from django.db.models import Count
|
||||
|
||||
import utilities.fields
|
||||
from utilities.counters import update_counts
|
||||
|
||||
|
||||
def recalculate_device_counts(apps, schema_editor):
|
||||
Device = apps.get_model("dcim", "Device")
|
||||
|
||||
update_counts(Device, 'console_port_count', 'consoleports')
|
||||
update_counts(Device, 'console_server_port_count', 'consoleserverports')
|
||||
update_counts(Device, 'power_port_count', 'powerports')
|
||||
update_counts(Device, 'power_outlet_count', 'poweroutlets')
|
||||
update_counts(Device, 'interface_count', 'interfaces')
|
||||
update_counts(Device, 'front_port_count', 'frontports')
|
||||
update_counts(Device, 'rear_port_count', 'rearports')
|
||||
update_counts(Device, 'device_bay_count', 'devicebays')
|
||||
update_counts(Device, 'module_bay_count', 'modulebays')
|
||||
update_counts(Device, 'inventory_item_count', 'inventoryitems')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0175_device_oob_ip'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='console_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.ConsolePort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='console_server_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.ConsoleServerPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='power_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.PowerPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='power_outlet_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.PowerOutlet'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='interface_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.Interface'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='front_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.FrontPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='rear_port_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.RearPort'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='device_bay_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.DeviceBay'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='module_bay_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.ModuleBay'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='inventory_item_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device', to_model='dcim.InventoryItem'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
recalculate_device_counts,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,83 +0,0 @@
|
||||
from django.db import migrations
|
||||
from django.db.models import Count
|
||||
|
||||
import utilities.fields
|
||||
from utilities.counters import update_counts
|
||||
|
||||
|
||||
def recalculate_devicetype_template_counts(apps, schema_editor):
|
||||
DeviceType = apps.get_model("dcim", "DeviceType")
|
||||
|
||||
update_counts(DeviceType, 'console_port_template_count', 'consoleporttemplates')
|
||||
update_counts(DeviceType, 'console_server_port_template_count', 'consoleserverporttemplates')
|
||||
update_counts(DeviceType, 'power_port_template_count', 'powerporttemplates')
|
||||
update_counts(DeviceType, 'power_outlet_template_count', 'poweroutlettemplates')
|
||||
update_counts(DeviceType, 'interface_template_count', 'interfacetemplates')
|
||||
update_counts(DeviceType, 'front_port_template_count', 'frontporttemplates')
|
||||
update_counts(DeviceType, 'rear_port_template_count', 'rearporttemplates')
|
||||
update_counts(DeviceType, 'device_bay_template_count', 'devicebaytemplates')
|
||||
update_counts(DeviceType, 'module_bay_template_count', 'modulebaytemplates')
|
||||
update_counts(DeviceType, 'inventory_item_template_count', 'inventoryitemtemplates')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0176_device_component_counters'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ConsolePortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='console_server_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ConsoleServerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.PowerPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='power_outlet_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.PowerOutletTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='interface_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.InterfaceTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='front_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.FrontPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='rear_port_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.RearPortTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='device_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.DeviceBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='module_bay_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.ModuleBayTemplate'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='devicetype',
|
||||
name='inventory_item_template_count',
|
||||
field=utilities.fields.CounterCacheField(default=0, to_field='device_type', to_model='dcim.InventoryItemTemplate'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
recalculate_devicetype_template_counts,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,31 +0,0 @@
|
||||
from django.db import migrations
|
||||
from django.db.models import Count
|
||||
|
||||
import utilities.fields
|
||||
from utilities.counters import update_counts
|
||||
|
||||
|
||||
def populate_virtualchassis_members(apps, schema_editor):
|
||||
VirtualChassis = apps.get_model('dcim', 'VirtualChassis')
|
||||
|
||||
update_counts(VirtualChassis, 'member_count', 'members')
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('dcim', '0177_devicetype_component_counters'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='virtualchassis',
|
||||
name='member_count',
|
||||
field=utilities.fields.CounterCacheField(
|
||||
default=0, to_field='virtual_chassis', to_model='dcim.Device'
|
||||
),
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=populate_virtualchassis_members,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,18 +0,0 @@
|
||||
# Generated by Django 4.2.2 on 2023-07-18 07:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0178_virtual_chassis_member_counter'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='interfacetemplate',
|
||||
name='rf_role',
|
||||
field=models.CharField(blank=True, max_length=30),
|
||||
),
|
||||
]
|
||||
@@ -1,20 +0,0 @@
|
||||
# Generated by Django 4.1.8 on 2023-07-29 11:29
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tenancy', '0010_tenant_relax_uniqueness'),
|
||||
('dcim', '0179_interfacetemplate_rf_role'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='powerfeed',
|
||||
name='tenant',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='power_feeds', to='tenancy.tenant'),
|
||||
),
|
||||
]
|
||||
@@ -1,35 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def update_table_configs(apps, schema_editor):
|
||||
"""
|
||||
Replace the `device_role` column in DeviceTable configs with `role`.
|
||||
"""
|
||||
UserConfig = apps.get_model('users', 'UserConfig')
|
||||
|
||||
for table in ('DeviceTable', 'DeviceBayTable'):
|
||||
for config in UserConfig.objects.filter(**{f'data__tables__{table}__columns__contains': 'device_role'}):
|
||||
config.data['tables'][table]['columns'] = [
|
||||
'role' if x == 'device_role' else x
|
||||
for x in config.data['tables'][table]['columns']
|
||||
]
|
||||
config.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0180_powerfeed_tenant'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='device',
|
||||
old_name='device_role',
|
||||
new_name='role',
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=update_table_configs,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -1,22 +0,0 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def update_cable_lengths(apps, schema_editor):
|
||||
Cable = apps.get_model('dcim', 'Cable')
|
||||
|
||||
# Set the absolute length for any zero-length Cables
|
||||
Cable.objects.filter(length=0).update(_abs_length=0)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0181_rename_device_role_device_role'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=update_cable_lengths,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
@@ -317,10 +317,14 @@ class CableTermination(ChangeLoggedModel):
|
||||
super().clean()
|
||||
|
||||
# Check for existing termination
|
||||
existing_termination = CableTermination.objects.exclude(cable=self.cable).filter(
|
||||
qs = CableTermination.objects.filter(
|
||||
termination_type=self.termination_type,
|
||||
termination_id=self.termination_id
|
||||
).first()
|
||||
)
|
||||
if self.cable.pk:
|
||||
qs = qs.exclude(cable=self.cable)
|
||||
|
||||
existing_termination = qs.first()
|
||||
if existing_termination is not None:
|
||||
raise ValidationError(
|
||||
f"Duplicate termination found for {self.termination_type.app_label}.{self.termination_type.model} "
|
||||
|
||||
@@ -1115,7 +1115,7 @@ class DeviceBay(ComponentModel, TrackingModelMixin):
|
||||
installed_device = models.OneToOneField(
|
||||
to='dcim.Device',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name=_('parent_bay'),
|
||||
related_name='parent_bay',
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user