From 92ddd23a74ea769a8ed51ce95b52235373cc0080 Mon Sep 17 00:00:00 2001
From: Ken Gaillot <kgaillot@redhat.com>
Date: Wed, 3 Jul 2019 22:41:45 -0500
Subject: [PATCH 2/8] Refactor: libpe_status: reorganize unpacking migration
 history

... to make it easier to follow and modify
---
 lib/pengine/unpack.c | 201 ++++++++++++++++++++++++-------------------
 1 file changed, 114 insertions(+), 87 deletions(-)

diff --git a/lib/pengine/unpack.c b/lib/pengine/unpack.c
index adbf481e6..ab619c836 100644
--- a/lib/pengine/unpack.c
+++ b/lib/pengine/unpack.c
@@ -2417,7 +2417,8 @@ stop_happened_after(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op,
 }
 
 static void
-unpack_rsc_migration(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_set_t * data_set)
+unpack_migrate_to_success(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op,
+                          pe_working_set_t *data_set)
 {
     /* A successful migration sequence is:
      *    migrate_to on source node
@@ -2433,15 +2434,16 @@ unpack_rsc_migration(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_
      *
      * If the migrate_to and migrate_from both succeeded (which also implies the
      * resource is no longer running on the source), but there is no stop, the
-     * migration is considered to be "dangling".
+     * migration is considered to be "dangling". Schedule a stop on the source
+     * in this case.
      */
     int from_rc = 0;
     int from_status = 0;
-    const char *migrate_source = NULL;
-    const char *migrate_target = NULL;
-    pe_node_t *target = NULL;
-    pe_node_t *source = NULL;
+    pe_node_t *target_node = NULL;
+    pe_node_t *source_node = NULL;
     xmlNode *migrate_from = NULL;
+    const char *source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
+    const char *target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
 
     if (stop_happened_after(rsc, node, xml_op, data_set)) {
         return;
@@ -2450,20 +2452,17 @@ unpack_rsc_migration(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_
     // Clones are not allowed to migrate, so role can't be master
     rsc->role = RSC_ROLE_STARTED;
 
-    migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
-    migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
+    target_node = pe_find_node(data_set->nodes, target);
+    source_node = pe_find_node(data_set->nodes, source);
 
-    target = pe_find_node(data_set->nodes, migrate_target);
-    source = pe_find_node(data_set->nodes, migrate_source);
-
-    // Check whether there was a migrate_from action
-    migrate_from = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, migrate_target,
-                               migrate_source, data_set);
+    // Check whether there was a migrate_from action on the target
+    migrate_from = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, target,
+                               source, data_set);
     if (migrate_from) {
         crm_element_value_int(migrate_from, XML_LRM_ATTR_RC, &from_rc);
         crm_element_value_int(migrate_from, XML_LRM_ATTR_OPSTATUS, &from_status);
         pe_rsc_trace(rsc, "%s op on %s exited with status=%d, rc=%d",
-                     ID(migrate_from), migrate_target, from_status, from_rc);
+                     ID(migrate_from), target, from_status, from_rc);
     }
 
     if (migrate_from && from_rc == PCMK_OCF_OK
@@ -2473,32 +2472,32 @@ unpack_rsc_migration(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_
          * source without affecting the target.
          */
         pe_rsc_trace(rsc, "Detected dangling migration op: %s on %s", ID(xml_op),
-                     migrate_source);
+                     source);
         rsc->role = RSC_ROLE_STOPPED;
         rsc->dangling_migrations = g_list_prepend(rsc->dangling_migrations, node);
 
     } else if (migrate_from && (from_status != PCMK_LRM_OP_PENDING)) { // Failed
-        if (target && target->details->online) {
-            pe_rsc_trace(rsc, "Marking active on %s %p %d", migrate_target, target,
-                         target->details->online);
-            native_add_running(rsc, target, data_set);
+        if (target_node && target_node->details->online) {
+            pe_rsc_trace(rsc, "Marking active on %s %p %d", target, target_node,
+                         target_node->details->online);
+            native_add_running(rsc, target_node, data_set);
         }
 
     } else { // Pending, or complete but erased
-        if (target && target->details->online) {
-            pe_rsc_trace(rsc, "Marking active on %s %p %d", migrate_target, target,
-                         target->details->online);
+        if (target_node && target_node->details->online) {
+            pe_rsc_trace(rsc, "Marking active on %s %p %d", target, target_node,
+                         target_node->details->online);
 
-            native_add_running(rsc, target, data_set);
-            if (source && source->details->online) {
+            native_add_running(rsc, target_node, data_set);
+            if (source_node && source_node->details->online) {
                 /* This is a partial migration: the migrate_to completed
                  * successfully on the source, but the migrate_from has not
                  * completed. Remember the source and target; if the newly
                  * chosen target remains the same when we schedule actions
                  * later, we may continue with the migration.
                  */
-                rsc->partial_migration_target = target;
-                rsc->partial_migration_source = source;
+                rsc->partial_migration_target = target_node;
+                rsc->partial_migration_source = source_node;
             }
         } else {
             /* Consider it failed here - forces a restart, prevents migration */
@@ -2509,75 +2508,100 @@ unpack_rsc_migration(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_
 }
 
 static void
-unpack_rsc_migration_failure(resource_t *rsc, node_t *node, xmlNode *xml_op, pe_working_set_t * data_set) 
+unpack_migrate_to_failure(pe_resource_t *rsc, pe_node_t *node, xmlNode *xml_op,
+                          pe_working_set_t *data_set)
 {
-    const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
-
-    CRM_ASSERT(rsc);
-    if (safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
-        int stop_id = 0;
-        int migrate_id = 0;
-        const char *migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
-        const char *migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
-
-        xmlNode *stop_op =
-            find_lrm_op(rsc->id, CRMD_ACTION_STOP, migrate_source, NULL, data_set);
-        xmlNode *migrate_op =
-            find_lrm_op(rsc->id, CRMD_ACTION_MIGRATE, migrate_source, migrate_target,
-                        data_set);
+    int target_stop_id = 0;
+    int target_migrate_from_id = 0;
+    xmlNode *target_stop = NULL;
+    xmlNode *target_migrate_from = NULL;
+    const char *source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
+    const char *target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
+
+    /* If a migration failed, we have to assume the resource is active. Clones
+     * are not allowed to migrate, so role can't be master.
+     */
+    rsc->role = RSC_ROLE_STARTED;
 
-        if (stop_op) {
-            crm_element_value_int(stop_op, XML_LRM_ATTR_CALLID, &stop_id);
-        }
-        if (migrate_op) {
-            crm_element_value_int(migrate_op, XML_LRM_ATTR_CALLID, &migrate_id);
-        }
+    // Check for stop on the target
+    target_stop = find_lrm_op(rsc->id, CRMD_ACTION_STOP, target, NULL,
+                              data_set);
+    if (target_stop) {
+        crm_element_value_int(target_stop, XML_LRM_ATTR_CALLID,
+                              &target_stop_id);
+    }
 
-        /* Get our state right */
-        rsc->role = RSC_ROLE_STARTED;   /* can be master? */
+    // Check for migrate_from on the target
+    target_migrate_from = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, target,
+                                      source, data_set);
+    if (target_migrate_from) {
+        crm_element_value_int(target_migrate_from, XML_LRM_ATTR_CALLID,
+                              &target_migrate_from_id);
+    }
 
-        if (stop_op == NULL || stop_id < migrate_id) {
-            node_t *source = pe_find_node(data_set->nodes, migrate_source);
+    if ((target_stop == NULL) || (target_stop_id < target_migrate_from_id)) {
+        /* There was no stop on the source, or a stop that happened before a
+         * migrate_from, so assume the resource is still active on the target
+         * (if it is up).
+         */
+        node_t *target_node = pe_find_node(data_set->nodes, target);
 
-            if (source && source->details->online) {
-                native_add_running(rsc, source, data_set);
-            }
+        pe_rsc_trace(rsc, "stop (%d) + migrate_from (%d)",
+                     target_stop_id, target_migrate_from_id);
+        if (target_node && target_node->details->online) {
+            native_add_running(rsc, target_node, data_set);
         }
 
-    } else if (safe_str_eq(task, CRMD_ACTION_MIGRATE)) {
-        int stop_id = 0;
-        int migrate_id = 0;
-        const char *migrate_source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
-        const char *migrate_target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
-
-        xmlNode *stop_op =
-            find_lrm_op(rsc->id, CRMD_ACTION_STOP, migrate_target, NULL, data_set);
-        xmlNode *migrate_op =
-            find_lrm_op(rsc->id, CRMD_ACTION_MIGRATED, migrate_target, migrate_source,
-                        data_set);
+    } else if (target_migrate_from == NULL) {
+        /* There was a stop, but no migrate_from. The stop could have happened
+         * before migrate_from was even scheduled, so mark it as dangling so we
+         * can force a stop later.
+         */
+        rsc->dangling_migrations = g_list_prepend(rsc->dangling_migrations, node);
+    }
+}
 
-        if (stop_op) {
-            crm_element_value_int(stop_op, XML_LRM_ATTR_CALLID, &stop_id);
-        }
-        if (migrate_op) {
-            crm_element_value_int(migrate_op, XML_LRM_ATTR_CALLID, &migrate_id);
-        }
+static void
+unpack_migrate_from_failure(pe_resource_t *rsc, pe_node_t *node,
+                            xmlNode *xml_op, pe_working_set_t *data_set)
+{
+    int source_stop_id = 0;
+    int source_migrate_to_id = 0;
+    xmlNode *source_stop = NULL;
+    xmlNode *source_migrate_to = NULL;
+    const char *source = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_SOURCE);
+    const char *target = crm_element_value(xml_op, XML_LRM_ATTR_MIGRATE_TARGET);
+
+    /* If a migration failed, we have to assume the resource is active. Clones
+     * are not allowed to migrate, so role can't be master.
+     */
+    rsc->role = RSC_ROLE_STARTED;
 
-        /* Get our state right */
-        rsc->role = RSC_ROLE_STARTED;   /* can be master? */
+    // Check for a stop on the source
+    source_stop = find_lrm_op(rsc->id, CRMD_ACTION_STOP, source, NULL,
+                              data_set);
+    if (source_stop) {
+        crm_element_value_int(source_stop, XML_LRM_ATTR_CALLID,
+                              &source_stop_id);
+    }
 
-        if (stop_op == NULL || stop_id < migrate_id) {
-            node_t *target = pe_find_node(data_set->nodes, migrate_target);
+    // Check for a migrate_to on the source
+    source_migrate_to = find_lrm_op(rsc->id, CRMD_ACTION_MIGRATE,
+                                    source, target, data_set);
+    if (source_migrate_to) {
+        crm_element_value_int(source_migrate_to, XML_LRM_ATTR_CALLID,
+                              &source_migrate_to_id);
+    }
 
-            pe_rsc_trace(rsc, "Stop: %p %d, Migrated: %p %d", stop_op, stop_id, migrate_op,
-                         migrate_id);
-            if (target && target->details->online) {
-                native_add_running(rsc, target, data_set);
-            }
+    if ((source_stop == NULL) || (source_stop_id < source_migrate_to_id)) {
+        /* There was no stop on the source, or a stop that happened before
+         * migrate_to, so assume the resource is still active on the source (if
+         * it is up).
+         */
+        pe_node_t *source_node = pe_find_node(data_set->nodes, source);
 
-        } else if (migrate_op == NULL) {
-            /* Make sure it gets cleaned up, the stop may pre-date the migrate_from */
-            rsc->dangling_migrations = g_list_prepend(rsc->dangling_migrations, node);
+        if (source_node && source_node->details->online) {
+            native_add_running(rsc, source_node, data_set);
         }
     }
 }
@@ -2676,8 +2700,11 @@ unpack_rsc_op_failure(resource_t * rsc, node_t * node, int rc, xmlNode * xml_op,
     if (safe_str_eq(task, CRMD_ACTION_STOP)) {
         resource_location(rsc, node, -INFINITY, "__stop_fail__", data_set);
 
-    } else if (safe_str_eq(task, CRMD_ACTION_MIGRATE) || safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
-        unpack_rsc_migration_failure(rsc, node, xml_op, data_set);
+    } else if (safe_str_eq(task, CRMD_ACTION_MIGRATE)) {
+        unpack_migrate_to_failure(rsc, node, xml_op, data_set);
+
+    } else if (safe_str_eq(task, CRMD_ACTION_MIGRATED)) {
+        unpack_migrate_from_failure(rsc, node, xml_op, data_set);
 
     } else if (safe_str_eq(task, CRMD_ACTION_PROMOTE)) {
         rsc->role = RSC_ROLE_MASTER;
@@ -3099,7 +3126,7 @@ update_resource_state(resource_t * rsc, node_t * node, xmlNode * xml_op, const c
         clear_past_failure = TRUE;
 
     } else if (safe_str_eq(task, CRMD_ACTION_MIGRATE)) {
-        unpack_rsc_migration(rsc, node, xml_op, data_set);
+        unpack_migrate_to_success(rsc, node, xml_op, data_set);
 
     } else if (rsc->role < RSC_ROLE_STARTED) {
         pe_rsc_trace(rsc, "%s active on %s", rsc->id, node->details->uname);
-- 
2.26.2

