Coverage for extras/management/commands/rebuild_config_context_cache.py: 0%
23 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.apps import apps
2from django.core.management.base import BaseCommand
4from extras.jobs import RENDER_CONFIG_CONTEXT_CHUNK_SIZE
6MODELS = ('dcim.device', 'virtualization.virtualmachine')
9class Command(BaseCommand):
10 help = "Pre-render and cache config context data for all devices and virtual machines"
12 def add_arguments(self, parser):
13 parser.add_argument(
14 '--force', action='store_true',
15 help="Re-render every object, including those whose cache is already populated"
16 )
18 def handle(self, *args, **options):
19 for model_label in MODELS:
20 Model = apps.get_model(model_label)
21 qs = Model.objects.all()
22 if not options['force']:
23 qs = qs.filter(_config_context_data__isnull=True)
25 # Annotate so each instance renders from the same aggregated subquery the on-demand path
26 # uses, avoiding N additional queries per object.
27 qs = qs.annotate_config_context_data()
29 self.stdout.write(f'Rendering config context for {qs.count()} {model_label} object(s)...')
31 rendered = 0
32 for obj in qs.iterator(chunk_size=RENDER_CONFIG_CONTEXT_CHUNK_SIZE):
33 # Capture the generation we render against and write the result back only if no
34 # invalidation has bumped it in the meantime (compare-and-set). This mirrors
35 # RenderConfigContextJob and ensures that running this command on a live system
36 # cannot clobber a concurrent invalidation with a stale render (which would leave a
37 # populated-but-stale cache that the background sweep would then skip).
38 generation = obj._config_context_generation
39 data = obj.render_config_context()
40 rendered += Model.objects.filter(
41 pk=obj.pk,
42 _config_context_generation=generation,
43 ).update(_config_context_data=data)
45 self.stdout.write(self.style.SUCCESS(f' Rendered {rendered} {model_label} object(s).'))
47 self.stdout.write(self.style.SUCCESS('Finished.'))