34
34
LOG = logging .getLogger (__name__ )
35
35
LOG .setLevel (logging .INFO )
36
36
37
+ KOLLA_DEFAULTS = "/etc/kolla/defaults"
38
+ KOLLA_DEFAULTS_STATE = KOLLA_DEFAULTS + '/' + 'state'
39
+
37
40
38
41
class ExitingException (Exception ):
39
42
def __init__ (self , message , exit_code = 1 ):
@@ -403,10 +406,157 @@ def handle_exclusion(root, path_suffix):
403
406
handle_exclusion (root , file_ )
404
407
405
408
409
+ def get_defaults_state ():
410
+ """Retrieve the saved default configuration state from default state file.
411
+
412
+ This function creates the directory for Kolla defaults if it does not
413
+ exist, and then attempts to read the current configuration state from
414
+ a JSON file. If the file exists, it reads and returns the content.
415
+ If not, it returns an empty dictionary.
416
+
417
+ Simply said, when the container starts for the first time, the state file
418
+ doesn't exist, and it returns an empty dictionary.
419
+ However, if it has already been started before, it will contain the state
420
+ as it was when it first ran.
421
+
422
+ Returns:
423
+ dict: The configuration state stored in the Kolla defaults state file.
424
+
425
+ Example:
426
+ {
427
+ "/etc/cinder/cinder.conf": {
428
+ "source": "/etc/cinder/cinder.conf",
429
+ "preserve_properties": true,
430
+ "dest": null
431
+ },
432
+ "/etc/apache2/conf-enabled/cinder-wsgi.conf": {
433
+ "source": "/etc/apache2/conf-enabled/cinder-wsgi.conf",
434
+ "preserve_properties": true,
435
+ "dest": null
436
+ },
437
+ "/etc/cinder/cinder_audit_map.conf": {
438
+ "source": "/etc/cinder/cinder_audit_map.conf",
439
+ "preserve_properties": true,
440
+ "dest": "/etc/kolla/defaults/etc/cinder/cinder_audit_map.conf"
441
+ }
442
+ }
443
+
444
+ From above example:
445
+ /etc/cinder/cinder.conf didn't exist
446
+ /etc/apache2/conf-enabled/cinder-wsgi.conf didn't exist
447
+ /etc/cinder/cinder_audit_map.conf exists and saved
448
+ """
449
+ os .makedirs (KOLLA_DEFAULTS , exist_ok = True )
450
+ if os .path .exists (KOLLA_DEFAULTS_STATE ):
451
+ with open (KOLLA_DEFAULTS_STATE , 'r' ) as f :
452
+ return json .load (f )
453
+ else :
454
+ return {}
455
+
456
+
457
+ def set_defaults_state (state ):
458
+ """Save the provided configuration state to the defaults state file.
459
+
460
+ This function writes the provided state (a dictionary) to a JSON file at
461
+ the specified Kolla defaults state location, ensuring that it is properly
462
+ formatted with indentation for readability.
463
+
464
+ Args:
465
+ state (dict): The configuration state to save to the Kolla defaults
466
+ state file.
467
+ """
468
+ with open (KOLLA_DEFAULTS_STATE , 'w' ) as f :
469
+ json .dump (state , f , indent = 4 )
470
+
471
+
472
+ def remove_or_restore_configs (state ):
473
+ """Remove or restore configuration files based on their current state.
474
+
475
+ This function iterates over the configuration files in the provided state.
476
+ If the destination is `None`, it removes the file or directory. Otherwise,
477
+ it swaps the source and destination, restoring the configuration file
478
+ by copying it back to its original location.
479
+
480
+ Args:
481
+ state (dict): The current default state of configuration files, mapping
482
+ file paths to their source and destination information.
483
+ """
484
+ for k , v in state .items ():
485
+ if v ['dest' ] is None :
486
+ if os .path .exists (k ):
487
+ if os .path .isfile (k ):
488
+ os .remove (k )
489
+ else :
490
+ shutil .rmtree (k )
491
+ else :
492
+ v ['source' ], v ['dest' ] = v ['dest' ], v ['source' ]
493
+ config_file = ConfigFile (** v )
494
+ config_file .copy ()
495
+
496
+
497
+ def backup_configs (config , state ):
498
+ """Back up new configuration files and update the default state.
499
+
500
+ This function processes new configuration files provided in the
501
+ input `config`. For each file, it checks if the destination exists in the
502
+ current state. If not, it backs up the file by copying it to the default
503
+ directory. It then updates the state with the new configuration file's
504
+ information.
505
+
506
+ Args:
507
+ config (dict): The input configuration containing a list of config
508
+ files.
509
+ state (dict): The current default state to be updated with the new
510
+ config files.
511
+ """
512
+ if 'config_files' in config :
513
+ for data in config ['config_files' ]:
514
+ if data ['dest' ] in state .keys ():
515
+ continue
516
+ src = data ['source' ]
517
+ if data ['dest' ].endswith ('/' ):
518
+ dst = data ['dest' ] + data ['source' ].split ('/' )[- 1 ]
519
+ else :
520
+ dst = data ['dest' ]
521
+ default = KOLLA_DEFAULTS + dst
522
+ if os .path .exists (src ):
523
+ copy = {'source' : dst , 'preserve_properties' : True }
524
+ if os .path .exists (dst ):
525
+ copy ['dest' ] = default
526
+ if dst not in state :
527
+ config_file = ConfigFile (** copy )
528
+ config_file .copy ()
529
+ state [dst ] = copy
530
+ else :
531
+ copy ['dest' ] = None
532
+ if dst not in state :
533
+ state [dst ] = copy
534
+
535
+
536
+ def handle_defaults (config ):
537
+ """Handle the default config files by copying/removing them as needed.
538
+
539
+ This function loads the current default state and manages the configuration
540
+ files. It first processes existing configuration files in the default
541
+ state, either removing or restoring them based on their destination status.
542
+ It then backs up any new configuration files from the input config,
543
+ updating the default state accordingly.
544
+
545
+ Args:
546
+ config (dict): A dictionary containing the list of configuration files
547
+ to be handled.
548
+ """
549
+ state = get_defaults_state ()
550
+ remove_or_restore_configs (state )
551
+ backup_configs (config , state )
552
+ set_defaults_state (state )
553
+
554
+
406
555
def execute_config_strategy (config ):
407
556
config_strategy = os .environ .get ("KOLLA_CONFIG_STRATEGY" )
408
557
LOG .info ("Kolla config strategy set to: %s" , config_strategy )
409
558
if config_strategy == "COPY_ALWAYS" :
559
+ handle_defaults (config )
410
560
copy_config (config )
411
561
handle_permissions (config )
412
562
elif config_strategy == "COPY_ONCE" :
@@ -415,6 +565,7 @@ def execute_config_strategy(config):
415
565
"The config strategy prevents copying new configs" ,
416
566
exit_code = 0 )
417
567
else :
568
+ handle_defaults (config )
418
569
copy_config (config )
419
570
handle_permissions (config )
420
571
os .mknod ('/configured' )
0 commit comments