1308 lines
52 KiB
Diff
1308 lines
52 KiB
Diff
From 62b970d5e9edbdd68dc006193b0e606fb7ae7cdd Mon Sep 17 00:00:00 2001
|
|
From: Tomas Jelinek <tojeline@redhat.com>
|
|
Date: Thu, 2 Jul 2020 15:18:29 +0200
|
|
Subject: [PATCH 1/3] upgrade CIB schema for on-fail=demote
|
|
|
|
---
|
|
pcs/lib/cib/resource/operations.py | 9 +-
|
|
pcs/lib/commands/remote_node.py | 73 +++--
|
|
pcs/lib/commands/resource.py | 269 ++++++++++--------
|
|
pcs/resource.py | 51 +++-
|
|
pcs_test/resources/cib-empty-3.3.xml | 2 +-
|
|
pcs_test/resources/cib-empty-3.4.xml | 2 +-
|
|
.../tier0/lib/cib/test_resource_operations.py | 9 +-
|
|
.../remote_node/test_node_add_remote.py | 54 +++-
|
|
.../commands/resource/test_resource_create.py | 237 ++++++++++++++-
|
|
pcs_test/tier1/cib_resource/test_create.py | 2 +-
|
|
pcs_test/tier1/legacy/test_resource.py | 23 ++
|
|
pcs_test/tools/misc.py | 6 +
|
|
pcsd/capabilities.xml | 42 +++
|
|
13 files changed, 594 insertions(+), 185 deletions(-)
|
|
|
|
diff --git a/pcs/lib/cib/resource/operations.py b/pcs/lib/cib/resource/operations.py
|
|
index 131e0a49..79d00685 100644
|
|
--- a/pcs/lib/cib/resource/operations.py
|
|
+++ b/pcs/lib/cib/resource/operations.py
|
|
@@ -39,13 +39,14 @@ ATTRIBUTES = [
|
|
]
|
|
|
|
ON_FAIL_VALUES = [
|
|
- "ignore",
|
|
"block",
|
|
- "stop",
|
|
- "restart",
|
|
- "standby",
|
|
+ "demote",
|
|
"fence",
|
|
+ "ignore",
|
|
+ "restart",
|
|
"restart-container",
|
|
+ "standby",
|
|
+ "stop",
|
|
]
|
|
|
|
BOOLEAN_VALUES = [
|
|
diff --git a/pcs/lib/commands/remote_node.py b/pcs/lib/commands/remote_node.py
|
|
index 6a2656a5..575e8044 100644
|
|
--- a/pcs/lib/commands/remote_node.py
|
|
+++ b/pcs/lib/commands/remote_node.py
|
|
@@ -1,3 +1,10 @@
|
|
+from typing import (
|
|
+ Iterable,
|
|
+ Mapping,
|
|
+ Optional,
|
|
+ Union,
|
|
+)
|
|
+
|
|
from pcs import settings
|
|
from pcs.common import reports
|
|
from pcs.common.file import RawFileError
|
|
@@ -13,6 +20,10 @@ from pcs.lib.cib.tools import (
|
|
ElementSearcher,
|
|
get_resources,
|
|
)
|
|
+
|
|
+# TODO lib.commands should never import each other. This is to be removed when
|
|
+# the 'resource create' commands are overhauled.
|
|
+from pcs.lib.commands.resource import get_required_cib_version_for_primitive
|
|
from pcs.lib.communication.nodes import (
|
|
DistributeFiles,
|
|
GetHostInfo,
|
|
@@ -24,6 +35,7 @@ from pcs.lib.communication.tools import (
|
|
run as run_com,
|
|
run_and_raise,
|
|
)
|
|
+from pcs.lib.corosync.config_facade import ConfigFacade as CorosyncConfigFacade
|
|
from pcs.lib.env import LibraryEnvironment
|
|
from pcs.lib.errors import LibraryError
|
|
from pcs.lib.file.instance import FileInstance
|
|
@@ -33,6 +45,9 @@ from pcs.lib.pacemaker import state
|
|
from pcs.lib.pacemaker.live import remove_node
|
|
|
|
|
|
+WaitType = Union[None, bool, int]
|
|
+
|
|
+
|
|
def _reports_skip_new_node(new_node_name, reason_type):
|
|
assert reason_type in {"unreachable", "not_live_cib"}
|
|
return [
|
|
@@ -220,19 +235,19 @@ def _ensure_resource_running(env: LibraryEnvironment, resource_id):
|
|
|
|
|
|
def node_add_remote(
|
|
- env,
|
|
- node_name,
|
|
- node_addr,
|
|
- operations,
|
|
- meta_attributes,
|
|
- instance_attributes,
|
|
- skip_offline_nodes=False,
|
|
- allow_incomplete_distribution=False,
|
|
- allow_pacemaker_remote_service_fail=False,
|
|
- allow_invalid_operation=False,
|
|
- allow_invalid_instance_attributes=False,
|
|
- use_default_operations=True,
|
|
- wait=False,
|
|
+ env: LibraryEnvironment,
|
|
+ node_name: str,
|
|
+ node_addr: Optional[str],
|
|
+ operations: Iterable[Mapping[str, str]],
|
|
+ meta_attributes: Mapping[str, str],
|
|
+ instance_attributes: Mapping[str, str],
|
|
+ skip_offline_nodes: bool = False,
|
|
+ allow_incomplete_distribution: bool = False,
|
|
+ allow_pacemaker_remote_service_fail: bool = False,
|
|
+ allow_invalid_operation: bool = False,
|
|
+ allow_invalid_instance_attributes: bool = False,
|
|
+ use_default_operations: bool = True,
|
|
+ wait: WaitType = False,
|
|
):
|
|
# pylint: disable=too-many-arguments
|
|
# pylint: disable=too-many-branches
|
|
@@ -241,34 +256,36 @@ def node_add_remote(
|
|
"""
|
|
create an ocf:pacemaker:remote resource and use it as a remote node
|
|
|
|
- LibraryEnvironment env -- provides all for communication with externals
|
|
- string node_name -- the name of the new node
|
|
- mixed node_addr -- the address of the new node or None for default
|
|
- list of dict operations -- attributes for each entered operation
|
|
- dict meta_attributes -- attributes for primitive/meta_attributes
|
|
- dict instance_attributes -- attributes for primitive/instance_attributes
|
|
- bool skip_offline_nodes -- if True, ignore when some nodes are offline
|
|
- bool allow_incomplete_distribution -- if True, allow this command to
|
|
+ env -- provides all for communication with externals
|
|
+ node_name -- the name of the new node
|
|
+ node_addr -- the address of the new node or None for default
|
|
+ operations -- attributes for each entered operation
|
|
+ meta_attributes -- attributes for primitive/meta_attributes
|
|
+ instance_attributes -- attributes for primitive/instance_attributes
|
|
+ skip_offline_nodes -- if True, ignore when some nodes are offline
|
|
+ allow_incomplete_distribution -- if True, allow this command to
|
|
finish successfully even if file distribution did not succeed
|
|
- bool allow_pacemaker_remote_service_fail -- if True, allow this command to
|
|
+ allow_pacemaker_remote_service_fail -- if True, allow this command to
|
|
finish successfully even if starting/enabling pacemaker_remote did not
|
|
succeed
|
|
- bool allow_invalid_operation -- if True, allow to use operations that
|
|
+ allow_invalid_operation -- if True, allow to use operations that
|
|
are not listed in a resource agent metadata
|
|
- bool allow_invalid_instance_attributes -- if True, allow to use instance
|
|
+ allow_invalid_instance_attributes -- if True, allow to use instance
|
|
attributes that are not listed in a resource agent metadata and allow to
|
|
omit required instance_attributes
|
|
- bool use_default_operations -- if True, add operations specified in
|
|
+ use_default_operations -- if True, add operations specified in
|
|
a resource agent metadata to the resource
|
|
- mixed wait -- a flag for controlling waiting for pacemaker idle mechanism
|
|
+ wait -- a flag for controlling waiting for pacemaker idle mechanism
|
|
"""
|
|
env.ensure_wait_satisfiable(wait)
|
|
|
|
report_processor = env.report_processor
|
|
- cib = env.get_cib()
|
|
+ cib = env.get_cib(
|
|
+ minimal_version=get_required_cib_version_for_primitive(operations)
|
|
+ )
|
|
id_provider = IdProvider(cib)
|
|
if env.is_cib_live:
|
|
- corosync_conf = env.get_corosync_conf()
|
|
+ corosync_conf: Optional[CorosyncConfigFacade] = env.get_corosync_conf()
|
|
else:
|
|
corosync_conf = None
|
|
report_processor.report(
|
|
diff --git a/pcs/lib/commands/resource.py b/pcs/lib/commands/resource.py
|
|
index 75826c9d..db4b7bb3 100644
|
|
--- a/pcs/lib/commands/resource.py
|
|
+++ b/pcs/lib/commands/resource.py
|
|
@@ -61,6 +61,9 @@ from pcs.lib.resource_agent import (
|
|
from pcs.lib.validate import ValueTimeInterval
|
|
|
|
|
|
+WaitType = Union[None, bool, int]
|
|
+
|
|
+
|
|
@contextmanager
|
|
def resource_environment(
|
|
env,
|
|
@@ -262,44 +265,43 @@ def _get_required_cib_version_for_container(
|
|
|
|
|
|
def create(
|
|
- env,
|
|
- resource_id,
|
|
- resource_agent_name,
|
|
- operation_list,
|
|
- meta_attributes,
|
|
- instance_attributes,
|
|
- allow_absent_agent=False,
|
|
- allow_invalid_operation=False,
|
|
- allow_invalid_instance_attributes=False,
|
|
- use_default_operations=True,
|
|
- ensure_disabled=False,
|
|
- wait=False,
|
|
- allow_not_suitable_command=False,
|
|
+ env: LibraryEnvironment,
|
|
+ resource_id: str,
|
|
+ resource_agent_name: str,
|
|
+ operation_list: Iterable[Mapping[str, str]],
|
|
+ meta_attributes: Mapping[str, str],
|
|
+ instance_attributes: Mapping[str, str],
|
|
+ allow_absent_agent: bool = False,
|
|
+ allow_invalid_operation: bool = False,
|
|
+ allow_invalid_instance_attributes: bool = False,
|
|
+ use_default_operations: bool = True,
|
|
+ ensure_disabled: bool = False,
|
|
+ wait: WaitType = False,
|
|
+ allow_not_suitable_command: bool = False,
|
|
):
|
|
# pylint: disable=too-many-arguments, too-many-locals
|
|
"""
|
|
- Create resource in a cib.
|
|
+ Create a primitive resource in a cib.
|
|
|
|
- LibraryEnvironment env provides all for communication with externals
|
|
- string resource_id is identifier of resource
|
|
- string resource_agent_name contains name for the identification of agent
|
|
- list of dict operation_list contains attributes for each entered operation
|
|
- dict meta_attributes contains attributes for primitive/meta_attributes
|
|
- dict instance_attributes contains attributes for
|
|
- primitive/instance_attributes
|
|
- bool allow_absent_agent is a flag for allowing agent that is not installed
|
|
+ env -- provides all for communication with externals
|
|
+ resource_id -- is identifier of resource
|
|
+ resource_agent_name -- contains name for the identification of agent
|
|
+ operation_list -- contains attributes for each entered operation
|
|
+ meta_attributes -- contains attributes for primitive/meta_attributes
|
|
+ instance_attributes -- contains attributes for primitive/instance_attributes
|
|
+ allow_absent_agent -- is a flag for allowing agent that is not installed
|
|
in a system
|
|
- bool allow_invalid_operation is a flag for allowing to use operations that
|
|
+ allow_invalid_operation -- is a flag for allowing to use operations that
|
|
are not listed in a resource agent metadata
|
|
- bool allow_invalid_instance_attributes is a flag for allowing to use
|
|
+ allow_invalid_instance_attributes -- is a flag for allowing to use
|
|
instance attributes that are not listed in a resource agent metadata
|
|
or for allowing to not use the instance_attributes that are required in
|
|
resource agent metadata
|
|
- bool use_default_operations is a flag for stopping stopping of adding
|
|
+ use_default_operations -- is a flag for stopping stopping of adding
|
|
default cib operations (specified in a resource agent)
|
|
- bool ensure_disabled is flag that keeps resource in target-role "Stopped"
|
|
- mixed wait is flag for controlling waiting for pacemaker idle mechanism
|
|
- bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
+ ensure_disabled -- is flag that keeps resource in target-role "Stopped"
|
|
+ wait -- is flag for controlling waiting for pacemaker idle mechanism
|
|
+ allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
"""
|
|
resource_agent = get_agent(
|
|
env.report_processor,
|
|
@@ -315,6 +317,9 @@ def create(
|
|
ensure_disabled
|
|
or resource.common.are_meta_disabled(meta_attributes)
|
|
),
|
|
+ required_cib_version=get_required_cib_version_for_primitive(
|
|
+ operation_list
|
|
+ ),
|
|
) as resources_section:
|
|
id_provider = IdProvider(resources_section)
|
|
_check_special_cases(
|
|
@@ -345,46 +350,45 @@ def create(
|
|
|
|
|
|
def create_as_clone(
|
|
- env,
|
|
- resource_id,
|
|
- resource_agent_name,
|
|
- operation_list,
|
|
- meta_attributes,
|
|
- instance_attributes,
|
|
- clone_meta_options,
|
|
- allow_absent_agent=False,
|
|
- allow_invalid_operation=False,
|
|
- allow_invalid_instance_attributes=False,
|
|
- use_default_operations=True,
|
|
- ensure_disabled=False,
|
|
- wait=False,
|
|
- allow_not_suitable_command=False,
|
|
+ env: LibraryEnvironment,
|
|
+ resource_id: str,
|
|
+ resource_agent_name: str,
|
|
+ operation_list: Iterable[Mapping[str, str]],
|
|
+ meta_attributes: Mapping[str, str],
|
|
+ instance_attributes: Mapping[str, str],
|
|
+ clone_meta_options: Mapping[str, str],
|
|
+ allow_absent_agent: bool = False,
|
|
+ allow_invalid_operation: bool = False,
|
|
+ allow_invalid_instance_attributes: bool = False,
|
|
+ use_default_operations: bool = True,
|
|
+ ensure_disabled: bool = False,
|
|
+ wait: WaitType = False,
|
|
+ allow_not_suitable_command: bool = False,
|
|
):
|
|
# pylint: disable=too-many-arguments, too-many-locals
|
|
"""
|
|
- Create resource in a clone
|
|
+ Create a primitive resource in a clone
|
|
|
|
- LibraryEnvironment env provides all for communication with externals
|
|
- string resource_id is identifier of resource
|
|
- string resource_agent_name contains name for the identification of agent
|
|
- list of dict operation_list contains attributes for each entered operation
|
|
- dict meta_attributes contains attributes for primitive/meta_attributes
|
|
- dict instance_attributes contains attributes for
|
|
- primitive/instance_attributes
|
|
- dict clone_meta_options contains attributes for clone/meta_attributes
|
|
- bool allow_absent_agent is a flag for allowing agent that is not installed
|
|
+ env -- provides all for communication with externals
|
|
+ resource_id -- is identifier of resource
|
|
+ resource_agent_name -- contains name for the identification of agent
|
|
+ operation_list -- contains attributes for each entered operation
|
|
+ meta_attributes -- contains attributes for primitive/meta_attributes
|
|
+ instance_attributes -- contains attributes for primitive/instance_attributes
|
|
+ clone_meta_options -- contains attributes for clone/meta_attributes
|
|
+ allow_absent_agent -- is a flag for allowing agent that is not installed
|
|
in a system
|
|
- bool allow_invalid_operation is a flag for allowing to use operations that
|
|
+ allow_invalid_operation -- is a flag for allowing to use operations that
|
|
are not listed in a resource agent metadata
|
|
- bool allow_invalid_instance_attributes is a flag for allowing to use
|
|
+ allow_invalid_instance_attributes -- is a flag for allowing to use
|
|
instance attributes that are not listed in a resource agent metadata
|
|
or for allowing to not use the instance_attributes that are required in
|
|
resource agent metadata
|
|
- bool use_default_operations is a flag for stopping stopping of adding
|
|
+ use_default_operations -- is a flag for stopping stopping of adding
|
|
default cib operations (specified in a resource agent)
|
|
- bool ensure_disabled is flag that keeps resource in target-role "Stopped"
|
|
- mixed wait is flag for controlling waiting for pacemaker idle mechanism
|
|
- bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
+ ensure_disabled -- is flag that keeps resource in target-role "Stopped"
|
|
+ wait -- is flag for controlling waiting for pacemaker idle mechanism
|
|
+ allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
"""
|
|
resource_agent = get_agent(
|
|
env.report_processor,
|
|
@@ -401,6 +405,9 @@ def create_as_clone(
|
|
or resource.common.are_meta_disabled(meta_attributes)
|
|
or resource.common.is_clone_deactivated_by_meta(clone_meta_options)
|
|
),
|
|
+ required_cib_version=get_required_cib_version_for_primitive(
|
|
+ operation_list
|
|
+ ),
|
|
) as resources_section:
|
|
id_provider = IdProvider(resources_section)
|
|
_check_special_cases(
|
|
@@ -437,49 +444,50 @@ def create_as_clone(
|
|
|
|
|
|
def create_in_group(
|
|
- env,
|
|
- resource_id,
|
|
- resource_agent_name,
|
|
- group_id,
|
|
- operation_list,
|
|
- meta_attributes,
|
|
- instance_attributes,
|
|
- allow_absent_agent=False,
|
|
- allow_invalid_operation=False,
|
|
- allow_invalid_instance_attributes=False,
|
|
- use_default_operations=True,
|
|
- ensure_disabled=False,
|
|
- adjacent_resource_id=None,
|
|
- put_after_adjacent=False,
|
|
- wait=False,
|
|
- allow_not_suitable_command=False,
|
|
+ env: LibraryEnvironment,
|
|
+ resource_id: str,
|
|
+ resource_agent_name: str,
|
|
+ group_id: str,
|
|
+ operation_list: Iterable[Mapping[str, str]],
|
|
+ meta_attributes: Mapping[str, str],
|
|
+ instance_attributes: Mapping[str, str],
|
|
+ allow_absent_agent: bool = False,
|
|
+ allow_invalid_operation: bool = False,
|
|
+ allow_invalid_instance_attributes: bool = False,
|
|
+ use_default_operations: bool = True,
|
|
+ ensure_disabled: bool = False,
|
|
+ adjacent_resource_id: Optional[str] = None,
|
|
+ put_after_adjacent: bool = False,
|
|
+ wait: WaitType = False,
|
|
+ allow_not_suitable_command: bool = False,
|
|
):
|
|
# pylint: disable=too-many-arguments, too-many-locals
|
|
"""
|
|
Create resource in a cib and put it into defined group
|
|
|
|
- LibraryEnvironment env provides all for communication with externals
|
|
- string resource_id is identifier of resource
|
|
- string resource_agent_name contains name for the identification of agent
|
|
- string group_id is identificator for group to put primitive resource inside
|
|
- list of dict operation_list contains attributes for each entered operation
|
|
- dict meta_attributes contains attributes for primitive/meta_attributes
|
|
- bool allow_absent_agent is a flag for allowing agent that is not installed
|
|
+ env -- provides all for communication with externals
|
|
+ resource_id -- is identifier of resource
|
|
+ resource_agent_name -- contains name for the identification of agent
|
|
+ group_id -- is identificator for group to put primitive resource inside
|
|
+ operation_list -- contains attributes for each entered operation
|
|
+ meta_attributes -- contains attributes for primitive/meta_attributes
|
|
+ instance_attributes -- contains attributes for primitive/instance_attributes
|
|
+ allow_absent_agent -- is a flag for allowing agent that is not installed
|
|
in a system
|
|
- bool allow_invalid_operation is a flag for allowing to use operations that
|
|
+ allow_invalid_operation -- is a flag for allowing to use operations that
|
|
are not listed in a resource agent metadata
|
|
- bool allow_invalid_instance_attributes is a flag for allowing to use
|
|
+ allow_invalid_instance_attributes -- is a flag for allowing to use
|
|
instance attributes that are not listed in a resource agent metadata
|
|
or for allowing to not use the instance_attributes that are required in
|
|
resource agent metadata
|
|
- bool use_default_operations is a flag for stopping stopping of adding
|
|
+ use_default_operations -- is a flag for stopping stopping of adding
|
|
default cib operations (specified in a resource agent)
|
|
- bool ensure_disabled is flag that keeps resource in target-role "Stopped"
|
|
- string adjacent_resource_id identify neighbor of a newly created resource
|
|
- bool put_after_adjacent is flag to put a newly create resource befor/after
|
|
+ ensure_disabled -- is flag that keeps resource in target-role "Stopped"
|
|
+ adjacent_resource_id -- identify neighbor of a newly created resource
|
|
+ put_after_adjacent -- is flag to put a newly create resource befor/after
|
|
adjacent resource
|
|
- mixed wait is flag for controlling waiting for pacemaker idle mechanism
|
|
- bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
+ wait -- is flag for controlling waiting for pacemaker idle mechanism
|
|
+ allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
"""
|
|
resource_agent = get_agent(
|
|
env.report_processor,
|
|
@@ -495,6 +503,9 @@ def create_in_group(
|
|
ensure_disabled
|
|
or resource.common.are_meta_disabled(meta_attributes)
|
|
),
|
|
+ required_cib_version=get_required_cib_version_for_primitive(
|
|
+ operation_list
|
|
+ ),
|
|
) as resources_section:
|
|
id_provider = IdProvider(resources_section)
|
|
_check_special_cases(
|
|
@@ -532,48 +543,48 @@ def create_in_group(
|
|
|
|
|
|
def create_into_bundle(
|
|
- env,
|
|
- resource_id,
|
|
- resource_agent_name,
|
|
- operation_list,
|
|
- meta_attributes,
|
|
- instance_attributes,
|
|
- bundle_id,
|
|
- allow_absent_agent=False,
|
|
- allow_invalid_operation=False,
|
|
- allow_invalid_instance_attributes=False,
|
|
- use_default_operations=True,
|
|
- ensure_disabled=False,
|
|
- wait=False,
|
|
- allow_not_suitable_command=False,
|
|
- allow_not_accessible_resource=False,
|
|
+ env: LibraryEnvironment,
|
|
+ resource_id: str,
|
|
+ resource_agent_name: str,
|
|
+ operation_list: Iterable[Mapping[str, str]],
|
|
+ meta_attributes: Mapping[str, str],
|
|
+ instance_attributes: Mapping[str, str],
|
|
+ bundle_id: str,
|
|
+ allow_absent_agent: bool = False,
|
|
+ allow_invalid_operation: bool = False,
|
|
+ allow_invalid_instance_attributes: bool = False,
|
|
+ use_default_operations: bool = True,
|
|
+ ensure_disabled: bool = False,
|
|
+ wait: WaitType = False,
|
|
+ allow_not_suitable_command: bool = False,
|
|
+ allow_not_accessible_resource: bool = False,
|
|
):
|
|
# pylint: disable=too-many-arguments, too-many-locals
|
|
"""
|
|
Create a new resource in a cib and put it into an existing bundle
|
|
|
|
- LibraryEnvironment env provides all for communication with externals
|
|
- string resource_id is identifier of resource
|
|
- string resource_agent_name contains name for the identification of agent
|
|
- list of dict operation_list contains attributes for each entered operation
|
|
- dict meta_attributes contains attributes for primitive/meta_attributes
|
|
- dict instance_attributes contains attributes for
|
|
+ env -- provides all for communication with externals
|
|
+ resource_id -- is identifier of resource
|
|
+ resource_agent_name -- contains name for the identification of agent
|
|
+ operation_list -- contains attributes for each entered operation
|
|
+ meta_attributes -- contains attributes for primitive/meta_attributes
|
|
+ instance_attributes -- contains attributes for
|
|
primitive/instance_attributes
|
|
- string bundle_id is id of an existing bundle to put the created resource in
|
|
- bool allow_absent_agent is a flag for allowing agent that is not installed
|
|
+ bundle_id -- is id of an existing bundle to put the created resource in
|
|
+ allow_absent_agent -- is a flag for allowing agent that is not installed
|
|
in a system
|
|
- bool allow_invalid_operation is a flag for allowing to use operations that
|
|
+ allow_invalid_operation -- is a flag for allowing to use operations that
|
|
are not listed in a resource agent metadata
|
|
- bool allow_invalid_instance_attributes is a flag for allowing to use
|
|
+ allow_invalid_instance_attributes -- is a flag for allowing to use
|
|
instance attributes that are not listed in a resource agent metadata
|
|
or for allowing to not use the instance_attributes that are required in
|
|
resource agent metadata
|
|
- bool use_default_operations is a flag for stopping stopping of adding
|
|
+ use_default_operations -- is a flag for stopping stopping of adding
|
|
default cib operations (specified in a resource agent)
|
|
- bool ensure_disabled is flag that keeps resource in target-role "Stopped"
|
|
- mixed wait is flag for controlling waiting for pacemaker idle mechanism
|
|
- bool allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
- bool allow_not_accessible_resource -- flag for
|
|
+ ensure_disabled -- is flag that keeps resource in target-role "Stopped"
|
|
+ wait -- is flag for controlling waiting for pacemaker idle mechanism
|
|
+ allow_not_suitable_command -- flag for FORCE_NOT_SUITABLE_COMMAND
|
|
+ allow_not_accessible_resource -- flag for
|
|
FORCE_RESOURCE_IN_BUNDLE_NOT_ACCESSIBLE
|
|
"""
|
|
resource_agent = get_agent(
|
|
@@ -582,6 +593,11 @@ def create_into_bundle(
|
|
resource_agent_name,
|
|
allow_absent_agent,
|
|
)
|
|
+ required_cib_version = get_required_cib_version_for_primitive(
|
|
+ operation_list
|
|
+ )
|
|
+ if not required_cib_version:
|
|
+ required_cib_version = Version(2, 8, 0)
|
|
with resource_environment(
|
|
env,
|
|
wait,
|
|
@@ -590,7 +606,7 @@ def create_into_bundle(
|
|
ensure_disabled
|
|
or resource.common.are_meta_disabled(meta_attributes)
|
|
),
|
|
- required_cib_version=Version(2, 8, 0),
|
|
+ required_cib_version=required_cib_version,
|
|
) as resources_section:
|
|
id_provider = IdProvider(resources_section)
|
|
_check_special_cases(
|
|
@@ -1070,9 +1086,7 @@ def disable_simulate(
|
|
|
|
|
|
def enable(
|
|
- env: LibraryEnvironment,
|
|
- resource_or_tag_ids: Iterable[str],
|
|
- wait: Optional[Union[bool, int]],
|
|
+ env: LibraryEnvironment, resource_or_tag_ids: Iterable[str], wait: WaitType,
|
|
):
|
|
"""
|
|
Allow specified resources to be started by the cluster
|
|
@@ -1689,3 +1703,12 @@ def _find_resources_expand_tags_or_raise(
|
|
return resource.common.expand_tags_to_resources(
|
|
resources_section, resource_or_tag_el_list,
|
|
)
|
|
+
|
|
+
|
|
+def get_required_cib_version_for_primitive(
|
|
+ op_list: Iterable[Mapping[str, str]]
|
|
+) -> Optional[Version]:
|
|
+ for op in op_list:
|
|
+ if op.get("on-fail", "") == "demote":
|
|
+ return Version(3, 4, 0)
|
|
+ return None
|
|
diff --git a/pcs/resource.py b/pcs/resource.py
|
|
index e835fc99..9a3bd0ee 100644
|
|
--- a/pcs/resource.py
|
|
+++ b/pcs/resource.py
|
|
@@ -355,6 +355,21 @@ def resource_op_add_cmd(lib, argv, modifiers):
|
|
if not argv:
|
|
raise CmdLineInputError()
|
|
res_id = argv.pop(0)
|
|
+
|
|
+ # Check if we need to upgrade cib schema.
|
|
+ # To do that, argv must be parsed, which is duplication of parsing in
|
|
+ # resource_operation_add. But we need to upgrade the cib first before
|
|
+ # calling that function. Hopefully, this will be fixed in the new pcs
|
|
+ # architecture.
|
|
+
|
|
+ # argv[0] is an operation name
|
|
+ op_properties = utils.convert_args_to_tuples(argv[1:])
|
|
+ for key, value in op_properties:
|
|
+ if key == "on-fail" and value == "demote":
|
|
+ utils.checkAndUpgradeCIB(3, 4, 0)
|
|
+ break
|
|
+
|
|
+ # add the requested operation
|
|
utils.replace_cib_configuration(
|
|
resource_operation_add(utils.get_cib_dom(), res_id, argv)
|
|
)
|
|
@@ -895,8 +910,6 @@ def resource_update(lib, args, modifiers, deal_with_guest_change=True):
|
|
if len(args) < 2:
|
|
raise CmdLineInputError()
|
|
res_id = args.pop(0)
|
|
- cib_xml = utils.get_cib()
|
|
- dom = utils.get_cib_dom(cib_xml=cib_xml)
|
|
|
|
# Extract operation arguments
|
|
ra_values, op_values, meta_values = parse_resource_options(args)
|
|
@@ -907,6 +920,28 @@ def resource_update(lib, args, modifiers, deal_with_guest_change=True):
|
|
wait_timeout = utils.validate_wait_get_timeout()
|
|
wait = True
|
|
|
|
+ # Check if we need to upgrade cib schema.
|
|
+ # To do that, argv must be parsed, which is duplication of parsing below.
|
|
+ # But we need to upgrade the cib first before calling that function.
|
|
+ # Hopefully, this will be fixed in the new pcs architecture.
|
|
+
|
|
+ cib_upgraded = False
|
|
+ for op_argv in op_values:
|
|
+ if cib_upgraded:
|
|
+ break
|
|
+ if len(op_argv) < 2:
|
|
+ continue
|
|
+ # argv[0] is an operation name
|
|
+ op_vars = utils.convert_args_to_tuples(op_argv[1:])
|
|
+ for k, v in op_vars:
|
|
+ if k == "on-fail" and v == "demote":
|
|
+ utils.checkAndUpgradeCIB(3, 4, 0)
|
|
+ cib_upgraded = True
|
|
+ break
|
|
+
|
|
+ cib_xml = utils.get_cib()
|
|
+ dom = utils.get_cib_dom(cib_xml=cib_xml)
|
|
+
|
|
resource = utils.dom_get_resource(dom, res_id)
|
|
if not resource:
|
|
clone = utils.dom_get_clone(dom, res_id)
|
|
@@ -994,21 +1029,21 @@ def resource_update(lib, args, modifiers, deal_with_guest_change=True):
|
|
else:
|
|
operations = operations[0]
|
|
|
|
- for element in op_values:
|
|
- if not element:
|
|
+ for op_argv in op_values:
|
|
+ if not op_argv:
|
|
continue
|
|
|
|
- op_name = element[0]
|
|
+ op_name = op_argv[0]
|
|
if op_name.find("=") != -1:
|
|
utils.err(
|
|
"%s does not appear to be a valid operation action" % op_name
|
|
)
|
|
|
|
- if len(element) < 2:
|
|
+ if len(op_argv) < 2:
|
|
continue
|
|
|
|
op_role = ""
|
|
- op_vars = utils.convert_args_to_tuples(element[1:])
|
|
+ op_vars = utils.convert_args_to_tuples(op_argv[1:])
|
|
|
|
for k, v in op_vars:
|
|
if k == "role":
|
|
@@ -1032,7 +1067,7 @@ def resource_update(lib, args, modifiers, deal_with_guest_change=True):
|
|
dom = resource_operation_add(
|
|
dom,
|
|
res_id,
|
|
- element,
|
|
+ op_argv,
|
|
validate_strict=False,
|
|
before_op=updating_op_before,
|
|
)
|
|
diff --git a/pcs_test/resources/cib-empty-3.3.xml b/pcs_test/resources/cib-empty-3.3.xml
|
|
index 3a44fe08..4de94b6e 100644
|
|
--- a/pcs_test/resources/cib-empty-3.3.xml
|
|
+++ b/pcs_test/resources/cib-empty-3.3.xml
|
|
@@ -1,4 +1,4 @@
|
|
-<cib epoch="557" num_updates="122" admin_epoch="0" validate-with="pacemaker-3.3" crm_feature_set="3.1.0" update-origin="rh7-3" update-client="crmd" cib-last-written="Thu Aug 23 16:49:17 2012" have-quorum="0" dc-uuid="2">
|
|
+<cib epoch="557" num_updates="122" admin_epoch="0" validate-with="pacemaker-3.3" crm_feature_set="3.4.0" update-origin="rh7-3" update-client="crmd" cib-last-written="Thu Aug 23 16:49:17 2012" have-quorum="0" dc-uuid="2">
|
|
<configuration>
|
|
<crm_config/>
|
|
<nodes>
|
|
diff --git a/pcs_test/resources/cib-empty-3.4.xml b/pcs_test/resources/cib-empty-3.4.xml
|
|
index dcd4ff44..e677462d 100644
|
|
--- a/pcs_test/resources/cib-empty-3.4.xml
|
|
+++ b/pcs_test/resources/cib-empty-3.4.xml
|
|
@@ -1,4 +1,4 @@
|
|
-<cib epoch="557" num_updates="122" admin_epoch="0" validate-with="pacemaker-3.4" crm_feature_set="3.1.0" update-origin="rh7-3" update-client="crmd" cib-last-written="Thu Aug 23 16:49:17 2012" have-quorum="0" dc-uuid="2">
|
|
+<cib epoch="557" num_updates="122" admin_epoch="0" validate-with="pacemaker-3.4" crm_feature_set="3.4.0" update-origin="rh7-3" update-client="crmd" cib-last-written="Thu Aug 23 16:49:17 2012" have-quorum="0" dc-uuid="2">
|
|
<configuration>
|
|
<crm_config/>
|
|
<nodes>
|
|
diff --git a/pcs_test/tier0/lib/cib/test_resource_operations.py b/pcs_test/tier0/lib/cib/test_resource_operations.py
|
|
index 5e556cf4..e5be7a54 100644
|
|
--- a/pcs_test/tier0/lib/cib/test_resource_operations.py
|
|
+++ b/pcs_test/tier0/lib/cib/test_resource_operations.py
|
|
@@ -316,13 +316,14 @@ class ValidateOperation(TestCase):
|
|
option_value="b",
|
|
option_name="on-fail",
|
|
allowed_values=[
|
|
- "ignore",
|
|
"block",
|
|
- "stop",
|
|
- "restart",
|
|
- "standby",
|
|
+ "demote",
|
|
"fence",
|
|
+ "ignore",
|
|
+ "restart",
|
|
"restart-container",
|
|
+ "standby",
|
|
+ "stop",
|
|
],
|
|
cannot_be_empty=False,
|
|
forbidden_characters=None,
|
|
diff --git a/pcs_test/tier0/lib/commands/remote_node/test_node_add_remote.py b/pcs_test/tier0/lib/commands/remote_node/test_node_add_remote.py
|
|
index 725ec68a..4da3fa0a 100644
|
|
--- a/pcs_test/tier0/lib/commands/remote_node/test_node_add_remote.py
|
|
+++ b/pcs_test/tier0/lib/commands/remote_node/test_node_add_remote.py
|
|
@@ -118,7 +118,7 @@ FIXTURE_RESOURCES_TEMPLATE = """
|
|
interval="0s" name="migrate_to" timeout="60"
|
|
/>
|
|
<op id="node-name-monitor-interval-60s"
|
|
- interval="60s" name="monitor" timeout="30"
|
|
+ interval="60s" name="monitor" timeout="30" {onfail}
|
|
/>
|
|
<op id="node-name-reload-interval-0s"
|
|
interval="0s" name="reload" timeout="60"
|
|
@@ -133,7 +133,9 @@ FIXTURE_RESOURCES_TEMPLATE = """
|
|
</primitive>
|
|
</resources>
|
|
"""
|
|
-FIXTURE_RESOURCES = FIXTURE_RESOURCES_TEMPLATE.format(server="remote-host")
|
|
+FIXTURE_RESOURCES = FIXTURE_RESOURCES_TEMPLATE.format(
|
|
+ server="remote-host", onfail=""
|
|
+)
|
|
|
|
|
|
class AddRemote(TestCase):
|
|
@@ -178,12 +180,48 @@ class AddRemote(TestCase):
|
|
.local.push_existing_authkey_to_remote(NODE_NAME, NODE_DEST_LIST)
|
|
.local.run_pacemaker_remote(NODE_NAME, NODE_DEST_LIST)
|
|
.env.push_cib(
|
|
- resources=FIXTURE_RESOURCES_TEMPLATE.format(server=NODE_NAME)
|
|
+ resources=FIXTURE_RESOURCES_TEMPLATE.format(
|
|
+ server=NODE_NAME, onfail=""
|
|
+ )
|
|
)
|
|
)
|
|
node_add_remote(self.env_assist.get_env(), node_addr=NODE_NAME)
|
|
self.env_assist.assert_reports(REPORTS)
|
|
|
|
+ def test_cib_upgrade_on_onfail_demote(self):
|
|
+ self._config_success_base()
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.4.xml", instead="runner.cib.load",
|
|
+ )
|
|
+ self.config.runner.cib.upgrade(before="runner.cib.load")
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.3.xml",
|
|
+ name="load_cib_old_version",
|
|
+ before="runner.cib.upgrade",
|
|
+ )
|
|
+ self.config.env.push_cib(
|
|
+ resources=FIXTURE_RESOURCES_TEMPLATE.format(
|
|
+ server="remote-host", onfail='on-fail="demote"'
|
|
+ ),
|
|
+ instead="env.push_cib",
|
|
+ )
|
|
+ node_add_remote(
|
|
+ self.env_assist.get_env(),
|
|
+ operations=[
|
|
+ {
|
|
+ "name": "monitor",
|
|
+ "timeout": "30",
|
|
+ "interval": "60s",
|
|
+ "on-fail": "demote",
|
|
+ }
|
|
+ ],
|
|
+ )
|
|
+ self.env_assist.assert_reports(
|
|
+ REPORTS.info(
|
|
+ "cib_upgrade_successful", reports.codes.CIB_UPGRADE_SUCCESSFUL
|
|
+ )
|
|
+ )
|
|
+
|
|
def test_node_name_conflict_report_is_unique(self):
|
|
(
|
|
self.config.runner.cib.load(
|
|
@@ -623,7 +661,7 @@ class NotLive(TestCase):
|
|
.runner.pcmk.load_agent(agent_name="ocf:pacemaker:remote")
|
|
.env.push_cib(
|
|
resources=FIXTURE_RESOURCES_TEMPLATE.format(
|
|
- server=NODE_ADDR_PCSD
|
|
+ server=NODE_ADDR_PCSD, onfail=""
|
|
)
|
|
)
|
|
)
|
|
@@ -648,7 +686,9 @@ class NotLive(TestCase):
|
|
self.config.runner.cib.load()
|
|
.runner.pcmk.load_agent(agent_name="ocf:pacemaker:remote")
|
|
.env.push_cib(
|
|
- resources=FIXTURE_RESOURCES_TEMPLATE.format(server=NODE_NAME)
|
|
+ resources=FIXTURE_RESOURCES_TEMPLATE.format(
|
|
+ server=NODE_NAME, onfail=""
|
|
+ )
|
|
)
|
|
)
|
|
node_add_remote(self.env_assist.get_env(), no_node_addr=True)
|
|
@@ -672,7 +712,9 @@ class NotLive(TestCase):
|
|
self.config.runner.cib.load()
|
|
.runner.pcmk.load_agent(agent_name="ocf:pacemaker:remote")
|
|
.env.push_cib(
|
|
- resources=FIXTURE_RESOURCES_TEMPLATE.format(server="addr")
|
|
+ resources=FIXTURE_RESOURCES_TEMPLATE.format(
|
|
+ server="addr", onfail=""
|
|
+ )
|
|
)
|
|
)
|
|
node_add_remote(self.env_assist.get_env(), node_addr="addr")
|
|
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 dc70ce22..a040a9d9 100644
|
|
--- a/pcs_test/tier0/lib/commands/resource/test_resource_create.py
|
|
+++ b/pcs_test/tier0/lib/commands/resource/test_resource_create.py
|
|
@@ -35,13 +35,19 @@ def create(
|
|
)
|
|
|
|
|
|
-def create_group(env, wait=TIMEOUT, disabled=False, meta_attributes=None):
|
|
+def create_group(
|
|
+ env,
|
|
+ wait=TIMEOUT,
|
|
+ disabled=False,
|
|
+ meta_attributes=None,
|
|
+ operation_list=None,
|
|
+):
|
|
return resource.create_in_group(
|
|
env,
|
|
"A",
|
|
"ocf:heartbeat:Dummy",
|
|
"G",
|
|
- operation_list=[],
|
|
+ operation_list=operation_list if operation_list else [],
|
|
meta_attributes=meta_attributes if meta_attributes else {},
|
|
instance_attributes={},
|
|
wait=wait,
|
|
@@ -50,13 +56,18 @@ def create_group(env, wait=TIMEOUT, disabled=False, meta_attributes=None):
|
|
|
|
|
|
def create_clone(
|
|
- env, wait=TIMEOUT, disabled=False, meta_attributes=None, clone_options=None
|
|
+ env,
|
|
+ wait=TIMEOUT,
|
|
+ disabled=False,
|
|
+ meta_attributes=None,
|
|
+ clone_options=None,
|
|
+ operation_list=None,
|
|
):
|
|
return resource.create_as_clone(
|
|
env,
|
|
"A",
|
|
"ocf:heartbeat:Dummy",
|
|
- operation_list=[],
|
|
+ operation_list=operation_list if operation_list else [],
|
|
meta_attributes=meta_attributes if meta_attributes else {},
|
|
instance_attributes={},
|
|
clone_meta_options=clone_options if clone_options else {},
|
|
@@ -71,12 +82,13 @@ def create_bundle(
|
|
disabled=False,
|
|
meta_attributes=None,
|
|
allow_not_accessible_resource=False,
|
|
+ operation_list=None,
|
|
):
|
|
return resource.create_into_bundle(
|
|
env,
|
|
"A",
|
|
"ocf:heartbeat:Dummy",
|
|
- operation_list=[],
|
|
+ operation_list=operation_list if operation_list else [],
|
|
meta_attributes=meta_attributes if meta_attributes else {},
|
|
instance_attributes={},
|
|
bundle_id="B",
|
|
@@ -576,6 +588,60 @@ class Create(TestCase):
|
|
]
|
|
)
|
|
|
|
+ def test_cib_upgrade_on_onfail_demote(self):
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.3.xml",
|
|
+ instead="runner.cib.load",
|
|
+ name="load_cib_old_version",
|
|
+ )
|
|
+ self.config.runner.cib.upgrade()
|
|
+ self.config.runner.cib.load(filename="cib-empty-3.4.xml")
|
|
+ self.config.env.push_cib(
|
|
+ resources="""
|
|
+ <resources>
|
|
+ <primitive class="ocf" id="A" provider="heartbeat"
|
|
+ type="Dummy"
|
|
+ >
|
|
+ <operations>
|
|
+ <op id="A-migrate_from-interval-0s" interval="0s"
|
|
+ name="migrate_from" timeout="20"
|
|
+ />
|
|
+ <op id="A-migrate_to-interval-0s" interval="0s"
|
|
+ name="migrate_to" timeout="20"
|
|
+ />
|
|
+ <op id="A-monitor-interval-10" interval="10"
|
|
+ name="monitor" timeout="10" on-fail="demote"
|
|
+ />
|
|
+ <op id="A-reload-interval-0s" interval="0s"
|
|
+ name="reload" timeout="20"
|
|
+ />
|
|
+ <op id="A-start-interval-0s" interval="0s"
|
|
+ name="start" timeout="20"
|
|
+ />
|
|
+ <op id="A-stop-interval-0s" interval="0s"
|
|
+ name="stop" timeout="20"
|
|
+ />
|
|
+ </operations>
|
|
+ </primitive>
|
|
+ </resources>
|
|
+ """
|
|
+ )
|
|
+
|
|
+ create(
|
|
+ self.env_assist.get_env(),
|
|
+ operation_list=[
|
|
+ {
|
|
+ "name": "monitor",
|
|
+ "timeout": "10",
|
|
+ "interval": "10",
|
|
+ "on-fail": "demote",
|
|
+ }
|
|
+ ],
|
|
+ )
|
|
+ self.env_assist.assert_reports(
|
|
+ [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)]
|
|
+ )
|
|
+
|
|
|
|
class CreateWait(TestCase):
|
|
def setUp(self):
|
|
@@ -746,6 +812,66 @@ class CreateInGroup(TestCase):
|
|
|
|
create_group(self.env_assist.get_env(), wait=False)
|
|
|
|
+ def test_cib_upgrade_on_onfail_demote(self):
|
|
+ self.config.remove(name="runner.pcmk.can_wait")
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.3.xml",
|
|
+ instead="runner.cib.load",
|
|
+ name="load_cib_old_version",
|
|
+ )
|
|
+ self.config.runner.cib.upgrade()
|
|
+ self.config.runner.cib.load(filename="cib-empty-3.4.xml")
|
|
+ self.config.env.push_cib(
|
|
+ resources="""
|
|
+ <resources>
|
|
+ <group id="G">
|
|
+ <primitive class="ocf" id="A" provider="heartbeat"
|
|
+ type="Dummy"
|
|
+ >
|
|
+ <operations>
|
|
+ <op id="A-migrate_from-interval-0s"
|
|
+ interval="0s" name="migrate_from"
|
|
+ timeout="20"
|
|
+ />
|
|
+ <op id="A-migrate_to-interval-0s"
|
|
+ interval="0s" name="migrate_to"
|
|
+ timeout="20"
|
|
+ />
|
|
+ <op id="A-monitor-interval-10" interval="10"
|
|
+ name="monitor" timeout="10" on-fail="demote"
|
|
+ />
|
|
+ <op id="A-reload-interval-0s" interval="0s"
|
|
+ name="reload" timeout="20"
|
|
+ />
|
|
+ <op id="A-start-interval-0s" interval="0s"
|
|
+ name="start" timeout="20"
|
|
+ />
|
|
+ <op id="A-stop-interval-0s" interval="0s"
|
|
+ name="stop" timeout="20"
|
|
+ />
|
|
+ </operations>
|
|
+ </primitive>
|
|
+ </group>
|
|
+ </resources>
|
|
+ """
|
|
+ )
|
|
+
|
|
+ create_group(
|
|
+ self.env_assist.get_env(),
|
|
+ operation_list=[
|
|
+ {
|
|
+ "name": "monitor",
|
|
+ "timeout": "10",
|
|
+ "interval": "10",
|
|
+ "on-fail": "demote",
|
|
+ }
|
|
+ ],
|
|
+ wait=False,
|
|
+ )
|
|
+ self.env_assist.assert_reports(
|
|
+ [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)]
|
|
+ )
|
|
+
|
|
def test_fail_wait(self):
|
|
self.config.env.push_cib(
|
|
resources=fixture_cib_resources_xml_group_simplest,
|
|
@@ -859,6 +985,62 @@ class CreateAsClone(TestCase):
|
|
)
|
|
create_clone(self.env_assist.get_env(), wait=False)
|
|
|
|
+ def test_cib_upgrade_on_onfail_demote(self):
|
|
+ self.config.remove(name="runner.pcmk.can_wait")
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.3.xml",
|
|
+ instead="runner.cib.load",
|
|
+ name="load_cib_old_version",
|
|
+ )
|
|
+ self.config.runner.cib.upgrade()
|
|
+ self.config.runner.cib.load(filename="cib-empty-3.4.xml")
|
|
+ self.config.env.push_cib(
|
|
+ resources="""<resources>
|
|
+ <clone id="A-clone">
|
|
+ <primitive class="ocf" id="A" provider="heartbeat"
|
|
+ type="Dummy"
|
|
+ >
|
|
+ <operations>
|
|
+ <op id="A-migrate_from-interval-0s" interval="0s"
|
|
+ name="migrate_from" timeout="20"
|
|
+ />
|
|
+ <op id="A-migrate_to-interval-0s" interval="0s"
|
|
+ name="migrate_to" timeout="20"
|
|
+ />
|
|
+ <op id="A-monitor-interval-10" interval="10"
|
|
+ name="monitor" timeout="10" on-fail="demote"
|
|
+ />
|
|
+ <op id="A-reload-interval-0s" interval="0s"
|
|
+ name="reload" timeout="20"
|
|
+ />
|
|
+ <op id="A-start-interval-0s" interval="0s"
|
|
+ name="start" timeout="20"
|
|
+ />
|
|
+ <op id="A-stop-interval-0s" interval="0s"
|
|
+ name="stop" timeout="20"
|
|
+ />
|
|
+ </operations>
|
|
+ </primitive>
|
|
+ </clone>
|
|
+ </resources>"""
|
|
+ )
|
|
+
|
|
+ create_clone(
|
|
+ self.env_assist.get_env(),
|
|
+ operation_list=[
|
|
+ {
|
|
+ "name": "monitor",
|
|
+ "timeout": "10",
|
|
+ "interval": "10",
|
|
+ "on-fail": "demote",
|
|
+ }
|
|
+ ],
|
|
+ wait=False,
|
|
+ )
|
|
+ self.env_assist.assert_reports(
|
|
+ [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)]
|
|
+ )
|
|
+
|
|
def test_fail_wait(self):
|
|
self.config.env.push_cib(
|
|
resources=fixture_cib_resources_xml_clone_simplest,
|
|
@@ -1168,7 +1350,7 @@ class CreateInToBundle(TestCase):
|
|
name="migrate_to" timeout="20"
|
|
/>
|
|
<op id="A-monitor-interval-10" interval="10"
|
|
- name="monitor" timeout="20"
|
|
+ name="monitor" timeout="20" {onfail}
|
|
/>
|
|
<op id="A-reload-interval-0s" interval="0s" name="reload"
|
|
timeout="20"
|
|
@@ -1190,7 +1372,8 @@ class CreateInToBundle(TestCase):
|
|
fixture_resource_post_simple_without_network.format(
|
|
network="""
|
|
<network control-port="12345" ip-range-start="192.168.100.200"/>
|
|
- """
|
|
+ """,
|
|
+ onfail=""
|
|
)
|
|
)
|
|
# fmt: on
|
|
@@ -1290,6 +1473,42 @@ class CreateInToBundle(TestCase):
|
|
[fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)]
|
|
)
|
|
|
|
+ def test_cib_upgrade_on_onfail_demote(self):
|
|
+ self.config.runner.pcmk.load_agent()
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.3.xml", name="load_cib_old_version",
|
|
+ )
|
|
+ self.config.runner.cib.upgrade()
|
|
+ self.config.runner.cib.load(
|
|
+ filename="cib-empty-3.4.xml", resources=self.fixture_resources_pre
|
|
+ )
|
|
+ self.config.env.push_cib(
|
|
+ resources=self.fixture_resource_post_simple_without_network.format(
|
|
+ network="""
|
|
+ <network
|
|
+ control-port="12345" ip-range-start="192.168.100.200"
|
|
+ />
|
|
+ """,
|
|
+ onfail='on-fail="demote"',
|
|
+ )
|
|
+ )
|
|
+
|
|
+ create_bundle(
|
|
+ self.env_assist.get_env(),
|
|
+ operation_list=[
|
|
+ {
|
|
+ "name": "monitor",
|
|
+ "timeout": "20",
|
|
+ "interval": "10",
|
|
+ "on-fail": "demote",
|
|
+ }
|
|
+ ],
|
|
+ wait=False,
|
|
+ )
|
|
+ self.env_assist.assert_reports(
|
|
+ [fixture.info(report_codes.CIB_UPGRADE_SUCCESSFUL)]
|
|
+ )
|
|
+
|
|
def test_simplest_resource(self):
|
|
(
|
|
self.config.runner.pcmk.load_agent()
|
|
@@ -1504,7 +1723,7 @@ class CreateInToBundle(TestCase):
|
|
.env.push_cib(
|
|
resources=(
|
|
self.fixture_resource_post_simple_without_network.format(
|
|
- network=""
|
|
+ network="", onfail=""
|
|
)
|
|
)
|
|
)
|
|
@@ -1540,7 +1759,7 @@ class CreateInToBundle(TestCase):
|
|
.env.push_cib(
|
|
resources=(
|
|
self.fixture_resource_post_simple_without_network.format(
|
|
- network=network
|
|
+ network=network, onfail=""
|
|
)
|
|
)
|
|
)
|
|
diff --git a/pcs_test/tier1/cib_resource/test_create.py b/pcs_test/tier1/cib_resource/test_create.py
|
|
index 977d627a..5ff83b71 100644
|
|
--- a/pcs_test/tier1/cib_resource/test_create.py
|
|
+++ b/pcs_test/tier1/cib_resource/test_create.py
|
|
@@ -1143,7 +1143,7 @@ class FailOrWarnOp(ResourceTest):
|
|
" monitor on-fail=Abc",
|
|
(
|
|
"Error: 'Abc' is not a valid on-fail value, use 'block', "
|
|
- "'fence', 'ignore', 'restart', 'restart-container', "
|
|
+ "'demote', 'fence', 'ignore', 'restart', 'restart-container', "
|
|
"'standby', 'stop'\n" + ERRORS_HAVE_OCURRED
|
|
),
|
|
)
|
|
diff --git a/pcs_test/tier1/legacy/test_resource.py b/pcs_test/tier1/legacy/test_resource.py
|
|
index 7ffcc83b..107ff406 100644
|
|
--- a/pcs_test/tier1/legacy/test_resource.py
|
|
+++ b/pcs_test/tier1/legacy/test_resource.py
|
|
@@ -22,6 +22,7 @@ from pcs_test.tools.misc import (
|
|
is_minimum_pacemaker_version,
|
|
outdent,
|
|
skip_unless_pacemaker_supports_bundle,
|
|
+ skip_unless_pacemaker_supports_op_onfail_demote,
|
|
skip_unless_crm_rule,
|
|
write_data_to_tmpfile,
|
|
write_file_to_tmpfile,
|
|
@@ -723,6 +724,28 @@ monitor interval=60s OCF_CHECK_LEVEL=1 (OPTest7-monitor-interval-60s)
|
|
),
|
|
)
|
|
|
|
+ @skip_unless_pacemaker_supports_op_onfail_demote()
|
|
+ def test_add_operation_onfail_demote_upgrade_cib(self):
|
|
+ write_file_to_tmpfile(rc("cib-empty-3.3.xml"), self.temp_cib)
|
|
+ self.assert_pcs_success(
|
|
+ "resource create --no-default-ops R ocf:pacemaker:Dummy"
|
|
+ )
|
|
+ self.assert_pcs_success(
|
|
+ "resource op add R start on-fail=demote",
|
|
+ stdout_full="Cluster CIB has been upgraded to latest version\n",
|
|
+ )
|
|
+
|
|
+ @skip_unless_pacemaker_supports_op_onfail_demote()
|
|
+ def test_update_add_operation_onfail_demote_upgrade_cib(self):
|
|
+ write_file_to_tmpfile(rc("cib-empty-3.3.xml"), self.temp_cib)
|
|
+ self.assert_pcs_success(
|
|
+ "resource create --no-default-ops R ocf:pacemaker:Dummy"
|
|
+ )
|
|
+ self.assert_pcs_success(
|
|
+ "resource update R op start on-fail=demote",
|
|
+ stdout_full="Cluster CIB has been upgraded to latest version\n",
|
|
+ )
|
|
+
|
|
def _test_delete_remove_operation(self, command):
|
|
assert command in {"delete", "remove"}
|
|
|
|
diff --git a/pcs_test/tools/misc.py b/pcs_test/tools/misc.py
|
|
index 33d78002..820f1e79 100644
|
|
--- a/pcs_test/tools/misc.py
|
|
+++ b/pcs_test/tools/misc.py
|
|
@@ -253,6 +253,12 @@ def skip_unless_pacemaker_supports_rsc_and_op_rules():
|
|
)
|
|
|
|
|
|
+def skip_unless_pacemaker_supports_op_onfail_demote():
|
|
+ return skip_unless_cib_schema_version(
|
|
+ (3, 4, 0), "resource operations with 'on-fail' option set to 'demote'"
|
|
+ )
|
|
+
|
|
+
|
|
def skip_if_service_enabled(service_name):
|
|
return skipUnless(
|
|
not is_service_enabled(runner, service_name),
|
|
diff --git a/pcsd/capabilities.xml b/pcsd/capabilities.xml
|
|
index 6e1886cb..09983354 100644
|
|
--- a/pcsd/capabilities.xml
|
|
+++ b/pcsd/capabilities.xml
|
|
@@ -465,6 +465,13 @@
|
|
pcs commands: cluster node ( add-remote | delete-remote | remove-remote )
|
|
</description>
|
|
</capability>
|
|
+ <capability id="node.remote.onfail-demote" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Support for "demote" value of resource operation's "on-fail" option
|
|
+
|
|
+ pcs commands: cluster node add-remote
|
|
+ </description>
|
|
+ </capability>
|
|
|
|
|
|
|
|
@@ -1056,6 +1063,13 @@
|
|
pcs commands: resource create ... op
|
|
</description>
|
|
</capability>
|
|
+ <capability id="pcmk.resource.create.operations.onfail-demote" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Support for "demote" value of resource operation's "on-fail" option
|
|
+
|
|
+ pcs commands: resource create ... op
|
|
+ </description>
|
|
+ </capability>
|
|
<capability id="pcmk.resource.create.wait" in-pcs="1" in-pcsd="0">
|
|
<description>
|
|
Wait for the created resource to start.
|
|
@@ -1105,6 +1119,13 @@
|
|
pcs commands: resource update ... op
|
|
</description>
|
|
</capability>
|
|
+ <capability id="pcmk.resource.update.operations.onfail-demote" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Support for "demote" value of resource operation's "on-fail" option
|
|
+
|
|
+ pcs commands: resource update ... op
|
|
+ </description>
|
|
+ </capability>
|
|
<capability id="pcmk.resource.update.wait" in-pcs="1" in-pcsd="0">
|
|
<description>
|
|
Wait for the changes to take effect.
|
|
@@ -1143,6 +1164,13 @@
|
|
pcs commands: resource op ( add | delete | remove )
|
|
</description>
|
|
</capability>
|
|
+ <capability id="pcmk.resource.update-operations.onfail-demote" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Support for "demote" value of resource operation's "on-fail" option
|
|
+
|
|
+ pcs commands: resource op add
|
|
+ </description>
|
|
+ </capability>
|
|
|
|
<capability id="pcmk.resource.group" in-pcs="1" in-pcsd="1">
|
|
<description>
|
|
@@ -1555,6 +1583,20 @@
|
|
pcs commands: stonith create ... op
|
|
</description>
|
|
</capability>
|
|
+ <capability id="pcmk.stonith.create.operations" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Set resource operations when creating a stonith resource.
|
|
+
|
|
+ pcs commands: stonith create ... op
|
|
+ </description>
|
|
+ </capability>
|
|
+ <capability id="pcmk.stonith.create.operations.onfail-demote" in-pcs="1" in-pcsd="0">
|
|
+ <description>
|
|
+ Support for "demote" value of resource operation's "on-fail" option
|
|
+
|
|
+ pcs commands: stonith create ... op
|
|
+ </description>
|
|
+ </capability>
|
|
<capability id="pcmk.stonith.create.wait" in-pcs="1" in-pcsd="0">
|
|
<description>
|
|
Wait for the created resource to start.
|
|
--
|
|
2.25.4
|
|
|