pcs/bz2159454-01-add-agent-vali...

1474 lines
65 KiB
Diff

From f60b24d7c70f63ceef0020a0a3b8a885aeccbdd1 Mon Sep 17 00:00:00 2001
From: Ondrej Mular <omular@redhat.com>
Date: Tue, 10 Jan 2023 15:57:33 +0100
Subject: [PATCH 1/2] add '--agent-validation' option for enabling agent
self-validation feature
---
CHANGELOG.md | 7 +
pcs/cli/common/parse_args.py | 3 +
pcs/lib/cib/resource/primitive.py | 12 +-
pcs/lib/cib/resource/remote_node.py | 1 +
pcs/lib/commands/booth.py | 1 +
pcs/lib/commands/resource.py | 16 ++
pcs/lib/commands/stonith.py | 8 +
pcs/pcs.8.in | 16 +-
pcs/resource.py | 12 +-
pcs/stonith.py | 3 +
pcs/usage.py | 32 ++--
.../cib/resource/test_primitive_validate.py | 49 ++++++
.../commands/resource/test_resource_create.py | 156 ++++++++++++------
pcs_test/tier0/lib/commands/test_booth.py | 49 ------
pcs_test/tier0/lib/commands/test_stonith.py | 24 +--
pcs_test/tier1/cib_resource/test_create.py | 2 +
.../tier1/cib_resource/test_stonith_create.py | 2 -
pcs_test/tier1/legacy/test_resource.py | 8 +-
pcs_test/tier1/legacy/test_stonith.py | 25 ++-
19 files changed, 280 insertions(+), 146 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 378cca50..47212f00 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,9 +12,16 @@
- Displaying bool and integer values in `pcs resource config` command
([rhbz#2151164], [ghissue#604])
+### Changed
+- Resource/stonith agent self-validation of instance attributes is now
+ disabled by default, as many agents do not work with it properly.
+ Use flag '--agent-validation' to enable it in supported commands.
+ ([rhbz#2159454])
+
[ghissue#604]: https://github.com/ClusterLabs/pcs/issues/604
[rhbz#2151164]: https://bugzilla.redhat.com/show_bug.cgi?id=2151164
[rhbz#2151524]: https://bugzilla.redhat.com/show_bug.cgi?id=2151524
+[rhbz#2159454]: https://bugzilla.redhat.com/show_bug.cgi?id=2159454
## [0.11.4] - 2022-11-21
diff --git a/pcs/cli/common/parse_args.py b/pcs/cli/common/parse_args.py
index 663751aa..1c75f406 100644
--- a/pcs/cli/common/parse_args.py
+++ b/pcs/cli/common/parse_args.py
@@ -93,6 +93,8 @@ PCS_LONG_OPTIONS = [
f"{_OUTPUT_FORMAT_OPTION_STR}=",
# auth token
"token=",
+ # enable agent self validation
+ "agent-validation",
]
@@ -484,6 +486,7 @@ class InputModifiers:
{
# boolean values
"--all": "--all" in options,
+ "--agent-validation": "--agent-validation" in options,
"--autodelete": "--autodelete" in options,
"--brief": "--brief" in options,
"--config": "--config" in options,
diff --git a/pcs/lib/cib/resource/primitive.py b/pcs/lib/cib/resource/primitive.py
index f9d52b9b..8d6e4c05 100644
--- a/pcs/lib/cib/resource/primitive.py
+++ b/pcs/lib/cib/resource/primitive.py
@@ -137,6 +137,7 @@ def create(
resource_type: str = "resource",
# TODO remove this arg
do_not_report_instance_attribute_server_exists: bool = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments
# pylint: disable=too-many-locals
@@ -159,6 +160,8 @@ def create(
resource_type -- describes the resource for reports
do_not_report_instance_attribute_server_exists -- dirty fix due to
suboptimal architecture, TODO: fix the architecture and remove the param
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
if raw_operation_list is None:
raw_operation_list = []
@@ -200,6 +203,7 @@ def create(
instance_attributes,
resources_section,
force=allow_invalid_instance_attributes,
+ enable_agent_self_validation=enable_agent_self_validation,
)
# TODO remove this "if", see pcs.lib.cib.remote_node.create for details
if do_not_report_instance_attribute_server_exists:
@@ -388,6 +392,7 @@ def validate_resource_instance_attributes_create(
instance_attributes: Mapping[str, str],
resources_section: _Element,
force: bool = False,
+ enable_agent_self_validation: bool = False,
) -> reports.ReportItemList:
report_items: reports.ReportItemList = []
report_items += validate.ValidatorAll(
@@ -422,7 +427,8 @@ def validate_resource_instance_attributes_create(
)
if (
- _is_ocf_or_stonith_agent(agent_name)
+ enable_agent_self_validation
+ and _is_ocf_or_stonith_agent(agent_name)
and resource_agent.metadata.agent_exists
and resource_agent.metadata.provides_self_validation
and not any(
@@ -450,6 +456,7 @@ def validate_resource_instance_attributes_update(
resource_id: str,
resources_section: _Element,
force: bool = False,
+ enable_agent_self_validation: bool = False,
) -> reports.ReportItemList:
# pylint: disable=too-many-locals
# TODO This function currently accepts the updated resource as a string and
@@ -524,7 +531,8 @@ def validate_resource_instance_attributes_update(
)
if (
- _is_ocf_or_stonith_agent(agent_name)
+ enable_agent_self_validation
+ and _is_ocf_or_stonith_agent(agent_name)
and resource_agent.metadata.agent_exists
and resource_agent.metadata.provides_self_validation
and not any(
diff --git a/pcs/lib/cib/resource/remote_node.py b/pcs/lib/cib/resource/remote_node.py
index c76e37a6..f65c5446 100644
--- a/pcs/lib/cib/resource/remote_node.py
+++ b/pcs/lib/cib/resource/remote_node.py
@@ -253,4 +253,5 @@ def create(
# 3) call the validation from here and handle the results or config
# the validator before / when running it
do_not_report_instance_attribute_server_exists=True,
+ enable_agent_self_validation=False,
)
diff --git a/pcs/lib/commands/booth.py b/pcs/lib/commands/booth.py
index ee91ea14..7b0ed4de 100644
--- a/pcs/lib/commands/booth.py
+++ b/pcs/lib/commands/booth.py
@@ -480,6 +480,7 @@ def create_in_cluster(
env.cmd_runner(),
resources_section,
id_provider,
+ enable_agent_self_validation=False,
)
agent_factory = ResourceAgentFacadeFactory(
env.cmd_runner(), report_processor
diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py
index 7c64ace7..41f1a1ac 100644
--- a/pcs/lib/commands/resource.py
+++ b/pcs/lib/commands/resource.py
@@ -361,6 +361,7 @@ def create(
ensure_disabled: bool = False,
wait: WaitType = False,
allow_not_suitable_command: bool = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -394,6 +395,8 @@ def create(
pcs.lib.commands.remote_node);
in the case of remote/guest node forcible error is produced when this
flag is set to False and warning is produced otherwise
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -440,6 +443,7 @@ def create(
allow_invalid_operation,
allow_invalid_instance_attributes,
use_default_operations,
+ enable_agent_self_validation=enable_agent_self_validation,
)
if env.report_processor.has_errors:
raise LibraryError()
@@ -465,6 +469,7 @@ def create_as_clone(
wait: WaitType = False,
allow_not_suitable_command: bool = False,
allow_incompatible_clone_meta_attributes: bool = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -495,6 +500,8 @@ def create_as_clone(
allow_incompatible_clone_meta_attributes -- if True some incompatible clone
meta attributes are treated as a warning, or as a forceable error if
False
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -579,6 +586,7 @@ def create_as_clone(
allow_invalid_operation,
allow_invalid_instance_attributes,
use_default_operations,
+ enable_agent_self_validation=enable_agent_self_validation,
)
clone_element = resource.clone.append_new(
@@ -609,6 +617,7 @@ def create_in_group(
put_after_adjacent: bool = False,
wait: WaitType = False,
allow_not_suitable_command: bool = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -637,6 +646,8 @@ def create_in_group(
adjacent resource
wait -- is flag for controlling waiting for pacemaker idle mechanism
allow_not_suitable_command -- turn forceable errors into warnings
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -712,6 +723,7 @@ def create_in_group(
allow_invalid_operation,
allow_invalid_instance_attributes,
use_default_operations,
+ enable_agent_self_validation=enable_agent_self_validation,
)
if ensure_disabled:
resource.common.disable(primitive_element, id_provider)
@@ -749,6 +761,7 @@ def create_into_bundle(
wait: WaitType = False,
allow_not_suitable_command: bool = False,
allow_not_accessible_resource: bool = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -776,6 +789,8 @@ def create_into_bundle(
wait -- is flag for controlling waiting for pacemaker idle mechanism
allow_not_suitable_command -- turn forceable errors into warnings
allow_not_accessible_resource -- turn forceable errors into warnings
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -823,6 +838,7 @@ def create_into_bundle(
allow_invalid_operation,
allow_invalid_instance_attributes,
use_default_operations,
+ enable_agent_self_validation=enable_agent_self_validation,
)
if ensure_disabled:
resource.common.disable(primitive_element, id_provider)
diff --git a/pcs/lib/commands/stonith.py b/pcs/lib/commands/stonith.py
index 42b5b270..3a3ea3b7 100644
--- a/pcs/lib/commands/stonith.py
+++ b/pcs/lib/commands/stonith.py
@@ -115,6 +115,7 @@ def create(
use_default_operations: bool = True,
ensure_disabled: bool = False,
wait: WaitType = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -137,6 +138,8 @@ def create(
operations (specified in a stonith agent)
ensure_disabled -- flag that keeps resource in target-role "Stopped"
wait -- flag for controlling waiting for pacemaker idle mechanism
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -173,6 +176,7 @@ def create(
allow_invalid_instance_attributes=allow_invalid_instance_attributes,
use_default_operations=use_default_operations,
resource_type="stonith",
+ enable_agent_self_validation=enable_agent_self_validation,
)
if ensure_disabled:
resource.common.disable(stonith_element, id_provider)
@@ -195,6 +199,7 @@ def create_in_group(
adjacent_resource_id: Optional[str] = None,
put_after_adjacent: bool = False,
wait: WaitType = False,
+ enable_agent_self_validation: bool = False,
):
# pylint: disable=too-many-arguments, too-many-locals
"""
@@ -222,6 +227,8 @@ def create_in_group(
put_after_adjacent -- is flag to put a newly create resource befor/after
adjacent stonith
wait -- flag for controlling waiting for pacemaker idle mechanism
+ enable_agent_self_validation -- if True, use agent self-validation feature
+ to validate instance attributes
"""
runner = env.cmd_runner()
agent_factory = ResourceAgentFacadeFactory(runner, env.report_processor)
@@ -288,6 +295,7 @@ def create_in_group(
allow_invalid_operation,
allow_invalid_instance_attributes,
use_default_operations,
+ enable_agent_self_validation=enable_agent_self_validation,
)
if ensure_disabled:
resource.common.disable(stonith_element, id_provider)
diff --git a/pcs/pcs.8.in b/pcs/pcs.8.in
index 7bbd1ae2..3be8465e 100644
--- a/pcs/pcs.8.in
+++ b/pcs/pcs.8.in
@@ -95,8 +95,8 @@ Show list of all available resource agents (if filter is provided then only reso
describe [<standard>:[<provider>:]]<type> [\fB\-\-full\fR]
Show options for the specified resource. If \fB\-\-full\fR is specified, all options including advanced and deprecated ones are shown.
.TP
-create <resource id> [<standard>:[<provider>:]]<type> [resource options] [\fBop\fR <operation action> <operation options> [<operation action> <operation options>]...] [\fBmeta\fR <meta options>...] [\fBclone\fR [<clone id>] [<clone options>] | promotable [<clone id>] [<promotable options>] | \fB\-\-group\fR <group id> [\fB\-\-before\fR <resource id> | \fB\-\-after\fR <resource id>] | \fBbundle\fR <bundle id>] [\fB\-\-disabled\fR] [\fB\-\-no\-default\-ops] [\fB\-\-wait\fR[=n]]
-Create specified resource. If \fBclone\fR is used a clone resource is created. If \fBpromotable\fR is used a promotable clone resource is created. If \fB\-\-group\fR is specified the resource is added to the group named. You can use \fB\-\-before\fR or \fB\-\-after\fR to specify the position of the added resource relatively to some resource already existing in the group. If \fBbundle\fR is specified, resource will be created inside of the specified bundle. If \fB\-\-disabled\fR is specified the resource is not started automatically. If \fB\-\-no\-default\-ops\fR is specified, only monitor operations are created for the resource and all other operations use default settings. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the resource to start and then return 0 if the resource is started, or 1 if the resource has not yet started. If 'n' is not specified it defaults to 60 minutes.
+create <resource id> [<standard>:[<provider>:]]<type> [resource options] [\fBop\fR <operation action> <operation options> [<operation action> <operation options>]...] [\fBmeta\fR <meta options>...] [\fBclone\fR [<clone id>] [<clone options>] | promotable [<clone id>] [<promotable options>] | \fB\-\-group\fR <group id> [\fB\-\-before\fR <resource id> | \fB\-\-after\fR <resource id>] | \fBbundle\fR <bundle id>] [\fB\-\-disabled\fR] [\fB\-\-agent\-validation\fR] [\fB\-\-no\-default\-ops\fR] [\fB\-\-wait\fR[=n]]
+Create specified resource. If \fBclone\fR is used a clone resource is created. If \fBpromotable\fR is used a promotable clone resource is created. If \fB\-\-group\fR is specified the resource is added to the group named. You can use \fB\-\-before\fR or \fB\-\-after\fR to specify the position of the added resource relatively to some resource already existing in the group. If \fBbundle\fR is specified, resource will be created inside of the specified bundle. If \fB\-\-disabled\fR is specified the resource is not started automatically. If \fB\-\-agent\-validation\fR is specified, resource agent validate\-all action will be used to validate resource options. If \fB\-\-no\-default\-ops\fR is specified, only monitor operations are created for the resource and all other operations use default settings. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the resource to start and then return 0 if the resource is started, or 1 if the resource has not yet started. If 'n' is not specified it defaults to 60 minutes.
Example: Create a new resource called 'VirtualIP' with IP address 192.168.0.99, netmask of 32, monitored everything 30 seconds, on eth2: pcs resource create VirtualIP ocf:heartbeat:IPaddr2 ip=192.168.0.99 cidr_netmask=32 nic=eth2 op monitor interval=30s
.TP
@@ -204,11 +204,13 @@ List available OCF resource agent providers.
agents [standard[:provider]]
List available agents optionally filtered by standard and provider.
.TP
-update <resource id> [resource options] [op [<operation action> <operation options>]...] [meta <meta operations>...] [\fB\-\-wait\fR[=n]]
+update <resource id> [resource options] [op [<operation action> <operation options>]...] [meta <meta operations>...] [\fB\-\-agent\-validation\fR] [\fB\-\-wait\fR[=n]]
Add, remove or change options of specified resource, clone or multi\-state resource. Unspecified options will be kept unchanged. If you wish to remove an option, set it to empty value, i.e. 'option_name='.
If an operation (op) is specified it will update the first found operation with the same action on the specified resource. If no operation with that action exists then a new operation will be created. (WARNING: all existing options on the updated operation will be reset if not specified.) If you want to create multiple monitor operations you should use the 'op add' & 'op remove' commands.
+If \fB\-\-agent\-validation\fR is specified, resource agent validate\-all action will be used to validate resource options.
+
If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the changes to take effect and then return 0 if the changes have been processed or 1 otherwise. If 'n' is not specified it defaults to 60 minutes.
.TP
op add <resource id> <operation action> [operation properties]
@@ -689,8 +691,8 @@ Show list of all available stonith agents (if filter is provided then only stoni
describe <stonith agent> [\fB\-\-full\fR]
Show options for specified stonith agent. If \fB\-\-full\fR is specified, all options including advanced and deprecated ones are shown.
.TP
-create <stonith id> <stonith device type> [stonith device options] [op <operation action> <operation options> [<operation action> <operation options>]...] [meta <meta options>...] [\fB\-\-group\fR <group id> [\fB\-\-before\fR <stonith id> | \fB\-\-after\fR <stonith id>]] [\fB\-\-disabled\fR] [\fB\-\-wait\fR[=n]]
-Create stonith device with specified type and options. If \fB\-\-group\fR is specified the stonith device is added to the group named. You can use \fB\-\-before\fR or \fB\-\-after\fR to specify the position of the added stonith device relatively to some stonith device already existing in the group. If\fB\-\-disabled\fR is specified the stonith device is not used. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the stonith device to start and then return 0 if the stonith device is started, or 1 if the stonith device has not yet started. If 'n' is not specified it defaults to 60 minutes.
+create <stonith id> <stonith device type> [stonith device options] [op <operation action> <operation options> [<operation action> <operation options>]...] [meta <meta options>...] [\fB\-\-group\fR <group id> [\fB\-\-before\fR <stonith id> | \fB\-\-after\fR <stonith id>]] [\fB\-\-disabled\fR] [\fB\-\-agent\-validation\fR] [\fB\-\-wait\fR[=n]]
+Create stonith device with specified type and options. If \fB\-\-group\fR is specified the stonith device is added to the group named. You can use \fB\-\-before\fR or \fB\-\-after\fR to specify the position of the added stonith device relatively to some stonith device already existing in the group. If\fB\-\-disabled\fR is specified the stonith device is not used. If \fB\-\-agent\-validation\fR is specified, stonith agent validate\-all action will be used to validate stonith device options. If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the stonith device to start and then return 0 if the stonith device is started, or 1 if the stonith device has not yet started. If 'n' is not specified it defaults to 60 minutes.
Example: Create a device for nodes node1 and node2
.br
@@ -700,11 +702,13 @@ Example: Use port p1 for node n1 and ports p2 and p3 for node n2
.br
pcs stonith create MyFence fence_virt 'pcmk_host_map=n1:p1;n2:p2,p3'
.TP
-update <stonith id> [stonith options] [op [<operation action> <operation options>]...] [meta <meta operations>...] [\fB\-\-wait\fR[=n]]
+update <stonith id> [stonith options] [op [<operation action> <operation options>]...] [meta <meta operations>...] [\fB\-\-agent\-validation\fR] [\fB\-\-wait\fR[=n]]
Add, remove or change options of specified stonith device. Unspecified options will be kept unchanged. If you wish to remove an option, set it to empty value, i.e. 'option_name='.
If an operation (op) is specified it will update the first found operation with the same action on the specified stonith device. If no operation with that action exists then a new operation will be created. (WARNING: all existing options on the updated operation will be reset if not specified.) If you want to create multiple monitor operations you should use the 'op add' & 'op remove' commands.
+If \fB\-\-agent\-validation\fR is specified, stonith agent validate\-all action will be used to validate stonith device options.
+
If \fB\-\-wait\fR is specified, pcs will wait up to 'n' seconds for the changes to take effect and then return 0 if the changes have been processed or 1 otherwise. If 'n' is not specified it defaults to 60 minutes.
.TP
update\-scsi\-devices <stonith id> (set <device\-path> [<device\-path>...]) | (add <device\-path> [<device\-path>...] delete|remove <device\-path> [<device\-path>...] )
diff --git a/pcs/resource.py b/pcs/resource.py
index b265b2d2..d8c61633 100644
--- a/pcs/resource.py
+++ b/pcs/resource.py
@@ -624,6 +624,7 @@ def _format_desc(indentation, desc):
def resource_create(lib, argv, modifiers):
"""
Options:
+ * --agent-validation - use agent self validation of instance attributes
* --before - specified resource inside a group before which new resource
will be placed inside the group
* --after - specified resource inside a group after which new resource
@@ -637,6 +638,7 @@ def resource_create(lib, argv, modifiers):
* -f - CIB file
"""
modifiers.ensure_only_supported(
+ "--agent-validation",
"--before",
"--after",
"--group",
@@ -699,6 +701,7 @@ def resource_create(lib, argv, modifiers):
use_default_operations=not modifiers.get("--no-default-ops"),
wait=modifiers.get("--wait"),
allow_not_suitable_command=modifiers.get("--force"),
+ enable_agent_self_validation=modifiers.get("--agent-validation"),
)
clone_id = parts.get("clone_id", None)
@@ -966,6 +969,7 @@ def update_cmd(lib: Any, argv: List[str], modifiers: InputModifiers) -> None:
"""
Options:
* -f - CIB file
+ * --agent-validation - use agent self validation of instance attributes
* --wait
* --force - allow invalid options, do not fail if not possible to get
agent metadata, allow not suitable command
@@ -982,11 +986,14 @@ def resource_update(args: List[str], modifiers: InputModifiers) -> None:
"""
Commandline options:
* -f - CIB file
+ * --agent-validation - use agent self validation of instance attributes
* --wait
* --force - allow invalid options, do not fail if not possible to get
agent metadata, allow not suitable command
"""
- modifiers.ensure_only_supported("-f", "--wait", "--force")
+ modifiers.ensure_only_supported(
+ "-f", "--wait", "--force", "--agent-validation"
+ )
if len(args) < 2:
raise CmdLineInputError()
res_id = args.pop(0)
@@ -1052,6 +1059,9 @@ def resource_update(args: List[str], modifiers: InputModifiers) -> None:
res_id,
get_resources(lib_pacemaker.get_cib(cib_xml)),
force=bool(modifiers.get("--force")),
+ enable_agent_self_validation=bool(
+ modifiers.get("--agent-validation")
+ ),
)
if report_list:
process_library_reports(report_list)
diff --git a/pcs/stonith.py b/pcs/stonith.py
index 8ba6066c..ef97b41b 100644
--- a/pcs/stonith.py
+++ b/pcs/stonith.py
@@ -148,6 +148,7 @@ def stonith_create(lib, argv, modifiers):
instance attributes
* --disabled - created resource will be disabled
* --no-default-ops - do not add default operations
+ * --agent-validation - use agent self validation of instance attributes
* --wait
* -f - CIB file
"""
@@ -158,6 +159,7 @@ def stonith_create(lib, argv, modifiers):
"--force",
"--disabled",
"--no-default-ops",
+ "--agent-validation",
"--wait",
"-f",
)
@@ -191,6 +193,7 @@ def stonith_create(lib, argv, modifiers):
ensure_disabled=modifiers.get("--disabled"),
use_default_operations=not modifiers.get("--no-default-ops"),
wait=modifiers.get("--wait"),
+ enable_agent_self_validation=modifiers.get("--agent-validation"),
)
if not modifiers.get("--group"):
diff --git a/pcs/usage.py b/pcs/usage.py
index 073e2b1e..b2c46669 100644
--- a/pcs/usage.py
+++ b/pcs/usage.py
@@ -680,16 +680,17 @@ _RESOURCE_UPDATE_CMD = "update"
_RESOURCE_UPDATE_SYNTAX = _unwrap(
"""
<{obj} id> [{obj} options] [op [<operation action> <operation options>]...]
- [meta <meta operations>...] [--wait[=n]]
+ [meta <meta operations>...] [--agent-validation] [--wait[=n]]
"""
)
def _resource_update_desc_fn(is_stonith: bool) -> Iterable[str]:
if is_stonith:
- obj = obj_long = "stonith device"
+ agent_type = "stonith"
+ obj = obj_long = f"{agent_type} device"
else:
- obj = "resource"
+ obj = agent_type = "resource"
obj_long = "resource, clone or multi-state resource"
return (
f"""
@@ -707,6 +708,11 @@ def _resource_update_desc_fn(is_stonith: bool) -> Iterable[str]:
you should use the 'op add' & 'op remove' commands.
""",
"",
+ f"""
+ If --agent-validation is specified, {agent_type} agent validate-all
+ action will be used to validate {obj} options.
+ """,
+ "",
"""
If --wait is specified, pcs will wait up to 'n' seconds for the changes
to take effect and then return 0 if the changes have been processed or
@@ -778,7 +784,8 @@ Commands:
[clone [<clone id>] [<clone options>] |
promotable [<clone id>] [<promotable options>] |
--group <group id> [--before <resource id> | --after <resource id>] |
- bundle <bundle id>] [--disabled] [--no-default-ops] [--wait[=n]]
+ bundle <bundle id>] [--disabled] [--agent-validation]
+ [--no-default-ops] [--wait[=n]]
Create specified resource. If clone is used a clone resource is
created. If promotable is used a promotable clone resource is created.
If --group is specified the resource is added to the group named. You
@@ -786,12 +793,13 @@ Commands:
resource relatively to some resource already existing in the group. If
bundle is used, the resource will be created inside of the specified
bundle. If --disabled is specified the resource is not started
- automatically. If --no-default-ops is specified, only monitor
- operations are created for the resource and all other operations use
- default settings. If --wait is specified, pcs will wait up to 'n'
- seconds for the resource to start and then return 0 if the resource is
- started, or 1 if the resource has not yet started. If 'n' is not
- specified it defaults to 60 minutes.
+ automatically. If --agent-validation is specified, resource agent
+ validate-all action will be used to validate resource options. If
+ --no-default-ops is specified, only monitor operations are created for
+ the resource and all other operations use default settings. If --wait
+ is specified, pcs will wait up to 'n' seconds for the resource to start
+ and then return 0 if the resource is started, or 1 if the resource has
+ not yet started. If 'n' is not specified it defaults to 60 minutes.
Example: Create a new resource called 'VirtualIP' with IP address
192.168.0.99, netmask of 32, monitored everything 30 seconds,
on eth2:
@@ -1844,13 +1852,15 @@ Commands:
[op <operation action> <operation options> [<operation action>
<operation options>]...] [meta <meta options>...]
[--group <group id> [--before <stonith id> | --after <stonith id>]]
- [--disabled] [--wait[=n]]
+ [--disabled] [--agent-validation] [--wait[=n]]
Create stonith device with specified type and options.
If --group is specified the stonith device is added to the group named.
You can use --before or --after to specify the position of the added
stonith device relatively to some stonith device already existing in the
group.
If --disabled is specified the stonith device is not used.
+ If --agent-validation is specified, stonith agent validate-all action
+ will be used to validate stonith device options.
If --wait is specified, pcs will wait up to 'n' seconds for the stonith
device to start and then return 0 if the stonith device is started, or 1
if the stonith device has not yet started. If 'n' is not specified it
diff --git a/pcs_test/tier0/lib/cib/resource/test_primitive_validate.py b/pcs_test/tier0/lib/cib/resource/test_primitive_validate.py
index 7a4e5c8f..0438ae5d 100644
--- a/pcs_test/tier0/lib/cib/resource/test_primitive_validate.py
+++ b/pcs_test/tier0/lib/cib/resource/test_primitive_validate.py
@@ -643,6 +643,22 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
self.agent_self_validation_mock.return_value = True, []
self.cmd_runner = mock.Mock()
+ def test_disabled(self):
+ attributes = {"required": "value"}
+ facade = _fixture_ocf_agent()
+ self.assertEqual(
+ primitive.validate_resource_instance_attributes_create(
+ self.cmd_runner,
+ facade,
+ attributes,
+ etree.Element("resources"),
+ force=False,
+ enable_agent_self_validation=False,
+ ),
+ [],
+ )
+ self.agent_self_validation_mock.assert_not_called()
+
def test_success(self):
attributes = {"required": "value"}
facade = _fixture_ocf_agent()
@@ -653,6 +669,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -672,6 +689,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=True,
+ enable_agent_self_validation=True,
),
[],
)
@@ -693,6 +711,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[
fixture.error(
@@ -718,6 +737,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -737,6 +757,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -752,6 +773,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -767,6 +789,7 @@ class ValidateResourceInstanceAttributesCreateSelfValidation(TestCase):
attributes,
etree.Element("resources"),
force=False,
+ enable_agent_self_validation=True,
),
[
fixture.error(
@@ -1326,6 +1349,24 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
etree.SubElement(nvset_el, "nvpair", dict(name=name, value=value))
return resources_el
+ def test_disabled(self):
+ old_attributes = {"required": "old_value"}
+ new_attributes = {"required": "new_value"}
+ facade = _fixture_ocf_agent()
+ self.assertEqual(
+ primitive.validate_resource_instance_attributes_update(
+ self.cmd_runner,
+ facade,
+ new_attributes,
+ self._NAME,
+ self._fixture_resources(old_attributes),
+ force=False,
+ enable_agent_self_validation=False,
+ ),
+ [],
+ )
+ self.agent_self_validation_mock.assert_not_called()
+
def test_success(self):
old_attributes = {"required": "old_value"}
new_attributes = {"required": "new_value"}
@@ -1338,6 +1379,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -1369,6 +1411,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=True,
+ enable_agent_self_validation=True,
),
[],
)
@@ -1405,6 +1448,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[
fixture.error(
@@ -1442,6 +1486,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -1473,6 +1518,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -1490,6 +1536,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[],
)
@@ -1507,6 +1554,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[
fixture.error(
@@ -1533,6 +1581,7 @@ class ValidateResourceInstanceAttributesUpdateSelfValidation(TestCase):
self._NAME,
self._fixture_resources(old_attributes),
force=False,
+ enable_agent_self_validation=True,
),
[
fixture.warn(
diff --git a/pcs_test/tier0/lib/commands/resource/test_resource_create.py b/pcs_test/tier0/lib/commands/resource/test_resource_create.py
index 433a7351..a038d0f5 100644
--- a/pcs_test/tier0/lib/commands/resource/test_resource_create.py
+++ b/pcs_test/tier0/lib/commands/resource/test_resource_create.py
@@ -30,7 +30,9 @@ def create(
allow_invalid_operation=False,
agent_name="ocf:heartbeat:Dummy",
allow_invalid_instance_attributes=False,
+ enable_agent_self_validation=False,
):
+ # pylint: disable=too-many-arguments
return resource.create(
env,
"A",
@@ -42,6 +44,7 @@ def create(
ensure_disabled=disabled,
allow_invalid_operation=allow_invalid_operation,
allow_invalid_instance_attributes=allow_invalid_instance_attributes,
+ enable_agent_self_validation=enable_agent_self_validation,
)
@@ -51,6 +54,7 @@ def create_group(
disabled=False,
meta_attributes=None,
operation_list=None,
+ enable_agent_self_validation=False,
):
return resource.create_in_group(
env,
@@ -62,6 +66,7 @@ def create_group(
instance_attributes={},
wait=wait,
ensure_disabled=disabled,
+ enable_agent_self_validation=enable_agent_self_validation,
)
@@ -75,6 +80,7 @@ def create_clone(
clone_id=None,
agent="ocf:heartbeat:Dummy",
allow_incompatible_clone_meta_attributes=False,
+ enable_agent_self_validation=False,
):
# pylint: disable=too-many-arguments
return resource.create_as_clone(
@@ -89,6 +95,7 @@ def create_clone(
wait=wait,
ensure_disabled=disabled,
allow_incompatible_clone_meta_attributes=allow_incompatible_clone_meta_attributes,
+ enable_agent_self_validation=enable_agent_self_validation,
)
@@ -99,6 +106,7 @@ def create_bundle(
meta_attributes=None,
allow_not_accessible_resource=False,
operation_list=None,
+ enable_agent_self_validation=False,
):
return resource.create_into_bundle(
env,
@@ -111,6 +119,7 @@ def create_bundle(
wait=wait,
ensure_disabled=disabled,
allow_not_accessible_resource=allow_not_accessible_resource,
+ enable_agent_self_validation=enable_agent_self_validation,
)
@@ -395,13 +404,6 @@ class CreateRolesNormalization(TestCase):
agent_filename=agent_file_name,
)
self.config.runner.cib.load(filename=cib_file)
- self.config.runner.pcmk.resource_agent_self_validation(
- {},
- output="",
- standard="ocf",
- provider="pacemaker",
- agent_type="Stateful",
- )
def create(self, operation_list=None):
resource.create(
@@ -597,7 +599,6 @@ class Create(TestCase):
def test_simplest_resource(self):
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=fixture_cib_resources_xml_primitive_simplest
)
@@ -619,7 +620,9 @@ class Create(TestCase):
returncode=1,
)
self.env_assist.assert_raise_library_error(
- lambda: create(self.env_assist.get_env()),
+ lambda: create(
+ self.env_assist.get_env(), enable_agent_self_validation=True
+ ),
)
self.env_assist.assert_reports(
[
@@ -650,7 +653,9 @@ class Create(TestCase):
resources=fixture_cib_resources_xml_primitive_simplest
)
create(
- self.env_assist.get_env(), allow_invalid_instance_attributes=True
+ self.env_assist.get_env(),
+ allow_invalid_instance_attributes=True,
+ enable_agent_self_validation=True,
)
self.env_assist.assert_reports(
[
@@ -670,7 +675,10 @@ class Create(TestCase):
returncode=0,
)
self.env_assist.assert_raise_library_error(
- lambda: create(self.env_assist.get_env()),
+ lambda: create(
+ self.env_assist.get_env(),
+ enable_agent_self_validation=True,
+ ),
)
self.env_assist.assert_reports(
[
@@ -715,7 +723,6 @@ class Create(TestCase):
)
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=fixture_cib_resources_xml_primitive_simplest
)
@@ -878,7 +885,6 @@ class Create(TestCase):
def test_resource_with_operation(self):
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources="""
<resources>
@@ -924,14 +930,12 @@ class Create(TestCase):
),
)
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(resources=self.fixture_sanitized_operation)
create(self.env_assist.get_env())
def test_sanitize_operation_id_from_user(self):
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(resources=self.fixture_sanitized_operation)
create(
self.env_assist.get_env(),
@@ -1113,9 +1117,6 @@ class Create(TestCase):
</resources>
""",
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(state=1), output=""
- )
self.config.env.push_cib(
resources="""
<resources>
@@ -1201,7 +1202,6 @@ class Create(TestCase):
)
self.config.runner.cib.upgrade()
self.config.runner.cib.load(filename="cib-empty-3.4.xml")
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources="""
<resources>
@@ -1257,7 +1257,6 @@ class CreateWait(TestCase):
self.env_assist, self.config = get_env_tools(test_case=self)
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=fixture_cib_resources_xml_primitive_simplest,
wait=TIMEOUT,
@@ -1387,15 +1386,9 @@ class CreateWait(TestCase):
class CreateInGroup(TestCase):
def setUp(self):
- self.agent_self_validation_call_name = (
- "runner.pcmk.resource_agent_self_validation"
- )
self.env_assist, self.config = get_env_tools(test_case=self)
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation(
- {}, output="", name=self.agent_self_validation_call_name
- )
def test_simplest_resource(self):
(
@@ -1438,7 +1431,6 @@ class CreateInGroup(TestCase):
create_group(self.env_assist.get_env(), wait=False)
def test_cib_upgrade_on_onfail_demote(self):
- self.config.remove(self.agent_self_validation_call_name)
self.config.runner.cib.load(
filename="cib-empty-3.3.xml",
instead="runner.cib.load",
@@ -1446,7 +1438,6 @@ class CreateInGroup(TestCase):
)
self.config.runner.cib.upgrade()
self.config.runner.cib.load(filename="cib-empty-3.4.xml")
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources="""
<resources>
@@ -1498,6 +1489,34 @@ class CreateInGroup(TestCase):
[fixture.info(reports.codes.CIB_UPGRADE_SUCCESSFUL)]
)
+ def test_resource_self_validation_failure(self):
+ self.config.runner.pcmk.resource_agent_self_validation(
+ {},
+ output="""
+ <output source="stderr">not ignored</output>
+ <output source="stdout">this is ignored</output>
+ <output source="stderr">
+ first issue
+ another one
+ </output>
+ """,
+ returncode=1,
+ )
+ self.env_assist.assert_raise_library_error(
+ lambda: create_group(
+ self.env_assist.get_env(), enable_agent_self_validation=True
+ ),
+ )
+ self.env_assist.assert_reports(
+ [
+ fixture.error(
+ reports.codes.AGENT_SELF_VALIDATION_RESULT,
+ result="not ignored\nfirst issue\nanother one",
+ force_code=reports.codes.FORCE,
+ )
+ ]
+ )
+
def test_fail_wait(self):
self.config.env.push_cib(
resources=fixture_cib_resources_xml_group_simplest,
@@ -1641,15 +1660,9 @@ class CreateInGroup(TestCase):
class CreateAsClone(TestCase):
def setUp(self):
- self.agent_self_validation_call_name = (
- "runner.pcmk.resource_agent_self_validation"
- )
self.env_assist, self.config = get_env_tools(test_case=self)
self.config.runner.pcmk.load_agent()
self.config.runner.cib.load()
- self.config.runner.pcmk.resource_agent_self_validation(
- {}, output="", name=self.agent_self_validation_call_name
- )
def test_simplest_resource(self):
(
@@ -1659,6 +1672,34 @@ class CreateAsClone(TestCase):
)
create_clone(self.env_assist.get_env(), wait=False)
+ def test_resource_self_validation_failure(self):
+ self.config.runner.pcmk.resource_agent_self_validation(
+ {},
+ output="""
+ <output source="stderr">not ignored</output>
+ <output source="stdout">this is ignored</output>
+ <output source="stderr">
+ first issue
+ another one
+ </output>
+ """,
+ returncode=1,
+ )
+ self.env_assist.assert_raise_library_error(
+ lambda: create_clone(
+ self.env_assist.get_env(), enable_agent_self_validation=True
+ ),
+ )
+ self.env_assist.assert_reports(
+ [
+ fixture.error(
+ reports.codes.AGENT_SELF_VALIDATION_RESULT,
+ result="not ignored\nfirst issue\nanother one",
+ force_code=reports.codes.FORCE,
+ )
+ ]
+ )
+
def test_custom_clone_id(self):
(
self.config.env.push_cib(
@@ -1670,7 +1711,6 @@ class CreateAsClone(TestCase):
)
def test_custom_clone_id_error_invalid_id(self):
- self.config.remove(self.agent_self_validation_call_name)
self.env_assist.assert_raise_library_error(
lambda: create_clone(
self.env_assist.get_env(), wait=False, clone_id="1invalid"
@@ -1682,7 +1722,6 @@ class CreateAsClone(TestCase):
def test_custom_clone_id_error_id_already_exist(self):
self.config.remove(name="runner.cib.load")
- self.config.remove(self.agent_self_validation_call_name)
self.config.runner.cib.load(
resources="""
<resources>
@@ -1705,7 +1744,6 @@ class CreateAsClone(TestCase):
self.env_assist.assert_reports([fixture.report_id_already_exist("C")])
def test_cib_upgrade_on_onfail_demote(self):
- self.config.remove(self.agent_self_validation_call_name)
self.config.runner.cib.load(
filename="cib-empty-3.3.xml",
instead="runner.cib.load",
@@ -1713,7 +1751,6 @@ class CreateAsClone(TestCase):
)
self.config.runner.cib.upgrade()
self.config.runner.cib.load(filename="cib-empty-3.4.xml")
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources="""<resources>
<clone id="A-clone">
@@ -2198,6 +2235,7 @@ class CreateAsCloneFailures(TestCase):
agent=agent.full_name,
clone_options={"promotable": "1"},
allow_incompatible_clone_meta_attributes=True,
+ enable_agent_self_validation=True,
),
)
self.env_assist.assert_reports(
@@ -2363,7 +2401,6 @@ class CreateInToBundle(TestCase):
self.config.runner.cib.load(
filename="cib-empty-3.4.xml", resources=self.fixture_resources_pre
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resource_post_simple_without_network.format(
network="""
@@ -2393,13 +2430,11 @@ class CreateInToBundle(TestCase):
def test_simplest_resource(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(resources=self.fixture_resources_post_simple)
create_bundle(self.env_assist.get_env(), wait=False)
def test_bundle_doesnt_exist(self):
self.config.runner.cib.load(resources=self.fixture_empty_resources)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.env_assist.assert_raise_library_error(
lambda: create_bundle(self.env_assist.get_env(), wait=False),
[
@@ -2422,7 +2457,6 @@ class CreateInToBundle(TestCase):
</resources>
"""
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.env_assist.assert_raise_library_error(
lambda: create_bundle(self.env_assist.get_env(), wait=False),
@@ -2448,7 +2482,6 @@ class CreateInToBundle(TestCase):
</resources>
"""
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.env_assist.assert_raise_library_error(
lambda: create_bundle(self.env_assist.get_env(), wait=False),
[
@@ -2463,7 +2496,6 @@ class CreateInToBundle(TestCase):
def test_wait_fail(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resources_post_simple,
wait=TIMEOUT,
@@ -2488,7 +2520,6 @@ class CreateInToBundle(TestCase):
)
def test_wait_ok_run_ok(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resources_post_simple, wait=TIMEOUT
)
@@ -2509,7 +2540,6 @@ class CreateInToBundle(TestCase):
)
def test_wait_ok_run_fail(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resources_post_simple, wait=TIMEOUT
)
@@ -2534,7 +2564,6 @@ class CreateInToBundle(TestCase):
)
def test_disabled_wait_ok_not_running(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resources_post_disabled, wait=TIMEOUT
)
@@ -2553,7 +2582,6 @@ class CreateInToBundle(TestCase):
)
def test_disabled_wait_ok_running(self):
self.config.runner.cib.load(resources=self.fixture_resources_pre)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=self.fixture_resources_post_disabled, wait=TIMEOUT
)
@@ -2581,7 +2609,6 @@ class CreateInToBundle(TestCase):
</resources>
"""
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.env_assist.assert_raise_library_error(
lambda: create_bundle(self.env_assist.get_env(), wait=False)
)
@@ -2605,7 +2632,6 @@ class CreateInToBundle(TestCase):
</resources>
"""
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=(
self.fixture_resource_post_simple_without_network.format(
@@ -2638,7 +2664,6 @@ class CreateInToBundle(TestCase):
</resources>
"""
)
- self.config.runner.pcmk.resource_agent_self_validation({}, output="")
self.config.env.push_cib(
resources=(
self.fixture_resource_post_simple_without_network.format(
@@ -2655,3 +2680,32 @@ class CreateInToBundle(TestCase):
self._test_with_network_defined(
'<network ip-range-start="192.168.100.200"/>'
)
+
+ def test_resource_self_validation_failure(self):
+ self.config.runner.cib.load()
+ self.config.runner.pcmk.resource_agent_self_validation(
+ {},
+ output="""
+ <output source="stderr">not ignored</output>
+ <output source="stdout">this is ignored</output>
+ <output source="stderr">
+ first issue
+ another one
+ </output>
+ """,
+ returncode=1,
+ )
+ self.env_assist.assert_raise_library_error(
+ lambda: create_bundle(
+ self.env_assist.get_env(), enable_agent_self_validation=True
+ ),
+ )
+ self.env_assist.assert_reports(
+ [
+ fixture.error(
+ reports.codes.AGENT_SELF_VALIDATION_RESULT,
+ result="not ignored\nfirst issue\nanother one",
+ force_code=reports.codes.FORCE,
+ )
+ ]
+ )
diff --git a/pcs_test/tier0/lib/commands/test_booth.py b/pcs_test/tier0/lib/commands/test_booth.py
index 220d058f..e0b6924e 100644
--- a/pcs_test/tier0/lib/commands/test_booth.py
+++ b/pcs_test/tier0/lib/commands/test_booth.py
@@ -1754,30 +1754,10 @@ class CreateInCluster(TestCase, FixtureMixin):
agent_name="ocf:heartbeat:IPaddr2",
name="runner.pcmk.load_agent.ipaddr2",
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(ip=self.site_ip),
- standard="ocf",
- provider="heartbeat",
- agent_type="IPaddr2",
- output="",
- )
self.config.runner.pcmk.load_agent(
agent_name="ocf:pacemaker:booth-site",
name="runner.pcmk.load_agent.booth-site",
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(
- config=os.path.join(
- settings.booth_config_dir,
- f"{instance_name}.conf",
- )
- ),
- standard="ocf",
- provider="pacemaker",
- agent_type="booth-site",
- output="",
- name="runner.pcmk.agent_self_validation.booth-site",
- )
self.config.env.push_cib(
resources=self.fixture_cib_booth_group(instance_name)
)
@@ -1809,33 +1789,11 @@ class CreateInCluster(TestCase, FixtureMixin):
name="runner.pcmk.load_agent.ipaddr2",
env=env,
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(ip=self.site_ip),
- standard="ocf",
- provider="heartbeat",
- agent_type="IPaddr2",
- output="",
- env=env,
- )
self.config.runner.pcmk.load_agent(
agent_name="ocf:pacemaker:booth-site",
name="runner.pcmk.load_agent.booth-site",
env=env,
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(
- config=os.path.join(
- settings.booth_config_dir,
- f"{constants.DEFAULT_INSTANCE_NAME}.conf",
- )
- ),
- standard="ocf",
- provider="pacemaker",
- agent_type="booth-site",
- output="",
- env=env,
- name="runner.pcmk.agent_self_validation.booth-site",
- )
self.config.env.push_cib(resources=self.fixture_cib_booth_group())
commands.create_in_cluster(self.env_assist.get_env(), self.site_ip)
@@ -1943,13 +1901,6 @@ class CreateInCluster(TestCase, FixtureMixin):
agent_name="ocf:heartbeat:IPaddr2",
name="runner.pcmk.load_agent.ipaddr2",
)
- self.config.runner.pcmk.resource_agent_self_validation(
- dict(ip=self.site_ip),
- standard="ocf",
- provider="heartbeat",
- agent_type="IPaddr2",
- output="",
- )
self.config.runner.pcmk.load_agent(
agent_name="ocf:pacemaker:booth-site",
agent_is_missing=True,
diff --git a/pcs_test/tier0/lib/commands/test_stonith.py b/pcs_test/tier0/lib/commands/test_stonith.py
index 65a0608f..eedd1c04 100644
--- a/pcs_test/tier0/lib/commands/test_stonith.py
+++ b/pcs_test/tier0/lib/commands/test_stonith.py
@@ -108,9 +108,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- instance_attributes, agent_name, output=""
- )
self.config.env.push_cib(
resources=self._expected_cib(expected_cib_simple)
)
@@ -158,6 +155,7 @@ class CreateMixin:
operations=[],
meta_attributes={},
instance_attributes=instance_attributes,
+ enable_agent_self_validation=True,
),
)
self.env_assist.assert_reports(
@@ -208,6 +206,7 @@ class CreateMixin:
meta_attributes={},
instance_attributes=instance_attributes,
allow_invalid_instance_attributes=True,
+ enable_agent_self_validation=True,
)
self.env_assist.assert_reports(
[
@@ -245,6 +244,7 @@ class CreateMixin:
operations=[],
meta_attributes={},
instance_attributes=instance_attributes,
+ enable_agent_self_validation=True,
),
)
self.env_assist.assert_reports(
@@ -266,9 +266,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- {}, agent_name, output=""
- )
self.config.env.push_cib(
resources=self._expected_cib(expected_cib_unfencing)
)
@@ -306,9 +303,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- instance_attributes, agent_name, output=""
- )
self.config.env.push_cib(resources=self._expected_cib(expected_cib))
self._create(
@@ -334,9 +328,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- {}, agent_name, output=""
- )
self.config.env.push_cib(
resources=self._expected_cib(expected_cib_operations)
)
@@ -395,9 +386,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- instance_attributes, agent_name, output=""
- )
self.config.env.push_cib(
resources=self._expected_cib(expected_cib_simple_forced)
)
@@ -611,9 +599,6 @@ class CreateMixin:
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load()
- self.config.runner.pcmk.stonith_agent_self_validation(
- instance_attributes, agent_name, output=""
- )
self.config.env.push_cib(
resources=self._expected_cib(expected_cib_simple), wait=timeout
)
@@ -727,9 +712,6 @@ class CreateInGroup(CreateMixin, TestCase):
)
self.config.runner.pcmk.load_fake_agent_metadata()
self.config.runner.cib.load(resources=original_cib)
- self.config.runner.pcmk.stonith_agent_self_validation(
- instance_attributes, agent_name, output=""
- )
self.config.env.push_cib(resources=expected_cib)
stonith.create_in_group(
diff --git a/pcs_test/tier1/cib_resource/test_create.py b/pcs_test/tier1/cib_resource/test_create.py
index 3a088513..bbc1acaa 100644
--- a/pcs_test/tier1/cib_resource/test_create.py
+++ b/pcs_test/tier1/cib_resource/test_create.py
@@ -751,7 +751,9 @@ class Promotable(TestCase, AssertPcsMixin):
ensure_disabled=False,
use_default_operations=True,
wait=False,
+ enable_agent_self_validation=False,
):
+ # pylint: disable=too-many-arguments
options = locals()
del options["self"]
return options
diff --git a/pcs_test/tier1/cib_resource/test_stonith_create.py b/pcs_test/tier1/cib_resource/test_stonith_create.py
index 77277b75..ea429b64 100644
--- a/pcs_test/tier1/cib_resource/test_stonith_create.py
+++ b/pcs_test/tier1/cib_resource/test_stonith_create.py
@@ -45,7 +45,6 @@ class PlainStonith(ResourceTest):
</operations>
</primitive>
</resources>""",
- output_start="Warning: Validation result from agent:",
)
def test_error_when_not_valid_name(self):
@@ -249,7 +248,6 @@ class WithMeta(ResourceTest):
</operations>
</primitive>
</resources>""",
- output_start="Warning: Validation result from agent:",
)
diff --git a/pcs_test/tier1/legacy/test_resource.py b/pcs_test/tier1/legacy/test_resource.py
index 3ba32ec7..d53af88b 100644
--- a/pcs_test/tier1/legacy/test_resource.py
+++ b/pcs_test/tier1/legacy/test_resource.py
@@ -5906,7 +5906,13 @@ class UpdateInstanceAttrs(
def test_agent_self_validation_failure(self):
self.fixture_resource()
self.assert_pcs_fail(
- ["resource", "update", "R", "fake=is_invalid=True"],
+ [
+ "resource",
+ "update",
+ "R",
+ "fake=is_invalid=True",
+ "--agent-validation",
+ ],
stdout_start="Error: Validation result from agent (use --force to override):",
)
diff --git a/pcs_test/tier1/legacy/test_stonith.py b/pcs_test/tier1/legacy/test_stonith.py
index 7e7ec030..8ca84065 100644
--- a/pcs_test/tier1/legacy/test_stonith.py
+++ b/pcs_test/tier1/legacy/test_stonith.py
@@ -1283,6 +1283,27 @@ class StonithTest(TestCase, AssertPcsMixin):
"Deleting Resource - apc-fencing\n",
)
+ self.assert_pcs_fail(
+ (
+ "stonith create apc-fencing fence_apc ip=morph-apc username=apc "
+ "--agent-validation"
+ ).split(),
+ stdout_start="Error: Validation result from agent",
+ )
+
+ self.assert_pcs_success(
+ (
+ "stonith create apc-fencing fence_apc ip=morph-apc username=apc "
+ "--agent-validation --force"
+ ).split(),
+ stdout_start="Warning: Validation result from agent",
+ )
+
+ self.assert_pcs_success(
+ "stonith remove apc-fencing".split(),
+ stdout_full="Deleting Resource - apc-fencing\n",
+ )
+
self.assert_pcs_fail(
"stonith update test3 bad_ipaddr=test username=login".split(),
stdout_regexp=(
@@ -1292,8 +1313,8 @@ class StonithTest(TestCase, AssertPcsMixin):
)
self.assert_pcs_success(
- "stonith update test3 username=testA".split(),
- stdout_start="Warning: ",
+ "stonith update test3 username=testA --agent-validation".split(),
+ stdout_start="Warning: The resource was misconfigured before the update,",
)
self.assert_pcs_success(
--
2.39.0