Skip to content

Commit 223ed18

Browse files
keukomnasiadka
authored andcommitted
Fix handling configs in base image
This commit restructures the handling of configuration files in set_configs.py, introducing functions for managing default configuration files first. Closes-Bug: #2060855 Change-Id: If91e0330dc149143c82d2183b8ddf6fa9f68d80e (cherry picked from commit 36c1267)
1 parent 4917ef7 commit 223ed18

File tree

3 files changed

+617
-0
lines changed

3 files changed

+617
-0
lines changed

docker/base/set_configs.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
LOG = logging.getLogger(__name__)
3030
LOG.setLevel(logging.INFO)
3131

32+
KOLLA_DEFAULTS = "/etc/kolla/defaults"
33+
KOLLA_DEFAULTS_STATE = KOLLA_DEFAULTS + '/' + 'state'
34+
3235

3336
class ExitingException(Exception):
3437
def __init__(self, message, exit_code=1):
@@ -383,10 +386,157 @@ def set_perms(path, uid, gid, perm):
383386
set_perms(os.path.join(root, file_), uid, gid, perm)
384387

385388

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+
386535
def execute_config_strategy(config):
387536
config_strategy = os.environ.get("KOLLA_CONFIG_STRATEGY")
388537
LOG.info("Kolla config strategy set to: %s", config_strategy)
389538
if config_strategy == "COPY_ALWAYS":
539+
handle_defaults(config)
390540
copy_config(config)
391541
handle_permissions(config)
392542
elif config_strategy == "COPY_ONCE":
@@ -395,6 +545,7 @@ def execute_config_strategy(config):
395545
"The config strategy prevents copying new configs",
396546
exit_code=0)
397547
else:
548+
handle_defaults(config)
398549
copy_config(config)
399550
handle_permissions(config)
400551
os.mknod('/configured')
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
fixes:
3+
- |
4+
Fixes the inconsistency issue between config.json and
5+
real state in the container.
6+
`LP#2060855 <https://launchpad.net/bugs/2060855>`__

0 commit comments

Comments
 (0)