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