Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for config models #873

Merged
merged 10 commits into from
Dec 11, 2023
152 changes: 151 additions & 1 deletion barman/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1205,9 +1205,10 @@ def diagnose(args=None):
"""
# Get every server (both inactive and temporarily disabled)
servers = get_server_list(on_error_stop=False, suppress_error=True)
models = get_models_list()
# errors list with duplicate paths between servers
errors_list = barman.__config__.servers_msg_list
barman.diagnose.exec_diagnose(servers, errors_list, args.show_config_source)
barman.diagnose.exec_diagnose(servers, models, errors_list, args.show_config_source)
output.close_and_exit()


Expand Down Expand Up @@ -1810,6 +1811,50 @@ def check_wal_archive(args):
output.close_and_exit()


@command(
[
argument(
"server_name",
completer=server_completer,
help="specifies the name of the server which configuration should "
"be override by the model",
),
argument(
"model_name",
help="specifies the name of the model which configuration should "
"override the server configuration. Not used when called with "
"the '--reset' flag",
nargs="?",
),
argument(
"--reset",
help="indicates that we should unapply the currently active model "
"for the server",
action="store_true",
),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add a --reset (or similarly named) option here which would cause Barman to delete the .active-model.audo file?

This could be useful in scenarios where a user removes a model from the configuration while it is still the active model - currently the only way to resolve this case would be to delete the file manually or to config-swtich to a different model for the server.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, makes total sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just submitted a commit with these changes.

)
def config_switch(args):
"""
Change the active configuration for a server by applying a named model on
top of it, or by resetting the active model.
"""
if args.model_name is None and not args.reset:
output.error("Either a model name or '--reset' flag need to be given")
return

server = get_server(args, skip_inactive=False)

if server is not None:
if args.reset:
server.config.reset_model()
else:
model = get_model(args)

if model is not None:
server.config.apply_model(model, True)


def pretty_args(args):
"""
Prettify the given argparse namespace to be human readable
Expand Down Expand Up @@ -2103,6 +2148,111 @@ def manage_server_command(
return True


def get_models_list(args=None):
"""Get the model list from the configuration.

If the *args* parameter is ``None`` returns all defined servers.

:param args: an :class:`argparse.Namespace` containing a list
``model_name`` parameter.

:return: a :class:`dict` -- each key is a model name, and its value the
corresponding :class:`ModelConfig` instance.
"""
model_dict = {}

# This function must to be called with in a multiple-model context
assert not args or isinstance(args.model_name, list)

# Generate the list of models (required for global errors)
available_models = barman.__config__.model_names()

# Handle special *args* is ``None`` case
if not args:
model_names = available_models
else:
# Put models in a set, so multiple occurrences are counted only once
model_names = set(args.model_name)

# Loop through all the requested models
for model_name in model_names:
model = barman.__config__.get_model(model_name)
if model is None:
# Unknown model
model_dict[model_name] = None
else:
model_dict[model_name] = model

return model_dict


def manage_model_command(model, name=None):
"""
Standard and consistent method for managing model errors within a model
command execution.

:param model: :class:`ModelConfig` to be checked for errors.
:param name: name of the model.

:return: ``True`` if the command has to be executed with this model.
"""

# Unknown model (skip it)
if not model:
output.error("Unknown model '%s'" % name)
return False

# All ok, execute the command
return True


def get_model(args, on_error_stop=True):
"""
Get a single model retrieving its configuration (wraps :func:`get_models_list`).

.. warning::
This function modifies the *args* parameter.

:param args: an :class:`argparse.Namespace` containing a single
``model_name`` parameter.
:param on_error_stop: stop if an error is found.

:return: a :class:`ModelConfig` or ``None`` if the required model is
unknown and *on_error_stop* is ``False``.
"""
# This function must to be called with in a single-model context
name = args.model_name
assert isinstance(name, str)

# Builds a list from a single given name
args.model_name = [name]

# Retrieve the requested model
models = get_models_list(args)

# The requested model has been excluded from :func:`get_models_list`` result
if len(models) == 0:
output.close_and_exit()
# The following return statement will never be reached
# but it is here for clarity
return None

# retrieve the model object
model = models[name]

# Apply standard validation control and skips
# the model if invalid, displaying standard
# error messages. If on_error_stop (default) exits
if not manage_model_command(model, name) and on_error_stop:
output.close_and_exit()
# The following return statement will never be reached
# but it is here for clarity
return None

# Returns the filtered model
return model


def parse_backup_id(server, args):
"""
Parses backup IDs including special words such as latest, oldest, etc.
Expand Down
Loading
Loading