Blame SOURCES/006-crm_resource.patch

36923b
From a467f0953c61bd56a9b34a98c71855d3cfbf6ba4 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 16:26:30 -0500
36923b
Subject: [PATCH 01/14] Refactor: tools: use a flag to indicate locked
36923b
 resources in crm_resource
36923b
36923b
... to make the handling consistent with other checks. This also allows some of
36923b
the code to be simplified.
36923b
---
36923b
 tools/crm_resource.h         | 13 +++++++++----
36923b
 tools/crm_resource_print.c   | 21 ++++++++-------------
36923b
 tools/crm_resource_runtime.c |  7 +++----
36923b
 3 files changed, 20 insertions(+), 21 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
36923b
index 71a978893..b5fdd1bb5 100644
36923b
--- a/tools/crm_resource.h
36923b
+++ b/tools/crm_resource.h
36923b
@@ -8,6 +8,10 @@
36923b
  */
36923b
 
36923b
 #include <crm_internal.h>
36923b
+
36923b
+#include <stdint.h>
36923b
+#include <stdbool.h>
36923b
+
36923b
 #include <crm/crm.h>
36923b
 
36923b
 #include <crm/msg_xml.h>
36923b
@@ -31,13 +35,14 @@ typedef struct node_info_s {
36923b
 enum resource_check_flags {
36923b
     rsc_remain_stopped  = (1 << 0),
36923b
     rsc_unpromotable    = (1 << 1),
36923b
-    rsc_unmanaged       = (1 << 2)
36923b
+    rsc_unmanaged       = (1 << 2),
36923b
+    rsc_locked          = (1 << 3),
36923b
 };
36923b
 
36923b
 typedef struct resource_checks_s {
36923b
-    pe_resource_t *rsc;
36923b
-    unsigned int flags;
36923b
-    const char *lock_node;
36923b
+    pe_resource_t *rsc;     // Resource being checked
36923b
+    uint32_t flags;         // Group of enum resource_check_flags
36923b
+    const char *lock_node;  // Node that resource is shutdown-locked to, if any
36923b
 } resource_checks_t;
36923b
 
36923b
 resource_checks_t *cli_check_resource(pe_resource_t *rsc, char *role_s, char *managed);
36923b
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
36923b
index 5abf3df0c..f63fc952d 100644
36923b
--- a/tools/crm_resource_print.c
36923b
+++ b/tools/crm_resource_print.c
36923b
@@ -450,14 +450,13 @@ resource_check_list_default(pcmk__output_t *out, va_list args) {
36923b
     resource_checks_t *checks = va_arg(args, resource_checks_t *);
36923b
 
36923b
     pe_resource_t *parent = uber_parent(checks->rsc);
36923b
-    int rc = pcmk_rc_no_output;
36923b
-    bool printed = false;
36923b
 
36923b
-    if (checks->flags != 0 || checks->lock_node != NULL) {
36923b
-        printed = true;
36923b
-        out->begin_list(out, NULL, NULL, "Resource Checks");
36923b
+    if (checks->flags == 0) {
36923b
+        return pcmk_rc_no_output;
36923b
     }
36923b
 
36923b
+    out->begin_list(out, NULL, NULL, "Resource Checks");
36923b
+
36923b
     if (pcmk_is_set(checks->flags, rsc_remain_stopped)) {
36923b
         out->list_item(out, "check", "Configuration specifies '%s' should remain stopped",
36923b
                        parent->id);
36923b
@@ -473,17 +472,13 @@ resource_check_list_default(pcmk__output_t *out, va_list args) {
36923b
                        parent->id);
36923b
     }
36923b
 
36923b
-    if (checks->lock_node) {
36923b
+    if (pcmk_is_set(checks->flags, rsc_locked)) {
36923b
         out->list_item(out, "check", "'%s' is locked to node %s due to shutdown",
36923b
                        parent->id, checks->lock_node);
36923b
     }
36923b
 
36923b
-    if (printed) {
36923b
-        out->end_list(out);
36923b
-        rc = pcmk_rc_ok;
36923b
-    }
36923b
-
36923b
-    return rc;
36923b
+    out->end_list(out);
36923b
+    return pcmk_rc_ok;
36923b
 }
36923b
 
36923b
 PCMK__OUTPUT_ARGS("resource-check-list", "resource_checks_t *")
36923b
@@ -509,7 +504,7 @@ resource_check_list_xml(pcmk__output_t *out, va_list args) {
36923b
         pcmk__xe_set_bool_attr(node, "unmanaged", true);
36923b
     }
36923b
 
36923b
-    if (checks->lock_node) {
36923b
+    if (pcmk_is_set(checks->flags, rsc_locked)) {
36923b
         crm_xml_add(node, "locked-to", checks->lock_node);
36923b
     }
36923b
 
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index 9e7e1fe74..b5bccadaf 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -36,7 +36,8 @@ cli_check_resource(pe_resource_t *rsc, char *role_s, char *managed)
36923b
         rc->flags |= rsc_unmanaged;
36923b
     }
36923b
 
36923b
-    if (rsc->lock_node) {
36923b
+    if (rsc->lock_node != NULL) {
36923b
+        rc->flags |= rsc_locked;
36923b
         rc->lock_node = rsc->lock_node->details->uname;
36923b
     }
36923b
 
36923b
@@ -914,9 +915,7 @@ cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
 
36923b
     checks = cli_check_resource(rsc, role_s, managed);
36923b
 
36923b
-    if (checks->flags != 0 || checks->lock_node != NULL) {
36923b
-        rc = out->message(out, "resource-check-list", checks);
36923b
-    }
36923b
+    rc = out->message(out, "resource-check-list", checks);
36923b
 
36923b
     free(role_s);
36923b
     free(managed);
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 7f8f94d0a1086e592e39f3a1a812b1a65225c09b Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 16:48:03 -0500
36923b
Subject: [PATCH 02/14] Refactor: tools: functionize individual resource checks
36923b
 in crm_resource
36923b
36923b
... rather than have one check-everything function, to make the code simpler
36923b
and more readable.
36923b
---
36923b
 tools/crm_resource_runtime.c | 101 ++++++++++++++++++++---------------
36923b
 1 file changed, 57 insertions(+), 44 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index b5bccadaf..d47f959f5 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -15,36 +15,6 @@
36923b
 #include <crm/common/lists_internal.h>
36923b
 #include <crm/services_internal.h>
36923b
 
36923b
-resource_checks_t *
36923b
-cli_check_resource(pe_resource_t *rsc, char *role_s, char *managed)
36923b
-{
36923b
-    pe_resource_t *parent = uber_parent(rsc);
36923b
-    resource_checks_t *rc = calloc(1, sizeof(resource_checks_t));
36923b
-
36923b
-    if (role_s) {
36923b
-        enum rsc_role_e role = text2role(role_s);
36923b
-
36923b
-        if (role == RSC_ROLE_STOPPED) {
36923b
-            rc->flags |= rsc_remain_stopped;
36923b
-        } else if (pcmk_is_set(parent->flags, pe_rsc_promotable) &&
36923b
-                   (role == RSC_ROLE_UNPROMOTED)) {
36923b
-            rc->flags |= rsc_unpromotable;
36923b
-        }
36923b
-    }
36923b
-
36923b
-    if (managed && !crm_is_true(managed)) {
36923b
-        rc->flags |= rsc_unmanaged;
36923b
-    }
36923b
-
36923b
-    if (rsc->lock_node != NULL) {
36923b
-        rc->flags |= rsc_locked;
36923b
-        rc->lock_node = rsc->lock_node->details->uname;
36923b
-    }
36923b
-
36923b
-    rc->rsc = rsc;
36923b
-    return rc;
36923b
-}
36923b
-
36923b
 static GList *
36923b
 build_node_info_list(pe_resource_t *rsc)
36923b
 {
36923b
@@ -898,29 +868,72 @@ cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
36923b
     return rc;
36923b
 }
36923b
 
36923b
-int
36923b
-cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
+static void
36923b
+check_role(pcmk__output_t *out, cib_t *cib_conn, resource_checks_t *checks)
36923b
 {
36923b
     char *role_s = NULL;
36923b
-    char *managed = NULL;
36923b
-    pe_resource_t *parent = uber_parent(rsc);
36923b
-    int rc = pcmk_rc_no_output;
36923b
-    resource_checks_t *checks = NULL;
36923b
-
36923b
-    find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
36923b
-                       NULL, NULL, NULL, XML_RSC_ATTR_MANAGED, &managed);
36923b
+    pe_resource_t *parent = uber_parent(checks->rsc);
36923b
 
36923b
     find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
36923b
                        NULL, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, &role_s);
36923b
+    if (role_s == NULL) {
36923b
+        return;
36923b
+    }
36923b
 
36923b
-    checks = cli_check_resource(rsc, role_s, managed);
36923b
+    switch (text2role(role_s)) {
36923b
+        case RSC_ROLE_STOPPED:
36923b
+            checks->flags |= rsc_remain_stopped;
36923b
+            break;
36923b
 
36923b
-    rc = out->message(out, "resource-check-list", checks);
36923b
+        case RSC_ROLE_UNPROMOTED:
36923b
+            if (pcmk_is_set(parent->flags, pe_rsc_promotable)) {
36923b
+                checks->flags |= rsc_unpromotable;
36923b
+            }
36923b
+            break;
36923b
 
36923b
+        default:
36923b
+            break;
36923b
+    }
36923b
     free(role_s);
36923b
-    free(managed);
36923b
-    free(checks);
36923b
-    return rc;
36923b
+}
36923b
+
36923b
+static void
36923b
+check_managed(pcmk__output_t *out, cib_t *cib_conn, resource_checks_t *checks)
36923b
+{
36923b
+    char *managed_s = NULL;
36923b
+    pe_resource_t *parent = uber_parent(checks->rsc);
36923b
+
36923b
+    find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
36923b
+                       NULL, NULL, NULL, XML_RSC_ATTR_MANAGED, &managed_s);
36923b
+    if (managed_s == NULL) {
36923b
+        return;
36923b
+    }
36923b
+
36923b
+    if (!crm_is_true(managed_s)) {
36923b
+        checks->flags |= rsc_unmanaged;
36923b
+    }
36923b
+    free(managed_s);
36923b
+}
36923b
+
36923b
+static void
36923b
+check_locked(resource_checks_t *checks)
36923b
+{
36923b
+    if (checks->rsc->lock_node != NULL) {
36923b
+        checks->flags |= rsc_locked;
36923b
+        checks->lock_node = checks->rsc->lock_node->details->uname;
36923b
+    }
36923b
+}
36923b
+
36923b
+int
36923b
+cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
+{
36923b
+    resource_checks_t checks = { .rsc = rsc };
36923b
+
36923b
+    check_role(out, cib_conn, &checks;;
36923b
+    check_managed(out, cib_conn, &checks;;
36923b
+    check_locked(&checks;;
36923b
+
36923b
+    return out->message(out, "resource-check-list", &checks;;
36923b
 }
36923b
 
36923b
 // \return Standard Pacemaker return code
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 32414475281d909cd808f723a41d88a5e0d2b254 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 17:11:07 -0500
36923b
Subject: [PATCH 03/14] Fix: tools: crm_resource target-role check should use
36923b
 meta-attribute table
36923b
36923b
Previously, check_role() searched the CIB for the uber-parent's target-role
36923b
attribute. That could give incorrect results if target-role was set on a
36923b
different resource in the ancestry chain (e.g. the resource itself for a group
36923b
member, or the group for a cloned group), or if there were multiple target-role
36923b
settings (e.g. using rules).
36923b
36923b
Now, target-role is checked in rsc->meta, which should be fully evaluated for
36923b
inheritance and rules.
36923b
---
36923b
 tools/crm_resource_runtime.c | 15 ++++++---------
36923b
 1 file changed, 6 insertions(+), 9 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index d47f959f5..e9d05cb77 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -869,24 +869,22 @@ cli_cleanup_all(pcmk_ipc_api_t *controld_api, const char *node_name,
36923b
 }
36923b
 
36923b
 static void
36923b
-check_role(pcmk__output_t *out, cib_t *cib_conn, resource_checks_t *checks)
36923b
+check_role(resource_checks_t *checks)
36923b
 {
36923b
-    char *role_s = NULL;
36923b
-    pe_resource_t *parent = uber_parent(checks->rsc);
36923b
+    const char *role_s = g_hash_table_lookup(checks->rsc->meta,
36923b
+                                             XML_RSC_ATTR_TARGET_ROLE);
36923b
 
36923b
-    find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
36923b
-                       NULL, NULL, NULL, XML_RSC_ATTR_TARGET_ROLE, &role_s);
36923b
     if (role_s == NULL) {
36923b
         return;
36923b
     }
36923b
-
36923b
     switch (text2role(role_s)) {
36923b
         case RSC_ROLE_STOPPED:
36923b
             checks->flags |= rsc_remain_stopped;
36923b
             break;
36923b
 
36923b
         case RSC_ROLE_UNPROMOTED:
36923b
-            if (pcmk_is_set(parent->flags, pe_rsc_promotable)) {
36923b
+            if (pcmk_is_set(uber_parent(checks->rsc)->flags,
36923b
+                            pe_rsc_promotable)) {
36923b
                 checks->flags |= rsc_unpromotable;
36923b
             }
36923b
             break;
36923b
@@ -894,7 +892,6 @@ check_role(pcmk__output_t *out, cib_t *cib_conn, resource_checks_t *checks)
36923b
         default:
36923b
             break;
36923b
     }
36923b
-    free(role_s);
36923b
 }
36923b
 
36923b
 static void
36923b
@@ -929,7 +926,7 @@ cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
 {
36923b
     resource_checks_t checks = { .rsc = rsc };
36923b
 
36923b
-    check_role(out, cib_conn, &checks;;
36923b
+    check_role(&checks;;
36923b
     check_managed(out, cib_conn, &checks;;
36923b
     check_locked(&checks;;
36923b
 
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 0fd133680f7b2c25a946cf3fb25f4ee9ffeeaf93 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 17:15:43 -0500
36923b
Subject: [PATCH 04/14] Fix: tools: crm_resource is-managed check should use
36923b
 meta-attribute table
36923b
36923b
Previously, check_managed() searched the CIB for the uber-parent's is-managed
36923b
attribute. That could give incorrect results if is-managed was set on a
36923b
different resource in the ancestry chain (e.g. the resource itself for a group
36923b
member, or the group for a cloned group), or if there were multiple is-managed
36923b
settings (e.g. using rules).
36923b
36923b
Now, is-managed is checked in rsc->meta, which should be fully evaluated for
36923b
inheritance and rules.
36923b
---
36923b
 tools/crm_resource_runtime.c | 17 +++++------------
36923b
 1 file changed, 5 insertions(+), 12 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index e9d05cb77..4f62b4b2e 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -895,21 +895,14 @@ check_role(resource_checks_t *checks)
36923b
 }
36923b
 
36923b
 static void
36923b
-check_managed(pcmk__output_t *out, cib_t *cib_conn, resource_checks_t *checks)
36923b
+check_managed(resource_checks_t *checks)
36923b
 {
36923b
-    char *managed_s = NULL;
36923b
-    pe_resource_t *parent = uber_parent(checks->rsc);
36923b
+    const char *managed_s = g_hash_table_lookup(checks->rsc->meta,
36923b
+                                                XML_RSC_ATTR_MANAGED);
36923b
 
36923b
-    find_resource_attr(out, cib_conn, XML_NVPAIR_ATTR_VALUE, parent->id,
36923b
-                       NULL, NULL, NULL, XML_RSC_ATTR_MANAGED, &managed_s);
36923b
-    if (managed_s == NULL) {
36923b
-        return;
36923b
-    }
36923b
-
36923b
-    if (!crm_is_true(managed_s)) {
36923b
+    if ((managed_s != NULL) && !crm_is_true(managed_s)) {
36923b
         checks->flags |= rsc_unmanaged;
36923b
     }
36923b
-    free(managed_s);
36923b
 }
36923b
 
36923b
 static void
36923b
@@ -927,7 +920,7 @@ cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
     resource_checks_t checks = { .rsc = rsc };
36923b
 
36923b
     check_role(&checks;;
36923b
-    check_managed(out, cib_conn, &checks;;
36923b
+    check_managed(&checks;;
36923b
     check_locked(&checks;;
36923b
 
36923b
     return out->message(out, "resource-check-list", &checks;;
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From e9523c1b238492c8cf8b453ba6710f13bf81cd28 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 17:18:44 -0500
36923b
Subject: [PATCH 05/14] Refactor: tools: drop unused argument from
36923b
 cli_resource_check()
36923b
36923b
---
36923b
 tools/crm_resource.c         |  4 ++--
36923b
 tools/crm_resource.h         |  2 +-
36923b
 tools/crm_resource_print.c   | 24 ++++++++++++------------
36923b
 tools/crm_resource_runtime.c |  2 +-
36923b
 4 files changed, 16 insertions(+), 16 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
36923b
index 883563df9..bf5326b40 100644
36923b
--- a/tools/crm_resource.c
36923b
+++ b/tools/crm_resource.c
36923b
@@ -1019,7 +1019,7 @@ cleanup(pcmk__output_t *out, pe_resource_t *rsc)
36923b
 
36923b
     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
36923b
         // Show any reasons why resource might stay stopped
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
     }
36923b
 
36923b
     if (rc == pcmk_rc_ok) {
36923b
@@ -1326,7 +1326,7 @@ refresh_resource(pcmk__output_t *out, pe_resource_t *rsc)
36923b
 
36923b
     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
36923b
         // Show any reasons why resource might stay stopped
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
     }
36923b
 
36923b
     if (rc == pcmk_rc_ok) {
36923b
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
36923b
index b5fdd1bb5..bcff2b5f6 100644
36923b
--- a/tools/crm_resource.h
36923b
+++ b/tools/crm_resource.h
36923b
@@ -68,7 +68,7 @@ int cli_resource_print_operations(const char *rsc_id, const char *host_uname,
36923b
                                   bool active, pe_working_set_t * data_set);
36923b
 
36923b
 /* runtime */
36923b
-int cli_resource_check(pcmk__output_t *out, cib_t * cib, pe_resource_t *rsc);
36923b
+int cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc);
36923b
 int cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname,
36923b
                       const char *rsc_id, pe_working_set_t *data_set);
36923b
 GList *cli_resource_search(pe_resource_t *rsc, const char *requested_name,
36923b
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
36923b
index f63fc952d..f025cbddd 100644
36923b
--- a/tools/crm_resource_print.c
36923b
+++ b/tools/crm_resource_print.c
36923b
@@ -587,7 +587,7 @@ PCMK__OUTPUT_ARGS("resource-reasons-list", "cib_t *", "GList *", "pe_resource_t
36923b
 static int
36923b
 resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
 {
36923b
-    cib_t *cib_conn = va_arg(args, cib_t *);
36923b
+    cib_t *cib_conn G_GNUC_UNUSED = va_arg(args, cib_t *);
36923b
     GList *resources = va_arg(args, GList *);
36923b
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
36923b
     pe_node_t *node = va_arg(args, pe_node_t *);
36923b
@@ -610,7 +610,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
                 out->list_item(out, "reason", "Resource %s is running", rsc->id);
36923b
             }
36923b
 
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
             g_list_free(hosts);
36923b
             hosts = NULL;
36923b
         }
36923b
@@ -624,7 +624,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
                            rsc->id, host_uname);
36923b
         }
36923b
 
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
 
36923b
     } else if ((rsc == NULL) && (host_uname != NULL)) {
36923b
         const char* host_uname =  node->details->uname;
36923b
@@ -637,14 +637,14 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
             pe_resource_t *rsc = (pe_resource_t *) lpc->data;
36923b
             out->list_item(out, "reason", "Resource %s is running on host %s",
36923b
                            rsc->id, host_uname);
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
         }
36923b
 
36923b
         for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
36923b
             pe_resource_t *rsc = (pe_resource_t *) lpc->data;
36923b
             out->list_item(out, "reason", "Resource %s is assigned to host %s but not running",
36923b
                            rsc->id, host_uname);
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
         }
36923b
 
36923b
         g_list_free(allResources);
36923b
@@ -657,7 +657,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
         rsc->fns->location(rsc, &hosts, TRUE);
36923b
         out->list_item(out, "reason", "Resource %s is %srunning",
36923b
                        rsc->id, (hosts? "" : "not "));
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
         g_list_free(hosts);
36923b
     }
36923b
 
36923b
@@ -670,7 +670,7 @@ PCMK__OUTPUT_ARGS("resource-reasons-list", "cib_t *", "GList *", "pe_resource_t
36923b
 static int
36923b
 resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
 {
36923b
-    cib_t *cib_conn = va_arg(args, cib_t *);
36923b
+    cib_t *cib_conn G_GNUC_UNUSED = va_arg(args, cib_t *);
36923b
     GList *resources = va_arg(args, GList *);
36923b
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
36923b
     pe_node_t *node = va_arg(args, pe_node_t *);
36923b
@@ -695,7 +695,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "running", pcmk__btoa(hosts != NULL),
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
             g_list_free(hosts);
36923b
             hosts = NULL;
36923b
@@ -708,7 +708,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
             crm_xml_add(xml_node, "running_on", host_uname);
36923b
         }
36923b
 
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
 
36923b
     } else if ((rsc == NULL) && (host_uname != NULL)) {
36923b
         const char* host_uname =  node->details->uname;
36923b
@@ -728,7 +728,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "host", host_uname,
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
         }
36923b
 
36923b
@@ -741,7 +741,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "host", host_uname,
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, cib_conn, rsc);
36923b
+            cli_resource_check(out, rsc);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
         }
36923b
 
36923b
@@ -755,7 +755,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
 
36923b
         rsc->fns->location(rsc, &hosts, TRUE);
36923b
         crm_xml_add(xml_node, "running", pcmk__btoa(hosts != NULL));
36923b
-        cli_resource_check(out, cib_conn, rsc);
36923b
+        cli_resource_check(out, rsc);
36923b
         g_list_free(hosts);
36923b
     }
36923b
 
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index 4f62b4b2e..47653a060 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -915,7 +915,7 @@ check_locked(resource_checks_t *checks)
36923b
 }
36923b
 
36923b
 int
36923b
-cli_resource_check(pcmk__output_t *out, cib_t * cib_conn, pe_resource_t *rsc)
36923b
+cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc)
36923b
 {
36923b
     resource_checks_t checks = { .rsc = rsc };
36923b
 
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From b1a1a07f3e44bc74575eab325277ea8c1f3391b2 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Tue, 5 Apr 2022 17:20:06 -0500
36923b
Subject: [PATCH 06/14] Refactor: tools: drop unused argument from
36923b
 resource-reasons-list message
36923b
36923b
---
36923b
 tools/crm_resource.c       | 2 +-
36923b
 tools/crm_resource_print.c | 6 ++----
36923b
 2 files changed, 3 insertions(+), 5 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
36923b
index bf5326b40..7f656a20d 100644
36923b
--- a/tools/crm_resource.c
36923b
+++ b/tools/crm_resource.c
36923b
@@ -1941,7 +1941,7 @@ main(int argc, char **argv)
36923b
             if ((options.host_uname != NULL) && (node == NULL)) {
36923b
                 rc = pcmk_rc_node_unknown;
36923b
             } else {
36923b
-                rc = out->message(out, "resource-reasons-list", cib_conn,
36923b
+                rc = out->message(out, "resource-reasons-list",
36923b
                                   data_set->resources, rsc, node);
36923b
             }
36923b
             break;
36923b
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
36923b
index f025cbddd..580f9c71a 100644
36923b
--- a/tools/crm_resource_print.c
36923b
+++ b/tools/crm_resource_print.c
36923b
@@ -582,12 +582,11 @@ resource_search_list_xml(pcmk__output_t *out, va_list args)
36923b
     return pcmk_rc_ok;
36923b
 }
36923b
 
36923b
-PCMK__OUTPUT_ARGS("resource-reasons-list", "cib_t *", "GList *", "pe_resource_t *",
36923b
+PCMK__OUTPUT_ARGS("resource-reasons-list", "GList *", "pe_resource_t *",
36923b
                   "pe_node_t *")
36923b
 static int
36923b
 resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
 {
36923b
-    cib_t *cib_conn G_GNUC_UNUSED = va_arg(args, cib_t *);
36923b
     GList *resources = va_arg(args, GList *);
36923b
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
36923b
     pe_node_t *node = va_arg(args, pe_node_t *);
36923b
@@ -665,12 +664,11 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
     return pcmk_rc_ok;
36923b
 }
36923b
 
36923b
-PCMK__OUTPUT_ARGS("resource-reasons-list", "cib_t *", "GList *", "pe_resource_t *",
36923b
+PCMK__OUTPUT_ARGS("resource-reasons-list", "GList *", "pe_resource_t *",
36923b
                   "pe_node_t *")
36923b
 static int
36923b
 resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
 {
36923b
-    cib_t *cib_conn G_GNUC_UNUSED = va_arg(args, cib_t *);
36923b
     GList *resources = va_arg(args, GList *);
36923b
     pe_resource_t *rsc = va_arg(args, pe_resource_t *);
36923b
     pe_node_t *node = va_arg(args, pe_node_t *);
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 973eb2694b334b4e9e6967f6c7ceaebec10693db Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 10:08:37 -0500
36923b
Subject: [PATCH 07/14] Refactor: tools: pass node to cli_resource_check()
36923b
36923b
The node is not used yet
36923b
---
36923b
 tools/crm_resource.c         | 12 ++++++------
36923b
 tools/crm_resource.h         |  3 ++-
36923b
 tools/crm_resource_print.c   | 20 ++++++++++----------
36923b
 tools/crm_resource_runtime.c |  2 +-
36923b
 4 files changed, 19 insertions(+), 18 deletions(-)
36923b
36923b
diff --git a/tools/crm_resource.c b/tools/crm_resource.c
36923b
index 7f656a20d..756a06268 100644
36923b
--- a/tools/crm_resource.c
36923b
+++ b/tools/crm_resource.c
36923b
@@ -1004,7 +1004,7 @@ ban_or_move(pcmk__output_t *out, pe_resource_t *rsc, const char *move_lifetime)
36923b
 }
36923b
 
36923b
 static void
36923b
-cleanup(pcmk__output_t *out, pe_resource_t *rsc)
36923b
+cleanup(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
36923b
 {
36923b
     int rc = pcmk_rc_ok;
36923b
 
36923b
@@ -1019,7 +1019,7 @@ cleanup(pcmk__output_t *out, pe_resource_t *rsc)
36923b
 
36923b
     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
36923b
         // Show any reasons why resource might stay stopped
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, node);
36923b
     }
36923b
 
36923b
     if (rc == pcmk_rc_ok) {
36923b
@@ -1311,7 +1311,7 @@ refresh(pcmk__output_t *out)
36923b
 }
36923b
 
36923b
 static void
36923b
-refresh_resource(pcmk__output_t *out, pe_resource_t *rsc)
36923b
+refresh_resource(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
36923b
 {
36923b
     int rc = pcmk_rc_ok;
36923b
 
36923b
@@ -1326,7 +1326,7 @@ refresh_resource(pcmk__output_t *out, pe_resource_t *rsc)
36923b
 
36923b
     if ((rc == pcmk_rc_ok) && !out->is_quiet(out)) {
36923b
         // Show any reasons why resource might stay stopped
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, node);
36923b
     }
36923b
 
36923b
     if (rc == pcmk_rc_ok) {
36923b
@@ -2075,7 +2075,7 @@ main(int argc, char **argv)
36923b
                     start_mainloop(controld_api);
36923b
                 }
36923b
             } else {
36923b
-                cleanup(out, rsc);
36923b
+                cleanup(out, rsc, node);
36923b
             }
36923b
             break;
36923b
 
36923b
@@ -2083,7 +2083,7 @@ main(int argc, char **argv)
36923b
             if (rsc == NULL) {
36923b
                 rc = refresh(out);
36923b
             } else {
36923b
-                refresh_resource(out, rsc);
36923b
+                refresh_resource(out, rsc, node);
36923b
             }
36923b
             break;
36923b
 
36923b
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
36923b
index bcff2b5f6..f7e44476d 100644
36923b
--- a/tools/crm_resource.h
36923b
+++ b/tools/crm_resource.h
36923b
@@ -68,7 +68,8 @@ int cli_resource_print_operations(const char *rsc_id, const char *host_uname,
36923b
                                   bool active, pe_working_set_t * data_set);
36923b
 
36923b
 /* runtime */
36923b
-int cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc);
36923b
+int cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc,
36923b
+                       pe_node_t *node);
36923b
 int cli_resource_fail(pcmk_ipc_api_t *controld_api, const char *host_uname,
36923b
                       const char *rsc_id, pe_working_set_t *data_set);
36923b
 GList *cli_resource_search(pe_resource_t *rsc, const char *requested_name,
36923b
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
36923b
index 580f9c71a..087819601 100644
36923b
--- a/tools/crm_resource_print.c
36923b
+++ b/tools/crm_resource_print.c
36923b
@@ -609,7 +609,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
                 out->list_item(out, "reason", "Resource %s is running", rsc->id);
36923b
             }
36923b
 
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, NULL);
36923b
             g_list_free(hosts);
36923b
             hosts = NULL;
36923b
         }
36923b
@@ -623,7 +623,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
                            rsc->id, host_uname);
36923b
         }
36923b
 
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, node);
36923b
 
36923b
     } else if ((rsc == NULL) && (host_uname != NULL)) {
36923b
         const char* host_uname =  node->details->uname;
36923b
@@ -636,14 +636,14 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
             pe_resource_t *rsc = (pe_resource_t *) lpc->data;
36923b
             out->list_item(out, "reason", "Resource %s is running on host %s",
36923b
                            rsc->id, host_uname);
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, node);
36923b
         }
36923b
 
36923b
         for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) {
36923b
             pe_resource_t *rsc = (pe_resource_t *) lpc->data;
36923b
             out->list_item(out, "reason", "Resource %s is assigned to host %s but not running",
36923b
                            rsc->id, host_uname);
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, node);
36923b
         }
36923b
 
36923b
         g_list_free(allResources);
36923b
@@ -656,7 +656,7 @@ resource_reasons_list_default(pcmk__output_t *out, va_list args)
36923b
         rsc->fns->location(rsc, &hosts, TRUE);
36923b
         out->list_item(out, "reason", "Resource %s is %srunning",
36923b
                        rsc->id, (hosts? "" : "not "));
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, NULL);
36923b
         g_list_free(hosts);
36923b
     }
36923b
 
36923b
@@ -693,7 +693,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "running", pcmk__btoa(hosts != NULL),
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, NULL);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
             g_list_free(hosts);
36923b
             hosts = NULL;
36923b
@@ -706,7 +706,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
             crm_xml_add(xml_node, "running_on", host_uname);
36923b
         }
36923b
 
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, node);
36923b
 
36923b
     } else if ((rsc == NULL) && (host_uname != NULL)) {
36923b
         const char* host_uname =  node->details->uname;
36923b
@@ -726,7 +726,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "host", host_uname,
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, node);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
         }
36923b
 
36923b
@@ -739,7 +739,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
                                            "host", host_uname,
36923b
                                            NULL);
36923b
 
36923b
-            cli_resource_check(out, rsc);
36923b
+            cli_resource_check(out, rsc, node);
36923b
             pcmk__output_xml_pop_parent(out);
36923b
         }
36923b
 
36923b
@@ -753,7 +753,7 @@ resource_reasons_list_xml(pcmk__output_t *out, va_list args)
36923b
 
36923b
         rsc->fns->location(rsc, &hosts, TRUE);
36923b
         crm_xml_add(xml_node, "running", pcmk__btoa(hosts != NULL));
36923b
-        cli_resource_check(out, rsc);
36923b
+        cli_resource_check(out, rsc, NULL);
36923b
         g_list_free(hosts);
36923b
     }
36923b
 
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index 47653a060..68e899c45 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -915,7 +915,7 @@ check_locked(resource_checks_t *checks)
36923b
 }
36923b
 
36923b
 int
36923b
-cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc)
36923b
+cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
36923b
 {
36923b
     resource_checks_t checks = { .rsc = rsc };
36923b
 
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From c3bfde0536f2eb51c81bf34fa957c38dc88f9cc3 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 09:49:03 -0500
36923b
Subject: [PATCH 08/14] Feature: tools: crm_resource --why now checks node
36923b
 health status
36923b
36923b
Closes T65
36923b
---
36923b
 tools/crm_resource.h         |  1 +
36923b
 tools/crm_resource_print.c   | 13 +++++++++
36923b
 tools/crm_resource_runtime.c | 56 ++++++++++++++++++++++++++++++++++++
36923b
 3 files changed, 70 insertions(+)
36923b
36923b
diff --git a/tools/crm_resource.h b/tools/crm_resource.h
36923b
index f7e44476d..ae4b02a98 100644
36923b
--- a/tools/crm_resource.h
36923b
+++ b/tools/crm_resource.h
36923b
@@ -37,6 +37,7 @@ enum resource_check_flags {
36923b
     rsc_unpromotable    = (1 << 1),
36923b
     rsc_unmanaged       = (1 << 2),
36923b
     rsc_locked          = (1 << 3),
36923b
+    rsc_node_health     = (1 << 4),
36923b
 };
36923b
 
36923b
 typedef struct resource_checks_s {
36923b
diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c
36923b
index 087819601..27fd76aaf 100644
36923b
--- a/tools/crm_resource_print.c
36923b
+++ b/tools/crm_resource_print.c
36923b
@@ -477,6 +477,15 @@ resource_check_list_default(pcmk__output_t *out, va_list args) {
36923b
                        parent->id, checks->lock_node);
36923b
     }
36923b
 
36923b
+    if (pcmk_is_set(checks->flags, rsc_node_health)) {
36923b
+        out->list_item(out, "check",
36923b
+                       "'%s' cannot run on unhealthy nodes due to "
36923b
+                       PCMK__OPT_NODE_HEALTH_STRATEGY "='%s'",
36923b
+                       parent->id,
36923b
+                       pe_pref(checks->rsc->cluster->config_hash,
36923b
+                               PCMK__OPT_NODE_HEALTH_STRATEGY));
36923b
+    }
36923b
+
36923b
     out->end_list(out);
36923b
     return pcmk_rc_ok;
36923b
 }
36923b
@@ -508,6 +517,10 @@ resource_check_list_xml(pcmk__output_t *out, va_list args) {
36923b
         crm_xml_add(node, "locked-to", checks->lock_node);
36923b
     }
36923b
 
36923b
+    if (pcmk_is_set(checks->flags, rsc_node_health)) {
36923b
+        pcmk__xe_set_bool_attr(node, "unhealthy", true);
36923b
+    }
36923b
+
36923b
     return pcmk_rc_ok;
36923b
 }
36923b
 
36923b
diff --git a/tools/crm_resource_runtime.c b/tools/crm_resource_runtime.c
36923b
index 68e899c45..2aa3efe38 100644
36923b
--- a/tools/crm_resource_runtime.c
36923b
+++ b/tools/crm_resource_runtime.c
36923b
@@ -914,6 +914,61 @@ check_locked(resource_checks_t *checks)
36923b
     }
36923b
 }
36923b
 
36923b
+static bool
36923b
+node_is_unhealthy(pe_node_t *node)
36923b
+{
36923b
+    switch (pe__health_strategy(node->details->data_set)) {
36923b
+        case pcmk__health_strategy_none:
36923b
+            break;
36923b
+
36923b
+        case pcmk__health_strategy_no_red:
36923b
+            if (pe__node_health(node) < 0) {
36923b
+                return true;
36923b
+            }
36923b
+            break;
36923b
+
36923b
+        case pcmk__health_strategy_only_green:
36923b
+            if (pe__node_health(node) <= 0) {
36923b
+                return true;
36923b
+            }
36923b
+            break;
36923b
+
36923b
+        case pcmk__health_strategy_progressive:
36923b
+        case pcmk__health_strategy_custom:
36923b
+            /* @TODO These are finite scores, possibly with rules, and possibly
36923b
+             * combining with other scores, so attributing these as a cause is
36923b
+             * nontrivial.
36923b
+             */
36923b
+            break;
36923b
+    }
36923b
+    return false;
36923b
+}
36923b
+
36923b
+static void
36923b
+check_node_health(resource_checks_t *checks, pe_node_t *node)
36923b
+{
36923b
+    if (node == NULL) {
36923b
+        GHashTableIter iter;
36923b
+        bool allowed = false;
36923b
+        bool all_nodes_unhealthy = true;
36923b
+
36923b
+        g_hash_table_iter_init(&iter, checks->rsc->allowed_nodes);
36923b
+        while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
36923b
+            allowed = true;
36923b
+            if (!node_is_unhealthy(node)) {
36923b
+                all_nodes_unhealthy = false;
36923b
+                break;
36923b
+            }
36923b
+        }
36923b
+        if (allowed && all_nodes_unhealthy) {
36923b
+            checks->flags |= rsc_node_health;
36923b
+        }
36923b
+
36923b
+    } else if (node_is_unhealthy(node)) {
36923b
+        checks->flags |= rsc_node_health;
36923b
+    }
36923b
+}
36923b
+
36923b
 int
36923b
 cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
36923b
 {
36923b
@@ -922,6 +977,7 @@ cli_resource_check(pcmk__output_t *out, pe_resource_t *rsc, pe_node_t *node)
36923b
     check_role(&checks;;
36923b
     check_managed(&checks;;
36923b
     check_locked(&checks;;
36923b
+    check_node_health(&checks, node);
36923b
 
36923b
     return out->message(out, "resource-check-list", &checks;;
36923b
 }
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 48730fd51a22e109514764a039e5c89fd204ad4c Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 10:41:48 -0500
36923b
Subject: [PATCH 09/14] Low: schemas: copy crm_resource API schema in
36923b
 preparation for changes
36923b
36923b
---
36923b
 include/crm/common/output_internal.h |   2 +-
36923b
 xml/api/crm_resource-2.22.rng        | 303 +++++++++++++++++++++++++++
36923b
 2 files changed, 304 insertions(+), 1 deletion(-)
36923b
 create mode 100644 xml/api/crm_resource-2.22.rng
36923b
36923b
diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h
36923b
index ca16227fe..bdcae8ad6 100644
36923b
--- a/include/crm/common/output_internal.h
36923b
+++ b/include/crm/common/output_internal.h
36923b
@@ -28,7 +28,7 @@ extern "C" {
36923b
  */
36923b
 
36923b
 
36923b
-#  define PCMK__API_VERSION "2.21"
36923b
+#  define PCMK__API_VERSION "2.22"
36923b
 
36923b
 #if defined(PCMK__WITH_ATTRIBUTE_OUTPUT_ARGS)
36923b
 #  define PCMK__OUTPUT_ARGS(ARGS...) __attribute__((output_args(ARGS)))
36923b
diff --git a/xml/api/crm_resource-2.22.rng b/xml/api/crm_resource-2.22.rng
36923b
new file mode 100644
36923b
index 000000000..cd74da0d8
36923b
--- /dev/null
36923b
+++ b/xml/api/crm_resource-2.22.rng
36923b
@@ -0,0 +1,303 @@
36923b
+
36923b
+
36923b
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
36923b
+
36923b
+    <start>
36923b
+        <ref name="element-crm-resource"/>
36923b
+    </start>
36923b
+
36923b
+    <define name="element-crm-resource">
36923b
+        <choice>
36923b
+            <ref name="agents-list" />
36923b
+            <ref name="alternatives-list" />
36923b
+            <ref name="constraints-list" />
36923b
+            <externalRef href="generic-list-2.4.rng"/>
36923b
+            <element name="metadata"> <text/> </element>
36923b
+            <ref name="locate-list" />
36923b
+            <ref name="operations-list" />
36923b
+            <ref name="providers-list" />
36923b
+            <ref name="reasons-list" />
36923b
+            <ref name="resource-check" />
36923b
+            <ref name="resource-config" />
36923b
+            <ref name="resources-list" />
36923b
+            <ref name="resource-agent-action" />
36923b
+        </choice>
36923b
+    </define>
36923b
+
36923b
+    <define name="agents-list">
36923b
+        <element name="agents">
36923b
+            <attribute name="standard"> <text/> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="provider"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <zeroOrMore>
36923b
+                <element name="agent"> <text/> </element>
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="alternatives-list">
36923b
+        <element name="providers">
36923b
+            <attribute name="for"> <text/> </attribute>
36923b
+            <zeroOrMore>
36923b
+                <element name="provider"> <text/> </element>
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="constraints-list">
36923b
+        <element name="constraints">
36923b
+            <interleave>
36923b
+                <zeroOrMore>
36923b
+                    <ref name="rsc-location" />
36923b
+                </zeroOrMore>
36923b
+                <zeroOrMore>
36923b
+                    <ref name="rsc-colocation" />
36923b
+                </zeroOrMore>
36923b
+            </interleave>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="locate-list">
36923b
+        <element name="nodes">
36923b
+            <attribute name="resource"> <text/> </attribute>
36923b
+            <zeroOrMore>
36923b
+                <element name="node">
36923b
+                    <optional>
36923b
+                        <attribute name="state"><value>promoted</value></attribute>
36923b
+                    </optional>
36923b
+                    <text/>
36923b
+                </element>
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="rsc-location">
36923b
+        <element name="rsc_location">
36923b
+            <attribute name="node"> <text/> </attribute>
36923b
+            <attribute name="rsc"> <text/> </attribute>
36923b
+            <attribute name="id"> <text/> </attribute>
36923b
+            <externalRef href="../score.rng"/>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="operations-list">
36923b
+        <element name="operations">
36923b
+            <oneOrMore>
36923b
+                <ref name="element-operation-list" />
36923b
+            </oneOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="providers-list">
36923b
+        <element name="providers">
36923b
+            <attribute name="standard"> <value>ocf</value> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="agent"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <zeroOrMore>
36923b
+                <element name="provider"> <text/> </element>
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="reasons-list">
36923b
+        <choice>
36923b
+            <ref name="no-resource-or-uname"/>
36923b
+            <ref name="resource-and-uname"/>
36923b
+            <ref name="no-resource-but-uname"/>
36923b
+            <ref name="resource-but-no-uname"/>
36923b
+        </choice>
36923b
+    </define>
36923b
+
36923b
+    <define name="no-resource-or-uname">
36923b
+        <element name="reason">
36923b
+            <element name="resources">
36923b
+                <zeroOrMore>
36923b
+                    <element name="resource">
36923b
+                        <attribute name="id"> <text/> </attribute>
36923b
+                        <attribute name="running"> <data type="boolean"/> </attribute>
36923b
+                        <ref name="resource-check"/>
36923b
+                    </element>
36923b
+                </zeroOrMore>
36923b
+            </element>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resource-and-uname">
36923b
+        <element name="reason">
36923b
+            <attribute name="running_on"> <text/> </attribute>
36923b
+            <ref name="resource-check"/>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="no-resource-but-uname">
36923b
+        <element name="reason">
36923b
+            <element name="resources">
36923b
+                <zeroOrMore>
36923b
+                    <element name="resource">
36923b
+                        <attribute name="id"> <text/> </attribute>
36923b
+                        <attribute name="running"> <data type="boolean"/> </attribute>
36923b
+                        <attribute name="host"> <text/> </attribute>
36923b
+                        <ref name="resource-check"/>
36923b
+                    </element>
36923b
+                </zeroOrMore>
36923b
+            </element>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resource-but-no-uname">
36923b
+        <element name="reason">
36923b
+            <attribute name="running"> <data type="boolean"/> </attribute>
36923b
+            <ref name="resource-check"/>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resource-config">
36923b
+        <element name="resource_config">
36923b
+            <externalRef href="resources-2.4.rng" />
36923b
+            <element name="xml"> <text/> </element>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resource-check">
36923b
+        <element name="check">
36923b
+            <attribute name="id"> <text/> </attribute>
36923b
+            <optional>
36923b
+                <choice>
36923b
+                    <attribute name="remain_stopped"><value>true</value></attribute>
36923b
+                    <attribute name="promotable"><value>false</value></attribute>
36923b
+                </choice>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="unmanaged"><value>true</value></attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="locked-to"> <text/> </attribute>
36923b
+            </optional>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resources-list">
36923b
+        <element name="resources">
36923b
+            <zeroOrMore>
36923b
+                <externalRef href="resources-2.4.rng" />
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="rsc-colocation">
36923b
+        <element name="rsc_colocation">
36923b
+            <attribute name="id"> <text/> </attribute>
36923b
+            <attribute name="rsc"> <text/> </attribute>
36923b
+            <attribute name="with-rsc"> <text/> </attribute>
36923b
+            <externalRef href="../score.rng"/>
36923b
+            <optional>
36923b
+                <attribute name="node-attribute"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="rsc-role">
36923b
+                    <ref name="attribute-roles"/>
36923b
+                </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="with-rsc-role">
36923b
+                    <ref name="attribute-roles"/>
36923b
+                </attribute>
36923b
+            </optional>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="element-operation-list">
36923b
+        <element name="operation">
36923b
+            <optional>
36923b
+                <group>
36923b
+                    <attribute name="rsc"> <text/> </attribute>
36923b
+                    <attribute name="agent"> <text/> </attribute>
36923b
+                </group>
36923b
+            </optional>
36923b
+            <attribute name="op"> <text/> </attribute>
36923b
+            <attribute name="node"> <text/> </attribute>
36923b
+            <attribute name="call"> <data type="integer" /> </attribute>
36923b
+            <attribute name="rc"> <data type="nonNegativeInteger" /> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="last-rc-change"> <text/> </attribute>
36923b
+                <attribute name="exec-time"> <data type="nonNegativeInteger" /> </attribute>
36923b
+            </optional>
36923b
+            <attribute name="status"> <text/> </attribute>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="resource-agent-action">
36923b
+        <element name="resource-agent-action">
36923b
+            <attribute name="action"> <text/> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="rsc"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <attribute name="class"> <text/> </attribute>
36923b
+            <attribute name="type"> <text/> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="provider"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <ref name="overrides-list"/>
36923b
+            </optional>
36923b
+            <ref name="agent-status"/>
36923b
+            <optional>
36923b
+                <choice>
36923b
+                    <element name="command">
36923b
+                        <text />
36923b
+                    </element>
36923b
+                    <externalRef href="command-output-1.0.rng"/>
36923b
+                </choice>
36923b
+            </optional>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="overrides-list">
36923b
+        <element name="overrides">
36923b
+            <zeroOrMore>
36923b
+                <element name="override">
36923b
+                    <optional>
36923b
+                        <attribute name="rsc"> <text/> </attribute>
36923b
+                    </optional>
36923b
+                    <attribute name="name"> <text/> </attribute>
36923b
+                    <attribute name="value"> <text/> </attribute>
36923b
+                </element>
36923b
+            </zeroOrMore>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="agent-status">
36923b
+        <element name="agent-status">
36923b
+            <attribute name="code"> <data type="integer" /> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="message"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="execution_code"> <data type="integer" /> </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="execution_message"> <text/> </attribute>
36923b
+            </optional>
36923b
+            <optional>
36923b
+                <attribute name="reason"> <text/> </attribute>
36923b
+            </optional>
36923b
+        </element>
36923b
+    </define>
36923b
+
36923b
+    <define name="attribute-roles">
36923b
+        <choice>
36923b
+            <value>Stopped</value>
36923b
+            <value>Started</value>
36923b
+            <value>Promoted</value>
36923b
+            <value>Unpromoted</value>
36923b
+
36923b
+            
36923b
+                 backward compatibility with output from older Pacemaker
36923b
+                 versions that used them -->
36923b
+            <value>Master</value>
36923b
+            <value>Slave</value>
36923b
+        </choice>
36923b
+    </define>
36923b
+</grammar>
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 75a885d9da92c84038e3abf732c11cf3fb6a79a7 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 11:33:50 -0500
36923b
Subject: [PATCH 10/14] Fix: tools: correct crm_resource --why schema to match
36923b
 actual output
36923b
36923b
If both a resource and node name are specified, "running_on" is optional
36923b
---
36923b
 xml/api/crm_resource-2.22.rng | 4 +++-
36923b
 1 file changed, 3 insertions(+), 1 deletion(-)
36923b
36923b
diff --git a/xml/api/crm_resource-2.22.rng b/xml/api/crm_resource-2.22.rng
36923b
index cd74da0d8..e89d850da 100644
36923b
--- a/xml/api/crm_resource-2.22.rng
36923b
+++ b/xml/api/crm_resource-2.22.rng
36923b
@@ -126,7 +126,9 @@
36923b
 
36923b
     <define name="resource-and-uname">
36923b
         <element name="reason">
36923b
-            <attribute name="running_on"> <text/> </attribute>
36923b
+            <optional>
36923b
+                <attribute name="running_on"> <text/> </attribute>
36923b
+            </optional>
36923b
             <ref name="resource-check"/>
36923b
         </element>
36923b
     </define>
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 5e4f993859dd68a3f88cb0648ace7b3837316288 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 11:20:03 -0500
36923b
Subject: [PATCH 11/14] Low: schemas: simplify crm_resource --why schema
36923b
36923b
---
36923b
 xml/api/crm_resource-2.22.rng | 64 ++++++++++++-----------------------
36923b
 1 file changed, 22 insertions(+), 42 deletions(-)
36923b
36923b
diff --git a/xml/api/crm_resource-2.22.rng b/xml/api/crm_resource-2.22.rng
36923b
index e89d850da..2d2ba839f 100644
36923b
--- a/xml/api/crm_resource-2.22.rng
36923b
+++ b/xml/api/crm_resource-2.22.rng
36923b
@@ -102,56 +102,36 @@
36923b
     </define>
36923b
 
36923b
     <define name="reasons-list">
36923b
-        <choice>
36923b
-            <ref name="no-resource-or-uname"/>
36923b
-            <ref name="resource-and-uname"/>
36923b
-            <ref name="no-resource-but-uname"/>
36923b
-            <ref name="resource-but-no-uname"/>
36923b
-        </choice>
36923b
-    </define>
36923b
-
36923b
-    <define name="no-resource-or-uname">
36923b
-        <element name="reason">
36923b
-            <element name="resources">
36923b
-                <zeroOrMore>
36923b
-                    <element name="resource">
36923b
-                        <attribute name="id"> <text/> </attribute>
36923b
-                        <attribute name="running"> <data type="boolean"/> </attribute>
36923b
-                        <ref name="resource-check"/>
36923b
-                    </element>
36923b
-                </zeroOrMore>
36923b
-            </element>
36923b
-        </element>
36923b
-    </define>
36923b
-
36923b
-    <define name="resource-and-uname">
36923b
         <element name="reason">
36923b
+            
36923b
             <optional>
36923b
                 <attribute name="running_on"> <text/> </attribute>
36923b
             </optional>
36923b
-            <ref name="resource-check"/>
36923b
-        </element>
36923b
-    </define>
36923b
 
36923b
-    <define name="no-resource-but-uname">
36923b
-        <element name="reason">
36923b
-            <element name="resources">
36923b
-                <zeroOrMore>
36923b
-                    <element name="resource">
36923b
-                        <attribute name="id"> <text/> </attribute>
36923b
-                        <attribute name="running"> <data type="boolean"/> </attribute>
36923b
-                        <attribute name="host"> <text/> </attribute>
36923b
-                        <ref name="resource-check"/>
36923b
-                    </element>
36923b
-                </zeroOrMore>
36923b
-            </element>
36923b
+            
36923b
+            <optional>
36923b
+                <attribute name="running"> <data type="boolean"/> </attribute>
36923b
+            </optional>
36923b
+
36923b
+            <choice>
36923b
+                <ref name="reasons-with-no-resource"/>
36923b
+                <ref name="resource-check"/>
36923b
+            </choice>
36923b
         </element>
36923b
     </define>
36923b
 
36923b
-    <define name="resource-but-no-uname">
36923b
-        <element name="reason">
36923b
-            <attribute name="running"> <data type="boolean"/> </attribute>
36923b
-            <ref name="resource-check"/>
36923b
+    <define name="reasons-with-no-resource">
36923b
+        <element name="resources">
36923b
+            <zeroOrMore>
36923b
+                <element name="resource">
36923b
+                    <attribute name="id"> <text/> </attribute>
36923b
+                    <attribute name="running"> <data type="boolean"/> </attribute>
36923b
+                    <optional>
36923b
+                        <attribute name="host"> <text/> </attribute>
36923b
+                    </optional>
36923b
+                    <ref name="resource-check"/>
36923b
+                </element>
36923b
+            </zeroOrMore>
36923b
         </element>
36923b
     </define>
36923b
 
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 79bdbbde27ad340c2054089aaecf5e0b49296e59 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 11:28:11 -0500
36923b
Subject: [PATCH 12/14] Test: cts-cli: use validated XML output for
36923b
 crm_resource --why test
36923b
36923b
---
36923b
 cts/cli/regression.tools.exp | 8 ++++++--
36923b
 cts/cts-cli.in               | 4 ++--
36923b
 2 files changed, 8 insertions(+), 4 deletions(-)
36923b
36923b
diff --git a/cts/cli/regression.tools.exp b/cts/cli/regression.tools.exp
36923b
index 0d1cfa2ab..4237a3ec5 100644
36923b
--- a/cts/cli/regression.tools.exp
36923b
+++ b/cts/cli/regression.tools.exp
36923b
@@ -888,8 +888,12 @@ Deleted 'dummy' option: id=dummy-meta_attributes-is-managed name=is-managed
36923b
 =#=#=#= End test: Create another resource meta attribute - OK (0) =#=#=#=
36923b
 * Passed: crm_resource   - Create another resource meta attribute
36923b
 =#=#=#= Begin test: Show why a resource is not running =#=#=#=
36923b
-Resource dummy is not running
36923b
-Configuration specifies 'dummy' should remain stopped
36923b
+<pacemaker-result api-version="X" request="crm_resource -Y -r dummy --output-as=xml">
36923b
+  <reason running="false">
36923b
+    <check id="dummy" remain_stopped="true"/>
36923b
+  </reason>
36923b
+  <status code="0" message="OK"/>
36923b
+</pacemaker-result>
36923b
 =#=#=#= End test: Show why a resource is not running - OK (0) =#=#=#=
36923b
 * Passed: crm_resource   - Show why a resource is not running
36923b
 =#=#=#= Begin test: Remove another resource meta attribute =#=#=#=
36923b
diff --git a/cts/cts-cli.in b/cts/cts-cli.in
36923b
index 8565c485a..289ac966f 100755
36923b
--- a/cts/cts-cli.in
36923b
+++ b/cts/cts-cli.in
36923b
@@ -657,8 +657,8 @@ function test_tools() {
36923b
     test_assert_validate $CRM_EX_OK 0
36923b
 
36923b
     desc="Show why a resource is not running"
36923b
-    cmd="crm_resource -Y -r dummy"
36923b
-    test_assert $CRM_EX_OK 0
36923b
+    cmd="crm_resource -Y -r dummy --output-as=xml"
36923b
+    test_assert_validate $CRM_EX_OK 0
36923b
 
36923b
     desc="Remove another resource meta attribute"
36923b
     cmd="crm_resource -r dummy --meta -d target-role --output-as=xml"
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 929d1b40e82f186e7e31e380db2620e7e23968f1 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 10:43:22 -0500
36923b
Subject: [PATCH 13/14] Low: schemas: update crm_resource --why schema for new
36923b
 health check
36923b
36923b
---
36923b
 xml/api/crm_resource-2.22.rng | 3 +++
36923b
 1 file changed, 3 insertions(+)
36923b
36923b
diff --git a/xml/api/crm_resource-2.22.rng b/xml/api/crm_resource-2.22.rng
36923b
index 2d2ba839f..8a4667559 100644
36923b
--- a/xml/api/crm_resource-2.22.rng
36923b
+++ b/xml/api/crm_resource-2.22.rng
36923b
@@ -157,6 +157,9 @@
36923b
             <optional>
36923b
                 <attribute name="locked-to"> <text/> </attribute>
36923b
             </optional>
36923b
+            <optional>
36923b
+                <attribute name="unhealthy"><value>true</value></attribute>
36923b
+            </optional>
36923b
         </element>
36923b
     </define>
36923b
 
36923b
-- 
36923b
2.31.1
36923b
36923b
36923b
From 6630e55abc7b26be294ab6d42f12cdb7e2c69b55 Mon Sep 17 00:00:00 2001
36923b
From: Ken Gaillot <kgaillot@redhat.com>
36923b
Date: Thu, 23 Jun 2022 11:07:20 -0500
36923b
Subject: [PATCH 14/14] Test: cts-cli: add tests for checking resource status
36923b
 on unhealthy node
36923b
36923b
---
36923b
 cts/cli/regression.tools.exp | 112 ++++++++++++++++++++++++++++++++++-
36923b
 cts/cts-cli.in               |  12 ++++
36923b
 2 files changed, 122 insertions(+), 2 deletions(-)
36923b
36923b
diff --git a/cts/cli/regression.tools.exp b/cts/cli/regression.tools.exp
36923b
index 4237a3ec5..89ae4e97d 100644
36923b
--- a/cts/cli/regression.tools.exp
36923b
+++ b/cts/cli/regression.tools.exp
36923b
@@ -3406,13 +3406,14 @@ Removing constraint: cli-prefer-dummy
36923b
 </cib>
36923b
 =#=#=#= End test: Clear all implicit constraints for dummy - OK (0) =#=#=#=
36923b
 * Passed: crm_resource   - Clear all implicit constraints for dummy
36923b
-=#=#=#= Begin test: Delete a resource =#=#=#=
36923b
-=#=#=#= Current cib after: Delete a resource =#=#=#=
36923b
+=#=#=#= Begin test: Set a node health strategy =#=#=#=
36923b
+=#=#=#= Current cib after: Set a node health strategy =#=#=#=
36923b
 <cib epoch="55" num_updates="0" admin_epoch="0">
36923b
   <configuration>
36923b
     <crm_config>
36923b
       <cluster_property_set id="cib-bootstrap-options">
36923b
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
36923b
+        <nvpair id="cib-bootstrap-options-node-health-strategy" name="node-health-strategy" value="migrate-on-red"/>
36923b
       </cluster_property_set>
36923b
       <cluster_property_set id="duplicate">
36923b
         <nvpair id="duplicate-cluster-delay" name="cluster-delay" value="30s"/>
36923b
@@ -3427,6 +3428,113 @@ Removing constraint: cli-prefer-dummy
36923b
       <node id="node2" uname="node2"/>
36923b
       <node id="node3" uname="node3"/>
36923b
     </nodes>
36923b
+    <resources>
36923b
+      <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
36923b
+        <meta_attributes id="dummy-meta_attributes"/>
36923b
+        <instance_attributes id="dummy-instance_attributes">
36923b
+          <nvpair id="dummy-instance_attributes-delay" name="delay" value="10s"/>
36923b
+        </instance_attributes>
36923b
+      </primitive>
36923b
+      <primitive id="Fence" class="stonith" type="fence_true"/>
36923b
+      <clone id="test-clone">
36923b
+        <primitive id="test-primitive" class="ocf" provider="pacemaker" type="Dummy">
36923b
+          <meta_attributes id="test-primitive-meta_attributes"/>
36923b
+        </primitive>
36923b
+        <meta_attributes id="test-clone-meta_attributes">
36923b
+          <nvpair id="test-clone-meta_attributes-is-managed" name="is-managed" value="true"/>
36923b
+        </meta_attributes>
36923b
+      </clone>
36923b
+    </resources>
36923b
+    <constraints/>
36923b
+  </configuration>
36923b
+  <status/>
36923b
+</cib>
36923b
+=#=#=#= End test: Set a node health strategy - OK (0) =#=#=#=
36923b
+* Passed: crm_attribute  - Set a node health strategy
36923b
+=#=#=#= Begin test: Set a node health attribute =#=#=#=
36923b
+=#=#=#= Current cib after: Set a node health attribute =#=#=#=
36923b
+<cib epoch="56" num_updates="0" admin_epoch="0">
36923b
+  <configuration>
36923b
+    <crm_config>
36923b
+      <cluster_property_set id="cib-bootstrap-options">
36923b
+        <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
36923b
+        <nvpair id="cib-bootstrap-options-node-health-strategy" name="node-health-strategy" value="migrate-on-red"/>
36923b
+      </cluster_property_set>
36923b
+      <cluster_property_set id="duplicate">
36923b
+        <nvpair id="duplicate-cluster-delay" name="cluster-delay" value="30s"/>
36923b
+      </cluster_property_set>
36923b
+    </crm_config>
36923b
+    <nodes>
36923b
+      <node id="node1" uname="node1">
36923b
+        <instance_attributes id="nodes-node1">
36923b
+          <nvpair id="nodes-node1-ram" name="ram" value="1024M"/>
36923b
+        </instance_attributes>
36923b
+      </node>
36923b
+      <node id="node2" uname="node2"/>
36923b
+      <node id="node3" uname="node3">
36923b
+        <instance_attributes id="nodes-node3">
36923b
+          <nvpair id="nodes-node3-.health-cts-cli" name="#health-cts-cli" value="red"/>
36923b
+        </instance_attributes>
36923b
+      </node>
36923b
+    </nodes>
36923b
+    <resources>
36923b
+      <primitive id="dummy" class="ocf" provider="pacemaker" type="Dummy">
36923b
+        <meta_attributes id="dummy-meta_attributes"/>
36923b
+        <instance_attributes id="dummy-instance_attributes">
36923b
+          <nvpair id="dummy-instance_attributes-delay" name="delay" value="10s"/>
36923b
+        </instance_attributes>
36923b
+      </primitive>
36923b
+      <primitive id="Fence" class="stonith" type="fence_true"/>
36923b
+      <clone id="test-clone">
36923b
+        <primitive id="test-primitive" class="ocf" provider="pacemaker" type="Dummy">
36923b
+          <meta_attributes id="test-primitive-meta_attributes"/>
36923b
+        </primitive>
36923b
+        <meta_attributes id="test-clone-meta_attributes">
36923b
+          <nvpair id="test-clone-meta_attributes-is-managed" name="is-managed" value="true"/>
36923b
+        </meta_attributes>
36923b
+      </clone>
36923b
+    </resources>
36923b
+    <constraints/>
36923b
+  </configuration>
36923b
+  <status/>
36923b
+</cib>
36923b
+=#=#=#= End test: Set a node health attribute - OK (0) =#=#=#=
36923b
+* Passed: crm_attribute  - Set a node health attribute
36923b
+=#=#=#= Begin test: Show why a resource is not running on an unhealthy node =#=#=#=
36923b
+<pacemaker-result api-version="X" request="crm_resource -N node3 -Y -r dummy --output-as=xml">
36923b
+  <reason>
36923b
+    <check id="dummy" unhealthy="true"/>
36923b
+  </reason>
36923b
+  <status code="0" message="OK"/>
36923b
+</pacemaker-result>
36923b
+=#=#=#= End test: Show why a resource is not running on an unhealthy node - OK (0) =#=#=#=
36923b
+* Passed: crm_resource   - Show why a resource is not running on an unhealthy node
36923b
+=#=#=#= Begin test: Delete a resource =#=#=#=
36923b
+=#=#=#= Current cib after: Delete a resource =#=#=#=
36923b
+<cib epoch="57" num_updates="0" admin_epoch="0">
36923b
+  <configuration>
36923b
+    <crm_config>
36923b
+      <cluster_property_set id="cib-bootstrap-options">
36923b
+        <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
36923b
+        <nvpair id="cib-bootstrap-options-node-health-strategy" name="node-health-strategy" value="migrate-on-red"/>
36923b
+      </cluster_property_set>
36923b
+      <cluster_property_set id="duplicate">
36923b
+        <nvpair id="duplicate-cluster-delay" name="cluster-delay" value="30s"/>
36923b
+      </cluster_property_set>
36923b
+    </crm_config>
36923b
+    <nodes>
36923b
+      <node id="node1" uname="node1">
36923b
+        <instance_attributes id="nodes-node1">
36923b
+          <nvpair id="nodes-node1-ram" name="ram" value="1024M"/>
36923b
+        </instance_attributes>
36923b
+      </node>
36923b
+      <node id="node2" uname="node2"/>
36923b
+      <node id="node3" uname="node3">
36923b
+        <instance_attributes id="nodes-node3">
36923b
+          <nvpair id="nodes-node3-.health-cts-cli" name="#health-cts-cli" value="red"/>
36923b
+        </instance_attributes>
36923b
+      </node>
36923b
+    </nodes>
36923b
     <resources>
36923b
       <primitive id="Fence" class="stonith" type="fence_true"/>
36923b
       <clone id="test-clone">
36923b
diff --git a/cts/cts-cli.in b/cts/cts-cli.in
36923b
index 289ac966f..990d37cf7 100755
36923b
--- a/cts/cts-cli.in
36923b
+++ b/cts/cts-cli.in
36923b
@@ -883,6 +883,18 @@ function test_tools() {
36923b
     cmd="crm_resource -r dummy -U"
36923b
     test_assert $CRM_EX_OK
36923b
 
36923b
+    desc="Set a node health strategy"
36923b
+    cmd="crm_attribute -n node-health-strategy -v migrate-on-red"
36923b
+    test_assert $CRM_EX_OK
36923b
+
36923b
+    desc="Set a node health attribute"
36923b
+    cmd="crm_attribute -N node3 -n '#health-cts-cli' -v red"
36923b
+    test_assert $CRM_EX_OK
36923b
+
36923b
+    desc="Show why a resource is not running on an unhealthy node"
36923b
+    cmd="crm_resource -N node3 -Y -r dummy --output-as=xml"
36923b
+    test_assert_validate $CRM_EX_OK 0
36923b
+
36923b
     desc="Delete a resource"
36923b
     cmd="crm_resource -D -r dummy -t primitive"
36923b
     test_assert $CRM_EX_OK
36923b
-- 
36923b
2.31.1
36923b