Blob Blame History Raw
From 756a3e522aa444b456e21128a52317226b346005 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Tue, 21 May 2019 15:26:20 -0500
Subject: [PATCH 01/11] Doc: libpacemaker: correct doxygen block for shutdown
 op creator

copy/paste error
---
 lib/pacemaker/pcmk_sched_utils.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/lib/pacemaker/pcmk_sched_utils.c b/lib/pacemaker/pcmk_sched_utils.c
index 5342e51..7b5cb7d 100644
--- a/lib/pacemaker/pcmk_sched_utils.c
+++ b/lib/pacemaker/pcmk_sched_utils.c
@@ -446,10 +446,7 @@ pe_cancel_op(pe_resource_t *rsc, const char *task, guint interval_ms,
  * \internal
  * \brief Create a shutdown op for a scheduler transition
  *
- * \param[in] rsc          Resource of action to cancel
- * \param[in] task         Name of action to cancel
- * \param[in] interval_ms  Interval of action to cancel
- * \param[in] node         Node of action to cancel
+ * \param[in] node         Node being shut down
  * \param[in] data_set     Working set of cluster
  *
  * \return Created op
-- 
1.8.3.1


From 5249dd9295307c0e22e223ea7d6f5f24a0a3fe25 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Fri, 24 May 2019 10:17:15 -0500
Subject: [PATCH 02/11] Refactor: libpe_status: rename target rc function

... in line with current naming standards, to avoid confusion with
controller function of the same name
---
 include/crm/pengine/internal.h | 2 +-
 lib/pengine/failcounts.c       | 4 ++--
 lib/pengine/unpack.c           | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h
index 6d22db7..fd55bb9 100644
--- a/include/crm/pengine/internal.h
+++ b/include/crm/pengine/internal.h
@@ -288,7 +288,7 @@ pe_base_name_eq(resource_t *rsc, const char *id)
     return FALSE;
 }
 
-int get_target_rc(xmlNode * xml_op);
+int pe__target_rc_from_xml(xmlNode *xml_op);
 
 gint sort_node_uname(gconstpointer a, gconstpointer b);
 bool is_set_recursive(resource_t * rsc, long long flag, bool any);
diff --git a/lib/pengine/failcounts.c b/lib/pengine/failcounts.c
index 8f01c07..0c8ca5d 100644
--- a/lib/pengine/failcounts.c
+++ b/lib/pengine/failcounts.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2018 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2008-2019 the Pacemaker project contributors
  *
  * This source code is licensed under the GNU Lesser General Public License
  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
@@ -62,7 +62,7 @@ is_matched_failure(const char *rsc_id, xmlNode *conf_op_xml,
 
         if (safe_str_eq(expected_op_key, lrm_op_id)) {
             int rc = 0;
-            int target_rc = get_target_rc(lrm_op_xml);
+            int target_rc = pe__target_rc_from_xml(lrm_op_xml);
 
             crm_element_value_int(lrm_op_xml, XML_LRM_ATTR_RC, &rc);
             if (rc != target_rc) {
diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
index 02cef2c..0e8177b 100644
--- a/lib/pengine/unpack.c
+++ b/lib/pengine/unpack.c
@@ -3013,7 +3013,7 @@ static bool check_operation_expiry(resource_t *rsc, node_t *node, int rc, xmlNod
     return expired;
 }
 
-int get_target_rc(xmlNode *xml_op)
+int pe__target_rc_from_xml(xmlNode *xml_op)
 {
     int target_rc = 0;
     const char *key = crm_element_value(xml_op, XML_ATTR_TRANSITION_KEY);
@@ -3141,7 +3141,7 @@ unpack_rsc_op(resource_t * rsc, node_t * node, xmlNode * xml_op, xmlNode ** last
 
     int rc = 0;
     int status = PCMK_LRM_OP_UNKNOWN;
-    int target_rc = get_target_rc(xml_op);
+    int target_rc = pe__target_rc_from_xml(xml_op);
     guint interval_ms = 0;
 
     gboolean expired = FALSE;
-- 
1.8.3.1


From 2ccbefc2b623a2671f14824c6aea87c87fc338a0 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Fri, 24 May 2019 09:59:35 -0500
Subject: [PATCH 03/11] Refactor: libpacemaker: make transition.h internal

transition.h has always been installed even though it was purely internal.
Since libtransitioner is now merged into libpacemaker, move transition.h
to include/pcmki/pcmki_transition.h and make it internal.

Also, get rid of pcmki_sched_transition.h since it no longer contains
anything transition-related, and move its two function declarations to
pcmki_sched_utils.h.
---
 daemons/controld/controld_execd_state.c |   4 +-
 daemons/controld/controld_fencing.h     |   2 +-
 daemons/controld/controld_join_dc.c     |   4 +-
 daemons/controld/controld_transition.h  |   2 +-
 daemons/controld/controld_utils.h       |   7 +-
 include/crm/Makefile.am                 |   5 +-
 include/crm/transition.h                | 153 --------------------------------
 include/pacemaker-internal.h            |   2 +-
 include/pcmki/Makefile.am               |  12 +--
 include/pcmki/pcmki_sched_transition.h  |  22 -----
 include/pcmki/pcmki_sched_utils.h       |  16 ++++
 include/pcmki/pcmki_transition.h        | 143 +++++++++++++++++++++++++++++
 lib/pacemaker/pcmk_sched_transition.c   |   3 +-
 lib/pacemaker/pcmk_trans_graph.c        |  27 ++----
 lib/pacemaker/pcmk_trans_unpack.c       |  23 ++---
 lib/pacemaker/pcmk_trans_utils.c        |  27 ++----
 tools/crm_simulate.c                    |   1 -
 17 files changed, 201 insertions(+), 252 deletions(-)
 delete mode 100644 include/crm/transition.h
 delete mode 100644 include/pcmki/pcmki_sched_transition.h
 create mode 100644 include/pcmki/pcmki_transition.h

diff --git a/daemons/controld/controld_execd_state.c b/daemons/controld/controld_execd_state.c
index 8a1a7f3..4e9f096 100644
--- a/daemons/controld/controld_execd_state.c
+++ b/daemons/controld/controld_execd_state.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2018 David Vossel <davidvossel@gmail.com>
+ * Copyright 2012-2019 the Pacemaker project contributors
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
@@ -10,6 +10,7 @@
 #include <crm/msg_xml.h>
 #include <crm/common/iso8601.h>
 
+#include <pacemaker-internal.h>
 #include <pacemaker-controld.h>
 #include <controld_fsa.h>
 #include <controld_messages.h>
@@ -18,7 +19,6 @@
 #include <controld_alerts.h>
 #include <crm/pengine/rules.h>
 #include <crm/pengine/rules_internal.h>
-#include <crm/transition.h>
 #include <crm/lrmd_alerts_internal.h>
 
 GHashTable *lrm_state_table = NULL;
diff --git a/daemons/controld/controld_fencing.h b/daemons/controld/controld_fencing.h
index 3ef537f..8f7f19b 100644
--- a/daemons/controld/controld_fencing.h
+++ b/daemons/controld/controld_fencing.h
@@ -11,7 +11,7 @@
 #  define CONTROLD_FENCING__H
 
 #include <stdbool.h>                // bool
-#include <crm/transition.h>         // crm_graph_t, crm_action_t
+#include <pacemaker-internal.h>     // crm_graph_t, crm_action_t
 
 // stonith fail counts
 void st_fail_count_reset(const char * target);
diff --git a/daemons/controld/controld_join_dc.c b/daemons/controld/controld_join_dc.c
index ddee895..d790d9a 100644
--- a/daemons/controld/controld_join_dc.c
+++ b/daemons/controld/controld_join_dc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2004-2019 the Pacemaker project contributors
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
@@ -15,7 +15,7 @@
 
 #include <controld_fsa.h>
 #include <controld_messages.h>
-#include "controld_transition.h"
+#include <controld_transition.h>
 
 char *max_epoch = NULL;
 char *max_generation_from = NULL;
diff --git a/daemons/controld/controld_transition.h b/daemons/controld/controld_transition.h
index f31ac2d..192a9e8 100644
--- a/daemons/controld/controld_transition.h
+++ b/daemons/controld/controld_transition.h
@@ -8,10 +8,10 @@
 #ifndef TENGINE__H
 #  define TENGINE__H
 
-#  include <crm/transition.h>
 #  include <crm/common/mainloop.h>
 #  include <crm/stonith-ng.h>
 #  include <crm/services.h>
+#  include <pacemaker-internal.h>
 
 /* tengine */
 extern crm_action_t *match_down_event(const char *target);
diff --git a/daemons/controld/controld_utils.h b/daemons/controld/controld_utils.h
index 8b80e3c..1946a82 100644
--- a/daemons/controld/controld_utils.h
+++ b/daemons/controld/controld_utils.h
@@ -11,11 +11,10 @@
 #  define CRMD_UTILS__H
 
 #  include <crm/crm.h>
-#  include <crm/transition.h>
 #  include <crm/common/xml.h>
-#  include <crm/cib/internal.h> /* For CIB_OP_MODIFY */
-#  include "controld_fsa.h"     // For fsa_cib_conn
-#  include "controld_alerts.h"
+#  include <crm/cib/internal.h>     // CIB_OP_MODIFY
+#  include <controld_fsa.h>         // fsa_cib_conn
+#  include <controld_alerts.h>
 
 #  define FAKE_TE_ID	"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
 
diff --git a/include/crm/Makefile.am b/include/crm/Makefile.am
index 3f5f4bf..bc939eb 100644
--- a/include/crm/Makefile.am
+++ b/include/crm/Makefile.am
@@ -1,5 +1,5 @@
 #
-# Copyright 2004-2018 the Pacemaker project contributors
+# Copyright 2004-2019 the Pacemaker project contributors
 #
 # The version control history for this file may have further details.
 #
@@ -22,7 +22,6 @@ MAINTAINERCLEANFILES	= Makefile.in
 headerdir=$(pkgincludedir)/crm
 
 header_HEADERS		= attrd.h cib.h cluster.h compatibility.h crm.h \
-			  lrmd.h msg_xml.h services.h stonith-ng.h \
-			  transition.h
+			  lrmd.h msg_xml.h services.h stonith-ng.h
 
 SUBDIRS                 = common pengine cib fencing cluster
diff --git a/include/crm/transition.h b/include/crm/transition.h
deleted file mode 100644
index 6e9a875..0000000
--- a/include/crm/transition.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* 
- * Copyright 2004-2018 the Pacemaker project contributors
- *
- * The version control history for this file may have further details.
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- * 
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#ifndef CRM_TRANSITION__H
-#  define CRM_TRANSITION__H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <crm/crm.h>
-#include <crm/msg_xml.h>
-#include <crm/common/xml.h>
-
-typedef enum {
-    action_type_pseudo,
-    action_type_rsc,
-    action_type_crm
-} action_type_e;
-
-typedef struct te_timer_s crm_action_timer_t;
-typedef struct crm_graph_s crm_graph_t;
-
-typedef struct synapse_s {
-    int id;
-    int priority;
-
-    gboolean ready;
-    gboolean failed;
-    gboolean executed;
-    gboolean confirmed;
-
-    GListPtr actions;           /* crm_action_t* */
-    GListPtr inputs;            /* crm_action_t* */
-} synapse_t;
-
-typedef struct crm_action_s {
-    int id;
-    int timeout;
-    guint interval_ms;
-    GHashTable *params;
-    action_type_e type;
-
-    crm_action_timer_t *timer;
-    synapse_t *synapse;
-
-    gboolean sent_update;       /* sent to the CIB */
-    gboolean executed;          /* sent to the CRM */
-    gboolean confirmed;
-
-    gboolean failed;
-    gboolean can_fail;
-
-    xmlNode *xml;
-
-} crm_action_t;
-
-struct te_timer_s {
-    int source_id;
-    int timeout;
-    crm_action_t *action;
-};
-
-/* order matters here */
-enum transition_action {
-    tg_done,
-    tg_stop,
-    tg_restart,
-    tg_shutdown,
-};
-
-struct crm_graph_s {
-    int id;
-    char *source;
-    int abort_priority;
-
-    gboolean complete;
-    const char *abort_reason;
-    enum transition_action completion_action;
-
-    int num_actions;
-    int num_synapses;
-
-    int batch_limit;
-    int network_delay;
-    int stonith_timeout;
-    int transition_timeout;
-
-    int fired;
-    int pending;
-    int skipped;
-    int completed;
-    int incomplete;
-
-    GListPtr synapses;          /* synapse_t* */
-
-    int migration_limit;
-};
-
-typedef struct crm_graph_functions_s {
-    gboolean(*pseudo) (crm_graph_t * graph, crm_action_t * action);
-    gboolean(*rsc) (crm_graph_t * graph, crm_action_t * action);
-    gboolean(*crmd) (crm_graph_t * graph, crm_action_t * action);
-    gboolean(*stonith) (crm_graph_t * graph, crm_action_t * action);
-    gboolean(*allowed) (crm_graph_t * graph, crm_action_t * action);
-} crm_graph_functions_t;
-
-enum transition_status {
-    transition_active,
-    transition_pending,         /* active but no actions performed this time */
-    transition_complete,
-    transition_stopped,
-    transition_terminated,
-    transition_action_failed,
-    transition_failed,
-};
-
-void set_default_graph_functions(void);
-void set_graph_functions(crm_graph_functions_t * fns);
-crm_graph_t *unpack_graph(xmlNode * xml_graph, const char *reference);
-int run_graph(crm_graph_t * graph);
-gboolean update_graph(crm_graph_t * graph, crm_action_t * action);
-void destroy_graph(crm_graph_t * graph);
-const char *transition_status(enum transition_status state);
-void print_graph(unsigned int log_level, crm_graph_t * graph);
-void print_action(int log_level, const char *prefix, crm_action_t * action);
-bool update_abort_priority(crm_graph_t * graph, int priority,
-                           enum transition_action action, const char *abort_reason);
-const char *actiontype2text(action_type_e type);
-lrmd_event_data_t *convert_graph_action(xmlNode * resource, crm_action_t * action, int status,
-                                        int rc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/include/pacemaker-internal.h b/include/pacemaker-internal.h
index 3627ba5..51d7225 100644
--- a/include/pacemaker-internal.h
+++ b/include/pacemaker-internal.h
@@ -13,8 +13,8 @@
 #  include <pcmki/pcmki_error.h>
 #  include <pcmki/pcmki_sched_allocate.h>
 #  include <pcmki/pcmki_sched_notif.h>
-#  include <pcmki/pcmki_sched_transition.h>
 #  include <pcmki/pcmki_sched_utils.h>
 #  include <pcmki/pcmki_scheduler.h>
+#  include <pcmki/pcmki_transition.h>
 
 #endif
diff --git a/include/pcmki/Makefile.am b/include/pcmki/Makefile.am
index b163e89..4cf1cf2 100644
--- a/include/pcmki/Makefile.am
+++ b/include/pcmki/Makefile.am
@@ -9,11 +9,11 @@
 
 MAINTAINERCLEANFILES    = Makefile.in
 
-noinst_HEADERS	        = pcmki_error.h \
-						  pcmki_sched_allocate.h \
-						  pcmki_sched_notif.h \
-						  pcmki_sched_transition.h \
-						  pcmki_sched_utils.h \
-						  pcmki_scheduler.h
+noinst_HEADERS		= pcmki_error.h \
+			  pcmki_sched_allocate.h \
+			  pcmki_sched_notif.h \
+			  pcmki_sched_utils.h \
+			  pcmki_scheduler.h \
+			  pcmki_transition.h
 
 .PHONY: $(ARCHIVE_VERSION)
diff --git a/include/pcmki/pcmki_sched_transition.h b/include/pcmki/pcmki_sched_transition.h
deleted file mode 100644
index 41f5d61..0000000
--- a/include/pcmki/pcmki_sched_transition.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2014-2019 the Pacemaker project contributors
- *
- * The version control history for this file may have further details.
- *
- * This source code is licensed under the GNU Lesser General Public License
- * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
- */
-#ifndef SCHED_TRANSITION__H
-#  define SCHED_TRANSITION__H
-
-#include <crm/cib.h>
-
-void modify_configuration(
-    pe_working_set_t * data_set, cib_t *cib,
-    const char *quorum, const char *watchdog, GListPtr node_up, GListPtr node_down, GListPtr node_fail,
-    GListPtr op_inject, GListPtr ticket_grant, GListPtr ticket_revoke,
-    GListPtr ticket_standby, GListPtr ticket_activate);
-
-int run_simulation(pe_working_set_t * data_set, cib_t *cib, GListPtr op_fail_list, bool quiet);
-
-#endif
diff --git a/include/pcmki/pcmki_sched_utils.h b/include/pcmki/pcmki_sched_utils.h
index b47a2bb..4361235 100644
--- a/include/pcmki/pcmki_sched_utils.h
+++ b/include/pcmki/pcmki_sched_utils.h
@@ -10,6 +10,14 @@
 #ifndef PENGINE_AUTILS__H
 #  define PENGINE_AUTILS__H
 
+#include <stdbool.h>                    // bool
+#include <glib.h>                       // GList, GHashTable, gboolean, guint
+#include <crm/crm.h>                    // GListPtr
+#include <crm/cib.h>                    // cib_t
+#include <crm/pengine/pe_types.h>
+#include <crm/pengine/internal.h>
+#include <pcmki/pcmki_scheduler.h>
+
 /* Constraint helper functions */
 extern rsc_colocation_t *invert_constraint(rsc_colocation_t * constraint);
 
@@ -75,4 +83,12 @@ pe_action_t *sched_shutdown_op(pe_node_t *node, pe_working_set_t *data_set);
 
 #  define LOAD_STOPPED "load_stopped"
 
+void modify_configuration(
+    pe_working_set_t * data_set, cib_t *cib,
+    const char *quorum, const char *watchdog, GListPtr node_up, GListPtr node_down, GListPtr node_fail,
+    GListPtr op_inject, GListPtr ticket_grant, GListPtr ticket_revoke,
+    GListPtr ticket_standby, GListPtr ticket_activate);
+
+int run_simulation(pe_working_set_t * data_set, cib_t *cib, GListPtr op_fail_list, bool quiet);
+
 #endif
diff --git a/include/pcmki/pcmki_transition.h b/include/pcmki/pcmki_transition.h
new file mode 100644
index 0000000..d9a0ff6
--- /dev/null
+++ b/include/pcmki/pcmki_transition.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2004-2019 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
+ */
+
+#ifndef CRM_TRANSITION__H
+#  define CRM_TRANSITION__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <crm/crm.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+
+typedef enum {
+    action_type_pseudo,
+    action_type_rsc,
+    action_type_crm
+} action_type_e;
+
+typedef struct te_timer_s crm_action_timer_t;
+typedef struct crm_graph_s crm_graph_t;
+
+typedef struct synapse_s {
+    int id;
+    int priority;
+
+    gboolean ready;
+    gboolean failed;
+    gboolean executed;
+    gboolean confirmed;
+
+    GListPtr actions;           /* crm_action_t* */
+    GListPtr inputs;            /* crm_action_t* */
+} synapse_t;
+
+typedef struct crm_action_s {
+    int id;
+    int timeout;
+    guint interval_ms;
+    GHashTable *params;
+    action_type_e type;
+
+    crm_action_timer_t *timer;
+    synapse_t *synapse;
+
+    gboolean sent_update;       /* sent to the CIB */
+    gboolean executed;          /* sent to the CRM */
+    gboolean confirmed;
+
+    gboolean failed;
+    gboolean can_fail;
+
+    xmlNode *xml;
+
+} crm_action_t;
+
+struct te_timer_s {
+    int source_id;
+    int timeout;
+    crm_action_t *action;
+};
+
+/* order matters here */
+enum transition_action {
+    tg_done,
+    tg_stop,
+    tg_restart,
+    tg_shutdown,
+};
+
+struct crm_graph_s {
+    int id;
+    char *source;
+    int abort_priority;
+
+    gboolean complete;
+    const char *abort_reason;
+    enum transition_action completion_action;
+
+    int num_actions;
+    int num_synapses;
+
+    int batch_limit;
+    int network_delay;
+    int stonith_timeout;
+    int transition_timeout;
+
+    int fired;
+    int pending;
+    int skipped;
+    int completed;
+    int incomplete;
+
+    GListPtr synapses;          /* synapse_t* */
+
+    int migration_limit;
+};
+
+typedef struct crm_graph_functions_s {
+    gboolean(*pseudo) (crm_graph_t * graph, crm_action_t * action);
+    gboolean(*rsc) (crm_graph_t * graph, crm_action_t * action);
+    gboolean(*crmd) (crm_graph_t * graph, crm_action_t * action);
+    gboolean(*stonith) (crm_graph_t * graph, crm_action_t * action);
+    gboolean(*allowed) (crm_graph_t * graph, crm_action_t * action);
+} crm_graph_functions_t;
+
+enum transition_status {
+    transition_active,
+    transition_pending,         /* active but no actions performed this time */
+    transition_complete,
+    transition_stopped,
+    transition_terminated,
+    transition_action_failed,
+    transition_failed,
+};
+
+void set_default_graph_functions(void);
+void set_graph_functions(crm_graph_functions_t * fns);
+crm_graph_t *unpack_graph(xmlNode * xml_graph, const char *reference);
+int run_graph(crm_graph_t * graph);
+gboolean update_graph(crm_graph_t * graph, crm_action_t * action);
+void destroy_graph(crm_graph_t * graph);
+const char *transition_status(enum transition_status state);
+void print_graph(unsigned int log_level, crm_graph_t * graph);
+void print_action(int log_level, const char *prefix, crm_action_t * action);
+bool update_abort_priority(crm_graph_t * graph, int priority,
+                           enum transition_action action, const char *abort_reason);
+const char *actiontype2text(action_type_e type);
+lrmd_event_data_t *convert_graph_action(xmlNode * resource, crm_action_t * action, int status,
+                                        int rc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/pacemaker/pcmk_sched_transition.c b/lib/pacemaker/pcmk_sched_transition.c
index 0fa5709..8ab8d82 100644
--- a/lib/pacemaker/pcmk_sched_transition.c
+++ b/lib/pacemaker/pcmk_sched_transition.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2018 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2009-2019 the Pacemaker project contributors
  *
  * This source code is licensed under the GNU General Public License version 2
  * or later (GPLv2+) WITHOUT ANY WARRANTY.
@@ -19,7 +19,6 @@
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/common/util.h>
-#include <crm/transition.h>
 #include <crm/common/iso8601.h>
 #include <crm/pengine/status.h>
 #include <pacemaker-internal.h>
diff --git a/lib/pacemaker/pcmk_trans_graph.c b/lib/pacemaker/pcmk_trans_graph.c
index 71568dd..77980e5 100644
--- a/lib/pacemaker/pcmk_trans_graph.c
+++ b/lib/pacemaker/pcmk_trans_graph.c
@@ -1,19 +1,10 @@
-/* 
- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+/*
+ * Copyright 2004-2019 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
@@ -21,9 +12,7 @@
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
-#include <crm/transition.h>
-/* #include <sys/param.h> */
-/*  */
+#include <pacemaker-internal.h>
 
 crm_graph_functions_t *graph_fns = NULL;
 
diff --git a/lib/pacemaker/pcmk_trans_unpack.c b/lib/pacemaker/pcmk_trans_unpack.c
index 31e39cb..b8147a9 100644
--- a/lib/pacemaker/pcmk_trans_unpack.c
+++ b/lib/pacemaker/pcmk_trans_unpack.c
@@ -1,30 +1,21 @@
 /*
- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
+ * Copyright 2004-2019 the Pacemaker project contributors
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
+ * The version control history for this file may have further details.
  *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
 
 #include <sys/param.h>
+#include <sys/stat.h>
+
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
-
 #include <crm/common/xml.h>
-#include <crm/transition.h>
-#include <sys/stat.h>
+#include <pacemaker-internal.h>
 
 CRM_TRACE_INIT_DATA(transitioner);
 
diff --git a/lib/pacemaker/pcmk_trans_utils.c b/lib/pacemaker/pcmk_trans_utils.c
index d3199d9..69da7f4 100644
--- a/lib/pacemaker/pcmk_trans_utils.c
+++ b/lib/pacemaker/pcmk_trans_utils.c
@@ -1,19 +1,10 @@
-/* 
- * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+/*
+ * Copyright 2004-2019 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU Lesser General Public License
+ * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
  */
 
 #include <crm_internal.h>
@@ -21,9 +12,7 @@
 #include <crm/crm.h>
 #include <crm/msg_xml.h>
 #include <crm/common/xml.h>
-#include <crm/transition.h>
-/* #include <sys/param.h> */
-/*  */
+#include <pacemaker-internal.h>
 
 extern crm_graph_functions_t *graph_fns;
 
diff --git a/tools/crm_simulate.c b/tools/crm_simulate.c
index 1921ee4..d4ab6a3 100644
--- a/tools/crm_simulate.c
+++ b/tools/crm_simulate.c
@@ -21,7 +21,6 @@
 #include <crm/crm.h>
 #include <crm/cib.h>
 #include <crm/common/util.h>
-#include <crm/transition.h>
 #include <crm/common/iso8601.h>
 #include <crm/pengine/status.h>
 #include <pacemaker-internal.h>
-- 
1.8.3.1


From 8a0b29d8ed21c97075b4c059fa4b0f5c0d985a73 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Thu, 6 Jun 2019 14:18:37 -0500
Subject: [PATCH 04/11] Test: scheduler: explicitly set concurrent-fencing in
 relevant regression tests

... since concurrent-fencing's default is likely to eventually change,
which would otherwise affect the results of these tests
---
 cts/scheduler/rec-node-14.xml                     | 1 +
 cts/scheduler/remote-connection-unrecoverable.xml | 1 +
 cts/scheduler/remote-recover-all.xml              | 1 +
 cts/scheduler/remote-recover-no-resources.xml     | 1 +
 cts/scheduler/remote-recover-unknown.xml          | 1 +
 cts/scheduler/stonith-4.xml                       | 1 +
 cts/scheduler/suicide-needed-inquorate.xml        | 1 +
 cts/scheduler/ticket-clone-21.xml                 | 1 +
 cts/scheduler/ticket-clone-9.xml                  | 1 +
 9 files changed, 9 insertions(+)

diff --git a/cts/scheduler/rec-node-14.xml b/cts/scheduler/rec-node-14.xml
index 60307ba..aefa410 100644
--- a/cts/scheduler/rec-node-14.xml
+++ b/cts/scheduler/rec-node-14.xml
@@ -4,6 +4,7 @@
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="nvpair.id21835" name="stonith-enabled" value="true"/>
         <nvpair id="nvpair.id21844" name="no-quorum-policy" value="ignore"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
diff --git a/cts/scheduler/remote-connection-unrecoverable.xml b/cts/scheduler/remote-connection-unrecoverable.xml
index df9fee2..efec646 100644
--- a/cts/scheduler/remote-connection-unrecoverable.xml
+++ b/cts/scheduler/remote-connection-unrecoverable.xml
@@ -7,6 +7,7 @@
         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
         <nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mycluster"/>
         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1459735110"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
diff --git a/cts/scheduler/remote-recover-all.xml b/cts/scheduler/remote-recover-all.xml
index 0ade7cd..1680166 100644
--- a/cts/scheduler/remote-recover-all.xml
+++ b/cts/scheduler/remote-recover-all.xml
@@ -10,6 +10,7 @@
         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
       <cluster_property_set id="redis_replication">
         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
diff --git a/cts/scheduler/remote-recover-no-resources.xml b/cts/scheduler/remote-recover-no-resources.xml
index 37708bb..602ed2b 100644
--- a/cts/scheduler/remote-recover-no-resources.xml
+++ b/cts/scheduler/remote-recover-no-resources.xml
@@ -10,6 +10,7 @@
         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
       <cluster_property_set id="redis_replication">
         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
diff --git a/cts/scheduler/remote-recover-unknown.xml b/cts/scheduler/remote-recover-unknown.xml
index f070f11..f47a841 100644
--- a/cts/scheduler/remote-recover-unknown.xml
+++ b/cts/scheduler/remote-recover-unknown.xml
@@ -10,6 +10,7 @@
         <nvpair id="cib-bootstrap-options-cluster-recheck-interval" name="cluster-recheck-interval" value="60s"/>
         <nvpair id="cib-bootstrap-options-maintenance-mode" name="maintenance-mode" value="false"/>
         <nvpair id="cib-bootstrap-options-last-lrm-refresh" name="last-lrm-refresh" value="1493817755"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
       <cluster_property_set id="redis_replication">
         <nvpair id="redis_replication-redis_REPL_INFO" name="redis_REPL_INFO" value="controller-0"/>
diff --git a/cts/scheduler/stonith-4.xml b/cts/scheduler/stonith-4.xml
index 7979462..dd7af8d 100644
--- a/cts/scheduler/stonith-4.xml
+++ b/cts/scheduler/stonith-4.xml
@@ -4,6 +4,7 @@
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.8-0.772.26fe3e5.git.fc17-26fe3e52d259e4726699300d27991fc1a80c556b"/>
         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
diff --git a/cts/scheduler/suicide-needed-inquorate.xml b/cts/scheduler/suicide-needed-inquorate.xml
index e626ea6..f87422b 100644
--- a/cts/scheduler/suicide-needed-inquorate.xml
+++ b/cts/scheduler/suicide-needed-inquorate.xml
@@ -6,6 +6,7 @@
         <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.1.17-1"/>
         <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="suicide"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
diff --git a/cts/scheduler/ticket-clone-21.xml b/cts/scheduler/ticket-clone-21.xml
index bb1f044..efd5294 100644
--- a/cts/scheduler/ticket-clone-21.xml
+++ b/cts/scheduler/ticket-clone-21.xml
@@ -4,6 +4,7 @@
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
diff --git a/cts/scheduler/ticket-clone-9.xml b/cts/scheduler/ticket-clone-9.xml
index e77210d..c6d5809 100644
--- a/cts/scheduler/ticket-clone-9.xml
+++ b/cts/scheduler/ticket-clone-9.xml
@@ -4,6 +4,7 @@
       <cluster_property_set id="cib-bootstrap-options">
         <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
         <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
+        <nvpair id="options-concurrent-fencing" name="concurrent-fencing" value="false"/>
       </cluster_property_set>
     </crm_config>
     <nodes>
-- 
1.8.3.1


From 359f0e6089ef618361acc2437d779ecad1edb8d3 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Thu, 6 Jun 2019 11:22:58 -0500
Subject: [PATCH 05/11] Build: doc: define variable properly

broke when moved from GNUmakefile to Makefile.am
---
 doc/Makefile.am | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/Makefile.am b/doc/Makefile.am
index f3b79bb..18747cf 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -25,6 +25,9 @@ RSYNC_DEST      ?= root@www.clusterlabs.org:/var/www/html
 # don't cross filesystems, sparse, show progress
 RSYNC_OPTS      = -rlptvzxS --progress
 
+LAST_RELEASE	?= Pacemaker-$(VERSION)
+TAG		?= $(shell git log --pretty=format:%H -n 1 HEAD)
+
 publican_docs   =
 generated_docs	=
 generated_mans	=
@@ -364,9 +367,6 @@ doxygen-upload: doxygen
 
 # ABI compatibility report as HTML
 
-LAST_RELEASE	?= Pacemaker-$(VERSION)
-TAG		?= $(git log --pretty=format:%H -n 1 HEAD)
-
 abi: abi-check
 	./abi-check $(PACKAGE) $(LAST_RELEASE) $(TAG)
 
-- 
1.8.3.1


From c0e1ff4cc8578b78b085b98effff11747f81a397 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Mon, 10 Jun 2019 11:38:51 -0500
Subject: [PATCH 06/11] Doc: doxygen: avoid full paths in output graphics

broke when doxygen target moved from toplevel to doc subdirectory
---
 doc/Doxyfile.in | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 81615fb..bc449df 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -142,7 +142,7 @@ FULL_PATH_NAMES        = YES
 # will be relative from the directory where doxygen is started.
 # This tag requires that the tag FULL_PATH_NAMES is set to YES.
 
-STRIP_FROM_PATH        =
+STRIP_FROM_PATH        = ..
 
 # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
 # path mentioned in the documentation of a class, which tells the reader which
@@ -151,7 +151,7 @@ STRIP_FROM_PATH        =
 # specify the list of include paths that are normally passed to the compiler
 # using the -I flag.
 
-STRIP_FROM_INC_PATH    =
+STRIP_FROM_INC_PATH    = ..
 
 # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
 # less readable) file names. This can be useful is your file systems doesn't
-- 
1.8.3.1


From a0ab603c5c416148132a91f5bf22d55e65f8ba4e Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Tue, 11 Jun 2019 14:26:28 -0500
Subject: [PATCH 07/11] Low: xml: add API schema for list_item() output

---
 xml/Makefile.am      |  9 +++++----
 xml/api/item-1.1.rng | 19 +++++++++++++++++++
 2 files changed, 24 insertions(+), 4 deletions(-)
 create mode 100644 xml/api/item-1.1.rng

diff --git a/xml/Makefile.am b/xml/Makefile.am
index 88edbda..49542a3 100644
--- a/xml/Makefile.am
+++ b/xml/Makefile.am
@@ -1,5 +1,5 @@
 #
-# Copyright 2004-2018 the Pacemaker project contributors
+# Copyright 2004-2019 the Pacemaker project contributors
 #
 # The version control history for this file may have further details.
 #
@@ -63,8 +63,9 @@ RNG_max			?= $(lastword $(RNG_numeric_versions))
 
 # A sorted list of all API and RNG versions (numeric and "next")
 API_versions 		= next $(API_numeric_versions)
-API_base 			= command-output stonith_admin
-API_files 			= $(foreach base,$(API_base),$(wildcard api/$(base)*.rng))
+API_request_base 	= command-output stonith_admin
+API_base		= $(API_request_base) item
+API_files 		= $(foreach base,$(API_base),$(wildcard api/$(base)*.rng))
 
 RNG_versions		= next $(RNG_numeric_versions)
 RNG_version_pairs	= $(call version_pairs,${RNG_numeric_versions})
@@ -139,7 +140,7 @@ api/api-result-%.rng: $(API_files) Makefile.am
 	echo '      <attribute name="request"> <text /> </attribute>' >> $@
 	echo '      <optional>' >> $@
 	echo '        <choice>' >> $@
-	for rng in $(API_base); do $(top_srcdir)/xml/best-match.sh api/$$rng $(*) $(@) "          " || :; done
+	for rng in $(API_request_base); do $(top_srcdir)/xml/best-match.sh api/$$rng $(*) $(@) "          " || :; done
 	echo '        </choice>' >> $@
 	echo '      </optional>' >> $@
 	echo '      <element name="status">' >> $@
diff --git a/xml/api/item-1.1.rng b/xml/api/item-1.1.rng
new file mode 100644
index 0000000..1a065ca
--- /dev/null
+++ b/xml/api/item-1.1.rng
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+    <!-- list_item() method -->
+    <start>
+        <ref name="element-item"/>
+    </start>
+
+    <define name="element-item">
+        <element name="item">
+            <optional>
+                <attribute name="name"> <text /> </attribute>
+            </optional>
+            <data type="string"/>
+        </element>
+    </define>
+
+</grammar>
-- 
1.8.3.1


From 311d8629241d227dded598225d8f413c9ebb4a9b Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Tue, 11 Jun 2019 18:47:10 -0500
Subject: [PATCH 08/11] Refactor: fencing: expose function for parsing targets
 from string

... as internal API, so it can be reused elsewhere. Also, refactor it for
simplicity and versatility.
---
 daemons/fenced/fenced_commands.c |  91 +---------------------------
 include/crm/fencing/internal.h   |   3 +
 lib/fencing/st_client.c          | 128 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 89 deletions(-)

diff --git a/daemons/fenced/fenced_commands.c b/daemons/fenced/fenced_commands.c
index 1be2508..54575f9 100644
--- a/daemons/fenced/fenced_commands.c
+++ b/daemons/fenced/fenced_commands.c
@@ -617,93 +617,6 @@ build_port_aliases(const char *hostmap, GListPtr * targets)
     return aliases;
 }
 
-static void
-parse_host_line(const char *line, int max, GListPtr * output)
-{
-    int lpc = 0;
-    int last = 0;
-
-    if (max <= 0) {
-        return;
-    }
-
-    /* Check for any complaints about additional parameters that the device doesn't understand */
-    if (strstr(line, "invalid") || strstr(line, "variable")) {
-        crm_debug("Skipping: %s", line);
-        return;
-    }
-
-    crm_trace("Processing %d bytes: [%s]", max, line);
-    /* Skip initial whitespace */
-    for (lpc = 0; lpc <= max && isspace(line[lpc]); lpc++) {
-        last = lpc + 1;
-    }
-
-    /* Now the actual content */
-    for (lpc = 0; lpc <= max; lpc++) {
-        gboolean a_space = isspace(line[lpc]);
-
-        if (a_space && lpc < max && isspace(line[lpc + 1])) {
-            /* fast-forward to the end of the spaces */
-
-        } else if (a_space || line[lpc] == ',' || line[lpc] == ';' || line[lpc] == 0) {
-            int rc = 1;
-            char *entry = NULL;
-
-            if (lpc != last) {
-                entry = calloc(1, 1 + lpc - last);
-                rc = sscanf(line + last, "%[a-zA-Z0-9_-.]", entry);
-            }
-
-            if (entry == NULL) {
-                /* Skip */
-            } else if (rc != 1) {
-                crm_warn("Could not parse (%d %d): %s", last, lpc, line + last);
-            } else if (safe_str_neq(entry, "on") && safe_str_neq(entry, "off")) {
-                crm_trace("Adding '%s'", entry);
-                *output = g_list_append(*output, entry);
-                entry = NULL;
-            }
-
-            free(entry);
-            last = lpc + 1;
-        }
-    }
-}
-
-static GListPtr
-parse_host_list(const char *hosts)
-{
-    int lpc = 0;
-    int max = 0;
-    int last = 0;
-    GListPtr output = NULL;
-
-    if (hosts == NULL) {
-        return output;
-    }
-
-    max = strlen(hosts);
-    for (lpc = 0; lpc <= max; lpc++) {
-        if (hosts[lpc] == '\n' || hosts[lpc] == 0) {
-            int len = lpc - last;
-
-            if(len > 1) {
-                char *line = strndup(hosts + last, len);
-
-                line[len] = 0; /* Because it might be '\n' */
-                parse_host_line(line, len, &output);
-                free(line);
-            }
-
-            last = lpc + 1;
-        }
-    }
-
-    crm_trace("Parsed %d entries from '%s'", g_list_length(output), hosts);
-    return output;
-}
-
 GHashTable *metadata_cache = NULL;
 
 void
@@ -937,7 +850,7 @@ build_device_from_xml(xmlNode * msg)
 
     value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTLIST);
     if (value) {
-        device->targets = parse_host_list(value);
+        device->targets = stonith__parse_targets(value);
     }
 
     value = g_hash_table_lookup(device->params, STONITH_ATTR_HOSTMAP);
@@ -1108,7 +1021,7 @@ dynamic_list_search_cb(GPid pid, int rc, const char *output, gpointer user_data)
     } else if (!rc) {
         crm_info("Refreshing port list for %s", dev->id);
         g_list_free_full(dev->targets, free);
-        dev->targets = parse_host_list(output);
+        dev->targets = stonith__parse_targets(output);
         dev->targets_age = time(NULL);
     }
 
diff --git a/include/crm/fencing/internal.h b/include/crm/fencing/internal.h
index 0c0ac70..f3d38a7 100644
--- a/include/crm/fencing/internal.h
+++ b/include/crm/fencing/internal.h
@@ -10,6 +10,7 @@
 #ifndef STONITH_NG_INTERNAL__H
 #  define STONITH_NG_INTERNAL__H
 
+#  include <glib.h>
 #  include <crm/common/ipc.h>
 #  include <crm/common/output.h>
 #  include <crm/common/xml.h>
@@ -49,6 +50,8 @@ xmlNode *create_device_registration_xml(const char *id,
 
 void stonith__register_messages(pcmk__output_t *out);
 
+GList *stonith__parse_targets(const char *hosts);
+
 #  define ST_LEVEL_MAX 10
 
 #  define F_STONITH_CLIENTID      "st_clientid"
diff --git a/lib/fencing/st_client.c b/lib/fencing/st_client.c
index d949fe1..629887a 100644
--- a/lib/fencing/st_client.c
+++ b/lib/fencing/st_client.c
@@ -9,6 +9,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
 #include <ctype.h>
 #include <libgen.h>
@@ -2304,3 +2305,130 @@ stonith_action_str(const char *action)
         return action;
     }
 }
+
+/*!
+ * \internal
+ * \brief Parse a target name from one line of a target list string
+ *
+ * \param[in]     line    One line of a target list string
+ * \parma[in]     len     String length of line
+ * \param[in,out] output  List to add newly allocated target name to
+ */
+static void
+parse_list_line(const char *line, int len, GList **output)
+{
+    size_t i = 0;
+    size_t entry_start = 0;
+
+    /* Skip complaints about additional parameters device doesn't understand
+     *
+     * @TODO Document or eliminate the implied restriction of target names
+     */
+    if (strstr(line, "invalid") || strstr(line, "variable")) {
+        crm_debug("Skipping list output line: %s", line);
+        return;
+    }
+
+    // Process line content, character by character
+    for (i = 0; i <= len; i++) {
+
+        if (isspace(line[i]) || (line[i] == ',') || (line[i] == ';')
+            || (line[i] == '\0')) {
+            // We've found a separator (i.e. the end of an entry)
+
+            int rc = 0;
+            char *entry = NULL;
+
+            if (i == entry_start) {
+                // Skip leading and sequential separators
+                entry_start = i + 1;
+                continue;
+            }
+
+            entry = calloc(i - entry_start + 1, sizeof(char));
+            CRM_ASSERT(entry != NULL);
+
+            /* Read entry, stopping at first separator
+             *
+             * @TODO Document or eliminate these character restrictions
+             */
+            rc = sscanf(line + entry_start, "%[a-zA-Z0-9_-.]", entry);
+            if (rc != 1) {
+                crm_warn("Could not parse list output entry: %s "
+                         CRM_XS " entry_start=%d position=%d",
+                         line + entry_start, entry_start, i);
+                free(entry);
+
+            } else if (safe_str_eq(entry, "on") || safe_str_eq(entry, "off")) {
+                /* Some agents print the target status in the list output,
+                 * though none are known now (the separate list-status command
+                 * is used for this, but it can also print "UNKNOWN"). To handle
+                 * this possibility, skip such entries.
+                 *
+                 * @TODO Document or eliminate the implied restriction of target
+                 * names.
+                 */
+                free(entry);
+
+            } else {
+                // We have a valid entry
+                *output = g_list_append(*output, entry);
+            }
+            entry_start = i + 1;
+        }
+    }
+}
+
+/*!
+ * \internal
+ * \brief Parse a list of targets from a string
+ *
+ * \param[in] list_output  Target list as a string
+ *
+ * \return List of target names
+ * \note The target list string format is flexible, to allow for user-specified
+ *       lists such pcmk_host_list and the output of an agent's list action
+ *       (whether direct or via the API, which escapes newlines). There may be
+ *       multiple lines, separated by either a newline or an escaped newline
+ *       (backslash n). Each line may have one or more target names, separated
+ *       by any combination of whitespace, commas, and semi-colons. Lines
+ *       containing "invalid" or "variable" will be ignored entirely. Target
+ *       names "on" or "off" (case-insensitive) will be ignored. Target names
+ *       may contain only alphanumeric characters, underbars (_), dashes (-),
+ *       and dots (.) (if any other character occurs in the name, it and all
+ *       subsequent characters in the name will be ignored).
+ * \note The caller is responsible for freeing the result with
+ *       g_list_free_full(result, free).
+ */
+GList *
+stonith__parse_targets(const char *target_spec)
+{
+    GList *targets = NULL;
+
+    if (target_spec != NULL) {
+        size_t out_len = strlen(target_spec);
+        size_t line_start = 0; // Starting index of line being processed
+
+        for (size_t i = 0; i <= out_len; ++i) {
+            if ((target_spec[i] == '\n') || (target_spec[i] == '\0')
+                || ((target_spec[i] == '\\') && (target_spec[i + 1] == 'n'))) {
+                // We've reached the end of one line of output
+
+                int len = i - line_start;
+
+                if (len > 0) {
+                    char *line = strndup(target_spec + line_start, len);
+
+                    line[len] = '\0'; // Because it might be a newline
+                    parse_list_line(line, len, &targets);
+                    free(line);
+                }
+                if (target_spec[i] == '\\') {
+                    ++i; // backslash-n takes up two positions
+                }
+                line_start = i + 1;
+            }
+        }
+    }
+    return targets;
+}
-- 
1.8.3.1


From 60ad7730fbf34c1f67700bace39a083c0e3d1c31 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Mon, 10 Jun 2019 16:13:29 -0500
Subject: [PATCH 09/11] Fix: tools: stonith_admin --list-targets should show
 what fencer would use

This fixes both a regression in 2.0.2 and a pre-existing issue before that.

Before 2.0.2's 52f614aa, stonith_admin --list-targets would print each line of
output from the fence agent's list action, with any commas and semi-colons
removed. After that, it would only print lines that had three values separated
by spaces.

In practice, fence agents have some variety in list action output, which is not
yet standardized by the fence agent API. Only fence_xvm is known to use the
three space-separated values. Most agents output the target name and an alias
separated by a comma.

The earlier behavior would actually be awkward in the comma-separated case,
since the target name and alias would be run together with no separator.

Neither behaviors matched what was actually used by the fencer.

This commit refactors to use the new stonith__parse_targets() function, to show
the same list the fencer would use. It also fixes a few related issues:

* Memory was not properly freed

* No list wrapper would be printed if the list were empty

* stonith_admin's XML output did not match its schema (the tool would output a
  <fence-target> element, while the schema had <target>). Now, we abandon the
  custom element and use the generic <item> schema instead. While technically
  this could be considered backward-incompatible, it's not really, because the
  schema didn't match to begin with. Also, the API XML schema is still
  considered experimental.

* Not really a problem, but since we now have the generic <item> schema,
  stonith_admin uses this in place of its former dedicated <item> schema.
  The only difference is the former allows arbitrary strings while the
  latter required NCName, but the reuse is more useful than type validation.
---
 lib/fencing/st_output.c       | 28 ----------------
 tools/stonith_admin.c         | 52 +++++-------------------------
 xml/api/stonith_admin-1.1.rng | 75 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+), 72 deletions(-)
 create mode 100644 xml/api/stonith_admin-1.1.rng

diff --git a/lib/fencing/st_output.c b/lib/fencing/st_output.c
index a8d0a60..0ceb699 100644
--- a/lib/fencing/st_output.c
+++ b/lib/fencing/st_output.c
@@ -17,32 +17,6 @@
 #include <crm/fencing/internal.h>
 
 static int
-fence_target_text(pcmk__output_t *out, va_list args) {
-    const char *hostname = va_arg(args, const char *);
-    const char *uuid = va_arg(args, const char *);
-    const char *status = va_arg(args, const char *);
-
-    pcmk__indented_printf(out, "%s\t%s\t%s\n", hostname, uuid, status);
-    return 0;
-}
-
-static int
-fence_target_xml(pcmk__output_t *out, va_list args) {
-    xmlNodePtr node = NULL;
-    const char *hostname = va_arg(args, const char *);
-    const char *uuid = va_arg(args, const char *);
-    const char *status = va_arg(args, const char *);
-
-    node = xmlNewNode(NULL, (pcmkXmlStr) "target");
-    xmlSetProp(node, (pcmkXmlStr) "hostname", (pcmkXmlStr) hostname);
-    xmlSetProp(node, (pcmkXmlStr) "uuid", (pcmkXmlStr) uuid);
-    xmlSetProp(node, (pcmkXmlStr) "status", (pcmkXmlStr) status);
-
-    pcmk__xml_add_node(out, node);
-    return 0;
-}
-
-static int
 last_fenced_text(pcmk__output_t *out, va_list args) {
     const char *target = va_arg(args, const char *);
     time_t when = va_arg(args, time_t);
@@ -216,8 +190,6 @@ validate_agent_xml(pcmk__output_t *out, va_list args) {
 }
 
 static pcmk__message_entry_t fmt_functions[] = {
-    { "fence-target", "text", fence_target_text },
-    { "fence-target", "xml", fence_target_xml },
     { "last-fenced", "text", last_fenced_text },
     { "last-fenced", "xml", last_fenced_xml },
     { "stonith-event", "text", stonith_event_text },
diff --git a/tools/stonith_admin.c b/tools/stonith_admin.c
index 6be66c6..a7551fd 100644
--- a/tools/stonith_admin.c
+++ b/tools/stonith_admin.c
@@ -635,53 +635,17 @@ main(int argc, char **argv)
             break;
         case 's':
             rc = st->cmds->list(st, st_opts, device, &lists, timeout);
-            if (rc == 0 && lists) {
-                char *head = lists;
-                char *eol = NULL;
+            if (rc == 0) {
+                GList *targets = stonith__parse_targets(lists);
 
                 out->begin_list(out, "Fence targets", "fence target", "fence targets");
-
-                do {
-                    char *line = NULL;
-                    char *elem = NULL;
-
-                    char *hostname = NULL;
-                    char *uuid = NULL;
-                    char *status = NULL;
-
-                    eol = strstr(head, "\\n");
-                    line = strndup(head, eol-head);
-
-                    while ((elem = strsep(&line, " ")) != NULL) {
-                        if (strcmp(elem, "") == 0) {
-                            continue;
-                        }
-
-                        if (hostname == NULL) {
-                            hostname = elem;
-                        } else if (uuid == NULL) {
-                            uuid = elem;
-                        } else if (status == NULL) {
-                            char *end = NULL;
-                            status = elem;
-
-                            end = strchr(status, '\n');
-                            if (end != NULL) {
-                                *end = '\0';
-                            }
-                        }
-                    }
-
-                    if (hostname != NULL && uuid != NULL && status != NULL) {
-                        out->message(out, "fence-target", hostname, uuid, status);
-                    }
-
-                    free(line);
-
-                    head = eol+2;
-                } while (eol != NULL);
-
+                while (targets != NULL) {
+                    out->list_item(out, NULL, (const char *) targets->data);
+                    targets = targets->next;
+                }
                 out->end_list(out);
+                free(lists);
+
             } else if (rc != 0) {
                 fprintf(stderr, "List command returned error. rc : %d\n", rc);
             }
diff --git a/xml/api/stonith_admin-1.1.rng b/xml/api/stonith_admin-1.1.rng
new file mode 100644
index 0000000..997670f
--- /dev/null
+++ b/xml/api/stonith_admin-1.1.rng
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+    <start>
+        <ref name="element-stonith-admin"/>
+    </start>
+
+    <define name="element-stonith-admin">
+        <choice>
+            <ref name="stonith-admin-list" />
+            <ref name="element-last-fenced" />
+            <ref name="element-validation" />
+            <element name="metadata"> <text /> </element>
+        </choice>
+    </define>
+
+    <define name="stonith-admin-list">
+        <element name="list">
+            <attribute name="name"> <text /> </attribute>
+            <attribute name="count"> <data type="nonNegativeInteger" /> </attribute>
+            <choice>
+                <empty/>
+                <oneOrMore>
+                    <externalRef href="item-1.1.rng"/>
+                </oneOrMore>
+                <oneOrMore>
+                    <ref name="fencing-history-event" />
+                </oneOrMore>
+            </choice>
+        </element>
+    </define>
+
+    <define name="element-last-fenced">
+        <element name="last-fenced">
+            <attribute name="target"> <text /> </attribute>
+            <attribute name="when"> <text /> </attribute>
+        </element>
+    </define>
+
+    <define name="element-validation">
+        <element name="validate">
+            <attribute name="agent"> <text /> </attribute>
+            <attribute name="valid"> <data type="boolean" /> </attribute>
+            <optional>
+                <externalRef href="command-output-1.0.rng" />
+            </optional>
+        </element>
+    </define>
+
+    <define name="fencing-history-event">
+        <element name="fence_event">
+            <attribute name="status">
+                <choice>
+                    <value>failed</value>
+                    <value>success</value>
+                    <value>pending</value>
+                </choice>
+            </attribute>
+            <optional>
+                <attribute name="extended-status"> <text /> </attribute>
+            </optional>
+            <optional>
+                <attribute name="delegate"> <text /> </attribute>
+            </optional>
+            <attribute name="action"> <text /> </attribute>
+            <attribute name="target"> <text /> </attribute>
+            <attribute name="client"> <text /> </attribute>
+            <attribute name="origin"> <text /> </attribute>
+            <optional>
+                <attribute name="completed"> <text /> </attribute>
+            </optional>
+        </element>
+    </define>
+</grammar>
-- 
1.8.3.1


From 8cc030c045e0a0b43a2a0dcfec5541e5e07faed3 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Mon, 10 Jun 2019 17:41:32 -0500
Subject: [PATCH 10/11] Fix: libcrmcommon: add stderr source correctly when
 outputting XML

---
 lib/common/output_xml.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/common/output_xml.c b/lib/common/output_xml.c
index c93d66c..994af43 100644
--- a/lib/common/output_xml.c
+++ b/lib/common/output_xml.c
@@ -130,7 +130,7 @@ xml_subprocess_output(pcmk__output_t *out, int exit_status,
     if (proc_stderr != NULL) {
         child_node = xmlNewTextChild(node, NULL, (pcmkXmlStr) "output",
                                      (pcmkXmlStr) proc_stderr);
-        xmlSetProp(node, (pcmkXmlStr) "source", (pcmkXmlStr) "stderr");
+        xmlSetProp(child_node, (pcmkXmlStr) "source", (pcmkXmlStr) "stderr");
     }
 
     pcmk__xml_add_node(out, node);
-- 
1.8.3.1


From 4ce8272fde2605099b9d4bb1e211bc66c4f79f90 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Wed, 12 Jun 2019 19:56:09 -0500
Subject: [PATCH 11/11] Test: CTS: update pattern for changed log message

changed in 0a884f32
---
 cts/CM_common.py | 4 ++--
 cts/patterns.py  | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/cts/CM_common.py b/cts/CM_common.py
index 0112fec..b7ff223 100755
--- a/cts/CM_common.py
+++ b/cts/CM_common.py
@@ -12,7 +12,7 @@ from __future__ import print_function, unicode_literals, absolute_import, divisi
 __copyright__ = """Original Author: Huang Zhen <zhenhltc@cn.ibm.com>
 Copyright 2004 International Business Machines
 
-with later changes copyright 2004-2018 the Pacemaker project contributors.
+with later changes copyright 2004-2019 the Pacemaker project contributors.
 The version control history for this file may have further details.
 """
 __license__ = "GNU General Public License version 2 or later (GPLv2+) WITHOUT ANY WARRANTY"
@@ -318,7 +318,7 @@ class crm_common(ClusterManager):
 
         stonith_ignore = [
             r"Updating failcount for child_DoFencing",
-            r"(ERROR|error).*: Sign-in failed: triggered a retry",
+            r"error.*: Fencer connection failed \(will retry\)",
             "pacemaker-execd.*(ERROR|error): stonithd_receive_ops_result failed.",
              ]
 
diff --git a/cts/patterns.py b/cts/patterns.py
index 1bdace0..1b86ee7 100644
--- a/cts/patterns.py
+++ b/cts/patterns.py
@@ -308,7 +308,7 @@ class crm_corosync(BasePatterns):
         self.components["pacemaker-fenced-ignore"] = [
             r"error:.*Connection to (fencer|stonith-ng).* (closed|failed|lost)",
             r"crit:.*Fencing daemon connection failed",
-            r"error:.*Sign-in failed: triggered a retry",
+            r"error:.*Fencer connection failed \(will retry\)",
             r"Connection to (fencer|stonith-ng) failed, finalizing .* pending operations",
             r"pacemaker-controld.*:\s+Result of .* operation for Fencing.*Error",
         ]
-- 
1.8.3.1