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

1from django.apps import apps 

2from django.core.management.base import BaseCommand 

3 

4from extras.jobs import RENDER_CONFIG_CONTEXT_CHUNK_SIZE 

5 

6MODELS = ('dcim.device', 'virtualization.virtualmachine') 

7 

8 

9class Command(BaseCommand): 

10 help = "Pre-render and cache config context data for all devices and virtual machines" 

11 

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 ) 

17 

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) 

24 

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() 

28 

29 self.stdout.write(f'Rendering config context for {qs.count()} {model_label} object(s)...') 

30 

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) 

44 

45 self.stdout.write(self.style.SUCCESS(f' Rendered {rendered} {model_label} object(s).')) 

46 

47 self.stdout.write(self.style.SUCCESS('Finished.'))