mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-13 16:47:34 -06:00
Rewrite trace_paths management command and call in upgrade.sh
This commit is contained in:
parent
6db3c65bcc
commit
f560693748
@ -1,68 +0,0 @@
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.color import no_style
|
||||
from django.db import connection
|
||||
from django.db.models import Q
|
||||
|
||||
from dcim.models import CablePath
|
||||
from dcim.signals import create_cablepath
|
||||
|
||||
ENDPOINT_MODELS = (
|
||||
'circuits.CircuitTermination',
|
||||
'dcim.ConsolePort',
|
||||
'dcim.ConsoleServerPort',
|
||||
'dcim.Interface',
|
||||
'dcim.PowerFeed',
|
||||
'dcim.PowerOutlet',
|
||||
'dcim.PowerPort',
|
||||
)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Recalculate natural ordering values for the specified models"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'args', metavar='app_label.ModelName', nargs='*',
|
||||
help='One or more specific models (each prefixed with its app_label) to retrace',
|
||||
)
|
||||
|
||||
def _get_content_types(self, model_names):
|
||||
q = Q()
|
||||
for model_name in model_names:
|
||||
app_label, model = model_name.split('.')
|
||||
q |= Q(app_label__iexact=app_label, model__iexact=model)
|
||||
return ContentType.objects.filter(q)
|
||||
|
||||
def handle(self, *model_names, **options):
|
||||
# Determine the models for which we're retracing all paths
|
||||
origin_types = self._get_content_types(model_names or ENDPOINT_MODELS)
|
||||
self.stdout.write(f"Retracing paths for models: {', '.join([str(ct) for ct in origin_types])}")
|
||||
|
||||
# Delete all existing CablePath instances
|
||||
self.stdout.write(f"Deleting existing cable paths...")
|
||||
deleted_count, _ = CablePath.objects.filter(origin_type__in=origin_types).delete()
|
||||
self.stdout.write((self.style.SUCCESS(f' Deleted {deleted_count} paths')))
|
||||
|
||||
# Reset the SQL sequence. Can do this only if deleting _all_ CablePaths.
|
||||
if not CablePath.objects.count():
|
||||
self.stdout.write(f'Resetting database sequence for CablePath...')
|
||||
sequence_sql = connection.ops.sequence_reset_sql(no_style(), [CablePath])
|
||||
with connection.cursor() as cursor:
|
||||
for sql in sequence_sql:
|
||||
cursor.execute(sql)
|
||||
self.stdout.write(self.style.SUCCESS(' Success.'))
|
||||
|
||||
# Retrace interfaces
|
||||
for ct in origin_types:
|
||||
model = ct.model_class()
|
||||
origins = model.objects.filter(cable__isnull=False)
|
||||
print(f'Retracing {origins.count()} cabled {model._meta.verbose_name_plural}...')
|
||||
i = 0
|
||||
for i, obj in enumerate(origins, start=1):
|
||||
create_cablepath(obj)
|
||||
if not i % 1000:
|
||||
self.stdout.write(f' {i}')
|
||||
self.stdout.write(self.style.SUCCESS(f' Retraced {i} {model._meta.verbose_name_plural}'))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Finished.'))
|
81
netbox/dcim/management/commands/trace_paths.py
Normal file
81
netbox/dcim/management/commands/trace_paths.py
Normal file
@ -0,0 +1,81 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.management.color import no_style
|
||||
from django.db import connection
|
||||
|
||||
from circuits.models import CircuitTermination
|
||||
from dcim.models import CablePath, ConsolePort, ConsoleServerPort, Interface, PowerFeed, PowerOutlet, PowerPort
|
||||
from dcim.signals import create_cablepath
|
||||
|
||||
ENDPOINT_MODELS = (
|
||||
CircuitTermination,
|
||||
ConsolePort,
|
||||
ConsoleServerPort,
|
||||
Interface,
|
||||
PowerFeed,
|
||||
PowerOutlet,
|
||||
PowerPort
|
||||
)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Generate any missing cable paths among all cable termination objects in NetBox"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--force", action='store_true', dest='force',
|
||||
help="Force recalculation of all existing cable paths"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-input", action='store_true', dest='no_input',
|
||||
help="Do not prompt user for any input/confirmation"
|
||||
)
|
||||
|
||||
def handle(self, *model_names, **options):
|
||||
|
||||
# If --force was passed, first delete all existing CablePaths
|
||||
if options['force']:
|
||||
cable_paths = CablePath.objects.all()
|
||||
paths_count = cable_paths.count()
|
||||
|
||||
# Prompt the user to confirm recalculation of all paths
|
||||
if paths_count and not options['no_input']:
|
||||
self.stdout.write(self.style.ERROR("WARNING: Forcing recalculation of all cable paths."))
|
||||
self.stdout.write(
|
||||
f"This will delete and recalculate all {paths_count} existing cable paths. Are you sure?"
|
||||
)
|
||||
confirmation = input("Type yes to confirm: ")
|
||||
if confirmation != 'yes':
|
||||
self.stdout.write(self.style.SUCCESS("Aborting"))
|
||||
return
|
||||
|
||||
# Delete all existing CablePath instances
|
||||
self.stdout.write(f"Deleting {paths_count} existing cable paths...")
|
||||
deleted_count, _ = CablePath.objects.all().delete()
|
||||
self.stdout.write((self.style.SUCCESS(f' Deleted {deleted_count} paths')))
|
||||
|
||||
# Reinitialize the model's PK sequence
|
||||
self.stdout.write(f'Resetting database sequence for CablePath model')
|
||||
sequence_sql = connection.ops.sequence_reset_sql(no_style(), [CablePath])
|
||||
with connection.cursor() as cursor:
|
||||
for sql in sequence_sql:
|
||||
cursor.execute(sql)
|
||||
|
||||
# Retrace paths
|
||||
for model in ENDPOINT_MODELS:
|
||||
origins = model.objects.filter(cable__isnull=False)
|
||||
if not options['force']:
|
||||
origins = origins.filter(_path__isnull=True)
|
||||
origins_count = origins.count()
|
||||
if not origins_count:
|
||||
print(f'Found no missing {model._meta.verbose_name} paths; skipping')
|
||||
continue
|
||||
print(f'Retracing {origins_count} cabled {model._meta.verbose_name_plural}...')
|
||||
i = 0
|
||||
for i, obj in enumerate(origins, start=1):
|
||||
create_cablepath(obj)
|
||||
# TODO: Come up with a better progress indicator
|
||||
if not i % 1000:
|
||||
self.stdout.write(f' {i}')
|
||||
self.stdout.write(self.style.SUCCESS(f' Retraced {i} {model._meta.verbose_name_plural}'))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Finished.'))
|
@ -55,6 +55,11 @@ COMMAND="python3 netbox/manage.py migrate"
|
||||
echo "Applying database migrations ($COMMAND)..."
|
||||
eval $COMMAND || exit 1
|
||||
|
||||
# Trace any missing cable paths (not typically needed)
|
||||
COMMAND="python3 netbox/manage.py trace_paths --no-input"
|
||||
echo "Checking for missing cable paths ($COMMAND)..."
|
||||
eval $COMMAND || exit 1
|
||||
|
||||
# Collect static files
|
||||
COMMAND="python3 netbox/manage.py collectstatic --no-input"
|
||||
echo "Collecting static files ($COMMAND)..."
|
||||
|
Loading…
Reference in New Issue
Block a user