Blame SOURCES/bz1522813-01-fix-a-crash-when-wait-is-used-in-stonith-create.patch

a3a2ad
From 663143e3abbf2798a3c780c691242511b64046a2 Mon Sep 17 00:00:00 2001
a3a2ad
From: Tomas Jelinek <tojeline@redhat.com>
a3a2ad
Date: Wed, 6 Dec 2017 17:38:15 +0100
a3a2ad
Subject: [PATCH] fix a crash when --wait is used in stonith create
a3a2ad
a3a2ad
---
a3a2ad
 pcs/lib/commands/stonith.py                       |  19 ++-
a3a2ad
 pcs/lib/commands/test/test_stonith.py             | 188 ++++++++++++++++++++++
a3a2ad
 pcs/lib/resource_agent.py                         |   4 +
a3a2ad
 pcs/test/resources/stonith_agent_fence_simple.xml |  33 ++++
a3a2ad
 pcs/test/resources/stonithd_metadata.xml          | 156 ++++++++++++++++++
a3a2ad
 pcs/test/tools/command_env/config_runner_pcmk.py  |  36 +++++
a3a2ad
 6 files changed, 430 insertions(+), 6 deletions(-)
a3a2ad
 create mode 100644 pcs/lib/commands/test/test_stonith.py
a3a2ad
 create mode 100644 pcs/test/resources/stonith_agent_fence_simple.xml
a3a2ad
 create mode 100644 pcs/test/resources/stonithd_metadata.xml
a3a2ad
a3a2ad
diff --git a/pcs/lib/commands/stonith.py b/pcs/lib/commands/stonith.py
a3a2ad
index bb9fb98..584e1b2 100644
a3a2ad
--- a/pcs/lib/commands/stonith.py
a3a2ad
+++ b/pcs/lib/commands/stonith.py
a3a2ad
@@ -4,11 +4,14 @@ from __future__ import (
a3a2ad
     print_function,
a3a2ad
 )
a3a2ad
 
a3a2ad
-from pcs.lib.resource_agent import find_valid_stonith_agent_by_name as get_agent
a3a2ad
 from pcs.lib.cib import resource
a3a2ad
 from pcs.lib.cib.resource.common import are_meta_disabled
a3a2ad
+from pcs.lib.commands.resource import (
a3a2ad
+    _ensure_disabled_after_wait,
a3a2ad
+    resource_environment
a3a2ad
+)
a3a2ad
 from pcs.lib.pacemaker.values import validate_id
a3a2ad
-from pcs.lib.commands.resource import resource_environment
a3a2ad
+from pcs.lib.resource_agent import find_valid_stonith_agent_by_name as get_agent
a3a2ad
 
a3a2ad
 def create(
a3a2ad
     env, stonith_id, stonith_agent_name,
a3a2ad
@@ -55,8 +58,10 @@ def create(
a3a2ad
     with resource_environment(
a3a2ad
         env,
a3a2ad
         wait,
a3a2ad
-        stonith_id,
a3a2ad
-        ensure_disabled or are_meta_disabled(meta_attributes),
a3a2ad
+        [stonith_id],
a3a2ad
+        _ensure_disabled_after_wait(
a3a2ad
+            ensure_disabled or are_meta_disabled(meta_attributes),
a3a2ad
+        )
a3a2ad
     ) as resources_section:
a3a2ad
         stonith_element = resource.primitive.create(
a3a2ad
             env.report_processor,
a3a2ad
@@ -125,8 +130,10 @@ def create_in_group(
a3a2ad
     with resource_environment(
a3a2ad
         env,
a3a2ad
         wait,
a3a2ad
-        stonith_id,
a3a2ad
-        ensure_disabled or are_meta_disabled(meta_attributes),
a3a2ad
+        [stonith_id],
a3a2ad
+        _ensure_disabled_after_wait(
a3a2ad
+            ensure_disabled or are_meta_disabled(meta_attributes),
a3a2ad
+        )
a3a2ad
     ) as resources_section:
a3a2ad
         stonith_element = resource.primitive.create(
a3a2ad
             env.report_processor, resources_section,
a3a2ad
diff --git a/pcs/lib/commands/test/test_stonith.py b/pcs/lib/commands/test/test_stonith.py
a3a2ad
new file mode 100644
a3a2ad
index 0000000..912742f
a3a2ad
--- /dev/null
a3a2ad
+++ b/pcs/lib/commands/test/test_stonith.py
a3a2ad
@@ -0,0 +1,188 @@
a3a2ad
+from __future__ import (
a3a2ad
+    absolute_import,
a3a2ad
+    division,
a3a2ad
+    print_function,
a3a2ad
+)
a3a2ad
+
a3a2ad
+from pcs.common import report_codes
a3a2ad
+from pcs.lib.commands import stonith
a3a2ad
+from pcs.lib.resource_agent import StonithAgent
a3a2ad
+from pcs.test.tools import fixture
a3a2ad
+from pcs.test.tools.command_env import get_env_tools
a3a2ad
+from pcs.test.tools.pcs_unittest import TestCase
a3a2ad
+
a3a2ad
+
a3a2ad
+class Create(TestCase):
a3a2ad
+    def setUp(self):
a3a2ad
+        self.env_assist, self.config = get_env_tools(test_case=self)
a3a2ad
+        self.agent_name = "test_simple"
a3a2ad
+        self.instance_name = "stonith-test"
a3a2ad
+        self.timeout = 10
a3a2ad
+        self.expected_cib = """
a3a2ad
+            <resources>
a3a2ad
+                <primitive class="stonith" id="stonith-test" type="test_simple">
a3a2ad
+                    <instance_attributes id="stonith-test-instance_attributes">
a3a2ad
+                        
a3a2ad
+                            name="must-set" value="value"
a3a2ad
+                        />
a3a2ad
+                    </instance_attributes>
a3a2ad
+                    <operations>
a3a2ad
+                        
a3a2ad
+                            interval="60s" name="monitor"
a3a2ad
+                        />
a3a2ad
+                    </operations>
a3a2ad
+                </primitive>
a3a2ad
+            </resources>
a3a2ad
+        """
a3a2ad
+        self.expected_status = """
a3a2ad
+            <resources>
a3a2ad
+                
a3a2ad
+                    id="{id}"
a3a2ad
+                    resource_agent="stonith:{agent}"
a3a2ad
+                    role="Started"
a3a2ad
+                    active="true"
a3a2ad
+                    failed="false"
a3a2ad
+                    nodes_running_on="1"
a3a2ad
+                >
a3a2ad
+                    <node name="node1" id="1" cached="false"/>
a3a2ad
+                </resource>
a3a2ad
+            </resources>
a3a2ad
+            """.format(id=self.instance_name, agent=self.agent_name)
a3a2ad
+        (self.config
a3a2ad
+            .runner.pcmk.load_agent(
a3a2ad
+                agent_name="stonith:{0}".format(self.agent_name),
a3a2ad
+                agent_filename="stonith_agent_fence_simple.xml"
a3a2ad
+            )
a3a2ad
+            .runner.cib.load()
a3a2ad
+            .runner.pcmk.load_stonithd_metadata()
a3a2ad
+        )
a3a2ad
+
a3a2ad
+    def tearDown(self):
a3a2ad
+        StonithAgent.clear_stonithd_metadata_cache()
a3a2ad
+
a3a2ad
+    def test_minimal_success(self):
a3a2ad
+        self.config.env.push_cib(resources=self.expected_cib)
a3a2ad
+        stonith.create(
a3a2ad
+            self.env_assist.get_env(),
a3a2ad
+            self.instance_name,
a3a2ad
+            self.agent_name,
a3a2ad
+            operations=[],
a3a2ad
+            meta_attributes={},
a3a2ad
+            instance_attributes={"must-set": "value"}
a3a2ad
+        )
a3a2ad
+
a3a2ad
+    def test_minimal_wait_ok_run_ok(self):
a3a2ad
+        (self.config
a3a2ad
+            .runner.pcmk.can_wait(before="runner.cib.load")
a3a2ad
+            .env.push_cib(
a3a2ad
+                resources=self.expected_cib,
a3a2ad
+                wait=self.timeout
a3a2ad
+            )
a3a2ad
+            .runner.pcmk.load_state(resources=self.expected_status)
a3a2ad
+        )
a3a2ad
+        stonith.create(
a3a2ad
+            self.env_assist.get_env(),
a3a2ad
+            self.instance_name,
a3a2ad
+            self.agent_name,
a3a2ad
+            operations=[],
a3a2ad
+            meta_attributes={},
a3a2ad
+            instance_attributes={"must-set": "value"},
a3a2ad
+            wait=self.timeout
a3a2ad
+        )
a3a2ad
+        self.env_assist.assert_reports([
a3a2ad
+            fixture.info(
a3a2ad
+                report_codes.RESOURCE_RUNNING_ON_NODES,
a3a2ad
+                roles_with_nodes={"Started": ["node1"]},
a3a2ad
+                resource_id=self.instance_name,
a3a2ad
+            ),
a3a2ad
+        ])
a3a2ad
+
a3a2ad
+
a3a2ad
+class CreateInGroup(TestCase):
a3a2ad
+    def setUp(self):
a3a2ad
+        self.env_assist, self.config = get_env_tools(test_case=self)
a3a2ad
+        self.agent_name = "test_simple"
a3a2ad
+        self.instance_name = "stonith-test"
a3a2ad
+        self.timeout = 10
a3a2ad
+        self.expected_cib = """
a3a2ad
+            <resources>
a3a2ad
+            <group id="my-group">
a3a2ad
+                <primitive class="stonith" id="stonith-test" type="test_simple">
a3a2ad
+                    <instance_attributes id="stonith-test-instance_attributes">
a3a2ad
+                        
a3a2ad
+                            name="must-set" value="value"
a3a2ad
+                        />
a3a2ad
+                    </instance_attributes>
a3a2ad
+                    <operations>
a3a2ad
+                        
a3a2ad
+                            interval="60s" name="monitor"
a3a2ad
+                        />
a3a2ad
+                    </operations>
a3a2ad
+                </primitive>
a3a2ad
+            </group>
a3a2ad
+            </resources>
a3a2ad
+        """
a3a2ad
+        self.expected_status = """
a3a2ad
+            <resources>
a3a2ad
+                
a3a2ad
+                    id="{id}"
a3a2ad
+                    resource_agent="stonith:{agent}"
a3a2ad
+                    role="Started"
a3a2ad
+                    active="true"
a3a2ad
+                    failed="false"
a3a2ad
+                    nodes_running_on="1"
a3a2ad
+                >
a3a2ad
+                    <node name="node1" id="1" cached="false"/>
a3a2ad
+                </resource>
a3a2ad
+            </resources>
a3a2ad
+            """.format(id=self.instance_name, agent=self.agent_name)
a3a2ad
+        (self.config
a3a2ad
+            .runner.pcmk.load_agent(
a3a2ad
+                agent_name="stonith:{0}".format(self.agent_name),
a3a2ad
+                agent_filename="stonith_agent_fence_simple.xml"
a3a2ad
+            )
a3a2ad
+            .runner.cib.load()
a3a2ad
+            .runner.pcmk.load_stonithd_metadata()
a3a2ad
+        )
a3a2ad
+
a3a2ad
+    def tearDown(self):
a3a2ad
+        StonithAgent.clear_stonithd_metadata_cache()
a3a2ad
+
a3a2ad
+    def test_minimal_success(self):
a3a2ad
+        self.config.env.push_cib(resources=self.expected_cib)
a3a2ad
+        stonith.create_in_group(
a3a2ad
+            self.env_assist.get_env(),
a3a2ad
+            self.instance_name,
a3a2ad
+            self.agent_name,
a3a2ad
+            "my-group",
a3a2ad
+            operations=[],
a3a2ad
+            meta_attributes={},
a3a2ad
+            instance_attributes={"must-set": "value"}
a3a2ad
+        )
a3a2ad
+
a3a2ad
+    def test_minimal_wait_ok_run_ok(self):
a3a2ad
+        (self.config
a3a2ad
+            .runner.pcmk.can_wait(before="runner.cib.load")
a3a2ad
+            .env.push_cib(
a3a2ad
+                resources=self.expected_cib,
a3a2ad
+                wait=self.timeout
a3a2ad
+            )
a3a2ad
+            .runner.pcmk.load_state(resources=self.expected_status)
a3a2ad
+        )
a3a2ad
+        stonith.create_in_group(
a3a2ad
+            self.env_assist.get_env(),
a3a2ad
+            self.instance_name,
a3a2ad
+            self.agent_name,
a3a2ad
+            "my-group",
a3a2ad
+            operations=[],
a3a2ad
+            meta_attributes={},
a3a2ad
+            instance_attributes={"must-set": "value"},
a3a2ad
+            wait=self.timeout
a3a2ad
+        )
a3a2ad
+        self.env_assist.assert_reports([
a3a2ad
+            fixture.info(
a3a2ad
+                report_codes.RESOURCE_RUNNING_ON_NODES,
a3a2ad
+                roles_with_nodes={"Started": ["node1"]},
a3a2ad
+                resource_id=self.instance_name,
a3a2ad
+            ),
a3a2ad
+        ])
a3a2ad
diff --git a/pcs/lib/resource_agent.py b/pcs/lib/resource_agent.py
a3a2ad
index 4639477..2f2686d 100644
a3a2ad
--- a/pcs/lib/resource_agent.py
a3a2ad
+++ b/pcs/lib/resource_agent.py
a3a2ad
@@ -836,6 +836,10 @@ class StonithAgent(CrmAgent):
a3a2ad
     """
a3a2ad
     _stonithd_metadata = None
a3a2ad
 
a3a2ad
+    @classmethod
a3a2ad
+    def clear_stonithd_metadata_cache(cls):
a3a2ad
+        cls._stonithd_metadata = None
a3a2ad
+
a3a2ad
     def _prepare_name_parts(self, name):
a3a2ad
         # pacemaker doesn't support stonith (nor resource) agents with : in type
a3a2ad
         if ":" in name:
a3a2ad
diff --git a/pcs/test/resources/stonith_agent_fence_simple.xml b/pcs/test/resources/stonith_agent_fence_simple.xml
a3a2ad
new file mode 100644
a3a2ad
index 0000000..bb86af2
a3a2ad
--- /dev/null
a3a2ad
+++ b/pcs/test/resources/stonith_agent_fence_simple.xml
a3a2ad
@@ -0,0 +1,33 @@
a3a2ad
+
a3a2ad
+
a3a2ad
+  name="fence_simple"
a3a2ad
+  shortdesc="Basic fence agent for pcs tests"
a3a2ad
+>
a3a2ad
+  <longdesc>
a3a2ad
+    This is a testing fence agent. Its purpose is to provide a mock of a fence
a3a2ad
+    agent which is always available no matter what is the configuration of a
a3a2ad
+    system pcs test suite runs on.
a3a2ad
+  </longdesc>
a3a2ad
+  <vendor-url>https://github.com/ClusterLabs/pcs</vendor-url>
a3a2ad
+  <parameters>
a3a2ad
+    <parameter name="must-set" unique="0" required="1">
a3a2ad
+      <content type="string" />
a3a2ad
+      <shortdesc lang="en">An example of a required attribute</shortdesc>
a3a2ad
+    </parameter>
a3a2ad
+    <parameter name="may-set" unique="0" required="0">
a3a2ad
+      <content type="string" />
a3a2ad
+      <shortdesc lang="en">An example of an optional attribute</shortdesc>
a3a2ad
+    </parameter>
a3a2ad
+  </parameters>
a3a2ad
+  <actions>
a3a2ad
+    <action name="on" automatic="0"/>
a3a2ad
+    <action name="off" />
a3a2ad
+    <action name="reboot" />
a3a2ad
+    <action name="status" />
a3a2ad
+    <action name="list" />
a3a2ad
+    <action name="list-status" />
a3a2ad
+    <action name="monitor" />
a3a2ad
+    <action name="metadata" />
a3a2ad
+    <action name="validate-all" />
a3a2ad
+  </actions>
a3a2ad
+</resource-agent>
a3a2ad
diff --git a/pcs/test/resources/stonithd_metadata.xml b/pcs/test/resources/stonithd_metadata.xml
a3a2ad
new file mode 100644
a3a2ad
index 0000000..fc638a2
a3a2ad
--- /dev/null
a3a2ad
+++ b/pcs/test/resources/stonithd_metadata.xml
a3a2ad
@@ -0,0 +1,156 @@
a3a2ad
+
a3a2ad
+<resource-agent name="stonithd">
a3a2ad
+ <version>1.0</version>
a3a2ad
+ <longdesc lang="en">This is a fake resource that details the instance attributes handled by stonithd.</longdesc>
a3a2ad
+ <shortdesc lang="en">Options available for all stonith resources</shortdesc>
a3a2ad
+ <parameters>
a3a2ad
+  <parameter name="priority" unique="0">
a3a2ad
+    <shortdesc lang="en">The priority of the stonith resource. Devices are tried in order of highest priority to lowest.</shortdesc>
a3a2ad
+    <content type="integer" default="0"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_host_argument" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate parameter to supply instead of 'port'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard 'port' parameter or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, parameter that should indicate the machine to be fenced.
a3a2ad
+A value of 'none' can be used to tell the cluster not to supply any additional parameters.
a3a2ad
+     </longdesc>
a3a2ad
+    <content type="string" default="port"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_host_map" unique="0">
a3a2ad
+    <shortdesc lang="en">A mapping of host names to ports numbers for devices that do not support host names.</shortdesc>
a3a2ad
+    <longdesc lang="en">Eg. node1:1;node2:2,3 would tell the cluster to use port 1 for node1 and ports 2 and 3 for node2</longdesc>
a3a2ad
+    <content type="string" default=""/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_host_list" unique="0">
a3a2ad
+    <shortdesc lang="en">A list of machines controlled by this device (Optional unless pcmk_host_check=static-list).</shortdesc>
a3a2ad
+    <content type="string" default=""/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_host_check" unique="0">
a3a2ad
+    <shortdesc lang="en">How to determine which machines are controlled by the device.</shortdesc>
a3a2ad
+    <longdesc lang="en">Allowed values: dynamic-list (query the device), static-list (check the pcmk_host_list attribute), none (assume every device can fence every machine)</longdesc>
a3a2ad
+    <content type="string" default="dynamic-list"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_delay_max" unique="0">
a3a2ad
+    <shortdesc lang="en">Enable a random delay for stonith actions and specify the maximum of random delay.</shortdesc>
a3a2ad
+    <longdesc lang="en">This prevents double fencing when using slow devices such as sbd.
a3a2ad
+Use this to enable a random delay for stonith actions.
a3a2ad
+The overall delay is derived from this random delay value adding a static delay so that the sum is kept below the maximum delay.</longdesc>
a3a2ad
+    <content type="time" default="0s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_delay_base" unique="0">
a3a2ad
+    <shortdesc lang="en">Enable a base delay for stonith actions and specify base delay value.</shortdesc>
a3a2ad
+    <longdesc lang="en">This prevents double fencing when different delays are configured on the nodes.
a3a2ad
+Use this to enable a static delay for stonith actions.
a3a2ad
+The overall delay is derived from a random delay value adding this static delay so that the sum is kept below the maximum delay.</longdesc>
a3a2ad
+    <content type="time" default="0s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_action_limit" unique="0">
a3a2ad
+    <shortdesc lang="en">The maximum number of actions can be performed in parallel on this device</shortdesc>
a3a2ad
+    <longdesc lang="en">Pengine property concurrent-fencing=true needs to be configured first.
a3a2ad
+Then use this to specify the maximum number of actions can be performed in parallel on this device. -1 is unlimited.</longdesc>
a3a2ad
+    <content type="integer" default="1"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_reboot_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'reboot'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'reboot' action.</longdesc>
a3a2ad
+    <content type="string" default="reboot"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_reboot_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for reboot actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'reboot' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_reboot_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'reboot' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'reboot' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_off_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'off'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'off' action.</longdesc>
a3a2ad
+    <content type="string" default="off"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_off_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for off actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'off' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_off_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'off' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'off' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_on_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'on'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'on' action.</longdesc>
a3a2ad
+    <content type="string" default="on"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_on_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for on actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'on' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_on_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'on' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'on' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_list_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'list'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'list' action.</longdesc>
a3a2ad
+    <content type="string" default="list"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_list_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for list actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'list' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_list_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'list' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'list' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_monitor_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'monitor'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'monitor' action.</longdesc>
a3a2ad
+    <content type="string" default="monitor"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_monitor_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for monitor actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'monitor' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_monitor_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'monitor' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'monitor' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_status_action" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: An alternate command to run instead of 'status'</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support the standard commands or may provide additional ones.
a3a2ad
+Use this to specify an alternate, device-specific, command that implements the 'status' action.</longdesc>
a3a2ad
+    <content type="string" default="status"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_status_timeout" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: Specify an alternate timeout to use for status actions instead of stonith-timeout</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices need much more/less time to complete than normal.
a3a2ad
+Use this to specify an alternate, device-specific, timeout for 'status' actions.</longdesc>
a3a2ad
+    <content type="time" default="60s"/>
a3a2ad
+  </parameter>
a3a2ad
+  <parameter name="pcmk_status_retries" unique="0">
a3a2ad
+    <shortdesc lang="en">Advanced use only: The maximum number of times to retry the 'status' command within the timeout period</shortdesc>
a3a2ad
+    <longdesc lang="en">Some devices do not support multiple connections. Operations may 'fail' if the device is busy with another task so Pacemaker will automatically retry the operation, if there is time remaining. Use this option to alter the number of times Pacemaker retries 'status' actions before giving up.</longdesc>
a3a2ad
+    <content type="integer" default="2"/>
a3a2ad
+  </parameter>
a3a2ad
+ </parameters>
a3a2ad
+</resource-agent>
a3a2ad
diff --git a/pcs/test/tools/command_env/config_runner_pcmk.py b/pcs/test/tools/command_env/config_runner_pcmk.py
a3a2ad
index 6499ef8..059f3eb 100644
a3a2ad
--- a/pcs/test/tools/command_env/config_runner_pcmk.py
a3a2ad
+++ b/pcs/test/tools/command_env/config_runner_pcmk.py
a3a2ad
@@ -70,6 +70,42 @@ class PcmkShortcuts(object):
a3a2ad
             instead=instead,
a3a2ad
         )
a3a2ad
 
a3a2ad
+    def load_stonithd_metadata(
a3a2ad
+        self,
a3a2ad
+        name="runner.pcmk.load_stonithd_metadata",
a3a2ad
+        stdout=None,
a3a2ad
+        stderr="",
a3a2ad
+        returncode=0,
a3a2ad
+        instead=None,
a3a2ad
+        before=None,
a3a2ad
+    ):
a3a2ad
+        """
a3a2ad
+        Create a call for loading stonithd metadata - additional fence options
a3a2ad
+
a3a2ad
+        string name -- the key of this call
a3a2ad
+        string stdout -- stonithd stdout, default metadata if None
a3a2ad
+        string stderr -- stonithd stderr
a3a2ad
+        int returncode -- stonithd returncode
a3a2ad
+        string instead -- the key of a call instead of which this new call is to
a3a2ad
+            be placed
a3a2ad
+        string before -- the key of a call before which this new call is to be
a3a2ad
+            placed
a3a2ad
+        """
a3a2ad
+        self.__calls.place(
a3a2ad
+            name,
a3a2ad
+            RunnerCall(
a3a2ad
+                "/usr/libexec/pacemaker/stonithd metadata",
a3a2ad
+                stdout=(
a3a2ad
+                    stdout if stdout is not None
a3a2ad
+                    else open(rc("stonithd_metadata.xml")).read()
a3a2ad
+                ),
a3a2ad
+                stderr=stderr,
a3a2ad
+                returncode=returncode
a3a2ad
+            ),
a3a2ad
+            before=before,
a3a2ad
+            instead=instead,
a3a2ad
+        )
a3a2ad
+
a3a2ad
     def resource_cleanup(
a3a2ad
         self,
a3a2ad
         name="runner.pcmk.cleanup",
a3a2ad
-- 
a3a2ad
1.8.3.1
a3a2ad