Skip to content

Commit

Permalink
17220 FIX cmk-update-config: No Default in Conflict Mode 'ask'
Browse files Browse the repository at this point in the history
This commit squashes the changes with ID:
Ib5d7e5f510a2081dbddd14bfab445812e361169e
Ibf29461625004370a0bed207ca315a09c191c29d
I4e846d10200ecbbb21bc9e9587f643c07e9ef4c1
I06751b29f2b7ff46fbe8230e58fc4ca421ea2cc7

CMK-20944
CMK-20945
SUP-21895

Change-Id: I62d826a849b1b2aadc168bf4be0f4ec634dbe923
  • Loading branch information
SoloJacobs committed Jan 13, 2025
1 parent 6fea1dd commit a47bd87
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 78 deletions.
20 changes: 20 additions & 0 deletions .werks/17220.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[//]: # (werk v2)
# cmk-update-config: No Default in Conflict Mode 'ask'

key | value
---------- | ---
date | 2025-01-08T10:23:54+00:00
version | 2.3.0p25
class | fix
edition | cre
component | omd
level | 1
compatible | yes

This change affects the update process (either using `cmk-update-config` or `omd update`).
Sites may have configuration, MKPs and other local files, which are incompatible with the version targeted by omd update.
If such a problem occurs, then the user may be prompted for input.
In the past, if the user typed any input other than `c`, `continue`, `d`, `disable`, then the update would be aborted.
This would lead to an aborted update in case of simple typos such as `contnue`.
With this Werk, the update only accepts the following for input strings: `a`, `abort`, `c`, `continue`, `d`, `disable`.
If anything else is typed, then the user will be prompted repeatedly until some valid input is provided.
19 changes: 17 additions & 2 deletions cmk/update_config/plugins/pre_actions/agent_based_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
from cmk.update_config.plugins.pre_actions.utils import (
AGENT_BASED_PLUGINS_PREACTION_SORT_INDEX,
ConflictMode,
continue_on_incomp_local_file,
continue_per_users_choice,
disable_incomp_mkp,
error_message_incomp_local_file,
get_installer_and_package_map,
get_path_config,
is_applicable_mkp,
PACKAGE_STORE,
Resume,
)
from cmk.update_config.registry import pre_update_action_registry, PreUpdateAction

Expand Down Expand Up @@ -52,7 +53,7 @@ def _disable_failure_and_reload_plugins(
# unpackaged files
if manifest is None:
logger.error(error_message_incomp_local_file(path, error))
if continue_on_incomp_local_file(conflict_mode):
if _continue_on_incomp_local_file(conflict_mode).is_not_abort():
continue
raise MKUserError(None, "incompatible local file")

Expand Down Expand Up @@ -87,6 +88,20 @@ def _disable_failure_and_reload_plugins(
return False


def _continue_on_incomp_local_file(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.ABORT
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) and try to fix "
"the incompatibilities or continue the update (c).\n\n"
"Abort the update process? [A/c] \n",
)


pre_update_action_registry.register(
PreUpdateAgentBasedPlugins(
name="agent_based_plugins",
Expand Down
26 changes: 18 additions & 8 deletions cmk/update_config/plugins/pre_actions/autochecks.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
AUTOCHECK_REWRITE_PREACTION_SORT_INDEX,
ConflictMode,
continue_per_users_choice,
Resume,
)
from cmk.update_config.registry import pre_update_action_registry, PreUpdateAction

Expand All @@ -33,12 +34,12 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
for error in rewrite_yielding_errors(write=False):
if error.plugin is None:
logger.error(f"{error.host_name}: {error.message}.")
if continue_per_users_choice(
conflict_mode,
if _continue_on_failed_to_migrate(
" You can abort and fix this manually."
" If you continue, the affected service(s) will be lost, but can be rediscovered."
" Abort the update process? [A/c] \n",
):
conflict_mode,
).is_not_abort():
continue
raise MKUserError(None, "Failed to migrate autochecks")

Expand All @@ -55,14 +56,23 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
all_messages = list(itertools.chain(*hosts.values()))

logger.error(f"{plugin}: {all_messages[0]}. ")
if continue_per_users_choice(
conflict_mode,
if _continue_on_failed_to_migrate(
"You can abort and fix this manually. "
f"If you continue, {len(all_messages)} service(s) on {len(hosts)} host(s) will be lost, but can be rediscovered."
" Abort the update process? [A/c] \n",
):
continue
raise MKUserError(None, "Failed to migrate autochecks")
conflict_mode,
).is_abort():
raise MKUserError(None, "Failed to migrate autochecks")


def _continue_on_failed_to_migrate(prompt: str, conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.ABORT
case ConflictMode.ASK:
return continue_per_users_choice(prompt)


pre_update_action_registry.register(
Expand Down
19 changes: 14 additions & 5 deletions cmk/update_config/plugins/pre_actions/legacy_check_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from cmk.update_config.plugins.pre_actions.utils import (
ConflictMode,
continue_per_users_choice,
Resume,
)
from cmk.update_config.registry import pre_update_action_registry, PreUpdateAction

Expand All @@ -31,13 +32,21 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
)
if errors:
logger.error(errors)
if continue_per_users_choice(
conflict_mode,
if _continue_on_incomp_legacy_check(conflict_mode).is_abort():
raise MKUserError(None, "incompatible local legacy check file(s)")


def _continue_on_incomp_legacy_check(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.ABORT
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) and try to fix the incompatibilities or "
"continue the update (c).\n\nAbort the update process? [A/c] \n",
):
return
raise MKUserError(None, "incompatible local legacy check file(s)")
)


pre_update_action_registry.register(
Expand Down
78 changes: 43 additions & 35 deletions cmk/update_config/plugins/pre_actions/rulesets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

from collections.abc import Sequence
from logging import Logger
from typing import assert_never

from cmk.utils import version
from cmk.utils.log import VERBOSE
Expand All @@ -24,8 +23,8 @@
from cmk.update_config.plugins.actions.rulesets import REPLACED_RULESETS
from cmk.update_config.plugins.pre_actions.utils import (
ConflictMode,
prompt,
USER_INPUT_CONTINUE,
continue_per_users_choice,
Resume,
)
from cmk.update_config.registry import pre_update_action_registry, PreUpdateAction

Expand All @@ -40,10 +39,7 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
rulesets = AllRulesets.load_all_rulesets()
except Exception as exc:
logger.error(f"Exception while trying to load rulesets: {exc}\n\n")
if (
conflict_mode is ConflictMode.ASK
and _request_user_input_on_ruleset_exception().lower() in USER_INPUT_CONTINUE
):
if _continue_on_ruleset_exception(conflict_mode).is_not_abort():
return None
raise MKUserError(None, "an incompatible ruleset") from exc

Expand All @@ -65,25 +61,50 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
ruleset.name,
)
logger.exception("This is the exception: ")
if conflict_mode is ConflictMode.ASK:
user_input = prompt(
"You can abort the update process (A) or continue (c) the update. Abort update? [A/c]\n"
)
if not user_input.lower() in USER_INPUT_CONTINUE:
raise MKUserError(None, "broken ruleset")
if _continue_on_broken_ruleset(conflict_mode).is_abort():
raise MKUserError(None, "broken ruleset")

if not result:
raise MKUserError(None, "failed ruleset validation")

return None


def _request_user_input_on_ruleset_exception() -> str:
return prompt(
"You can abort the update process (A) and try to fix "
"the incompatibilities or try to continue the update (c).\n"
"Abort update? [A/c]\n"
)
def _continue_on_broken_ruleset(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.UPDATE
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.UPDATE
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) or continue (c) the update. Abort update? [A/c]\n"
)


def _continue_on_invalid_rule(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.UPDATE
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) or continue (c) the update. Abort update? [A/c]\n"
)


def _continue_on_ruleset_exception(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.ABORT
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) and try to fix "
"the incompatibilities or try to continue the update (c).\n"
"Abort update? [A/c]\n"
)


def _validate_rule_values(
Expand Down Expand Up @@ -147,21 +168,8 @@ def _validate_rule_values(
addition_info = []
error_message = _error_message(ruleset, folder, index, e, addition_info)
logger.error(error_message)
match conflict_mode:
case ConflictMode.ABORT:
return False
case ConflictMode.ASK:
if (
prompt(
"You can abort the update process (A) or continue (c) the update. Abort update? [A/c]\n"
).lower()
not in USER_INPUT_CONTINUE
):
return False
case ConflictMode.KEEP_OLD | ConflictMode.INSTALL:
continue
case _:
assert_never(conflict_mode)
if _continue_on_invalid_rule(conflict_mode).is_abort():
return False

return True

Expand Down
19 changes: 17 additions & 2 deletions cmk/update_config/plugins/pre_actions/ui_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
from cmk.mkp_tool import Manifest, PackageID
from cmk.update_config.plugins.pre_actions.utils import (
ConflictMode,
continue_on_incomp_local_file,
continue_per_users_choice,
disable_incomp_mkp,
error_message_incomp_local_file,
get_installer_and_package_map,
get_path_config,
GUI_PLUGINS_PREACTION_SORT_INDEX,
is_applicable_mkp,
PACKAGE_STORE,
Resume,
)
from cmk.update_config.registry import pre_update_action_registry, PreUpdateAction

Expand Down Expand Up @@ -55,7 +56,7 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
# unpackaged files
if manifest is None:
logger.error(error_message_incomp_local_file(path, error))
if continue_on_incomp_local_file(conflict_mode):
if _continue_on_incomp_local_file(conflict_mode).is_not_abort():
continue
raise MKUserError(None, "incompatible local file")

Expand Down Expand Up @@ -95,6 +96,20 @@ def __call__(self, logger: Logger, conflict_mode: ConflictMode) -> None:
print(e)


def _continue_on_incomp_local_file(conflict_mode: ConflictMode) -> Resume:
match conflict_mode:
case ConflictMode.ABORT:
return Resume.ABORT
case ConflictMode.INSTALL | ConflictMode.KEEP_OLD:
return Resume.ABORT
case ConflictMode.ASK:
return continue_per_users_choice(
"You can abort the update process (A) and try to fix "
"the incompatibilities or continue the update (c).\n\n"
"Abort the update process? [A/c] \n",
)


pre_update_action_registry.register(
PreUpdateUIExtensions(
name="ui_extensions",
Expand Down
Loading

0 comments on commit a47bd87

Please sign in to comment.