Blame SOURCES/bz2158804-01-fix-stonith-watchdog-timeout-validation.patch

3362d5
From 5bed788246ac19c866a60ab3773d94fa4ca28c37 Mon Sep 17 00:00:00 2001
3362d5
From: Miroslav Lisik <mlisik@redhat.com>
3362d5
Date: Thu, 5 Jan 2023 16:21:44 +0100
3362d5
Subject: [PATCH 5/5] Fix stonith-watchdog-timeout validation
3362d5
3362d5
---
3362d5
 pcs/lib/cluster_property.py                   | 25 ++++-
3362d5
 pcs/lib/sbd.py                                | 15 ++-
3362d5
 .../lib/commands/test_cluster_property.py     | 50 ++++++++--
3362d5
 pcs_test/tier0/lib/test_cluster_property.py   | 98 ++++++++++++++-----
3362d5
 pcs_test/tier1/test_cluster_property.py       | 14 ++-
3362d5
 5 files changed, 157 insertions(+), 45 deletions(-)
3362d5
3362d5
diff --git a/pcs/lib/cluster_property.py b/pcs/lib/cluster_property.py
3362d5
index 9ccacd74..b622bdaf 100644
3362d5
--- a/pcs/lib/cluster_property.py
3362d5
+++ b/pcs/lib/cluster_property.py
3362d5
@@ -8,6 +8,7 @@ from lxml.etree import _Element
3362d5
 
3362d5
 from pcs.common import reports
3362d5
 from pcs.common.services.interfaces import ServiceManagerInterface
3362d5
+from pcs.common.tools import timeout_to_seconds
3362d5
 from pcs.common.types import StringSequence
3362d5
 from pcs.lib import (
3362d5
     sbd,
3362d5
@@ -38,8 +39,21 @@ def _validate_stonith_watchdog_timeout_property(
3362d5
     force: bool = False,
3362d5
 ) -> reports.ReportItemList:
3362d5
     report_list: reports.ReportItemList = []
3362d5
+    original_value = value
3362d5
+    # if value is not empty, try to convert time interval string
3362d5
+    if value:
3362d5
+        seconds = timeout_to_seconds(value)
3362d5
+        if seconds is None:
3362d5
+            # returns empty list because this should be reported by
3362d5
+            # ValueTimeInterval validator
3362d5
+            return report_list
3362d5
+        value = str(seconds)
3362d5
     if sbd.is_sbd_enabled(service_manager):
3362d5
-        report_list.extend(sbd.validate_stonith_watchdog_timeout(value, force))
3362d5
+        report_list.extend(
3362d5
+            sbd.validate_stonith_watchdog_timeout(
3362d5
+                validate.ValuePair(original_value, value), force
3362d5
+            )
3362d5
+        )
3362d5
     else:
3362d5
         if value not in ["", "0"]:
3362d5
             report_list.append(
3362d5
@@ -124,9 +138,6 @@ def validate_set_cluster_properties(
3362d5
             # unknow properties are reported by NamesIn validator
3362d5
             continue
3362d5
         property_metadata = possible_properties_dict[property_name]
3362d5
-        if property_metadata.name == "stonith-watchdog-timeout":
3362d5
-            # needs extra validation
3362d5
-            continue
3362d5
         if property_metadata.type == "boolean":
3362d5
             validators.append(
3362d5
                 validate.ValuePcmkBoolean(
3362d5
@@ -154,9 +165,13 @@ def validate_set_cluster_properties(
3362d5
                 )
3362d5
             )
3362d5
         elif property_metadata.type == "time":
3362d5
+            # make stonith-watchdog-timeout value not forcable
3362d5
             validators.append(
3362d5
                 validate.ValueTimeInterval(
3362d5
-                    property_metadata.name, severity=severity
3362d5
+                    property_metadata.name,
3362d5
+                    severity=severity
3362d5
+                    if property_metadata.name != "stonith-watchdog-timeout"
3362d5
+                    else reports.ReportItemSeverity.error(),
3362d5
                 )
3362d5
             )
3362d5
     report_list.extend(
3362d5
diff --git a/pcs/lib/sbd.py b/pcs/lib/sbd.py
3362d5
index 1e3cfb37..38cd8767 100644
3362d5
--- a/pcs/lib/sbd.py
3362d5
+++ b/pcs/lib/sbd.py
3362d5
@@ -1,6 +1,9 @@
3362d5
 import re
3362d5
 from os import path
3362d5
-from typing import Optional
3362d5
+from typing import (
3362d5
+    Optional,
3362d5
+    Union,
3362d5
+)
3362d5
 
3362d5
 from pcs import settings
3362d5
 from pcs.common import reports
3362d5
@@ -392,7 +395,10 @@ def _get_local_sbd_watchdog_timeout() -> int:
3362d5
 
3362d5
 
3362d5
 def validate_stonith_watchdog_timeout(
3362d5
-    stonith_watchdog_timeout: str, force: bool = False
3362d5
+    stonith_watchdog_timeout: Union[
3362d5
+        validate.TypeOptionValue, validate.ValuePair
3362d5
+    ],
3362d5
+    force: bool = False,
3362d5
 ) -> reports.ReportItemList:
3362d5
     """
3362d5
     Check sbd status and config when user is setting stonith-watchdog-timeout
3362d5
@@ -401,6 +407,7 @@ def validate_stonith_watchdog_timeout(
3362d5
 
3362d5
     stonith_watchdog_timeout -- value to be validated
3362d5
     """
3362d5
+    stonith_watchdog_timeout = validate.ValuePair.get(stonith_watchdog_timeout)
3362d5
     severity = reports.get_severity(reports.codes.FORCE, force)
3362d5
     if _is_device_set_local():
3362d5
         return (
3362d5
@@ -412,11 +419,11 @@ def validate_stonith_watchdog_timeout(
3362d5
                     ),
3362d5
                 )
3362d5
             ]
3362d5
-            if stonith_watchdog_timeout not in ["", "0"]
3362d5
+            if stonith_watchdog_timeout.normalized not in ["", "0"]
3362d5
             else []
3362d5
         )
3362d5
 
3362d5
-    if stonith_watchdog_timeout in ["", "0"]:
3362d5
+    if stonith_watchdog_timeout.normalized in ["", "0"]:
3362d5
         return [
3362d5
             reports.ReportItem(
3362d5
                 severity,
3362d5
diff --git a/pcs_test/tier0/lib/commands/test_cluster_property.py b/pcs_test/tier0/lib/commands/test_cluster_property.py
3362d5
index 319d1df6..fd124843 100644
3362d5
--- a/pcs_test/tier0/lib/commands/test_cluster_property.py
3362d5
+++ b/pcs_test/tier0/lib/commands/test_cluster_property.py
3362d5
@@ -120,6 +120,34 @@ class StonithWatchdogTimeoutMixin(LoadMetadataMixin):
3362d5
         )
3362d5
         self.env_assist.assert_reports([])
3362d5
 
3362d5
+    def _set_invalid_value(self, forced=False):
3362d5
+        self.config.remove("services.is_enabled")
3362d5
+        self.env_assist.assert_raise_library_error(
3362d5
+            lambda: cluster_property.set_properties(
3362d5
+                self.env_assist.get_env(),
3362d5
+                {"stonith-watchdog-timeout": "15x"},
3362d5
+                [] if not forced else [reports.codes.FORCE],
3362d5
+            )
3362d5
+        )
3362d5
+        self.env_assist.assert_reports(
3362d5
+            [
3362d5
+                fixture.error(
3362d5
+                    reports.codes.INVALID_OPTION_VALUE,
3362d5
+                    option_name="stonith-watchdog-timeout",
3362d5
+                    option_value="15x",
3362d5
+                    allowed_values="time interval (e.g. 1, 2s, 3m, 4h, ...)",
3362d5
+                    cannot_be_empty=False,
3362d5
+                    forbidden_characters=None,
3362d5
+                ),
3362d5
+            ]
3362d5
+        )
3362d5
+
3362d5
+    def test_set_invalid_value(self):
3362d5
+        self._set_invalid_value(forced=False)
3362d5
+
3362d5
+    def test_set_invalid_value_forced(self):
3362d5
+        self._set_invalid_value(forced=True)
3362d5
+
3362d5
 
3362d5
 class TestSetStonithWatchdogTimeoutSBDIsDisabled(
3362d5
     StonithWatchdogTimeoutMixin, TestCase
3362d5
@@ -132,6 +160,9 @@ class TestSetStonithWatchdogTimeoutSBDIsDisabled(
3362d5
     def test_set_zero(self):
3362d5
         self._set_success({"stonith-watchdog-timeout": "0"})
3362d5
 
3362d5
+    def test_set_zero_time_suffix(self):
3362d5
+        self._set_success({"stonith-watchdog-timeout": "0s"})
3362d5
+
3362d5
     def test_set_not_zero_or_empty(self):
3362d5
         self.env_assist.assert_raise_library_error(
3362d5
             lambda: cluster_property.set_properties(
3362d5
@@ -231,12 +262,12 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledWatchdogOnly(
3362d5
     def test_set_zero_forced(self):
3362d5
         self.config.env.push_cib(
3362d5
             crm_config=fixture_crm_config_properties(
3362d5
-                [("cib-bootstrap-options", {"stonith-watchdog-timeout": "0"})]
3362d5
+                [("cib-bootstrap-options", {"stonith-watchdog-timeout": "0s"})]
3362d5
             )
3362d5
         )
3362d5
         cluster_property.set_properties(
3362d5
             self.env_assist.get_env(),
3362d5
-            {"stonith-watchdog-timeout": "0"},
3362d5
+            {"stonith-watchdog-timeout": "0s"},
3362d5
             [reports.codes.FORCE],
3362d5
         )
3362d5
         self.env_assist.assert_reports(
3362d5
@@ -271,7 +302,7 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledWatchdogOnly(
3362d5
         self.env_assist.assert_raise_library_error(
3362d5
             lambda: cluster_property.set_properties(
3362d5
                 self.env_assist.get_env(),
3362d5
-                {"stonith-watchdog-timeout": "9"},
3362d5
+                {"stonith-watchdog-timeout": "9s"},
3362d5
                 [],
3362d5
             )
3362d5
         )
3362d5
@@ -281,7 +312,7 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledWatchdogOnly(
3362d5
                     reports.codes.STONITH_WATCHDOG_TIMEOUT_TOO_SMALL,
3362d5
                     force_code=reports.codes.FORCE,
3362d5
                     cluster_sbd_watchdog_timeout=10,
3362d5
-                    entered_watchdog_timeout="9",
3362d5
+                    entered_watchdog_timeout="9s",
3362d5
                 )
3362d5
             ]
3362d5
         )
3362d5
@@ -289,12 +320,12 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledWatchdogOnly(
3362d5
     def test_too_small_forced(self):
3362d5
         self.config.env.push_cib(
3362d5
             crm_config=fixture_crm_config_properties(
3362d5
-                [("cib-bootstrap-options", {"stonith-watchdog-timeout": "9"})]
3362d5
+                [("cib-bootstrap-options", {"stonith-watchdog-timeout": "9s"})]
3362d5
             )
3362d5
         )
3362d5
         cluster_property.set_properties(
3362d5
             self.env_assist.get_env(),
3362d5
-            {"stonith-watchdog-timeout": "9"},
3362d5
+            {"stonith-watchdog-timeout": "9s"},
3362d5
             [reports.codes.FORCE],
3362d5
         )
3362d5
         self.env_assist.assert_reports(
3362d5
@@ -302,13 +333,13 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledWatchdogOnly(
3362d5
                 fixture.warn(
3362d5
                     reports.codes.STONITH_WATCHDOG_TIMEOUT_TOO_SMALL,
3362d5
                     cluster_sbd_watchdog_timeout=10,
3362d5
-                    entered_watchdog_timeout="9",
3362d5
+                    entered_watchdog_timeout="9s",
3362d5
                 )
3362d5
             ]
3362d5
         )
3362d5
 
3362d5
     def test_more_than_timeout(self):
3362d5
-        self._set_success({"stonith-watchdog-timeout": "11"})
3362d5
+        self._set_success({"stonith-watchdog-timeout": "11s"})
3362d5
 
3362d5
 
3362d5
 @mock.patch("pcs.lib.sbd.get_local_sbd_device_list", lambda: ["dev1", "dev2"])
3362d5
@@ -323,6 +354,9 @@ class TestSetStonithWatchdogTimeoutSBDIsEnabledSharedDevices(
3362d5
     def test_set_to_zero(self):
3362d5
         self._set_success({"stonith-watchdog-timeout": "0"})
3362d5
 
3362d5
+    def test_set_to_zero_time_suffix(self):
3362d5
+        self._set_success({"stonith-watchdog-timeout": "0min"})
3362d5
+
3362d5
     def test_set_not_zero_or_empty(self):
3362d5
         self.env_assist.assert_raise_library_error(
3362d5
             lambda: cluster_property.set_properties(
3362d5
diff --git a/pcs_test/tier0/lib/test_cluster_property.py b/pcs_test/tier0/lib/test_cluster_property.py
3362d5
index 2feb728d..8d6f90b1 100644
3362d5
--- a/pcs_test/tier0/lib/test_cluster_property.py
3362d5
+++ b/pcs_test/tier0/lib/test_cluster_property.py
3362d5
@@ -83,6 +83,7 @@ FIXTURE_VALID_OPTIONS_DICT = {
3362d5
     "integer_param": "10",
3362d5
     "percentage_param": "20%",
3362d5
     "select_param": "s3",
3362d5
+    "stonith-watchdog-timeout": "0",
3362d5
     "time_param": "5min",
3362d5
 }
3362d5
 
3362d5
@@ -96,6 +97,8 @@ FIXTURE_INVALID_OPTIONS_DICT = {
3362d5
     "have-watchdog": "100",
3362d5
 }
3362d5
 
3362d5
+STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES = ["", "0", "0s"]
3362d5
+
3362d5
 
3362d5
 def _fixture_parameter(name, param_type, default, enum_values):
3362d5
     return ResourceAgentParameter(
3362d5
@@ -239,6 +242,7 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
         sbd_enabled=False,
3362d5
         sbd_devices=False,
3362d5
         force=False,
3362d5
+        valid_value=True,
3362d5
     ):
3362d5
         self.mock_is_sbd_enabled.return_value = sbd_enabled
3362d5
         self.mock_sbd_devices.return_value = ["devices"] if sbd_devices else []
3362d5
@@ -254,9 +258,13 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
             ),
3362d5
             expected_report_list,
3362d5
         )
3362d5
-        if "stonith-watchdog-timeout" in new_properties and (
3362d5
-            new_properties["stonith-watchdog-timeout"]
3362d5
-            or "stonith-watchdog-timeout" in configured_properties
3362d5
+        if (
3362d5
+            "stonith-watchdog-timeout" in new_properties
3362d5
+            and (
3362d5
+                new_properties["stonith-watchdog-timeout"]
3362d5
+                or "stonith-watchdog-timeout" in configured_properties
3362d5
+            )
3362d5
+            and valid_value
3362d5
         ):
3362d5
             self.mock_is_sbd_enabled.assert_called_once_with(
3362d5
                 self.mock_service_manager
3362d5
@@ -266,7 +274,10 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
                 if sbd_devices:
3362d5
                     self.mock_sbd_timeout.assert_not_called()
3362d5
                 else:
3362d5
-                    if new_properties["stonith-watchdog-timeout"] in ["", "0"]:
3362d5
+                    if (
3362d5
+                        new_properties["stonith-watchdog-timeout"]
3362d5
+                        in STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES
3362d5
+                    ):
3362d5
                         self.mock_sbd_timeout.assert_not_called()
3362d5
                     else:
3362d5
                         self.mock_sbd_timeout.assert_called_once_with()
3362d5
@@ -280,6 +291,8 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
             self.mock_sbd_timeout.assert_not_called()
3362d5
 
3362d5
         self.mock_is_sbd_enabled.reset_mock()
3362d5
+        self.mock_sbd_devices.reset_mock()
3362d5
+        self.mock_sbd_timeout.reset_mock()
3362d5
 
3362d5
     def test_no_properties_to_set_or_unset(self):
3362d5
         self.assert_validate_set(
3362d5
@@ -328,7 +341,7 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
         )
3362d5
 
3362d5
     def test_unset_stonith_watchdog_timeout_sbd_disabled(self):
3362d5
-        for value in ["0", ""]:
3362d5
+        for value in STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES:
3362d5
             with self.subTest(value=value):
3362d5
                 self.assert_validate_set(
3362d5
                     ["stonith-watchdog-timeout"],
3362d5
@@ -349,22 +362,27 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
         )
3362d5
 
3362d5
     def test_set_ok_stonith_watchdog_timeout_sbd_enabled_without_devices(self):
3362d5
-        self.assert_validate_set(
3362d5
-            [], {"stonith-watchdog-timeout": "15"}, [], sbd_enabled=True
3362d5
-        )
3362d5
+        for value in ["15", "15s"]:
3362d5
+            with self.subTest(value=value):
3362d5
+                self.assert_validate_set(
3362d5
+                    [],
3362d5
+                    {"stonith-watchdog-timeout": value},
3362d5
+                    [],
3362d5
+                    sbd_enabled=True,
3362d5
+                )
3362d5
 
3362d5
     def test_set_small_stonith_watchdog_timeout_sbd_enabled_without_devices(
3362d5
         self,
3362d5
     ):
3362d5
         self.assert_validate_set(
3362d5
             [],
3362d5
-            {"stonith-watchdog-timeout": "9"},
3362d5
+            {"stonith-watchdog-timeout": "9s"},
3362d5
             [
3362d5
                 fixture.error(
3362d5
                     reports.codes.STONITH_WATCHDOG_TIMEOUT_TOO_SMALL,
3362d5
                     force_code=reports.codes.FORCE,
3362d5
                     cluster_sbd_watchdog_timeout=10,
3362d5
-                    entered_watchdog_timeout="9",
3362d5
+                    entered_watchdog_timeout="9s",
3362d5
                 )
3362d5
             ],
3362d5
             sbd_enabled=True,
3362d5
@@ -387,28 +405,54 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
             force=True,
3362d5
         )
3362d5
 
3362d5
-    def test_set_not_a_number_stonith_watchdog_timeout_sbd_enabled_without_devices(
3362d5
+    def _set_invalid_value_stonith_watchdog_timeout(
3362d5
+        self, sbd_enabled=False, sbd_devices=False
3362d5
+    ):
3362d5
+        for value in ["invalid", "10x"]:
3362d5
+            with self.subTest(value=value):
3362d5
+                self.assert_validate_set(
3362d5
+                    [],
3362d5
+                    {"stonith-watchdog-timeout": value},
3362d5
+                    [
3362d5
+                        fixture.error(
3362d5
+                            reports.codes.INVALID_OPTION_VALUE,
3362d5
+                            option_name="stonith-watchdog-timeout",
3362d5
+                            option_value=value,
3362d5
+                            allowed_values="time interval (e.g. 1, 2s, 3m, 4h, ...)",
3362d5
+                            cannot_be_empty=False,
3362d5
+                            forbidden_characters=None,
3362d5
+                        )
3362d5
+                    ],
3362d5
+                    sbd_enabled=sbd_enabled,
3362d5
+                    sbd_devices=sbd_devices,
3362d5
+                    valid_value=False,
3362d5
+                )
3362d5
+
3362d5
+    def test_set_invalid_value_stonith_watchdog_timeout_sbd_enabled_without_devices(
3362d5
         self,
3362d5
     ):
3362d5
+        self._set_invalid_value_stonith_watchdog_timeout(
3362d5
+            sbd_enabled=True, sbd_devices=False
3362d5
+        )
3362d5
 
3362d5
-        self.assert_validate_set(
3362d5
-            [],
3362d5
-            {"stonith-watchdog-timeout": "invalid"},
3362d5
-            [
3362d5
-                fixture.error(
3362d5
-                    reports.codes.STONITH_WATCHDOG_TIMEOUT_TOO_SMALL,
3362d5
-                    force_code=reports.codes.FORCE,
3362d5
-                    cluster_sbd_watchdog_timeout=10,
3362d5
-                    entered_watchdog_timeout="invalid",
3362d5
-                )
3362d5
-            ],
3362d5
-            sbd_enabled=True,
3362d5
+    def test_set_invalid_value_stonith_watchdog_timeout_sbd_enabled_with_devices(
3362d5
+        self,
3362d5
+    ):
3362d5
+        self._set_invalid_value_stonith_watchdog_timeout(
3362d5
+            sbd_enabled=True, sbd_devices=True
3362d5
+        )
3362d5
+
3362d5
+    def test_set_invalid_value_stonith_watchdog_timeout_sbd_disabled(
3362d5
+        self,
3362d5
+    ):
3362d5
+        self._set_invalid_value_stonith_watchdog_timeout(
3362d5
+            sbd_enabled=False, sbd_devices=False
3362d5
         )
3362d5
 
3362d5
     def test_unset_stonith_watchdog_timeout_sbd_enabled_without_devices(
3362d5
         self,
3362d5
     ):
3362d5
-        for value in ["0", ""]:
3362d5
+        for value in STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES:
3362d5
             with self.subTest(value=value):
3362d5
                 self.assert_validate_set(
3362d5
                     ["stonith-watchdog-timeout"],
3362d5
@@ -426,7 +470,7 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
     def test_unset_stonith_watchdog_timeout_sbd_enabled_without_devices_forced(
3362d5
         self,
3362d5
     ):
3362d5
-        for value in ["0", ""]:
3362d5
+        for value in STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES:
3362d5
             with self.subTest(value=value):
3362d5
                 self.assert_validate_set(
3362d5
                     ["stonith-watchdog-timeout"],
3362d5
@@ -459,7 +503,7 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
     def test_set_stonith_watchdog_timeout_sbd_enabled_with_devices_forced(self):
3362d5
         self.assert_validate_set(
3362d5
             [],
3362d5
-            {"stonith-watchdog-timeout": 15},
3362d5
+            {"stonith-watchdog-timeout": "15s"},
3362d5
             [
3362d5
                 fixture.warn(
3362d5
                     reports.codes.STONITH_WATCHDOG_TIMEOUT_CANNOT_BE_SET,
3362d5
@@ -472,7 +516,7 @@ class TestValidateSetClusterProperties(TestCase):
3362d5
         )
3362d5
 
3362d5
     def test_unset_stonith_watchdog_timeout_sbd_enabled_with_devices(self):
3362d5
-        for value in ["0", ""]:
3362d5
+        for value in STONITH_WATCHDOG_TIMEOUT_UNSET_VALUES:
3362d5
             with self.subTest(value=value):
3362d5
                 self.assert_validate_set(
3362d5
                     ["stonith-watchdog-timeout"],
3362d5
diff --git a/pcs_test/tier1/test_cluster_property.py b/pcs_test/tier1/test_cluster_property.py
3362d5
index ff1f9cfb..51e25efc 100644
3362d5
--- a/pcs_test/tier1/test_cluster_property.py
3362d5
+++ b/pcs_test/tier1/test_cluster_property.py
3362d5
@@ -169,7 +169,7 @@ class TestPropertySet(PropertyMixin, TestCase):
3362d5
 
3362d5
     def test_set_stonith_watchdog_timeout(self):
3362d5
         self.assert_pcs_fail(
3362d5
-            "property set stonith-watchdog-timeout=5".split(),
3362d5
+            "property set stonith-watchdog-timeout=5s".split(),
3362d5
             stdout_full=(
3362d5
                 "Error: stonith-watchdog-timeout can only be unset or set to 0 "
3362d5
                 "while SBD is disabled\n"
3362d5
@@ -179,6 +179,18 @@ class TestPropertySet(PropertyMixin, TestCase):
3362d5
         )
3362d5
         self.assert_resources_xml_in_cib(UNCHANGED_CRM_CONFIG)
3362d5
 
3362d5
+    def test_set_stonith_watchdog_timeout_invalid_value(self):
3362d5
+        self.assert_pcs_fail(
3362d5
+            "property set stonith-watchdog-timeout=5x".split(),
3362d5
+            stdout_full=(
3362d5
+                "Error: '5x' is not a valid stonith-watchdog-timeout value, use"
3362d5
+                " time interval (e.g. 1, 2s, 3m, 4h, ...)\n"
3362d5
+                "Error: Errors have occurred, therefore pcs is unable to "
3362d5
+                "continue\n"
3362d5
+            ),
3362d5
+        )
3362d5
+        self.assert_resources_xml_in_cib(UNCHANGED_CRM_CONFIG)
3362d5
+
3362d5
 
3362d5
 class TestPropertyUnset(PropertyMixin, TestCase):
3362d5
     def test_success(self):
3362d5
-- 
3362d5
2.39.0
3362d5