Compare commits
No commits in common. "rawhide" and "f36" have entirely different histories.
14 changed files with 1412 additions and 639 deletions
|
|
@ -1 +0,0 @@
|
|||
1
|
||||
17
.gitignore
vendored
17
.gitignore
vendored
|
|
@ -108,20 +108,3 @@
|
|||
/pcs-0.11.5.tar.gz
|
||||
/pcs-web-ui-0.1.16.1.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.16.1.tar.xz
|
||||
/pcs-0.11.6.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.17.tar.xz
|
||||
/pcs-web-ui-0.1.17.tar.gz
|
||||
/dacite-1.8.1.tar.gz
|
||||
/pcs-0.11.7.tar.gz
|
||||
/pcs-web-ui-0.1.18.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.18.tar.xz
|
||||
/pcs-0.11.8.tar.gz
|
||||
/pcs-web-ui-0.1.20.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.20.tar.xz
|
||||
/pcs-0.12.0.tar.gz
|
||||
/pcs-web-ui-0.1.22.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.22.tar.xz
|
||||
/dacite-1.9.2.tar.gz
|
||||
/pcs-0.12.1.tar.gz
|
||||
/pcs-web-ui-0.1.23.tar.gz
|
||||
/pcs-web-ui-node-modules-0.1.23.tar.xz
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
From 72588f150e89b6f06810321245a13157b7e00b09 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= <miro@hroncok.cz>
|
||||
Date: Tue, 29 Jul 2025 23:42:00 +0200
|
||||
Subject: [PATCH] Do not require wheel when setuptools is new enough
|
||||
|
||||
Current version of setuptools creates wheels on its own.
|
||||
---
|
||||
README.md | 2 +-
|
||||
configure.ac | 7 +++++--
|
||||
rpm/pcs.spec.in | 2 +-
|
||||
3 files changed, 7 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/README.md b/README.md
|
||||
index a06143eba..636485be6 100644
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -47,7 +47,7 @@ Apart from the dependencies listed above, these are also required for
|
||||
installation:
|
||||
|
||||
* python development files (packages python3-devel, python3-setuptools 66.1+,
|
||||
- python3-pip, python3-wheel)
|
||||
+ python3-pip, python3-wheel if python3-setuptools < 71)
|
||||
* ruby development files (package ruby-devel)
|
||||
* rubygems
|
||||
* rubygem bundler (package rubygem-bundler or ruby-bundler or bundler)
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 4e7d36599..0a782bfa7 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -347,12 +347,15 @@ AC_SUBST([PYAGENTX_VERSION])
|
||||
|
||||
# pip 19.0 required for PEP517 support
|
||||
PCS_CHECK_PYMOD([pip], [>= 23.0])
|
||||
-# pip builds a wheel first
|
||||
-PCS_CHECK_PYMOD([wheel])
|
||||
|
||||
if test "x$tests_only" != "xyes"; then
|
||||
# setuptools 61.0.0 required for PEP621 support
|
||||
PCS_CHECK_PYMOD([setuptools], [>= 66.1])
|
||||
+ # wheel is required if setuptools < 71
|
||||
+ AC_PIP_MODULE([setuptools], [>= 71], [], [], [need_wheel=yes])
|
||||
+ if test "x$need_wheel" = "xyes"; then
|
||||
+ PCS_CHECK_PYMOD([wheel])
|
||||
+ fi
|
||||
PCS_CHECK_PYMOD([cryptography])
|
||||
PCS_CHECK_PYMOD([lxml])
|
||||
PCS_CHECK_PYMOD([pyparsing], [>= 3.0.0])
|
||||
diff --git a/rpm/pcs.spec.in b/rpm/pcs.spec.in
|
||||
index 55881a398..639a3e974 100644
|
||||
--- a/rpm/pcs.spec.in
|
||||
+++ b/rpm/pcs.spec.in
|
||||
@@ -86,7 +86,7 @@ BuildRequires: python%{python3_version}-pip >= 23
|
||||
BuildRequires: python%{python3_version}-setuptools >= 66.1
|
||||
|
||||
# for building wheel during make install
|
||||
-BuildRequires: python%{python3_version}-wheel
|
||||
+BuildRequires: (python%{python3_version}-wheel if python%{python3_version}-setuptools < 71)
|
||||
|
||||
# for bundling dateutil
|
||||
%if "@cirpmworkarounds@" != "yes"
|
||||
--
|
||||
2.50.1
|
||||
|
||||
67
fix-broken-typeahead-component.patch
Normal file
67
fix-broken-typeahead-component.patch
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
From b53feb9febd8be85ab8eb90fda02478e4d7e9fea Mon Sep 17 00:00:00 2001
|
||||
From: Ivan Devat <idevat@redhat.com>
|
||||
Date: Tue, 13 Dec 2022 12:58:00 +0100
|
||||
Subject: [PATCH 1/2] fix agents filter in resource/fence device create
|
||||
|
||||
---
|
||||
.../cluster/fenceDevices/task/create/NameTypeTypeSelect.tsx | 4 ++--
|
||||
.../view/cluster/resources/task/create/NameTypeTypeSelect.tsx | 4 ++--
|
||||
src/app/view/share/form/Select.tsx | 2 +-
|
||||
3 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/app/view/cluster/fenceDevices/task/create/NameTypeTypeSelect.tsx b/src/app/view/cluster/fenceDevices/task/create/NameTypeTypeSelect.tsx
|
||||
index 80327801..8d623e2b 100644
|
||||
--- a/src/app/view/cluster/fenceDevices/task/create/NameTypeTypeSelect.tsx
|
||||
+++ b/src/app/view/cluster/fenceDevices/task/create/NameTypeTypeSelect.tsx
|
||||
@@ -38,13 +38,13 @@ export const NameTypeTypeSelect = ({
|
||||
return (
|
||||
<Select
|
||||
variant="typeahead"
|
||||
- typeAheadAriaLabel="Select a fence device"
|
||||
+ typeAheadAriaLabel="Select a fence device agent"
|
||||
+ placeholderText="Select a fence device agent"
|
||||
onSelect={onSelect}
|
||||
onClear={onClear}
|
||||
onFilter={onFilter}
|
||||
selections={agentName}
|
||||
isGrouped
|
||||
- hasInlineFilter
|
||||
customBadgeText={agentName.length > 0 ? agentName : undefined}
|
||||
optionsValues={filteredFenceAgentList}
|
||||
data-test="fence-device-agent"
|
||||
diff --git a/src/app/view/cluster/resources/task/create/NameTypeTypeSelect.tsx b/src/app/view/cluster/resources/task/create/NameTypeTypeSelect.tsx
|
||||
index bd7807d8..b531e825 100644
|
||||
--- a/src/app/view/cluster/resources/task/create/NameTypeTypeSelect.tsx
|
||||
+++ b/src/app/view/cluster/resources/task/create/NameTypeTypeSelect.tsx
|
||||
@@ -52,13 +52,13 @@ export const NameTypeTypeSelect = ({
|
||||
return (
|
||||
<Select
|
||||
variant="typeahead"
|
||||
- typeAheadAriaLabel="Select a state"
|
||||
+ typeAheadAriaLabel="Select a resource agent"
|
||||
+ placeholderText="Select a resource agent"
|
||||
onSelect={onSelect}
|
||||
onClear={onClear}
|
||||
onFilter={onFilter}
|
||||
selections={agentName}
|
||||
isGrouped
|
||||
- hasInlineFilter
|
||||
customBadgeText={agentName.length > 0 ? agentName : undefined}
|
||||
data-test="resource-agent"
|
||||
>
|
||||
diff --git a/src/app/view/share/form/Select.tsx b/src/app/view/share/form/Select.tsx
|
||||
index d73f126c..e2b81ce2 100644
|
||||
--- a/src/app/view/share/form/Select.tsx
|
||||
+++ b/src/app/view/share/form/Select.tsx
|
||||
@@ -31,7 +31,7 @@ export const Select = (
|
||||
const filter = onFilter
|
||||
? (_event: React.ChangeEvent<HTMLInputElement> | null, value: string) => {
|
||||
onFilter(value);
|
||||
- return null as unknown as React.ReactElement[];
|
||||
+ return undefined;
|
||||
}
|
||||
: null;
|
||||
|
||||
--
|
||||
2.39.2
|
||||
|
||||
89
fix-cluster-status-fence-levels.patch
Normal file
89
fix-cluster-status-fence-levels.patch
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
From 9e960df30366a93c3b383b34612451817cc617d8 Mon Sep 17 00:00:00 2001
|
||||
From: Ivan Devat <idevat@redhat.com>
|
||||
Date: Thu, 30 Mar 2023 17:03:06 +0200
|
||||
Subject: [PATCH 2/2] fix cluster-status/fence_levels shape expectation
|
||||
|
||||
---
|
||||
jest.config.js | 1 +
|
||||
.../endpoints/clusterStatus/shape/cluster.ts | 10 +++--
|
||||
.../cluster/displayAdvancedStatus.test.ts | 37 +++++++++++++++++++
|
||||
3 files changed, 44 insertions(+), 4 deletions(-)
|
||||
create mode 100644 src/test/scenes/cluster/displayAdvancedStatus.test.ts
|
||||
|
||||
diff --git a/jest.config.js b/jest.config.js
|
||||
index 08660443..c5c39dc5 100644
|
||||
--- a/jest.config.js
|
||||
+++ b/jest.config.js
|
||||
@@ -1,4 +1,5 @@
|
||||
module.exports = {
|
||||
globalSetup: "./src/test/jest-preset.ts",
|
||||
moduleDirectories: ["node_modules", "src"],
|
||||
+ testTimeout: 10000,
|
||||
};
|
||||
diff --git a/src/app/backend/endpoints/clusterStatus/shape/cluster.ts b/src/app/backend/endpoints/clusterStatus/shape/cluster.ts
|
||||
index 97ec4f17..ea29470e 100644
|
||||
--- a/src/app/backend/endpoints/clusterStatus/shape/cluster.ts
|
||||
+++ b/src/app/backend/endpoints/clusterStatus/shape/cluster.ts
|
||||
@@ -13,10 +13,12 @@ The key of record is a target.
|
||||
*/
|
||||
const ApiFencingLevels = t.record(
|
||||
t.string,
|
||||
- t.type({
|
||||
- level: t.string,
|
||||
- devices: t.array(t.string),
|
||||
- }),
|
||||
+ t.array(
|
||||
+ t.type({
|
||||
+ level: t.string,
|
||||
+ devices: t.string,
|
||||
+ }),
|
||||
+ ),
|
||||
);
|
||||
|
||||
export const ApiClusterStatusFlag = t.keyof({
|
||||
diff --git a/src/test/scenes/cluster/displayAdvancedStatus.test.ts b/src/test/scenes/cluster/displayAdvancedStatus.test.ts
|
||||
new file mode 100644
|
||||
index 00000000..78eb7dbe
|
||||
--- /dev/null
|
||||
+++ b/src/test/scenes/cluster/displayAdvancedStatus.test.ts
|
||||
@@ -0,0 +1,37 @@
|
||||
+// Cluster status is pretty complex. Sometimes a discrepancy between frontend
|
||||
+// and backend appears. This modules collect tests for discovered cases.
|
||||
+
|
||||
+import * as t from "dev/responses/clusterStatus/tools";
|
||||
+
|
||||
+import {dt} from "test/tools/selectors";
|
||||
+import {location, shortcuts} from "test/tools";
|
||||
+
|
||||
+const clusterName = "test-cluster";
|
||||
+
|
||||
+// We want to see browser behavior with (for now) invalid status before fix. But
|
||||
+// the typecheck tell us that it is wrong and dev build fails. So, we decive it.
|
||||
+const deceiveTypeCheck = (maybeInvalidPart: ReturnType<typeof JSON.parse>) =>
|
||||
+ JSON.parse(JSON.stringify(maybeInvalidPart));
|
||||
+
|
||||
+describe("Cluster with advanced status", () => {
|
||||
+ it("accept fence levels", async () => {
|
||||
+ shortcuts.interceptWithCluster({
|
||||
+ clusterStatus: t.cluster(clusterName, "ok", {
|
||||
+ fence_levels: deceiveTypeCheck({
|
||||
+ "node-1": [
|
||||
+ {
|
||||
+ level: "1",
|
||||
+ devices: "fence-1",
|
||||
+ },
|
||||
+ {
|
||||
+ level: "2",
|
||||
+ devices: "fence-2",
|
||||
+ },
|
||||
+ ],
|
||||
+ }),
|
||||
+ }),
|
||||
+ });
|
||||
+ await page.goto(location.cluster({clusterName}));
|
||||
+ await page.waitForSelector(dt("cluster-overview"));
|
||||
+ });
|
||||
+});
|
||||
--
|
||||
2.39.2
|
||||
|
||||
84
fix-pcs-config-checkpoint-diff.patch
Normal file
84
fix-pcs-config-checkpoint-diff.patch
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
From 22b275bd8571b7b949b23c5c39d05fbc9e812e12 Mon Sep 17 00:00:00 2001
|
||||
From: Miroslav Lisik <mlisik@redhat.com>
|
||||
Date: Mon, 6 Mar 2023 15:42:35 +0100
|
||||
Subject: [PATCH 1/2] fix `pcs config checkpoint diff` command
|
||||
|
||||
---
|
||||
pcs/cli/common/lib_wrapper.py | 15 +--------------
|
||||
pcs/config.py | 3 +++
|
||||
2 files changed, 4 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/pcs/cli/common/lib_wrapper.py b/pcs/cli/common/lib_wrapper.py
|
||||
index dabc5fd2..1c9e2f4d 100644
|
||||
--- a/pcs/cli/common/lib_wrapper.py
|
||||
+++ b/pcs/cli/common/lib_wrapper.py
|
||||
@@ -1,9 +1,5 @@
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
-from typing import (
|
||||
- Any,
|
||||
- Dict,
|
||||
-)
|
||||
|
||||
from pcs import settings
|
||||
from pcs.cli.common import middleware
|
||||
@@ -36,9 +32,6 @@ from pcs.lib.commands.constraint import order as constraint_order
|
||||
from pcs.lib.commands.constraint import ticket as constraint_ticket
|
||||
from pcs.lib.env import LibraryEnvironment
|
||||
|
||||
-# Note: not properly typed
|
||||
-_CACHE: Dict[Any, Any] = {}
|
||||
-
|
||||
|
||||
def wrapper(dictionary):
|
||||
return namedtuple("wrapper", dictionary.keys())(**dictionary)
|
||||
@@ -106,12 +99,6 @@ def bind_all(env, run_with_middleware, dictionary):
|
||||
)
|
||||
|
||||
|
||||
-def get_module(env, middleware_factory, name):
|
||||
- if name not in _CACHE:
|
||||
- _CACHE[name] = load_module(env, middleware_factory, name)
|
||||
- return _CACHE[name]
|
||||
-
|
||||
-
|
||||
def load_module(env, middleware_factory, name):
|
||||
# pylint: disable=too-many-return-statements, too-many-branches
|
||||
if name == "acl":
|
||||
@@ -547,4 +534,4 @@ class Library:
|
||||
self.middleware_factory = middleware_factory
|
||||
|
||||
def __getattr__(self, name):
|
||||
- return get_module(self.env, self.middleware_factory, name)
|
||||
+ return load_module(self.env, self.middleware_factory, name)
|
||||
diff --git a/pcs/config.py b/pcs/config.py
|
||||
index e0d179f0..6da1151b 100644
|
||||
--- a/pcs/config.py
|
||||
+++ b/pcs/config.py
|
||||
@@ -691,6 +691,7 @@ def _checkpoint_to_lines(lib, checkpoint_number):
|
||||
orig_usefile = utils.usefile
|
||||
orig_filename = utils.filename
|
||||
orig_middleware = lib.middleware_factory
|
||||
+ orig_env = lib.env
|
||||
# configure old code to read the CIB from a file
|
||||
utils.usefile = True
|
||||
utils.filename = os.path.join(
|
||||
@@ -700,6 +701,7 @@ def _checkpoint_to_lines(lib, checkpoint_number):
|
||||
lib.middleware_factory = orig_middleware._replace(
|
||||
cib=middleware.cib(utils.filename, utils.touch_cib_file)
|
||||
)
|
||||
+ lib.env = utils.get_cli_env()
|
||||
# export the CIB to text
|
||||
result = False, []
|
||||
if os.path.isfile(utils.filename):
|
||||
@@ -708,6 +710,7 @@ def _checkpoint_to_lines(lib, checkpoint_number):
|
||||
utils.usefile = orig_usefile
|
||||
utils.filename = orig_filename
|
||||
lib.middleware_factory = orig_middleware
|
||||
+ lib.env = orig_env
|
||||
return result
|
||||
|
||||
|
||||
--
|
||||
2.39.2
|
||||
|
||||
975
fix-pcs-stonith-update-scsi-devices.patch
Normal file
975
fix-pcs-stonith-update-scsi-devices.patch
Normal file
|
|
@ -0,0 +1,975 @@
|
|||
From 16cfc184b4544156df36fa66f7cb5fbf015b18f1 Mon Sep 17 00:00:00 2001
|
||||
From: Miroslav Lisik <mlisik@redhat.com>
|
||||
Date: Mon, 20 Mar 2023 10:35:34 +0100
|
||||
Subject: [PATCH 2/2] fix `pcs stonith update-scsi-devices` command
|
||||
|
||||
---
|
||||
pcs/lib/cib/resource/stonith.py | 168 +++++-
|
||||
.../test_stonith_update_scsi_devices.py | 571 ++++++++++++++----
|
||||
2 files changed, 601 insertions(+), 138 deletions(-)
|
||||
|
||||
diff --git a/pcs/lib/cib/resource/stonith.py b/pcs/lib/cib/resource/stonith.py
|
||||
index b730fbbf..6eec6611 100644
|
||||
--- a/pcs/lib/cib/resource/stonith.py
|
||||
+++ b/pcs/lib/cib/resource/stonith.py
|
||||
@@ -173,12 +173,64 @@ def get_node_key_map_for_mpath(
|
||||
return node_key_map
|
||||
|
||||
|
||||
-DIGEST_ATTRS = ["op-digest", "op-secure-digest", "op-restart-digest"]
|
||||
-DIGEST_ATTR_TO_TYPE_MAP = {
|
||||
+DIGEST_ATTR_TO_DIGEST_TYPE_MAP = {
|
||||
"op-digest": "all",
|
||||
"op-secure-digest": "nonprivate",
|
||||
"op-restart-digest": "nonreloadable",
|
||||
}
|
||||
+TRANSIENT_DIGEST_ATTR_TO_DIGEST_TYPE_MAP = {
|
||||
+ "#digests-all": "all",
|
||||
+ "#digests-secure": "nonprivate",
|
||||
+}
|
||||
+DIGEST_ATTRS = frozenset(DIGEST_ATTR_TO_DIGEST_TYPE_MAP.keys())
|
||||
+TRANSIENT_DIGEST_ATTRS = frozenset(
|
||||
+ TRANSIENT_DIGEST_ATTR_TO_DIGEST_TYPE_MAP.keys()
|
||||
+)
|
||||
+
|
||||
+
|
||||
+def _get_digest(
|
||||
+ attr: str,
|
||||
+ attr_to_type_map: Dict[str, str],
|
||||
+ calculated_digests: Dict[str, Optional[str]],
|
||||
+) -> str:
|
||||
+ """
|
||||
+ Return digest of right type for the specified attribute. If missing, raise
|
||||
+ an error.
|
||||
+
|
||||
+ attr -- name of digest attribute
|
||||
+ atttr_to_type_map -- map for attribute name to digest type conversion
|
||||
+ calculated_digests -- digests calculated by pacemaker
|
||||
+ """
|
||||
+ if attr not in attr_to_type_map:
|
||||
+ raise AssertionError(
|
||||
+ f"Key '{attr}' is missing in the attribute name to digest type map"
|
||||
+ )
|
||||
+ digest = calculated_digests.get(attr_to_type_map[attr])
|
||||
+ if digest is None:
|
||||
+ # this should not happen and when it does it is pacemaker fault
|
||||
+ raise LibraryError(
|
||||
+ ReportItem.error(
|
||||
+ reports.messages.StonithRestartlessUpdateUnableToPerform(
|
||||
+ f"necessary digest for '{attr}' attribute is missing"
|
||||
+ )
|
||||
+ )
|
||||
+ )
|
||||
+ return digest
|
||||
+
|
||||
+
|
||||
+def _get_transient_instance_attributes(cib: _Element) -> List[_Element]:
|
||||
+ """
|
||||
+ Return list of instance_attributes elements which could contain digest
|
||||
+ attributes.
|
||||
+
|
||||
+ cib -- CIB root element
|
||||
+ """
|
||||
+ return cast(
|
||||
+ List[_Element],
|
||||
+ cib.xpath(
|
||||
+ "./status/node_state/transient_attributes/instance_attributes"
|
||||
+ ),
|
||||
+ )
|
||||
|
||||
|
||||
def _get_lrm_rsc_op_elements(
|
||||
@@ -282,21 +334,89 @@ def _update_digest_attrs_in_lrm_rsc_op(
|
||||
)
|
||||
)
|
||||
for attr in common_digests_attrs:
|
||||
- new_digest = calculated_digests[DIGEST_ATTR_TO_TYPE_MAP[attr]]
|
||||
- if new_digest is None:
|
||||
- # this should not happen and when it does it is pacemaker fault
|
||||
+ # update digest in cib
|
||||
+ lrm_rsc_op.attrib[attr] = _get_digest(
|
||||
+ attr, DIGEST_ATTR_TO_DIGEST_TYPE_MAP, calculated_digests
|
||||
+ )
|
||||
+
|
||||
+
|
||||
+def _get_transient_digest_value(
|
||||
+ old_value: str, stonith_id: str, stonith_type: str, digest: str
|
||||
+) -> str:
|
||||
+ """
|
||||
+ Return transient digest value with replaced digest.
|
||||
+
|
||||
+ Value has comma separated format:
|
||||
+ <stonith_id>:<stonith_type>:<digest>,...
|
||||
+
|
||||
+ and we need to replace only digest for our currently updated stonith device.
|
||||
+
|
||||
+ old_value -- value to be replaced
|
||||
+ stonith_id -- id of stonith resource
|
||||
+ stonith_type -- stonith resource type
|
||||
+ digest -- digest for new value
|
||||
+ """
|
||||
+ new_comma_values_list = []
|
||||
+ for comma_value in old_value.split(","):
|
||||
+ if comma_value:
|
||||
+ try:
|
||||
+ _id, _type, _ = comma_value.split(":")
|
||||
+ except ValueError as e:
|
||||
+ raise LibraryError(
|
||||
+ ReportItem.error(
|
||||
+ reports.messages.StonithRestartlessUpdateUnableToPerform(
|
||||
+ f"invalid digest attribute value: '{old_value}'"
|
||||
+ )
|
||||
+ )
|
||||
+ ) from e
|
||||
+ if _id == stonith_id and _type == stonith_type:
|
||||
+ comma_value = ":".join([stonith_id, stonith_type, digest])
|
||||
+ new_comma_values_list.append(comma_value)
|
||||
+ return ",".join(new_comma_values_list)
|
||||
+
|
||||
+
|
||||
+def _update_digest_attrs_in_transient_instance_attributes(
|
||||
+ nvset_el: _Element,
|
||||
+ stonith_id: str,
|
||||
+ stonith_type: str,
|
||||
+ calculated_digests: Dict[str, Optional[str]],
|
||||
+) -> None:
|
||||
+ """
|
||||
+ Update digests attributes in transient instance attributes element.
|
||||
+
|
||||
+ nvset_el -- instance_attributes element containing nvpairs with digests
|
||||
+ attributes
|
||||
+ stonith_id -- id of stonith resource being updated
|
||||
+ stonith_type -- type of stonith resource being updated
|
||||
+ calculated_digests -- digests calculated by pacemaker
|
||||
+ """
|
||||
+ for attr in TRANSIENT_DIGEST_ATTRS:
|
||||
+ nvpair_list = cast(
|
||||
+ List[_Element],
|
||||
+ nvset_el.xpath("./nvpair[@name=$name]", name=attr),
|
||||
+ )
|
||||
+ if not nvpair_list:
|
||||
+ continue
|
||||
+ if len(nvpair_list) > 1:
|
||||
raise LibraryError(
|
||||
ReportItem.error(
|
||||
reports.messages.StonithRestartlessUpdateUnableToPerform(
|
||||
- (
|
||||
- f"necessary digest for '{attr}' attribute is "
|
||||
- "missing"
|
||||
- )
|
||||
+ f"multiple digests attributes: '{attr}'"
|
||||
)
|
||||
)
|
||||
)
|
||||
- # update digest in cib
|
||||
- lrm_rsc_op.attrib[attr] = new_digest
|
||||
+ old_value = nvpair_list[0].attrib["value"]
|
||||
+ if old_value:
|
||||
+ nvpair_list[0].attrib["value"] = _get_transient_digest_value(
|
||||
+ str(old_value),
|
||||
+ stonith_id,
|
||||
+ stonith_type,
|
||||
+ _get_digest(
|
||||
+ attr,
|
||||
+ TRANSIENT_DIGEST_ATTR_TO_DIGEST_TYPE_MAP,
|
||||
+ calculated_digests,
|
||||
+ ),
|
||||
+ )
|
||||
|
||||
|
||||
def update_scsi_devices_without_restart(
|
||||
@@ -315,6 +435,8 @@ def update_scsi_devices_without_restart(
|
||||
id_provider -- elements' ids generator
|
||||
device_list -- list of updated scsi devices
|
||||
"""
|
||||
+ # pylint: disable=too-many-locals
|
||||
+ cib = get_root(resource_el)
|
||||
resource_id = resource_el.get("id", "")
|
||||
roles_with_nodes = get_resource_state(cluster_state, resource_id)
|
||||
if "Started" not in roles_with_nodes:
|
||||
@@ -345,17 +467,14 @@ def update_scsi_devices_without_restart(
|
||||
)
|
||||
|
||||
lrm_rsc_op_start_list = _get_lrm_rsc_op_elements(
|
||||
- get_root(resource_el), resource_id, node_name, "start"
|
||||
+ cib, resource_id, node_name, "start"
|
||||
+ )
|
||||
+ new_instance_attrs_digests = get_resource_digests(
|
||||
+ runner, resource_id, node_name, new_instance_attrs
|
||||
)
|
||||
if len(lrm_rsc_op_start_list) == 1:
|
||||
_update_digest_attrs_in_lrm_rsc_op(
|
||||
- lrm_rsc_op_start_list[0],
|
||||
- get_resource_digests(
|
||||
- runner,
|
||||
- resource_id,
|
||||
- node_name,
|
||||
- new_instance_attrs,
|
||||
- ),
|
||||
+ lrm_rsc_op_start_list[0], new_instance_attrs_digests
|
||||
)
|
||||
else:
|
||||
raise LibraryError(
|
||||
@@ -368,7 +487,7 @@ def update_scsi_devices_without_restart(
|
||||
|
||||
monitor_attrs_list = _get_monitor_attrs(resource_el)
|
||||
lrm_rsc_op_monitor_list = _get_lrm_rsc_op_elements(
|
||||
- get_root(resource_el), resource_id, node_name, "monitor"
|
||||
+ cib, resource_id, node_name, "monitor"
|
||||
)
|
||||
if len(lrm_rsc_op_monitor_list) != len(monitor_attrs_list):
|
||||
raise LibraryError(
|
||||
@@ -384,7 +503,7 @@ def update_scsi_devices_without_restart(
|
||||
|
||||
for monitor_attrs in monitor_attrs_list:
|
||||
lrm_rsc_op_list = _get_lrm_rsc_op_elements(
|
||||
- get_root(resource_el),
|
||||
+ cib,
|
||||
resource_id,
|
||||
node_name,
|
||||
"monitor",
|
||||
@@ -413,3 +532,10 @@ def update_scsi_devices_without_restart(
|
||||
)
|
||||
)
|
||||
)
|
||||
+ for nvset_el in _get_transient_instance_attributes(cib):
|
||||
+ _update_digest_attrs_in_transient_instance_attributes(
|
||||
+ nvset_el,
|
||||
+ resource_id,
|
||||
+ resource_el.get("type", ""),
|
||||
+ new_instance_attrs_digests,
|
||||
+ )
|
||||
diff --git a/pcs_test/tier0/lib/commands/test_stonith_update_scsi_devices.py b/pcs_test/tier0/lib/commands/test_stonith_update_scsi_devices.py
|
||||
index 69ea097c..72c7dbcf 100644
|
||||
--- a/pcs_test/tier0/lib/commands/test_stonith_update_scsi_devices.py
|
||||
+++ b/pcs_test/tier0/lib/commands/test_stonith_update_scsi_devices.py
|
||||
@@ -38,6 +38,7 @@ DEFAULT_DIGEST = _DIGEST + "0"
|
||||
ALL_DIGEST = _DIGEST + "1"
|
||||
NONPRIVATE_DIGEST = _DIGEST + "2"
|
||||
NONRELOADABLE_DIGEST = _DIGEST + "3"
|
||||
+DIGEST_ATTR_VALUE_GOOD_FORMAT = f"stonith_id:stonith_type:{DEFAULT_DIGEST},"
|
||||
DEV_1 = "/dev/sda"
|
||||
DEV_2 = "/dev/sdb"
|
||||
DEV_3 = "/dev/sdc"
|
||||
@@ -151,33 +152,58 @@ def _fixture_lrm_rsc_start_ops(resource_id, lrm_start_ops):
|
||||
return _fixture_lrm_rsc_ops("start", resource_id, lrm_start_ops)
|
||||
|
||||
|
||||
-def _fixture_status_lrm_ops_base(
|
||||
- resource_id,
|
||||
- resource_type,
|
||||
- lrm_ops,
|
||||
-):
|
||||
+def _fixture_status_lrm_ops(resource_id, resource_type, lrm_ops):
|
||||
return f"""
|
||||
- <status>
|
||||
- <node_state id="1" uname="node1">
|
||||
- <lrm id="1">
|
||||
- <lrm_resources>
|
||||
- <lrm_resource id="{resource_id}" type="{resource_type}" class="stonith">
|
||||
- {lrm_ops}
|
||||
- </lrm_resource>
|
||||
- </lrm_resources>
|
||||
- </lrm>
|
||||
- </node_state>
|
||||
- </status>
|
||||
+ <lrm id="1">
|
||||
+ <lrm_resources>
|
||||
+ <lrm_resource id="{resource_id}" type="{resource_type}" class="stonith">
|
||||
+ {lrm_ops}
|
||||
+ </lrm_resource>
|
||||
+ </lrm_resources>
|
||||
+ </lrm>
|
||||
+ """
|
||||
+
|
||||
+
|
||||
+def _fixture_digest_nvpair(node_id, digest_name, digest_value):
|
||||
+ return (
|
||||
+ f'<nvpair id="status-{node_id}-.{digest_name}" name="#{digest_name}" '
|
||||
+ f'value="{digest_value}"/>'
|
||||
+ )
|
||||
+
|
||||
+
|
||||
+def _fixture_transient_attributes(node_id, digests_nvpairs):
|
||||
+ return f"""
|
||||
+ <transient_attributes id="{node_id}">
|
||||
+ <instance_attributes id="status-{node_id}">
|
||||
+ <nvpair id="status-{node_id}-.feature-set" name="#feature-set" value="3.16.2"/>
|
||||
+ <nvpair id="status-{node_id}-.node-unfenced" name="#node-unfenced" value="1679319764"/>
|
||||
+ {digests_nvpairs}
|
||||
+ </instance_attributes>
|
||||
+ </transient_attributes>
|
||||
+ """
|
||||
+
|
||||
+
|
||||
+def _fixture_node_state(node_id, lrm_ops=None, transient_attrs=None):
|
||||
+ if transient_attrs is None:
|
||||
+ transient_attrs = ""
|
||||
+ if lrm_ops is None:
|
||||
+ lrm_ops = ""
|
||||
+ return f"""
|
||||
+ <node_state id="{node_id}" uname="node{node_id}">
|
||||
+ {lrm_ops}
|
||||
+ {transient_attrs}
|
||||
+ </node_state>
|
||||
"""
|
||||
|
||||
|
||||
-def _fixture_status_lrm_ops(
|
||||
+def _fixture_status(
|
||||
resource_id,
|
||||
resource_type,
|
||||
lrm_start_ops=DEFAULT_LRM_START_OPS,
|
||||
lrm_monitor_ops=DEFAULT_LRM_MONITOR_OPS,
|
||||
+ digests_attrs_list=None,
|
||||
):
|
||||
- return _fixture_status_lrm_ops_base(
|
||||
+ lrm_ops = _fixture_status_lrm_ops(
|
||||
resource_id,
|
||||
resource_type,
|
||||
"\n".join(
|
||||
@@ -185,18 +211,52 @@ def _fixture_status_lrm_ops(
|
||||
+ _fixture_lrm_rsc_monitor_ops(resource_id, lrm_monitor_ops)
|
||||
),
|
||||
)
|
||||
+ node_states_list = []
|
||||
+ if not digests_attrs_list:
|
||||
+ node_states_list.append(
|
||||
+ _fixture_node_state("1", lrm_ops, transient_attrs=None)
|
||||
+ )
|
||||
+ else:
|
||||
+ for node_id, digests_attrs in enumerate(digests_attrs_list, start=1):
|
||||
+ transient_attrs = _fixture_transient_attributes(
|
||||
+ node_id,
|
||||
+ "\n".join(
|
||||
+ _fixture_digest_nvpair(node_id, name, value)
|
||||
+ for name, value in digests_attrs
|
||||
+ ),
|
||||
+ )
|
||||
+ node_state = _fixture_node_state(
|
||||
+ node_id,
|
||||
+ lrm_ops=lrm_ops if node_id == 1 else None,
|
||||
+ transient_attrs=transient_attrs,
|
||||
+ )
|
||||
+ node_states_list.append(node_state)
|
||||
+ node_states = "\n".join(node_states_list)
|
||||
+ return f"""
|
||||
+ <status>
|
||||
+ {node_states}
|
||||
+ </status>
|
||||
+ """
|
||||
+
|
||||
|
||||
+def fixture_digests_xml(resource_id, node_name, devices="", nonprivate=True):
|
||||
+ nonprivate_xml = (
|
||||
+ f"""
|
||||
+ <digest type="nonprivate" hash="{NONPRIVATE_DIGEST}">
|
||||
+ <parameters devices="{devices}"/>
|
||||
+ </digest>
|
||||
+ """
|
||||
+ if nonprivate
|
||||
+ else ""
|
||||
+ )
|
||||
|
||||
-def fixture_digests_xml(resource_id, node_name, devices=""):
|
||||
return f"""
|
||||
<pacemaker-result api-version="2.9" request="crm_resource --digests --resource {resource_id} --node {node_name} --output-as xml devices={devices}">
|
||||
<digests resource="{resource_id}" node="{node_name}" task="stop" interval="0ms">
|
||||
<digest type="all" hash="{ALL_DIGEST}">
|
||||
<parameters devices="{devices}" pcmk_host_check="static-list" pcmk_host_list="node1 node2 node3" pcmk_reboot_action="off"/>
|
||||
</digest>
|
||||
- <digest type="nonprivate" hash="{NONPRIVATE_DIGEST}">
|
||||
- <parameters devices="{devices}"/>
|
||||
- </digest>
|
||||
+ {nonprivate_xml}
|
||||
</digests>
|
||||
<status code="0" message="OK"/>
|
||||
</pacemaker-result>
|
||||
@@ -334,6 +394,8 @@ class UpdateScsiDevicesMixin:
|
||||
nodes_running_on=1,
|
||||
start_digests=True,
|
||||
monitor_digests=True,
|
||||
+ digests_attrs_list=None,
|
||||
+ crm_digests_xml=None,
|
||||
):
|
||||
# pylint: disable=too-many-arguments
|
||||
# pylint: disable=too-many-locals
|
||||
@@ -346,11 +408,12 @@ class UpdateScsiDevicesMixin:
|
||||
resource_ops=resource_ops,
|
||||
host_map=host_map,
|
||||
),
|
||||
- status=_fixture_status_lrm_ops(
|
||||
+ status=_fixture_status(
|
||||
self.stonith_id,
|
||||
self.stonith_type,
|
||||
lrm_start_ops=lrm_start_ops,
|
||||
lrm_monitor_ops=lrm_monitor_ops,
|
||||
+ digests_attrs_list=digests_attrs_list,
|
||||
),
|
||||
)
|
||||
self.config.runner.pcmk.is_resource_digests_supported()
|
||||
@@ -363,14 +426,17 @@ class UpdateScsiDevicesMixin:
|
||||
nodes=FIXTURE_CRM_MON_NODES,
|
||||
)
|
||||
devices_opt = "devices={}".format(devices_value)
|
||||
+
|
||||
+ if crm_digests_xml is None:
|
||||
+ crm_digests_xml = fixture_digests_xml(
|
||||
+ self.stonith_id, SCSI_NODE, devices=devices_value
|
||||
+ )
|
||||
if start_digests:
|
||||
self.config.runner.pcmk.resource_digests(
|
||||
self.stonith_id,
|
||||
SCSI_NODE,
|
||||
name="start.op.digests",
|
||||
- stdout=fixture_digests_xml(
|
||||
- self.stonith_id, SCSI_NODE, devices=devices_value
|
||||
- ),
|
||||
+ stdout=crm_digests_xml,
|
||||
args=[devices_opt],
|
||||
)
|
||||
if monitor_digests:
|
||||
@@ -394,11 +460,7 @@ class UpdateScsiDevicesMixin:
|
||||
self.stonith_id,
|
||||
SCSI_NODE,
|
||||
name=f"{name}-{num}.op.digests",
|
||||
- stdout=fixture_digests_xml(
|
||||
- self.stonith_id,
|
||||
- SCSI_NODE,
|
||||
- devices=devices_value,
|
||||
- ),
|
||||
+ stdout=crm_digests_xml,
|
||||
args=args,
|
||||
)
|
||||
|
||||
@@ -406,14 +468,16 @@ class UpdateScsiDevicesMixin:
|
||||
self,
|
||||
devices_before=DEVICES_1,
|
||||
devices_updated=DEVICES_2,
|
||||
- devices_add=(),
|
||||
- devices_remove=(),
|
||||
+ devices_add=None,
|
||||
+ devices_remove=None,
|
||||
unfence=None,
|
||||
resource_ops=DEFAULT_OPS,
|
||||
lrm_monitor_ops=DEFAULT_LRM_MONITOR_OPS,
|
||||
lrm_start_ops=DEFAULT_LRM_START_OPS,
|
||||
lrm_monitor_ops_updated=DEFAULT_LRM_MONITOR_OPS_UPDATED,
|
||||
lrm_start_ops_updated=DEFAULT_LRM_START_OPS_UPDATED,
|
||||
+ digests_attrs_list=None,
|
||||
+ digests_attrs_list_updated=None,
|
||||
):
|
||||
# pylint: disable=too-many-arguments
|
||||
self.config_cib(
|
||||
@@ -422,6 +486,7 @@ class UpdateScsiDevicesMixin:
|
||||
resource_ops=resource_ops,
|
||||
lrm_monitor_ops=lrm_monitor_ops,
|
||||
lrm_start_ops=lrm_start_ops,
|
||||
+ digests_attrs_list=digests_attrs_list,
|
||||
)
|
||||
if unfence:
|
||||
self.config.corosync_conf.load_content(
|
||||
@@ -445,20 +510,34 @@ class UpdateScsiDevicesMixin:
|
||||
devices=devices_updated,
|
||||
resource_ops=resource_ops,
|
||||
),
|
||||
- status=_fixture_status_lrm_ops(
|
||||
+ status=_fixture_status(
|
||||
self.stonith_id,
|
||||
self.stonith_type,
|
||||
lrm_start_ops=lrm_start_ops_updated,
|
||||
lrm_monitor_ops=lrm_monitor_ops_updated,
|
||||
+ digests_attrs_list=digests_attrs_list_updated,
|
||||
),
|
||||
)
|
||||
- self.command(
|
||||
- devices_updated=devices_updated,
|
||||
- devices_add=devices_add,
|
||||
- devices_remove=devices_remove,
|
||||
- )()
|
||||
+ kwargs = dict(devices_updated=devices_updated)
|
||||
+ if devices_add is not None:
|
||||
+ kwargs["devices_add"] = devices_add
|
||||
+ if devices_remove is not None:
|
||||
+ kwargs["devices_remove"] = devices_remove
|
||||
+ self.command(**kwargs)()
|
||||
self.env_assist.assert_reports([])
|
||||
|
||||
+ def digest_attr_value_single(self, digest, last_comma=True):
|
||||
+ comma = "," if last_comma else ""
|
||||
+ return f"{self.stonith_id}:{self.stonith_type}:{digest}{comma}"
|
||||
+
|
||||
+ def digest_attr_value_multiple(self, digest, last_comma=True):
|
||||
+ if self.stonith_type == STONITH_TYPE_SCSI:
|
||||
+ value = f"{STONITH_ID_MPATH}:{STONITH_TYPE_MPATH}:{DEFAULT_DIGEST},"
|
||||
+ else:
|
||||
+ value = f"{STONITH_ID_SCSI}:{STONITH_TYPE_SCSI}:{DEFAULT_DIGEST},"
|
||||
+
|
||||
+ return f"{value}{self.digest_attr_value_single(digest, last_comma=last_comma)}"
|
||||
+
|
||||
|
||||
class UpdateScsiDevicesFailuresMixin(UpdateScsiDevicesMixin):
|
||||
def test_pcmk_doesnt_support_digests(self):
|
||||
@@ -567,9 +646,7 @@ class UpdateScsiDevicesFailuresMixin(UpdateScsiDevicesMixin):
|
||||
)
|
||||
|
||||
def test_no_lrm_start_op(self):
|
||||
- self.config_cib(
|
||||
- lrm_start_ops=(), start_digests=False, monitor_digests=False
|
||||
- )
|
||||
+ self.config_cib(lrm_start_ops=(), monitor_digests=False)
|
||||
self.env_assist.assert_raise_library_error(
|
||||
self.command(),
|
||||
[
|
||||
@@ -622,6 +699,59 @@ class UpdateScsiDevicesFailuresMixin(UpdateScsiDevicesMixin):
|
||||
expected_in_processor=False,
|
||||
)
|
||||
|
||||
+ def test_crm_resource_digests_missing_for_transient_digests_attrs(self):
|
||||
+ self.config_cib(
|
||||
+ digests_attrs_list=[
|
||||
+ [
|
||||
+ (
|
||||
+ "digests-secure",
|
||||
+ self.digest_attr_value_single(ALL_DIGEST),
|
||||
+ ),
|
||||
+ ],
|
||||
+ ],
|
||||
+ crm_digests_xml=fixture_digests_xml(
|
||||
+ self.stonith_id, SCSI_NODE, devices="", nonprivate=False
|
||||
+ ),
|
||||
+ )
|
||||
+ self.env_assist.assert_raise_library_error(
|
||||
+ self.command(),
|
||||
+ [
|
||||
+ fixture.error(
|
||||
+ reports.codes.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM,
|
||||
+ reason=(
|
||||
+ "necessary digest for '#digests-secure' attribute is "
|
||||
+ "missing"
|
||||
+ ),
|
||||
+ reason_type=reports.const.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM_REASON_OTHER,
|
||||
+ )
|
||||
+ ],
|
||||
+ expected_in_processor=False,
|
||||
+ )
|
||||
+
|
||||
+ def test_multiple_digests_attributes(self):
|
||||
+ self.config_cib(
|
||||
+ digests_attrs_list=[
|
||||
+ 2
|
||||
+ * [
|
||||
+ (
|
||||
+ "digests-all",
|
||||
+ self.digest_attr_value_single(DEFAULT_DIGEST),
|
||||
+ ),
|
||||
+ ],
|
||||
+ ],
|
||||
+ )
|
||||
+ self.env_assist.assert_raise_library_error(
|
||||
+ self.command(),
|
||||
+ [
|
||||
+ fixture.error(
|
||||
+ reports.codes.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM,
|
||||
+ reason=("multiple digests attributes: '#digests-all'"),
|
||||
+ reason_type=reports.const.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM_REASON_OTHER,
|
||||
+ )
|
||||
+ ],
|
||||
+ expected_in_processor=False,
|
||||
+ )
|
||||
+
|
||||
def test_monitor_ops_and_lrm_monitor_ops_do_not_match(self):
|
||||
self.config_cib(
|
||||
resource_ops=(
|
||||
@@ -812,7 +942,7 @@ class UpdateScsiDevicesFailuresMixin(UpdateScsiDevicesMixin):
|
||||
stonith_type=self.stonith_type,
|
||||
devices=DEVICES_2,
|
||||
),
|
||||
- status=_fixture_status_lrm_ops(
|
||||
+ status=_fixture_status(
|
||||
self.stonith_id,
|
||||
self.stonith_type,
|
||||
lrm_start_ops=DEFAULT_LRM_START_OPS_UPDATED,
|
||||
@@ -959,6 +1089,28 @@ class UpdateScsiDevicesFailuresMixin(UpdateScsiDevicesMixin):
|
||||
]
|
||||
)
|
||||
|
||||
+ def test_transient_digests_attrs_bad_value_format(self):
|
||||
+ bad_format = f"{DIGEST_ATTR_VALUE_GOOD_FORMAT}id:type,"
|
||||
+ self.config_cib(
|
||||
+ digests_attrs_list=[
|
||||
+ [
|
||||
+ ("digests-all", DIGEST_ATTR_VALUE_GOOD_FORMAT),
|
||||
+ ("digests-secure", bad_format),
|
||||
+ ]
|
||||
+ ]
|
||||
+ )
|
||||
+ self.env_assist.assert_raise_library_error(
|
||||
+ self.command(),
|
||||
+ [
|
||||
+ fixture.error(
|
||||
+ reports.codes.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM,
|
||||
+ reason=f"invalid digest attribute value: '{bad_format}'",
|
||||
+ reason_type=reports.const.STONITH_RESTARTLESS_UPDATE_UNABLE_TO_PERFORM_REASON_OTHER,
|
||||
+ )
|
||||
+ ],
|
||||
+ expected_in_processor=False,
|
||||
+ )
|
||||
+
|
||||
|
||||
class UpdateScsiDevicesSetBase(UpdateScsiDevicesMixin, CommandSetMixin):
|
||||
def test_update_1_to_1_devices(self):
|
||||
@@ -1002,80 +1154,6 @@ class UpdateScsiDevicesSetBase(UpdateScsiDevicesMixin, CommandSetMixin):
|
||||
unfence=[DEV_3, DEV_4],
|
||||
)
|
||||
|
||||
- def test_default_monitor(self):
|
||||
- self.assert_command_success(unfence=[DEV_2])
|
||||
-
|
||||
- def test_no_monitor_ops(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(),
|
||||
- lrm_monitor_ops=(),
|
||||
- lrm_monitor_ops_updated=(),
|
||||
- )
|
||||
-
|
||||
- def test_1_monitor_with_timeout(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(("monitor", "30s", "10s", None),),
|
||||
- lrm_monitor_ops=(("30000", DEFAULT_DIGEST, None, None),),
|
||||
- lrm_monitor_ops_updated=(("30000", ALL_DIGEST, None, None),),
|
||||
- )
|
||||
-
|
||||
- def test_2_monitor_ops_with_timeouts(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(
|
||||
- ("monitor", "30s", "10s", None),
|
||||
- ("monitor", "40s", "20s", None),
|
||||
- ),
|
||||
- lrm_monitor_ops=(
|
||||
- ("30000", DEFAULT_DIGEST, None, None),
|
||||
- ("40000", DEFAULT_DIGEST, None, None),
|
||||
- ),
|
||||
- lrm_monitor_ops_updated=(
|
||||
- ("30000", ALL_DIGEST, None, None),
|
||||
- ("40000", ALL_DIGEST, None, None),
|
||||
- ),
|
||||
- )
|
||||
-
|
||||
- def test_2_monitor_ops_with_one_timeout(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(
|
||||
- ("monitor", "30s", "10s", None),
|
||||
- ("monitor", "60s", None, None),
|
||||
- ),
|
||||
- lrm_monitor_ops=(
|
||||
- ("30000", DEFAULT_DIGEST, None, None),
|
||||
- ("60000", DEFAULT_DIGEST, None, None),
|
||||
- ),
|
||||
- lrm_monitor_ops_updated=(
|
||||
- ("30000", ALL_DIGEST, None, None),
|
||||
- ("60000", ALL_DIGEST, None, None),
|
||||
- ),
|
||||
- )
|
||||
-
|
||||
- def test_various_start_ops_one_lrm_start_op(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(
|
||||
- ("monitor", "60s", None, None),
|
||||
- ("start", "0s", "40s", None),
|
||||
- ("start", "0s", "30s", "1"),
|
||||
- ("start", "10s", "5s", None),
|
||||
- ("start", "20s", None, None),
|
||||
- ),
|
||||
- )
|
||||
-
|
||||
- def test_1_nonrecurring_start_op_with_timeout(self):
|
||||
- self.assert_command_success(
|
||||
- unfence=[DEV_2],
|
||||
- resource_ops=(
|
||||
- ("monitor", "60s", None, None),
|
||||
- ("start", "0s", "40s", None),
|
||||
- ),
|
||||
- )
|
||||
-
|
||||
|
||||
class UpdateScsiDevicesAddRemoveBase(
|
||||
UpdateScsiDevicesMixin, CommandAddRemoveMixin
|
||||
@@ -1245,6 +1323,221 @@ class MpathFailuresMixin:
|
||||
self.assert_failure("node1:1;node2=", ["node2", "node3"])
|
||||
|
||||
|
||||
+class UpdateScsiDevicesDigestsBase(UpdateScsiDevicesMixin):
|
||||
+ def test_default_monitor(self):
|
||||
+ self.assert_command_success(unfence=[DEV_2])
|
||||
+
|
||||
+ def test_no_monitor_ops(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(),
|
||||
+ lrm_monitor_ops=(),
|
||||
+ lrm_monitor_ops_updated=(),
|
||||
+ )
|
||||
+
|
||||
+ def test_1_monitor_with_timeout(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(("monitor", "30s", "10s", None),),
|
||||
+ lrm_monitor_ops=(("30000", DEFAULT_DIGEST, None, None),),
|
||||
+ lrm_monitor_ops_updated=(("30000", ALL_DIGEST, None, None),),
|
||||
+ )
|
||||
+
|
||||
+ def test_2_monitor_ops_with_timeouts(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(
|
||||
+ ("monitor", "30s", "10s", None),
|
||||
+ ("monitor", "40s", "20s", None),
|
||||
+ ),
|
||||
+ lrm_monitor_ops=(
|
||||
+ ("30000", DEFAULT_DIGEST, None, None),
|
||||
+ ("40000", DEFAULT_DIGEST, None, None),
|
||||
+ ),
|
||||
+ lrm_monitor_ops_updated=(
|
||||
+ ("30000", ALL_DIGEST, None, None),
|
||||
+ ("40000", ALL_DIGEST, None, None),
|
||||
+ ),
|
||||
+ )
|
||||
+
|
||||
+ def test_2_monitor_ops_with_one_timeout(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(
|
||||
+ ("monitor", "30s", "10s", None),
|
||||
+ ("monitor", "60s", None, None),
|
||||
+ ),
|
||||
+ lrm_monitor_ops=(
|
||||
+ ("30000", DEFAULT_DIGEST, None, None),
|
||||
+ ("60000", DEFAULT_DIGEST, None, None),
|
||||
+ ),
|
||||
+ lrm_monitor_ops_updated=(
|
||||
+ ("30000", ALL_DIGEST, None, None),
|
||||
+ ("60000", ALL_DIGEST, None, None),
|
||||
+ ),
|
||||
+ )
|
||||
+
|
||||
+ def test_various_start_ops_one_lrm_start_op(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(
|
||||
+ ("monitor", "60s", None, None),
|
||||
+ ("start", "0s", "40s", None),
|
||||
+ ("start", "0s", "30s", "1"),
|
||||
+ ("start", "10s", "5s", None),
|
||||
+ ("start", "20s", None, None),
|
||||
+ ),
|
||||
+ )
|
||||
+
|
||||
+ def test_1_nonrecurring_start_op_with_timeout(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ resource_ops=(
|
||||
+ ("monitor", "60s", None, None),
|
||||
+ ("start", "0s", "40s", None),
|
||||
+ ),
|
||||
+ )
|
||||
+
|
||||
+ def _digests_attrs_before(self, last_comma=True):
|
||||
+ return [
|
||||
+ (
|
||||
+ "digests-all",
|
||||
+ self.digest_attr_value_single(DEFAULT_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ (
|
||||
+ "digests-secure",
|
||||
+ self.digest_attr_value_single(DEFAULT_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ ]
|
||||
+
|
||||
+ def _digests_attrs_after(self, last_comma=True):
|
||||
+ return [
|
||||
+ (
|
||||
+ "digests-all",
|
||||
+ self.digest_attr_value_single(ALL_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ (
|
||||
+ "digests-secure",
|
||||
+ self.digest_attr_value_single(NONPRIVATE_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ ]
|
||||
+
|
||||
+ def _digests_attrs_before_multi(self, last_comma=True):
|
||||
+ return [
|
||||
+ (
|
||||
+ "digests-all",
|
||||
+ self.digest_attr_value_multiple(DEFAULT_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ (
|
||||
+ "digests-secure",
|
||||
+ self.digest_attr_value_multiple(DEFAULT_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ ]
|
||||
+
|
||||
+ def _digests_attrs_after_multi(self, last_comma=True):
|
||||
+ return [
|
||||
+ (
|
||||
+ "digests-all",
|
||||
+ self.digest_attr_value_multiple(ALL_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ (
|
||||
+ "digests-secure",
|
||||
+ self.digest_attr_value_multiple(NONPRIVATE_DIGEST, last_comma),
|
||||
+ ),
|
||||
+ ]
|
||||
+
|
||||
+ def test_transient_digests_attrs_all_nodes(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_before()],
|
||||
+ digests_attrs_list_updated=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_after()],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_not_on_all_nodes(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=[self._digests_attrs_before()],
|
||||
+ digests_attrs_list_updated=[self._digests_attrs_after()],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_all_nodes_multi_value(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_before_multi()],
|
||||
+ digests_attrs_list_updated=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_after_multi()],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_not_on_all_nodes_multi_value(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=[self._digests_attrs_before()],
|
||||
+ digests_attrs_list_updated=[self._digests_attrs_after()],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_not_all_digest_types(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_before()[0:1]],
|
||||
+ digests_attrs_list_updated=len(self.existing_nodes)
|
||||
+ * [self._digests_attrs_after()[0:1]],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_without_digests_attrs(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=len(self.existing_nodes) * [[]],
|
||||
+ digests_attrs_list_updated=len(self.existing_nodes) * [[]],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_without_last_comma(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=[self._digests_attrs_before(last_comma=False)],
|
||||
+ digests_attrs_list_updated=[
|
||||
+ self._digests_attrs_after(last_comma=False)
|
||||
+ ],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_without_last_comma_multi_value(self):
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=[
|
||||
+ self._digests_attrs_before_multi(last_comma=False)
|
||||
+ ],
|
||||
+ digests_attrs_list_updated=[
|
||||
+ self._digests_attrs_after_multi(last_comma=False)
|
||||
+ ],
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_no_digest_for_our_stonith_id(self):
|
||||
+ digests_attrs_list = len(self.existing_nodes) * [
|
||||
+ [
|
||||
+ ("digests-all", DIGEST_ATTR_VALUE_GOOD_FORMAT),
|
||||
+ ("digests-secure", DIGEST_ATTR_VALUE_GOOD_FORMAT),
|
||||
+ ]
|
||||
+ ]
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=digests_attrs_list,
|
||||
+ digests_attrs_list_updated=digests_attrs_list,
|
||||
+ )
|
||||
+
|
||||
+ def test_transient_digests_attrs_digests_with_empty_value(self):
|
||||
+ digests_attrs_list = len(self.existing_nodes) * [
|
||||
+ [("digests-all", ""), ("digests-secure", "")]
|
||||
+ ]
|
||||
+ self.assert_command_success(
|
||||
+ unfence=[DEV_2],
|
||||
+ digests_attrs_list=digests_attrs_list,
|
||||
+ digests_attrs_list_updated=digests_attrs_list,
|
||||
+ )
|
||||
+
|
||||
+
|
||||
@mock.patch.object(
|
||||
settings,
|
||||
"pacemaker_api_result_schema",
|
||||
@@ -1337,3 +1630,47 @@ class TestUpdateScsiDevicesAddRemoveFailuresScsi(
|
||||
UpdateScsiDevicesAddRemoveFailuresBaseMixin, ScsiMixin, TestCase
|
||||
):
|
||||
pass
|
||||
+
|
||||
+
|
||||
+@mock.patch.object(
|
||||
+ settings,
|
||||
+ "pacemaker_api_result_schema",
|
||||
+ rc("pcmk_api_rng/api-result.rng"),
|
||||
+)
|
||||
+class TestUpdateScsiDevicesDigestsSetScsi(
|
||||
+ UpdateScsiDevicesDigestsBase, ScsiMixin, CommandSetMixin, TestCase
|
||||
+):
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+@mock.patch.object(
|
||||
+ settings,
|
||||
+ "pacemaker_api_result_schema",
|
||||
+ rc("pcmk_api_rng/api-result.rng"),
|
||||
+)
|
||||
+class TestUpdateScsiDevicesDigestsAddRemoveScsi(
|
||||
+ UpdateScsiDevicesDigestsBase, ScsiMixin, CommandAddRemoveMixin, TestCase
|
||||
+):
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+@mock.patch.object(
|
||||
+ settings,
|
||||
+ "pacemaker_api_result_schema",
|
||||
+ rc("pcmk_api_rng/api-result.rng"),
|
||||
+)
|
||||
+class TestUpdateScsiDevicesDigestsSetMpath(
|
||||
+ UpdateScsiDevicesDigestsBase, MpathMixin, CommandSetMixin, TestCase
|
||||
+):
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
+@mock.patch.object(
|
||||
+ settings,
|
||||
+ "pacemaker_api_result_schema",
|
||||
+ rc("pcmk_api_rng/api-result.rng"),
|
||||
+)
|
||||
+class TestUpdateScsiDevicesDigestsAddRemoveMpath(
|
||||
+ UpdateScsiDevicesDigestsBase, MpathMixin, CommandAddRemoveMixin, TestCase
|
||||
+):
|
||||
+ pass
|
||||
--
|
||||
2.39.2
|
||||
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From a2899ef0e20bb638f47e74077281e73f4f18faf3 Mon Sep 17 00:00:00 2001
|
||||
From: Miroslav Lisik <mlisik@redhat.com>
|
||||
Date: Thu, 10 Jul 2025 19:48:28 +0200
|
||||
Subject: [PATCH 2/2] fix ruby NameError exception in pcsd/pcsd.rb occuring
|
||||
with older rack
|
||||
|
||||
---
|
||||
pcsd/pcsd.rb | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/pcsd/pcsd.rb b/pcsd/pcsd.rb
|
||||
index e8ae9f106..c9f668851 100644
|
||||
--- a/pcsd/pcsd.rb
|
||||
+++ b/pcsd/pcsd.rb
|
||||
@@ -74,9 +74,11 @@ configure do
|
||||
CAPABILITIES_PCSD = capabilities_pcsd.freeze
|
||||
end
|
||||
|
||||
-error Rack::QueryParser::QueryLimitError do
|
||||
- $logger.warn(env['sinatra.error'].message)
|
||||
- return 400, env['sinatra.error'].message
|
||||
+if Rack.const_defined?(:QueryParser) and Rack::QueryParser.const_defined?(:QueryLimitError)
|
||||
+ error Rack::QueryParser::QueryLimitError do
|
||||
+ $logger.warn(env['sinatra.error'].message)
|
||||
+ return 400, env['sinatra.error'].message
|
||||
+ end
|
||||
end
|
||||
|
||||
get '/remote/?:command?' do
|
||||
--
|
||||
2.50.1
|
||||
|
||||
441
pcs.spec
441
pcs.spec
|
|
@ -1,6 +1,6 @@
|
|||
Name: pcs
|
||||
Version: 0.12.1
|
||||
Release: 5%{?dist}
|
||||
Version: 0.11.5
|
||||
Release: 2%{?dist}
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/
|
||||
# https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses
|
||||
# GPL-2.0-only: pcs
|
||||
|
|
@ -11,52 +11,28 @@ Group: System Environment/Base
|
|||
Summary: Pacemaker/Corosync Configuration System
|
||||
BuildArch: noarch
|
||||
|
||||
# Remove a tilde used by RPM to get the correct upstream version
|
||||
%global clean_version %(echo %{version} | sed 's/~//')
|
||||
|
||||
# To build an official pcs release, comment out branch_or_commit
|
||||
# Use long commit hash or branch name to build an unreleased version
|
||||
# %%global branch_or_commit 1353dfbb3af82d77f4de17a3fa4cbde185bb2b2d
|
||||
%global version_or_commit %{clean_version}
|
||||
%if 0%{?branch_or_commit:1}
|
||||
%global version_or_commit %{branch_or_commit}
|
||||
%global tarball_version %{clean_version}+%(echo %{branch_or_commit} | head -c 8)
|
||||
%endif
|
||||
# When specifying a commit, use its long hash
|
||||
%global version_or_commit %{version}
|
||||
# %%global version_or_commit 10069ca47e5c9f4ac1abd8bc4cd99281ead047b7
|
||||
%global pcs_source_name %{name}-%{version_or_commit}
|
||||
|
||||
# To build an official pcs-web-ui release, comment out ui_branch_or_commit
|
||||
# Last tagged version, also used as fallback version for untagged tarballs
|
||||
%global ui_version 0.1.23
|
||||
%global ui_modules_version 0.1.23
|
||||
# Use long commit hash or branch name to build an unreleased version
|
||||
# %%global ui_branch_or_commit 34372d1268f065ed186546f55216aaa2d7e76b54
|
||||
%global ui_version_or_commit %{ui_version}
|
||||
%if 0%{?ui_branch_or_commit:1}
|
||||
%global ui_version_or_commit %{ui_branch_or_commit}
|
||||
%global ui_tarball_version %{ui_version}-%(echo %{ui_branch_or_commit} | head -c 8)
|
||||
%endif
|
||||
%global ui_src_name pcs-web-ui-%{ui_version_or_commit}
|
||||
# ui_commit can be determined by hash, tag or branch
|
||||
%global ui_commit 0.1.16.1
|
||||
%global ui_modules_version 0.1.16.1
|
||||
%global ui_src_name pcs-web-ui-%{ui_commit}
|
||||
|
||||
%global pcs_snmp_pkg_name pcs-snmp
|
||||
|
||||
%global pyagentx_version 0.4.pcs.2
|
||||
%global dacite_version 1.9.2
|
||||
%global dacite_version 1.8.0
|
||||
|
||||
%global required_pacemaker_version 3.0.0
|
||||
%global required_pacemaker_version 2.1.0
|
||||
|
||||
%global pcs_bundled_dir pcs_bundled
|
||||
%global pcsd_webui_dir %{_prefix}/lib/pcsd/public/ui
|
||||
|
||||
%global cockpit_dir %{_datadir}/cockpit/
|
||||
%global metainfo_dir %{_datadir}/metainfo
|
||||
%global ui_metainfo_name org.clusterlabs.cockpit_pcs_web_ui.metainfo.xml
|
||||
%global ui_metainfo %{metainfo_dir}/%{ui_metainfo_name}
|
||||
|
||||
%global pkg_pcs_snmp pcs-snmp
|
||||
%global pkg_pcs_web_ui pcs-web-ui
|
||||
%global pkg_cockpit_ha_cluster cockpit-ha-cluster
|
||||
%global pcsd_public_dir pcsd/public
|
||||
|
||||
# prepend v for folder in GitHub link when using tagged tarball
|
||||
%if "%{clean_version}" == "%{version_or_commit}"
|
||||
%if "%{version}" == "%{version_or_commit}"
|
||||
%global v_prefix v
|
||||
%endif
|
||||
|
||||
|
|
@ -66,42 +42,25 @@ Source0: %{url}/archive/%{?v_prefix}%{version_or_commit}/%{pcs_source_name}.tar.
|
|||
Source41: https://github.com/ondrejmular/pyagentx/archive/v%{pyagentx_version}/pyagentx-%{pyagentx_version}.tar.gz
|
||||
Source42: https://github.com/konradhalas/dacite/archive/v%{dacite_version}/dacite-%{dacite_version}.tar.gz
|
||||
|
||||
Source100: https://github.com/ClusterLabs/pcs-web-ui/archive/%{ui_version_or_commit}/%{ui_src_name}.tar.gz
|
||||
Source101: https://github.com/ClusterLabs/pcs-web-ui/releases/download/%{ui_version_or_commit}/pcs-web-ui-node-modules-%{ui_modules_version}.tar.xz
|
||||
|
||||
Source100: https://github.com/ClusterLabs/pcs-web-ui/archive/%{ui_commit}/%{ui_src_name}.tar.gz
|
||||
Source101: https://github.com/ClusterLabs/pcs-web-ui/releases/download/%{ui_commit}/pcs-web-ui-node-modules-%{ui_modules_version}.tar.xz
|
||||
|
||||
# pcs patches: <= 200
|
||||
# Patch1: name.patch
|
||||
Patch1: show-info-page-instead-of-webui.patch
|
||||
Patch2: fix-pcsd-not-starting-with-older-rack.patch
|
||||
Patch3: do-not-require-wheel.patch
|
||||
# Patch0: name.patch
|
||||
Patch0: fix-pcs-config-checkpoint-diff.patch
|
||||
Patch1: fix-pcs-stonith-update-scsi-devices.patch
|
||||
|
||||
# ui patches: >200
|
||||
# Patch201: name-web-ui.patch
|
||||
|
||||
|
||||
# Split pcs to pcs and pcs-web-ui, all packages that replace pcs must obsolete
|
||||
# the old monolithic package
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/#_one_to_many_replacement
|
||||
Obsoletes: pcs < 0.12.0
|
||||
# Web UI is an add-on that doesn't need to be installed for pcs to function.
|
||||
# Upgrades from before 0.12 will install it thanks to Obsoletes. But it will
|
||||
# be possible to uninstall web UI to disable it and then it will not be
|
||||
# installed during upgrades because it is a weak dependency.
|
||||
Recommends: %{pkg_pcs_web_ui} == %{version}-%{release}
|
||||
|
||||
Patch201: fix-broken-typeahead-component.patch
|
||||
Patch202: fix-cluster-status-fence-levels.patch
|
||||
|
||||
# git for patches
|
||||
BuildRequires: git-core
|
||||
# for building pcs tarballs
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: make
|
||||
# printf from coreutils is used in makefile, head is used in spec
|
||||
BuildRequires: coreutils
|
||||
# find is used in Makefile and also somewhere else
|
||||
BuildRequires: findutils
|
||||
# python for pcs
|
||||
BuildRequires: python3 >= 3.9
|
||||
BuildRequires: python3-dateutil >= 2.7.0
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: python3-setuptools
|
||||
|
|
@ -112,8 +71,10 @@ BuildRequires: python3-tornado
|
|||
BuildRequires: python3-cryptography
|
||||
BuildRequires: python3-lxml
|
||||
# for building bundled python packages
|
||||
# setuptools 71+ builds wheels by itself
|
||||
BuildRequires: (python3-wheel if python3-setuptools < 71)
|
||||
BuildRequires: python3-wheel
|
||||
# for bundled python dateutil
|
||||
BuildRequires: python3-setuptools_scm
|
||||
BuildRequires: python3-distro
|
||||
# ruby and gems for pcsd
|
||||
BuildRequires: ruby >= 2.5.0
|
||||
BuildRequires: ruby-devel
|
||||
|
|
@ -124,52 +85,55 @@ BuildRequires: rubygem-ffi
|
|||
BuildRequires: rubygem-json
|
||||
BuildRequires: rubygem-mustermann
|
||||
BuildRequires: rubygem-puma
|
||||
BuildRequires: (rubygem(rack) < 3 or (rubygem(rack) >= 3 and rubygem(rackup)))
|
||||
BuildRequires: rubygem-rack
|
||||
BuildRequires: rubygem-rack-protection
|
||||
BuildRequires: rubygem-rack-test
|
||||
BuildRequires: rubygem-sinatra
|
||||
BuildRequires: rubygem-tilt
|
||||
%if 0%{?fedora} || 0%{?rhel} >= 9
|
||||
%if 0%{?fedora} || 0%{?eln} || 0%{?rhel} >= 9
|
||||
BuildRequires: rubygem(rexml)
|
||||
%endif
|
||||
# ruby libraries for tests
|
||||
BuildRequires: rubygem-test-unit
|
||||
# for touching patch files (sanitization function)
|
||||
BuildRequires: diffstat
|
||||
# for systemd scriptlet macros
|
||||
BuildRequires: systemd-rpm-macros
|
||||
# for post, preun and postun macros
|
||||
BuildRequires: systemd
|
||||
# pam is used for authentication inside daemon (python ctypes)
|
||||
# needed for tier0 tests during build
|
||||
BuildRequires: pam
|
||||
# for working with qdevice certificates (certutil) - used in configure.ac
|
||||
BuildRequires: nss-tools
|
||||
# pcs now provides a pc file
|
||||
BuildRequires: pkgconfig
|
||||
|
||||
# for creating the web ui favicon symlink to the Fedora logo
|
||||
BuildRequires: fedora-logos
|
||||
# for building web ui
|
||||
%if 0%{?fedora} < 37
|
||||
BuildRequires: npm
|
||||
%else
|
||||
BuildRequires: nodejs-npm
|
||||
%endif
|
||||
|
||||
# cluster stack packages for pkg-config
|
||||
# corosync has different package names on distributions but all provide
|
||||
# corosync-devel
|
||||
# corosync and pacemaker need versions and it's not working in virtual provides
|
||||
BuildRequires: corosync-devel >= 3.0
|
||||
BuildRequires: booth
|
||||
BuildRequires: corosync-qdevice-devel
|
||||
BuildRequires: corosynclib-devel >= 3.0
|
||||
BuildRequires: fence-agents-common
|
||||
BuildRequires: pacemaker-libs-devel >= %{required_pacemaker_version}
|
||||
BuildRequires: pkgconfig(booth)
|
||||
BuildRequires: pkgconfig(corosync-qdevice)
|
||||
BuildRequires: pkgconfig(sbd)
|
||||
|
||||
# for validating cockpit-ha-cluster metainfo
|
||||
BuildRequires: libappstream-glib
|
||||
|
||||
BuildRequires: resource-agents
|
||||
BuildRequires: sbd
|
||||
|
||||
# python and libraries for pcs, setuptools for pcs entrypoint
|
||||
Requires: python3 >= 3.9
|
||||
Requires: python3-cryptography
|
||||
Requires: python3-dateutil >= 2.7.0
|
||||
Requires: python3-lxml
|
||||
Requires: python3-setuptools
|
||||
Requires: python3-pycurl
|
||||
Requires: python3-pyparsing
|
||||
Requires: python3-tornado
|
||||
# ruby and gems for pcsd
|
||||
Requires: ruby >= 3.3.0
|
||||
Requires: ruby >= 2.5.0
|
||||
Requires: rubygem-backports
|
||||
Requires: rubygem-childprocess
|
||||
Requires: rubygem-ethon
|
||||
|
|
@ -177,11 +141,12 @@ Requires: rubygem-ffi
|
|||
Requires: rubygem-json
|
||||
Requires: rubygem-mustermann
|
||||
Requires: rubygem-puma
|
||||
Requires: (rubygem(rack) < 3 or (rubygem(rack) >= 3 and rubygem(rackup)))
|
||||
Requires: rubygem-rack
|
||||
Requires: rubygem-rack-protection
|
||||
Requires: rubygem-rack-test
|
||||
Requires: rubygem-sinatra
|
||||
Requires: rubygem-tilt
|
||||
%if 0%{?fedora} || 0%{?rhel} >= 9
|
||||
%if 0%{?fedora} || 0%{?eln} || 0%{?rhel} >= 9
|
||||
Requires: rubygem(rexml)
|
||||
%endif
|
||||
# for killall
|
||||
|
|
@ -193,6 +158,10 @@ Requires: (corosync >= 3.0 if pacemaker)
|
|||
# pcs enables corosync encryption by default so we require libknet1-plugins-all
|
||||
Requires: (libknet1-plugins-all if corosync)
|
||||
Requires: pacemaker-cli >= %{required_pacemaker_version}
|
||||
# for post, preun and postun macros
|
||||
Requires(post): systemd
|
||||
Requires(preun): systemd
|
||||
Requires(postun): systemd
|
||||
# pam is used for authentication inside daemon (python ctypes)
|
||||
# more details: https://bugzilla.redhat.com/show_bug.cgi?id=1717113
|
||||
Requires: pam
|
||||
|
|
@ -200,12 +169,18 @@ Requires: pam
|
|||
Requires: logrotate
|
||||
# for working with qdevice certificates (certutil)
|
||||
Requires: nss-tools
|
||||
# for web ui favicon - symlink to the Fedora logo
|
||||
Requires: fedora-logos
|
||||
|
||||
|
||||
Provides: bundled(dacite) = %{dacite_version}
|
||||
|
||||
# pcs-snmp subpackage definition
|
||||
%package -n %{pkg_pcs_snmp}
|
||||
%description
|
||||
pcs is a corosync and pacemaker configuration tool. It permits users to
|
||||
easily view, modify and create pacemaker based clusters.
|
||||
|
||||
# pcs-snmp package definition
|
||||
%package -n %{pcs_snmp_pkg_name}
|
||||
Group: System Environment/Base
|
||||
Summary: Pacemaker cluster SNMP agent
|
||||
# https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses
|
||||
|
|
@ -224,60 +199,11 @@ Requires: net-snmp
|
|||
|
||||
Provides: bundled(pyagentx) = %{pyagentx_version}
|
||||
|
||||
# pcs-web-ui subpackage definition
|
||||
%package -n %{pkg_pcs_web_ui}
|
||||
Summary: Standalone web UI for Pacemaker/Corosync Configuration System
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/
|
||||
# https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses
|
||||
# GPL-2.0-only: pcs
|
||||
License: GPL-2.0-only
|
||||
URL: https://github.com/ClusterLabs/pcs-web-ui
|
||||
|
||||
# Split pcs to pcs and pcs-web-ui, all packages that replace pcs must obsolete
|
||||
# the old monolithic package
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/#_one_to_many_replacement
|
||||
Obsoletes: pcs < 0.12.0
|
||||
|
||||
Requires: pcs = %{version}-%{release}
|
||||
|
||||
Provides: bundled(pcs-web-ui) = %{!?ui_tarball_version:%{ui_version}}%{?ui_tarball_version}
|
||||
|
||||
# cockpit-ha-cluster subpackage definition
|
||||
%package -n %{pkg_cockpit_ha_cluster}
|
||||
Group: System Environment/Base
|
||||
Summary: Cockpit application for managing Pacemaker based clusters
|
||||
License: GPL-2.0-only AND CC0-1.0
|
||||
URL: https://github.com/ClusterLabs/pcs-web-ui
|
||||
|
||||
BuildRequires: make
|
||||
BuildRequires: nodejs-npm
|
||||
|
||||
Requires: pcs = %{version}-%{release}
|
||||
Requires: cockpit-bridge
|
||||
|
||||
Provides: bundled(pcs-web-ui) = %{!?ui_tarball_version:%{ui_version}}%{?ui_tarball_version}
|
||||
|
||||
|
||||
|
||||
%description
|
||||
pcs is a configuration tool for Corosync and Pacemaker. It permits users to
|
||||
easily view, modify and create high availability clusters based on Pacemaker.
|
||||
This package contains the pcs command-line utility and its server pcsd.
|
||||
|
||||
%description -n %{pkg_pcs_web_ui}
|
||||
Provides standalone web UI for Pacemaker/Corosync Configuration System (pcs).
|
||||
|
||||
%description -n %{pkg_pcs_snmp}
|
||||
SNMP agent that provides information about Pacemaker cluster to the main agent
|
||||
(snmpd).
|
||||
|
||||
%description -n %{pkg_cockpit_ha_cluster}
|
||||
Cockpit application for managing Pacemaker based clusters. Uses
|
||||
Pacemaker/Corosync Configuration System (pcs) in the background.
|
||||
|
||||
|
||||
%description -n %{pcs_snmp_pkg_name}
|
||||
SNMP agent that provides information about pacemaker cluster to the master agent (snmpd)
|
||||
|
||||
%prep
|
||||
|
||||
# -- following is inspired by python-simplejon.el5 --
|
||||
# Update timestamps on the files touched by a patch, to avoid non-equal
|
||||
# .pyc/.pyo files across the multilib peers within a build
|
||||
|
|
@ -321,35 +247,23 @@ update_times_patch(){
|
|||
# * http://ftp.rpm.org/max-rpm/s1-rpm-inside-macros.html
|
||||
# * https://rpm-software-management.github.io/rpm/manual/autosetup.html
|
||||
# patch web-ui sources
|
||||
# -n <name> — Set Name of Build Directory
|
||||
# -T — Do Not Perform Default Archive Unpacking
|
||||
# -b <n> — Unpack The nth Sources Before Changing Directory
|
||||
# -a <n> — Unpack The nth Sources After Changing Directory
|
||||
# -N — disables automatic patch application, use autopatch to apply patches
|
||||
#
|
||||
# 1. unpack sources (-b 0)
|
||||
# 2. then cd into sources tree (the setup macro itself)
|
||||
# 3. then unpack node_modules into sources tree (-a 1).
|
||||
%autosetup -T -b 100 -a 101 -N -n %{ui_src_name}
|
||||
%autosetup -D -T -b 100 -a 101 -S git -n %{ui_src_name} -N
|
||||
%autopatch -p1 -m 201
|
||||
# update_times_patch %%{PATCH201}
|
||||
update_times_patch %{PATCH201}
|
||||
update_times_patch %{PATCH202}
|
||||
|
||||
# patch pcs sources
|
||||
%autosetup -S git -n %{pcs_source_name} -N
|
||||
%autopatch -p1 -M 200
|
||||
# update_times_patch %%{PATCH1}
|
||||
# update_times_patch %%{PATCH0}
|
||||
update_times_patch %{PATCH0}
|
||||
update_times_patch %{PATCH1}
|
||||
update_times_patch %{PATCH2}
|
||||
update_times_patch %{PATCH3}
|
||||
|
||||
# generate .tarball-version if building from an untagged commit, not a released version
|
||||
# autogen uses git-version-gen which uses .tarball-version for generating version number
|
||||
%if 0%{?tarball_version:1}
|
||||
echo %{tarball_version} > %{_builddir}/%{pcs_source_name}/.tarball-version
|
||||
%endif
|
||||
|
||||
%if 0%{?ui_tarball_version:1}
|
||||
echo %{ui_tarball_version} > %{_builddir}/%{ui_src_name}/.tarball-version
|
||||
%if "%{version}" != "%{version_or_commit}"
|
||||
echo "%version+$(echo "%{version_or_commit}" | head -c 8)" > %{_builddir}/%{pcs_source_name}/.tarball-version
|
||||
%endif
|
||||
|
||||
# prepare dirs/files necessary for building python bundles
|
||||
|
|
@ -357,58 +271,39 @@ mkdir -p %{pcs_bundled_dir}/src
|
|||
cp -f %SOURCE41 rpm/
|
||||
cp -f %SOURCE42 rpm/
|
||||
|
||||
|
||||
|
||||
%build
|
||||
%define debug_package %{nil}
|
||||
|
||||
# We left off by setting up pcs, so we are in its directory now
|
||||
# Booth authfile fix support
|
||||
# Fedora 35, 36: set and unset
|
||||
# Fedora 37, 38, ELN = RHEL10: unset only
|
||||
# Fedora 39+: no booth build options
|
||||
%if 0%{?fedora} <= 36
|
||||
%define booth_build_options --enable-booth-enable-authfile-set --enable-booth-enable-authfile-unset
|
||||
%elif 0%{?fedora} <= 38 || 0%{?eln}
|
||||
%define booth_build_options --enable-booth-enable-authfile-unset
|
||||
%endif
|
||||
|
||||
./autogen.sh
|
||||
%{configure} --enable-local-build --enable-use-local-cache-only \
|
||||
--enable-individual-bundling --enable-webui \
|
||||
--with-pcsd-default-cipherlist='PROFILE=SYSTEM' \
|
||||
--with-pcs-lib-dir="%{_prefix}/lib" PYTHON=%{__python3}
|
||||
%{configure} --enable-local-build --enable-use-local-cache-only --enable-individual-bundling %{?booth_build_options} --with-pcs-lib-dir="%{_prefix}/lib" PYTHON=%{__python3}
|
||||
make all
|
||||
|
||||
# Web UI installation
|
||||
# Switch to web ui folder first
|
||||
cd ../%{ui_src_name}
|
||||
./autogen.sh
|
||||
%{configure} \
|
||||
--with-pcsd-webui-dir=%{pcsd_webui_dir} \
|
||||
--with-cockpit-dir=%{cockpit_dir} \
|
||||
--with-metainfo-dir=%{metainfo_dir}
|
||||
make all
|
||||
|
||||
|
||||
# build pcs-web-ui
|
||||
make -C %{_builddir}/%{ui_src_name} build BUILD_USE_EXISTING_NODE_MODULES=true
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
pwd
|
||||
|
||||
# Install cockpit pcs-web-ui
|
||||
cd ../%{ui_src_name}
|
||||
%make_install
|
||||
|
||||
# prepare pcs-web-ui files (not needed for pcs as pcs installs them in Makefile)
|
||||
mkdir -p %{buildroot}/%{_defaultlicensedir}/%{pkg_cockpit_ha_cluster}
|
||||
mkdir -p %{buildroot}/%{_defaultlicensedir}/%{pkg_pcs_web_ui}
|
||||
# install pcs-web-ui
|
||||
# cp -r %%{_builddir}/%%{ui_src_name}/build ${RPM_BUILD_ROOT}%%{_prefix}/lib/%%{pcsd_public_dir}/ui
|
||||
make -C %{_builddir}/%{ui_src_name} _install PCSD_DIR=${RPM_BUILD_ROOT}%{_prefix}/lib/pcsd
|
||||
|
||||
cp COPYING %{buildroot}/%{_defaultlicensedir}/%{pkg_cockpit_ha_cluster}/COPYING_WUI.md
|
||||
mv COPYING %{buildroot}/%{_defaultlicensedir}/%{pkg_pcs_web_ui}/COPYING_WUI.md
|
||||
|
||||
mkdir -p %{buildroot}/%{_docdir}/%{pkg_cockpit_ha_cluster}
|
||||
mkdir -p %{buildroot}/%{_docdir}/%{pkg_pcs_web_ui}
|
||||
|
||||
cp CHANGELOG.md %{buildroot}/%{_docdir}/%{pkg_cockpit_ha_cluster}/CHANGELOG_WUI.md
|
||||
mv CHANGELOG.md %{buildroot}/%{_docdir}/%{pkg_pcs_web_ui}/CHANGELOG_WUI.md
|
||||
|
||||
cp README.md %{buildroot}/%{_docdir}/%{pkg_cockpit_ha_cluster}/README_WUI.md
|
||||
mv README.md %{buildroot}/%{_docdir}/%{pkg_pcs_web_ui}/README_WUI.md
|
||||
|
||||
# Install pcs
|
||||
cd ../%{pcs_source_name}
|
||||
%make_install
|
||||
# symlink favicon into pcsd directories
|
||||
mkdir -p ${RPM_BUILD_ROOT}%{_prefix}/lib/%{pcsd_public_dir}/images/
|
||||
ln -fs /etc/favicon.png ${RPM_BUILD_ROOT}%{_prefix}/lib/%{pcsd_public_dir}/images/favicon.png
|
||||
|
||||
# prepare license files
|
||||
cp %{pcs_bundled_dir}/src/pyagentx-*/LICENSE.txt pyagentx_LICENSE.txt
|
||||
|
|
@ -418,12 +313,7 @@ cp %{pcs_bundled_dir}/src/pyagentx-*/README.md pyagentx_README.md
|
|||
cp %{pcs_bundled_dir}/src/dacite-*/LICENSE dacite_LICENSE
|
||||
cp %{pcs_bundled_dir}/src/dacite-*/README.md dacite_README.md
|
||||
|
||||
|
||||
|
||||
%check
|
||||
# Run validation of cockpit metainfo
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_datadir}/metainfo/%{ui_metainfo_name}
|
||||
|
||||
# In the building environment LC_CTYPE is set to C which causes tests to fail
|
||||
# due to python prints a warning about it to stderr. The following environment
|
||||
# variable disables the warning.
|
||||
|
|
@ -447,7 +337,7 @@ run_all_tests(){
|
|||
|
||||
#run pcsd tests and remove them
|
||||
ruby \
|
||||
-I%{buildroot}%{_prefix}/lib/pcsd \
|
||||
-I$RPM_BUILD_ROOT%{_prefix}/lib/pcsd \
|
||||
-Ipcsd/test \
|
||||
pcsd/test/test_all_suite.rb
|
||||
test_result_ruby=$?
|
||||
|
|
@ -460,31 +350,34 @@ run_all_tests(){
|
|||
|
||||
run_all_tests
|
||||
|
||||
|
||||
# Mark pcsd and pcs_snmp_agent for restart after upgrade
|
||||
%posttrans
|
||||
%systemd_posttrans_with_restart pcsd.service
|
||||
|
||||
%posttrans -n %{pkg_pcs_snmp}
|
||||
%systemd_posttrans_with_restart pcs_snmp_agent.service
|
||||
|
||||
# Restart pcsd if it is running to reload the Tornado app so it detects
|
||||
# presence or absence of the webui backend handler on install/update
|
||||
# of pcs-web-ui that contains it
|
||||
# Systemd will not pick-up on this change because pcs-web-ui doesn't contain
|
||||
# a unit file that would mark it for restart
|
||||
# https://fedoraproject.org/wiki/Changes/Restart_services_at_end_of_rpm_transaction
|
||||
%posttrans -n %{pkg_pcs_web_ui}
|
||||
systemctl try-restart pcsd.service
|
||||
|
||||
# Runs only on pcs-web-ui uninstall
|
||||
# https://docs.fedoraproject.org/en-US/packaging-guidelines/Scriptlets/
|
||||
%postun -n %{pkg_pcs_web_ui}
|
||||
if [ $1 -eq 0 ] ; then
|
||||
systemctl try-restart pcsd.service
|
||||
fi
|
||||
# Make sure the new version of the daemon is running.
|
||||
# Also, make sure to start pcsd-ruby if it hasn't been started or even
|
||||
# installed before. This is done by restarting pcsd.service.
|
||||
%{_bindir}/systemctl daemon-reload
|
||||
%{_bindir}/systemctl try-restart pcsd.service
|
||||
|
||||
|
||||
%post
|
||||
%systemd_post pcsd.service
|
||||
%systemd_post pcsd-ruby.service
|
||||
|
||||
%post -n %{pcs_snmp_pkg_name}
|
||||
%systemd_post pcs_snmp_agent.service
|
||||
|
||||
%preun
|
||||
%systemd_preun pcsd.service
|
||||
%systemd_preun pcsd-ruby.service
|
||||
|
||||
%preun -n %{pcs_snmp_pkg_name}
|
||||
%systemd_preun pcs_snmp_agent.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart pcsd.service
|
||||
%systemd_postun_with_restart pcsd-ruby.service
|
||||
|
||||
%postun -n %{pcs_snmp_pkg_name}
|
||||
%systemd_postun_with_restart pcs_snmp_agent.service
|
||||
|
||||
%files
|
||||
%doc CHANGELOG.md
|
||||
|
|
@ -493,10 +386,9 @@ fi
|
|||
%license dacite_LICENSE
|
||||
%license COPYING
|
||||
%{python3_sitelib}/*
|
||||
%{_bindir}/pcs
|
||||
%{_bindir}/pcsd
|
||||
%{_sbindir}/pcs
|
||||
%{_sbindir}/pcsd
|
||||
%{_prefix}/lib/pcs/*
|
||||
%{_prefix}/lib/pkgconfig/pcs.pc
|
||||
%{_prefix}/lib/pcsd/*
|
||||
%{_unitdir}/pcsd.service
|
||||
%{_unitdir}/pcsd-ruby.service
|
||||
|
|
@ -517,21 +409,9 @@ fi
|
|||
%{_mandir}/man8/pcsd.*
|
||||
%exclude %{_prefix}/lib/pcs/pcs_snmp_agent
|
||||
%exclude %{_prefix}/lib/pcs/%{pcs_bundled_dir}/packages/pyagentx*
|
||||
%exclude %{cockpit_dir}
|
||||
%exclude %{ui_metainfo}
|
||||
%exclude %{python3_sitelib}/pcs/daemon/app/webui
|
||||
%exclude %{pcsd_webui_dir}
|
||||
|
||||
%files -n %{pkg_pcs_web_ui}
|
||||
%doc CHANGELOG.md
|
||||
%doc %{_docdir}/%{pkg_pcs_web_ui}/CHANGELOG_WUI.md
|
||||
%doc %{_docdir}/%{pkg_pcs_web_ui}/README_WUI.md
|
||||
%license COPYING
|
||||
%license %{_defaultlicensedir}/%{pkg_pcs_web_ui}/COPYING_WUI.md
|
||||
%{python3_sitelib}/pcs/daemon/app/webui
|
||||
%{pcsd_webui_dir}
|
||||
|
||||
%files -n %{pkg_pcs_snmp}
|
||||
%files -n %{pcs_snmp_pkg_name}
|
||||
%{_prefix}/lib/pcs/pcs_snmp_agent
|
||||
%{_prefix}/lib/pcs/%{pcs_bundled_dir}/packages/pyagentx*
|
||||
%{_unitdir}/pcs_snmp_agent.service
|
||||
|
|
@ -544,86 +424,7 @@ fi
|
|||
%license COPYING
|
||||
%license pyagentx_LICENSE.txt
|
||||
|
||||
%files -n %{pkg_cockpit_ha_cluster}
|
||||
%doc %{_docdir}/%{pkg_cockpit_ha_cluster}/CHANGELOG_WUI.md
|
||||
%doc %{_docdir}/%{pkg_cockpit_ha_cluster}/README_WUI.md
|
||||
%license %{_defaultlicensedir}/%{pkg_cockpit_ha_cluster}/COPYING_WUI.md
|
||||
%{cockpit_dir}
|
||||
%{ui_metainfo}
|
||||
|
||||
|
||||
|
||||
%changelog
|
||||
* Fri Sep 19 2025 Python Maint <python-maint@redhat.com> - 0.12.1-5
|
||||
- Rebuilt for Python 3.14.0rc3 bytecode
|
||||
|
||||
* Fri Aug 15 2025 Python Maint <python-maint@redhat.com> - 0.12.1-4
|
||||
- Rebuilt for Python 3.14.0rc2 bytecode
|
||||
|
||||
* Wed Jul 30 2025 Michal Pospíšil <mpospisi@redhat.com> - 0.12.1-3
|
||||
- Remove BuildRequires: python3-wheel when using setuptools 71+
|
||||
|
||||
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 0.12.1-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
|
||||
|
||||
* Fri Jul 18 2025 Michal Pospíšil <mpospisi@redhat.com> - 0.12.1-1
|
||||
- Rebased pcs to the newest major version (see CHANGELOG.md)
|
||||
Resolves: rhbz#2371770
|
||||
- Updated standalone web UI and HA Cluster Management Cockpit application to pcs-web-ui 0.1.23 (see CHANGELOG_WUI.md)
|
||||
- There is now a changelog for the HA Cluster Management Cockpit application and the standalone web UI in both packages
|
||||
- The upstream version of pcs-web-ui can now be queried through RPM in both packages - see bundled(pcs-web-ui)
|
||||
- Updated bundled Python dependency dacite
|
||||
- Compatibility with rubygem-rack >= 3
|
||||
Resolves: rhbz#2372462
|
||||
|
||||
* Tue Jun 03 2025 Python Maint <python-maint@redhat.com> - 0.12.0-2
|
||||
- Rebuilt for Python 3.14
|
||||
|
||||
* Mon Jan 27 2025 Michal Pospíšil <mpospisi@redhat.com> - 0.12.0-1
|
||||
- Rebased pcs to the newest major version (see CHANGELOG.md)
|
||||
Resolves: rhbz#2341012
|
||||
- New subpackage pcs-web-ui - enables standalone web UI when the subpackage is installed on the system (default), uninstall the subpackage to disable the web UI
|
||||
- Updated standalone web UI and HA Cluster Management Cockpit application to pcs-web-ui 0.1.22
|
||||
- Fixes for compatibility with Ruby 3.4
|
||||
Resolves: rhbz#2331005
|
||||
|
||||
* Fri Jan 17 2025 Fedora Release Engineering <releng@fedoraproject.org> - 0.11.8-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
|
||||
|
||||
* Tue Aug 6 2024 Michal Pospíšil <mpospisi@redhat.com> - 0.11.8-1
|
||||
- Rebased to the latest sources (see CHANGELOG.md)
|
||||
- Updated pcs-web-ui to 0.1.20
|
||||
|
||||
* Thu Jul 18 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.11.7-5
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
|
||||
|
||||
* Sun Jun 09 2024 Python Maint <python-maint@redhat.com> - 0.11.7-4
|
||||
- Rebuilt for Python 3.13
|
||||
|
||||
* Mon Feb 5 2024 Michal Pospisil <mpospisi@redhat.com> - 0.11.7-3
|
||||
- Fixed a bug preventing the Cockpit Application from being installed from Cockpit
|
||||
|
||||
* Thu Jan 25 2024 Fedora Release Engineering <releng@fedoraproject.org> - 0.11.7-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Mon Jan 8 2024 Michal Pospisil <mpospisi@redhat.com> - 0.11.7-1
|
||||
- Rebased to the latest upstream sources (see CHANGELOG.md)
|
||||
- Updated pcs-web-ui to 0.1.18
|
||||
- TLS cipher setting in pcsd now follows system-wide crypto policies by default
|
||||
- Added cockpit-ha-cluster subpackage that adds pcs-web-ui as a Cockpit application
|
||||
|
||||
* Thu Jul 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 0.11.6-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
|
||||
|
||||
* Wed Jun 28 2023 Python Maint <python-maint@redhat.com> - 0.11.6-2
|
||||
- Rebuilt for Python 3.12
|
||||
|
||||
* Wed Jun 21 2023 Michal Pospisil <mpospisi@redhat.com> - 0.11.6-1
|
||||
- Rebased to the latest upstream sources (see CHANGELOG.md)
|
||||
- Updated pcs-web-ui
|
||||
- Removed dependency fedora-logos - favicon is now correctly provided by pcs-web-ui
|
||||
- Resolves: rhbz#2109852 rhbz#2170648
|
||||
|
||||
* Wed Apr 12 2023 Michal Pospisil <mpospisi@redhat.com> - 0.11.5-2
|
||||
- Fix displaying differences between configuration checkpoints in “pcs config checkpoint diff” command
|
||||
- Fix “pcs stonith update-scsi-devices” command which was broken since Pacemaker-2.1.5-rc1
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
summary: PCS gating test plan
|
||||
description: Runs upstream tier0, tier1 and smoke tests
|
||||
|
||||
discover:
|
||||
dist-git-source: true
|
||||
dist-git-install-builddeps: true
|
||||
how: shell
|
||||
tests:
|
||||
- name: tier0
|
||||
test: |
|
||||
./prepare-tests.sh
|
||||
$TMT_SOURCE_DIR/pcs-*/pcs_test/suite --tier0 -v --vanilla --installed
|
||||
duration: 10m
|
||||
tier: 0
|
||||
tag: fast
|
||||
- name: tier1
|
||||
test: |
|
||||
./prepare-tests.sh
|
||||
$TMT_SOURCE_DIR/pcs-*/pcs_test/suite --tier1 -v --vanilla --installed
|
||||
duration: 2h
|
||||
tier: 1
|
||||
- name: smoke
|
||||
test: |
|
||||
systemctl start pcsd
|
||||
./prepare-tests.sh
|
||||
$TMT_SOURCE_DIR/pcs-*/pcs_test/smoke.sh
|
||||
duration: 10m
|
||||
tier: smoke
|
||||
tag: fast
|
||||
|
||||
execute:
|
||||
how: tmt
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eo xtrace
|
||||
cd $TMT_SOURCE_DIR
|
||||
# Use stamp file to abort if this script already ran
|
||||
if [ -e tests-prepared-stamp ]; then exit 0; fi
|
||||
# RPM 4.20 changed the builddir structure - unpacked sources go to *-build but
|
||||
# tmt copies them back to pcs-*, so the pcs-*-build folder is empty
|
||||
# Remove pcs-web-ui, pcs-*-build for "cd pcs-*" to have exactly one match
|
||||
rm -rf pcs-web-ui-* pcs-*-build
|
||||
cd pcs-*/
|
||||
# Run autotools, use bundled dependencies from the system
|
||||
export PYTHONPATH=/usr/lib/pcs/pcs_bundled/packages/
|
||||
export GEM_HOME=/usr/lib/pcsd/vendor/bundle/
|
||||
# We need to use cd pcs-* because when pcs-web-ui starts using autotools, running
|
||||
# autogen and configure with expanded TMT_SOURCE_DIR will match that too
|
||||
./autogen.sh
|
||||
./configure --enable-webui --enable-local-build --enable-use-local-cache-only \
|
||||
--enable-individual-bundling --with-pcs-lib-dir=/usr/lib
|
||||
# Remove pcs sources to make sure tests are not using any of those files
|
||||
rm -rf pcs
|
||||
touch ../tests-prepared-stamp
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
From e7fa056f582c992d3d2b289911be20440fb839ac Mon Sep 17 00:00:00 2001
|
||||
From: Ivan Devat <idevat@redhat.com>
|
||||
Date: Tue, 5 Nov 2024 16:35:02 +0100
|
||||
Subject: [PATCH 1/2] show info page instead of webui
|
||||
|
||||
---
|
||||
pcs/Makefile.am | 1 +
|
||||
pcs/daemon/app/webui_info_handler.py | 31 ++++++++++++++++++++++++++++
|
||||
pcs/daemon/run.py | 4 +++-
|
||||
pcs_test/smoke.sh.in | 4 ++--
|
||||
pcsd/public/ui_instructions.html | 24 ++++++++++-----------
|
||||
5 files changed, 48 insertions(+), 16 deletions(-)
|
||||
create mode 100644 pcs/daemon/app/webui_info_handler.py
|
||||
|
||||
diff --git a/pcs/Makefile.am b/pcs/Makefile.am
|
||||
index 1297473ff..8d4b93073 100644
|
||||
--- a/pcs/Makefile.am
|
||||
+++ b/pcs/Makefile.am
|
||||
@@ -219,6 +219,7 @@ EXTRA_DIST = \
|
||||
daemon/app/webui/core.py \
|
||||
daemon/app/webui/session.py \
|
||||
daemon/app/webui/sinatra_ui.py \
|
||||
+ daemon/app/webui_info_handler.py \
|
||||
daemon/async_tasks/__init__.py \
|
||||
daemon/async_tasks/scheduler.py \
|
||||
daemon/async_tasks/task.py \
|
||||
diff --git a/pcs/daemon/app/webui_info_handler.py b/pcs/daemon/app/webui_info_handler.py
|
||||
new file mode 100644
|
||||
index 000000000..3ab8275bf
|
||||
--- /dev/null
|
||||
+++ b/pcs/daemon/app/webui_info_handler.py
|
||||
@@ -0,0 +1,31 @@
|
||||
+from pcs.daemon.app.common import (
|
||||
+ BaseHandler,
|
||||
+ RoutesType,
|
||||
+)
|
||||
+
|
||||
+
|
||||
+class _WebuiInfoHandler(BaseHandler):
|
||||
+ __path = None
|
||||
+
|
||||
+ def initialize(self, path):
|
||||
+ self.__path = path
|
||||
+
|
||||
+ def get(self):
|
||||
+ self.set_status(404)
|
||||
+ self.render(self.__path)
|
||||
+
|
||||
+
|
||||
+def get_routes(path: str) -> RoutesType:
|
||||
+ return [
|
||||
+ # The following two rules can be compressed into one: r"/(ui/?)?".
|
||||
+ # However, the content of the parentheses used here should be captured
|
||||
+ # and passed in to the handler’s get method as an argument.
|
||||
+ # Unfortunately, it seems that tornado version 6.4.1 don't pass this
|
||||
+ # argument (unlike version 6.3.3). Maybe it's a bug (it needs further
|
||||
+ # inspection). These rules are a safe way to avoid surprises.
|
||||
+ # Moreover, the captured parameter is irrelevant to the functionality
|
||||
+ # of the handler.
|
||||
+ (r"/", _WebuiInfoHandler, dict(path=path)),
|
||||
+ (r"/ui/?", _WebuiInfoHandler, dict(path=path)),
|
||||
+ (r"/ui/.*", _WebuiInfoHandler, dict(path=path)),
|
||||
+ ]
|
||||
diff --git a/pcs/daemon/run.py b/pcs/daemon/run.py
|
||||
index 558315c23..cfe9999fc 100644
|
||||
--- a/pcs/daemon/run.py
|
||||
+++ b/pcs/daemon/run.py
|
||||
@@ -33,6 +33,7 @@ from pcs.daemon.app import (
|
||||
auth,
|
||||
sinatra_remote,
|
||||
sinatra_ui,
|
||||
+ webui_info_handler,
|
||||
)
|
||||
from pcs.daemon.app import capabilities as capabilities_app
|
||||
|
||||
@@ -168,7 +169,8 @@ def configure_app( # noqa: PLR0913
|
||||
# Even with disabled (standalone) webui the following routes must be
|
||||
# provided because they can be used via unix socket from cockpit.
|
||||
routes.extend(
|
||||
- sinatra_ui.get_routes(auth_provider, ruby_pcsd_wrapper)
|
||||
+ webui_info_handler.get_routes(webui_fallback)
|
||||
+ + sinatra_ui.get_routes(auth_provider, ruby_pcsd_wrapper)
|
||||
)
|
||||
|
||||
return Application(
|
||||
diff --git a/pcs_test/smoke.sh.in b/pcs_test/smoke.sh.in
|
||||
index fdfe8be2c..a9bb83447 100755
|
||||
--- a/pcs_test/smoke.sh.in
|
||||
+++ b/pcs_test/smoke.sh.in
|
||||
@@ -71,10 +71,10 @@ if [ "$webui_http_code_response" = "200" ]; then
|
||||
curl --insecure --cookie ${cookie_file} --header "X-Requested-With: XMLHttpRequest" --data "hidden[hidden_input]=&config[stonith-enabled]=false" https://localhost:2224/managec/${cluster_name}/update_cluster_settings > "${output_file}"
|
||||
cat "${output_file}"; echo ""
|
||||
[ "$(cat ${output_file})" = "Update Successful" ]
|
||||
-elif [ "$webui_http_code_response" = "401" ]; then
|
||||
+elif [ "$webui_http_code_response" = "404" ]; then
|
||||
curl --insecure https://localhost:2224/ui/ > "${output_file}"
|
||||
cat "${output_file}"; echo ""
|
||||
- [ "$(cat "${output_file}")" = '{"notauthorized":"true"}' ]
|
||||
+ grep "HA cluster management has been moved" "${output_file}"
|
||||
else
|
||||
echo "Unexpected response from https://localhost:2224/ui/ - http code: '${webui_http_code_response}'"
|
||||
exit 1
|
||||
diff --git a/pcsd/public/ui_instructions.html b/pcsd/public/ui_instructions.html
|
||||
index a120ed3d4..b9c1c3152 100644
|
||||
--- a/pcsd/public/ui_instructions.html
|
||||
+++ b/pcsd/public/ui_instructions.html
|
||||
@@ -1,27 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
- <title>Pcs WebUI instructions</title>
|
||||
+ <title>Web UI is disabled</title>
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
- <h1>Pcs WebUI instructions</h1>
|
||||
+ <h1>Package <code>pcs-web-ui</code> is not installed</h1>
|
||||
<p>
|
||||
- WebUI is not a part of pcs repository but it has its own
|
||||
- <a href="https://github.com/ClusterLabs/pcs-web-ui">repository</a>.
|
||||
+ Since Fedora 42, pcsd web UI is distributed with pcs as <code>pcs-web-ui
|
||||
+ </code> package. This<br>package can be uninstalled to disable the web UI.
|
||||
</p>
|
||||
<p>
|
||||
- You can clone <a href="https://github.com/ClusterLabs/pcs-web-ui">WebUI repository</a>
|
||||
- and build the web application into pcs by:
|
||||
+ To re-enable pcsd web UI, install the <code>pcs-web-ui</code> RPM package.
|
||||
</p>
|
||||
- <pre><code>
|
||||
- $ npm install
|
||||
- $ npm run build
|
||||
- $ mv ./build [/path/to/]pcs/pcsd/public/ui
|
||||
- </code></pre>
|
||||
<p>
|
||||
- For more details, see instructions in
|
||||
- <a href="https://github.com/ClusterLabs/pcs-web-ui/blob/main/README.md">README.md</a>.
|
||||
+ Another option is to try pcsd web UI as an application for
|
||||
+ <a href="https://cockpit-project.org/">Cockpit</a>
|
||||
+ - a web-based<br>graphical interface for servers. The HA Cluster Management
|
||||
+ application can be<br>installed from within the Applications pane in
|
||||
+ Cockpit or by installing the<br><code>cockpit-ha-cluster</code> RPM
|
||||
+ package.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
--
|
||||
2.50.1
|
||||
|
||||
8
sources
8
sources
|
|
@ -1,5 +1,5 @@
|
|||
SHA512 (pyagentx-0.4.pcs.2.tar.gz) = d4194fec9a3e5fefe3793d49b7fec1feafef294c7e613a06046c2993daeefc5cb39d7c5b2b402ff83e49b2d976953f862264288c758c0be09d997b5323cc558a
|
||||
SHA512 (dacite-1.9.2.tar.gz) = 69513bc1acd43e45a208ce4b4186072f92d9057a6a88c77d56f21405fbed7964d94fe4f6a37c99754a793caa2bd0584664dfab69169ef0d3564bb09d37769e59
|
||||
SHA512 (pcs-0.12.1.tar.gz) = 4f17a8d9c15b8c9208c94a264f5f79f03abc451e3f4ae4ba0fb338055a26407d4961466dd8f3565f6882c2c00f1d6a1ec8fd15dadcb0cf1a5586d37c56c77238
|
||||
SHA512 (pcs-web-ui-0.1.23.tar.gz) = 6bc709926f26a02d33fb3865d15a1cf15db51a07dd9b25c63f33277c427c3403c189e2ac5e7adc795b254ad0bdb50f1bc4be70f1385bc8522ca502142d41fc26
|
||||
SHA512 (pcs-web-ui-node-modules-0.1.23.tar.xz) = f39dd1fd391f10b874b5fec34da1a2f2496d66b31af736ee1dfc2ef6e0b518efd03053fd00312c84e10a33ffda492e12d48a898a21efb6241e5459828e500e80
|
||||
SHA512 (dacite-1.8.0.tar.gz) = 97816021b8285197bcd00d9323dd61b33b3a2e51424287ff8e63545082ae9c6b45a416cd2ff2daff41b271a0312192d6a0ec967f6f929402d3c6b8c12b809e08
|
||||
SHA512 (pcs-0.11.5.tar.gz) = 2c344537d41416c9af22a18057523b22a1b40b6354ad4b7c7061f1a1690828553ba1d7d10cff0c8adda3c7ef0bee5ce76ece8f2a05d80865f49b71c676fed6aa
|
||||
SHA512 (pcs-web-ui-0.1.16.1.tar.gz) = 01427f35276cd5ee2926d6541ec9ccce7e86ec592d294dfb08b086ca701e6b937563ac09ba2b5e82b342b58234f41f6cec38bb22599a3b5181db96e0a0382004
|
||||
SHA512 (pcs-web-ui-node-modules-0.1.16.1.tar.xz) = 6263f14ba017ed98a17985ee2899f25eb97288f62ef2ded90b0217702bc30d0aa80238f1787e34f6ae6b276df2543451eda44422c1df7cade96617209de5c62d
|
||||
|
|
|
|||
72
tests/tests.yml
Normal file
72
tests/tests.yml
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
- hosts: localhost
|
||||
tags:
|
||||
- classic
|
||||
vars:
|
||||
# standard-test-basic directory for tests are relative to {{ tenv_workdir }}
|
||||
tenv_workdir: /var/test
|
||||
pre_tasks:
|
||||
- import_role:
|
||||
name: standard-test-source
|
||||
vars:
|
||||
fetch_only: True
|
||||
- name: Copy files including source to test environment
|
||||
synchronize:
|
||||
src: "{{ playbook_dir }}/.."
|
||||
dest: "{{ tenv_workdir }}"
|
||||
mode: push
|
||||
ssh_args: "-o UserKnownHostsFile=/dev/null"
|
||||
- name: Start pcsd
|
||||
systemd:
|
||||
state: started
|
||||
name: pcsd
|
||||
daemon_reload: yes
|
||||
|
||||
roles:
|
||||
# roles documentation:
|
||||
# https://pagure.io/standard-test-roles/blob/master/f/roles/standard-test-source
|
||||
- role: standard-test-basic
|
||||
required_packages:
|
||||
- autoconf
|
||||
- automake
|
||||
- make
|
||||
- rpm-build
|
||||
- ruby-devel
|
||||
- git-core
|
||||
- booth-site
|
||||
- fence-agents-apc
|
||||
- fence-agents-ipmilan
|
||||
- fence-agents-scsi
|
||||
- fence-virt
|
||||
- pcs
|
||||
- python3-pip
|
||||
- python3-setuptools_scm
|
||||
- python3-wheel
|
||||
- rubygem-test-unit
|
||||
- wget
|
||||
required_services:
|
||||
- pcsd
|
||||
tests:
|
||||
# dir: . -> dot means tests dir in distgit
|
||||
- prepare-source:
|
||||
dir: ./
|
||||
run: rpmbuild -bp {{tenv_workdir}}/*.spec --nodeps --define "_sourcedir {{tenv_workdir}}" --define "_builddir {{tenv_workdir}}/source"
|
||||
# pcs-web-ui sources are deleted because there are conflicts during move of sources
|
||||
# pcs-web-ui sources aren't needed during testing
|
||||
- flatten-source:
|
||||
dir: ./
|
||||
run: rm -rf {{tenv_workdir}}/source/pcs-web-ui-*; shopt -s dotglob; mv {{tenv_workdir}}/source/*/* {{tenv_workdir}}/source
|
||||
- build_sources:
|
||||
dir: ./source
|
||||
run: "export PYTHONPATH=/usr/lib/pcs/pcs_bundled/packages/; ./autogen.sh && ./configure --enable-tests-only --with-pcs-lib-dir=/usr/lib"
|
||||
- remove_sources:
|
||||
dir: ./source
|
||||
run: rm -rfv pcs
|
||||
- run_upstream_tier0_tests:
|
||||
dir: ./source
|
||||
run: pcs_test/suite --tier0 -v --vanilla --installed
|
||||
- run_upstream_tier1_tests:
|
||||
dir: ./source
|
||||
run: pcs_test/suite --tier1 -v --vanilla --installed
|
||||
- run_smoke_tests:
|
||||
dir: ./source
|
||||
run: pcs_test/smoke.sh
|
||||
Loading…
Add table
Add a link
Reference in a new issue