diff --git a/.werks/17221.md b/.werks/17221.md new file mode 100644 index 00000000000..fe8e5e53c3c --- /dev/null +++ b/.werks/17221.md @@ -0,0 +1,39 @@ +[//]: # (werk v2) +# omd update: Do not trigger conflicts during stateful update + +key | value +---------- | --- +date | 2025-01-13T08:16:03+00:00 +version | 2.4.0b1 +class | fix +edition | cre +component | omd +level | 2 +compatible | yes + +This change affects users, who run into conflicts while updating their site. + +With this Werk, `omd` will automatically choose to continue the update once it is no longer safe to abort the update. + +**Background** + +In [#Werk 16408](https://checkmk.com/werk/16408), it was made possible to safely abort the update if a conflict occurs. +A conflict can occur due to different reasons, for example: + +* An enabled MKPs raises an exception during the update. +* A ruleset is present, which cannot be loaded anymore. +* Files are installed in `local/lib/check_mk/plugins/agent_based`, and they will no longer be loaded in 2.4.0. + +These conflicts need to be resolved, and will prompt the user on whether to continue the update (this behaviour can be changed by selecting a conflict mode). + +However, the update should only be aborted, before the following message is shown: +``` +Completed verifying site configuration. Your site now has version {version}. +``` +This message marks the beginning of the stateful update. +If such a stateful update does not complete, it creates a broken site. + +The verification steps, which detect conflicts, are executed a second time during the stateful update. + +Previously, the verification steps would offer to abort the update. +This would happen even if the user confirmed to continue the update previously and despite the fact that it was no longer safe to abort the update. diff --git a/cmk/update_config/main.py b/cmk/update_config/main.py index 621a6a450be..d39fb749804 100644 --- a/cmk/update_config/main.py +++ b/cmk/update_config/main.py @@ -136,7 +136,8 @@ def _parse_arguments(args: Sequence[str]) -> argparse.Namespace: type=ConflictMode, help=( f"If you choose '{ConflictMode.ASK}', you will need to manually answer all upcoming questions. " - f"With '{ConflictMode.INSTALL}' or '{ConflictMode.KEEP_OLD}' no interaction is needed. " + f"With '{ConflictMode.FORCE}', '{ConflictMode.INSTALL}' or '{ConflictMode.KEEP_OLD}' no interaction is needed. " + f"'{ConflictMode.FORCE}' continues the update even if errors occur during the pre-flight checks. " f"If you choose '{ConflictMode.ABORT}', the update will be aborted if interaction is needed." ), ) diff --git a/cmk/update_config/plugins/lib/pagetypes.py b/cmk/update_config/plugins/lib/pagetypes.py index 30fa2279da3..b452a2099a5 100644 --- a/cmk/update_config/plugins/lib/pagetypes.py +++ b/cmk/update_config/plugins/lib/pagetypes.py @@ -111,6 +111,8 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None: def _continue_per_users_choice(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/cmk/update_config/plugins/pre_actions/agent_based_plugins.py b/cmk/update_config/plugins/pre_actions/agent_based_plugins.py index e9b4073affe..e1efdbc7518 100644 --- a/cmk/update_config/plugins/pre_actions/agent_based_plugins.py +++ b/cmk/update_config/plugins/pre_actions/agent_based_plugins.py @@ -82,6 +82,8 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None: def _continue_per_users_choice(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/cmk/update_config/plugins/pre_actions/legacy_check_plugins.py b/cmk/update_config/plugins/pre_actions/legacy_check_plugins.py index 0b36d653f8c..1757d382114 100644 --- a/cmk/update_config/plugins/pre_actions/legacy_check_plugins.py +++ b/cmk/update_config/plugins/pre_actions/legacy_check_plugins.py @@ -35,6 +35,8 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None: def _continue_on_incomp_legacy_check(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/cmk/update_config/plugins/pre_actions/rulesets.py b/cmk/update_config/plugins/pre_actions/rulesets.py index b0431028367..bb941253599 100644 --- a/cmk/update_config/plugins/pre_actions/rulesets.py +++ b/cmk/update_config/plugins/pre_actions/rulesets.py @@ -72,6 +72,8 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None: def _continue_on_broken_ruleset(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.UPDATE case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: @@ -84,6 +86,8 @@ def _continue_on_broken_ruleset(conflict_mode: ConflictMode) -> Resume: def _continue_on_invalid_rule(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: @@ -96,6 +100,8 @@ def _continue_on_invalid_rule(conflict_mode: ConflictMode) -> Resume: def _continue_on_ruleset_exception(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/cmk/update_config/plugins/pre_actions/ui_extensions.py b/cmk/update_config/plugins/pre_actions/ui_extensions.py index 7ff03079479..bfe16706bfb 100644 --- a/cmk/update_config/plugins/pre_actions/ui_extensions.py +++ b/cmk/update_config/plugins/pre_actions/ui_extensions.py @@ -92,6 +92,8 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None: def _continue_on_incomp_local_file(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/cmk/update_config/plugins/pre_actions/utils.py b/cmk/update_config/plugins/pre_actions/utils.py index 932f9e0d569..ae72bfe79d1 100644 --- a/cmk/update_config/plugins/pre_actions/utils.py +++ b/cmk/update_config/plugins/pre_actions/utils.py @@ -90,6 +90,7 @@ class ConflictMode(enum.StrEnum): INSTALL = "install" KEEP_OLD = "keepold" ABORT = "abort" + FORCE = "force" _USER_INPUT_ABORT: Final = ("a", "abort") @@ -134,6 +135,8 @@ def disable_incomp_mkp( def _request_user_input_on_incompatible_file(conflict_mode: ConflictMode) -> Resume: match conflict_mode: + case ConflictMode.FORCE: + return Resume.UPDATE case ConflictMode.ABORT: return Resume.ABORT case ConflictMode.INSTALL | ConflictMode.KEEP_OLD: diff --git a/omd/packages/check_mk/scripts/update-pre-hooks/02_cmk-update-config b/omd/packages/check_mk/scripts/update-pre-hooks/02_cmk-update-config index 4ed9e047d59..bf7dd99e435 100644 --- a/omd/packages/check_mk/scripts/update-pre-hooks/02_cmk-update-config +++ b/omd/packages/check_mk/scripts/update-pre-hooks/02_cmk-update-config @@ -1,2 +1,2 @@ #!/bin/bash -cmk-update-config "--conflict" "$OMD_CONFLICT_MODE" +cmk-update-config "--conflict" force